Установка и настройка PostgreSQL в Docker

Docker — удобный инструмент для создания изолированных сред. Именно этой своей особенностью он и удобен для разворачивания различных приложений, требующих дополнительных зависимостей.


Managed Kubernetes помогает разворачивать контейнерные приложения в инфраструктуре Selectel. Сосредоточьтесь на разработке, а мы займемся рутинными операциями по обеспечению работы вашего кластера Kubernetes.

В прошлой статье о Docker-контейнерах мы рассказывали о преимуществах контейнеризации в целом, а в этой рассмотрим их относительно СУБД PostgreSQL, также расскажем о ее установке внутри контейнера.

Зачем использовать PostgreSQL в контейнере

Чтобы больше понять о преимуществах контейнеризации PostgreSQL, немного забежим вперед и для примера посмотрим на те зависимые пакеты, которые автоматически будут установлены вместе с приложениями, относящимся непосредственно к PostgreSQL, если мы будем ставить СУБД на сервер:

sudo apt install postgresql postgresql-contrib
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
  libllvm10 libpq5 libxslt1.1 postgresql-12 postgresql-client-12
  postgresql-client-common postgresql-common
Suggested packages:
  postgresql-doc postgresql-doc-12 libjson-perl
Recommended packages:
  sysstat

В нашем примере их три: libllvm10, libpq5, libxslt1.1. Однако, в зависимости от дистрибутива, может быть и больше. Посмотрим от каких пакетов на самом деле зависит пакет postgresql-12 (спойлер: 25 обязательных пакетов и 1 рекомендованный):

sudo apt-cache depends postgresql-12
postgresql-12
 |Depends: locales
  Depends: locales-all
  Depends: postgresql-client-12
  Depends: postgresql-common
  Depends: ssl-cert
  Depends: tzdata
 |Depends: debconf
  Depends: <debconf-2.0>
    cdebconf
    debconf
  Depends: libc6
  Depends: libgcc-s1
  Depends: libgssapi-krb5-2
  Depends: libicu66
  Depends: libldap-2.4-2
  Depends: libllvm10
  Depends: libpam0g
  Depends: libpq5
  Depends: libselinux1
  Depends: libssl1.1
  Depends: libstdc++6
  Depends: libsystemd0
  Depends: libuuid1
  Depends: libxml2
  Depends: libxslt1.1
  Depends: zlib1g
  Recommends: sysstat

Наличие или отсутствие тех или иных пакетов, различные версии и другие факторы напрямую влияют на стабильность работы PostgreSQL. Используя контейнеризацию, возможные конфликты несовместимости нивелируются, т.к. все необходимые зависимости уже будут находиться в среде контейнера. Если загрузить готовый образ контейнера с ресурса Docker Hub (об этом ниже в статье), мы получим протестированную на совместимость и полностью готовую к работе среду.

Еще одно важное преимущество использования контейнеризации среды PostgreSQL — воспроизводимость. Разработчики и те, кто вносит какие-либо изменения в код процедур или добавляет новый функционал, могут быстро развернуть тестовую среду, полностью идентичную боевой, чтобы проверить свои гипотезы.

И, наконец, отказоустойчивость. Если с сервером что-то случится, точно такой же контейнер может быть запущен на другом сервере с уже примонтированным хранилищем датафайлов.

Откроем консоль управления Selectel, перейдем в представление Облачная платформа и нажмем на кнопку Создать сервер.

Далее вводим имя сервера, выбираем образ операционной системы (остановимся на Ubuntu 20.04 LTS 64-bit) и фиксированную конфигурацию сервера с 2 vCPU и 4 ГБ RAM. Объем дискового пространства диска установим в 20 ГБ. Еще раз проверяем конфигурацию сервера и нажимаем Создать.

Проверим сетевые настройки, копируем пароль для root и удостоверимся в нижней части экрана, что все настройки корректны. Нажмем кнопку Создать.

Подождем минуту или две пока сервер не перейдет в состояние Active.

Теперь можем приступать к установке PostgreSQL в Docker. Поехали!

Как установить PostgreSQL в Docker из образа

Перед началом работы с PostgreSQL в контейнере Docker, установим сам Docker. Предварительно, добавим ключ для работы с репозиторием Docker Hub:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

Добавим этот репозиторий в локальный список репозиториев и установим Docker:

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt install docker-ce

Запустим демон Docker и активируем его автозапуск:

sudo systemctl start docker
sudo systemctl enable docker

Поскольку за пределами жизненного цикла контейнера не остается каких либо данных, на файловой системе сервера (или другом файловом хранилище) необходимо создать каталог для хранения данных, которые будут появятся в процессе работы экземпляра PostgreSQL.

mkdir -p $HOME/docker/volumes/postgres

Чтобы получить из репозитория Docker Hub готовый образ контейнера с PostgreSQL, выполним следующую команду:

sudo docker pull postgres
Using default tag: latest
latest: Pulling from library/postgres
f7ec5a41d630: Pull complete
d073cd070242: Pull complete
03790957a916: Pull complete
b3776ac15dab: Pull complete
7144fd00aec4: Pull complete
54f6491bd120: Pull complete
247ab23c6036: Pull complete
57800498c536: Pull complete
bcb15a4d14f4: Pull complete
cfc751ecbc6e: Pull complete
bbf042afd4a4: Pull complete
453056a20de6: Pull complete
d5b1a75378ef: Pull complete
7841e2074775: Pull complete
Digest: sha256:61d5d8ef6cb4e2035f053f26b6b455c201a809354084cc8426b6904b8dd35602
Status: Downloaded newer image for postgres:latest
docker.io/library/postgres:latest

Теперь все готово к запуску.

Как запустить контейнер PostgreSQL

Выполним команду docker с ключом run:

sudo docker run --rm --name selectel-pgdocker -e POSTGRES_PASSWORD=selectel -e POSTGRES_USER=selectel -e POSTGRES_DB=selectel -d -p 5432:5432 -v $HOME/docker/volumes/postgres:/var/lib/postgresql/data postgres

Если возникла ошибка вида: "Error starting userland proxy: listen tcp4 0.0.0.0:5432: bind: address already in use.", то следует вначале посмотреть какой процесс задействует порт 5432:

