如何修改正在运行的 Docker 容器端口映射?这是从中文网络世界中搜集到的一道真实的大厂面试题。下面通过集中情况来讨论如何实现这个问题。
容器未启动?
如果你的容器还没有构建时,想添加端口映射时,你只需要在创建容器的时候添加 -p 参数,想添加几个端口映射就追加几个 -p 参数。类似于如下是启动elasticsearch实例的示例:
docker run --name elasticsearch -d \
-p 9200:9200 \
-p 9300:9300 \
-e "discovery.type=single-node" \
docker.elastic.co/elasticsearch/elasticsearch:7.10.1
docker容器暴露端口的形式有四种:
| 参数 | 说明 |
|---|---|
| -P(大写P) | 将指定的容器端口映射到宿主机所有地址的一个随机端口 |
| -p : | 将容器端口映射到指定的主机端口 |
| -P ::(大写P) | 将容器端口映射到主机指定ip的随机端口 |
| -p :: | 将容器端口映射到指定主机ip的指定端口 |
容器已启动?
方法一: 删除原有容器,重新建新容器
这个解决方案最为简单,把原来的容器删掉,重新建一个。当然这次不要忘记加上端口映射。
sean@sean-VMware-Virtual-Platform:~$ docker run -d -p 8080:80 --name webserver -v /data/web:/usr/share/nginx/html nginx:alpine
Unable to find image 'nginx:alpine' locally
alpine: Pulling from library/nginx
c6a83fedfae6: Pull complete
7f5898476db7: Pull complete
45f552c78c31: Pull complete
62a896bb4a21: Pull complete
532b9a30583c: Pull complete
41c49cbde6a6: Pull complete
9da224fdd412: Pull complete
35b039ba2bc5: Pull complete
Digest: sha256:c04c18adc2a407740a397c8407c011fc6c90026a9b65cceddef7ae5484360158
Status: Downloaded newer image for nginx:alpine
258edd02bfcdf6c5a4ef554b8ee614bc7e7e4530384109ef1f3c37b1c972cfe2
优缺点:优点是简单快捷,在测试环境使用较多。缺点是如果是数据库镜像,那重新建一个又要重新配置一次,就会比较麻烦。
方法二:修改容器配置文件,重启docker服务
但是想修改或者添加端口时,先停止掉正在运行的容器。
以下内容都是以容器 id 为 258edd02bfcd 进行操作的,请务必将容器 id 换成你自己需要修改的容器 id。
docker ps
docker stop {容器的名称或者 id }
比如:
sean@sean-VMware-Virtual-Platform:~$ docker stop 258edd02bfcd
258edd02bfcd
sean@sean-VMware-Virtual-Platform:~$
查看容器完整的 hash_of_the_container 数值:
docker inspect {容器的名称或者 id } | grep Id
# 比如:
sean@sean-VMware-Virtual-Platform:~$ docker inspect 258edd02bfcd|grep Id
"Id": "258edd02bfcdf6c5a4ef554b8ee614bc7e7e4530384109ef1f3c37b1c972cfe2",
打开 hostconfig.json 配置文件
vim /var/lib/docker/containers/{hash_of_the_container}/hostconfig.json
比如:
nano /var/lib/docker/containers/258edd02bfcdf6c5a4ef554b8ee614bc7e7e4530384109ef1f3c37b1c972cfe2/hostconfig.json
如果你不想先查看完整的容器 hash_of_the_container 数值,你也可以直接先切换到当前容器相关目录中 cd /var/lib/docker/containers/{hash_of_the_container}* ,然后再去编辑 hostconfig.json 配置文件。
cd /var/lib/docker/containers/{hash_of_the_container}*
比如
cd /var/lib/docker/containers/cbe26510c276*
然后再去编辑 hostconfig.json 配置文件:
vim hostconfig.json
修改 hostconfig.json 配置文件
在 hostconfig.json 配置文件中,找到 "PortBindings":{} 这个配置项,然后进行修改。这里的Nginx添加了将宿主机的 8080 端口映射到容器的 80 端口。
HostPort 对应的端口代表 宿主机 的端口。
建议容器使用什么端口,宿主机就映射什么端口,方便以后管理。当然,具体情况,具体分析。
"PortBindings":{
"80/tcp":[
{
"HostIp":"","HostPort":"8080"
}
]
}
只需要修改 "PortBindings": {} 中对应的"HostPort"的值,修改后的内容如下:
"PortBindings":{
"80/tcp":[
{
"HostIp":"","HostPort":"8000"
}
]
}
最后重启 docker,然后查看容器相关配置信息是否已经修改完毕
systemctl restart docker
查看容器相关配置信息:
docker inspect {容器的名称或者 id }
# 比如:
docker inspect 258edd02bfcd
配置符合你的要求后,再次启动容器:
docker start {容器的名称或者 id }
# 比如:
docker start 258edd02bfcd
优缺点:这个方法的优点是没有副作用,操作简单。缺点是需要重启整个docker服务,如果在同一个宿主机上运行着多个容器服务的话,就会影响其他容器服务。
方法三:利用docker commit新构镜像
docker commit:把一个容器的文件改动和配置信息commit到一个新的镜像。这个在测试的时候会非常有用,把容器所有的文件改动和配置信息导入成一个新的docker镜像,然后用这个新的镜像重起一个容器,这对之前的容器不会有任何影响。
停止docker容器
docker stop container01
commit该docker容器
docker commit container01 new_image:tag
用前一步新生成的镜像重新起一个容器
docker run --name container02 -p 80:80 new_image:tag
优缺点:这种方式的优点是不会影响统一宿主机上的其他容器,缺点是管理起来显得比较乱,没有第二种方法那么直观。