Skip to content

Commit 864fecb

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

File tree

6 files changed

+76
-14
lines changed

6 files changed

+76
-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: 6 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,10 @@ 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+
) if self.network else None,
8691
)["Id"]
8792
self.docker_client.start(self._daemon_container)
8893
self.log.write(

buildrunner/docker/runner.py

Lines changed: 19 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,14 @@ def start(
250251
if entrypoint:
251252
kwargs["entrypoint"] = entrypoint
252253
del kwargs["command"]
254+
if network:
255+
kwargs["networking_config"] = self.docker_client.create_networking_config(
256+
{
257+
network: self.docker_client.create_endpoint_config(
258+
aliases=[hostname] if hostname else None
259+
)
260+
}
261+
) if network else None
253262

254263
if compare_version("1.10", self.docker_client.api_version) < 0:
255264
kwargs["dns"] = dns
@@ -654,7 +663,7 @@ def _get_status(self):
654663
pass
655664
return status
656665

657-
def get_ip(self):
666+
def get_ip(self, network=None):
658667
"""
659668
Return the ip address of the running container
660669
"""
@@ -664,7 +673,15 @@ def get_ip(self):
664673
inspection = self.docker_client.inspect_container(
665674
self.container["Id"],
666675
)
667-
ipaddr = inspection.get("NetworkSettings", {}).get("IPAddress", None)
676+
network_settings = inspection.get("NetworkSettings", {})
677+
if network:
678+
ipaddr = (
679+
network_settings.get("Networks", {})
680+
.get(network, {})
681+
.get("IPAddress", None)
682+
)
683+
else:
684+
ipaddr = network_settings.get("IPAddress", None)
668685
except docker.errors.APIError:
669686
pass
670687
return ipaddr

buildrunner/sshagent/__init__.py

Lines changed: 14 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,9 @@ 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+
) if self._network else None,
141146
host_config=self.docker_client.create_host_config(
142147
publish_all_ports=True,
143148
),
@@ -154,9 +159,15 @@ def start(self, keys):
154159
_ssh_container = self.docker_client.inspect_container(
155160
self._ssh_agent_container
156161
)
157-
_ssh_host = _ssh_container.get("NetworkSettings", {}).get(
158-
"IPAddress", _ssh_host
159-
)
162+
network_settings = _ssh_container.get("NetworkSettings", {})
163+
if self._network:
164+
_ssh_host = (
165+
network_settings.get("Networks", {})
166+
.get(self._network, {})
167+
.get("IPAddress", _ssh_host)
168+
)
169+
else:
170+
_ssh_host = network_settings.get("IPAddress", _ssh_host)
160171
_ssh_port = 22
161172
else:
162173
# 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: 34 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,8 @@ 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(names=[self.step_runner.network_name]):
72+
self._docker_client.create_network(self.step_runner.network_name)
6973
self._source_container = None
7074
self._service_runners = OrderedDict()
7175
self._service_links = {}
@@ -74,6 +78,10 @@ def __init__(self, step_runner, step: StepRun):
7478
self.runner = None
7579
self.images_to_remove = []
7680

81+
def __del__(self):
82+
if self.step_runner.network_name and self._docker_client.networks(names=[self.step_runner.network_name]):
83+
self._docker_client.remove_network(self.step_runner.network_name)
84+
7785
def _get_source_container(self):
7886
"""
7987
Get (creating the container if necessary) the container id of the
@@ -84,6 +92,11 @@ def _get_source_container(self):
8492
self.step_runner.build_runner.get_source_image(),
8593
command="/bin/sh",
8694
labels=self.step_runner.container_labels,
95+
networking_config=self._docker_client.create_networking_config(
96+
{
97+
self.step_runner.network_name: self._docker_client.create_endpoint_config()
98+
}
99+
) if self.step_runner.network_name else None,
87100
)["Id"]
88101
self._docker_client.start(
89102
self._source_container,
@@ -504,7 +517,7 @@ def _start_service_container(self, name, service: Service):
504517
_user = service.user
505518

506519
# determine if a hostname is specified
507-
_hostname = service.hostname
520+
_hostname = service.hostname or name
508521

509522
# determine if a dns host is specified
510523
_dns = None
@@ -618,6 +631,7 @@ def _start_service_container(self, name, service: Service):
618631
containers=_containers,
619632
systemd=systemd,
620633
systemd_cgroup2=self.is_systemd_cgroup2(systemd, service, _image),
634+
network=self.step_runner.network_name,
621635
)
622636
self._service_links[cont_name] = name
623637

@@ -658,9 +672,17 @@ def wait(self, name, wait_for_data):
658672
"""
659673
Wait for listening port on named container
660674
"""
661-
ipaddr = self._docker_client.inspect_container(name)["NetworkSettings"][
662-
"IPAddress"
663-
]
675+
network_settings = self._docker_client.inspect_container(name).get(
676+
"NetworkSettings", {}
677+
)
678+
if self.step_runner.network_name:
679+
ipaddr = (
680+
network_settings.get("Networks", {})
681+
.get(self.step_runner.network_name, {})
682+
.get("IPAddress", None)
683+
)
684+
else:
685+
ipaddr = network_settings.get("IPAddress", None)
664686
socket_open = False
665687

666688
if isinstance(wait_for_data, dict):
@@ -710,6 +732,7 @@ def wait(self, name, wait_for_data):
710732
nc_tester.start(
711733
# The shell is the command
712734
shell=f"-n -z {ipaddr} {port}",
735+
network=self.step_runner.network_name,
713736
)
714737

715738
nc_tester.attach_until_finished()
@@ -734,12 +757,14 @@ def wait(self, name, wait_for_data):
734757

735758
def _resolve_service_ip(self, service_name):
736759
"""
737-
If service_name represents a running service, return it's IP address.
760+
If service_name represents a running service, return its IP address.
738761
Otherwise, return the service_name
739762
"""
740763
rval = service_name
741764
if isinstance(service_name, str) and service_name in self._service_runners:
742-
ipaddr = self._service_runners[service_name].get_ip()
765+
ipaddr = self._service_runners[service_name].get_ip(
766+
self.step_runner.network_name
767+
)
743768
if ipaddr is not None:
744769
rval = ipaddr
745770
return rval
@@ -830,6 +855,7 @@ def run(self, context: dict): # pylint: disable=too-many-statements,too-many-br
830855
buildrunner_config.global_config.docker_registry,
831856
self.step_runner.multi_platform,
832857
self.step_runner.container_labels,
858+
self.step_runner.network_name,
833859
)
834860
self._sshagent.start(
835861
buildrunner_config.get_ssh_keys_from_aliases(
@@ -843,6 +869,7 @@ def run(self, context: dict): # pylint: disable=too-many-statements,too-many-br
843869
self.step_runner.log,
844870
buildrunner_config.global_config.docker_registry,
845871
self.step_runner.container_labels,
872+
self.step_runner.network_name,
846873
)
847874
self._dockerdaemonproxy.start()
848875

@@ -1031,6 +1058,7 @@ def run(self, context: dict): # pylint: disable=too-many-statements,too-many-br
10311058
container_args["systemd_cgroup2"] = self.is_systemd_cgroup2(
10321059
container_args["systemd"], self.step, _run_image
10331060
)
1061+
container_args["network"] = self.step_runner.network_name
10341062

10351063
container_id = self.runner.start(
10361064
links=self._service_links, **container_args

0 commit comments

Comments
 (0)