Arkeep - Централизованный Backup сервер с агентами, на базе Restic и Rclone
Приветствую!

В этой статье рассмотрим установку и настройку системы резервного копирования Arkeep с помощью Docker Compose.

Предисловие

Arkeep - это Open source система централизованного резервного копирования, построенная на базе таких замечательных инструментов, как Restic и Rclone.

Существует множество различных инструментов бэкапа, использующих данные утилиты. Но все они не являются “полноценно централизованными”. Это довольно актуальная проблема в мире Open source.

И как гласит философия программистов: если нет нужного тебе инструмента, напиши его сам. Что и сделал разработчик Arkeep. Скрин с Реддита:

Arkeep имеет агент-серверную архитектуру. То есть вы настраиваете сервер Arkeep, затем устанавливаете на нужные вам хосты arkeep-agent и подключаете их к серверу. После этого вы можете управлять настройкой бэкапа этих хостов. В качестве хранилища можно использовать всё то, с чем умеют работать Restic и Rclone.

Схема резервного копирования с Arkeep

В данной статье мы рассмотрим настройку резервного копирования Linux-хостов под управлением Debian 13 с помощью Arkeep (Restic) в объектное S3-хранилище на базе RustFS.

Доступ ко всем ресурсам организуем через обратный proxy-сервер Angie. К Web GUI-панелям подключаться будем по HTTPS, для чего настроим автоматическое получение TLS-сертификатов от Let’s Encrypt.

Ниже представлена схема будущей инфраструктуры:

Тут важно понимать один момент:

Взаимодействие агентов и сервера Arkeep мы будем настраивать через проксирование gRPC с помощью директивы grpc_proxy. При этом подключения агентов до прокси-сервера будут осуществляться с помощью HTTPS, а от Angie до сервера Arkeep уже по обычному HTTP+gRPC.

Вводные данные

ПО, используемое в статье:

ПОВерсия
Debian13
Docker Engine28
Angie1.9.1
Arkeep0.4.5
RustFS1.0.0-beta.8

Доменная схема:

Подготовка инфраструктуры

Установка бэкап-сервера Arkeep

Подключаемся к серверу arkeep.r4ven.me с помощью SSH и переходим на УЗ root с помощью sudo:

BASH
ssh ivan@arkeep.r4ven.me

sudo -i
Нажмите, чтобы развернуть и увидеть больше

Создаём общую сеть Docker:

BASH
docker network create --opt com.docker.network.bridge.name=br-arkeep --opt com.docker.network.enable_ipv6=false --driver bridge --subnet 172.20.20.0/24 --gateway 172.20.20.1 arkeep_net
Нажмите, чтобы развернуть и увидеть больше

Создаём директорию проекта Arkeep:

BASH
install -m 700 -d /etc/compose

mkdir -vp /etc/compose/arkeep && cd /etc/compose/arkeep
Нажмите, чтобы развернуть и увидеть больше

Теперь создаём compose-файл, например, с помощью редактора vim:

BASH
vim ./compose.yaml
Нажмите, чтобы развернуть и увидеть больше

Наполняем:

YAML
---
# https://github.com/arkeep-io/arkeep/tree/main/deploy/docker

networks:
  arkeep_net:
    external: true

volumes:
  arkeep_server:
    name: arkeep_server
  arkeep_agent:
    name: arkeep_agent

