Обслуживая 1С, мы сталкивается с проблемой копий баз для разработки и тестирования. Особенно это больно на больших базах (от 100Гб). Делать копии средствами 1С - совсем моветон, а pg_dump/pg_restore - долго. А если нам надо не одну, а три или более копии рабочей базы? Допустим, у нас сразу несколько разработчиков хотят выполнить разные доработки / эксперименты / тесты. Допустим, рабочая база 250Гб. Тогда потребуется 1Тб для разработки. Зачастую у компаний не одна база. Зачастую требуются копии не только текущей точки, но и на определенные моменты времени. Даже с настроенным бекапом с PITR, восстановление инстанса с отдельной базой - целое дело.
Для быстрых экспериментов с базами PostgreSQL - есть классное решение от postgres.ai
Представьте, что копия рабочего инстанса создается мгновенно (секунды), с возможностью выбора даты. Представьте, что для нескольких параллельных экспериментов с базой в 250Гб, не потребуется терабайт. Ребята сделали классный сервис над ZFS, реализующий "тонкие клоны" и дают бесплатную Community Edition!
Более подробно в их GitLab-реппозитории
Кому-то лучше воспринимать из видеопрезентации
Как запустить это для 1С?
Есть официальная инструкция, по ней довольно легко запускается решение в варианте с логическим копированием (через dump/restore), но это "из коробки" не сработает для PostgreSQL для 1С. Для 1С же мы используем не ванильный PostgreSQL, а специфичный, именно это создает сложность. Мы должны будем переопределить шаблоны (images) docker контейнеров на свои (как минимум из-за локалей ru_RU.UTF-8).
У нас в Яндекс.Облаке развернут типичный сетап инфраструктуры 1С:
- - сервер БД PostgreSQL (1С сборка от Postgres Pro)
- - сервер 1С
- - сервер лицензирования
- - web-сервер
Там же рядом (для скорости - в той же зоне доступности) создаем виртуалку +/- не сильно хуже рабочего сервера БД, чтобы разработчикам было комфортно разрабатывать/тестировать. Для системы можно использовать небольшой SSD и отдельно добавляем дополнительный диск для баз данных, объемом как минимум равным объему рабочего инстанса PostgreSQL. Объем будет определяться тем, какую глубину снепшотов захотите хранить и как много параллельной разработки/экспериментов. За счет сжатия ZFS у нас получается в 2-3 раза меньший объем.
Подготовка dev-сервера
Устанавливаем Docker
Устанавливаем Docker Compose
Проверяем, как идентифицировался доп.диск в виртуалке
$ sudo lsblk
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
loop0    7:0    0  63.3M  1 loop /snap/core20/1822
loop1    7:1    0 111.9M  1 loop /snap/lxd/24322
loop2    7:2    0  49.8M  1 loop /snap/snapd/18357
loop3    7:3    0    87M  1 loop /snap/lxd/28373
vda    252:0    0    40G  0 disk << системный диск
_00;^72;vda1 252:1    0     1M  0 part
^92;^72;vda2 252:2    0    40G  0 part /
vdb    252:16   0   186G  0 disk << доп.диск под ZFS для баз PostgreSQL
Создаем zfs-pool на /dev/vdb:
sudo zpool create -f \
    -O compression=on \
    -O atime=off \
    -O recordsize=128k \
    -O logbias=throughput \
    -m /var/lib/dblab/dblab_pool \
    dblab_pool \
    /dev/vdb
