Перейти к содержанию

▍Все контейнеры в docker-compose для Docker Swarm

Необходимые требования

У вас должны быть:

Подготовительный этап

Создадим структуру директорий:

sudo mkdir -p /docker/{backup,build,conf,data,logs,swarm}

Дерево каталогов:

┌─( daffin@srv-manager ) - ( 30 files, 112K ) - ( / )
└─> tree -d -L 1 /docker
/docker
├── backup
├── build
├── conf
├── data
├── logs
└── swarm

Docker-compose

Устанавливаем вторую версию Docker compose

$ sudo curl -SL https://github.com/docker/compose/releases/download/v2.15.1/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose

$ sudo chmod +x /usr/local/bin/docker-compose

$ sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

$ docker-compose -v
Docker Compose version v2.15.1

Docker Stack

Ниже приведены стеки с перечнем сервисов:

┌─( root@swarm-manager1 ) - ( 23 files,  ) - ( /docker/swarm )
└─> ls
total 90K
drw------- 2 root root   18 мар  5 14:19 ./
drwxr-xr-x 9 root root    9 янв 19 10:20 ../
-rw------- 1 root root 4,4K мар  4 12:53 archive.yml
-rw------- 1 root root 1019 мар  4 12:54 backups.yml
-rw------- 1 root root 3,3K мар  4 12:55 cloud.yml
-rw------- 1 root root 1,7K мар  4 12:55 control.yml
-rw------- 1 root root 2,7K янв 28 12:30 dashboard.yml
-rw------- 1 root root  11K мар  4 12:56 database.yml
-rw------- 1 root root 4,1K мар  4 11:50 dev.yml
-rw------- 1 root root 2,2K мар  4 12:57 gpt.yml
-rw------- 1 root root 5,5K мар  4 15:00 immich.yml
-rw------- 1 root root  12K мар  4 15:01 monitoring.yml
-rw------- 1 root root 3,6K мар  4 12:50 registry.yml
-rw------- 1 root root  16K мар  4 15:07 service.yml
-rw------- 1 root root 1010 янв 16 11:59 update.yml
-rw------- 1 root root 6,0K мар  4 15:09 www.yml
-rw------- 1 root root 3,5K мар  5 13:58 zcrontab.yml

Для их запуска используем команду:

docker stack deploy --with-registry-auth -c www.yml www

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

#!/bin/bash
DIR="/docker/swarm"
cd $DIR

case "$1" in
     on)
        find . -name "*.yml" ! -name 'docker-compose.yml' -print0 | while read -d $'\0' staks
        do
            stakname=$(basename -- "$staks")
            docker stack deploy --with-registry-auth -c "${stakname%.*}".yml "${stakname%.*}"
        done
          ;;
     off)
        find . -name "*.yml" ! -name 'docker-compose.yml' -print0 | while read -d $'\0' staks
        do
            stakname=$(basename -- "$staks")
            docker stack rm "${stakname%.*}"
        done
          ;;
     *)
          echo "Usage: $0 (on|off)"
          ;;
esac

Для запуска всех сервисов:

~/bin/swarm.sh on

Чтобы погасить всё:

~/bin/swarm.sh off

Т.к. все контейнеры у меня загружены в локальный Docker Registry, то используется ключ "--with-registry-auth" для авторизации. Данные авторизации лежат в домашней директории пользователя, для root это /root/.docker/config.json. Этот файл появится после выполнения шага авторизации в регистри docker login https://registry.example.com. Далее этот файл нужно скопировать на все сервера нашего кластера.

Stack www.yml

version: '3.9'
services:
  traefik:
    image: traefik:latest
    ports:
      - target: 80
        published: 80
        protocol: tcp
        mode: host
      - target: 443
        published: 443
        protocol: tcp
        mode: host
      - target: 443
        published: 443
        protocol: udp
        mode: host
    depends_on:
      - authelia
    environment:
      - [email protected]
      - CF_DNS_API_TOKEN=11111111222222222333333344444445555555
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /docker/conf/traefik/traefik.yml:/etc/traefik/traefik.yml:ro
      - /docker/conf/traefik/data:/data
    networks:
      - traefik-public
    deploy:
      replicas: 2
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      resources:
        limits:
          memory: 128M
        reservations:
          memory: 64M
      placement:
        constraints: [node.role == manager]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.traefik.entrypoints=http"
        - "traefik.http.routers.traefik.rule=Host(`traefik.example.ru`)"
        - "traefik.http.middlewares.traefik-auth.basicauth.users=traefik:$$apr1$$3BL6MNLt$$TYlUAcgfkmwRGD9JTVlA11" # traefik PaSSw0rd для генерации используй: echo $(htpasswd -nb user PaSSw0rd) | sed -e s/\\$/\\$\\$/g
        - "traefik.http.middlewares.WhitelistHome.ipwhitelist.sourcerange=172.18.0.0/24, 172.19.0.0/24, 172.20.0.0/24, 192.168.0.0/16, 10.0.0.0/8"
        - "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
        - "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https"
        - "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
        - "traefik.http.routers.traefik-secure.entrypoints=https"
        - "traefik.http.routers.traefik-secure.rule=Host(`traefik.example.ru`)"
        - "traefik.http.services.traefik-secure.loadbalancer.server.port=8080"
        - "traefik.http.routers.traefik-secure.middlewares=WhitelistHome,traefik-auth,CORS@file"
        - "traefik.http.routers.traefik-secure.tls=true"
        - "traefik.http.routers.traefik-secure.tls.certresolver=cloudflare"
        - "traefik.http.routers.traefik-secure.tls.domains[0].main=example.ru"
        - "traefik.http.routers.traefik-secure.tls.domains[0].sans=*.example.ru"
        - "traefik.http.routers.traefik-secure.service=api@internal"
        - "prometheus-job=traefik"
        - "prometheus-port=8181"


  authelia:
    image: registry.example.ru/authelia:latest
    environment:
      - TZ=Europe/Moscow
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      resources:
        limits:
          memory: 128M
        reservations:
          memory: 64M
      placement:
        constraints: [node.role == manager]
      labels:
        - 'traefik.enable=true'
        - 'traefik.http.routers.authelia.rule=Host(`login.example.ru`)'
        - 'traefik.http.routers.authelia.entrypoints=https'
        - 'traefik.http.routers.authelia.tls=true'
        - 'traefik.http.middlewares.authelia.forwardauth.address=http://authelia:9091/api/verify?rd=https://login.example.ru/'
        - 'traefik.http.middlewares.authelia.forwardauth.trustForwardHeader=true'
        - 'traefik.http.middlewares.authelia.forwardauth.authResponseHeaders=Remote-User, Remote-Groups, Remote-Name, Remote-Email'
        - 'traefik.http.middlewares.authelia-basic.forwardauth.address=http://authelia:9091/api/verify?auth=basic'
        - 'traefik.http.middlewares.authelia-basic.forwardauth.trustForwardHeader=true'
        - 'traefik.http.middlewares.authelia-basic.forwardauth.authResponseHeaders=Remote-User, Remote-Groups, Remote-Name, Remote-Email'
        - "traefik.http.services.authelia.loadbalancer.server.port=9091"
        - "traefik.docker.network=traefik-public"


