Docker 容器网络配置详解:从基础到实战

# 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、路由信息,问题基本都能定位。

搞定了这些,生产环境的容器网络配置就能应付了。网络安全不是小事,配好了不仅稳,还安全。有什么问题多实践,踩坑长记性。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