(выше в инструкции на postgres.ai описан трейдоф о размере блока, я оставляю 128k в угоду большему сжатию)
Проверяем результат:
$ zfs list
NAME         USED  AVAIL     REFER  MOUNTPOINT
dblab_pool   408K   179G       96K  /var/lib/dblab/dblab_pool
Нам потребуются два docker образа:
- один для контейнера, выполняющего и поддерживающего реплику основного инстанса PostgreSQL
- второй для контейнеров, запускающих тонкие клоны, именно с ним будут работать 1С разработчики
Для первого мы за основу берем оригинальный Dockerfile от postgres.ai, добавляем ему локали и я убрал установку доп.модулей PostgreSQL.
Dockerfile.dblab-ru:
ARG PG_SERVER_VERSION=15
# Build the extended image
FROM postgres:${PG_SERVER_VERSION}-bullseye
LABEL maintainer="postgres.ai"
ARG PG_SERVER_VERSION
ENV PG_SERVER_VERSION=${PG_SERVER_VERSION:-15}
ARG PG_UNIX_SOCKET_DIR
ENV PG_UNIX_SOCKET_DIR=${PG_UNIX_SOCKET_DIR:-"/var/run/postgresql"}
ARG PG_SERVER_PORT
ENV PG_SERVER_PORT=${PG_SERVER_PORT:-5432}
RUN apt-get clean && rm -rf /var/lib/apt/lists/partial \
    # remove the "beta" and "rc" suffix in the PG_SERVER_VERSION variable (if exists)
    && PG_SERVER_VERSION="$( echo ${PG_SERVER_VERSION} | sed 's/beta.*//' | sed 's/rc.*//' )" \
    && apt-get update -o Acquire::CompressionTypes::Order::=gz \
    && apt-get install --no-install-recommends -y wget make gcc unzip sudo git \
    curl libc6-dev apt-transport-https ca-certificates pgxnclient bc \
    build-essential libssl-dev krb5-multidev libkrb5-dev lsb-release apt-utils \
    && apt-get install --no-install-recommends -y postgresql-server-dev-${PG_SERVER_VERSION} \
    # plpython3 (procedural language implementation for Python 3.x)
    && apt-get install --no-install-recommends -y postgresql-plpython3-${PG_SERVER_VERSION} \
    # remove all auxilary packages to reduce final image size
    && cd / && rm -rf /tmp/* && apt-get purge -y --auto-remove \
    gcc make wget unzip curl libc6-dev apt-transport-https git \
    postgresql-server-dev-${PG_SERVER_VERSION} pgxnclient build-essential \
    libssl-dev krb5-multidev comerr-dev krb5-multidev libkrb5-dev apt-utils lsb-release \
    libgssrpc4 libevent-dev libbrotli-dev \
    && apt-get clean -y autoclean \
    && rm -rf /var/lib/apt/lists/* \
    # remove standard pgdata
    && rm -rf /var/lib/postgresql/${PG_SERVER_VERSION}/ \
    # add ru locale
    && /bin/sed -i 's/# ru_RU.UTF-8/ru_RU.UTF-8/g; s/# en_US.UTF-8/en_US.UTF-8/g' /etc/locale.gen && /usr/sbin/locale-gen && /bin/echo "LANG=en_US.UTF-8" >> /etc/default/locale
EXPOSE ${PG_SERVER_PORT}
# Prepare Postgres start script
RUN echo "#!/bin/bash" > /pg_start.sh && chmod a+x /pg_start.sh \
    && echo "chown -R postgres:postgres \${PGDATA} \${PG_UNIX_SOCKET_DIR}" \
    >> /pg_start.sh \
    && printf "sudo -Eu postgres /usr/lib/postgresql/$(echo ${PG_SERVER_VERSION} | sed 's/beta.*//' | sed 's/rc.*//')/bin/postgres -D \${PGDATA} -k \${PG_UNIX_SOCKET_DIR}  -p \${PG_SERVER_PORT} >& /proc/1/fd/1 \n" \
    >> /pg_start.sh \
    # Infinite sleep to allow restarting Postgres
    && echo "/bin/bash -c \"trap : TERM INT; sleep infinity & wait\"" \
    >> /pg_start.sh
CMD ["/pg_start.sh"]
Для второго мы сами на базе ubuntu:22.04 разворачиваем PostgreSQL от Рostgres PRO
Dockerfile.1c:
FROM ubuntu:22.04
ARG PG_SERVER_VERSION
ENV PG_SERVER_VERSION=${PG_SERVER_VERSION:-15}
ARG PG_UNIX_SOCKET_DIR
ENV PG_UNIX_SOCKET_DIR=${PG_UNIX_SOCKET_DIR:-"/var/run/postgresql"}
ARG PG_SERVER_PORT
ENV PG_SERVER_PORT=${PG_SERVER_PORT:-5432}
RUN apt-get clean && rm -rf /var/lib/apt/lists/partial \
    # install dependencies
    && apt-get update -o Acquire::CompressionTypes::Order::=gz \
    && apt-get install --no-install-recommends -y apt-transport-https ca-certificates \
    wget curl sudo
