# Docker 容器网络配置详解:从基础到实战
做 Docker 开发的人很多,但真正能把网络配置搞清楚的不多。我见过太多项目因为网络问题卡住:容器之间打不通、端口映射乱套、甚至有把数据库直接暴露到公网的惨剧。这篇教程就是为了解决这些问题。
## 背景介绍
Docker 已经成为现代软件开发的基础设施。这话虽然听起来像套话,但确实是事实。不管是本地开发、微服务部署还是 CI/CD 流水线,Docker 都绕不开。
但我发现很多人用 Docker 时只关心容器怎么启动、镜像怎么拉,对网络配置基本不过问。结果呢?两个容器跑起来发现互相访问不了,必须用宿主机 IP 才能通信——用 `–link` 还被官方标为废弃。烦死了。
端口映射也是重灾区。`-p 8080:80` 到底啥意思?前面是宿主机端口还是容器端口?很多人搞不清楚。配置错了服务就访问不了,还得找半天原因。
还有一个容易被忽略的问题:安全。Docker 默认会创建一个叫 bridge 的网络,所有不指定网络的容器都扔进去。这意味着如果某个容器被黑,攻击者可以直接在内网横着走。这个风险很多人意识不到。
跨主机通信就更复杂了。单机上遇不到,但上线后就躲不开。得多台机器协同工作的话,怎么让容器像在同一台机器上一样通信?这里需要更高级的配置。
这篇文章不整虚的,就讲实际能用的东西。网络驱动怎么选、网络怎么创建、容器怎么配置、怎么保证安全,我会通过具体的例子一步步演示。代码都是可以直接抄的。
## 问题描述
实际工作中,网络相关的问题主要有这几类:
**容器间通信**是最普遍的。启动一个 Redis,再启动一个 Node.js 应用,发现应用连不上 Redis。必须用宿主机 IP 或者 `–link`(虽然已经废弃了)才能行。这玩意儿用起来特别扭,扩展性也差。
**端口映射**看着简单,但容易出错。`-p` 参数的顺序老是搞错,容器端口和宿主机端口分不清。想让服务能从外网访问,结果配置错了访问不了。
**网络隔离和安全**容易被轻视。默认情况下所有容器都在同一个内网里,一个容器被攻破,整个内网都危险。生产环境尤其要注意这点。
**跨主机通信**在单机上遇不到,但上线后就躲不开。得多台机器协同工作的话,怎么让容器像在同一台机器上一样通信?这里需要更高级的配置。
这些问题不解决,Docker 用起来会一直不得劲。接下来一个一个搞定。
## 详细步骤
### 理解 Docker 网络驱动
Docker 提供了好几种网络驱动,不同场景用不同的:
**Bridge 网络**最常用,单台主机上的容器互相通信就靠它。安装 Docker 后会自动建一个叫 docker0 的网桥,所有用默认 bridge 网络的容器都接上面。简单是简单,但隔离性一般。
**Host 网络**让容器直接用宿主机的网络命名空间,容器端口就是宿主机端口。性能会好一些,但容器和宿主机之间完全没有网络隔离,用错了风险很大。
**Overlay 网络**是为了多主机通信设计的,用在 Docker Swarm 或者 Kubernetes 环境下。跨机器的容器能透明通信,就像在同一个局域网里一样。
**Macvlan 网络**比较特殊,允许容器有独立的 MAC 地址和 IP 地址,看起来就像物理机一样。适合老应用迁移到容器化环境的场景。
不同的驱动适用于不同的情况,没有绝对的好坏之分。
### 查看和管理网络
先看看当前有哪些网络:
“`bash
docker network ls
“`
会列出所有网络,名字、驱动、作用范围都能看到。
想看某个网络的具体信息:
“`bash
docker network inspect bridge
“`
这里能看到网络的完整配置:有哪些容器连着、网关是多少、IP 段是什么。排查问题的时候这个命令特别管用。
### 创建自定义网络
建议不要用默认的 bridge,自己建一个:
“`bash
docker network create my-network
“`
可以指定更多参数:
“`bash
docker network create –driver bridge \
–subnet=172.20.0.0/16 \
–gateway=172.20.0.1 \
my-network
“`
这样创建的网络有独立的子网和网关。关键是好用:同一网络的容器可以直接用容器名做 DNS 解析,不用记 IP 地址。
### 容器网络配置
启动容器时指定网络:
“`bash
docker run -d –name my-app –network my-network my-image
“`
已经启动的容器可以连到某个网络,或者从某个网络断开:
“`bash
docker network connect my-network my-container
docker network disconnect my-network my-container
“`
### 端口映射配置
把容器端口映射到宿主机用 `-p`:
“`bash
docker run -d -p 8080:80 nginx
“`
格式是 `宿主机端口:容器端口`。这个顺序我一直记不住,每次都要查。
映射多个端口:
“`bash
docker run -d -p 8080:80 -p 8443:443 my-image
“`
还可以指定只监听本地:
“`bash
docker run -d -p 127.0.0.1:8080:80 nginx
“`
这样只有本机能访问,不会暴露到公网。生产环境尤其要注意这点。
### 网络隔离与安全
创建多个隔离的网络可以实现更精细的安全控制:
“`bash
# 前端网络
docker network create frontend-network
# 后端网络
docker network create backend-network
# 数据库网络
docker network create database-network
“`
不同角色的容器放到不同网络里。Docker 默认不允许跨网络通信,这本身就是一层保护。
## 完整代码示例
来一个完整的实战例子,演示怎么搭建一个安全的多容器架构。
### 场景
做一个 WordPress 博客系统,需要这些组件:
– Nginx 反向代理
– WordPress 应用
– MySQL 数据库
– Redis 缓存
### 创建网络
先把网络建好:
“`bash
docker network create frontend-network
docker network create backend-network
docker network create database-network
“`
三个网络相互隔离。
### 启动 MySQL
“`bash
docker run -d \
–name mysql \
–network database-network \
-e MYSQL_ROOT_PASSWORD=secure_password \
-e MYSQL_DATABASE=wordpress \
-e MYSQL_USER=wp_user \
-e MYSQL_PASSWORD=wp_password \
-v mysql-data:/var/lib/mysql \
mysql:8.0
“`
数据库只连 database-network,不暴露任何端口到宿主机。
### 启动 Redis
“`bash
docker run -d \
–name redis \
–network backend-network \
-v redis-data:/data \
redis:7-alpine \
redis-server –appendonly yes
“`
Redis 也在内部网络里,不对外暴露。
### 启动 WordPress
“`bash
docker run -d \
–name wordpress \
–network backend-network \
-e WORDPRESS_DB_HOST=mysql:3306 \
-e WORDPRESS_DB_USER=wp_user \
-e WORDPRESS_DB_PASSWORD=wp_password \
-e WORDPRESS_DB_NAME=wordpress \
-e REDIS_HOST=redis \
-v wordpress-data:/var/www/html \
wordpress:php8.2-fpm
“`
WordPress 放在 backend-network,能访问 MySQL 和 Redis,但不会直接暴露到公网。
### 启动 Nginx
“`bash
docker run -d \
–name nginx \
–network frontend-network \
-p 80:80 \
-p 443:443 \
-v nginx-conf:/etc/nginx/conf.d \
-v wordpress-data:/var/www/html \
nginx:alpine
“`
Nginx 放在 frontend-network,接收外部流量。
### Nginx 配置
写一个简单的配置文件:
“`nginx
upstream wordpress {
server wordpress:9000;
}
server {
listen 80;
server_name example.com;
root /var/www/html;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
fastcgi_pass wordpress;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ \/\.ht {
deny all;
}
}
“`
复制到容器里:
“`bash
docker cp nginx.conf nginx:/etc/nginx/conf.d/default.conf
docker exec nginx nginx -s reload
“`
### 验证网络配置
看看各个容器的网络连接:
“`bash
docker network inspect frontend-network
docker network inspect backend-network
docker network inspect database-network
“`
确认每个容器连到了正确的网络。
### 测试连通性
从 Nginx 测试到 WordPress:
“`bash
docker exec nginx curl -I http://wordpress:9000
“`
从 WordPress 测试到数据库和缓存:
“`bash
docker exec wordpress ping mysql
docker exec wordpress ping redis
“`
这些测试都应该成功。
## 运行结果
配置完成后,得到一个分层的安全架构:
**网络结构**:Nginx 在前端接收请求,WordPress 在后端处理业务,MySQL 和 Redis 在数据库层。数据库完全不暴露到公网。
**安全验证**:从外面没法直接访问数据库,因为数据库容器没有映射任何端口到宿主机。数据库层和前端层是隔离的,即使前端被黑,攻击者也很难渗透到数据库层。
**功能测试**:访问配置的域名(需要 hosts 或者 DNS 配置),应该能看到 WordPress 安装界面。安装完成后博客就能用了,Redis 缓存也会正常工作。
**性能表现**:因为容器间通信走的是 Docker 内网,不需要经过物理网络层,延迟很低。Nginx 到 WordPress 的通信基本能达到本地通信的速度。
## 总结
这篇教程讲完了 Docker 容器网络的核心内容。几个关键点:
**选对网络驱动**:开发环境 bridge 就够;生产环境多主机用 overlay;需要直连物理网络用 macvlan。
**用自定义网络**:比默认的 bridge 好用太多。容器之间用名字就能互相访问,不用记 IP,也不用 `–link`。
**端口只开必要的**:优先绑定 127.0.0.1,不是 0.0.0.0。不需要外网访问的容器干脆不暴露端口。
**网络隔离要重视**:按功能分层,前端、后端、数据库分开。 Docker 默认就不让跨网络通信,这是天然的保护。
**会排查问题**:`docker network inspect` 这个命令要会用。查一下网络状态、容器 IP、路由信息,问题基本都能定位。
搞定了这些,生产环境的容器网络配置就能应付了。网络安全不是小事,配好了不仅稳,还安全。有什么问题多实践,踩坑长记性。