services:
  arkeep_server:
    image: ghcr.io/arkeep-io/arkeep-server:v0.4.5
    container_name: arkeep-server
    restart: unless-stopped
    stop_grace_period: 1m
    cpus: 1
    mem_limit: 1G
    hostname: arkeep-server
    env_file: ./.env
    healthcheck:
      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/health/ready"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s
    expose:
      - "8080"   # REST API + GUI
      - "9090"   # gRPC (agents)
    volumes:
      - arkeep_server:/var/lib/arkeep/
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    networks:
      - arkeep_net

  arkeep_agent:
    image: ghcr.io/arkeep-io/arkeep-agent:v0.4.5
    depends_on:
      arkeep_server:
        condition: service_healthy
    container_name: arkeep-agent
    restart: unless-stopped
    stop_grace_period: 1m
    cpus: 1
    mem_limit: 1G
    hostname: arkeep-agent
    environment:
      TZ: "${TZ:-Europe/Moscow}"
      ARKEEP_SERVER_ADDR: "arkeep-server:9090"
      ARKEEP_AGENT_SECRET: "${ARKEEP_AGENT_SECRET}"
      ARKEEP_STATE_DIR: "/var/lib/arkeep-agent"
      ARKEEP_LOG_LEVEL: "${ARKEEP_LOG_LEVEL:-info}"
      ARKEEP_GRPC_INSECURE: "${ARKEEP_GRPC_INSECURE:-false}"
    volumes:
      - arkeep_agent:/var/lib/arkeep-agent/
      - /:/hostfs/:ro # :ro for backup-only; change to :rw to also restore to local paths
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /var/lib/docker/volumes/:/var/lib/docker/volumes/:ro
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    networks:
      - arkeep_net
Нажмите, чтобы развернуть и увидеть больше

Отдельно стоит сказать про монтирование корня файловой системы хоста: /:/hostfs/:ro. Монтирование в режиме только для чтения (ro) позволит выполнять бэкап любой точки системы. Если вы хотите также иметь возможность восстанавливать файлы в исходные директории - в таком случае необходимо монтировать в режиме rw (просто уберите ro). И т.к. Arkeep-агент в нашем случае будет работать от имени пользователя root, это подразумевает полный доступ агента к файлам системы. Имейте это в виду. Продолжим.

Создаём env файл:

BASH
vim ./.env
Нажмите, чтобы развернуть и увидеть больше

Наполняем:

INI
# https://github.com/arkeep-io/arkeep/tree/main/deploy/docker

TZ=Europe/Moscow
ARKEEP_SECRET_KEY=
ARKEEP_AGENT_SECRET=
ARKEEP_DATA_DIR=/var/lib/arkeep/data
ARKEEP_DB_DRIVER=sqlite
ARKEEP_DB_DSN=/var/lib/arkeep/arkeep.db
ARKEEP_LOG_LEVEL=info
ARKEEP_SERVER_ADDR=arkeep-grpc.r4ven.me:443
ARKEEP_SERVER_HTTP_ADDR=https://arkeep.r4ven.me
ARKEEP_GRPC_INSECURE=true
ARKEEP_TELEMETRY=true
Нажмите, чтобы развернуть и увидеть больше

Описание параметров:

Генерируем секреты рекомендуемой длины:

BASH
sed -iE "s/^ARKEEP_SECRET_KEY=.*/ARKEEP_SECRET_KEY=$(openssl rand -hex 32)/" ./.env

sed -iE "s/^ARKEEP_AGENT_SECRET=.*/ARKEEP_AGENT_SECRET=$(openssl rand -hex 24)/" ./.env
Нажмите, чтобы развернуть и увидеть больше

Запускаем стек:

BASH
docker compose up -d && docker compose logs -f
Нажмите, чтобы развернуть и увидеть больше

Проверяем:

BASH
docker compose ps

docker compose volumes
Нажмите, чтобы развернуть и увидеть больше

Если всё нормально, увидим примерно такой вывод:

Сразу же настроим автозапуск с помощью Systemd:

BASH
cat > ./arkeep.service << EOF
[Unit]
Description=Arkeep service
Requires=docker.service
After=docker.service

[Service]
Restart=always
RestartSec=5
User=root
Group=root
WorkingDirectory=$(realpath ./)
ExecStart=/usr/bin/docker compose up --remove-orphans
ExecStop=/usr/bin/docker compose down

[Install]
WantedBy=multi-user.target
EOF
Нажмите, чтобы развернуть и увидеть больше
BASH
chmod 600 ./arkeep.service

ln -s $(realpath ./arkeep.service) /etc/systemd/system

systemctl daemon-reload

systemctl enable --now arkeep

systemctl status arkeep
Нажмите, чтобы развернуть и увидеть больше

Теперь сервисом arkeep можно управлять утилитой systemctl:

