1. 概述
当我们需要从宿主机访问 Docker 容器提供的服务时,就需要配置端口映射(Port Mapping)。有时候,我们可能在启动容器时忘记映射某个后续需要用到的端口。
在本文中,我们将探讨 Docker 中端口映射的重要性,并介绍几种在容器启动后添加新端口映射的方法。
2. 为什么使用端口映射
端口映射用于从宿主机访问 Docker 容器内部运行的服务。我们通过将宿主机的一个端口与容器内的某个端口进行绑定,使对宿主机端口的请求被转发到容器中。
端口映射使得容器内部的服务可以从外部访问。
启动一个新的 Docker 容器时,可以在 docker run
命令中使用 -p
参数来配置端口映射:
$ docker run -d -p 81:80 --name httpd-container httpd
上面的命令会启动一个名为 httpd-container
的容器,并将宿主机的 81 端口映射到容器的 80 端口。
httpd
默认监听 80 端口,因此我们可以通过宿主机的 81 端口访问它:
$ curl http://localhost:81
<html><body><h1>It works!</h1></body></html>
并非所有容器都必须配置端口映射。 有时我们为了安全或隔离性,不对外暴露容器服务,只允许同一 Docker 网络中的其他容器访问。
3. 为运行中的容器添加端口映射的几种方式
假设我们在启动容器时忘了配置端口映射,这时就无法通过宿主机的 TCP/IP 协议访问该容器的服务。
解决这个问题主要有三种方式:
✅ 重新启动容器:
- 停止当前容器
- 使用原镜像重新启动,并加上新的端口映射
✅ 提交容器为新镜像后重启:
- 将当前容器提交为镜像
- 使用新镜像启动容器,并配置端口映射
✅ 修改容器配置文件:
- 停止容器和 Docker 服务
- 修改容器的
hostconfig.json
和config.v2.json
文件 - 重启 Docker 服务并启动容器
接下来我们逐一介绍这几种方法。
4. 重新启动容器
最直接的方式是删除当前容器并重新启动一个新容器,使用原始镜像并添加端口映射。
这是最简单、最安全的做法,但不适用于已有大量配置或数据改动的容器。
比如我们启动了一个容器后,进行了若干操作(如安装软件、修改配置等),此时再重新启动原镜像会导致这些改动丢失。
这时候就需要使用第二种方法。
5. 提交容器为镜像后重启
与其从零开始启动新容器,我们可以将当前容器保存为一个新镜像,再用这个新镜像启动容器并配置端口映射。
这样可以保留原容器的状态和改动。
操作步骤如下:
- 停止容器并提交为新镜像:
$ docker stop httpd-container
httpd-container
$ docker commit httpd-container httpd-image
sha256:33da33fcad051c90ac9b7dea9b2dbda442767e05ddebd8d6db8ac6893ef4ef40
- 删除旧容器并用新镜像启动:
$ docker rm httpd-container
httpd-container
$ docker run -d -p 83:80 --name httpd-container httpd-image
dd2535c477ad74e80b3642abca9055efacb89eaf14572b91f91bf20cd3f0cbf3
现在,我们有了一个保留了原容器状态并配置了端口映射的新容器。
6. 动态修改 Docker 配置
前两种方式都涉及删除容器并重新创建,虽然功能一致,但容器 ID 和元数据会改变。
如果我们希望保留容器 ID 和其他元数据,可以考虑直接修改容器的配置文件。
6.1. 停止容器和服务
首先,我们启动一个未配置端口映射的容器:
$ docker run -d --name httpd-container httpd
a0ed1c9fc60c358d53400dc244e94ef0db4d1347e70bd4be725a890b062ebbe7
查看容器状态:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a0ed1c9fc60c httpd "httpd-foreground" 1 second ago Up 1 second 80/tcp httpd-container
获取容器完整 ID:
$ docker inspect --format="{{.Id}}" httpd-container
a0ed1c9fc60c358d53400dc244e94ef0db4d1347e70bd4be725a890b062ebbe7
然后停止容器和 Docker 服务:
$ docker stop httpd-container
httpd-container
$ systemctl stop docker
⚠️ 注意:停止 Docker 服务会停止所有容器,操作完成后记得重启。
6.2. 找到配置文件
Docker 容器的配置文件位于:
/var/lib/docker/containers/<容器ID>/
对于本例,路径为:
/var/lib/docker/containers/a0ed1c9fc60c358d53400dc244e94ef0db4d1347e70bd4be725a890b062ebbe7/
我们重点关注两个文件:
hostconfig.json
:包含端口绑定信息config.v2.json
:包含容器的配置信息,包括暴露的端口
6.3. 修改配置文件
首先,编辑 hostconfig.json
,找到 PortBindings
字段:
{
...
"PortBindings": {},
...
}
将其修改为:
{
...
"PortBindings": {"80/tcp":[{"HostIp":"","HostPort":"82"}]},
...
}
接着,编辑 config.v2.json
,确保 Config
节点下包含 ExposedPorts
字段:
{
"Config": {
...
"ExposedPorts": {
"80/tcp": {}
},
...
}
}
如果需要暴露多个端口,可以写成:
{
"Config": {
...
"ExposedPorts": {
"80/tcp": {},
"82/tcp": {},
"8080/tcp": {}
},
...
}
}
6.4. 验证修改
重启 Docker 服务并启动容器:
$ systemctl start docker
$ docker start httpd-container
查看端口映射是否生效:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a0ed1c9fc60c httpd "httpd-foreground" 1 hours ago Up 1 seconds 0.0.0.0:82->80/tcp, :::82->80/tcp httpd-container
测试访问:
$ curl http://localhost:82
<html><body><h1>It works!</h1></body></html>
✅ 成功!端口映射已更新,且容器 ID 和元数据保持不变。
6.5. 修改已有端口映射
如果要修改已有端口映射,也可以用相同方式:
- 修改
hostconfig.json
中的PortBindings
- 如果修改了容器监听的端口,记得在
config.v2.json
中更新ExposedPorts
- 重启 Docker 服务和容器
7. 总结
本文介绍了三种为已启动的 Docker 容器添加或修改端口映射的方法:
方法 | 是否保留容器状态 | 是否保留容器 ID | 推荐场景 |
---|---|---|---|
重新启动容器 | ❌ | ❌ | 简单、干净,适用于无状态容器 |
提交为镜像后重启 | ✅ | ❌ | 容器有状态改动时推荐 |
修改配置文件 | ✅ | ✅ | 需保留容器 ID 和元数据时使用 |
选择哪种方式取决于你的具体需求。如果你只是想快速解决问题,建议使用前两种方法;如果必须保留容器 ID,可以使用第三种方法。
💡 踩坑提醒:修改配置文件方式虽然保留了容器元数据,但操作过程较为复杂,容易出错,建议只在必要时使用。同时操作前务必备份配置文件,避免误操作导致容器无法启动。