单机跑Docker时,docker run敲多了就想吐。尤其是微服务场景,一个Web应用要配MySQL、Redis、Nginx,每次启动都要写一长串参数,端口映射、网络连接、环境变量,漏一个就得排查半天。Docker Compose就是干这个的:用一个YAML文件定义多个容器,一条命令全部拉起来。
先装Compose
Docker Desktop自带Compose。Linux服务器需要单独装,官方推荐用插件方式:
sudo apt update
sudo apt install docker-compose-plugin
装完验证:
docker compose version
注意是`docker compose`,中间没横杠。老版本用`docker-compose`,新版的插件模式更推荐。
写第一个compose文件
项目目录结构:
myapp/
docker-compose.yml
web/
app.py
Dockerfile
db/
init.sql
核心就是docker-compose.yml:
version: '3.8'
services:
web:
build: ./web
ports:
- "5000:5000"
depends_on:
- db
environment:
- DB_HOST=db
- DB_USER=root
- DB_PASS=secret
db:
image: mysql:8.0
volumes:
- db_data:/var/lib/mysql
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
environment:
- MYSQL_ROOT_PASSWORD=secret
- MYSQL_DATABASE=myapp
volumes:
db_data:
解释几个关键点:
services:每个顶级key就是一个容器,Compose会为每个service创建一个容器实例。service name同时作为DNS主机名,所以web里可以直接用`db`连接数据库,不用写IP。
depends_on:控制启动顺序。这里web依赖db,Compose会先启动db再启动web。但注意depends_on只保证启动顺序,不保证db服务已经就绪。MySQL启动需要时间,web启动时可能连不上。解决办法是在应用代码里加重试,或者用wait-for-it脚本。
volumes:两种写法。`db_data:/var/lib/mysql`是命名卷,数据持久化在Docker管理的目录里。`./db/init.sql:/docker-entrypoint-initdb.d/init.sql`是绑定挂载,把本地文件映射到容器里,MySQL镜像会自动执行init.sql初始化数据库。
启动和停止
在docker-compose.yml所在目录执行:
docker compose up -d
-d是后台运行。不加-d会前台输出日志,Ctrl+C停止所有容器。
查看状态:
docker compose ps
看日志:
docker compose logs -f web
-f持续跟踪,类似tail -f。可以指定service名,不指定则输出所有。
停止并删除容器、网络、卷:
docker compose down -v
-v会删除命名卷,慎用。如果只是想停掉容器,保留数据,用`docker compose stop`,下次`docker compose start`恢复。
多环境配置
开发和生产环境通常有差异。Compose支持多个文件覆盖:
# docker-compose.yml 公共配置
# docker-compose.override.yml 开发环境覆盖(自动加载)
# docker-compose.prod.yml 生产环境
启动生产环境:
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
后面的文件覆盖前面的。比如公共配置里暴露端口3000,生产文件里改成80。
网络细节
Compose自动创建一个默认网络,所有service都加入这个网络,通过service name互相访问。如果想手动控制:
services:
web:
networks:
- frontend
- backend
api:
networks:
- backend
db:
networks:
- backend
networks:
frontend:
backend:
这样web同时接入两个网络,api和db只在backend网络里,无法被外部直接访问。数据库不暴露端口,只有api能连,安全一些。
实际踩坑记录
– 容器内连接localhost是容器自己,不是宿主机。要连宿主机服务用`host.docker.internal`(Windows/Mac)或`–network=host`(Linux)。
– 环境变量写在yml里,别写在Dockerfile里。Dockerfile里的ENV是构建时,Compose的environment是运行时,后者可以覆盖前者。
– 数据卷权限问题:MySQL容器用uid 999运行,宿主机挂载的目录权限不对会导致启动失败。加`:z`或设置目录权限为999:999。
– 生产环境别用`build`,用`image`指定已经push到仓库的镜像。在云服务器上部署时,我们团队用雨云,直接拉镜像跑Compose,稳定性不错,性价比也高。
一个完整的web+redis+nginx示例
version: '3.8'
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- web
web:
build: .
expose:
- "8000"
environment:
- REDIS_HOST=redis
depends_on:
- redis
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
volumes:
redis_data:
nginx反向代理到web的8000端口,web用redis做缓存。expose只暴露给内部网络,不映射宿主机端口,安全。
写Compose的核心就两点:搞清楚service之间的依赖和通信方式,管理好数据和配置的持久化。剩下的就是根据业务需求堆service,每个容器只做一件事,互相配合。
雨云是国内一家老牌云服务商,提供高性价比的云服务器和虚拟主机。我用它部署了好几个项目,速度和稳定性都不错。通过 https://www.rainyun.com/SAJA_ 注册可以领一张 5折优惠券,有需要的朋友可以看看。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END



暂无评论内容