常用服务容器化
本教程共 25 篇 · 第 23 篇 · 更新于 2026-07-26 · 约 7 分钟阅读
23. 常用服务容器化
本节目标:掌握用官方镜像跑 Nginx、MySQL、Redis 的通用套路,学会端口暴露、数据持久化、配置注入这三板斧,能照着模式套到其他服务上。
容器化一个服务的通用套路
不管跑什么服务,容器化的思路都差不多。我把它总结成四问:
- 用哪个镜像? 优先官方镜像,版本要钉死,别用
latest。 - 端口怎么暴露? 容器内服务监听的端口,要不要映射到宿主机。
- 数据放哪? 数据库的数据、配置文件的改动,得挂到卷或宿主机目录,否则容器一删就没。
- 配置怎么传? 环境变量、配置文件挂载、初始化脚本,选最合适的那条路。
这四问答完,一个服务基本就能跑起来。下面拿 Nginx、MySQL、Redis 三个最常见的服务练手。
Note本章是知识点讲解,不组装完整项目。重点是理解每个服务容器化时的关键配置,能举一反三。
Nginx 容器化
Nginx 是最简单的入门案例:静态文件服务器或反向代理,没有持久状态。
基础运行
最简形态,拉官方镜像跑起来:
docker run -d --name my-nginx -p 8080:80 nginx:alpine
参数含义:
nginx:alpine:用基于 Alpine 的精简版,镜像才几十 MB。-p 8080:80:宿主机 8080 映射到容器 80(Nginx 默认端口)。-d:后台跑。
浏览器打开 http://localhost:8080 就能看到 Nginx 欢迎页。
Tip别用
nginx:latest,版本不可控。生产环境钉死具体版本,比如nginx:1.27-alpine。alpine 版本镜像小,但缺少一些调试工具,需要排查问题时可以临时换成nginx:1.27。
挂载自己的静态文件
默认页面没用,我们要托管自己的网站。把宿主机的 HTML 目录挂进去:
docker run -d --name my-nginx \
-p 8080:80 \
-v /path/to/html:/usr/share/nginx/html:ro \
nginx:alpine
/usr/share/nginx/html 是 Nginx 镜像的默认站点目录,:ro 表示只读挂载,避免容器内进程意外改了源文件。
注入自定义配置
改 Nginx 行为得改配置文件。主配置在 /etc/nginx/nginx.conf,站点配置在 /etc/nginx/conf.d/ 下。常用做法是只挂站点配置,主配置用默认:
docker run -d --name my-nginx \
-p 8080:80 \
-v /path/to/html:/usr/share/nginx/html:ro \
-v /path/to/site.conf:/etc/nginx/conf.d/default.conf:ro \
nginx:alpine
一个 site.conf 示例:
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
}
Warning配置文件挂载一定要加
:ro。Nginx 启动时如果检测到配置目录可写,某些场景下会触发nginx -s reload的权限问题,只读挂载最稳。
验证与重启
改完配置文件不用重建容器,发个 reload 信号就行:
docker exec my-nginx nginx -s reload
也可以先用 nginx -t 测试配置语法:
docker exec my-nginx nginx -t
MySQL 容器化
数据库容器化的核心是「数据持久化」和「初始化配置」。
基础运行
MySQL 官方镜像必须设 root 密码,否则启动会报错退出:
docker run -d --name my-mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=secret \
mysql:8.0
环境变量含义:
MYSQL_ROOT_PASSWORD:必填,root 密码。MYSQL_DATABASE:可选,启动时自动建这个库。MYSQL_USER/MYSQL_PASSWORD:可选,自动建用户并授权上面的库。
Warning不要把密码直接写在命令行里,
docker inspect能看到。生产环境用--env-file或 Docker Secrets,开发环境至少用.env文件。
数据持久化
容器一删,/var/lib/mysql 下的数据全没。必须挂命名卷:
docker volume create mysql-data
docker run -d --name my-mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=secret \
-v mysql-data:/var/lib/mysql \
mysql:8.0
这样容器删了重建,数据还在:
docker rm -f my-mysql
docker run -d --name my-mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=secret \
-v mysql-data:/var/lib/mysql \
mysql:8.0
# 数据库里的表都还在
初始化脚本
MySQL 镜像有个贴心机制:容器首次启动时,会自动执行 /docker-entrypoint-initdb.d/ 目录下的 .sql、.sql.gz、.sh 文件。利用它能自动建库建表灌初始数据。
docker run -d --name my-mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=app \
-v mysql-data:/var/lib/mysql \
-v /path/to/init:/docker-entrypoint-initdb.d:ro \
mysql:8.0
放一个 init.sql 进去:
USE app;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL
);
INSERT INTO users (name) VALUES ('alice'), ('bob');
Note初始化脚本只在数据目录为空时(首次启动)执行。已经初始化过的卷再挂上去,脚本不会重跑。想重新初始化,得先删卷。
配置文件注入
改 MySQL 参数(如字符集、连接数)有两种方式:
方式一:命令行参数(推荐简单场景)
docker run -d --name my-mysql \
-e MYSQL_ROOT_PASSWORD=secret \
mysql:8.0 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
镜像名后面的参数会传给 mysqld。
方式二:挂载配置文件
docker run -d --name my-mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-v /path/to/my.cnf:/etc/mysql/conf.d/my.cnf:ro \
mysql:8.0
/etc/mysql/conf.d/ 下的 .cnf 会被自动加载,适合复杂配置。
Redis 容器化
Redis 容器化和 MySQL 类似,但更简单。
基础运行
docker run -d --name my-redis \
-p 6379:6379 \
redis:alpine
默认不需要密码。生产环境一定要设密码:
docker run -d --name my-redis \
-p 6379:6379 \
redis:alpine redis-server --requirepass yourpassword
镜像名后跟的 redis-server --requirepass 会覆盖默认启动命令。
连接测试
docker exec -it my-redis redis-cli
# 或者带密码
docker exec -it my-redis redis-cli -a yourpassword
数据持久化
Redis 默认数据在内存里,重启就丢。要持久化得开 RDB 或 AOF,并把数据目录挂出来:
docker volume create redis-data
docker run -d --name my-redis \
-p 6379:6379 \
-v redis-data:/data \
redis:alpine redis-server --appendonly yes
--appendonly yes 开启 AOF 持久化,数据写到 /data 目录,挂到命名卷上。
TipRedis 的
/data目录是它持久化文件的默认位置。RDB 快照和 AOF 文件都放这。挂这一个卷就够了。
配置文件方式
命令行参数多了不好维护,可以挂配置文件:
docker run -d --name my-redis \
-p 6379:6379 \
-v redis-data:/data \
-v /path/to/redis.conf:/usr/local/etc/redis/redis.conf:ro \
redis:alpine redis-server /usr/local/etc/redis/redis.conf
redis.conf 示例:
requirepass yourpassword
appendonly yes
maxmemory 256mb
maxmemory-policy allkeys-lru
三种服务的速查对比
把三个服务的关键配置拉个表,方便对照:
| 服务 | 镜像 | 默认端口 | 数据目录 | 必填环境变量 |
|---|---|---|---|---|
| Nginx | nginx:alpine | 80 | /usr/share/nginx/html(站点) | 无 |
| MySQL | mysql:8.0 | 3306 | /var/lib/mysql | MYSQL_ROOT_PASSWORD |
| Redis | redis:alpine | 6379 | /data | 无(生产建议设密码) |
三个服务容器化的「最小持久化」命令:
# Nginx:挂静态文件
docker run -d -p 8080:80 -v ./html:/usr/share/nginx/html:ro nginx:alpine
# MySQL:挂数据卷
docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=secret -v mysql-data:/var/lib/mysql mysql:8.0
# Redis:挂数据卷并开 AOF
docker run -d -p 6379:6379 -v redis-data:/data redis:alpine redis-server --appendonly yes
配置注入的三条路
回顾一下,容器化服务时传配置主要有三条路,按优先级选:
- 环境变量:适合简单参数(密码、开关)。官方镜像通常都支持,看镜像文档的「Environment Variables」部分。
- 命令行参数:覆盖默认启动命令的参数,如
mysql:8.0 --character-set-server=utf8mb4。适合少量参数。 - 配置文件挂载:挂载
.conf文件到约定路径。适合复杂配置,最灵活。
Note三条路可以混用。比如 MySQL 同时用环境变量设密码、用配置文件调性能参数。优先级一般是「命令行参数 > 配置文件 > 环境变量 > 默认值」,具体看镜像实现。
几个通用注意事项
不管跑什么服务,这几条都成立:
钉死版本。nginx:latest 今天跑的可能是 1.27,明天就是 1.28,行为可能变。生产用 nginx:1.27.3-alpine 这种精确版本。
数据卷单独管理。命名卷比 bind mount 更适合数据,Docker 帮你管理生命周期,跨容器复用也方便。
配置文件只读挂载。挂配置文件时加 :ro,避免容器内进程改了配置你不知道。
最小权限。能不暴露端口就不暴露。比如 MySQL 如果只给本机应用用,可以不映射端口,让应用容器和它在同一网络里用服务名通信。
初始化只跑一次。MySQL 的 initdb、Redis 的脚本,都只在首次启动数据目录为空时执行。别指望它们每次启动都跑。
Tip看不懂某个镜像怎么配?去 Docker Hub 搜镜像名,官方镜像的 README 都写得很详细,包括支持的环境变量、挂载点、默认端口。这是第一手资料,比搜索引擎靠谱。
小结
容器化常用服务的套路高度一致:选官方镜像、钉死版本、暴露必要端口、挂载数据卷持久化、用环境变量或配置文件传配置。Nginx 简单到几乎不用配置,MySQL 要操心密码和数据,Redis 介于两者之间。
掌握这个套路,再遇到 PostgreSQL、MongoDB、Elasticsearch 这些服务,照着 Docker Hub 文档套就行。下一章换个话题,讲讲怎么把自己的镜像构建得更小、更安全、更快。