From 3fb025b5c9d55c4ad8c1b841c68c6aadcdedd3d1 Mon Sep 17 00:00:00 2001 From: David Boreham Date: Thu, 13 Jun 2024 03:26:58 +0000 Subject: [PATCH] Make remote image tags unique to the deployment (#838) Reviewed-on: https://git.vdb.to/cerc-io/stack-orchestrator/pulls/838 Reviewed-by: Thomas E Lackey Co-authored-by: David Boreham Co-committed-by: David Boreham --- stack_orchestrator/deploy/images.py | 29 ++++++++++++++----- stack_orchestrator/deploy/k8s/cluster_info.py | 9 ++++-- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/stack_orchestrator/deploy/images.py b/stack_orchestrator/deploy/images.py index 77713d18..891b9a2a 100644 --- a/stack_orchestrator/deploy/images.py +++ b/stack_orchestrator/deploy/images.py @@ -29,16 +29,29 @@ def _image_needs_pushed(image: str): return image.endswith(":local") +def _remote_tag_for_image(image: str, remote_repo_url: str): + # Turns image tags of the form: foo/bar:local into remote.repo/org/bar:deploy + major_parts = image.split("/", 2) + image_name_with_version = major_parts[1] if 2 == len(major_parts) else major_parts[0] + (image_name, image_version) = image_name_with_version.split(":") + if image_version == "local": + return f"{remote_repo_url}/{image_name}:deploy" + else: + return image + + +# Note: do not add any calls this function def remote_image_exists(remote_repo_url: str, local_tag: str): docker = DockerClient() try: - remote_tag = remote_tag_for_image(local_tag, remote_repo_url) + remote_tag = _remote_tag_for_image(local_tag, remote_repo_url) result = docker.manifest.inspect(remote_tag) return True if result else False except Exception: # noqa: E722 return False +# Note: do not add any calls this function def add_tags_to_image(remote_repo_url: str, local_tag: str, *additional_tags): if not additional_tags: return @@ -47,18 +60,20 @@ def add_tags_to_image(remote_repo_url: str, local_tag: str, *additional_tags): raise Exception(f"{local_tag} does not exist in {remote_repo_url}") docker = DockerClient() - remote_tag = remote_tag_for_image(local_tag, remote_repo_url) - new_remote_tags = [remote_tag_for_image(tag, remote_repo_url) for tag in additional_tags] + remote_tag = _remote_tag_for_image(local_tag, remote_repo_url) + new_remote_tags = [_remote_tag_for_image(tag, remote_repo_url) for tag in additional_tags] docker.buildx.imagetools.create(sources=[remote_tag], tags=new_remote_tags) -def remote_tag_for_image(image: str, remote_repo_url: str): +def remote_tag_for_image_unique(image: str, remote_repo_url: str, deployment_id: str): # Turns image tags of the form: foo/bar:local into remote.repo/org/bar:deploy major_parts = image.split("/", 2) image_name_with_version = major_parts[1] if 2 == len(major_parts) else major_parts[0] (image_name, image_version) = image_name_with_version.split(":") if image_version == "local": - return f"{remote_repo_url}/{image_name}:deploy" + # Salt the tag with part of the deployment id to make it unique to this deployment + deployment_tag = deployment_id[0, 7] + return f"{remote_repo_url}/{image_name}:deploy-{deployment_tag}" else: return image @@ -73,14 +88,14 @@ def push_images_operation(command_context: DeployCommandContext, deployment_cont docker = DockerClient() for image in images: if _image_needs_pushed(image): - remote_tag = remote_tag_for_image(image, remote_repo_url) + remote_tag = remote_tag_for_image_unique(image, remote_repo_url, deployment_context.id) if opts.o.verbose: print(f"Tagging {image} to {remote_tag}") docker.image.tag(image, remote_tag) # Run docker push commands to upload for image in images: if _image_needs_pushed(image): - remote_tag = remote_tag_for_image(image, remote_repo_url) + remote_tag = remote_tag_for_image_unique(image, remote_repo_url, deployment_context.id) if opts.o.verbose: print(f"Pushing image {remote_tag}") docker.image.push(remote_tag) diff --git a/stack_orchestrator/deploy/k8s/cluster_info.py b/stack_orchestrator/deploy/k8s/cluster_info.py index dbf7c907..7c696691 100644 --- a/stack_orchestrator/deploy/k8s/cluster_info.py +++ b/stack_orchestrator/deploy/k8s/cluster_info.py @@ -26,7 +26,7 @@ from stack_orchestrator.deploy.k8s.helpers import envs_from_environment_variable from stack_orchestrator.deploy.deploy_util import parsed_pod_files_map_from_file_names, images_for_deployment from stack_orchestrator.deploy.deploy_types import DeployEnvVars from stack_orchestrator.deploy.spec import Spec, Resources, ResourceLimits -from stack_orchestrator.deploy.images import remote_tag_for_image +from stack_orchestrator.deploy.images import remote_tag_for_image_unique DEFAULT_VOLUME_RESOURCES = Resources({ "reservations": {"storage": "2Gi"} @@ -326,8 +326,11 @@ class ClusterInfo: if opts.o.debug: print(f"Merged envs: {envs}") # Re-write the image tag for remote deployment - image_to_use = remote_tag_for_image( - image, self.spec.get_image_registry()) if self.spec.get_image_registry() is not None else image + # Note self.app_name has the same value as deployment_id + image_to_use = remote_tag_for_image_unique( + image, + self.spec.get_image_registry(), + self.app_name) if self.spec.get_image_registry() is not None else image volume_mounts = volume_mounts_for_service(self.parsed_pod_yaml_map, service_name) container = client.V1Container( name=container_name,