首页 / Docker 入门教程 / 常用服务容器化

Docker 入门教程

常用服务容器化

本教程共 25 篇 · 第 23 篇 · 更新于 2026-07-26 · 约 7 分钟阅读

DockerDocker 入门教程NginxMySQLRedis容器化官方镜像数据持久化

23. 常用服务容器化

本节目标:掌握用官方镜像跑 Nginx、MySQL、Redis 的通用套路,学会端口暴露、数据持久化、配置注入这三板斧,能照着模式套到其他服务上。

容器化一个服务的通用套路

不管跑什么服务,容器化的思路都差不多。我把它总结成四问:

  1. 用哪个镜像? 优先官方镜像,版本要钉死,别用 latest
  2. 端口怎么暴露? 容器内服务监听的端口,要不要映射到宿主机。
  3. 数据放哪? 数据库的数据、配置文件的改动,得挂到卷或宿主机目录,否则容器一删就没。
  4. 配置怎么传? 环境变量、配置文件挂载、初始化脚本,选最合适的那条路。

这四问答完,一个服务基本就能跑起来。下面拿 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 目录,挂到命名卷上。

Tip

Redis 的 /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

三种服务的速查对比

把三个服务的关键配置拉个表,方便对照:

服务镜像默认端口数据目录必填环境变量
Nginxnginx:alpine80/usr/share/nginx/html(站点)
MySQLmysql:8.03306/var/lib/mysqlMYSQL_ROOT_PASSWORD
Redisredis:alpine6379/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

配置注入的三条路

回顾一下,容器化服务时传配置主要有三条路,按优先级选:

  1. 环境变量:适合简单参数(密码、开关)。官方镜像通常都支持,看镜像文档的「Environment Variables」部分。
  2. 命令行参数:覆盖默认启动命令的参数,如 mysql:8.0 --character-set-server=utf8mb4。适合少量参数。
  3. 配置文件挂载:挂载 .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 文档套就行。下一章换个话题,讲讲怎么把自己的镜像构建得更小、更安全、更快。