sudo ss -lptn 'sport = :5432'
State       Recv-Q      Send-Q            Local Address:Port             Peer Address:Port      Process      
LISTEN      0           244                   127.0.0.1:5432                  0.0.0.0:*          users:(("postgres",pid=2592,fd=3)

Затем прибить” процесс по его PID и вновь выполнить запуск Docker-контейнера:

sudo kill 2592

Разберем ключи, которые мы использовали для запуска контейнера:

  • --rm — ключ активирует автоматическое удаление контейнера и связанную с ним файловую систему после остановки контейнера. Полезный ключ для экономии дискового пространства.
  • --name — ключ устанавливает имя контейнера. В пределах одного сервера имена контейнеров должны быть уникальны. Даже если один из них остановлен.
  • -e — ключ задает переменные окружения, с которыми будет запущен контейнер. В нашей ситуации мы добавляем пароль суперпользователя, (POSTGRES_PASSWORD=selectel), имя суперпользователя (POSTGRES_USER=selectel) и имя базы данных по умолчанию (POSTGRES_DB=selectel) к базе данных.
  • -d — ключ указывает, что контейнер должен быть запущен в в фоновом режиме (возвращает управление после его запуска).
  • -p — ключ указывает на привязку внутреннего порта контейнера к порту сервера (используем порт по умолчанию 5432).
  • -v — ключ создает точку монтирования каталога $HOME/docker/volumes/postgres на сервере к каталогу /var/lib/postgresql/data внутри контейнера.

Как подключиться к PostgreSQL в контейнере

После успешного запуска контейнера с PostgreSQL, попробуем к нему подключиться при помощи утилиты psql. Установим ее из пакета postgresql-client:

sudo apt install postgresql-client

Теперь можно подключиться и выполнить тестовый SQL-запрос:

psql -h 127.0.0.1 -U selectel -d selectel
Password for user selectel:
psql (12.6 (Ubuntu 12.6-0ubuntu0.20.04.1), server 13.2 (Debian 13.2-1.pgdg100+1))
WARNING: psql major version 12, server major version 13.
         Some psql features might not work.
Type "help" for help.

selectel=#

Если появилось приглашение к вводу запроса, значит все действия были выполнены правильно.

Еще один вариант подключиться к базе данных, не устанавливая дополнительных утилит — подключиться непосредственно к Docker-контейнеру. Для этого выполним команду docker exec с дополнительными ключами:

sudo docker exec -it selectel-pgdocker psql -U selectel
psql (13.2 (Debian 13.2-1.pgdg100+1))
Type "help" for help.

selectel=#

Приглашение к вводу запроса будет означать корректность ввода команды. Разберем ключи, которые мы использовали для выполнения команды:

  • -i — ключ активирует интерактивную работу с терминалом.
  • -t — ключ запускает псевдо-терминал (pseudo-TTY).
  • selectel-pgdocker — имя контейнера, к которому выполняется подключение.
  • psql — указание на запуск утилиты для подключение к базе данных PostgreSQL.
  • -U — ключ указывает на имя пользователя, которое будет использоваться для подключения к базе данных.

Теперь попробуем создать новую таблицу, добавить в нее данные и выполнить запрос:

selectel=# create table cities (name varchar(80));
CREATE TABLE
selectel=# insert into cities values ('Moscow');
INSERT 0 1
selectel=# select * from cities;
  name
--------
 Moscow
(1 row)

Чтобы остановить запущенный контейнер выполним docker stop и укажем имя контейнера:

sudo docker stop selectel-pgdocker

Файлы и процессы, созданные контейнером, принадлежат пользователю postgres, который является внутренним по отношению к контейнеру. В отсутствие пространства имен пользователей внутри контейнера, UID и GID в контейнере могут иметь произвольное значение. На самом сервере этим UID и GID могут соответствовать привилегированные пользователи или группы соответственно.

Например, пользователь на хосте с тем же UID или GID, что и пользователь postgres в контейнере, сможет получить доступ к данным в различных каталогах хоста, а также сможет завершить любой запущенный процесс. Чтобы избежать такой бреши в безопасности, укажем при запуске контейнера специализированные переменные USERMAP_UID и USERMAP_GID:

sudo docker run --rm --name selectel-pgdocker -e POSTGRES_PASSWORD=selectel -e POSTGRES_USER=selectel -e POSTGRES_DB=selectel -e USERMAP_UID=999 -e USERMAP_GID=999 -d -p 5432:5432 -v $HOME/docker/volumes/postgres:/var/lib/postgresql/data postgres

Как запустить PostgreSQL в контейнере в составе docker-compose

Еще одним вариантом запуска PostgreSQL в Docker-контейнере, является запуск контейнера с базой данных в составе docker-compose. В первую очередь, создадим соответствующий yml-файл:

nano docker-compose.yml
version: '3.1'

volumes:
  pg_selectel:

services:
  pg_db:
    image: postgres
    restart: always
    environment:
      - POSTGRES_PASSWORD=selectel
      - POSTGRES_USER=selectel
      - POSTGRES_DB=selectel
    volumes:
      - pg_project:/var/lib/postgresql/data
    ports:
      - ${POSTGRES_PORT:-5432}:5432

Затем установим docker-compose:

sudo apt install docker-compose

Теперь запустим контейнер:

sudo docker-compose up -d

Ключ -d указывает, что docker-compose должен быть запущен в в фоновом режиме (вернет управление после его запуска).

Проверим возможность подключения к базе данных:

psql -h 192.168.0.4 -U selectel -d selectel
Password for user selectel:
psql (12.6 (Ubuntu 12.6-0ubuntu0.20.04.1), server 13.2 (Debian 13.2-1.pgdg100+1))
WARNING: psql major version 12, server major version 13.
         Some psql features might not work.
Type "help" for help.

selectel=#

Появление приглашения к вводу команд для PostgreSQL означает корректность выполненных настроек.

Чтобы остановить запущенный контейнер, выполним docker-compose stop:

sudo docker-compose stop

Заключение

Мы рассказали о работе с базой данных PostgreSQL в контейнере Docker, запуске, выполнении запросов и остановке. Как и говорили в начале статьи, работа с контейнеризованной в Docker базой данных упрощает процесс разработки и администрирование. Контейнеры могут быть легко перезапущены на другом сервере и сервис, предоставляемый базой данных, не прервется.