陈承沛头像

Docker Compose统一管理nginx redis haproxy容器

一、Docker Compose介绍

Docker Compose 是一个单机环境下的多容器编排工具,通过 YAML 文件声明式地定义和管理多个相关容器,实现一键启动、停止和配置。

1.1为什么说它是「单机」?

  • Compose 只运行在一台机器上
  • 所有容器共享这台机器的:
    • Docker 引擎
    • 网络
    • 文件系统
  • 不支持跨主机调度

所以叫 单机工具,不是集群工具

1.2为什么说它是「多容器」?

  • 一个 Compose 项目里可以定义多个 service
  • 每个 service 通常对应一个容器
  • 这些容器之间有明确关系(依赖、通信、数据共享)
services:
  web:
  db:
  redis:

本质就是 管理一组容器

1.3为什么说它是「编排工具」?

它做的事情正是“编排”的含义:

编排能力Compose 是否支持
定义容器关系✅
启动顺序控制✅
网络互通✅
数据卷管理✅
环境变量配置✅
一键启停✅

它不是“高级编排平台”,但确实是编排工具

1.4一个容易混淆的点

Compose ≠ 生产级编排平台

对比项Docker ComposeKubernetes
运行范围单机多机集群
自动伸缩❌✅
高可用❌✅
自愈能力❌✅
学习成本低高

Compose 是轻量级编排工具

1.5Docker Compose 解决的本质问题

它解决的是:

  1. ✅ 多容器协作
  2. ✅ 配置集中管理
  3. ✅ 环境一致性
  4. ✅ 启动流程自动化
  5. ✅ 降低运维复杂度

1.6Docker Compose适用场景判断

场景是否适合 Compose
本地开发环境✅ 非常适合
测试环境✅ 非常适合
CI/CD✅ 非常适合
小项目生产✅ 可以用
单机私有化部署✅ 适合
教学 / 演示 / 培训✅ 适合
高可用生产❌ 不适合
自动扩缩容❌ 不适合
多机集群❌ 不适合
大型微服务❌ 不适合

二、先确认现状

2.1把三个容器的真实配置全导出来

[root@ubuntu2404 docker]#cd /data/docker

# === 通用信息:镜像、重启策略、网络、端口、挂载 ===
[root@ubuntu2404 docker]#for c in myredis mynginx myhaproxy; do
   echo "=============== $c ==============="
   docker inspect $c --format '
 镜像:      {{.Config.Image}}
 重启策略:  {{.HostConfig.RestartPolicy.Name}}
 网络模式:  {{.HostConfig.NetworkMode}}
 PID模式:   {{.HostConfig.PidMode}}
 只读根FS:  {{.HostConfig.ReadonlyRootfs}}
 端口绑定:  {{json .HostConfig.PortBindings}}
 挂载:      {{json .Mounts}}
 命令:      {{json .Config.Cmd}}
 入口:      {{json .Config.Entrypoint}}
 环境变量:  {{json .Config.Env}}
 标签:      {{json .Config.Labels}}
 日志驱动:  {{.HostConfig.LogConfig.Type}}
 日志参数:  {{json .HostConfig.LogConfig.Config}}
 ulimits:   {{json .HostConfig.Ulimits}}'
 done

=============== myredis ===============

镜像:      redis:8.2.11-alpine3.24.4
重启策略:  unless-stopped
网络模式:  test-net
PID模式:   
只读根FS:  false
端口绑定:  {}
挂载:      [{"Type":"volume","Name":"redis-data","Source":"/data/docker/volumes/redis-data/_data","Destination":"/data/redis","Driver":"local","Mode":"z","RW":true,"Propagation":""}]
命令:      ["/apps/redis/bin/redis-server","--dir","/data/redis","--appendonly","yes"]
入口:      null
环境变量:  ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"]
标签:      {"description":"Docker 容器基础镜像","maintainer":"陈承沛 <2088346053@qq.com>","website":"https://www.chenchengpei.cn"}
日志驱动:  json-file
日志参数:  {"max-file":"3","max-size":"100m"}
ulimits:   [{"Name":"nofile","Hard":65536,"Soft":65536}]
=============== mynginx ===============

