Docker 实战:使用自定义网络隔离与连接 Zabbix 和 WordPress 应用
今天,我们将通过两个实战案例——部署 Zabbix 监控套件和 WordPress 博客系统——来深入探讨如何使用 Docker 自定义网络,并分享一些生产环境中的最佳实践。
当我们部署像 Zabbix 监控系统或 WordPress 这样的多组件应用时,容器间的网络通信和隔离就显得尤为重要。Docker 的自定义网络(Custom Networks)正是解决这一问题的利器。
为什么需要 Docker 自定义网络?
你可能会问,Docker不是自带一个默认的 bridge 网络吗?为什么还要创建自定义网络?
- 自动服务发现 (DNS 解析): 在自定义网络中,Docker 内置了 DNS 服务器。这意味着同一网络内的容器可以直接通过容器名称互相访问,无需关心对方的 IP 地址。例如,
zabbix-server容器可以直接连接到mysql-server容器,只需将数据库主机指定为mysql-server。这极大简化了配置。 - 更好的隔离: 默认
bridge网络中的所有容器理论上可以互相访问(除非使用icc=false)。自定义网络提供了更强的网络隔离。只有连接到同一个自定义网络的容器才能直接通信。不同自定义网络之间是隔离的。 - 更灵活的 IP 地址管理 (IPAM): 虽然不常用,但自定义网络允许你指定子网(subnet)、IP 范围(ip-range)、网关等,对网络拓扑有更精细的控制。
- 动态连接/断开: 容器可以在运行时动态地连接到一个或多个自定义网络,或从中移除。
总而言之,对于需要多个容器协作的应用,强烈推荐使用自定义网络,而不是依赖默认的 bridge 网络。
实战一:部署 Zabbix 监控系统
Zabbix 是一个非常流行的开源监控解决方案,通常包含 Server、Database、Web UI,有时还有 Java Gateway 等组件。我们将使用自定义网络将它们部署在同一个 Docker 主机上。
目标:
- 创建一个名为
zabbix-net的自定义网络。 - 在该网络内部署 MySQL、Zabbix Server、Zabbix Java Gateway 和 Zabbix Web UI 容器。
- 确保各组件能通过容器名互相通信。
步骤:
1. 创建自定义网络 zabbix-net
我们首先创建一个专用于 Zabbix 各组件的网络。这里我们指定了子网和 IP 范围(虽然在很多场景下 Docker 自动管理即可,但指定可以提供更可预测的 IP 分配)。
# 创建网络,指定子网为 172.20.0.0/16
# 并指定 Docker 在分配 IP 时,优先从 172.20.240.0/20 这个范围选取
# (注意:IP 范围必须是子网的一部分)
docker network create \
--subnet 172.20.0.0/16 \
--ip-range 172.20.240.0/20 \
zabbix-net
2. 准备 Zabbix Docker 镜像
你可以从 Docker Hub 拉取官方镜像,或者像示例中一样,从本地或指定 URL 加载预先下载好的镜像文件(.tar.gz)。加载本地镜像文件在离线环境或需要使用特定构建版本时很有用。
# (方法一:从 URL 下载并加载 - 如示例所示)
# wget http://<your-repo>/oldboyedu-zabbix-java-gateway-alpine-6.4.tar.gz
# wget http://<your-repo>/oldboyedu-zabbix-server-mysql-alpine-6.4.tar.gz
# wget http://<your-repo>/oldboyedu-zabbix-web-alpine-6.4.tar.gz
# for i in oldboyedu-zabbix-*.tar.gz; do docker load -i $i; done
# (方法二:更常见的 Docker Hub 拉取方式)
docker pull mysql:8.3.0-oracle # 或你选择的其他版本
docker pull zabbix/zabbix-java-gateway:alpine-6.4-latest
docker pull zabbix/zabbix-server-mysql:alpine-6.4-latest
docker pull zabbix/zabbix-web-nginx-mysql:alpine-6.4-latest
生产建议: 优先使用 docker pull 从可信的 registry 拉取。如果使用加载方式,确保镜像来源可靠。始终使用明确的版本标签(如 alpine-6.4-latest),避免使用 latest 以保证部署的可重现性。
3. 部署 MySQL 数据库容器
这是 Zabbix Server 存储数据的地方。
docker run --name mysql-server \
-e MYSQL_DATABASE="zabbix" \
-e MYSQL_USER="linux92" \
-e MYSQL_PASSWORD="oldboyedu" \
-e MYSQL_ROOT_PASSWORD="123456" \
--network=zabbix-net \
--restart unless-stopped \
-v zabbix-mysql-data:/var/lib/mysql \ # <-- 生产环境关键:持久化数据
-d mysql:8.3.0-oracle \
# 注意:MySQL特定的启动参数(如字符集)通常通过环境变量或挂载配置文件传递
# 例如,可以通过挂载 /etc/mysql/conf.d/my.cnf 来设置
# --character-set-server=utf8 --collation-server=utf8_bin 这些参数直接放在 docker run 后面是无效的
关键点与生产建议:
--network=zabbix-net: 将容器连接到我们创建的网络。-e VAR="value": 通过环境变量配置 MySQL (数据库名、用户、密码)。警告: 直接在命令行写密码存在安全风险,生产环境建议使用 Docker Secrets 或环境变量文件 (--env-file)。--name mysql-server: 指定容器名称,以便其他容器(如 Zabbix Server)可以通过这个名字连接到它。--restart unless-stopped: 容器退出时自动重启,除非手动停止。-v zabbix-mysql-data:/var/lib/mysql: 极其重要! 使用 Docker 命名卷 (named volume)zabbix-mysql-data来持久化 MySQL 数据。没有这个,容器删除后所有 Zabbix 数据都会丢失!- MySQL 字符集:官方
mysql镜像通常默认使用utf8mb4。如果需要强制指定utf8和utf8_bin,建议通过挂载自定义配置文件 (my.cnf或my.ini) 到容器的/etc/mysql/conf.d/目录来实现,而不是作为docker run的参数。
4. 部署 Zabbix Java Gateway 容器
如果需要监控 JMX 应用,则需要此组件。
docker run --name zabbix-java-gateway \
--network=zabbix-net \
--restart unless-stopped \
-d zabbix/zabbix-java-gateway:alpine-6.4-latest
关键点:
--network=zabbix-net: 加入 Zabbix 网络。--name zabbix-java-gateway: 方便 Zabbix Server 通过名字连接。
5. 部署 Zabbix Server 容器
Zabbix 的核心组件,负责数据收集、处理和告警。
docker run --name zabbix-server-mysql \
-e DB_SERVER_HOST="mysql-server" \ # <-- 通过容器名连接数据库
-e MYSQL_DATABASE="zabbix" \
-e MYSQL_USER="linux92" \
-e MYSQL_PASSWORD="oldboyedu" \
# -e MYSQL_ROOT_PASSWORD="123456" # <-- Server 通常不需要 Root 密码,仅需 Zabbix 库的用户密码
-e ZBX_JAVAGATEWAY="zabbix-java-gateway" \ # <-- 通过容器名连接 Java Gateway
--network=zabbix-net \
-p 10051:10051 \ # <-- 暴露 Agent 连接端口
--restart unless-stopped \
# 生产建议:添加资源限制
# --memory=2g --cpus=1.0 \
# 生产建议:考虑持久化日志和配置(如果需要)
# -v zabbix-server-logs:/var/log/zabbix \
-d zabbix/zabbix-server-mysql:alpine-6.4-latest
关键点与生产建议:
DB_SERVER_HOST="mysql-server": 核心优势体现! 直接使用 MySQL 容器的名称进行连接,得益于自定义网络的 DNS 解析。ZBX_JAVAGATEWAY="zabbix-java-gateway": 同理,连接到 Java Gateway。-p 10051:10051: 将宿主机的 10051 端口映射到容器的 10051 端口,允许 Zabbix Agent 连接到 Server。- 密码安全:同样,生产环境避免明文密码。
- 资源限制:生产环境中为 Server 容器设置合理的 CPU 和内存限制(
--memory,--cpus)非常重要,防止其耗尽宿主机资源。 - 持久化:如果需要保留 Server 的日志或进行深度自定义配置,可以考虑挂载卷。
6. 部署 Zabbix Web UI 容器
提供 Zabbix 的 Web 管理界面。
docker run --name zabbix-web-nginx-mysql \
-e ZBX_SERVER_HOST="zabbix-server-mysql" \ # <-- 通过容器名连接 Server
-e DB_SERVER_HOST="mysql-server" \ # <-- Web UI 可能也需要直连 DB (视版本和配置)
-e MYSQL_DATABASE="zabbix" \
-e MYSQL_USER="linux92" \
-e MYSQL_PASSWORD="oldboyedu" \
# -e MYSQL_ROOT_PASSWORD="123456" # <-- 通常不需要 Root 密码
-e ZBX_SERVER_PORT="10051" \ # 明确指定 Server 端口
--network=zabbix-net \
-p 80:8080 \ # <-- 将宿主机的 80 端口映射到容器的 8080 端口
--restart unless-stopped \
# 生产建议:添加资源限制
# --memory=512m --cpus=0.5 \
-d zabbix/zabbix-web-nginx-mysql:alpine-6.4-latest
关键点与生产建议:
ZBX_SERVER_HOST="zabbix-server-mysql": Web UI 需要知道 Zabbix Server 在哪里。DB_SERVER_HOST="mysql-server": Web UI 可能也需要连接数据库进行某些操作。-p 80:8080: 将宿主机的 80 端口映射到容器内部 Nginx 监听的 8080 端口。这样你就可以通过访问宿主机的 IP 地址(如http://<your-host-ip>) 来访问 Zabbix Web 界面了。- 密码安全:同上。
- 资源限制:为 Web UI 设置资源限制。
7. 验证部署
- 打开浏览器,访问
http://<你的Docker主机IP>。你应该能看到 Zabbix 的登录页面。 - 使用
docker ps确认所有 Zabbix 相关容器都在运行。 - 使用
docker logs <container_name>查看各个容器的启动日志,排查潜在问题。例如docker logs zabbix-server-mysql。
实战二:部署 WordPress (课堂练习复盘)
这个练习是巩固自定义网络和多容器部署的好例子。我们将部署一个包含 WordPress 应用和 MySQL 数据库的环境。
目标:
- 创建一个名为
oldboyedu-wp的自定义网络。 - 在该网络内部署 MySQL 和 WordPress 容器。
- 确保 WordPress 可以连接到 MySQL。
- 关键: 持久化 WordPress 网站文件和 MySQL 数据。
步骤:
1. 创建自定义网络 oldboyedu-wp
docker network create \
--subnet 172.21.0.0/16 \
--ip-range 172.21.100.0/24 \
oldboyedu-wp
2. 部署 MySQL 数据库容器
docker run --name db-wp \
-e MYSQL_DATABASE="wordpress" \
-e MYSQL_USER="linux92" \
-e MYSQL_PASSWORD="123456" \
# -e MYSQL_ALLOW_EMPTY_PASSWORD=yes # <-- 极不推荐!生产环境绝不能允许空密码!
-e MYSQL_ROOT_PASSWORD="a_strong_root_password" \ # <-- 总是设置一个强密码
--network oldboyedu-wp \
-v oldboyedu-wp-db:/var/lib/mysql \ # <-- 正确!使用命名卷持久化数据
--restart unless-stopped \
-d mysql:8.3.0-oracle # 或其他版本
关键点与生产建议:
--network oldboyedu-wp: 加入 WordPress 的专属网络。-v oldboyedu-wp-db:/var/lib/mysql: 做得很好! 使用了命名卷oldboyedu-wp-db来持久化数据库。MYSQL_ALLOW_EMPTY_PASSWORD=yes: 严重安全风险! 示例中使用了这个,但强烈建议在任何非临时测试环境都不要使用。务必为MYSQL_PASSWORD和MYSQL_ROOT_PASSWORD设置强密码。- 密码安全:同 Zabbix,生产环境使用 secrets 或 env 文件。
3. 部署 WordPress 容器
docker run --name wp \
-e WORDPRESS_DB_HOST="db-wp:3306" \ # <-- 通过容器名连接数据库, 明确端口通常更好
-e WORDPRESS_DB_USER="linux92" \
-e WORDPRESS_DB_PASSWORD="123456" \
-e WORDPRESS_DB_NAME="wordpress" \
--network oldboyedu-wp \
-p 88:80 \ # <-- 将宿主机的 88 端口映射到容器的 80 端口
-v oldboyedu-wp-files:/var/www/html/ \ # <-- 正确!使用命名卷持久化网站文件
--restart unless-stopped \
# 生产建议:添加资源限制
# --memory=1g --cpus=0.5 \
-d wordpress # 使用官方 wordpress 镜像最新稳定版,或指定版本
关键点与生产建议:
WORDPRESS_DB_HOST="db-wp:3306": 通过 MySQL 容器名db-wp连接。虽然 Docker DNS 会解析名字,但显式指定端口3306是个好习惯。-p 88:80: 映射宿主机 88 端口到容器 80 端口。-v oldboyedu-wp-files:/var/www/html/: 做得很好! 使用命名卷oldboyedu-wp-files持久化 WordPress 的核心文件、主题、插件和上传内容。这是保证网站数据不丢失的关键。- 密码安全:同上。
- 资源限制:根据需要为 WordPress 设置资源限制。
4. 验证部署
- 打开浏览器,访问
http://<你的Docker主机IP>:88。你应该能看到 WordPress 的安装向导页面。 - 示例中的
curl -I 10.0.0.102:88测试也验证了服务已启动并返回 HTTP 状态码(301 重定向到安装页面是正常的初始行为)。
总结与更进一步
通过这两个实战案例,我们看到了 Docker 自定义网络的强大之处:
- 简化连接: 服务发现让容器间通信配置变得简单直观。
- 增强隔离: 不同应用可以放在不同的网络中,互不干扰。
- 生产必备: 结合命名卷进行数据持久化,是生产环境部署有状态应用(如数据库、CMS)的标准做法。
生产环境的额外考量:
- Docker Compose: 对于管理像 Zabbix 或 WordPress 这样由多个容器组成的应用,手动执行
docker run命令既繁琐又容易出错。强烈推荐使用 Docker Compose。它允许你用一个 YAML 文件 (docker-compose.yml) 定义所有服务(容器)、网络、卷及其配置,然后用简单的命令 (docker-compose up -d) 一键启动整个应用栈。 - 安全性:
- 绝不在命令行或 Dockerfile 中硬编码敏感信息(如密码)。使用 Docker Secrets、环境变量文件或专门的配置管理工具。
- 定期更新基础镜像和应用镜像以修复安全漏洞。
- 根据最小权限原则,配置容器的安全选项(如 Capabilities, Seccomp)。
- 资源管理: 务必为生产环境的容器设置合理的 CPU 和内存限制,并进行监控。
- 日志管理: 配置集中的日志收集方案(如 ELK Stack, Grafana Loki)来管理容器日志。
- 备份与恢复: 制定并定期测试针对持久化卷(数据库文件、网站文件等)的备份和恢复策略。
浙公网安备 33010602011771号