How can I retrieve the container images from a K8s cluster (not just list the container image names)?

2/22/2022

I would like to run a K8s Cronjob (or controller) to mirror copies of the actual container images used to a external (ECR) Docker repo. How can I do the equivalent of:

docker pull localimage
docker tag localimage newlocation
docker push newlocation
-- user2442172
containers
docker
docker-registry
kubernetes

1 Answer

2/22/2022

Kubernetes doesn't have any way to push or rename images, or to manually pull images beyond declaring them in a Pod spec.

The Docker registry system has its own HTTP API. One possibility is, when you discover a new image, manually make the API calls to pull and push it. In this context you wouldn't specifically need to "tag" the image since the image repository, name, and tag only appear as URL components. I'm not specifically aware of a prebuilt tool that can do this, though I'd be very surprised if nobody's built it.

If you can't do this, then the only reliable way to get access to some Docker daemon in Kubernetes is to run one yourself. In this scenario you don't need access to "the real" container system, just somewhere you can target the specific docker commands you list, so you're not limited by the container runtime Kubernetes uses. The one big "but" here is that the Docker daemon must run in a privileged container, which your local environment may not allow.

It's a little unusual to run two containers in one Pod but this is a case where it makes sense. The Docker daemon can run as a prepackaged separate container, tightly bound to its client, as a single unit. Here you don't need persistent storage or anything else that might want the Docker daemon to have a different lifecycle than the thing that's using it; it's just an implementation detail of the copy process. Carefully Googling "docker in docker" kubernetes finds write-ups like this or this that similarly describe this pattern.

By way of illustration, here's a way you might do this in a Kubernetes Job:

apiVersion: batch/v1
kind: Job
metadata: { ... }
spec:
  template:
    spec:
      containers:
        - name: cloner
          image: docker:latest # just the client and not a daemon
          environment:
            - name: IMAGE
              value: some/image:tag
            - name: REGISTRY
              value: registry.example.com
            - name: DOCKER_HOST
              value: tcp://localhost:2375 # pointing at the other container
          command:
            - /bin/sh
            - -c
            - |-
                docker pull "$IMAGE"
                docker tag "$IMAGE" "$REGISTRY/$IMAGE"
                docker push "$REGISTRY/$IMAGE"
                docker rmi "$IMAGE" "$REGISTRY/$IMAGE"
        - name: docker
          image: docker:dind
          securityContext:
            privileged: true # <-- could be a problem with your security team
          volumes:
            - name: dind-storage
              mountPath: /var/lib/docker
      volumes:
        - name: dind-storage
          emptyDir: {} # won't outlive this Pod and that's okay

In practice I suspect you'd want a single long-running process to manage this, maybe running the DinD daemon as a second container in your controller's Deployment.

-- David Maze
Source: StackOverflow