docker容器动态添加端口

一、背景

部署在阿里云服务器上面的容器绑定了固定端口,运行一段时间后由于业务扩展,需要在容器上绑定新的端口。本文讲述解决在容器上面动态添加端口。

二、解决思路

容器的配置文件/var/lib/docker/containers/<容器ID目录>/hostconfig.json

{
	"Binds": null,
	"ContainerIDFile": "",
	"LogConfig": {
		"Type": "json-file",
		"Config": {}
	},
	"NetworkMode": "default",
	"PortBindings": {
		"5000/tcp": [{
			"HostIp": "",
			"HostPort": "5000"
		}],
		"80/tcp": [{
			"HostIp": "",
			"HostPort": "80"
		}],
		"888/tcp": [{
			"HostIp": "",
			"HostPort": "888"
		}],
		"8888/tcp": [{
			"HostIp": "",
			"HostPort": "8888"
		}]
	},
	"RestartPolicy": {
		"Name": "always",
		"MaximumRetryCount": 0
	},
	"AutoRemove": false,
	"VolumeDriver": "",
	"VolumesFrom": null,
	"CapAdd": null,
	"CapDrop": null,
	"Capabilities": null,
	"Dns": [],
	"DnsOptions": [],
	"DnsSearch": [],
	"ExtraHosts": null,
	"GroupAdd": null,
	"IpcMode": "private",
	"Cgroup": "",
	"Links": null,
	"OomScoreAdj": 0,
	"PidMode": "",
	"Privileged": true,
	"PublishAllPorts": false,
	"ReadonlyRootfs": false,
	"SecurityOpt": ["label=disable"],
	"UTSMode": "",
	"UsernsMode": "",
	"ShmSize": 67108864,
	"Runtime": "runc",
	"ConsoleSize": [0, 0],
	"Isolation": "",
	"CpuShares": 0,
	"Memory": 0,
	"NanoCpus": 0,
	"CgroupParent": "",
	"BlkioWeight": 0,
	"BlkioWeightDevice": [],
	"BlkioDeviceReadBps": null,
	"BlkioDeviceWriteBps": null,
	"BlkioDeviceReadIOps": null,
	"BlkioDeviceWriteIOps": null,
	"CpuPeriod": 0,
	"CpuQuota": 0,
	"CpuRealtimePeriod": 0,
	"CpuRealtimeRuntime": 0,
	"CpusetCpus": "",
	"CpusetMems": "",
	"Devices": [],
	"DeviceCgroupRules": null,
	"DeviceRequests": null,
	"KernelMemory": 0,
	"KernelMemoryTCP": 0,
	"MemoryReservation": 0,
	"MemorySwap": 0,
	"MemorySwappiness": null,
	"OomKillDisable": false,
	"PidsLimit": null,
	"Ulimits": null,
	"CpuCount": 0,
	"CpuPercent": 0,
	"IOMaximumIOps": 0,
	"IOMaximumBandwidth": 0,
	"MaskedPaths": null,
	"ReadonlyPaths": null
}

/var/lib/docker/containers/<容器ID目录>/config.v2.json

