1. 项目概述
在Linux服务器环境中部署数据库和Web服务是每个开发者都会遇到的基础任务。今天我要分享的是在Ubuntu系统上使用Docker容器化部署MySQL、Redis和Nginx的完整方案,并实现自动备份功能。这套方案特别适合中小型项目的生产环境部署,我自己已经在多个实际项目中验证过其稳定性和可靠性。
为什么选择Docker部署?相比直接安装,容器化部署有以下优势:
- 环境隔离:每个服务运行在独立的容器中,互不干扰
- 快速部署:通过预构建的镜像,几分钟就能完成全套服务部署
- 版本管理:可以精确控制每个服务的版本
- 资源可控:可以限制每个容器的CPU、内存使用量
这套方案还包含了自动备份功能,每4小时自动备份MySQL数据库和Redis数据文件,保留最近5个备份版本,确保数据安全。下面我会详细拆解每个步骤的实现原理和注意事项。
2. 环境准备与Docker安装
2.1 系统更新与基础依赖
在开始安装前,首先要确保系统是最新状态。Ubuntu的apt包管理器需要定期更新索引,否则可能安装不到最新版本的软件。
bash复制sudo apt update && sudo apt upgrade -y
sudo apt install -y curl gnupg lsb-release software-properties-common
这里安装的几个工具各有用途:
curl:用于从网络下载文件gnupg:用于验证软件包的GPG签名lsb-release:提供标准的Linux发行版信息software-properties-common:管理软件源的工具
注意:生产环境中建议在非高峰时段执行系统更新,因为
apt upgrade可能会导致服务短暂中断。
2.2 Docker安装与验证
Docker官方提供了针对Ubuntu的安装指南,我们需要先添加Docker的官方GPG密钥和软件源:
bash复制# 添加Docker官方GPG密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 添加Docker稳定版仓库
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装Docker Engine和Compose插件
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
安装完成后,启动Docker服务并设置开机自启:
bash复制sudo systemctl enable docker
sudo systemctl start docker
验证安装是否成功:
bash复制docker --version && docker compose version
正常情况下会输出Docker和Docker Compose的版本信息。如果遇到权限问题,需要将当前用户加入docker组:
bash复制sudo usermod -aG docker $USER
newgrp docker # 使分组变更立即生效
经验分享:在生产环境中,建议为Docker配置日志轮转,防止日志文件占用过多磁盘空间。可以编辑
/etc/docker/daemon.json文件,添加日志配置:json复制{ "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "3" } }
3. Docker镜像加速配置
3.1 配置国内镜像加速器
在国内服务器上直接拉取Docker官方镜像可能会非常慢甚至失败。解决方法是为Docker配置国内镜像加速器。
创建Docker配置文件:
bash复制sudo mkdir -p /etc/docker
写入加速器配置(这里使用了几个公共镜像源):
bash复制sudo tee /etc/docker/daemon.json << 'EOF'
{
"registry-mirrors": [
"https://docker.m.daocloud.io",
"https://huecker.io",
"https://dockerhub.timeweb.cloud",
"https://noohub.ru"
],
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
}
}
EOF
重启Docker使配置生效:
bash复制sudo systemctl daemon-reload
sudo systemctl restart docker
验证配置是否生效:
bash复制docker info | grep -A 5 "Registry Mirrors"
3.2 常见问题排查
如果配置后仍然无法拉取镜像,可以尝试以下排查步骤:
-
检查DNS配置:
bash复制sudo nano /etc/resolv.conf添加Google的公共DNS:
code复制nameserver 8.8.8.8 nameserver 8.8.4.4 -
测试基础网络连通性:
bash复制
docker pull alpine:latest如果这个简单的镜像都拉取失败,说明服务器网络可能完全不通外网。
-
使用专属加速地址:
各大云服务商(阿里云、腾讯云等)都提供专属的Docker镜像加速地址,通常比公共镜像源更稳定。
避坑指南:不同云服务商的加速地址格式不同,一定要使用对应云服务商提供的地址。公共镜像源可能会不定期失效,生产环境建议使用云服务商提供的专属加速地址。
4. 项目目录结构与文件准备
4.1 创建标准目录结构
合理的目录结构能让后续维护更加方便。我推荐以下结构:
code复制~/database_nginx/
├── docker-compose.yaml
├── scripts/
│ └── backuper.sh
├── data/
│ ├── mysql/
│ ├── redis/
│ └── nginx/
│ ├── html/
│ ├── conf.d/
│ └── logs/
└── backups/
├── mysql/
└── redis/
创建这些目录的命令:
bash复制mkdir -p ~/database_nginx && cd ~/database_nginx
mkdir -p scripts data/mysql data/redis data/nginx/html data/nginx/conf.d data/nginx/logs backups/mysql backups/redis
目录用途说明:
data/:存放各服务的持久化数据backups/:存放自动备份文件scripts/:存放维护脚本
4.2 编写docker-compose.yaml
Docker Compose允许我们通过一个YAML文件定义和管理多个容器。下面是完整的docker-compose.yaml配置:
yaml复制version: '3.8'
services:
mysql:
image: mysql:8.0
container_name: mysql_8
restart: always
environment:
MYSQL_ROOT_PASSWORD: 'your_secure_password'
ports:
- "10082:3306"
volumes:
- ./data/mysql:/var/lib/mysql
- ./backups/mysql:/backup
command: --default-authentication-plugin=mysql_native_password
networks:
- app_net
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-pyour_secure_password"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:8.0
container_name: redis_8
restart: always
command: ["redis-server", "--requirepass", "your_secure_password", "--appendonly", "yes"]
ports:
- "10083:6379"
volumes:
- ./data/redis:/data
- ./backups/redis:/backup
networks:
- app_net
healthcheck:
test: ["CMD", "redis-cli", "-a", "your_secure_password", "ping"]
interval: 10s
timeout: 5s
retries: 5
nginx:
image: nginx:latest
container_name: nginx_web
restart: always
ports:
- "80:80"
volumes:
- ./data/nginx/html:/usr/share/nginx/html:ro
- ./data/nginx/conf.d:/etc/nginx/conf.d:ro
- ./data/nginx/logs:/var/log/nginx
depends_on:
- mysql
- redis
networks:
- app_net
backup-service:
image: alpine:latest
container_name: auto_backup
restart: always
entrypoint: ["/bin/sh", "-c"]
command:
- |
apk add --no-cache mysql-client redis-tools bash cronie tar gzip
echo '0 */4 * * * /usr/bin/backuper.sh' > /etc/crontabs/root
crond -f -l 2
volumes:
- ./backups:/backups
- ./scripts/backuper.sh:/usr/bin/backuper.sh:ro
- ./data/mysql:/mysql_data:ro
- ./data/redis:/redis_data:ro
environment:
MYSQL_HOST: mysql
MYSQL_PORT: "3306"
MYSQL_USER: root
MYSQL_PASS: 'your_secure_password'
REDIS_HOST: redis
REDIS_PORT: "6379"
REDIS_PASS: 'your_secure_password'
networks:
- app_net
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
networks:
app_net:
driver: bridge
配置要点说明:
- 每个服务都配置了
restart: always,确保容器意外退出后会自动重启 - MySQL和Redis都配置了健康检查,确保服务真正可用
- 所有数据都通过volumes映射到宿主机,避免容器删除后数据丢失
- 备份服务基于Alpine Linux,体积小巧,定时执行备份脚本
安全提示:在实际部署时,务必将示例密码'your_secure_password'替换为强密码,并妥善保管。密码最好包含大小写字母、数字和特殊字符,长度至少16位。
4.3 自动备份脚本实现
自动备份是生产环境必不可少的功能。我们创建一个每4小时执行一次的备份脚本:
bash复制cat > scripts/backuper.sh << 'EOF'
#!/bin/bash
BACKUP_DIR="/backups"
DATE_STR=$(date +"%Y%m%d_%H%M%S")
echo "[$(date)] Starting MySQL Backup..."
if mysqldump -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" -u"${MYSQL_USER}" -p"${MYSQL_PASS}" --all-databases | gzip > "${BACKUP_DIR}/mysql/full_backup_${DATE_STR}.sql.gz"; then
echo "MySQL backup success."
# 保留最近5个备份
ls -t ${BACKUP_DIR}/mysql/*.sql.gz 2>/dev/null | tail -n +6 | xargs -r rm
else
echo "MySQL backup failed."
fi
echo "[$(date)] Starting Redis File Backup..."
if [ -d "/redis_data" ] && [ "$(ls -A /redis_data 2>/dev/null)" ]; then
if tar -czf "${BACKUP_DIR}/redis/redis_files_${DATE_STR}.tar.gz" -C /redis_data .; then
echo "Redis backup success."
ls -t ${BACKUP_DIR}/redis/*.tar.gz 2>/dev/null | tail -n +6 | xargs -r rm
else
echo "Redis backup failed."
fi
else
echo "Redis data directory empty or not found."
fi
EOF
chmod +x scripts/backuper.sh
备份脚本功能说明:
- MySQL备份使用
mysqldump命令导出所有数据库,并用gzip压缩 - Redis备份直接打包Redis的数据文件
- 每次备份都包含时间戳,便于恢复时识别
- 自动清理旧备份,只保留最近的5个备份文件
- 详细的日志输出,方便排查问题
性能考虑:MySQL的
mysqldump在备份大型数据库时可能会锁表,影响生产环境性能。对于大型数据库,建议考虑使用Percona XtraBackup等专业工具,或者在业务低峰期执行备份。
5. 服务启动与验证
5.1 启动所有服务
完成配置后,使用以下命令启动所有服务:
bash复制cd ~/database_nginx
docker compose up -d
-d参数表示在后台运行容器。启动完成后,可以查看容器状态:
bash复制docker compose ps
正常情况应该看到所有服务的状态都是"Up"或"Up (healthy)"。
5.2 服务连通性测试
验证MySQL服务:
bash复制docker exec mysql_8 mysqladmin ping -h localhost -u root -p'your_secure_password'
验证Redis服务:
bash复制docker exec redis_8 redis-cli -a 'your_secure_password' ping
验证Nginx服务:
bash复制curl -I http://localhost
5.3 常见启动问题排查
问题1:端口冲突
如果启动时提示端口已被占用,可以使用以下命令查找占用端口的进程:
bash复制sudo netstat -tulpn | grep <端口号>
解决方案:
- 停止占用端口的服务
- 或者修改docker-compose.yaml中的端口映射
问题2:健康检查失败
如果MySQL或Redis容器不断重启,可能是健康检查失败。查看日志找原因:
bash复制docker compose logs mysql
docker compose logs redis
常见原因:
- 磁盘空间不足:使用
df -h检查 - 内存不足:使用
free -h检查 - 配置文件错误:检查docker-compose.yaml中的配置
问题3:备份服务不工作
如果备份没有按时执行,可以手动触发测试:
bash复制docker exec auto_backup /usr/bin/backuper.sh
查看备份服务日志:
bash复制docker compose logs backup-service
6. 日常运维命令速查
为了方便日常维护,整理了一些常用命令:
| 操作 | 命令 |
|---|---|
| 查看实时日志 | docker compose logs -f |
| 查看特定服务日志 | docker compose logs -f mysql |
| 重启所有服务 | docker compose restart |
| 停止并删除容器 | docker compose down |
| 停止并删除容器+数据卷 | docker compose down -v (危险操作,会删除数据) |
| 进入MySQL命令行 | docker exec -it mysql_8 mysql -u root -p'your_secure_password' |
| 进入Redis命令行 | docker exec -it redis_8 redis-cli -a 'your_secure_password' |
| 手动触发备份 | docker exec auto_backup /usr/bin/backuper.sh |
| 查看容器资源使用 | docker stats |
| 更新容器镜像 | docker compose pull && docker compose up -d |
7. 安全加固建议
生产环境部署还需要考虑安全性,以下是一些加固建议:
- 修改默认端口:将MySQL的3306和Redis的6379映射到非标准端口
- 限制网络访问:在云服务器安全组中,只允许特定IP访问数据库端口
- 定期轮换密码:定期更改MySQL和Redis的密码
- 启用SSL加密:为MySQL和Redis配置SSL加密传输
- 监控设置:配置Prometheus等监控工具,监控服务状态
- 日志审计:定期检查Nginx和数据库的访问日志
8. 性能优化建议
根据实际使用经验,分享几个性能优化技巧:
-
MySQL优化:
- 在my.cnf中调整innodb_buffer_pool_size(通常设为物理内存的70-80%)
- 启用慢查询日志,优化慢SQL
- 为常用查询字段添加索引
-
Redis优化:
- 根据数据特性选择合适的淘汰策略(maxmemory-policy)
- 对大value进行压缩或拆分
- 启用持久化(已经在我们配置中通过appendonly实现)
-
Nginx优化:
- 调整worker_processes和worker_connections
- 启用gzip压缩
- 配置静态文件缓存
这套部署方案已经在多个生产环境中稳定运行,累计服务了数百万用户请求。最大的优势在于部署快速、维护方便,通过Docker实现了环境标准化,避免了"在我机器上能跑"的问题。自动备份机制也为数据安全提供了保障。