RUN wget --no-check-certificate https://repo.postgrespro.ru/1c/1c-15/keys/pgpro-repo-add.sh && \
    sh pgpro-repo-add.sh && \
    apt-get update && \
    DEBIAN_FRONTEND=noninteractive apt-get install -y postgrespro-1c-15 && \
    /bin/sed -i 's/# ru_RU.UTF-8/ru_RU.UTF-8/g; s/# en_US.UTF-8/en_US.UTF-8/g' /etc/locale.gen && /usr/sbin/locale-gen && /bin/echo "LANG=en_US.UTF-8" >> /etc/default/locale && \
    rm -rf /var/lib/apt/lists/*
EXPOSE ${PG_SERVER_PORT}
# Prepare Postgres start script
RUN echo "#!/bin/bash" > /pg_start.sh && chmod a+x /pg_start.sh \
    && echo "chown -R postgres:postgres \${PGDATA} \${PG_UNIX_SOCKET_DIR}" \
    >> /pg_start.sh \
    && printf "sudo -Eu postgres /opt/pgpro/1c-15/bin/postgres -D \${PGDATA} -k \${PG_UNIX_SOCKET_DIR}  -p \${PG_SERVER_PORT} >& /proc/1/fd/1 \n" \
    >> /pg_start.sh \
    # Infinite sleep to allow restarting Postgres
    && echo "/bin/bash -c \"trap : TERM INT; sleep infinity & wait\"" \
    >> /pg_start.sh
CMD ["/pg_start.sh"]
Билдим оба образа:
sudo docker build -t pg-dblab-ru:v1 -f Dockerfile.dblab-ru .
sudo docker build -t pg-1c-ru:v1 -f Dockerfile.1c .
`pg-dblab-ru:v1` и `pg-1c-ru:v1`нужно будет указать далее в настройках в качестве образов контейнеров
Получившиеся образы:
 
$ sudo docker images
REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
pg-1c-ru      v1        f2abd2f089e2   3 seconds ago    249MB
pg-dblab-ru   v1        4f129cca299a   50 minutes ago   427MB
Чтобы перейти к заполнению файла настроек `~/.dblab/engine/configs/server.yml` нам потребуется небольшая подготовка продуктового инстанса PostgreSQL
Подготовка продуктового инстанса PostgreSQL
- Создадим пользователя для репликации
CREATE USER pgdev_user REPLICATION LOGIN PASSWORD 'superpassword';
- Разрешим подключение с определенного IP
в файл /var/lib/pgpro/1c-15/data/pg_hba.conf добавляем запись:
# TYPE  DATABASE        USER            ADDRESS                 METHOD
host    replication    pgdev_user      10.х.х.х/32          md5
где 10.х.х.х - адрес вашего Dev-инстанса
- Включим настройки физической репликации
в файле /var/lib/pgpro/1c-15/data/postgresql.conf проверяем:
wal_level = replica           # set WAL level to 'replica' for physical replication
max_wal_senders = 10          # max number of walsender processes
- Создадим слот репликации
SELECT pg_create_physical_replication_slot('dev_replica');
В процессе, не забываем перезапустить, чтобы применились настройки:
`sudo systemctl restart postgrespro-1c-15.service` или `SELECT pg_reload_conf();`
Подготовка файла настроек DBLab
Исходный пример файла настроек
`mkdir -p .dblab/engine/configs`
Редактируем файл ~/.dblab/engine/configs/server.yml под свои данные:
verificationToken: "secret_token" # Меняем дефолтный token авторизации на что-то свое
...
# Configure PostgreSQL containers
databaseContainer: &db_container
  # Database Lab provisions thin clones using Docker containers and uses auxiliary containers.
  # We need to specify which Postgres Docker image is to be used for that.
  # The default is the extended Postgres image built on top of the official Postgres image
  # (See https://postgres.ai/docs/database-lab/supported_databases).
  # Any custom or official Docker image that runs Postgres. Our Dockerfile
  # (See https://gitlab.com/postgres-ai/custom-images/-/tree/master/extended)
  # is recommended in case if customization is needed.
  #dockerImage: "postgresai/extended-postgres:14" # переопределяем
  dockerImage: "pg-1c-ru:v1" # на свой шаблон контейнера
...
# Adjust PostgreSQL configuration
# Параметры контейнеров для клонов
databaseConfigs: &db_configs
  configs:
    # In order to match production plans with Database Lab plans set parameters related to Query Planning as on production.
    # shared_buffers: 1GB
    # shared_preload_libraries – copy the value from the source
    # Adding shared preload libraries, make sure that there are "pg_stat_statements, auto_explain, logerrors" in the list.
    # It is necessary to perform query and db migration analysis.
    # Note, if you are using PostgreSQL 9.6 and older, remove the logerrors extension from the list since it is not supported.
    #shared_preload_libraries: "pg_stat_statements, pg_stat_kcache, auto_explain, logerrors"
    shared_preload_libraries: "" ### отключаем доп.модули
    # work_mem and all the Query Planning parameters – copy the values from the source.
    # Detailed guide: https://postgres.ai/docs/how-to-guides/administration/postgresql-configuration#postgresql-configuration-in-clones
    # work_mem: "100MB"
    # ... put Query Planning parameters here
    ### и добавляем свои параметры PostgreSQL, адаптируя под dev-машинку
    lc_messages: "en_US.UTF-8"
    lc_monetary: "ru_RU.UTF-8"
    lc_numeric: "ru_RU.UTF-8"
    lc_time: "ru_RU.UTF-8"
    max_connections: 100
    default_text_search_config: 'pg_catalog.russian'
    shared_buffers: 2988MB # 25% of RAM
    temp_buffers: 128MB
    ...
### Далее в блоке provision
provision:
  <<: *db_container
  ...
  # IP addresses that can be used to access clones.
  # By default, using a loop-back to accept only local connections.
  # The empty string means "all available addresses".
  # The option supports multiple IPs (using comma-separated format) and IPv6 addresses (for example, [::1])
  #cloneAccessAddresses: "127.0.0.1"
  cloneAccessAddresses: ""
  ### по-хорошему тут нужно указать адрес сервера 1С
  ### у нас это все в закрытом контуре, поэтому оставляю пустым
### Далее в блоке retrieval
retrieval:
  # The jobs section must not contain physical and logical restore jobs simultaneously.
  jobs:
    - physicalRestore
    - physicalSnapshot
  spec:
    # Restores database data from a physical backup.
    physicalRestore:
      options:
        #dockerImage: "postgresai/extended-postgres:14"
        dockerImage: "pg-dblab-ru:v1"
        ### переопределяем шаблон контейнера на адаптированный (в нем добавлену ru локали)
        <<: *db_container
        # Defines the tool to restore data.
        tool: customTool
        ...
        ### Далее в блоке Sync задаем критичные параметры PostgreSQL
        sync:
          # Enable running of a sync instance.
          enabled: true
          ...
          # Add PostgreSQL configuration parameters to the sync container.
          # Параметры контейнера репликации
          configs:
            shared_buffers: 2GB
            ### для работающей репликации нам нужны
            ### не все настройки рабочего инстанса
            ### а только эти два критичных:
            max_connections: 100
            max_locks_per_transaction: 256
            
        ### Далее задаем переменные окружения
        envs:
          PGUSER: "pgdev_user"
          PGPASSWORD: "********"
          PGHOST: "10.х.х.х"
          PGPORT: 5432
        customTool:
          # To use pg_basebackup, specify environment variables in "envs".
          # Do not edit PostgreSQL data directory (-D).
          # Note that command chains are not supported here; if you need to use a more
          # complicated snippet, create a shell script, use --mount (-v) option
          # when starting a container with Database Lab and use path to it here.
          # Write your data to dataDir defined in "global.config"
          #command: "pg_basebackup -P -R -X stream -D /var/lib/dblab/dblab_pool/data"
          command: "pg_basebackup  -P -R --slot=dev_replica -X stream -D /var/lib/dblab/dblab_pool/data"
          ### и переопределяем команду репликации
          # PostgreSQL "restore_command" configuration option.
          restore_command: ""
    ### в блоке physicalSnapshot тоже переопределяем шаблон контейнера
    physicalSnapshot:
      options:
        ...
        # Promote PGDATA after data fetching.
        promotion:
          <<: *db_container
          # Enable PGDATA promotion.
          enabled: true
          ### переопределяем на свой шаблон
          dockerImage: "pg-dblab-ru:v1"
          ...
        ### И последнее, задаем расписание снепшотов
        ### И их количество (глубину)
        # Scheduler contains tasks that run on a schedule.
        scheduler:
          # Snapshot scheduler creates a new snapshot on a schedule.
          snapshot:
            # Timetable defines in crontab format: https://en.wikipedia.org/wiki/Cron#Overview
            timetable: "0 0 * * *" ### раз в сутки в полночь создаем снепшот реплики
          # Retention scheduler cleans up old snapshots on a schedule.
          retention:
            ### каждый час проверяем нужно ли удалить старые снепшоты
            timetable: "0 * * * *"
            # Limit defines how many snapshots should be hold.
            limit: 10 ### задаем количество хранимых снепшотов
            ### При такой настройке у нас будет доступны слепки рабочих баз
            ### за последние 10 дней
            
Ссылка на полный вариант нашего файла настроек: dev-server-1c-example.yml в начале статьи.
Все готово, чтобы запустить сервис.
docker-compose.yml
version: '3.8'
services:
  dblab_server:
    container_name: dblab_server
    labels:
      - dblab_control
    privileged: true
    ports:
      - "2345:2345"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /var/lib/dblab:/var/lib/dblab/:rshared
      - .dblab/engine/configs:/home/dblab/configs
      - .dblab/engine/meta:/home/dblab/meta
      - .dblab/engine/logs:/home/dblab/logs
      - /sys/kernel/debug:/sys/kernel/debug:rw
      - /lib/modules:/lib/modules:ro
      - /proc:/host_proc:ro
    environment:
      - DOCKER_API_VERSION=1.39
    restart: unless-stopped
    image: postgresai/dblab-server:3.5.0
Настройки запуска контейнера получаются не самые безопасные, поэтому лучше dev-машинку запускать в закрытом контуре, не выставляя наружу.
Можно использовать виртуалку с web-сервером как Jump Server. Тогда сначала устанавливаем соединение: `ssh -N -L 2346:127.0.0.1:2346 dev-server`
Затем в браузере можем открывать: http://127.0.0.1:2346
Результат
После запуска будет создано несколько контейнеров:
$ sudo docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.State}}\t{{.Image}}"
CONTAINER ID   NAMES                      IMAGE
ad6c0f30a73b   dblab_sync_xxxxxx          pg-1c-ru:v2
9ca5fc83ce16   dblab_embedded_ui_xxxxxx   postgresai/ce-ui:latest
2805086d0ede   dblab_server               postgresai/dblab-server:3.5.0
dblab_server - основной сервис, в нем смотрим все логи процесса
dblab_embedded_ui_xxxxxx - из названия понятно, что это фронтенд
dblab_sync_xxxxxx - контейнер репликации
Далее по заданному расписанию будут создаваться ежедневные снепшоты. И еще при старте основного сервиса, автоматически запускается создание снепшота (отключается в настройках server.xml).

Теперь мы можем создавать для разработчиков клоны инстанса PostgreSQL на любой из снепшотов. Клон можно отметить как защищенный (автоматически не удаляемый). В настройках server.xml можно задать "время неактивности", после которого клоны будут удаляться автоматически (по умолчанию 3 часа).

При создании клона задаем произвольный ID, имя пользователя и сложный пароль. Эти данные будем далее использовать при добавлении dev-базы на сервере 1С. Клонам автоматически по порядку назначаются порты 6000, 6001... (диапазон задается в server.xml). Теперь можем добавить базу в 1С:
Пользователь и пароль БД: uclone / ***
Сервер: dev-server port=6000
Где dev-server - имя или IP-адрес dev-сервера

Классно, что у клона можно вызвать сброс (reset) на нужную точку (на нужный снепшот) и таким образом производить множество быстрых итераций экспериментов с базами 1С.

Как это выглядит на ZFS:
zfs list
NAME                                  USED  AVAIL     REFER  MOUNTPOINT
dblab_pool                           20.9G   158G     20.5G  /var/lib/dblab/dblab_pool
dblab_pool/clone_pre_20240503184521  70.9M   158G     20.5G  /var/lib/dblab/dblab_pool/clones/clone_pre_20240503184521
dblab_pool/dblab_clone_6000           126M   158G     20.6G  /var/lib/dblab/dblab_pool/clones/dblab_clone_6000
/var/lib/dblab/dblab_pool/data - тут расположена реплика
dblab_pool/clone_pre_20240503184521 - снепшот реплики после первого запуска
dblab_pool/dblab_clone_6000 - клон, с которым можем проводить эксперименты.
Вступайте в нашу телеграмм-группу Инфостарт
 
                                     
                                     
                                     
                                     
                                    