镜像:      nginx:1.30.6-alpine3.24.4
重启策略:  unless-stopped
网络模式:  test-net
PID模式:   
只读根FS:  false
端口绑定:  {"80/tcp":[{"HostIp":"127.0.0.1","HostPort":"8088"}]}
挂载:      [{"Type":"bind","Source":"/data/docker/nginx-logs","Destination":"/apps/nginx/logs","Mode":"","RW":true,"Propagation":"rslave"}]
命令:      ["/apps/nginx/sbin/nginx","-g","daemon off;"]
入口:      ["/myserver.sh"]
环境变量:  ["SERVER=www.chenchengpei.cn","PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"]
标签:      {"description":"Docker 容器基础镜像","maintainer":"陈承沛 <2088346053@qq.com>","website":"https://www.chenchengpei.cn"}
日志驱动:  json-file
日志参数:  {"max-file":"3","max-size":"100m"}
ulimits:   [{"Name":"nofile","Hard":65536,"Soft":65536}]
=============== myhaproxy ===============

镜像:      haproxy:3.2.26-alpine3.24.4
重启策略:  unless-stopped
网络模式:  test-net
PID模式:   
只读根FS:  false
端口绑定:  {"80/tcp":[{"HostIp":"127.0.0.1","HostPort":"8080"}],"8404/tcp":[{"HostIp":"127.0.0.1","HostPort":"8404"}]}
挂载:      []
命令:      ["/apps/haproxy/sbin/haproxy","-f","/apps/haproxy/conf/haproxy.cfg","-db"]
入口:      null
环境变量:  ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"]
标签:      {"description":"Docker 容器基础镜像","maintainer":"陈承沛 <2088346053@qq.com>","website":"https://www.chenchengpei.cn"}
日志驱动:  json-file
日志参数:  {"max-file":"3","max-size":"100m"}
ulimits:   [{"Name":"nofile","Hard":65536,"Soft":65536}]

2.2Redis 专属

#redis config
[root@ubuntu2404 docker]#docker exec myredis /apps/redis/bin/redis-cli -a chenchengpei_redis_2026 --no-auth-warning config get dir
dir
/data/redis

#数据目录对齐

[root@ubuntu2404 docker]#docker exec myredis /apps/redis/bin/redis-cli -a chenchengpei_redis_2026 --no-auth-warning config get appendonly
appendonly
yes

#AOF 持久化确认开启

#密码验证
[root@ubuntu2404 docker]#docker exec myredis /apps/redis/bin/redis-cli -a chenchengpei_redis_2026 --no-auth-warning config get requirepass
requirepass
chenchengpei_redis_2026


[root@ubuntu2404 docker]#docker exec myredis /apps/redis/bin/redis-cli -a chenchengpei_redis_2026 --no-auth-warning config get maxmemory
maxmemory
536870912

#内存上限 512MB

[root@ubuntu2404 docker]#docker exec myredis /apps/redis/bin/redis-cli -a chenchengpei_redis_2026 --no-auth-warning config get maxmemory-policy
maxmemory-policy
allkeys-lru

#淘汰策略,删最久没用的 key

# redis 数据实际落盘
[root@ubuntu2404 docker]#ls -la /data/docker/volumes/redis-data/_data/
total 4
drwxr-xr-x 3 10002 10002  43 Nov 11 01:47 .
drwx-----x 3 root  root   19 Nov  9 08:22 ..
drwxr-xr-x 2 10002 10002 103 Nov 11 00:47 appendonlydir
-rw-r--r-- 1 10002 10002 137 Nov 11 01:47 dump.rdb

2.3Nginx 专属

#nginx 编译参数(看路径前缀)
[root@ubuntu2404 docker]#docker exec mynginx /apps/nginx/sbin/nginx -V 2>&1 | tr ' ' '\n' | grep -E 'prefix|conf-path|log-path|error-log|http-log|pid-path'
--prefix=/apps/nginx


