Docker Compose 紧急救援:凌晨3点服务器报警的解决方案
Docker Compose 紧急救援凌晨3点服务器报警的解决方案凌晨3点你还躺在床上手机突然响了。是服务器报警短信提示网站因 MySQL 服务异常而无法访问。你迅速爬起来打开笔记本心想如果能快速恢复服务该多好。这时你记起 Docker Compose 是处理这种情况的理想工具因为可以轻松地重新部署整个应用栈。想象一下如果每次服务出现问题都需要手动启动每个容器检查日志处理异常不仅耗时还容易出错。Docker Compose 通过一个docker-compose.yml文件可以一口气管理多个 Docker 容器让应用的部署和恢复变得简单、高效。今天我们就从这个深夜报警的场景开始一起看看如何使用 Docker Compose 解决问题。场景设定你的网站由两个主要部分组成一个基于 Node.js 的 Web 应用和一个 MySQL 数据库。两个部分分别运行在不同的 Docker 容器中。在docker-compose.yml文件的帮助下可以快速启动、停止和重启整个应用栈而无需分别管理每个容器。准备docker-compose.yml文件在一个平静的白天你需要先准备好docker-compose.yml文件确保在紧急情况时可以立即使用。假设你的项目目录结构如下myapp/ ├── docker-compose.yml ├── web/ │ └── Dockerfile └── db/ └── init.sqldocker-compose.yml文件内容如下version: 3.8 # 指定 compose 文件版本 services: # 定义服务 web: # Web 应用服务 build: ./web # 指定构建目录 ports: # 映射端口 - 4000:3000 # 将主机的 4000 端口映射到容器的 3000 端口 depends_on: # 依赖的服务 - db # 依赖 db 服务 environment: # 环境变量 MYSQL_HOST: db # 指定 MySQL 主机名 MYSQL_USER: root MYSQL_PASSWORD: example MYSQL_DATABASE: appdb db: # 数据库服务 image: mysql:5.7 # 使用官方的 MySQL 镜像 volumes: # 挂载卷 - db_data:/var/lib/mysql # 持久化数据 - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql # 初始化数据库脚本 environment: # 环境变量 MYSQL_ROOT_PASSWORD: example # 设置 root 用户的密码 MYSQL_DATABASE: appdb # 创建数据库 volumes: # 定义卷 db_data: # 数据卷名称构建和启动应用在白天你可以构建和启动你的应用确保一切正常。打开终端进入项目目录运行以下命令docker-compose up --build # 构建并启动所有服务这条命令会先构建web服务的 Docker 镜像然后启动web和db服务。--build选项表示强制重新构建镜像确保最新代码被使用。检查服务状态启动服务后可以使用以下命令检查服务状态docker-compose ps # 查看所有服务的运行状态如果一切正常你会看到web和db服务都在运行中。如果有问题可以通过docker-compose logs查看日志定位问题docker-compose logs # 查看所有服务的日志 docker-compose logs web # 仅查看 web 服务的日志服务异常处理回到那个不眠之夜你发现 MySQL 服务崩溃了。这个问题可能是因为磁盘空间不足、配置错误或其他原因。使用 Docker Compose你可以迅速停止并重启数据库服务而无需重新启动整个应用docker-compose stop db # 停止 db 服务 docker-compose start db # 启动 db 服务如果重启服务后问题依然存在可以尝试重新构建数据库服务docker-compose up --build db # 重新构建并启动 db 服务数据库初始化假设你新添加了一张表需要重新初始化数据库。你可以通过修改init.sql文件然后重新启动数据库服务来实现-- db/init.sql CREATE DATABASE appdb; USE appdb; CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL UNIQUE ); INSERT INTO users (name, email) VALUES (Alice, aliceexample.com); INSERT INTO users (name, email) VALUES (Bob, bobexample.com);保存文件后重新启动数据库服务docker-compose up --build db # 重新构建并启动 db 服务这次启动时Docker 会执行init.sql文件中的 SQL 命令完成数据库的初始化。持久化数据为了避免数据库数据丢失Docker Compose 使用卷来持久化数据。在docker-compose.yml文件中我们定义了一个名为db_data的卷并将其挂载到 MySQL 容器的数据目录。这样即使容器被删除数据依然保留。环境变量管理在docker-compose.yml文件中我们通过environment部分设置了环境变量。这些环境变量可以在应用中使用例如在 Node.js 应用中可以通过process.env.MYSQL_HOST获取 MySQL 服务的主机名。网络配置默认情况下Docker Compose 会为每个项目创建一个默认网络所有服务都在这个网络中通信。你也可以自定义网络例如version: 3.8 services: web: build: ./web ports: - 4000:3000 depends_on: - db environment: MYSQL_HOST: db MYSQL_USER: root MYSQL_PASSWORD: example MYSQL_DATABASE: appdb networks: # 指定网络 - appnet # 使用 appnet 网络 db: image: mysql:5.7 volumes: - db_data:/var/lib/mysql - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql environment: MYSQL_ROOT_PASSWORD: example MYSQL_DATABASE: appdb networks: - appnet networks: appnet: # 定义 appnet 网络通过自定义网络你可以更好地控制服务之间的通信。高级用法服务扩展假设你的 Web 应用需要扩展以应对突然增加的流量。Docker Compose 支持服务扩展你只需要在docker-compose.yml文件中添加deploy部分version: 3.8 services: web: build: ./web ports: - 4000:3000 depends_on: - db environment: MYSQL_HOST: db MYSQL_USER: root MYSQL_PASSWORD: example MYSQL_DATABASE: appdb networks: - appnet deploy: # 部署配置 replicas: 3 # 设置副本数量 restart_policy: # 重启策略 condition: on-failure # 只在失败时重启 db: image: mysql:5.7 volumes: - db_data:/var/lib/mysql - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql environment: MYSQL_ROOT_PASSWORD: example MYSQL_DATABASE: appdb networks: - appnet networks: appnet: volumes: db_data:使用docker-compose up --scale web3命令可以启动 3 个web服务的副本实现负载均衡。服务配置更新假设你发现 Web 应用的端口需要从 3000 改为 8080。只需修改docker-compose.yml文件中的ports部分然后重启服务version: 3.8 services: web: build: ./web ports: - 4000:8080 # 修改端口映射 depends_on: - db environment: MYSQL_HOST: db MYSQL_USER: root MYSQL_PASSWORD: example MYSQL_DATABASE: appdb networks: - appnet db: image: mysql:5.7 volumes: - db_data:/var/lib/mysql - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql environment: MYSQL_ROOT_PASSWORD: example MYSQL_DATABASE: appdb networks: - appnet networks: appnet: volumes: db_data:保存文件后运行以下命令更新服务配置docker-compose up --force-recreate # 强制重新创建并启动所有服务定时任务有时候你可能需要定期执行一些维护任务例如备份数据库。Docker Compose 本身不提供定时任务功能但你可以使用一个定时任务容器来实现。创建一个新的backup服务并使用 Cron 表达式来定义任务调度version: 3.8 services: web: build: ./web ports: - 4000:8080 depends_on: - db environment: MYSQL_HOST: db MYSQL_USER: root MYSQL_PASSWORD: example MYSQL_DATABASE: appdb networks: - appnet db: image: mysql:5.7 volumes: - db_data:/var/lib/mysql - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql environment: MYSQL_ROOT_PASSWORD: example MYSQL_DATABASE: appdb networks: - appnet backup: image: alpine:latest volumes: - ./backup:/backup # 挂载备份脚本 command: sh -c crond tail -f /dev/null # 启动 Cron 守护进程 environment: CRON_SCHEDULE: 0 2 * * * # 每天凌晨2点执行 BACKUP_COMMAND: mysqldump -h db -u root -pexample appdb /backup/appdb.sql # 备份命令 networks: - appnet networks: appnet: volumes: db_data:在这个例子中backup服务使用 Alpine 镜像挂载了一个备份脚本目录并通过环境变量CRON_SCHEDULE和BACKUP_COMMAND来定义定时任务和备份命令。你可以在./backup目录中创建一个crontab文件来配置定时任务# ./backup/crontab 0 2 * * * mysqldump -h db -u root -pexample appdb /backup/appdb.sql # 每天凌晨2点备份数据库然后运行以下命令启动所有服务docker-compose up --build # 构建并启动所有服务常用命令汇总为了方便你在紧急情况下快速操作这里列出一些常用的 Docker Compose 命令docker-compose up --build构建并启动所有服务docker-compose ps查看服务状态docker-compose logs [service]查看服务日志docker-compose stop [service]停止指定服务docker-compose start [service]启动指定服务docker-compose up --force-recreate强制重新创建并启动所有服务docker-compose down停止并删除所有服务及其网络和卷自然推荐 Hey Cron在处理定时任务时如果你不熟悉 Cron 表达式或者需要生成复杂的定时任务可以考虑使用 Hey Cron。Hey Cron 是一个免费在线工具网站提供中文描述秒转 Cron 的功能让你轻松生成 Cron 表达式。它还支持正则表达式生成器、中英互译、JSON 格式化、Base64 编码解码、时间戳转换和 JWT 解析等多种实用工具非常适合开发者的日常使用。现在你可以回到床上安心睡觉了。Docker Compose 和 Hey Cron 都已经准备好下次再遇到这种紧急情况你可以迅速解决问题继续享受你的美梦。