mirror container images
Less than 1 minute
mirror container images
prepare
- argo workflows is ready
- minio is ready for artifact repository
- endpoint: minio.storage:9000
demo
- configure s3 artifact repository
- prepare
images-to-mirror.yaml
which contains a configmap storing a list of images to mirrorapiVersion: v1 kind: ConfigMap metadata: name: images-to-mirror data: images-to-mirror.yaml: | - registry: docker.io repository: library/busybox tag: stable-glibc - registry: docker.io repository: library/alpine tag: latest - registry: ghcr.io repository: ben-wangz/blog-skopeo tag: main
- apply
images-to-mirror.yaml
to k8skubectl -n business-workflows apply -f images-to-mirror.yaml
- prepare
registry-credentials
secret#REGISTRY_INSECURE=false #REGISTRY=REGISTRY #REGISTRY_USERNAME=your-username #REGISTRY_PASSWORD=your-password kubectl -n business-workflows create secret generic registry-credentials \ --from-literal="insecure=${REGISTRY_INSECURE:-false}" \ --from-literal="registry=${REGISTRY:-docker.io}" \ --from-literal="username=${REGISTRY_USERNAME:-wangz2019}" \ --from-literal="password=${REGISTRY_PASSWORD}"
- prepare
mirror-container-images.yaml
- with-docker
apiVersion: argoproj.io/v1alpha1 kind: Workflow metadata: generateName: mirror-container-images- spec: entrypoint: entry artifactRepositoryRef: configmap: artifact-repositories key: default-artifact-repository serviceAccountName: argo-workflow templates: - name: entry dag: tasks: - name: initialization template: initialization arguments: parameters: - name: registry-credentials-secret-name value: registry-credentials - name: images-to-mirror-configmap-name value: images-to-mirror - name: dind dependencies: - initialization template: dind arguments: parameters: - name: insecure-option value: "{{tasks.initialization.outputs.parameters.insecure-option}}" - name: insecure-registry value: "{{tasks.initialization.outputs.parameters.insecure-registry}}" - name: wait-for-dind dependencies: - dind template: wait-for-dind arguments: parameters: - name: dockerd-host value: "{{tasks.dind.ip}}" - name: mirror dependencies: - wait-for-dind template: mirror arguments: parameters: - name: dockerd-host value: "{{tasks.dind.ip}}" - name: repository-prefix value: wangz2019/mirror_ - name: keep-structure value: "false" - name: string-to-replace-slash value: _ - name: registry-credentials-secret-name value: registry-credentials - name: dry-run-push value: "false" artifacts: - name: images-to-mirror from: "{{tasks.initialization.outputs.artifacts.images-to-mirror}}" - name: initialization inputs: parameters: - name: registry-credentials-secret-name - name: images-to-mirror-configmap-name volumes: - name: images-to-mirror configMap: name: "{{inputs.parameters.images-to-mirror-configmap-name}}" container: image: docker.io/library/alpine:3.19.1 volumeMounts: - name: images-to-mirror mountPath: /app/images-to-mirror.yaml subPath: images-to-mirror.yaml readOnly: true env: - name: REGISTRY_INSECURE valueFrom: secretKeyRef: name: "{{inputs.parameters.registry-credentials-secret-name}}" key: insecure - name: REGISTRY valueFrom: secretKeyRef: name: "{{inputs.parameters.registry-credentials-secret-name}}" key: registry command: - sh - -c args: - | printf "--insecure-registry" > /tmp/insecure-option if [ "${REGISTRY_INSECURE}" = "true" ]; then echo "insecure registry ${REGISTRY}" printf "%s" ${REGISTRY} > /tmp/insecure-registry else printf "127.0.0.1" > /tmp/insecure-registry fi outputs: parameters: - name: insecure-option valueFrom: path: /tmp/insecure-option - name: insecure-registry valueFrom: path: /tmp/insecure-registry artifacts: - name: images-to-mirror path: /app/images-to-mirror.yaml - name: dind daemon: true inputs: parameters: - name: insecure-option - name: insecure-registry container: image: docker.io/library/docker:25.0.3-dind-alpine3.19 env: - name: DOCKER_TLS_CERTDIR value: "" command: - dockerd-entrypoint.sh - "{{inputs.parameters.insecure-option}}" - "{{inputs.parameters.insecure-registry}}" securityContext: privileged: true - name: wait-for-dind inputs: parameters: - name: dockerd-host container: image: ghcr.io/ben-wangz/blog-docker-cli-with-bash:main env: - name: DOCKER_HOST value: "{{inputs.parameters.dockerd-host}}" command: - sh - -c args: - | until docker ps; do sleep 3; done; - name: mirror inputs: artifacts: - name: images-to-mirror path: /app/images.yaml - name: mirror-scripts path: /app/mirror.sh raw: data: | #! /bin/bash set -e SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" IMAGE_YAML_FILE=${IMAGE_YAML_FILE:-${SCRIPT_DIR}/images.yaml} KEEP_STRUCTURE=${KEEP_STRUCTURE:-true} STRING_TO_REPLACE_SLASH=${STRING_TO_REPLACE_SLASH:-_} REGISTRY_INSECURE=${REGISTRY_INSECURE:-true} if type podman > /dev/null 2>&1; then CONTAINER_MANAGER=podman else CONTAINER_MANAGER=docker fi if [ "${CONTAINER_MANAGER}" = "podman" ] && [ "${REGISTRY_INSECURE}" = "true" ]; then OPTIONS="--tls-verify=${REGISTRY_INSECURE}" else OPTIONS="" fi ${CONTAINER_MANAGER} login ${OPTIONS} -u ${REGISTRY_USERNAME} -p ${REGISTRY_PASSWORD} ${REGISTRY} yq eval '.[] | ("registry=" + .registry + "; repository=" + .repository + "; tag=" + .tag)' ${IMAGE_YAML_FILE} \ | while read -r EXPRESION do eval $EXPRESION SOURCE_IMAGE=${registry}/${repository}:${tag} if [ "${KEEP_STRUCTURE}" = "true" ]; then TARGET_IMAGE=${REGISTRY}/${REPOSITORY_PREFIX}${SOURCE_IMAGE} else TARGET_IMAGE=${REGISTRY}/${REPOSITORY_PREFIX}$(echo ${SOURCE_IMAGE} | sed -e "s/\//${STRING_TO_REPLACE_SLASH}/g") fi ${CONTAINER_MANAGER} image pull ${SOURCE_IMAGE} ${CONTAINER_MANAGER} image tag ${SOURCE_IMAGE} ${TARGET_IMAGE} if [ "${DRY_RUN_PUSH:-true}" = "true" ]; then echo "dry run command: '${CONTAINER_MANAGER} push ${OPTIONS} ${TARGET_IMAGE}'" else ${CONTAINER_MANAGER} push ${OPTIONS} ${TARGET_IMAGE} echo "successfully pushed ${TARGET_IMAGE} to ${REGISTRY}" fi done parameters: - name: dockerd-host - name: repository-prefix - name: keep-structure - name: string-to-replace-slash - name: registry-credentials-secret-name - name: dry-run-push container: image: ghcr.io/ben-wangz/blog-docker-cli-with-bash:main env: - name: DOCKER_HOST value: "{{inputs.parameters.dockerd-host}}" - name: REPOSITORY_PREFIX value: "{{inputs.parameters.repository-prefix}}" - name: KEEP_STRUCTURE value: "{{inputs.parameters.keep-structure}}" - name: STRING_TO_REPLACE_SLASH value: "{{inputs.parameters.string-to-replace-slash}}" - name: IMAGE_YAML_FILE value: "{{inputs.artifacts.images-to-mirror.path}}" - name: REGISTRY_INSECURE valueFrom: secretKeyRef: name: "{{inputs.parameters.registry-credentials-secret-name}}" key: insecure - name: REGISTRY valueFrom: secretKeyRef: name: "{{inputs.parameters.registry-credentials-secret-name}}" key: registry - name: REGISTRY_USERNAME valueFrom: secretKeyRef: name: "{{inputs.parameters.registry-credentials-secret-name}}" key: username - name: REGISTRY_PASSWORD valueFrom: secretKeyRef: name: "{{inputs.parameters.registry-credentials-secret-name}}" key: password - name: DRY_RUN_PUSH value: "{{inputs.parameters.dry-run-push}}" command: - bash args: - /app/mirror.sh
with-seopeoapiVersion: argoproj.io/v1alpha1 kind: Workflow metadata: generateName: mirror-container-images- spec: entrypoint: entry serviceAccountName: argo-workflow templates: - name: entry dag: tasks: - name: mirror template: mirror arguments: parameters: - name: repository-prefix value: wangz2019/mirror_ - name: keep-structure value: "false" - name: string-to-replace-slash value: _ - name: registry-credentials-secret-name value: registry-credentials - name: dry-run value: "false" - name: images-to-mirror-configmap-name value: images-to-mirror - name: mirror inputs: artifacts: - name: mirror-scripts path: /app/mirror.sh raw: data: | #! /bin/bash set -e SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" IMAGE_YAML_FILE=${IMAGE_YAML_FILE:-/app/images-to-mirror.yaml} KEEP_STRUCTURE=${KEEP_STRUCTURE:-true} STRING_TO_REPLACE_SLASH=${STRING_TO_REPLACE_SLASH:-_} if [ "${REGISTRY_INSECURE}" = "true" ]; then INSPECT_OPTIONS="--tls-verify=false" COPY_OPTIONS="--dest-tls-verify=false" else INSPECT_OPTIONS="" COPY_OPTIONS="" fi yq eval '.[] | ("registry=" + .registry + "; repository=" + .repository + "; tag=" + .tag)' ${IMAGE_YAML_FILE} \ | while read -r EXPRESION do eval $EXPRESION SOURCE_IMAGE=${registry}/${repository}:${tag} if [ "${KEEP_STRUCTURE}" = "true" ]; then TARGET_IMAGE=${REGISTRY}/${REPOSITORY_PREFIX}${SOURCE_IMAGE} else TARGET_IMAGE=${REGISTRY}/${REPOSITORY_PREFIX}$(echo ${SOURCE_IMAGE} | sed -e "s/\//${STRING_TO_REPLACE_SLASH}/g") fi if [ "${DRY_RUN:-true}" = "true" ]; then echo "dry run command: skopeo copy \ docker://${SOURCE_IMAGE} \ docker://${TARGET_IMAGE} \ --dest-creds ${REGISTRY_USERNAME}:**********" else skopeo inspect ${INSPECT_OPTIONS} docker://${TARGET_IMAGE} --creds ${REGISTRY_USERNAME}:${REGISTRY_PASSWORD} > /dev/null 2>&1 \ && echo "skip mirroring ${SOURCE_IMAGE} to ${TARGET_IMAGE}" \ || ( echo "mirroring ${SOURCE_IMAGE} to ${TARGET_IMAGE}..." \ && skopeo copy ${COPY_OPTIONS} \ docker://${SOURCE_IMAGE} \ docker://${TARGET_IMAGE} \ --dest-creds ${REGISTRY_USERNAME}:${REGISTRY_PASSWORD} \ && echo "successfully mirrored ${SOURCE_IMAGE} to ${TARGET_IMAGE}") fi done parameters: - name: repository-prefix - name: keep-structure - name: string-to-replace-slash - name: registry-credentials-secret-name - name: dry-run - name: images-to-mirror-configmap-name volumes: - name: images-to-mirror configMap: name: "{{inputs.parameters.images-to-mirror-configmap-name}}" container: image: ghcr.io/ben-wangz/blog-skopeo:main volumeMounts: - name: images-to-mirror mountPath: /app/images-to-mirror.yaml subPath: images-to-mirror.yaml readOnly: true env: - name: REPOSITORY_PREFIX value: "{{inputs.parameters.repository-prefix}}" - name: KEEP_STRUCTURE value: "{{inputs.parameters.keep-structure}}" - name: STRING_TO_REPLACE_SLASH value: "{{inputs.parameters.string-to-replace-slash}}" - name: REGISTRY_INSECURE valueFrom: secretKeyRef: name: "{{inputs.parameters.registry-credentials-secret-name}}" key: insecure - name: REGISTRY valueFrom: secretKeyRef: name: "{{inputs.parameters.registry-credentials-secret-name}}" key: registry - name: REGISTRY_USERNAME valueFrom: secretKeyRef: name: "{{inputs.parameters.registry-credentials-secret-name}}" key: username - name: REGISTRY_PASSWORD valueFrom: secretKeyRef: name: "{{inputs.parameters.registry-credentials-secret-name}}" key: password - name: DRY_RUN value: "{{inputs.parameters.dry-run}}" command: - bash args: - /app/mirror.sh
- submit with argo workflow client
argo -n business-workflows submit mirror-container-images.yaml
- check status
argo -n business-workflows list
# argo -n business-workflows get mirror-container-images-2j5z2 argo -n business-workflows get @lastest
# argo -n business-workflows logs mirror-container-images-2j5z2 argo -n business-workflows logs @latest