#!/bin/bash # This script is used to build container images that are embedded in HookOS. # When HookOS boots up, the DinD container will have all the images in its cache. set -euo pipefail function docker_save_image() { local image="$1" local output_dir="$2" local output_file="${output_dir}/$(echo "${image}" | tr '/' '-')" docker save -o "${output_file}".tar "${image}" } function docker_pull_image() { local image="$1" local arch="${2-amd64}" docker pull --platform=linux/"${arch}" "${image}" } function docker_remove_image() { local image="$1" docker rmi "${image}" || true } function trap_handler() { local dind_container="$1" if [[ "${remove_dind_container}" == "true" ]]; then docker rm -f "${dind_container}" &> /dev/null else echo "DinD container NOT removed, please remove it manually" fi } function main() { local dind_container="$1" local images_file="$2" local arch="$3" local dind_container_image="$4" # Pull the images while IFS=" " read -r first_image image_tag || [ -n "${first_image}" ] ; do echo -e "----------------------- $first_image -----------------------" # Remove the image if it exists so that the image pulls the correct architecture docker_remove_image "${first_image}" docker_pull_image "${first_image}" "${arch}" done < "${images_file}" # Save the images local output_dir="${PWD}/images_tar" mkdir -p "${output_dir}" while IFS=" " read -r first_image image_tag || [ -n "${first_image}" ] ; do docker_save_image "${first_image}" "${output_dir}" done < "${images_file}" export remove_dind_container="true" # as this function maybe called multiple times, we need to ensure the container is removed trap "trap_handler ${dind_container}" RETURN # we're using set -e so the trap on RETURN will not be executed when a command fails trap "trap_handler ${dind_container}" EXIT # start DinD container # In order to avoid the src bind mount directory (./images/) ownership from changing to root # we don't bind mount to /var/lib/docker in the container because the DinD container is running as root and # will change the permissions of the bind mount directory (images/) to root. echo -e "Starting DinD container" echo -e "-----------------------" docker run -d --privileged --name "${dind_container}" -v "${PWD}/images_tar":/images_tar -v "${PWD}"/images/:/var/lib/docker-embedded/ -d "${dind_container_image}" # wait until the docker daemon is ready until docker exec "${dind_container}" docker info &> /dev/null; do sleep 1 if [[ $(docker inspect -f '{{.State.Status}}' "${dind_container}") == "exited" ]]; then echo "DinD container exited unexpectedly" docker logs "${dind_container}" exit 1 fi done # As hook-docker uses the overlay2 storage driver the DinD must use the overlay2 storage driver too. # make sure the overlay2 storage driver is used by the DinD container. # The VFS storage driver might get used if /var/lib/docker in the DinD container cannot be used by overlay2. storage_driver=$(docker exec "${dind_container}" docker info --format '{{.Driver}}') if [[ "${storage_driver}" != "overlay2" ]]; then export remove_dind_container="false" echo "DinD container is not using overlay2 storage driver, storage driver detected: ${storage_driver}" exit 1 fi # remove the contents of /var/lib/docker-embedded so that any previous images are removed. Without this it seems to cause boot issues. docker exec "${dind_container}" sh -c "rm -rf /var/lib/docker-embedded/*" # Load the images for image_file in "${output_dir}"/*; do echo -e "Loading image: ${image_file}" docker exec "${dind_container}" docker load -i "/images_tar/$(basename ${image_file})" done # clean up tar files rm -rf "${output_dir}"/* # Create any tags for the images and remove any original tags while IFS=" " read -r first_image image_tag remove_original || [ -n "${first_image}" ] ; do if [[ "${image_tag}" != "" ]]; then docker exec "${dind_container}" docker tag "${first_image}" "${image_tag}" if [[ "${remove_original}" == "true" ]]; then docker exec "${dind_container}" docker rmi "${first_image}" fi fi done < "${images_file}" # We need to copy /var/lib/docker to /var/lib/docker-embedded in order for HookOS to use the Docker images in its build. docker exec "${dind_container}" sh -c "cp -a /var/lib/docker/* /var/lib/docker-embedded/" } arch="${1-amd64}" dind_container_name="hookos-dind" images_file="images.txt" dind_container_image="${2-docker:dind}" main "${dind_container_name}" "${images_file}" "${arch}" "${dind_container_image}"