使用 Docker Compose 管理容器服务

在早期,我通过 docker run 命令手动运行容器,这在服务数量较少时尚可应付。但随着了解并使用的容器增多,手动创建变得低效且混乱。同时,先前发布过一次 Docker 常用服务相关代码,评论区也推荐我使用 Docker Compose。因此,我逐步迁移到使用 Docker Compose 进行容器编排,统一管理后端数据库、前端代理、开发应用与运维服务。

本文整理并展示了我当前服务器上运行的主要容器配置,包括 nginx、mysql、wordpress、vaultwarden 等服务。相关配置需要配合 .env 文件变量,下面的内容部分细节只针对我的服务器调试,如果需要可能需根据你的服务器自行调整。如果你有优化或者更好的建议也可以在下面评论中与我进行沟通交流。

docker-compose.yml

# 定义两个自定义网络,实现服务间的隔离
networks:
  backend:
    driver: bridge  # 后端服务间通信网络
  frontend:
    driver: bridge  # 前端服务与外部通信网络

services:
  nginx:
    image: nginx
    container_name: nginx
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ${ROOT_PATH}/nginx/nginx.conf:/etc/nginx/nginx.conf
      - ${ROOT_PATH}/nginx/conf.d:/etc/nginx/conf.d
      - ${ROOT_PATH}/nginx/ssl:/etc/nginx/ssl
      - ${ROOT_PATH}/nginx/html:/usr/share/nginx/html
      - ${ROOT_PATH}/nginx/log:/var/log/nginx
    environment:
      - TZ=Asia/Shanghai
    labels:
      # Nginx 配合 acme.sh 自动加载证书,支持热更新。
      - sh.acme.autoload.domain=${CAME_SH_AUTOLOAD_DOMAIN}
    networks:
      - frontend
      - backend
    healthcheck:
      test: ["CMD-SHELL", "nginx -t || exit 1"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s

  mysql:
    image: mysql
    container_name: mysql
    restart: always
    expose:
      - "3306"
    volumes:
      - ${ROOT_PATH}/mysql/conf.d:/etc/mysql/conf.d
      - ${ROOT_PATH}/mysql/data:/var/lib/mysql
      - ${ROOT_PATH}/mysql/log:/var/log/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - TZ=Asia/Shanghai
    command:
      - --lower_case_table_names=1
      - --sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
    networks:
      - backend
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:latest
    container_name: redis
    restart: always
    expose:
      - "6379"
    volumes:
      - ${ROOT_PATH}/redis/data:/data
      - ${ROOT_PATH}/redis/redis.conf:/usr/local/etc/redis/redis.conf
    command: redis-server /usr/local/etc/redis/redis.conf
    networks:
      - backend
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 3
  
  wordpress:
    image: wordpress:latest
    container_name: wordpress
    restart: always
    expose:
      - "80"
    volumes:
      - ${ROOT_PATH}/wordpress:/var/www/html
    environment:
      - WORDPRESS_DB_NAME=${WORDPRESS_DB_NAME}
      - WORDPRESS_DB_HOST=${WORDPRESS_DB_HOST}
      - WORDPRESS_DB_USER=${WORDPRESS_DB_USER}
      - WORDPRESS_DB_PASSWORD=${WORDPRESS_DB_PASSWORD}
    networks:
      - backend
    healthcheck:
      test: ["CMD-SHELL", "curl -s -o /dev/null -w '%{http_code}' http://localhost/wp-login.php | grep -qE '2[0-9]{2}|3[0-9]{2}|403|404' || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 180s
    depends_on:
      mysql:
        condition: service_healthy
  
  phpmyadmin:
    image: phpmyadmin
    container_name: phpmyadmin
    restart: always
    expose:
      - "80"
    environment:
      - PMA_HOST=mysql
      - PMA_PORT=3306
      - TZ=Asia/Shanghai
    networks:
      - backend
    healthcheck:
      test: ["CMD", "curl", "-fsSL", "http://localhost"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s
    depends_on:
      mysql:
        condition: service_healthy

  vaultwarden:
    image: vaultwarden/server
    container_name: vaultwarden
    restart: always
    expose:
    - "80"
    volumes:
    - ${ROOT_PATH}/vaultwarden:/data
    environment:
    - DATABASE_URL=mysql://${VAULTWARDEN_DATABASE_USER}:${VAULTWARDEN_DATABASE_PASSWORD}@mysql/vaultwarden
    - ADMIN_TOKEN=${VAULTWARDEN_ADMIN_TOKEN}
    - RUST_BACKTRACE=1
    networks:
      - backend
    healthcheck:
      test: ["CMD", "curl", "-fsSL", "http://localhost"]
      interval: 30s
      timeout: 15s
      retries: 3
      start_period: 30s
    depends_on:
      mysql:
        condition: service_healthy

  acme.sh:
    image: neilpang/acme.sh
    container_name: acme.sh
    restart: always
    volumes:
      - ${ROOT_PATH}/acme.sh:/acme.sh
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      - DP_Id=${CAME_SH_DNSPOD_ID}
      - DP_Key=${CAME_SH_DNSPOD_KEY}
      - DEPLOY_DOCKER_CONTAINER_LABEL=sh.acme.autoload.domain=${CAME_SH_AUTOLOAD_DOMAIN}
      - DEPLOY_DOCKER_CONTAINER_KEY_FILE="/etc/nginx/ssl/${CAME_SH_AUTOLOAD_DOMAIN}/${CAME_SH_AUTOLOAD_DOMAIN}.key"
      - DEPLOY_DOCKER_CONTAINER_CERT_FILE="/etc/nginx/ssl/${CAME_SH_AUTOLOAD_DOMAIN}/${CAME_SH_AUTOLOAD_DOMAIN}.cer"
      - DEPLOY_DOCKER_CONTAINER_CA_FILE="/etc/nginx/ssl/${CAME_SH_AUTOLOAD_DOMAIN}/ca.cer"
      - DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE="/etc/nginx/ssl/${CAME_SH_AUTOLOAD_DOMAIN}/fullchain.cer"
      - DEPLOY_DOCKER_CONTAINER_RELOAD_CMD="docker compose exec nginx nginx -s reload"
    command: daemon
    networks:
      - backend

  watchtower:
    image: containrrr/watchtower
    container_name: watchtower
    restart: always
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - TZ=Asia/Shanghai
    command:
      - --cleanup=true
    networks:
      - backend
  
  minecraft:
    image: itzg/minecraft-server
    container_name: minecraft-server
    restart: always
    tty: true
    stdin_open: true
    ports:
      - "25565:25565"
    environment:
      - EULA=TRUE
      - MAX_PLAYERS=8
      - TZ=Asia/Shanghai
      - DIFFICULTY=2
      - ENABLE_COMMAND_BLOCK=true
    volumes:
      - ${ROOT_PATH}/minecraft:/data
    networks:
      - backend

  beszel:
    image: henrygd/beszel:latest
    container_name: beszel
    restart: always
    expose:
      - "8090"
    volumes:
      - ${ROOT_PATH}/beszel:/beszel_data
    healthcheck:
      test: ['CMD', '/beszel', 'health', '--url', 'http://localhost:8090']
      start_period: 5s
      interval: 120s
    networks:
      - frontend
  
  beszel-agent:
    image: henrygd/beszel-agent:latest
    container_name: beszel-agent
    restart: always
    network_mode: host
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    healthcheck:
      test: ['CMD', '/agent', 'health']
      start_period: 5s
      interval: 120s
    environment:
      PORT: 45876
      KEY: '<公钥>'

自定义网络:

backend 用于内部服务通信(MySQL、Redis、WordPress、Vaultwarden 等)

frontend 用于暴露 Nginx、监控等对外服务

.env 文件

# 项目根路径映射(用于挂载)
ROOT_PATH=/home/halon/apps

# 域名配置
# 替换为你的网站域名
CAME_SH_AUTOLOAD_DOMAIN="example.com"

# ACME DNSPod 证书自动签发
CAME_SH_DNSPOD_ID="DNSPod ID"
CAME_SH_DNSPOD_KEY="DNSPod Key"

# MySQL 配置
MYSQL_ROOT_PASSWORD="MySQL root 密码"

# WordPress 数据库
WORDPRESS_DB_NAME=WordPress 数据库名称
WORDPRESS_DB_HOST=WordPress 数据库主机名称
WORDPRESS_DB_USER=WordPress 数据库用户名
WORDPRESS_DB_PASSWORD=WordPress 数据库密码

# Vaultwarden 配置
VAULTWARDEN_DATABASE_USER="Vaultwarden 数据库用户名"
VAULTWARDEN_DATABASE_PASSWORD="Vaultwarden 数据库密码"
VAULTWARDEN_ADMIN_TOKEN='Vaultwarden Admin Token'

上述两个文件需要放置在一起,以供执行 Docker Compose 时能够寻找到相对应的变量。

评论

《 “使用 Docker Compose 管理容器服务” 》 有 2 条评论

  1. nato-words 的头像

    为啥有2个发表评论的框框

    1. 管理员 的头像

      主题设置出错了,刚更正好😂

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注