bin: improve manage-offline-container-images script (#10857)

Fixes bug for retrieving images with tags containing image digests.
Script now gets images from jobs and cronjobs as well.
New env variable DESTINATION_REGISTRY to push to another registry
instead of local registry.
New env variable IMAGES_FROM_FILE to pull images listed in a file
instead of getting images from a running k8s environment.
New env variable REGISTRY_PORT to override port (default is 5000).
pull/10943/head
anders-elastisys 2024-02-18 04:34:29 +01:00 committed by GitHub
parent 65b0604db7
commit 8fa5ae1865
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 68 additions and 27 deletions

2
.gitignore vendored
View File

@ -3,6 +3,8 @@
**/vagrant_ansible_inventory **/vagrant_ansible_inventory
*.iml *.iml
temp temp
contrib/offline/container-images
contrib/offline/container-images.tar.gz
contrib/offline/offline-files contrib/offline/offline-files
contrib/offline/offline-files.tar.gz contrib/offline/offline-files.tar.gz
.idea .idea

View File

@ -5,15 +5,17 @@
Container image collecting script for offline deployment Container image collecting script for offline deployment
This script has two features: This script has two features:
(1) Get container images from an environment which is deployed online, or set IMAGES_FROM_FILE
(1) Get container images from an environment which is deployed online. environment variable to get images from a file (e.g. temp/images.list after running the
./generate_list.sh script).
(2) Deploy local container registry and register the container images to the registry. (2) Deploy local container registry and register the container images to the registry.
Step(1) should be done online site as a preparation, then we bring the gotten images Step(1) should be done online site as a preparation, then we bring the gotten images
to the target offline environment. if images are from a private registry, to the target offline environment. if images are from a private registry,
you need to set `PRIVATE_REGISTRY` environment variable. you need to set `PRIVATE_REGISTRY` environment variable.
Then we will run step(2) for registering the images to local registry. Then we will run step(2) for registering the images to local registry, or to an existing
registry set by the `DESTINATION_REGISTRY` environment variable. By default, the local registry
will run on port 5000. This can be changed with the `REGISTRY_PORT` environment variable
Step(1) can be operated with: Step(1) can be operated with:

View File

@ -12,11 +12,24 @@ RETRY_COUNT=5
function create_container_image_tar() { function create_container_image_tar() {
set -e set -e
IMAGES=$(kubectl describe pods --all-namespaces | grep " Image:" | awk '{print $2}' | sort | uniq) if [ -z "${IMAGES_FROM_FILE}" ]; then
echo "Getting images from current \"$(kubectl config current-context)\""
IMAGES=$(mktemp --suffix=-images)
trap 'rm -f "${IMAGES}"' EXIT
kubectl describe cronjobs,jobs,pods --all-namespaces | grep " Image:" | awk '{print $2}' | sort | uniq > "${IMAGES}"
# NOTE: etcd and pause cannot be seen as pods. # NOTE: etcd and pause cannot be seen as pods.
# The pause image is used for --pod-infra-container-image option of kubelet. # The pause image is used for --pod-infra-container-image option of kubelet.
EXT_IMAGES=$(kubectl cluster-info dump | egrep "quay.io/coreos/etcd:|registry.k8s.io/pause:" | sed s@\"@@g) kubectl cluster-info dump | grep -E "quay.io/coreos/etcd:|registry.k8s.io/pause:" | sed s@\"@@g >> "${IMAGES}"
IMAGES="${IMAGES} ${EXT_IMAGES}" else
echo "Getting images from file \"${IMAGES_FROM_FILE}\""
if [ ! -f "${IMAGES_FROM_FILE}" ]; then
echo "${IMAGES_FROM_FILE} is not a file"
exit 1
fi
IMAGES=$(realpath $IMAGES_FROM_FILE)
fi
rm -f ${IMAGE_TAR_FILE} rm -f ${IMAGE_TAR_FILE}
rm -rf ${IMAGE_DIR} rm -rf ${IMAGE_DIR}
@ -26,9 +39,9 @@ function create_container_image_tar() {
sudo ${runtime} pull registry:latest sudo ${runtime} pull registry:latest
sudo ${runtime} save -o registry-latest.tar registry:latest sudo ${runtime} save -o registry-latest.tar registry:latest
for image in ${IMAGES} while read -r image
do do
FILE_NAME="$(echo ${image} | sed s@"/"@"-"@g | sed s/":"/"-"/g)".tar FILE_NAME="$(echo ${image} | sed s@"/"@"-"@g | sed s/":"/"-"/g | sed -E 's/\@.*//g')".tar
set +e set +e
for step in $(seq 1 ${RETRY_COUNT}) for step in $(seq 1 ${RETRY_COUNT})
do do
@ -48,18 +61,20 @@ function create_container_image_tar() {
# so that these parts will be replaced with Kubespray. # so that these parts will be replaced with Kubespray.
# - kube_image_repo: "registry.k8s.io" # - kube_image_repo: "registry.k8s.io"
# - gcr_image_repo: "gcr.io" # - gcr_image_repo: "gcr.io"
# - ghcr_image_repo: "ghcr.io"
# - docker_image_repo: "docker.io" # - docker_image_repo: "docker.io"
# - quay_image_repo: "quay.io" # - quay_image_repo: "quay.io"
FIRST_PART=$(echo ${image} | awk -F"/" '{print $1}') FIRST_PART=$(echo ${image} | awk -F"/" '{print $1}')
if [ "${FIRST_PART}" = "registry.k8s.io" ] || if [ "${FIRST_PART}" = "registry.k8s.io" ] ||
[ "${FIRST_PART}" = "gcr.io" ] || [ "${FIRST_PART}" = "gcr.io" ] ||
[ "${FIRST_PART}" = "ghcr.io" ] ||
[ "${FIRST_PART}" = "docker.io" ] || [ "${FIRST_PART}" = "docker.io" ] ||
[ "${FIRST_PART}" = "quay.io" ] || [ "${FIRST_PART}" = "quay.io" ] ||
[ "${FIRST_PART}" = "${PRIVATE_REGISTRY}" ]; then [ "${FIRST_PART}" = "${PRIVATE_REGISTRY}" ]; then
image=$(echo ${image} | sed s@"${FIRST_PART}/"@@) image=$(echo ${image} | sed s@"${FIRST_PART}/"@@ | sed -E 's/\@.*/\n/g')
fi fi
echo "${FILE_NAME} ${image}" >> ${IMAGE_LIST} echo "${FILE_NAME} ${image}" >> ${IMAGE_LIST}
done done < "${IMAGES}"
cd .. cd ..
sudo chown ${USER} ${IMAGE_DIR}/* sudo chown ${USER} ${IMAGE_DIR}/*
@ -72,6 +87,16 @@ function create_container_image_tar() {
} }
function register_container_images() { function register_container_images() {
create_registry=false
REGISTRY_PORT=${REGISTRY_PORT:-"5000"}
if [ -z "${DESTINATION_REGISTRY}" ]; then
echo "DESTINATION_REGISTRY not set, will create local registry"
create_registry=true
DESTINATION_REGISTRY="$(hostname):${REGISTRY_PORT}"
fi
echo "Images will be pushed to ${DESTINATION_REGISTRY}"
if [ ! -f ${IMAGE_TAR_FILE} ]; then if [ ! -f ${IMAGE_TAR_FILE} ]; then
echo "${IMAGE_TAR_FILE} should exist." echo "${IMAGE_TAR_FILE} should exist."
exit 1 exit 1
@ -81,18 +106,17 @@ function register_container_images() {
fi fi
# To avoid "http: server gave http response to https client" error. # To avoid "http: server gave http response to https client" error.
LOCALHOST_NAME=$(hostname)
if [ -d /etc/docker/ ]; then if [ -d /etc/docker/ ]; then
set -e set -e
# Ubuntu18.04, RHEL7/CentOS7 # Ubuntu18.04, RHEL7/CentOS7
cp ${CURRENT_DIR}/docker-daemon.json ${TEMP_DIR}/docker-daemon.json cp ${CURRENT_DIR}/docker-daemon.json ${TEMP_DIR}/docker-daemon.json
sed -i s@"HOSTNAME"@"${LOCALHOST_NAME}"@ ${TEMP_DIR}/docker-daemon.json sed -i s@"HOSTNAME"@"$(hostname)"@ ${TEMP_DIR}/docker-daemon.json
sudo cp ${TEMP_DIR}/docker-daemon.json /etc/docker/daemon.json sudo cp ${TEMP_DIR}/docker-daemon.json /etc/docker/daemon.json
elif [ -d /etc/containers/ ]; then elif [ -d /etc/containers/ ]; then
set -e set -e
# RHEL8/CentOS8 # RHEL8/CentOS8
cp ${CURRENT_DIR}/registries.conf ${TEMP_DIR}/registries.conf cp ${CURRENT_DIR}/registries.conf ${TEMP_DIR}/registries.conf
sed -i s@"HOSTNAME"@"${LOCALHOST_NAME}"@ ${TEMP_DIR}/registries.conf sed -i s@"HOSTNAME"@"$(hostname)"@ ${TEMP_DIR}/registries.conf
sudo cp ${TEMP_DIR}/registries.conf /etc/containers/registries.conf sudo cp ${TEMP_DIR}/registries.conf /etc/containers/registries.conf
else else
echo "runtime package(docker-ce, podman, nerctl, etc.) should be installed" echo "runtime package(docker-ce, podman, nerctl, etc.) should be installed"
@ -100,19 +124,28 @@ function register_container_images() {
fi fi
tar -zxvf ${IMAGE_TAR_FILE} tar -zxvf ${IMAGE_TAR_FILE}
if [ "${create_registry}" ]; then
sudo ${runtime} load -i ${IMAGE_DIR}/registry-latest.tar sudo ${runtime} load -i ${IMAGE_DIR}/registry-latest.tar
set +e set +e
sudo ${runtime} container inspect registry >/dev/null 2>&1 sudo ${runtime} container inspect registry >/dev/null 2>&1
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
sudo ${runtime} run --restart=always -d -p 5000:5000 --name registry registry:latest sudo ${runtime} run --restart=always -d -p "${REGISTRY_PORT}":"${REGISTRY_PORT}" --name registry registry:latest
fi fi
set -e set -e
fi
while read -r line; do while read -r line; do
file_name=$(echo ${line} | awk '{print $1}') file_name=$(echo ${line} | awk '{print $1}')
raw_image=$(echo ${line} | awk '{print $2}') raw_image=$(echo ${line} | awk '{print $2}')
new_image="${LOCALHOST_NAME}:5000/${raw_image}" new_image="${DESTINATION_REGISTRY}/${raw_image}"
org_image=$(sudo ${runtime} load -i ${IMAGE_DIR}/${file_name} | head -n1 | awk '{print $3}') load_image=$(sudo ${runtime} load -i ${IMAGE_DIR}/${file_name} | head -n1)
org_image=$(echo "${load_image}" | awk '{print $3}')
# special case for tags containing the digest when using docker or podman as the container runtime
if [ "${org_image}" == "ID:" ]; then
org_image=$(echo "${load_image}" | awk '{print $4}')
fi
image_id=$(sudo ${runtime} image inspect ${org_image} | grep "\"Id\":" | awk -F: '{print $3}'| sed s/'\",'//) image_id=$(sudo ${runtime} image inspect ${org_image} | grep "\"Id\":" | awk -F: '{print $3}'| sed s/'\",'//)
if [ -z "${file_name}" ]; then if [ -z "${file_name}" ]; then
echo "Failed to get file_name for line ${line}" echo "Failed to get file_name for line ${line}"
@ -136,7 +169,7 @@ function register_container_images() {
done <<< "$(cat ${IMAGE_LIST})" done <<< "$(cat ${IMAGE_LIST})"
echo "Succeeded to register container images to local registry." echo "Succeeded to register container images to local registry."
echo "Please specify ${LOCALHOST_NAME}:5000 for the following options in your inventry:" echo "Please specify \"${DESTINATION_REGISTRY}\" for the following options in your inventry:"
echo "- kube_image_repo" echo "- kube_image_repo"
echo "- gcr_image_repo" echo "- gcr_image_repo"
echo "- docker_image_repo" echo "- docker_image_repo"
@ -161,13 +194,17 @@ elif [ "${OPTION}" == "register" ]; then
register_container_images register_container_images
else else
echo "This script has two features:" echo "This script has two features:"
echo "(1) Get container images from an environment which is deployed online." echo "(1) Get container images from an environment which is deployed online, or set IMAGES_FROM_FILE"
echo " environment variable to get images from a file (e.g. temp/images.list after running the"
echo " ./generate_list.sh script)."
echo "(2) Deploy local container registry and register the container images to the registry." echo "(2) Deploy local container registry and register the container images to the registry."
echo "" echo ""
echo "Step(1) should be done online site as a preparation, then we bring" echo "Step(1) should be done online site as a preparation, then we bring"
echo "the gotten images to the target offline environment. if images are from" echo "the gotten images to the target offline environment. if images are from"
echo "a private registry, you need to set PRIVATE_REGISTRY environment variable." echo "a private registry, you need to set PRIVATE_REGISTRY environment variable."
echo "Then we will run step(2) for registering the images to local registry." echo "Then we will run step(2) for registering the images to local registry, or to an existing"
echo "registry set by the DESTINATION_REGISTRY environment variable. By default, the local registry"
echo "will run on port 5000. This can be changed with the REGISTRY_PORT environment variable"
echo "" echo ""
echo "${IMAGE_TAR_FILE} is created to contain your container images." echo "${IMAGE_TAR_FILE} is created to contain your container images."
echo "Please keep this file and bring it to your offline environment." echo "Please keep this file and bring it to your offline environment."