Skip to content

Commit 02899a8

Browse files
author
Jacob Truman
committed
XENG-8909 Create docker network for step containers
1 parent 6237bfb commit 02899a8

File tree

6 files changed

+90
-14
lines changed

6 files changed

+90
-14
lines changed

README.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -690,8 +690,7 @@ Service Containers
690690
Service containers allow you to create and start additional containers that
691691
are linked to the primary build container. This is useful, for instance, if
692692
your unit or integration tests require an outside service, such as a database
693-
service. Service containers are instantiated in the order they are listed, and
694-
service containers can rely on previously instantiated service containers.
693+
service. Service containers are instantiated in the order they are listed.
695694
Service containers have the same injected environment variables and volume
696695
mounts as build containers do, but the /source mount is read-only.
697696

buildrunner/docker/daemon.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@ class DockerDaemonProxy:
1919
Class used to encapsulate Docker daemon information within a container.
2020
"""
2121

22-
def __init__(self, docker_client, log, docker_registry, container_labels):
22+
def __init__(self, docker_client, log, docker_registry, container_labels, network):
2323
""" """
2424
self.docker_client = docker_client
2525
self.docker_registry = docker_registry
2626
self.log = log
2727
self.container_labels = container_labels
28+
self.network = network
2829
self._daemon_container = None
2930
self._env = {
3031
"DOCKER_HOST": DOCKER_DEFAULT_DOCKERD_URL,
@@ -83,6 +84,12 @@ def start(self):
8384
command="/bin/sh",
8485
volumes=_volumes,
8586
host_config=self.docker_client.create_host_config(binds=_binds),
87+
labels=self.container_labels,
88+
networking_config=self.docker_client.create_networking_config(
89+
{self.network: self.docker_client.create_endpoint_config()}
90+
)
91+
if self.network
92+
else None,
8693
)["Id"]
8794
self.docker_client.start(self._daemon_container)
8895
self.log.write(

buildrunner/docker/runner.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ def start(
155155
systemd_cgroup2: bool = False,
156156
cap_add=None,
157157
privileged=False,
158+
network=None,
158159
): # pylint: disable=too-many-arguments,too-many-locals
159160
"""
160161
Kwargs:
@@ -250,6 +251,18 @@ def start(
250251
if entrypoint:
251252
kwargs["entrypoint"] = entrypoint
252253
del kwargs["command"]
254+
if network:
255+
kwargs["networking_config"] = (
256+
self.docker_client.create_networking_config(
257+
{
258+
network: self.docker_client.create_endpoint_config(
259+
aliases=[hostname] if hostname else None
260+
)
261+
}
262+
)
263+
if network
264+
else None
265+
)
253266

254267
if compare_version("1.10", self.docker_client.api_version) < 0:
255268
kwargs["dns"] = dns
@@ -654,7 +667,7 @@ def _get_status(self):
654667
pass
655668
return status
656669

657-
def get_ip(self):
670+
def get_ip(self, network=None):
658671
"""
659672
Return the ip address of the running container
660673
"""
@@ -664,7 +677,15 @@ def get_ip(self):
664677
inspection = self.docker_client.inspect_container(
665678
self.container["Id"],
666679
)
667-
ipaddr = inspection.get("NetworkSettings", {}).get("IPAddress", None)
680+
network_settings = inspection.get("NetworkSettings", {})
681+
if network:
682+
ipaddr = (
683+
network_settings.get("Networks", {})
684+
.get(network, {})
685+
.get("IPAddress", None)
686+
)
687+
else:
688+
ipaddr = network_settings.get("IPAddress", None)
668689
except docker.errors.APIError:
669690
pass
670691
return ipaddr

buildrunner/sshagent/__init__.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ def __init__(
9595
docker_registry,
9696
multiplatform_image_builder,
9797
container_labels,
98+
network,
9899
):
99100
""" """
100101
self.docker_client = docker_client
@@ -106,6 +107,7 @@ def __init__(
106107
self._ssh_channel = None
107108
self._multiplatform_image_builder = multiplatform_image_builder
108109
self._container_labels = container_labels
110+
self._network = network
109111

110112
def get_info(self):
111113
"""
@@ -138,6 +140,11 @@ def start(self, keys):
138140
f"{keys[0].get_name()} {keys[0].get_base64()}",
139141
],
140142
labels=self._container_labels,
143+
networking_config=self.docker_client.create_networking_config(
144+
{self._network: self.docker_client.create_endpoint_config()}
145+
)
146+
if self._network
147+
else None,
141148
host_config=self.docker_client.create_host_config(
142149
publish_all_ports=True,
143150
),
@@ -154,9 +161,15 @@ def start(self, keys):
154161
_ssh_container = self.docker_client.inspect_container(
155162
self._ssh_agent_container
156163
)
157-
_ssh_host = _ssh_container.get("NetworkSettings", {}).get(
158-
"IPAddress", _ssh_host
159-
)
164+
network_settings = _ssh_container.get("NetworkSettings", {})
165+
if self._network:
166+
_ssh_host = (
167+
network_settings.get("Networks", {})
168+
.get(self._network, {})
169+
.get("IPAddress", _ssh_host)
170+
)
171+
else:
172+
_ssh_host = network_settings.get("IPAddress", _ssh_host)
160173
_ssh_port = 22
161174
else:
162175
# get the Docker server ip address and ssh port exposed by this

buildrunner/steprunner/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ def __init__(
8080
self.id = str(uuid.uuid4()) # pylint: disable=invalid-name
8181
self.multi_platform = multi_platform
8282
self.container_labels = container_labels
83+
# network name is used to identify the network that the build step is running in
84+
self.network_name = f"{build_runner.build_id}-{step_name}"
8385

8486
def run(self):
8587
"""

buildrunner/steprunner/tasks/run.py

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import threading
1515
import time
1616
import uuid
17+
from encodings.aliases import aliases
18+
1719
import python_on_whales
1820

1921
import buildrunner.docker
@@ -66,6 +68,10 @@ def __init__(self, step_runner, step: StepRun):
6668
self._docker_client = buildrunner.docker.new_client(
6769
timeout=step_runner.build_runner.docker_timeout,
6870
)
71+
if self.step_runner.network_name and not self._docker_client.networks(
72+
names=[self.step_runner.network_name]
73+
):
74+
self._docker_client.create_network(self.step_runner.network_name)
6975
self._source_container = None
7076
self._service_runners = OrderedDict()
7177
self._service_links = {}
@@ -74,6 +80,12 @@ def __init__(self, step_runner, step: StepRun):
7480
self.runner = None
7581
self.images_to_remove = []
7682

83+
def __del__(self):
84+
if self.step_runner.network_name and self._docker_client.networks(
85+
names=[self.step_runner.network_name]
86+
):
87+
self._docker_client.remove_network(self.step_runner.network_name)
88+
7789
def _get_source_container(self):
7890
"""
7991
Get (creating the container if necessary) the container id of the
@@ -84,6 +96,13 @@ def _get_source_container(self):
8496
self.step_runner.build_runner.get_source_image(),
8597
command="/bin/sh",
8698
labels=self.step_runner.container_labels,
99+
networking_config=self._docker_client.create_networking_config(
100+
{
101+
self.step_runner.network_name: self._docker_client.create_endpoint_config()
102+
}
103+
)
104+
if self.step_runner.network_name
105+
else None,
87106
)["Id"]
88107
self._docker_client.start(
89108
self._source_container,
@@ -504,7 +523,7 @@ def _start_service_container(self, name, service: Service):
504523
_user = service.user
505524

506525
# determine if a hostname is specified
507-
_hostname = service.hostname
526+
_hostname = service.hostname or name
508527

509528
# determine if a dns host is specified
510529
_dns = None
@@ -618,6 +637,7 @@ def _start_service_container(self, name, service: Service):
618637
containers=_containers,
619638
systemd=systemd,
620639
systemd_cgroup2=self.is_systemd_cgroup2(systemd, service, _image),
640+
network=self.step_runner.network_name,
621641
)
622642
self._service_links[cont_name] = name
623643

@@ -658,9 +678,17 @@ def wait(self, name, wait_for_data):
658678
"""
659679
Wait for listening port on named container
660680
"""
661-
ipaddr = self._docker_client.inspect_container(name)["NetworkSettings"][
662-
"IPAddress"
663-
]
681+
network_settings = self._docker_client.inspect_container(name).get(
682+
"NetworkSettings", {}
683+
)
684+
if self.step_runner.network_name:
685+
ipaddr = (
686+
network_settings.get("Networks", {})
687+
.get(self.step_runner.network_name, {})
688+
.get("IPAddress", None)
689+
)
690+
else:
691+
ipaddr = network_settings.get("IPAddress", None)
664692
socket_open = False
665693

666694
if isinstance(wait_for_data, dict):
@@ -710,6 +738,7 @@ def wait(self, name, wait_for_data):
710738
nc_tester.start(
711739
# The shell is the command
712740
shell=f"-n -z {ipaddr} {port}",
741+
network=self.step_runner.network_name,
713742
)
714743

715744
nc_tester.attach_until_finished()
@@ -734,12 +763,14 @@ def wait(self, name, wait_for_data):
734763

735764
def _resolve_service_ip(self, service_name):
736765
"""
737-
If service_name represents a running service, return it's IP address.
766+
If service_name represents a running service, return its IP address.
738767
Otherwise, return the service_name
739768
"""
740769
rval = service_name
741770
if isinstance(service_name, str) and service_name in self._service_runners:
742-
ipaddr = self._service_runners[service_name].get_ip()
771+
ipaddr = self._service_runners[service_name].get_ip(
772+
self.step_runner.network_name
773+
)
743774
if ipaddr is not None:
744775
rval = ipaddr
745776
return rval
@@ -830,6 +861,7 @@ def run(self, context: dict): # pylint: disable=too-many-statements,too-many-br
830861
buildrunner_config.global_config.docker_registry,
831862
self.step_runner.multi_platform,
832863
self.step_runner.container_labels,
864+
self.step_runner.network_name,
833865
)
834866
self._sshagent.start(
835867
buildrunner_config.get_ssh_keys_from_aliases(
@@ -843,6 +875,7 @@ def run(self, context: dict): # pylint: disable=too-many-statements,too-many-br
843875
self.step_runner.log,
844876
buildrunner_config.global_config.docker_registry,
845877
self.step_runner.container_labels,
878+
self.step_runner.network_name,
846879
)
847880
self._dockerdaemonproxy.start()
848881

@@ -1031,6 +1064,7 @@ def run(self, context: dict): # pylint: disable=too-many-statements,too-many-br
10311064
container_args["systemd_cgroup2"] = self.is_systemd_cgroup2(
10321065
container_args["systemd"], self.step, _run_image
10331066
)
1067+
container_args["network"] = self.step_runner.network_name
10341068

10351069
container_id = self.runner.start(
10361070
links=self._service_links, **container_args

0 commit comments

Comments
 (0)