# nginx 实际生效配置
[root@ubuntu2404 docker]#docker exec mynginx /apps/nginx/sbin/nginx -T 2>/dev/null | grep -E '^\s*(listen|server_name|location|root|proxy_pass|access_log|error_log)' | head -40
        listen       80;
        server_name  localhost;
        location /nginx-health {
            access_log off;
        location = /50x.html {
            root   html;
    listen 80;
    server_name www.chenchengpei.cn;
    root /data/website;

#健康检查路径是否可用
[root@ubuntu2404 docker]#docker exec mynginx wget -qO- http://127.0.0.1/nginx-health >/dev/null 2>&1 && echo "nginx-health 存在" || echo "nginx-health 不存在"
nginx-health 存在

[root@ubuntu2404 docker]#docker exec mynginx wget -qO- http://127.0.0.1/ >/dev/null 2>&1 && echo "/ 存在" || echo "/ 不存在"
/ 存在

# 确认配置文件位置
[root@ubuntu2404 docker]#docker exec mynginx ls -la /apps/nginx/conf/nginx.conf
-rw-r--r--    1 root     root          2709 Nov 11 06:04 /apps/nginx/conf/nginx.conf

# 确认日志目录
[root@ubuntu2404 docker]#docker exec mynginx ls -la /apps/nginx/logs/
total 12
drwxr-xr-x    2 nginx    nginx           58 Nov 12 08:43 .
drwxr-xr-x    1 root     root            18 Nov  8 06:18 ..
-rw-r--r--    1 nginx    nginx          172 Nov 12 10:11 access.log
-rw-r--r--    1 nginx    nginx          498 Nov 12 08:43 error.log
-rw-r--r--    1 nginx    nginx            2 Nov 12 08:43 nginx.pid

# 确认 pid
[root@ubuntu2404 docker]#docker exec mynginx cat /apps/nginx/logs/nginx.pid
1


#启动脚本
[root@ubuntu2404 docker]#ll /data/dockerfile/web/nginx/myserver.sh 
-rw-r--r-- 1 root root 913 Nov 11 05:53 /data/dockerfile/web/nginx/myserver.sh

2.4HAProxy 专属

#haproxy 启动参数 
[root@ubuntu2404 docker]#docker inspect myhaproxy --format '{{json .Args}}'
["-f","/apps/haproxy/conf/haproxy.cfg","-db"]


# haproxy 配置 
[root@ubuntu2404 docker]#docker exec myhaproxy cat /usr/local/etc/haproxy/haproxy.cfg 2>/dev/null || \
 docker exec myhaproxy sh -c 'find / -name "haproxy.cfg" 2>/dev/null | head -1 | xargs cat'
global
    log stdout format raw local0
    maxconn 20480
    user haproxy
    group haproxy
    ssl-default-bind-options ssl-min-ver TLSv1.2

defaults
    log global
    mode http
    option httplog
    timeout connect 5s
    timeout client  50s
    timeout server  50s

resolvers docker
    nameserver dns1 127.0.0.11:53
    resolve_retries 3
    timeout resolve 1s
    timeout retry   1s
    hold valid      10s

frontend stats
    bind *:8404
    stats enable
    stats uri /
    stats refresh 5s
    stats admin if TRUE

frontend http-in
    bind *:80
    default_backend web_back

backend web_back
    balance roundrobin
    server nginx1 mynginx:80 check inter 3s fall 3 rise 2 resolvers docker init-addr none


# stats 端点 
[root@ubuntu2404 docker]#docker exec myhaproxy wget -qO- http://127.0.0.1:8404/stats >/dev/null 2>&1 && echo "/stats OK" || echo "/stats 不可用"
/stats OK

[root@ubuntu2404 docker]#docker exec myhaproxy wget -qO- http://127.0.0.1:8404/ >/dev/null 2>&1 && echo "/ OK" || echo "/ 不可用"
/ OK

2.5external 资源确认

#网络
[root@ubuntu2404 docker]#docker network inspect test-net --format '{{.Name}} | driver={{.Driver}} | subnet={{range .IPAM.Config}}{{.Subnet}}{{end}} | external={{.Labels}}'
test-net | driver=bridge | subnet=172.27.10.0/24 | external=map[env:prod project:test]

#volume
[root@ubuntu2404 docker]#docker volume inspect redis-data --format '{{.Name}} | driver={{.Driver}} | mountpoint={{.Mountpoint}} | labels={{json .Labels}}'
redis-data | driver=local | mountpoint=/data/docker/volumes/redis-data/_data | labels={"keep":"true"}

三、创建docker-compose.yml文件

3.1创建 .env 文件

Docker Compose 只会自动加载 docker-compose.yml 同级目录下的 .env 文件,不会去扫子目录。

[root@ubuntu2404 ~]#cd /data/docker
[root@ubuntu2404 docker]#vim /data/docker/.env
[root@ubuntu2404 docker]#cat /data/docker/.env
REDIS_PASSWORD=chenchengpei_redis_2026

#在yml 中引用:${REDIS_PASSWORD}

[root@ubuntu2404 docker]#chmod 600 /data/docker/.env

3.2创建docker-compose.yml文件

[root@ubuntu2404 docker]#cd /data/docker
[root@ubuntu2404 docker]#vim /data/docker/docker-compose.yml
[root@ubuntu2404 docker]#cat /data/docker/docker-compose.yml
services:
  redis:
    image: redis:8.2.11-alpine3.24.4
    container_name: myredis
    restart: unless-stopped
    networks:
      - test-net
    volumes:
      - redis-data:/data/redis
    command:
      - /apps/redis/bin/redis-server
      - --dir
      - /data/redis
      - --appendonly
      - "yes"
      - --requirepass
      - "${REDIS_PASSWORD}"
      - --maxmemory
      - "536870912"
      - --maxmemory-policy
      - allkeys-lru
    healthcheck:
      test: ["CMD", "/apps/redis/bin/redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
      interval: 10s
      timeout: 3s
      start_period: 5s
      retries: 3
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
    logging:
      driver: json-file
      options:
        max-size: "100m"
        max-file: "3"
    labels:
      description: "Docker 容器基础镜像"
      maintainer: "陈承沛 <2088346053@qq.com>"
      website: "https://www.chenchengpei.cn"

  nginx:
    image: nginx:1.30.6-alpine3.24.4
    container_name: mynginx
    restart: unless-stopped
    networks:
      - test-net
    volumes:
      - /data/docker/nginx-logs:/apps/nginx/logs
    ports:
      - "127.0.0.1:8088:80"
    environment:
      SERVER: www.chenchengpei.cn
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
    entrypoint: ["/myserver.sh"]
    command: ["/apps/nginx/sbin/nginx", "-g", "daemon off;"]
    depends_on:
      redis:
        condition: service_healthy
    healthcheck:
      test: ["CMD-SHELL", "wget -qO- http://127.0.0.1/nginx-health >/dev/null 2>&1 || exit 1"]
      interval: 30s
      timeout: 3s
      start_period: 5s
      retries: 3
    logging:
      driver: json-file
      options:
        max-size: "100m"
        max-file: "3"
    labels:
      description: "Docker 容器基础镜像"
      maintainer: "陈承沛 <2088346053@qq.com>"
      website: "https://www.chenchengpei.cn"

  haproxy:
    image: haproxy:3.2.26-alpine3.24.4
    container_name: myhaproxy
    restart: unless-stopped
    networks:
      - test-net
    ports:
      - "127.0.0.1:8080:80"
      - "127.0.0.1:8404:8404"
    command:
      - /apps/haproxy/sbin/haproxy
      - -f
      - /apps/haproxy/conf/haproxy.cfg
      - -db
    depends_on:
      nginx:
        condition: service_healthy
    healthcheck:
      test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:8404/ >/dev/null 2>&1 || exit 1"]
      interval: 30s
      timeout: 3s
      start_period: 5s
      retries: 3
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
    logging:
      driver: json-file
      options:
        max-size: "100m"
        max-file: "3"
    labels:
      description: "Docker 容器基础镜像"
      maintainer: "陈承沛 <2088346053@qq.com>"
      website: "https://www.chenchengpei.cn"

networks:
  test-net:
    external: true

volumes:
  redis-data:
    external: true

3.2.1关键指令说明
3.2.1.1全局结构
services:       # 定义三个容器
networks:       # 引用已存在的外部网络
volumes:        # 引用已存在的外部数据卷

Docker Compose V2已经废弃 version

3.2.1.2services 级关键指令
container_name: myredis   #固定容器名
restart: unless-stopped   #开机自启;手动 docker stop 后不会再被拉起,直到手动 start


networks:
  test-net:			 #三个容器同属 test-net,容器间通过服务名/容器名 DNS 互通
    external: true   #网络在 compose 外创建,不被 down 删除

volumes:
  redis-data:
    external: true
    
数据位置:/data/docker/volumes/redis-data/_data  

volumes:
  - /data/docker/nginx-logs:/apps/nginx/logs   #宿主机路径,直接映射,日志落盘可见


command(数组形式 vs 字符串)
数字加引号,"536870912" 防止 YAML 解析为整数
${REDIS_PASSWORD},从同级 .env 文件读取,运行时展开

entrypoint: ["/myserver.sh"],entrypoint,容器启动入口(前置脚本)
command: ["/apps/nginx/sbin/nginx", "-g", "daemon off;"],入口脚本的参数

environment:
  SERVER: www.chenchengpei.cn   #注入环境变量,容器内进程可通过 $SERVER 读取
  
  ports:
  - "127.0.0.1:8088:80",格式:"宿主机IP:宿主机端口:容器端口",只监听 127.0.0.1,不暴露到公网
 
 depends_on:
  redis:        #启动顺序,nginx 等 redis healthy 后才启动
    condition: service_healthy   #依赖方必须有 healthcheck 配置 

 healthcheck:
      test: ["CMD", "/apps/redis/bin/redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
      
      #CMD(非 CMD-SHELL),直接执行,不通过 shell,更轻量
      #-a 参数:有密码必须带,否则返回 -NOAUTH 导致 healthcheck 失败

ulimits:      #文件描述符上限,每个连接/日志文件都占 fd
  nofile:
    soft: 65536
    hard: 65536
    
logging:
  driver: json-file
  options:
    max-size: "100m"   #单文件超 100MB 轮转
    max-file: "3"      #保留 3 个旧文件
3.2.1.3 networks 段
networks:
  test-net:   #必须已存在,需提前 docker network create
    external: true  #compose up 不创建网络,down 不删除网络
3.2.1.4 volumes 段
volumes:
  redis-data:
    external: true   #数据卷独立于 compose 生命周期

3.3验证 compose 能正确展开变量

[root@ubuntu2404 docker]#cd /data/docker

# 1. 语法检查
[root@ubuntu2404 docker]#docker compose config -q && echo "✅ 语法 OK"
✅ 语法 OK


# 2. 确认变量展开正常
[root@ubuntu2404 docker]#docker compose config | grep -A5 "requirepass"
      - --requirepass
      - chenchengpei_redis_2026
    image: redis:8.2.11-alpine3.24.4
    labels:
      description: Docker 容器基础镜像
      maintainer: 陈承沛 <2088346053@qq.com>

[root@ubuntu2404 docker]#docker compose config | grep -A5 "redis:"
      redis:
        condition: service_healthy
        required: true
    healthcheck:
      test:
        - CMD-SHELL
--
  redis:
    restart: unless-stopped
    container_name: myredis
    command:
      - /apps/redis/bin/redis-server
      - --dir
--
    image: redis:8.2.11-alpine3.24.4
    labels:
      description: Docker 容器基础镜像
      maintainer: 陈承沛 <2088346053@qq.com>
      website: https://www.chenchengpei.cn
    logging:

# 3.模拟执行,上线前的安全检查
[root@ubuntu2404 docker]#docker compose up -d --dry-run 2>&1

四、先停掉现有手动容器

#停容器前需确认

# redis-data volume 已存在
[root@ubuntu2404 docker]#docker container inspect myredis --format='{{ json .Mounts }}' | jq
[
  {
    "Type": "volume",
    "Name": "redis-data",
    "Source": "/data/docker/volumes/redis-data/_data",
    "Destination": "/data/redis",
    "Driver": "local",
    "Mode": "z",
    "RW": true,
    "Propagation": ""
  }
]

#nginx-logs存在
[root@ubuntu2404 docker]#ll /data/docker/nginx-logs
total 16
drwxr-xr-x  2 10001 10001   58 Nov 11 07:01 ./
drwx--x--- 15 root  root  4096 Nov 12 05:52 ../
-rw-r--r--  1 10001 10001   86 Nov 11 07:03 access.log
-rw-r--r--  1 10001 10001  166 Nov 11 07:01 error.log
-rw-r--r--  1 10001 10001    2 Nov 11 07:01 nginx.pid

# 唯一要确认的是 redis 的 command 路径
[root@ubuntu2404 docker]#docker inspect myredis --format '{{.Path}} {{.Args}}'
/apps/redis/bin/redis-server [--dir /data/redis --appendonly yes]

[root@ubuntu2404 docker]#docker stop mynginx myhaproxy myredis
[root@ubuntu2404 docker]#docker rm mynginx myhaproxy myredis

五、用 compose 拉起

[root@ubuntu2404 docker]#cd /data/docker
[root@ubuntu2404 docker]#docker compose up -d

六、验证

# 看状态
[root@ubuntu2404 docker]#docker compose ps
NAME        IMAGE                         COMMAND                  SERVICE   CREATED          STATUS                    PORTS
myhaproxy   haproxy:3.2.26-alpine3.24.4   "/apps/haproxy/sbin/…"   haproxy   35 seconds ago   Up 24 seconds (healthy)   443/tcp, 127.0.0.1:8404->8404/tcp, 127.0.0.1:8080->80/tcp
mynginx     nginx:1.30.6-alpine3.24.4     "/myserver.sh /apps/…"   nginx     35 seconds ago   Up 30 seconds (healthy)   443/tcp, 127.0.0.1:8088->80/tcp
myredis     redis:8.2.11-alpine3.24.4     "/apps/redis/bin/red…"   redis     35 seconds ago   Up 35 seconds (healthy)   6379/tcp

# 看日志
[root@ubuntu2404 docker]#docker compose logs -f

# 密码确认
[root@ubuntu2404 docker]#docker exec myredis /apps/redis/bin/redis-cli -a chenchengpei_redis_2026 --no-auth-warning config get requirepass
requirepass
chenchengpei_redis_2026

#跨容器验证
[root@ubuntu2404 docker]#docker exec mynginx sh -c 'echo PING | /apps/redis/bin/redis-cli -h myredis -a chenchengpei_redis_2026 2>/dev/null'

[root@ubuntu2404 docker]#docker exec mynginx sh -c 'echo PING | nc myredis 6379'
-NOAUTH Authentication required.

[root@ubuntu2404 docker]#docker exec myredis /apps/redis/bin/redis-cli -h myredis -a chenchengpei_redis_2026 --no-auth-warning ping
PONG

七、日常运维速查

# 起全部
[root@ubuntu2404 docker]#docker compose up -d

# 看状态
[root@ubuntu2404 docker]#docker compose ps


# 看所有日志
[root@ubuntu2404 docker]#docker compose logs -f

# 看单个服务日志
[root@ubuntu2404 docker]#docker compose logs -f redis
[root@ubuntu2404 docker]#docker compose logs -f --tail=50 nginx

# 重启单个服务
[root@ubuntu2404 docker]#docker compose restart nginx

# 改配置后重建redis
[root@ubuntu2404 docker]#docker compose up -d --force-recreate redis


#停+删容器,保留数据
[root@ubuntu2404 docker]#docker compose down


# 停全部
[root@ubuntu2404 docker]#docker compose stop

# 停+删容器+删 compose volume(危险,别随便跑)
[root@ubuntu2404 docker]#docker compose down -v

#停单个
[root@ubuntu2404 docker]#docker compose stop nginx

#进容器
[root@ubuntu2404 docker]#docker compose exec nginx bash


#看展开结果
[root@ubuntu2404 docker]#docker compose config | grep -A18 "redis:"

#改 yml 后全量检查	
[root@ubuntu2404 docker]#docker compose config -q

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/weixin_51867896/article/details/170630993

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--