一、背景
部署在阿里云服务器上面的容器绑定了固定端口,运行一段时间后由于业务扩展,需要在容器上绑定新的端口。本文讲述解决在容器上面动态添加端口。
二、解决思路
容器的配置文件/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