volumes:
  traefik:

networks:
  traefik-public:
    external: true

Stack registry.yml

version: "3.9"
services:
  registry:
    image: registry:latest
    volumes:
      - /docker/data/registry:/var/lib/registry
      - /docker/conf/registry/auth:/auth
      - /etc/localtime:/etc/localtime:ro
    environment:
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_REALM: Registry
      REGISTRY_AUTH_HTPASSWD_PATH: /auth/registry.password
      REGISTRY_STORAGE_DELETE_ENABLED: 'true'
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.registry.rule=Host(`registry.example.ru`)"
        - "traefik.http.routers.registry.entrypoints=https"
        - "traefik.http.routers.registry.tls=true"
        - "traefik.http.routers.registry.middlewares=WhitelistHome"
        - "traefik.http.services.registry.loadbalancer.server.port=5000"


  registry-ui:
    image: registry.example.ru/docker-registry-ui:main
    environment:
      - SINGLE_REGISTRY=true
      - REGISTRY_TITLE=Docker Registry UI
      - DELETE_IMAGES=true
      - SHOW_CONTENT_DIGEST=true
      - NGINX_PROXY_PASS_URL=http://registry:5000
      - SHOW_CATALOG_NB_TAGS=true
      - CATALOG_MIN_BRANCHES=1
      - CATALOG_MAX_BRANCHES=1
      - TAGLIST_PAGE_SIZE=100
      - REGISTRY_SECURED=false
      - CATALOG_ELEMENTS_LIMIT=1000
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.registry-ui.rule=Host(`registry.example.ru`)"
        - "traefik.http.routers.registry-ui.entrypoints=https"
        - "traefik.http.routers.registry-ui.tls=true"
        - "traefik.http.routers.registry-ui.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.registry-ui.loadbalancer.server.port=80"
        # При удалении образов удаляются только ссылки, для физического удаления необходимо запустить сборщик мусора: 
        # docker exec -it registry_registry.1.uujkkcs9v6pyqthkaqcxrdzon registry garbage-collect /etc/docker/registry/config.yml

  verdaccio:
    image: registry.example.ru/verdaccio
    environment:
      - VERDACCIO_PORT=4873
    volumes:
      - /docker/data/verdaccio:/verdaccio/storage
      - /docker/conf/verdaccio:/verdaccio/conf
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.verdaccio.rule=Host(`npm.example.ru`)"
        - "traefik.http.routers.verdaccio.entrypoints=https"
        - "traefik.http.routers.verdaccio.tls=true"
        - "traefik.http.routers.verdaccio.middlewares=WhitelistHome"
        - "traefik.http.services.verdaccio.loadbalancer.server.port=4873"


networks:
  traefik-public:
    external: true

Stack monitoring.yml

version: "3.9"
services:
  grafana:
    image: registry.example.ru/grafana-oss:latest
    environment:
      GF_REMOTE_CACHE_TYPE: redis
      GF_REMOTE_CACHE_CONNSTR: addr=redis:6379,pool_size=100,db=0,ssl=false
    volumes:
      - /docker/data/grafana:/var/lib/grafana
      - /etc/localtime:/etc/localtime:ro
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.grafana.tls=true"
        - "traefik.http.routers.grafana.rule=Host(`grafana.example.ru`)"
        - "traefik.http.routers.grafana.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.grafana.loadbalancer.server.port=3000"


  elasticsearch:
    image: registry.example.ru/elasticsearch:8.4.3
    hostname: 'elasticsearch'
    environment:
      - discovery.type=single-node
      - ELASTIC_PASSWORD=paSSw0rd
      - xpack.license.self_generated.type=basic
      - path.data=/usr/share/elasticsearch/data
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    volumes:
      - /docker/data/elasticsearch:/usr/share/elasticsearch/data
      - /etc/localtime:/etc/localtime:ro
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]


  kibana:
    image: registry.example.ru/kibana:latest #8.4.3
    depends_on:
      - elasticsearch
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
      - KIBANA_URL=http://kibana.example.ru
      - SERVER_NAME=kibana
      - PATH_DATA=/usr/share/kibana/data
      - ELASTICSEARCH_USERNAME=kibana_system
      - ELASTICSEARCH_PASSWORD=paSSw0rd
    volumes:
      - /docker/data/kibana:/usr/share/kibana/data
      - /etc/localtime:/etc/localtime:ro
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.kibana.tls=true"
        - "traefik.http.routers.kibana.rule=Host(`kibana.example.ru`)"
        - "traefik.http.routers.kibana.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.kibana.loadbalancer.server.port=5601"


  prometheus:
    image: registry.example.ru/prometheus:latest
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--storage.tsdb.retention=750h' # автоочистка данных старше месяца
      - '--web.console.libraries=/usr/share/prometheus/console_libraries'
      - '--web.console.templates=/usr/share/prometheus/consoles'
    depends_on:
      - cadvisor
    volumes:
      - /docker/data/prometheus:/prometheus
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: stop-first
      placement:
        constraints: [node.role == manager]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.prometheus.rule=Host(`prometheus.example.ru`)"
        - "traefik.http.routers.prometheus.entrypoints=https"
        - "traefik.http.routers.prometheus.tls=true"
        - "traefik.http.routers.prometheus.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.prometheus.loadbalancer.server.port=9090"


  node-exporter:
    image: registry.example.ru/node-exporter
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/host:ro,rslave
    command:
      - '--path.rootfs=/host'
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - --collector.filesystem.mount-points-exclude
      - "^/(sys|proc|dev|host|etc|rootfs/var/lib/docker/containers|rootfs/var/lib/docker/overlay2|rootfs/run/docker/netns|rootfs/var/lib/docker/aufs)($$|/)"
    networks:
      - traefik-public
    deploy:
      mode: global
      resources:
        limits:
          memory: 128M
        reservations:
          memory: 64M
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      resources:
        limits:
          memory: 128M
        reservations:
          memory: 64M
      labels:
        - prometheus-job=node-exporter
        - prometheus-port=9100


  fluentd:
    image: registry.example.ru/fluentd:latest
    ports:
      - 5140:5140/udp
    environment:
      - FLUENTD_PASSWORD=paSSw0rd
    volumes:
      - /etc/localtime:/etc/localtime:ro
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]


  cadvisor:
    image: registry.example.ru/cadvisor
    command:
      - --docker_only
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /:/rootfs:ro
      - /var/run:/var/run:rw
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
    networks:
      - traefik-public
    deploy:
      mode: global
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      resources:
        limits:
          memory: 128M
        reservations:
          memory: 64M
      labels:
        - "prometheus-job=cadvisor"
        - "prometheus-port=8080"


  mysql-zabbix:
    image: registry.example.ru/mariadb:10.8
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /docker/data/mysql-zabbix:/var/lib/mysql:Z
    environment:
      - MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql_root_zabbix
      - MYSQL_PASSWORD_FILE=/run/secrets/mysql_zabbix
      - MYSQL_USER=zabbix
      - MYSQL_DATABASE=zabbix
    secrets:
      - mysql_root_zabbix
      - mysql_zabbix
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: stop-first
      placement:
        constraints: [node.role == worker]


  zabbix-web-nginx-mysql:
    image: registry.example.ru/zabbix-web-nginx-mysql:latest
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 30s
    environment:
      DB_SERVER_HOST: mysql-zabbix
      MYSQL_DATABASE: zabbix
      MYSQL_USER: zabbix
      MYSQL_PASSWORD_FILE: /run/secrets/mysql_zabbix
    secrets:
      - mysql_zabbix
    depends_on:
      - mysql-zabbix
    volumes:
      - /etc/localtime:/etc/localtime:ro
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.zabbix.tls=true"
        - "traefik.http.routers.zabbix.rule=Host(`zabbix.example.ru`)"
        - "traefik.http.routers.zabbix.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.zabbix.loadbalancer.server.port=8080"


  zabbix-java-gateway:
    image: registry.example.ru/zabbix-java-gateway:latest
    volumes:
      - /etc/localtime:/etc/localtime:ro
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]


  zabbix-server-mysql:
    image: registry.example.ru/zabbix-server-mysql:latest
    depends_on:
      - zabbix-java-gateway
      - mysql-zabbix
    environment:
      DB_SERVER_HOST: mysql-zabbix
      MYSQL_DATABASE: zabbix
      MYSQL_USER: zabbix
      MYSQL_PASSWORD_FILE: /run/secrets/mysql_zabbix
      ZBX_JAVAGATEWAY: zabbix-java-gateway
    secrets:
      - mysql_zabbix
    volumes:
      - /etc/localtime:/etc/localtime:ro
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]


  uptimekuma:
    image: registry.example.ru/uptime-kuma:latest
    volumes:
      - /docker/conf/uptimekuma:/app/data
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: stop-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.uptime.tls=true"
        - "traefik.http.routers.uptime.rule=Host(`uptime.example.ru`)"
        - "traefik.http.routers.uptime.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.uptime.loadbalancer.server.port=3001"


  alertmanager:
    image: registry.example.ru/alertmanager:latest
    environment:
      - SMTP_SERVER=smtp.mail.ru:465
      - [email protected]
      - [email protected]
      - [email protected]
      - SMTP_AUTH_PASSWORD_FILE=/run/secrets/smtp_passwd
    secrets:
      - smtp_passwd
    volumes:
      - /etc/localtime:/etc/localtime:ro
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      resources:
        limits:
          memory: 128M
        reservations:
          memory: 64M
      placement:
        constraints: [node.role == worker]


