以每周一个节点,记录知识点。
2024-12-09~15
不重建 Docker 容器的情况下修改端口绑定
在 Docker 中,我们可以通过 docker run -p
或者 docker run -P
来将 container 的端口映射到宿主机的端口。但是如果我们想修改 container 的端口映射,通常的做法是删除 container,然后重新创建一个新的 container。但是这样做会导致 container 的数据丢失,如果我们不想丢失数据,可以通过修改 container 的配置文件来实现。
例如我们想将 container 的 80 端口映射到 8080 端口,可以按照下列方式操作:
- 查看 container 的 id
docker inspect --format="{{.Id}}" container_name
- 关闭容器和 docker 服务
docker stop container_name systemctl stop docker
- 修改 container 的配置文件
修改
/var/lib/docker/containers/{{container_id}}/hostconfig.json
文件中的PortBindings
配置,将 80 端口映射到 8080 端口。... "PortBindings": { "3000/tcp": [ { "HostIp": "", "HostPort": "3001" } ], "80/tcp": [ { "HostIp": "", "HostPort": "8080" } ] } ...
修改
/var/lib/docker/containers/{{container_id}}/config.v2.json
文件中的ExposedPorts
,Ports
配置... "Config": { "ExposedPorts": { "3000/tcp": {}, "80/tcp": {} } }, ... "NetworkSettings": { "Ports": { "3000/tcp": [ { "HostIp": "0.0.0.0", "HostPort": "3001" } ], "80/tcp": [ { "HostIp": "0.0.0.0", "HostPort": "8080" } ] } } ...
- 重启 Docker 服务
systemctl restart docker
- 启动 container
docker start container_name
- 查看 container 的端口绑定
docker port container_name
但是上面的方式需要重启 Docker container,如果不想重启 container,可以通过临时修改 iptables 规则来实现。
HOST_PORT=8080
CONTAINER_PORT=80
CONTAINER_IP=$(docker inspect --format="{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}" container_name)
# 在 nat 表中添加 DNAT 规则, 将宿主机的 HOST_PORT 端口映射到容器的 CONTAINER_PORT 端口
iptables -t nat -I DOCKER 1 -p tcp --dport ${HOST_PORT} -j DNAT --to-destination ${CONTAINER_IP}:${CONTAINER_PORT}
# 在 nat 表中添加 MASQUERADE 规则, 使容器可以访问外部网络
iptables -t nat -A POSTROUTING -j MASQUERADE -p tcp --source ${CONTAINER_IP} --destination ${CONTAINER_IP} --dport ${CONTAINER_PORT}
# 在 filter 表中添加 ACCEPT 规则, 允许外部访问容器的 CONTAINER_PORT 端口
iptables -A DOCKER -j ACCEPT -p tcp --destination ${CONTAINER_IP} --dport ${CONTAINER_PORT}
注意: 上面的方式只能在 Docker container 启动后才能生效,如果 container 重启,需要重新执行上面的命令。宿主机重启后,上面的规则会失效,需要重新执行上面的命令。
2024-12-23~29
非root用户监听特权端口方案
特权端口是指1~1023之间的端口,这些区间范围端口通常需要管理员权限才能监听。非管理员权限只能监控特权端口(1024以上的端口)。
方案1: 使用内核参数
举例:用一个普通用户监控80端口
- 使用root添加内核参数,值是我们需要使用普通用户所监听的端口
# sysctl -w net.ipv4.ip_unprivileged_port_start=80
- 切换到普通用户并开启监听端口
# su - zhang3 [zhang3@c1 ~]$ python3 -m http.server 80 Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
方案2:使用setcap命令添加权限
为程序赋予 CAP_NET_BIND_SERVICE 权限,即使服务程序运行在非root帐户下,也能够 binding 到低位端口。以Nginx为例:
# setcap 'cap_net_bind_service=+eip' /usr/sbin/nginx
此时就可以使用普通用户来运行nginx,即使是监控1024以下的端口。
假如哪一天我想将这权限进行回收,使用以下命令来实现:
# setcap -r /usr/sbin/nginx
方案3: 使用 authbind工具
- 为Linux系统安装 authbind
# wget https://s3.amazonaws.com/aaronsilber/public/authbind-2.1.1-0.1.x86_64.rpm # rpm -vih uthbind-2.1.1-0.1.x86_64.rpm Verifying... ################################# [100%] 准备中... ################################# [100%] 正在升级/安装... 1:authbind-2.1.1-0.1 ################################# [100%] Debian/Ubuntu # apt install authbind
- 分配特定端口
# touch /etc/authbind/byport/80 # chown zhang3 /etc/authbind/byport/80 # chmod 500 /etc/authbind/byport/80
- 启动端口
# su - zhang3 $ authbind --deep python3 -m http.server 80 $ ps -ef |grep python3 zhang3 114803 114741 2 23:47 pts/1 00:00:00 python3 -m http.server 80
- https://vqiu.cn/nonroot-user-listening-on-privilege-ports/