Openstack Zun 容器网络使用主机端口映射

传参定义:
使用容器的labels属性作为端口映射的扩展字段进行传参。

格式:

1
2
3
4
"labels": {
"mode": "port_binding"
"expose_ports": {80:3001, 31:3002...}
}

参数解析:

  • mode:端口映射模式,值为PortBinding时开启端口映射模式,其他则采用Openstack Neutron方式(Kuryr)。
  • expose_ports:容器开放端口映射关系,Key为容器内部端口,Value为节点端口映射端口(内:外)
    默认值当前expose_ports长度数量为1,如以后内部端口集合需要开放多个可以考虑扩展。

kd_zun_client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
def createContainer(self, opsName, imageUuid, nets, security_groups, command=None, labels={}):
self.logger.DEBUG("::API: createContainer")

IMAGE_PULL_POLICY = "ifnotpresent"
IMAGE_DRIVER = "glance"
INTERACTICE = True

run_container_dict = {
"image_pull_policy": IMAGE_PULL_POLICY,
"image_driver": IMAGE_DRIVER,
"interactive": INTERACTICE
}

run_container_dict.update({
"name": opsName,
"image": imageUuid,
"nets": nets,
"security_groups": security_groups
})
if command:
run_container_dict.update({
"command": [command]
})
if labels:
run_container_dict.update({
"labels": labels
})

self.logger.INFO("*Container: {}".format(run_container_dict))

try:
_c = self._zunClient.containers.run(**run_container_dict)

def __instanceSpawn():
while 1:
try:
docker = self.findContainer(_c.uuid)
except Exception as e:
self.logger.WARNING(e)
yield constant.NOVA_POLL_INTERVAL
continue

if docker.status not in ('Running', 'Error'):
yield constant.NOVA_POLL_INTERVAL
elif docker.status == 'Error':
raise self.StdException, self.errno.CONTAINER_STATE_ERROR
else:
self.logger.INFO("Docker: {0} spawn status: {1}".format(_c.uuid, docker.status))
break
try:
self.wait(__instanceSpawn, timeout=constant.NOVA_SPAWN_TIMEOUT)
except Exception:
self.forceDeleteContainer(_c.uuid)
raise
return _c, _c.uuid
except Exception as e:
self.logger.ERROR("create container exception: {0}.".format(e))
raise self.StdException, self.errno.CREATE_CONTAINER_ERROR

/usr/lib/python2.7/site-packages/zun/container/docker/driver.py 行134

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
134     def create(self, context, container, image, requested_networks,
135 requested_volumes):
136 LOG.info("*** create start.")
137 sandbox_id = container.get_sandbox_id()
138 LOG.info("*** sandbox_id: {}".format(sandbox_id))
139 LOG.info("*** container: {}".format(container))
140 with docker_utils.docker_client() as docker:
141 name = container.name
142 addresses = {}
143 kwargs = {
144 'name': self.get_container_name(container),
145 'command': container.command,
146 'environment': container.environment,
147 'working_dir': container.workdir,
148 'labels': container.labels,
149 'tty': container.interactive,
150 'stdin_open': container.interactive,
151 }
152 if not sandbox_id:
153 # Sandbox is not used so it is legitimate to customize
154 # the container's hostname
155 kwargs['hostname'] = container.hostname
156
157 if not self._is_runtime_supported():
158 if container.runtime:
159 raise exception.ZunException(_(
160 'Specifying runtime in Docker API is not supported'))
161 runtime = None
162 else:
163 runtime = container.runtime or CONF.container_runtime
164 if container.labels and container.labels.get("mode") == "port_binding":
165 host_config = {}
166 host_config['runtime'] = runtime
167 host_config['port_bindings'] = {}
168 import json
169 #for expose in json.loads(container.labels.get("expose_ports")):
170 # host_config['port_bindings'].update({int(expose): int(container.labels.get("bind_port"))})
171 # host_config['port_bindings'] = {80:int(container.labels.get("port"))}
172 port_list = []
173 for _k,_v in json.loads(container.labels.get("expose_ports")).items():
174 host_config['port_bindings'].update({"{}/tcp".format(_k): int(_v), "{}/udp".format(_k): int(_v)})
175 port_list.append(int(_k))
176 port_list.append((int(_k), 'udp'))
177 kwargs['host_config'] = docker.create_host_config(**host_config)
178 kwargs['ports'] = port_list
179 LOG.info("*** kwargs: {}".format(kwargs))
180 else:
181 network_api = zun_network.api(context=context, docker_api=docker)
182 LOG.debug('Creating container with image %(image)s name %(name)s',
183 {'image': image['image'], 'name': name})
184 self._provision_network(context, network_api, requested_networks)
185 binds = self._get_binds(context, requested_volumes)
186 if not sandbox_id:
187 # Sandbox is not used so it is legitimate to customize
188 # the container's hostname
189 kwargs['hostname'] = container.hostname
190
191 if not self._is_runtime_supported():
192 if container.runtime:
193 raise exception.ZunException(_(
194 'Specifying runtime in Docker API is not supported'))
195 runtime = None
196 else:
197 runtime = container.runtime or CONF.container_runtime
198
199 host_config = {}
200 host_config['runtime'] = runtime
201 host_config['binds'] = binds
202 kwargs['volumes'] = [b['bind'] for b in binds.values()]
203 if sandbox_id:
204 host_config['network_mode'] = 'container:%s' % sandbox_id
205 # TODO(hongbin): Uncomment this after docker-py add support for
206 # container mode for pid namespace.
207 # host_config['pid_mode'] = 'container:%s' % sandbox_id
208 host_config['ipc_mode'] = 'container:%s' % sandbox_id
209 else:
210 self._process_networking_config(
211 context, container, requested_networks, host_config,
212 kwargs, docker)
213 if container.auto_remove:
214 host_config['auto_remove'] = container.auto_remove
215 if container.memory is not None:
216 host_config['mem_limit'] = container.memory
217 if container.cpu is not None:
218 host_config['cpu_quota'] = int(100000 * container.cpu)
219 host_config['cpu_period'] = 100000
220 if container.restart_policy:
221 count = int(container.restart_policy['MaximumRetryCount'])
222 name = container.restart_policy['Name']
223 host_config['restart_policy'] = {'Name': name,
224 'MaximumRetryCount': count}
225 if container.disk:
226 disk_size = str(container.disk) + 'G'
227 host_config['storage_opt'] = {'size': disk_size}
228
229 kwargs['host_config'] = docker.create_host_config(**host_config)
230
231 addresses = self._setup_network_for_container(
232 context, container, requested_networks, network_api)
233
234 image_repo = image['repo'] + ":" + image['tag']
235 LOG.info("*** kwargs: {}".format(kwargs))
236 response = docker.create_container(image_repo, **kwargs)
237 container.container_id = response['Id']
238
239 LOG.info("*** addresses: {}".format(addresses))
240
241 response = docker.inspect_container(container.container_id)
242 self._populate_container(container, response)
243 container.save(context)
244 return container

kd_zun_client调用Example

1
2
3
4
5
6
7
8
zc = KdZunClient()
print zc.createContainer(
opsName="test8",
imageUuid="9641f1c2-1082-4575-924d-26089573a3d5",
nets=[{"network": "0cfd1a52-b888-4e2d-b95b-5e82e22ff966"}],
security_groups=["default"],
labels={"mode": "port_binding", "expose_ports": json.dumps({80:3008})}
)

Openstack Zun 容器网络使用主机端口映射
http://maitianxin.github.io/2024/02/28/openstack/zun/openstack_zun_portbind/
作者
Matianxin
发布于
2024年2月28日
许可协议