BASH
systemctl stop arkeep
systemctl start arkeep
systemctl restart arkeep
systemctl status arkeep
Нажмите, чтобы развернуть и увидеть больше

Установка S3-хранилища RustFS

RustFS - S3-совместимое хранилище, установку, настройку и использование которого мы рассматривали в прошлой статье.

Создаём директорию проекта:

BASH
mkdir -vp /etc/compose/rustfs && cd /etc/compose/rustfs
Нажмите, чтобы развернуть и увидеть больше

Теперь создаём compose-файл:

BASH
vim ./compose.yaml
Нажмите, чтобы развернуть и увидеть больше

Наполняем:

YAML
---
# https://github.com/rustfs/rustfs

networks:
  arkeep_net:
    external: true

volumes:
  rustfs:
    name: rustfs

services:
  rustfs:
    image: rustfs/rustfs:1.0.0-beta.8
    container_name: rustfs
    restart: unless-stopped
    stop_grace_period: 30s
    cpus: 1
    mem_limit: 1G
    hostname: rustfs
    env_file: ./.env
    healthcheck:
      test:
        ["CMD", "sh", "-c", "curl -f http://127.0.0.1:9000/health && curl -f http://127.0.0.1:9001/rustfs/console/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    expose:
      - "9000" # S3 API port
      - "9001" # Console port
    volumes:
      - rustfs:/data/
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    networks:
      - arkeep_net
Нажмите, чтобы развернуть и увидеть больше

Создаём env-файл:

BASH
vim ./.env
Нажмите, чтобы развернуть и увидеть больше

Наполняем:

INI
# https://docs.rustfs.com/installation/docker/#complete-parameter-configuration-example

TZ=Europe/Moscow
# RUSTFS_VOLUMES=/data/rustfs{0..3} # Define 4 storage volumes
RUSTFS_ADDRESS=0.0.0.0:9000
RUSTFS_CONSOLE_ENABLE=true
RUSTFS_CONSOLE_ADDRESS=0.0.0.0:9001
RUSTFS_CORS_ALLOWED_ORIGINS=https://rustfs.r4ven.me
RUSTFS_CONSOLE_CORS_ALLOWED_ORIGINS=https://rustfs.r4ven.me
RUSTFS_ACCESS_KEY=
RUSTFS_SECRET_KEY=
RUSTFS_OBS_LOGGER_LEVEL=info
Нажмите, чтобы развернуть и увидеть больше

Где:

Задаём “логин” (замените на свой) и генерируем “пароль”:

BASH
sed -iE "s/^RUSTFS_ACCESS_KEY=.*/RUSTFS_ACCESS_KEY=ivan/" ./.env

sed -iE "s/^RUSTFS_SECRET_KEY=.*/RUSTFS_SECRET_KEY=$(openssl rand -hex 32)/" ./.env
Нажмите, чтобы развернуть и увидеть больше

Запускаем стек:

BASH
docker compose up -d && docker compose logs -f
Нажмите, чтобы развернуть и увидеть больше

Проверяем:

BASH
docker compose ps

docker compose volumes
Нажмите, чтобы развернуть и увидеть больше

Если всё нормально, увидим примерно такой вывод:

Сразу же настроим автозапуск с помощью Systemd:

BASH
cat > ./rustfs.service << EOF
[Unit]
Description=RustFS S3 service
Requires=docker.service
After=docker.service

[Service]
Restart=always
RestartSec=5
User=root
Group=root
WorkingDirectory=$(realpath ./)
ExecStart=/usr/bin/docker compose up --remove-orphans
ExecStop=/usr/bin/docker compose down

[Install]
WantedBy=multi-user.target
EOF
Нажмите, чтобы развернуть и увидеть больше
BASH
chmod 600 ./rustfs.service

ln -s $(realpath ./rustfs.service) /etc/systemd/system

systemctl daemon-reload

systemctl enable --now rustfs

systemctl status rustfs
Нажмите, чтобы развернуть и увидеть больше

Теперь сервисом rustfs можно управлять утилитой systemctl:

BASH
systemctl stop rustfs
systemctl start rustfs
systemctl restart rustfs
systemctl status rustfs
Нажмите, чтобы развернуть и увидеть больше

Установка обратного прокси-сервера Angie

Angie - это форк известного Nginx (только лучше!) от наших соотечественников, которые ранее работали над Nginx.

Создаём директорию проекта:

BASH
mkdir -vp /etc/compose/angie && cd /etc/compose/angie
Нажмите, чтобы развернуть и увидеть больше

Создаём файл описания Docker-сервиса:

BASH
vim ./compose.yaml
Нажмите, чтобы развернуть и увидеть больше

Наполняем:

YAML
---
# https://angie.software/angie/docs/installation/docker/

networks:
  arkeep_net:
    external: true

services:
  angie:
    image: docker.angie.software/angie:1.9.1-alpine
    container_name: angie
    restart: unless-stopped
    stop_grace_period: 1m
    cpus: 1
    mem_limit: 1G
    hostname: angie
    environment:
      TZ: Europe/Moscow
    volumes:
      - ./config/angie.conf:/etc/angie/angie.conf:ro
      - ./config/http.d/:/etc/angie/http.d/:ro
      - ./certs/:/var/lib/angie/acme/
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "80:80/tcp"
      - "443:443/tcp"
      - "443:443/udp"
    networks:
      - arkeep_net
Нажмите, чтобы развернуть и увидеть больше

Создаём конфиг:

BASH
mkdir -vp ./config

vim ./config/angie.conf
Нажмите, чтобы развернуть и увидеть больше

Наполняем:

BASH
user angie;
worker_processes auto;
worker_rlimit_nofile 65536;

error_log /var/log/angie/error.log notice;
pid /run/angie/angie.pid;

events {
    worker_connections 65536;
}

http {
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }

    include /etc/angie/mime.types;
    default_type application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    log_format extended '$remote_addr - $remote_user [$time_local] "$request" '
                        '$status $body_bytes_sent "$http_referer" rt="$request_time" '
                        '"$http_user_agent" "$http_x_forwarded_for" '
                        'h="$host" sn="$server_name" ru="$request_uri" u="$uri" '
                        'ucs="$upstream_cache_status" ua="$upstream_addr" us="$upstream_status" '
                        'uct="$upstream_connect_time" urt="$upstream_response_time"';

    access_log /var/log/angie/access.log main;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    keepalive_timeout 20;
    keepalive_requests 1000;

    server_tokens off;

    # DNS resolver for ACME.
    resolver 8.8.8.8 8.8.4.4 ipv6=off valid=300s;

    acme_client le https://acme-v02.api.letsencrypt.org/directory
        email=kar-kar@r4ven.me
        key_type=ecdsa
        renew_before_expiry=30d
        # renew_on_load=on
    ;

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    upstream arkeep_server {
        server arkeep-server:9090;
    }

    upstream arkeep_console {
        server arkeep-server:8080;
    }

    upstream rustfs_server {
        server rustfs:9000;
    }

    upstream rustfs_console {
        server rustfs:9001;
    }

    server {
        listen 80;

        server_name
            arkeep-grpc.r4ven.me
            arkeep.r4ven.me
            rustfs-s3.r4ven.me
            rustfs.r4ven.me
        ;

        location /.well-known/acme-challenge/ {
            root /usr/share/angie/html/;
        }

        location / {
            return 301 https://$host$request_uri;
        }
    }

    server {
        listen 443 ssl;

        http2 on;
        http3 on;

        server_name arkeep-grpc.r4ven.me;

        acme le;

        ssl_certificate $acme_cert_le;
        ssl_certificate_key $acme_cert_key_le;

        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers on;

        location / {
            grpc_pass grpc://arkeep_server;

            grpc_set_header Host $host;
            grpc_set_header X-Real-IP $remote_addr;
            grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

            grpc_connect_timeout 10s;
            grpc_send_timeout 1h;
            grpc_read_timeout 1h;

            grpc_socket_keepalive on;
        }
    }

    server {
        listen 443 ssl;
    
        http2 on;
        http3 on;
    
        server_name arkeep.r4ven.me;
    
        acme le;
    
        ssl_certificate $acme_cert_le;
        ssl_certificate_key $acme_cert_key_le;
    
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers on;
    
        client_max_body_size 0;
    
        location / {
            proxy_pass http://arkeep_console;
    
            proxy_http_version 1.1;
            proxy_request_buffering off;
            proxy_buffering off;
    
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Forwarded-Host $host;
            proxy_set_header X-Forwarded-Port 443;
            proxy_set_header X-Forwarded-Ssl on;
    
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
    
            proxy_connect_timeout 10s;
            proxy_send_timeout 1h;
            proxy_read_timeout 1h;
        }
    }

    server {
        listen 443 ssl;

        http2 on;
        http3 on;

        server_name rustfs-s3.r4ven.me;

        acme le;

        ssl_certificate $acme_cert_le;
        ssl_certificate_key $acme_cert_key_le;

        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers on;

        client_max_body_size 0;

        location / {
            proxy_pass http://rustfs_server;

            proxy_http_version 1.1;
            proxy_request_buffering off;
            proxy_buffering off;
            proxy_cache off;
            proxy_max_temp_file_size 0;

            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Forwarded-Host $host;
            proxy_set_header X-Forwarded-Port 443;
            proxy_set_header X-Forwarded-Ssl on;

            proxy_connect_timeout 10s;
            proxy_send_timeout 1h;
            proxy_read_timeout 1h;
        }
    }

    server {
        listen 443 ssl;

        http2 on;
        http3 on;

        server_name rustfs.r4ven.me;

        acme le;

        ssl_certificate $acme_cert_le;
        ssl_certificate_key $acme_cert_key_le;

        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers on;

        location / {
            proxy_pass http://rustfs_console;

            proxy_http_version 1.1;

            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
        }
    }

    include /etc/angie/http.d/*.conf;
}
Нажмите, чтобы развернуть и увидеть больше

Запускаем стек:

BASH
docker compose up -d && docker compose logs -f
Нажмите, чтобы развернуть и увидеть больше

Проверяем Angie и все остальные сервисы:

BASH
docker compose ps

docker ps
Нажмите, чтобы развернуть и увидеть больше

Если всё нормально, увидим примерно такой вывод:

Сразу же настроим автозапуск с помощью Systemd:

BASH
cat > ./angie.service << EOF
[Unit]
Description=Angie proxy service
Requires=docker.service
After=docker.service

[Service]
Restart=always
RestartSec=5
User=root
Group=root
WorkingDirectory=$(realpath ./)
ExecStart=/usr/bin/docker compose up --remove-orphans
ExecStop=/usr/bin/docker compose down

[Install]
WantedBy=multi-user.target
EOF
Нажмите, чтобы развернуть и увидеть больше
BASH
chmod 600 ./angie.service

ln -s $(realpath ./angie.service) /etc/systemd/system

systemctl daemon-reload

systemctl enable --now angie

systemctl status angie
Нажмите, чтобы развернуть и увидеть больше

Теперь сервисом angie можно управлять утилитой systemctl:

BASH
systemctl stop angie
systemctl start angie
systemctl restart angie
systemctl status angie
Нажмите, чтобы развернуть и увидеть больше

Первым же делом после запуска обратного прокси создаём admin account в Arkeep:

Открываем веб-браузер, переходим по адресу, который указывали для GUI панели и задаём реквизиты для входа администратора:

TXT
https://arkeep.r4ven.me/
Нажмите, чтобы развернуть и увидеть больше

После входа попадём на дашборд Arkeep:

В разделе “Agents” должны увидеть нашего локального агента, который поднимается вместе с сервером:

Установка и настройка Arkeep агентов на app-серверах

Теперь переходим на хосты, которые нужно бэкапить:

Создаём директорию:

BASH
install -m 700 -d /etc/compose

mkdir -vp /etc/compose/arkeep_agent && cd /etc/compose/arkeep_agent
Нажмите, чтобы развернуть и увидеть больше

Создаём compose-файл агента:

BASH
vim ./compose.yaml
Нажмите, чтобы развернуть и увидеть больше

Наполняем:

YAML
---
# https://github.com/arkeep-io/arkeep/tree/main/deploy/docker

volumes:
  arkeep_agent:
    name: arkeep_agent

services:
  arkeep_agent:
    image: ghcr.io/arkeep-io/arkeep-agent:v0.4.5
    container_name: arkeep-agent-app1
    restart: unless-stopped
    stop_grace_period: 1m
    cpus: 1
    mem_limit: 1G
    hostname: arkeep-agent-app1
    env_file: ./.env
    volumes:
      - arkeep_agent:/var/lib/arkeep-agent/
      - /:/hostfs/:ro # :ro for backup-only; change to :rw to also restore to local paths
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /var/lib/docker/volumes/:/var/lib/docker/volumes/:ro
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
Нажмите, чтобы развернуть и увидеть больше

Тут стоит отдельно пояснить bind mount /hostfs: именно через него агент получает доступ к файловой системе хоста для backup. Режима ro достаточно только для создания бэкапов. Для восстановления файлов в исходное расположение необходим доступ в режиме rw.

Создаём env-файл:

BASH
vim ./.env
Нажмите, чтобы развернуть и увидеть больше

Наполняем:

INI
# https://github.com/arkeep-io/arkeep/tree/main/deploy/docker

TZ=Europe/Moscow
ARKEEP_SERVER_ADDR=arkeep-grpc.r4ven.me:443
ARKEEP_SERVER_HTTP_ADDR=https://arkeep.r4ven.me
ARKEEP_AGENT_SECRET=
ARKEEP_STATE_DIR=/var/lib/arkeep-agent
ARKEEP_LOG_LEVEL=info
ARKEEP_GRPC_INSECURE=false
Нажмите, чтобы развернуть и увидеть больше

Описание параметров:

Запускаем контейнер:

BASH
docker compose up -d && docker compose logs -f
Нажмите, чтобы развернуть и увидеть больше

При успешном подключении агента к серверу мы должны увидеть эти две строки:

BASH
arkeep-agent-app1  | {"level":"info","ts":1781279912.8271096,"logger":"connection","caller":"connection/manager.go:427","msg":"registered with server","agent_id":"019ebc8e-7375-7ec1-b345-9d309cc983e8","agent_name":"arkeep-agent-app1"}
arkeep-agent-app1  | {"level":"info","ts":1781279912.827225,"logger":"connection","caller":"connection/manager.go:527","msg":"job stream open","agent_id":"019ebc8e-7375-7ec1-b345-9d309cc983e8"}
Нажмите, чтобы развернуть и увидеть больше

А в консоли управления Arkeep появится новый агент:

Сразу же настроим автозапуск агента с помощью Systemd:

BASH
cat > ./arkeep-agent.service << EOF
[Unit]
Description=Arkeep agent service
Requires=docker.service
After=docker.service

[Service]
Restart=always
RestartSec=5
User=root
Group=root
WorkingDirectory=$(realpath ./)
ExecStart=/usr/bin/docker compose up --remove-orphans
ExecStop=/usr/bin/docker compose down

[Install]
WantedBy=multi-user.target
EOF
Нажмите, чтобы развернуть и увидеть больше
BASH
chmod 600 ./arkeep-agent.service

ln -s $(realpath ./arkeep-agent.service) /etc/systemd/system

systemctl daemon-reload

systemctl enable --now arkeep-agent

systemctl status arkeep-agent
Нажмите, чтобы развернуть и увидеть больше

Теперь сервисом arkeep-agent можно также управлять утилитой systemctl:

BASH
systemctl stop arkeep-agent
systemctl start arkeep-agent
systemctl restart arkeep-agent
systemctl status arkeep-agent
Нажмите, чтобы развернуть и увидеть больше

Настройка RustFS

Для подготовки и настройки S3-хранилища, пожалуйста, изучите мою отдельную статью:

Для дальнейшей настройки нам понадобятся следующие данные:

Настройка Arkeep

Сперва настроим удалённое хранилище, куда будем складывать резервные копии.

Настройка Destination - S3

Переходим в раздел “Destinations”:

Нажимаем “New Destination”, в параметре “Type” указываем желаемый тип хранилища, в нашем случае это “S3/Object Storage”, имя бакета и задаём реквизиты для подключения:

Новое хранилище появится в списке:

Немного про другие типы Destination

Помимо S3, бэкапы можно сохранять в локальную директорию, в директорию доступную по SFTP, на REST Server или в любое другое удалённое хранилище, доступ к которому можно настроить с помощью Rclone (а это 40+ провайдеров):

Для использования rclone в случае arkep-agent‘а, запущенного в Docker, необходимо доустановить rclone и примонтировать к нему конфиг с нужным удалённым хранилищем. Пример для WebDav:

BASH
cat > ./rclone.conf << EOF
[webdav-backup]
type = webdav
url = https://cloud.example.com/remote.php/dav/files/USER
vendor = nextcloud
user = USER
pass = OBSCURED_PASSWORD
EOF
Нажмите, чтобы развернуть и увидеть больше

А compose файл будет выглядеть так:

YAML
---

services:
  arkeep_agent:
    image: ghcr.io/arkeep-io/arkeep-agent:v0.4.5
    container_name: arkeep-agent-rclone
    restart: unless-stopped
    hostname: arkeep-agent-rclone
    env_file: ./.env
    command: sh -c 'apk add rclone; exec arkeep-agent'
    volumes:
      - ./data/:/var/lib/arkeep-agent/
      - /:/hostfs/:rw
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /var/lib/docker/volumes/:/var/lib/docker/volumes/:ro
      - ./rclone.conf:/root/.config/rclone/rclone.conf:ro
Нажмите, чтобы развернуть и увидеть больше

В настройках же “Destination” в панели Arkeep нужно будет указать тип бэкапа - “Rclone” и, опционально, путь к директории хранения:

Добавление Policy

Следующим шагом настроим политику, а точнее задание бэкапирования. Переходим в “Policies” и нажимаем “New Policy”:

Тут указываем все необходимые параметры: имя задания, агента и пароль для шифрования файлов в удалённом хранилище:

Далее указываем источники бэкапа: в нашем примере будем бэкапить директорию /etc и Docker volume Arkeep агента на хосте app1.r4ven.me:

Следующим настраивается расписание выполнения задания в формате crontab, а также время хранения и количество резервных копий:

В самом конце выбираем удалённое хранилище (наш S3) и при необходимости задаём исключения:

Запуск резервного копирования

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

Успех:

В разделе “Snapshots” появится новый бэкап:

В нашем S3 rustfs.r4ven.me можно будет увидеть файлы репозитория Restic:

Восстановление из бэкапа

Как уже говорилось ранее, по умолчанию файловая система хоста монтируется в режиме только чтения. В compose.yaml это место подписано так: :ro for backup-only; change to :rw to also restore to local paths.

BASH
volumes:
  - /:/hostfs:ro
Нажмите, чтобы развернуть и увидеть больше

При добавлении возможности агенту производить запись в файловую систему хоста измените параметр выше на:

BASH
volumes:
  - /:/hostfs:rw
Нажмите, чтобы развернуть и увидеть больше

И перезапустите агента:

BASH
systemctl restart arkeep-agent
Нажмите, чтобы развернуть и увидеть больше

Ну или примонтируйте отдельную директорию с возможностью записи.

Переходим в раздел “Snapshots”, выбираем подходящий, далее три точки и “Restore”:

Тут нам на выбор доступно два режима восстановления:

Рассмотрим каждый из них.

Custom path

В этом варианте нам также доступен выбор: восстановить всё в указанную директорию - мы явно задаём свой путь в файловой системе хоста (без hostfs) куда будем восстанавливать файлы из бэкапа или восстановить отдельные файлы - тут можно выделить отдельные файлы/директории и восстановить только их.

Для запуска восстановления нажимаем “Start restore”. При успехе увидим:

Проверяем в файловой системе хоста:

Отлично!

Original path

При использовании режима восстановления “Original path” файлы из бэкапа будут восстановлены по исходному пути, где они располагались во время бэкапа. Данная процедура может “перезатереть” файлы, изменённые уже после бэкапа. О чём нас и предупреждают:

Запускаем восстановление и… успешно:

Возможные проблемы

В ходе изучения Arkeep я столкнулся с некоторыми проблемами/ошибками. Укажу их тут, вдруг для кого-то окажется полезным.

Чаще всего можно столкнуться именно с такой ошибкой:

Как указано в сообщении, директория назначения недоступна для записи. Про этот момент я рассказывал ранее, в начале шага восстановления из бэкапа.

При подключении агентов:

BASH
arkeep-agent-app1  | {... "msg":"enrollment failed — check --server-http-addr and --agent-secret","error":"enroll: server returned 405 Method Not Allowed" ...}
Нажмите, чтобы развернуть и увидеть больше

Сообщение enrollment failed — server returned 405 Method Not Allowed возникает из-за того, что агент пытается выполнить процедуру автоматической выдачи клиентского сертификата (enrollment) через HTTP API, однако на сервере включён режим ARKEEP_GRPC_INSECURE=true, в котором этот механизм не используется.

Ошибку можно игнорировать, если после неё агент успешно подключается к серверу по gRPC, что подтверждается сообщениями registered with server и job stream open. При этом соединение между агентом и сервером остаётся защищённым TLS-сертификатом Angie на порту 443, а незашифрованный трафик существует только внутри локальной Docker-сети сервера.

TXT
tls: failed to verify certificate:
x509: certificate signed by unknown authority
Нажмите, чтобы развернуть и увидеть больше

Обычно причины такие:

TXT
x509: certificate is valid for arkeep-grpc, not arkeep.r4ven.me
Нажмите, чтобы развернуть и увидеть больше

Обычно она возникает, если:

В таком случае проще всего остановить сервер, удалить директорию Docker volume с данными (если вы только что его развернули) и заново запустить контейнер.

Сертификаты будут перевыпущены автоматически.

Пару слов про добровольную телеметрию

По умолчанию Arkeep собирает анонимную телеметрию. Данное действие можно отключить, но сперва прочтите цитату разработчика:

https://github.com/arkeep-io/arkeep#telemetry

Arkeep sends anonymous usage statistics once per day to help prioritize development. No personal data, backup contents, credentials, or hostnames are ever transmitted.

What is sent: a stable random instance ID, Arkeep version, OS, number of connected agents, and number of active policies.

Aggregate stats are public at: https://telemetry.arkeep.io/stats

To opt out: set ARKEEP_TELEMETRY=false or pass --telemetry=false.

Послесловие

В целом Arkeep мне видится очень удобным и полезным инструментом бэкапа с крутым потенциалом. Надеюсь проект станет популярным и у разработчика будет мотивация его развивать и улучшать. Идея использовать Restic и Rclone проста и гениальна 👍.

Мне кажется у проекта незаслуженно мало звёзд и форков. Если инструмент вам зашёл и у вас есть аккаунт на GitHub, пожалуйста, поставьте репозиторию Arkeep звёздочку ⭐.

Перед тем, как написать эту статью, я проводил свои тесты на версии 0.4.3. На этапе восстановления я заметил один баг: при выборе режима восстановления поле было пустое 🤷‍♂️. Ещё был нюанс с некорректным сообщением типа “error” в логе агента.

В итоге я создал два issue в репозитории Arkeep и разработчик довольно оперативно отреагировал на них, пофиксив баг в очередном обновлении (на момент написания статьи версия 0.4.5), а сообщение перевёл в раздел “info”, за что ему огромное спасибо 🤝.

Если кому интересны подробности, то вот ссылки:

Спасибо, что читаете. И вновь повторюсь: админы делятся на два типа: те, кто делает бэкапы, и те, кто обязательно будет их делать. Всех благ!

Используемые материалы

Авторские права

Автор: Иван Чёрный

Ссылка: https://r4ven.me/storage/arkeep-centralizovannyy-backup-server-s-agentami-na-baze-restic-i-rclone/

Лицензия: CC BY-NC-SA 4.0

Использование материалов блога разрешается при условии: указания авторства/источника, некоммерческого использования и сохранения лицензии.

Начать поиск

Введите ключевые слова для поиска статей

↑↓
ESC
⌘K Горячая клавиша