SDK - Containers - Returning image name with digest (#1768)
* SDK - Containers - Returning image name with digest Image building functions now return image name with digest: image_repo@sha256:digest Fixes https://github.com/kubeflow/pipelines/issues/1715 * Added comments
This commit is contained in:
parent
69ca3c7e4b
commit
17e0efe51d
|
|
@ -324,13 +324,13 @@ class ComponentBuilder(object):
|
|||
|
||||
# Prepare build files
|
||||
logging.info('Generate build files.')
|
||||
self._container_builder.build(local_build_dir, self._arc_docker_filename, self._target_image, timeout)
|
||||
return self._container_builder.build(local_build_dir, self._arc_docker_filename, self._target_image, timeout)
|
||||
|
||||
def build_image_from_dockerfile(self, docker_filename, timeout):
|
||||
""" build_image_from_dockerfile builds an image based on the dockerfile """
|
||||
with tempfile.TemporaryDirectory() as local_build_dir:
|
||||
self._prepare_files(local_build_dir, docker_filename)
|
||||
self._container_builder.build(local_build_dir, self._arc_docker_filename, self._target_image, timeout)
|
||||
return self._container_builder.build(local_build_dir, self._arc_docker_filename, self._target_image, timeout)
|
||||
|
||||
def _configure_logger(logger):
|
||||
""" _configure_logger configures the logger such that the info level logs
|
||||
|
|
@ -440,11 +440,11 @@ def build_python_component(component_func, target_image, base_image=None, depend
|
|||
' and push the image to ' +
|
||||
target_image)
|
||||
builder = ComponentBuilder(gcs_staging=staging_gcs_path, target_image=target_image, namespace=namespace)
|
||||
builder.build_image_from_func(component_func,
|
||||
image_name_with_digest = builder.build_image_from_func(component_func,
|
||||
base_image=base_image, timeout=timeout,
|
||||
python_version=python_version, dependency=dependency)
|
||||
logging.info('Build component complete.')
|
||||
return _generate_pythonop(component_func, target_image, target_component_file)
|
||||
return _generate_pythonop(component_func, image_name_with_digest, target_component_file)
|
||||
|
||||
def build_docker_image(staging_gcs_path, target_image, dockerfile_path, timeout=600, namespace='kubeflow'):
|
||||
""" build_docker_image automatically builds a container image based on the specification in the dockerfile and
|
||||
|
|
@ -459,5 +459,6 @@ def build_docker_image(staging_gcs_path, target_image, dockerfile_path, timeout=
|
|||
"""
|
||||
_configure_logger(logging.getLogger())
|
||||
builder = ComponentBuilder(gcs_staging=staging_gcs_path, target_image=target_image, namespace=namespace)
|
||||
builder.build_image_from_dockerfile(docker_filename=dockerfile_path, timeout=timeout)
|
||||
image_name_with_digest = builder.build_image_from_dockerfile(docker_filename=dockerfile_path, timeout=timeout)
|
||||
logging.info('Build image complete.')
|
||||
return image_name_with_digest
|
||||
|
|
|
|||
|
|
@ -63,7 +63,9 @@ class ContainerBuilder(object):
|
|||
'args': ['--cache=true',
|
||||
'--dockerfile=' + docker_filename,
|
||||
'--context=' + context,
|
||||
'--destination=' + target_image],
|
||||
'--destination=' + target_image,
|
||||
'--digest-file=/dev/termination-log', # This is suggested by the Kaniko devs as a way to return the image digest from Kaniko Pod. See https://github.com/GoogleContainerTools/kaniko#--digest-file
|
||||
],
|
||||
'image': 'gcr.io/kaniko-project/executor@sha256:78d44ec4e9cb5545d7f85c1924695c89503ded86a59f92c7ae658afa3cff5400',
|
||||
'env': [{
|
||||
'name': 'GOOGLE_APPLICATION_CREDENTIALS',
|
||||
|
|
@ -116,8 +118,19 @@ class ContainerBuilder(object):
|
|||
logging.info('Start a kaniko job for build.')
|
||||
from ._k8s_helper import K8sHelper
|
||||
k8s_helper = K8sHelper()
|
||||
k8s_helper.run_job(kaniko_spec, timeout)
|
||||
result_pod_obj = k8s_helper.run_job(kaniko_spec, timeout)
|
||||
logging.info('Kaniko job complete.')
|
||||
|
||||
# Clean up
|
||||
GCSHelper.remove_gcs_blob(context)
|
||||
|
||||
# Returning image name with digest
|
||||
(image_repo, _, image_tag) = target_image.partition(':')
|
||||
# When Kaniko build completes successfully, the termination message is the hash digest of the newly built image. Otherwise it's empty. See https://github.com/GoogleContainerTools/kaniko#--digest-file https://kubernetes.io/docs/tasks/debug-application-cluster/determine-reason-pod-failure/#customizing-the-termination-message
|
||||
termination_message = [status.state.terminated.message for status in result_pod_obj.status.container_statuses if status.name == 'kaniko'][0] # Note: Using status.state instead of status.last_state since last_state entries can still be None
|
||||
image_digest = termination_message
|
||||
if not image_digest.startswith('sha256:'):
|
||||
raise RuntimeError("Kaniko returned invalid image digest: {}".format(image_digest))
|
||||
strict_image_name = image_repo + '@' + image_digest
|
||||
logging.info('Built and pushed image: {}.'.format(strict_image_name))
|
||||
return strict_image_name
|
||||
|
|
|
|||
|
|
@ -108,9 +108,20 @@ class K8sHelper(object):
|
|||
return False
|
||||
return api_response
|
||||
|
||||
def _read_pod_status(self, pod_name, namespace):
|
||||
try:
|
||||
# Using read_namespaced_pod due to the following error: "pods \"kaniko-p2phh\" is forbidden: User \"system:serviceaccount:kubeflow:jupyter-notebook\" cannot get pods/status in the namespace \"kubeflow\""
|
||||
#api_response = self._corev1.read_namespaced_pod_status(pod_name, namespace)
|
||||
api_response = self._corev1.read_namespaced_pod(pod_name, namespace)
|
||||
except k8s_client.rest.ApiException as e:
|
||||
logging.exception('Exception when calling CoreV1Api->read_namespaced_pod_status: {}\n'.format(str(e)))
|
||||
return False
|
||||
return api_response
|
||||
|
||||
def run_job(self, yaml_spec, timeout=600):
|
||||
""" run_job runs a kubernetes job and clean up afterwards """
|
||||
pod_name, succ = self._create_k8s_job(yaml_spec)
|
||||
namespace = yaml_spec['metadata']['namespace']
|
||||
if not succ:
|
||||
return False
|
||||
# timeout in seconds
|
||||
|
|
@ -119,8 +130,9 @@ class K8sHelper(object):
|
|||
logging.info('Kubernetes job failed.')
|
||||
print(self._read_pod_log(pod_name, yaml_spec))
|
||||
return False
|
||||
status_obj = self._read_pod_status(pod_name, namespace)
|
||||
self._delete_k8s_job(pod_name, yaml_spec)
|
||||
return succ
|
||||
return status_obj
|
||||
|
||||
@staticmethod
|
||||
def sanitize_k8s_name(name):
|
||||
|
|
|
|||
|
|
@ -29,7 +29,9 @@ spec:
|
|||
args: ["--cache=true",
|
||||
"--dockerfile=dockerfile",
|
||||
"--context=gs://mlpipeline/kaniko_build.tar.gz",
|
||||
"--destination=gcr.io/mlpipeline/kaniko_image:latest"]
|
||||
"--destination=gcr.io/mlpipeline/kaniko_image:latest",
|
||||
"--digest-file=/dev/termination-log",
|
||||
]
|
||||
env:
|
||||
- name: GOOGLE_APPLICATION_CREDENTIALS
|
||||
value: /secret/gcp-credentials/user-gcp-sa.json
|
||||
|
|
|
|||
Loading…
Reference in New Issue