secrets:
  mysql_root_zabbix:
    external: true
  mysql_zabbix:
    external: true
  smtp_passwd:
    external: true


volumes:
  mysql-zabbix:

networks:
  traefik-public:
    external: true

Stack control.yml

version: "3.9"
services:
  portainer:
    image: registry.example.ru/portainer-ce
    command: -H tcp://tasks.agent:9001 --tlsskipverify
    environment:
      TZ: Europe/Moscow
    volumes:
      - /docker/conf/portainer:/data
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      resources:
        limits:
          memory: 128M
        reservations:
          memory: 64M
      placement:
        constraints: [node.role == manager]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.portainer.rule=Host(`portainer.example.ru`)"
        - "traefik.http.routers.portainer.entrypoints=https"
        - "traefik.http.routers.portainer.tls=true"
        - "traefik.http.routers.portainer.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.portainer.loadbalancer.server.port=9000"


  agent:
    image: registry.example.ru/agent
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /var/lib/docker/volumes:/var/lib/docker/volumes
    environment:
      AGENT_CLUSTER_ADDR: tasks.agent
    networks:
      - traefik-public
    deploy:
      mode: global
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      resources:
        limits:
          memory: 128M
        reservations:
          memory: 64M


networks:
  traefik-public:
    external: true

Stack database.yml

