一、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 Compose | Kubernetes |
|---|---|---|
| 运行范围 | 单机 | 多机集群 |
| 自动伸缩 | ❌ | ✅ |
| 高可用 | ❌ | ✅ |
| 自愈能力 | ❌ | ✅ |
| 学习成本 | 低 | 高 |
Compose 是轻量级编排工具
1.5Docker Compose 解决的本质问题
它解决的是:
- ✅ 多容器协作
- ✅ 配置集中管理
- ✅ 环境一致性
- ✅ 启动流程自动化
- ✅ 降低运维复杂度
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