{
	"StreamConfig": {},
	"State": {
		"Running": false,
		"Paused": false,
		"Restarting": false,
		"OOMKilled": false,
		"RemovalInProgress": false,
		"Dead": false,
		"Pid": 0,
		"ExitCode": 255,
		"Error": "driver failed programming external connectivity on endpoint flask_app (d8b581a6cbab76f24b7c6d446af2b0590233608794d3bf7879bba8896620f826): Error starting userland proxy: listen tcp 0.0.0.0:80: listen: address already in use",
		"StartedAt": "2020-05-25T02:07:57.38131025Z",
		"FinishedAt": "2020-06-08T13:39:30.756972425+08:00",
		"Health": null
	},
	"ID": "c37069bfeebc9ef4a532d9b9ec05e6600fcdfca499db90b6b36745d0d217809f",
	"Created": "2019-11-05T10:00:09.353749707Z",
	"Managed": false,
	"Path": "/bin/bash",
	"Args": [],
	"Config": {
		"Hostname": "c37069bfeebc",
		"Domainname": "",
		"User": "",
		"AttachStdin": false,
		"AttachStdout": false,
		"AttachStderr": false,
		"ExposedPorts": {
			"5000/tcp": {},
			"80/tcp": {},
			"888/tcp": {},
			"8888/tcp": {}
		},
		"Tty": true,
		"OpenStdin": true,
		"StdinOnce": false,
		"Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],
		"Cmd": ["/bin/bash"],
		"Image": "yyt/centos:v1",
		"Volumes": null,
		"WorkingDir": "",
		"Entrypoint": null,
		"OnBuild": null,
		"Labels": {
			"org.label-schema.build-date": "20190927",
			"org.label-schema.license": "GPLv2",
			"org.label-schema.name": "CentOS Base Image",
			"org.label-schema.schema-version": "1.0",
			"org.label-schema.vendor": "CentOS"
		}
	},
	"Image": "sha256:ba1f2161718903a0765eca9780c8eb0cac161678c576e7123fb176a0a087c6ec",
	"NetworkSettings": {
		"Bridge": "",
		"SandboxID": "63e1658daa246e837066c70162c42fda733eb3ca4fe6275023dfad3e707928a3",
		"HairpinMode": false,
		"LinkLocalIPv6Address": "",
		"LinkLocalIPv6PrefixLen": 0,
		"Networks": {
			"bridge": {
				"IPAMConfig": null,
				"Links": null,
				"Aliases": null,
				"NetworkID": "d0a1bc95d698a356a865d91791692da7ce3a48bf4061d2f757dca8c8e2d5409d",
				"EndpointID": "d8b581a6cbab76f24b7c6d446af2b0590233608794d3bf7879bba8896620f826",
				"Gateway": "",
				"IPAddress": "172.17.0.2",
				"IPPrefixLen": 16,
				"IPv6Gateway": "",
				"GlobalIPv6Address": "",
				"GlobalIPv6PrefixLen": 0,
				"MacAddress": "02:42:ac:11:00:02",
				"DriverOpts": null,
				"IPAMOperational": false
			}
		},
		"Service": null,
		"Ports": {
			"5000/tcp": [{
				"HostIp": "0.0.0.0",
				"HostPort": "5000"
			}],
			"80/tcp": [{
				"HostIp": "0.0.0.0",
				"HostPort": "80"
			}],
			"888/tcp": [{
				"HostIp": "0.0.0.0",
				"HostPort": "888"
			}],
			"8888/tcp": [{
				"HostIp": "0.0.0.0",
				"HostPort": "8888"
			}]
		},
		"SandboxKey": "/var/run/docker/netns/63e1658daa24",
		"SecondaryIPAddresses": null,
		"SecondaryIPv6Addresses": null,
		"IsAnonymousEndpoint": false,
		"HasSwarmEndpoint": false
	},
	"LogPath": "/var/lib/docker/containers/c37069bfeebc9ef4a532d9b9ec05e6600fcdfca499db90b6b36745d0d217809f/c37069bfeebc9ef4a532d9b9ec05e6600fcdfca499db90b6b36745d0d217809f-json.log",
	"Name": "/flask_app",
	"Driver": "devicemapper",
	"OS": "linux",
	"MountLabel": "",
	"ProcessLabel": "",
	"RestartCount": 0,
	"HasBeenStartedBefore": true,
	"HasBeenManuallyStopped": false,
	"MountPoints": {},
	"SecretReferences": null,
	"ConfigReferences": null,
	"AppArmorProfile": "",
	"HostnamePath": "/var/lib/docker/containers/c37069bfeebc9ef4a532d9b9ec05e6600fcdfca499db90b6b36745d0d217809f/hostname",
	"HostsPath": "/var/lib/docker/containers/c37069bfeebc9ef4a532d9b9ec05e6600fcdfca499db90b6b36745d0d217809f/hosts",
	"ShmPath": "",
	"ResolvConfPath": "/var/lib/docker/containers/c37069bfeebc9ef4a532d9b9ec05e6600fcdfca499db90b6b36745d0d217809f/resolv.conf",
	"SeccompProfile": "",
	"NoNewPrivileges": false
}

我们只需要在两个配置文件里面按照里面的格式添加端口,重启docker就可以新增端口了。

三、解决步骤

1. 进入阿里云平台开放端口

如果本地服务器可以省略该步骤
进入阿里云后台,如图:
在这里插入图片描述
添加开发端口8090,如图:
在这里插入图片描述
点击保存后就开放了8090端口。

2. 进入阿里云后台开放端口

查询已开放的端口

netstat -anp

查询指定端口是否已开

firewall-cmd --query-port=8090/tcp

提示 yes,表示开启;no表示未开启。

查看防火墙状态

 systemctl status firewalld

开启防火墙

systemctl start firewalld  

关闭防火墙

systemctl stop firewalld

若遇到无法开启

systemctl unmask firewalld.service 
systemctl start firewalld.service

添加指定需要开放的端口:

firewall-cmd --add-port=8090/tcp --permanent

重载入添加的端口:

firewall-cmd --reload

查询指定端口是否开启成功:

firewall-cmd --query-port=8090/tcp

移除指定端口:

firewall-cmd --permanent --remove-port=8090/tcp

重载入添加的端口:

firewall-cmd --reload

3. 脚本实现端口添加

创建文件add_docker_ports.py,内容如下:

if __name__ == '__main__':
  dockname = 'FlaskDemo'
  os.system('docker stop {0}'.format(dockname))  # 注意一定要先停止容器,再修改配置文件,否则端口添加不上
  addports = ['80', '443', '888', '5000', '8888', '8890']
  dockid, portlist = get_ports(dockname), addports
  # print(dockid, portlist)
  longdockid = get_dock_conf(dockid)
  # print('longdockid = ', longdockid)
  hostname = '/var/lib/docker/containers/{0}/hostconfig.json'.format(longdockid)
  configname = '/var/lib/docker/containers/{0}/config.v2.json'.format(longdockid)
  hostjson = json.loads(read_file(hostname))
  #print(hostjson)
  configjson = json.loads(read_file(configname))
  #print(configjson)
  # 删除不在列表中的端口
  for k in list(hostjson['PortBindings'].keys()):
    port = k.split('/')[0]
    if port not in addports:
      del hostjson['PortBindings']['{0}/tcp'.format(port)]

  for k in list(configjson['Config']['ExposedPorts'].keys()):
    port = k.split('/')[0]
    if port not in addports:
      del configjson['Config']['ExposedPorts']['{0}/tcp'.format(port)]
      
  for port in addports:
    hostjson['PortBindings']['{0}/tcp'.format(port)] = [{"HostIp":"","HostPort":"{0}".format(port)}] 
    configjson['Config']['ExposedPorts']['{0}/tcp'.format(port)] = {}
  print(hostjson)
  print(configjson)
  write_file(hostname, json.dumps(hostjson))
  write_file(configname, json.dumps(configjson))
  os.system('service docker restart')

脚本资源下载:add_docker_ports.py

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丁爸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值