version: "3.9"
services:
 postgres:
   image: registry.example.ru/postgres:15.3
   command:
     - "postgres"
     - "-c"
     - "max_connections=500"
     - "-c"
     - "work_mem=16MB"
     - "-c"
     - "maintenance_work_mem=512MB"
     - "-c"
     - "log_min_duration_statement=200ms"
     - "-c"
     - "idle_in_transaction_session_timeout=10s"
     - "-c"
     - "lock_timeout=1s"
     - "-c"
     - "statement_timeout=60s"
     - "-c"
     - "shared_preload_libraries=pg_stat_statements"
     - "-c"
     - "pg_stat_statements.max=10000"
     - "-c"
     - "pg_stat_statements.track=all"
   healthcheck:
     test: ["CMD-SHELL", "pg_isready"]
     interval: 30s
     timeout: 20s
     retries: 7
   volumes:
     - /etc/localtime:/etc/localtime:ro
     - /docker/data/postgresql:/var/lib/postgresql/data:Z
   environment:
     - POSTGRES_USER=postgres
     - POSTGRES_PASSWORD_FILE=/run/secrets/postgresql_root
     - POSTGRES_INITDB_ARGS=--data-checksums
     - PGDATA=/var/lib/postgresql/data/swarm
   secrets:
     - postgresql_root
   networks:
     - traefik-public
   deploy:
     replicas: 1
     restart_policy:
       condition: any
       delay: 5s
       window: 120s
     update_config:
       parallelism: 1
       monitor: 60s
       failure_action: rollback
       order: stop-first
     placement:
       constraints: [node.role == worker]
     resources:
       limits:
         cpus: '2'
         memory: 2048M
       reservations:
         cpus: '0.5'
         memory: 512M


  postgres-backup:
    image: registry.example.ru/postgres:15.3
    depends_on:
      - postgres
    environment:
      - BACKUP_NUM_KEEP=30
      - BACKUP_FREQUENCY=1d
      - PASSWORD=/run/secrets/postgresql_root
    secrets:
      - postgresql_root
    volumes:
      - /docker/backup/postgres_dump:/dump
      - /etc/localtime:/etc/localtime:ro
    entrypoint: |
      bash -c 'bash -s <<EOF
      trap "break;exit" SIGHUP SIGINT SIGTERM
      sleep 2m
      export PGPASSWORD=`cat $$PASSWORD`
      while /bin/true; do
        pg_dumpall -U postgres -h postgres | gzip > /dump/dump_\`date +%d-%m-%Y"_"%H_%M_%S\`.sql.gz
        ls -tr /dump/dump_*.gz | head -n -"$$BACKUP_NUM_KEEP" | xargs -r rm
        sleep $$BACKUP_FREQUENCY
      done
      EOF'
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 120s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]


 mysql:
   image: registry.example.ru/mariadb:10.8
   environment:
     - MARIADB_AUTO_UPGRADE=1
     - MARIADB_ROOT_PASSWORD_FILE=/run/secrets/mysql_root
   ports:
     - "3306:3306"
   healthcheck:
     test: ["CMD", "mysqladmin", "ping", "-S", "/var/lib/mysql/mysqld.sock", "--silent"]
     interval: 5s
     timeout: 5s
     retries: 10
   secrets:
     - mysql_root
   volumes:
     - /docker/conf/50-server.cnf:/etc/mysql/mariadb.conf.d/50-server.cnf
     - /docker/backup/mysql_dump:/dump:ro
     - /docker/data/init.db/init.sql:/docker-entrypoint-initdb.d/init.sql
     - /docker/data/mysql:/var/lib/mysql
     - /etc/localtime:/etc/localtime:ro
   networks:
     - traefik-public
   deploy:
     replicas: 1
     restart_policy:
       condition: on-failure
     update_config:
       parallelism: 1
       monitor: 60s
       failure_action: rollback
       order: stop-first
     placement:
       constraints: [node.role == worker]


  mysql-backup:
    image: registry.example.ru/mariadb:10.8
    depends_on:
      - mysql
    environment:
      - BACKUP_NUM_KEEP=30
      - BACKUP_FREQUENCY=1d
      - ROOT=/run/secrets/mysql_root
    secrets:
      - mysql_root
    volumes:
      - /docker/backup/mysql_dump:/dump
      - /etc/localtime:/etc/localtime:ro
    entrypoint: |
      bash -c 'bash -s <<EOF
      trap "break;exit" SIGHUP SIGINT SIGTERM
      sleep 2m
      while /bin/true; do
        mysqldump -h mysql -p`cat $$ROOT` --events --routines --triggers -A --opt | gzip -c > /dump/dump_\`date +%d-%m-%Y"_"%H_%M_%S\`.sql.gz
        ls -tr /dump/dump_*.sql.gz | head -n -"$$BACKUP_NUM_KEEP" | xargs -r rm
        sleep $$BACKUP_FREQUENCY
      done
      EOF'
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]


 redis:
   image: registry.example.ru/redis:7.0-alpine
   command: redis-server --appendonly yes --loglevel warning
   healthcheck:
     test: ["CMD", "redis-cli", "ping"]
   volumes:
     - /docker/data/redis:/data:Z
     - /etc/localtime:/etc/localtime:ro
   networks:
     - traefik-public
   deploy:
     replicas: 1
     restart_policy:
       condition: any
       delay: 5s
       window: 120s
     update_config:
       parallelism: 1
       monitor: 60s
       failure_action: rollback
       order: stop-first
     placement:
       constraints: [node.role == worker]
     resources:
       limits:
         cpus: '0.25'
         memory: 256M
       reservations:
         cpus: '0.25'
         memory: 128M


 minio:
   image: registry.example.ru/minio:latest
   command: server /data --address ":9000" --console-address ":9001"
   environment:
     MINIO_ROOT_USER: minio
     MINIO_ROOT_PASSWORD_FILE: /run/secrets/minio_root
   secrets:
     - minio_root
   volumes:
     - /etc/localtime:/etc/localtime:ro
     - /docker/data/minio:/data:Z
   networks:
     - traefik-public
   deploy:
     replicas: 1
     restart_policy:
       condition: any
       delay: 5s
       window: 120s
     update_config:
       parallelism: 1
       monitor: 60s
       failure_action: rollback
       order: stop-first
     placement:
       constraints: [node.role == worker]
     labels:
       - "traefik.enable=true"
       - "traefik.http.routers.s3web.rule=Host(`s3web.example.ru`)"
       - "traefik.http.routers.s3web.entrypoints=https"
       - "traefik.http.routers.s3web.tls=true"
       - "traefik.http.routers.s3web.middlewares=WhitelistHome"
       - "traefik.http.services.s3web.loadbalancer.server.port=9001"


  phpmyadmin:
    image: registry.example.ru/phpmyadmin:latest
    environment:
      - PMA_ARBITRARY=0
      - PMA_HOSTS=mysql
      - UPLOAD_LIMIT=500M
      - HIDE_PHP_VERSION=true
    volumes:
      - /etc/localtime:/etc/localtime:ro
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.pma.tls=true"
        - "traefik.http.routers.pma.rule=Host(`pma.example.ru`)"
        - "traefik.http.routers.pma.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.pma.loadbalancer.server.port=80"

  pgadmin:
    image: registry.example.ru/pgadmin4:latest
    environment:
      PGADMIN_DEFAULT_EMAIL: [email protected]
      PGADMIN_DEFAULT_PASSWORD_FILE: /run/secrets/pgadmin
      PGADMIN_LISTEN_PORT: 80
    secrets:
      - pgadmin
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.pgadmin.tls=true"
        - "traefik.http.routers.pgadmin.rule=Host(`pgadmin.example.ru`)"
        - "traefik.http.routers.pgadmin.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.pgadmin.loadbalancer.server.port=80"


  adminer:
    image: registry.example.ru/adminer:latest
    environment:
      - ADMINER_PLUGINS=tinymce
      - ADMINER_DESIGN=nette
      - ADMINER_DEFAULT_SERVER=mysql
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.adminer.tls=true"
        - "traefik.http.routers.adminer.rule=Host(`adminer.example.ru`)"
        - "traefik.http.routers.adminer.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.adminer.loadbalancer.server.port=8080"
      resources:
        limits:
          cpus: '0.25'
          memory: 256M
        reservations:
          cpus: '0.25'
          memory: 128M

secrets:
  postgresql_root:
    external: true
  mysql_root:
    external: true
  mysql_root_synology:
    external: true
  pgadmin:
    external: true
  minio_root:
    external: true

networks:
  traefik-public:
    external: true

Stack dev.yml

version: '3.9'

services:
### DEVELOPMENT
  codeserver:
    image: registry.example.ru/code-server:latest
    command: --auth none --disable-telemetry
    volumes:
      - /docker/conf/codeserver/coder:/home/coder
      - /docker/data/projects:/home/coder/projects
      - /etc/localtime:/etc/localtime:ro
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.codeserver.tls=true"
        - "traefik.http.routers.codeserver.rule=Host(`codeserver.example.ru`)"
        - "traefik.http.routers.codeserver.middlewares=WhitelistHome,authelia@docker,CORS@file"
        - "traefik.http.services.codeserver.loadbalancer.server.port=8080"


  gitlab:
    image: registry.example.ru/gitlab-ce:latest
    environment:
#      GITLAB_SKIP_UNMIGRATED_DATA_CHECK: 'true'
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'https://gitlab.example.ru'
        nginx['listen_port'] = 80
        nginx['listen_https'] = false
        nginx['proxy_set_headers'] = {
        "X-Forwarded-Proto" => "https",
        "X-Forwarded-Ssl" => "on"
         }
        gitlab_rails['smtp_enable'] = true
        gitlab_rails['smtp_address'] = "smtp.mail.ru"
        gitlab_rails['smtp_port'] = 465
        gitlab_rails['smtp_user_name'] = "[email protected]"
        gitlab_rails['smtp_password'] = "paSSw0rd"
        gitlab_rails['smtp_domain'] = "mail.ru"
        gitlab_rails['smtp_authentication'] = "login"
        gitlab_rails['smtp_enable_starttls_auto'] = false
        gitlab_rails['smtp_tls'] = true
        gitlab_rails['smtp_openssl_verify_mode'] = 'peer'
        gitlab_rails['gitlab_email_from'] = '[email protected]'
        gitlab_rails['gitlab_email_reply_to'] = '[email protected]'
        patroni['remove_data_directory_on_rewind_failure'] = true
        patroni['remove_data_directory_on_diverged_timelines'] = true
    ports:
      - "2222:22"
    volumes:
      - /docker/conf/gitlab:/etc/gitlab
      - /docker/data/gitlab:/var/opt/gitlab
      - /etc/localtime:/etc/localtime:ro
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 600s
        failure_action: continue
        order: stop-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.gitlab.tls=true"
        - "traefik.http.routers.gitlab.rule=Host(`gitlab.example.ru`)"
        - "traefik.http.routers.gitlab.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.gitlab.loadbalancer.server.port=80"


  gitlab-runner:
    image: registry.example.ru/gitlab-runner:latest
    volumes:
      - /docker/conf/gitlab-runner:/etc/gitlab-runner
      - /var/run/docker.sock:/var/run/docker.sock
      - /etc/localtime:/etc/localtime:ro
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]


  gitlab-runner-swarm:
    image: registry.example.ru/gitlab-runner:latest
    volumes:
      - /docker/conf/gitlab-runner-swarm:/etc/gitlab-runner
      - /var/run/docker.sock:/var/run/docker.sock
      - /etc/localtime:/etc/localtime:ro
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]


networks:
  traefik-public:
    external: true

Stack cloud.yml

version: "3.9"
services:
  nextcloud:
    image: registry.example.ru/nextcloud:latest
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /docker/data/www/nextcloud.example.ru:/var/www/html
      - /docker/data/nextcloud:/data
      - type: tmpfs
        target: /tmp
    healthcheck:
      test: curl http://127.0.0.1:80/login || exit 1
      start_period: 60s
      interval: 60s
      timeout: 30s
      retries: 15
    depends_on:
      - postgres
      - redis
    environment:
      REDIS_HOST: redis
      POSTGRES_HOST: postgres
      POSTGRES_DB: nextcloud
      POSTGRES_USER: nextcloud
      POSTGRES_PASSWORD_FILE: /run/secrets/postgres_nextcloud
      TRUSTED_PROXIES: 'traefik 172.16.0.0/12 192.168.0.0/16 10.0.0.0/8'
      NEXTCLOUD_TRUSTED_DOMAINS: nextcloud.example.ru
      NEXTCLOUD_DATA_DIR: /data
    secrets:
      - postgres_nextcloud
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      resources:
        limits:
          cpus: '2'
          memory: 768M
        reservations:
          cpus: '1'
          memory: 512M
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.nextcloud.middlewares=nextcloud,nextcloud_redirect"
        - "traefik.http.routers.nextcloud.tls=true"
        - "traefik.http.routers.nextcloud.rule=Host(`nextcloud.example.ru`)"
        - "traefik.http.routers.nextcloud.middlewares=default-headers@file,nextcloud_redirect,CORS@file"
        - "traefik.http.middlewares.nextcloud.headers.customFrameOptionsValue=ALLOW-FROM https://nextcloud.example.ru"
        - "traefik.http.middlewares.nextcloud.headers.contentSecurityPolicy=frame-ancestors 'self' nextcloud.example.ru *.example.ru"
        - "traefik.http.middlewares.nextcloud_redirect.redirectregex.permanent=true"
        - "traefik.http.middlewares.nextcloud_redirect.redirectregex.regex=https://(.*)/.well-known/(card|cal)dav"
        - "traefik.http.middlewares.nextcloud_redirect.redirectregex.replacement=https://$${1}/remote.php/dav/"
        - "traefik.http.services.nextcloud.loadbalancer.server.port=80"
        - "traefik.docker.network=traefik-public"


secrets:
  postgres_nextcloud:
    external: true

networks:
  traefik-public:
    external: true

Stack immich.yml

version: "3.9"
services:
  server:
    image: registry.example.ru/immich-server:release
    command: [ "start.sh", "immich" ]
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /docker/data/immich/upload:/usr/src/app/upload
    depends_on:
      - dbimmich
      - redis
    environment:
      REDIS_HOSTNAME: redis
      DB_HOSTNAME: dbimmich
      DB_USERNAME: immich
      DB_DATABASE_NAME: immich
      DB_PASSWORD_FILE: /run/secrets/postgres_immich
      NODE_ENV: production
      JWT_SECRET: 1234567899098765432132423564767
      LOG_LEVEL: error
      PUBLIC_LOGIN_PAGE_MESSAGE: "My Family Photos and Videos Backup Server"
      REVERSE_GEOCODING_PRECISION: 3
    secrets:
      - postgres_immich
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.immich.rule=Host(`immich.example.ru`)"
        - "traefik.http.routers.immich.entrypoints=https"
        - "traefik.http.routers.immich.tls=true"
        - "traefik.http.routers.immich.middlewares=default-headers@file,CORS@file"
        - "traefik.http.services.immich.loadbalancer.server.port=3001"


  microservices:
    image: registry.example.ru/immich-server:release
    command: [ "start.sh", "microservices" ]
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /docker/data/immich/upload:/usr/src/app/upload
    depends_on:
      - dbimmich
      - redis
      - server
    environment:
      REDIS_HOSTNAME: redis
      DB_HOSTNAME: dbimmich
      DB_USERNAME: immich
      DB_DATABASE_NAME: immich
      DB_PASSWORD_FILE: /run/secrets/postgres_immich
      NODE_ENV: production
      JWT_SECRET: 1234567899098765432132423564767
      LOG_LEVEL: error
      REVERSE_GEOCODING_PRECISION: 3
    secrets:
      - postgres_immich
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]


  machine-learning:
    image: registry.example.ru/immich-machine-learning:release
    volumes:
      - /docker/data/immich/cache:/cache
    environment:
      REDIS_HOSTNAME: redis
      DB_HOSTNAME: dbimmich
      DB_USERNAME: immich
      DB_DATABASE_NAME: immich
      DB_PASSWORD_FILE: /run/secrets/postgres_immich
      LOG_LEVEL: error
      REVERSE_GEOCODING_PRECISION: 3
    secrets:
      - postgres_immich
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]


  postgres-backup-immich:
    image: tensorchord/pgvecto-rs:pg16-v0.2.0
    environment:
      - BACKUP_NUM_KEEP=30
      - BACKUP_FREQUENCY=1d
      - PASSWORD=/run/secrets/postgres_immich
    secrets:
      - postgres_immich
    volumes:
      - /docker/backup/postgres_dump_immich:/dump
      - /etc/localtime:/etc/localtime:ro
    entrypoint: |
      bash -c 'bash -s <<EOF
      trap "break;exit" SIGHUP SIGINT SIGTERM
      sleep 2m
      export PGPASSWORD=`cat $$PASSWORD`
      while /bin/true; do
        pg_dumpall -U immich -h dbimmich | gzip > /dump/dump_\`date +%d-%m-%Y"_"%H_%M_%S\`.sql.gz
        ls -tr /dump/dump_*.gz | head -n -"$$BACKUP_NUM_KEEP" | xargs -r rm
        sleep $$BACKUP_FREQUENCY
      done
      EOF'
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]


 dbimmich:
   image: tensorchord/pgvecto-rs:pg16-v0.2.0
   volumes:
     - /etc/localtime:/etc/localtime:ro
     - /docker/data/immich/postgresql:/var/lib/postgresql/data:Z
   environment:
     - POSTGRES_USER=immich
     - POSTGRES_PASSWORD_FILE=/run/secrets/postgres_immich
     - POSTGRES_DB=immich
     - POSTGRES_INITDB_ARGS=--data-checksums
   secrets:
     - postgres_immich
   networks:
     - traefik-public
   deploy:
     replicas: 1
     restart_policy:
       condition: any
       delay: 5s
       window: 120s
     update_config:
       parallelism: 1
       monitor: 60s
       failure_action: rollback
       order: stop-first
     placement:
       constraints: [node.role == worker]
     resources:
       limits:
         cpus: '2'
         memory: 2048M
       reservations:
         cpus: '0.5'
         memory: 512M


secrets:
  postgres_immich:
    external: true


networks:
  traefik-public:
    external: true

Stack dashboard.yml

version: '3.9'

services:
  homer:
    image: registry.example.ru/homer:latest
    volumes:
      - /docker/conf/homer:/www/assets
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.homer.rule=Host(`homer.example.ru`)"
        - "traefik.http.routers.homer.entrypoints=https"
        - "traefik.http.routers.homer.tls=true"
        - "traefik.http.routers.homer.middlewares=WhitelistHome"
        - "traefik.http.services.homer.loadbalancer.server.port=8080"


  heimdall:
    image: registry.example.ru/heimdall:latest
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Moscow
    volumes:
      - /docker/conf/heimdall:/config
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.heimdall.rule=Host(`heimdall.example.ru`)"
        - "traefik.http.routers.heimdall.entrypoints=https"
        - "traefik.http.routers.heimdall.tls=true"
        - "traefik.http.routers.heimdall.middlewares=WhitelistHome"
        - "traefik.http.services.heimdall.loadbalancer.server.port=80"


  homarr:
    image: ghcr.io/ajnart/homarr:latest
    volumes:
      - /docker/conf/homarr/configs:/app/data/configs
      - /docker/conf/homarr/icons:/app/public/icons
      - /docker/conf/homarr/data:/data
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.homarr.rule=Host(`homarr.example.ru`)"
        - "traefik.http.routers.homarr.entrypoints=https"
        - "traefik.http.routers.homarr.tls=true"
        - "traefik.http.routers.homarr.middlewares=WhitelistHome"
        - "traefik.http.services.homarr.loadbalancer.server.port=7575"


networks:
  traefik-public:
    external: true

Stack service.yml

version: '3.9'

services:
  trilium:
    image: registry.example.ru/trilium:0.45-latest
    environment:
      - TRILIUM_DATA_DIR=/data
    volumes:
      - /docker/data/trilium:/data
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.trilium.rule=Host(`trilium.example.ru`)"
        - "traefik.http.routers.trilium.entrypoints=https"
        - "traefik.http.routers.trilium.tls=true"
        - "traefik.http.routers.trilium.middlewares=authelia@docker,CORS@file"
        - "traefik.http.services.trilium.loadbalancer.server.port=8080"


  vault:
    image: registry.example.ru/vault
    command: vault server -config=/vault/config/vault.json
    environment:
      - VAULT_ADDR=http://0.0.0.0:8200
      - VAULT_API_ADDR=http://0.0.0.0:8200
      - VAULT_ADDRESS=http://0.0.0.0:8200
    volumes:
      - /docker/conf/vault:/vault
      - /docker/conf/vault/file:/vault/file
    cap_add:
      - IPC_LOCK
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.vault.rule=Host(`vault.example.ru`)"
        - "traefik.http.routers.vault.entrypoints=https"
        - "traefik.http.routers.vault.tls=true"
        - "traefik.http.routers.vault.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.vault.loadbalancer.server.port=8200"


  vaultwarden:
    image: registry.example.ru/server:latest
    environment:
      - WEBSOCKET_ENABLED=true  # Enable WebSocket notifications.
      - SIGNUPS_ALLOWED=false
    volumes:
      - /docker/conf/vaultwarden:/data
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.vaultwarden.tls=true"
        - "traefik.http.routers.vaultwarden.middlewares=default-headers@file,CORS@file"
        - "traefik.http.routers.vaultwarden.rule=Host(`vaultwarden.example.ru`)"
        - "traefik.http.services.vaultwarden.loadbalancer.server.port=80"


  ipam:
    image: registry.example.ru/ipam:latest
    volumes:
      - /etc/localtime:/etc/localtime:ro
    environment:
      - MYSQL_ENV_MYSQL_DB=ipam
      - MYSQL_ENV_MYSQL_USER=ipam
      - MYSQL_ENV_MYSQL_PASSWORD=paSSw0rd
      - MYSQL_ENV_MYSQL_HOST=mysql
    depends_on:
      - mysql
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.ipam.tls=true"
        - "traefik.http.routers.ipam.rule=Host(`ipam.example.ru`)"
        - "traefik.http.routers.ipam.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.ipam.loadbalancer.server.port=80"


  ocs:
    image: registry.example.ru/ocsinventory-docker-image:latest
    volumes:
      - /etc/localtime:/etc/localtime:ro
    environment:
      OCS_DB_SERVER: mysql
      OCS_DB_USER: ocs
      OCS_DB_PASS: paSSw0rd
      OCS_DB_NAME: ocsweb
      OCS_OPT_DBI_PRINT_ERROR: 1
    depends_on:
      - mysql
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.ocs.tls=true"
        - "traefik.http.routers.ocs.rule=Host(`ocs.example.ru`)"
        - "traefik.http.routers.ocs.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.ocs.loadbalancer.server.port=80"


  syncthing:
    image: registry.example.ru/syncthing:latest
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /docker/conf/syncthing:/var/syncthing/config
      - /docker/data/syncthing:/var/syncthing
    ports:
      - "22000:22000"
      - "21027:21027/udp"
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: stop-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.syncthing.rule=Host(`syncthing.example.ru`)"
        - "traefik.http.routers.syncthing.entrypoints=https"
        - "traefik.http.routers.syncthing.tls=true"
        - "traefik.http.routers.syncthing.middlewares=WhitelistHome,authelia@docker,CORS@file"
        - "traefik.http.services.syncthing.loadbalancer.server.port=8384"


  altmirror:
    image: registry.example.ru/altmirror:latest
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /docker/data/alt-mirror:/alt-mirror
    networks:
      - traefik-public
    ports:
      - 8080:80
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == manager]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.altmirror.rule=Host(`altmirror.example.ru`)"
        - "traefik.http.routers.altmirror.entrypoints=https"
        - "traefik.http.routers.altmirror.tls=true"
        - "traefik.http.routers.altmirror.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.altmirror.loadbalancer.server.port=80"


 rutorrent:
   image: registry.example.ru/rutorrent
   environment:
     - PUID=1000
     - PGID=1000
   ports:
     - 51413:51413
     - 6881:6881/udp
   volumes:
     - /docker/conf/rutorrent:/config
     - /media/TORRENTS:/downloads
   networks:
     - traefik-public
   deploy:
     replicas: 1
     restart_policy:
       condition: on-failure
     update_config:
       parallelism: 1
       monitor: 60s
       failure_action: rollback
       order: start-first
     placement:
       constraints: [node.role == worker]
     labels:
       - "traefik.enable=true"
       - "traefik.http.routers.rutorrent.rule=Host(`torrents.example.ru`)"
       - "traefik.http.routers.rutorrent.entrypoints=https"
       - "traefik.http.routers.rutorrent.tls=true"
       - "traefik.http.routers.rutorrent.middlewares=WhitelistHome"
       - "traefik.http.services.rutorrent.loadbalancer.server.port=80"


  speedtest:
    image: registry.example.ru/latest:latest
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.speedtest.rule=Host(`speedtest.example.ru`)"
        - "traefik.http.routers.speedtest.entrypoints=https"
        - "traefik.http.routers.speedtest.tls=true"
        - "traefik.http.routers.speedtest.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.speedtest.loadbalancer.server.port=3000"


  paperless:
    image: ghcr.io/paperless-ngx/paperless-ngx:latest
    depends_on:
      - gotenberg
      - tika
    healthcheck:
      test: ["CMD", "curl", "-fs", "-S", "--max-time", "2", "http://localhost:8000"]
      interval: 30s
      timeout: 10s
      retries: 5
    environment:
      - PAPERLESS_TIME_ZONE=Europe/Moscow
      - PAPERLESS_ADMIN_USER=admin
      - PAPERLESS_ADMIN_PASSWORD=paSSw0rd
      - PAPERLESS_URL=https://paper.example.ru
      - [email protected]
      - PAPERLESS_REDIS=redis://redis:6379
      - PAPERLESS_TIKA_ENABLED=1
      - PAPERLESS_TIKA_GOTENBERG_ENDPOINT=http://gotenberg:3000
      - PAPERLESS_TIKA_ENDPOINT=http://tika:9998
    volumes:
      - /docker/data/paperless/data:/usr/src/paperless/data
      - /docker/data/paperless/media:/usr/src/paperless/media
      - /docker/data/paperless/export:/usr/src/paperless/export
      - /docker/data/paperless/consume:/usr/src/paperless/consume
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: stop-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.paperless.rule=Host(`paper.example.ru`)"
        - "traefik.http.routers.paperless.entrypoints=https"
        - "traefik.http.routers.paperless.tls=true"
        - "traefik.http.routers.paperless.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.paperless.loadbalancer.server.port=8000"

  gotenberg:
    image: thecodingmachine/gotenberg
    environment:
      - DISABLE_GOOGLE_CHROME=1
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]

  tika:
    image: apache/tika
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]


 jellyfin:
   image: registry.example.ru/jellyfin
   volumes:
     - /docker/conf/jellyfin/config:/config
     - /media/ФИЛЬМЫ:/data/movies:ro
   environment:
     - PUID=1000
     - PGID=1000
     - TZ=Europe/Moscow
   networks:
     - traefik-public
   deploy:
     replicas: 1
     restart_policy:
       condition: on-failure
     update_config:
       parallelism: 1
       monitor: 60s
       failure_action: rollback
       order: stop-first
     placement:
       constraints: [node.role == worker]
     labels:
       - "traefik.enable=true"
       - "traefik.http.routers.jellyfin.rule=Host(`jellyfin.example.ru`)"
       - "traefik.http.routers.jellyfin.entrypoints=https"
       - "traefik.http.routers.jellyfin.tls=true"
       - "traefik.http.routers.jellyfin.middlewares=WhitelistHome,default-headers@file"
       - "traefik.http.services.jellyfin.loadbalancer.server.port=8096"



networks:
  traefik-public:
    external: true

Stack archive.yml

version: '3.9'

services:
### LOCAL ARCHIVE
  archivebox:
    image: registry.example.ru/archivebox
    volumes:
      - /docker/data/archivebox:/data
    environment:
      - ALLOWED_HOSTS=*
      - MEDIA_MAX_SIZE=750m
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.archive.rule=Host(`archive.example.ru`)"
        - "traefik.http.routers.archive.entrypoints=https"
        - "traefik.http.routers.archive.tls=true"
        - "traefik.http.routers.archive.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.archive.loadbalancer.server.port=8000"


 ytdl_material:
   image: registry.example.ru/youtubedl-material:latest
   environment:
     - ALLOW_CONFIG_MUTATIONS=true
     - ytdl_use_local_db=true
     - write_ytdl_config=true
   volumes:
     - /docker/conf/ytdl/appdata:/app/appdata
     - /media/YOUTUBE:/app/video
     - /docker/conf/ytdl/subscriptions:/app/subscriptions
     - /docker/conf/ytdl/users:/app/users
   networks:
     - traefik-public
   deploy:
     replicas: 1
     restart_policy:
       condition: any
       delay: 5s
       window: 120s
     update_config:
       parallelism: 1
       monitor: 60s
       failure_action: rollback
       order: start-first
     placement:
       constraints: [node.role == worker]
     labels:
       - "traefik.enable=true"
       - "traefik.http.routers.ytdl.rule=Host(`youtube.example.ru`)"
       - "traefik.http.routers.ytdl.entrypoints=https"
       - "traefik.http.routers.ytdl.tls=true"
       - "traefik.http.routers.ytdl.middlewares=WhitelistHome"
       - "traefik.http.services.ytdl.loadbalancer.server.port=17442"


  kiwix:
    image: registry.example.ru/kiwix-serve:3.5.0
    volumes:
      - /docker/data/wikipedia:/data
    command:
      wikipedia_ru_all_maxi_2022-12.zim
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.kiwix.rule=Host(`wikipedia.example.ru`)"
        - "traefik.http.routers.kiwix.entrypoints=https"
        - "traefik.http.routers.kiwix.tls=true"
        - "traefik.http.routers.kiwix.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.kiwix.loadbalancer.server.port=8080"


  offline-map:
    image: registry.example.ru/offline-map:latest
    volumes:
      - /docker/data/maps:/usr/share/nginx/html/map:ro
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.offline-map.rule=Host(`map.example.ru`)"
        - "traefik.http.routers.offline-map.entrypoints=https"
        - "traefik.http.routers.offline-map.tls=true"
        - "traefik.http.routers.offline-map.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.offline-map.loadbalancer.server.port=80"


networks:
  traefik-public:
    external: true

Stack update.yml

version: "3.9"
services:
  shepherd:
    image: registry.example.ru/shepherd:latest
    volumes:
      - /root/.docker/config.json:/root/.docker/config.json:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      TZ: 'Europe/Moscow'
      SLEEP_TIME: '5m'
      IGNORELIST_SERVICES: 'shepherd control_portainer service_archivebox-cron dev_gitlab www_traefik www_npm'
      FILTER_SERVICES: ''
      VERBOSE: 'true'
      IMAGE_AUTOCLEAN_LIMIT: '5'
      WITH_REGISTRY_AUTH: 'true'
      UPDATE_OPTIONS: '--update-delay=30s'
      ROLLBACK_OPTIONS: '--rollback-delay=0s'
      ROLLBACK_ON_FAILURE: 'true'
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == manager]


networks:
  traefik-public:
    external: true

Stack backups.yml

version: '3.9'

services:
  duplicati:
    image: registry.example.ru/duplicati:latest
    environment:
      - PUID=0
      - PGID=0
      - TZ=Europe/Moscow
    volumes:
      - /docker/conf/duplicati:/config
      - /docker:/docker
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.duplicati.rule=Host(`duplicati.example.ru`)"
        - "traefik.http.routers.duplicati.entrypoints=https"
        - "traefik.http.routers.duplicati.tls=true"
        - "traefik.http.services.duplicati.loadbalancer.server.port=8200"
        - "traefik.http.routers.duplicati.middlewares=WhitelistHome,authelia@docker,CORS@file"


networks:
  traefik-public:
    external: true

Stack gpt.yml

version: '3.9'

services:
  private-gpt:
    image: registry.example.ru/privategpt:latest
    environment:
      - PORT=8080
      - PGPT_PROFILES=docker
      - PGPT_MODE=local
      - PGPT_HF_REPO_ID=IlyaGusev/saiga_mistral_7b_gguf
      - PGPT_HF_MODEL_FILE=model-q4_K.gguf
      - PGPT_EMBEDDING_HF_MODEL_NAME=BAAI/bge-small-en-v1.5
    volumes:
      - /docker/data/private-gpt/local_data:/home/worker/app/local_data
      - /docker/data/private-gpt/models:/home/worker/app/models
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: stop-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.gpt.rule=Host(`gpt.example.ru`)"
        - "traefik.http.routers.gpt.entrypoints=https"
        - "traefik.http.routers.gpt.tls=true"
        - "traefik.http.routers.gpt.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.gpt.loadbalancer.server.port=8080"


  qdrant:
    image: qdrant/qdrant:latest
    volumes:
      - /docker/data/qdrant:/qdrant/storage
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: stop-first
      placement:
        constraints: [node.role == worker]
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.qdrant.rule=Host(`qdrant.example.ru`)"
        - "traefik.http.routers.qdrant.entrypoints=https"
        - "traefik.http.routers.qdrant.tls=true"
        - "traefik.http.routers.qdrant.middlewares=WhitelistHome,CORS@file"
        - "traefik.http.services.qdrant.loadbalancer.server.port=6333"


networks:
  traefik-public:
    external: true

Stack zcrontab.yml

version: '3.9'

services:
  swarm-cronjob:
    image: crazymax/swarm-cronjob:latest
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      - "TZ=Europe/Moscow"
      - "LOG_LEVEL=info"
      - "LOG_JSON=false"
    networks:
      - traefik-public
    deploy:
      replicas: 1
      restart_policy:
        condition: any
        delay: 5s
        window: 120s
      update_config:
        parallelism: 1
        monitor: 60s
        failure_action: rollback
        order: start-first
      placement:
        constraints: [node.role == manager]


  nextcloud-cron-job:
    image: registry.example.ru/nextcloud:latest
    networks:
      - traefik-public
    command: su www-data -s /usr/local/bin/php -f /var/www/html/cron.php
    environment:
      REDIS_HOST: redis
      POSTGRES_HOST: postgres
      POSTGRES_DB: nextcloud
      POSTGRES_USER: nextcloud
      POSTGRES_PASSWORD_FILE: /run/secrets/postgres_nextcloud
    secrets:
      - postgres_nextcloud
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /docker/data/www/nextcloud.example.ru:/var/www/html
      - /docker/data/nextcloud:/data
      - type: tmpfs
        target: /tmp
    deploy:
      mode: replicated
      replicas: 0
      labels:
        - "swarm.cronjob.enable=true"
        - "swarm.cronjob.schedule=*/5  * * * *"
        - "swarm.cronjob.skip-running=false"
      restart_policy:
        condition: none


  nextcloud-cron2-job:
    image: registry.example.ru/nextcloud:latest
    networks:
      - traefik-public
    command: su www-data -s /data/cron.sh
    environment:
      REDIS_HOST: redis
      POSTGRES_HOST: postgres
      POSTGRES_DB: nextcloud
      POSTGRES_USER: nextcloud
      POSTGRES_PASSWORD_FILE: /run/secrets/postgres_nextcloud
    secrets:
      - postgres_nextcloud
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /docker/data/www/nextcloud.example.ru:/var/www/html
      - /docker/data/nextcloud:/data
      - type: tmpfs
        target: /tmp
    deploy:
      mode: replicated
      replicas: 0
      labels:
        - "swarm.cronjob.enable=true"
        - "swarm.cronjob.schedule=0 4 * * *"
        - "swarm.cronjob.skip-running=false"
      restart_policy:
        condition: none


  gitlab-cron-backup-job:
    image: registry.example.ru/gitlab-ce:latest
    networks:
      - traefik-public
    command: su git -s /usr/bin/gitlab-backup create
    volumes:
      - /docker/conf/gitlab:/etc/gitlab
      - /docker/data/gitlab:/var/opt/gitlab
      - /etc/localtime:/etc/localtime:ro
    deploy:
      mode: replicated
      replicas: 0
      labels:
        - "swarm.cronjob.enable=true"
        - "swarm.cronjob.schedule=0 1 * * *"
        - "swarm.cronjob.skip-running=false"
      restart_policy:
        condition: none


  paperless-cron-backup-job:
    image: paperlessngx/paperless-ngx
    networks:
      - traefik-public
    command: document_exporter /usr/src/paperless/export --zip
    volumes:
      - /docker/data/paperless/data:/usr/src/paperless/data
      - /docker/data/paperless/media:/usr/src/paperless/media
      - /docker/data/paperless/export:/usr/src/paperless/export
      - /docker/data/paperless/consume:/usr/src/paperless/consume
    deploy:
      mode: replicated
      replicas: 0
      labels:
        - "swarm.cronjob.enable=true"
        - "swarm.cronjob.schedule=0 1 * * *"
        - "swarm.cronjob.skip-running=false"
      restart_policy:
        condition: none

secrets:
  postgres_nextcloud:
    external: true


networks:
  traefik-public:
    external: true

Создание секретов

 echo "paSSw0rd" | docker secret create mysql_root -
 echo "paSSw0rd" | docker secret create minio_root -
 echo "paSSw0rd" | docker secret create mysql_root_zabbix -
 echo "paSSw0rd" | docker secret create mysql_zabbix -
 echo "paSSw0rd" | docker secret create fluentd -
 echo "paSSw0rd" | docker secret create smtp_passwd -
 echo "paSSw0rd" | docker secret create kibana_system_passwd -
 echo "paSSw0rd" | docker secret create pgadmin -
 echo "paSSw0rd" | docker secret create postgres_nextcloud -
 echo "paSSw0rd" | docker secret create postgresql_root -
 echo "paSSw0rd" | docker secret create postgres_immich -
К началу