从Dockerfile到Compose新手避坑指南你的第一个多容器应用NginxPHPMySQL当你第一次成功运行一个简单的Docker容器时那种成就感就像小时候第一次骑自行车不摔倒一样令人兴奋。但很快你会发现现实世界的应用很少是单一容器就能搞定的——就像骑自行车上路后才发现马路上不只有你一个人。本文将带你从单打独斗的Dockerfile思维升级到团队协作的Compose编排思维用NginxPHPMySQL这个经典组合作为实战案例。1. 为什么需要Compose从单兵作战到团队协作还记得你第一次用Docker运行MySQL数据库的场景吗可能是这样一条命令docker run --name some-mysql -e MYSQL_ROOT_PASSWORDmy-secret-pw -d mysql:5.7然后你需要一个PHP应用容器docker run --name my-php-app -v $PWD:/var/www/html -d php:7.4-fpm接着是Nginxdocker run --name my-nginx -v $PWD:/var/www/html -p 8080:80 --link my-php-app:php -d nginx突然之间你需要记住三条复杂的命令处理容器间的网络连接确保启动顺序正确——这就像同时抛接三个球稍有不慎就会全盘崩溃。这就是Compose要解决的问题。手动管理多容器的痛点启动顺序难以控制数据库没启动应用就挂了网络配置复杂容器间如何互相发现环境变量难以统一管理重复输入大量参数容易出错2. 搭建你的第一个Compose项目LEMP栈实战让我们从创建一个项目目录开始mkdir my-lemp-project cd my-lemp-project2.1 编写docker-compose.yml创建docker-compose.yml文件内容如下version: 3.8 services: db: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: example MYSQL_DATABASE: myapp MYSQL_USER: user MYSQL_PASSWORD: password volumes: - db_data:/var/lib/mysql ports: - 3306:3306 php: build: context: . dockerfile: Dockerfile.php volumes: - ./src:/var/www/html depends_on: - db nginx: image: nginx:alpine ports: - 8080:80 volumes: - ./src:/var/www/html - ./nginx.conf:/etc/nginx/conf.d/default.conf depends_on: - php2.2 创建必要的配置文件Dockerfile.php:FROM php:7.4-fpm RUN docker-php-ext-install pdo_mysqlnginx.conf:server { listen 80; index index.php index.html; server_name localhost; root /var/www/html; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_pass php:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } }2.3 项目结构说明最终你的项目结构应该是my-lemp-project/ ├── docker-compose.yml ├── Dockerfile.php ├── nginx.conf └── src/ └── index.php3. Compose核心概念深度解析3.1 服务发现容器间如何通信在Compose中每个service的名称自动成为该服务的hostname。例如db服务可以通过db主机名访问php服务可以通过php:9000访问网络拓扑对比方式手动运行Compose容器互访需要--link或自定义网络自动创建网络主机名需手动指定服务名即主机名隔离性可能混杂项目独立网络3.2 数据持久化策略Compose中数据管理有两种主要方式命名卷推荐volumes: db_data:数据存储在Docker管理的位置即使容器删除数据依然存在主机绑定挂载volumes: - ./src:/var/www/html适合开发时快速修改代码3.3 环境变量管理Compose提供了多种环境变量管理方式直接在yml中定义environment: MYSQL_ROOT_PASSWORD: example使用.env文件# .env文件 MYSQL_ROOT_PASSWORDmysecret然后在yml中引用environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}4. 常见问题与调试技巧4.1 容器启动顺序问题虽然depends_on可以确保启动顺序但不能保证服务已准备好。解决方案使用健康检查db: healthcheck: test: [CMD, mysqladmin, ping, -h, localhost] interval: 5s timeout: 10s retries: 5应用层重试逻辑4.2 调试容器常用命令# 查看日志 docker-compose logs -f nginx # 进入容器 docker-compose exec php bash # 重建单个服务 docker-compose up -d --no-deps --build php4.3 性能优化建议开发环境php: build: . volumes: - ./src:/var/www/html生产环境php: image: my-php-app:1.0区别在于生产环境应该使用构建好的镜像而非源码挂载5. 从开发到生产Compose进阶实践5.1 多环境配置通过多个Compose文件实现环境差异docker-compose.yml # 基础配置 docker-compose.override.yml # 开发环境(默认加载) docker-compose.prod.yml # 生产环境启动时指定# 开发环境(默认) docker-compose up # 生产环境 docker-compose -f docker-compose.yml -f docker-compose.prod.yml up5.2 扩展服务规模# 启动3个PHP实例 php: scale: 35.3 使用扩展字段x-common-env: common-env TZ: Asia/Shanghai APP_ENV: production services: db: environment: : *common-env MYSQL_ROOT_PASSWORD: example6. 最佳实践与经验分享版本控制固定镜像版本避免使用latest记录Compose文件版本兼容性敏感信息管理永远不要在yml中直接写密码使用.env文件并加入.gitignore资源限制php: deploy: resources: limits: cpus: 0.5 memory: 512M清理策略# 停止并删除所有资源 docker-compose down -v项目迁移# 在新的机器上只需要 git clone your-project docker-compose up -d