in cli/src/klio_cli/utils/docker_utils.py [0:0]
def build_docker_image(job_dir, image_name, image_tag, config_file=None):
"""Build given Docker image.
Note: This uses the python Docker SDK's low-level API in order to capture
and emit build logs as they are generated by Docker. Using the
high-level API, you only get access to logs at the end of the build,
which creates a bad user experience.
Args:
job_dir (str): Relative path to directory containing Dockerfile.
image_name (str): Name to build the image with (forms a ‘name:tag’ pair)
image_tag (str): Tag to build the image with (forms a ‘name:tag’ pair)
Raises:
SystemExit(1) If Docker build errors out, process terminates.
"""
def clean_logs(log_generator):
# Loop through lines containing log JSON objects.
# Example line: {"stream":"Starting build..."}\r\n{"stream":"\\n"}\n
for line in log_generator:
if isinstance(line, bytes):
line = line.decode("utf-8")
# Some lines contain multiple whitespace-separated objects.
# Split them so json.loads doesn't choke.
for log_obj in line.split("\r\n"):
# Some log objects only wrap newlines.
# Split sometimes produces '' char.
# Remove these artifacts.
if log_obj != '{"stream":"\\n"}' and log_obj != "":
yield log_obj
def print_log(log):
if "stream" in log:
logging.info(log["stream"].strip("\n"))
if "error" in log:
fail_color = "\033[91m"
end_color = "\033[0m"
logging.info(
"{}{}{}".format(
fail_color, log["errorDetail"]["message"], end_color
)
)
logging.error("\nDocker hit an error while building job image.")
logging.error(
"Please fix your Dockerfile: {}/Dockerfile".format(job_dir)
)
raise SystemExit(1)
build_flag = {
"path": job_dir,
"tag": "{}:{}".format(image_name, image_tag),
"rm": True,
"buildargs": {
"tag": image_tag,
"KLIO_CONFIG": config_file or "klio-job.yaml",
},
} # Remove intermediate build containers.
logs = docker.APIClient(base_url="unix://var/run/docker.sock").build(
**build_flag
)
for log_obj in clean_logs(logs):
log = json.loads(log_obj)
print_log(log)