Kopia в Docker Compose: готовый файл
Если вы уже пробовали restic или BorgBackup и упирались в то, что для просмотра снапшотов и статуса репозитория нужно лезть в консоль каждый раз, — у Kopia есть то, чего нет у обоих: собственный веб-интерфейс из коробки. При этом ядро осталось тем же самым — дедупликация по содержимому и шифрование на клиенте. Ниже — рабочий docker-compose.yml для CLI-режима с расписанием и для режима сервера с веб-UI, плюс разбор, чем это всё отличается от более привычных инструментов.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Чем Kopia отличается от restic и Borg
По архитектуре Kopia близка к restic: данные режутся на чанки переменного размера по содержимому (content-defined chunking), одинаковые куски между снапшотами хранятся один раз, а шифрование происходит на стороне клиента до отправки в хранилище — бэкенду видны только зашифрованные блобы. Разница в деталях реализации есть, но без бенчмарка на своих данных говорить, у кого дедупликация эффективнее в конкретном случае, не буду — это оговаривается отдельно и зависит от типа данных.
Главное отличие на практике — три вещи:
- Встроенный веб-UI. Команда
kopia server startподнимает REST API и браузерный интерфейс: список снапшотов, политики, статус репозитория без единой команды в консоли. У restic и Borg такого нет из коробки — там либо CLI, либо сторонние обвязки. - Собственный бэкенд
rclone. Kopia умеет создавать репозиторий поверх любого настроенного rclone-remote одной командой, то есть получает доступ к десяткам облачных хранилищ, которые сама не поддерживает нативно. Сравнение с более прямым подходом — в статье про rclone в Docker Compose. - Политики на уровне репозитория, а не только команды.
kopia policy setсохраняет настройки ретеншена, сжатия и расписания внутри репозитория — при переносе на новый сервер их не нужно переносить отдельно, достаточно переподключиться.
Минус тоже есть: экосистема вокруг Kopia меньше, чем у restic, и часть флагов может незначительно отличаться от версии к версии — команды ниже стоит сверить с kopia --help на установленной у вас версии перед тем, как класть в прод.
Готовый docker-compose.yml: CLI-режим без веб-интерфейса
Самый простой и предсказуемый вариант — без сервера, просто периодический запуск CLI через docker compose run, как это обычно делают с restic.
services:
kopia:
image: kopia/kopia:latest
container_name: kopia-backup
environment:
KOPIA_CHECK_FOR_UPDATES: "false"
volumes:
- /srv/app/data:/data:ro
- kopia-cache:/app/cache
- kopia-config:/app/config
- /mnt/backup-disk/kopia-repo:/repo
secrets:
- kopia_password
entrypoint: /bin/sh
command:
- -c
- "export KOPIA_PASSWORD=$$(cat /run/secrets/kopia_password) && kopia snapshot create /data --override-hostname=app-prod --override-username=backup"
restart: "no"
secrets:
kopia_password:
file: ./secrets/kopia_password.txt
volumes:
kopia-cache:
kopia-config:
Пароль репозитория в отличие от restic Kopia не читает напрямую из файла через _FILE-суффикс — переменной KOPIA_PASSWORD_FILE в CLI нет, поэтому секрет пробрасывается через docker secrets и подставляется в переменную окружения прямо в команде запуска. Зачем это важно и чем плохи пароли прямо в environment: — в статье Docker secrets: управление паролями.
Флаги --override-hostname и --override-username — не косметика: Kopia привязывает снапшоты к паре хост+пользователь, а у контейнера при пересоздании хостнейм случайный (короткий hash-id). Без явного override каждый пересозданный контейнер будет плодить новый «источник» снапшотов вместо того, чтобы продолжать историю существующего.
Репозиторий инициализируется один раз:
docker compose run --rm --entrypoint /bin/sh kopia -c \
"export KOPIA_PASSWORD=\$(cat /run/secrets/kopia_password) && kopia repository create filesystem --path=/repo --override-hostname=app-prod --override-username=backup"
Каталог /app/cache вынесен в отдельный volume по той же причине, что и у restic: без сохранённого кеша каждый запуск заново собирает индексы репозитория, и это заметно бьёт по времени и трафику на удалённых бэкендах. Каталог /app/config хранит подключение к репозиторию (адрес, hostname override) — тоже стоит сохранять между запусками контейнера, иначе придётся заново подключаться командой kopia repository connect при каждом пересоздании.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверВеб-UI: kopia server в отдельном контейнере
Если хочется смотреть на снапшоты и статус репозитория в браузере, а не в выводе консоли, поднимается второй, постоянно живущий сервис с kopia server. Это уже не разовая задача, а демон, поэтому имеет смысл держать его отдельно от CLI-сервиса, который бэкапится по расписанию.
services:
kopia-server:
image: kopia/kopia:latest
container_name: kopia-server
ports:
- "127.0.0.1:51515:51515"
environment:
KOPIA_CHECK_FOR_UPDATES: "false"
volumes:
- /srv/app/data:/data:ro
- kopia-cache:/app/cache
- kopia-config:/app/config
- /mnt/backup-disk/kopia-repo:/repo
secrets:
- kopia_password
entrypoint: /bin/sh
command:
- -c
- "export KOPIA_PASSWORD=$$(cat /run/secrets/kopia_password) && kopia server start --address=0.0.0.0:51515 --insecure --without-password"
restart: unless-stopped
secrets:
kopia_password:
file: ./secrets/kopia_password.txt
volumes:
kopia-cache:
kopia-config:
Порт опубликован только на 127.0.0.1, чтобы веб-UI не смотрел наружу напрямую. --insecure отключает встроенную генерацию self-signed TLS-сертификата внутри самого kopia — это осмысленно только когда перед контейнером стоит reverse-proxy (nginx, Caddy, Traefik), который сам терминирует HTTPS; без proxy этот флаг открывает панель без шифрования. --without-password здесь — самый быстрый способ проверить, что сервер вообще поднимается; в реальной эксплуатации вместо него заводятся отдельные пользователи через kopia server user add, синтаксис которого стоит сверить с kopia server start --help на своей версии.
Если reverse-proxy уже настроен для других сервисов на этом сервере, логично добавить сюда ещё один location/host, а не поднимать отдельный внешний вход только ради панели бэкапа.
Хранилища: локальный диск, S3, SFTP и через rclone
Меняется только тип и адрес репозитория при kopia repository create — CLI- и server-сервисы в compose-файле остаются теми же, меняется лишь команда инициализации и, при необходимости, набор секретов.
# S3 и S3-совместимые (MinIO, Backblaze B2 через совместимый endpoint)
kopia repository create s3 \
--bucket=my-backup-bucket \
--prefix=app-data/ \
--endpoint=s3.eu-west-1.amazonaws.com \
--access-key=$(cat /run/secrets/s3_access_key) \
--secret-access-key=$(cat /run/secrets/s3_secret_key)
# SFTP на свой сервер-хранилище
kopia repository create sftp \
--path=/mnt/kopia-repo \
--host=203.0.113.10 \
--username=backup \
--keyfile=/root/.ssh/id_ed25519
# Через rclone-remote (Google Drive, Yandex.Disk, десятки других)
kopia repository create rclone \
--remote-path=gdrive-backup:kopia-repo \
--embedded-config-file=/app/config/rclone.conf
Для SFTP приватный ключ монтируется отдельным volume-mount с правами 600 на хосте — при более широких правах ssh-клиент откажется его использовать. Для rclone-бэкенда нужен готовый rclone.conf с уже настроенным remote — проще сгенерировать его локально командой rclone config и скопировать файл, чем настраивать remote в неинтерактивном контейнере.
Сравнение по тому, что реально нужно подготовить:
| Бэкенд | Что нужно заранее | Когда уместен |
|---|---|---|
| Локальный диск | Смонтированный отдельный диск/раздел | Первая копия или часть правила 3-2-1, не единственная |
| S3 / совместимое | Bucket, access/secret key | Managed-хранилище без администрирования второго сервера |
| SFTP | Второй сервер, SSH-ключ с ограниченными правами | Полный контроль над хранилищем, свой второй сервер в другой локации |
| rclone | Настроенный rclone.conf с нужным remote | Хранилище, у которого нет нативной поддержки в Kopia (Google Drive, Яндекс.Диск и другие) |
Политики хранения, дедупликация и сжатие
В Kopia политики ретеншена и сжатия привязаны к репозиторию (или к конкретному источнику), а не передаются флагами при каждом запуске — задаются один раз командой kopia policy set:
kopia policy set --global \
--keep-latest 10 \
--keep-hourly 0 \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6 \
--keep-annual 0 \
--compression=zstd
--global применяет политику ко всем источникам сразу; для отдельного каталога её можно переопределить, указав вместо --global конкретный путь источника. Сжатие zstd работает поверх дедупликации и уменьшает объём уникальных чанков — экономия сильно зависит от типа данных (текстовые логи и дампы БД сжимаются лучше, чем уже сжатые архивы или медиафайлы), точный процент без замера на своих данных не приведу.
Посмотреть, какая политика сейчас действует и сколько места фактически занимает репозиторий, можно так:
kopia policy show --global
kopia repository status
Дедупликация и сжатие требовательны к CPU и RAM заметно больше, чем простое копирование файлов, — если сервер под бэкапы выбирается впритык по ресурсам, это стоит учитывать заранее.
Maintenance, восстановление и проверка бэкапа
В отличие от restic, где ротацию запускают явно командой forget --prune, Kopia по умолчанию сама выполняет лёгкое (quick) обслуживание при обычных операциях снапшота, если контейнер выступает владельцем репозитория (kopia maintenance set --owner, задаётся при создании репозитория). Но полное (full) обслуживание — то, которое реально освобождает место после истечения снапшотов, — стоит гонять отдельной плановой задачей, а не полагаться только на автоматику:
0 4 * * 0 cd /srv/app && docker compose run --rm --entrypoint /bin/sh kopia -c \
"export KOPIA_PASSWORD=\$(cat /run/secrets/kopia_password) && kopia maintenance run --full" \
>> /var/log/kopia-maintenance.log 2>&1
Текущее состояние обслуживания и время последнего запуска показывает kopia maintenance info — стоит проверить сразу после первого запуска, поведение автоматики могло отличаться в вашей версии образа.
Бэкап без проверенного восстановления — это просто занятое место на диске. Три команды, которые стоит гонять регулярно:
docker compose run --rm --entrypoint /bin/sh kopia -c \
"export KOPIA_PASSWORD=\$(cat /run/secrets/kopia_password) && kopia snapshot list --all"
docker compose run --rm --entrypoint /bin/sh kopia -c \
"export KOPIA_PASSWORD=\$(cat /run/secrets/kopia_password) && kopia snapshot verify"
docker compose run --rm -v /tmp/restore-test:/restore --entrypoint /bin/sh kopia -c \
"export KOPIA_PASSWORD=\$(cat /run/secrets/kopia_password) && kopia snapshot restore latest /restore"
snapshot list --all показывает снапшоты по всем источникам сразу — полезно, если в одном репозитории лежат бэкапы нескольких приложений. snapshot verify проверяет целостность данных на уровне блобов. Восстановление в отдельный временный каталог — единственный надёжный способ убедиться, что из репозитория реально достаются рабочие файлы. Если бэкапится том с базой данных, а не просто файловая система, восстановление устроено чуть иначе — со своими нюансами по остановке сервиса и правам на файлы.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Kopia сама создаёт репозиторий при первом снапшоте?
Нет, как и у restic, репозиторий нужно инициализировать явно командой kopia repository create до первого snapshot create.
Обязателен ли режим сервера с веб-UI?
Нет, это независимая опция. CLI-режим через docker compose run полностью самодостаточен для бэкапа по расписанию, сервер нужен только для визуального контроля.
Что будет при пересоздании контейнера без сохранённого /app/config?
Подключение к репозиторию потеряется, и контейнер запросит kopia repository connect заново — данные в самом репозитории при этом не пострадают, теряется только локальное состояние подключения и кеш.
Чем Kopia лучше или хуже BorgBackup для контейнерного бэкапа?
У Borg более зрелая экосистема и предсказуемое поведение, но нет встроенного веб-UI и меньше нативных облачных бэкендов; сравнение конфигурации в Docker Compose — в статье про BorgBackup в Docker Compose, а для сравнения с restic — в статье restic в Docker Compose.
Нужно ли фиксировать тег образа вместо latest?
Да, для предсказуемости лучше зафиксировать конкретный тег с Docker Hub, а не latest — версия репозиторийного формата Kopia исторически совместима вперёд, но поведение флагов CLI между релизами может отличаться, и внезапное обновление образа при пересборке — не то время, чтобы это выяснять.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →