Search code examples
kuberneteskubernetes-podpodspec

Kubernetes Podspec to download only container image but it should not install


I want to download the container image, but dont want to deploy/install the image. How can i deploy podspec to download only images but it should not create container. Any podspec snapshot for this?


Solution

  • As far as I know there is no direct Kubernetes resources to only download an image of your choosing. To have the images of your applications on your Nodes you can consider using following solutions/workarounds:

    • Use a Daemonset with an initContainer('s)
    • Use tools like Ansible to pull the images with a playbook

    Use a Daemonset with InitContainers

    Assuming the following situation:

    You've created 2 images that you want to have on all of the Nodes.

    You can use a Daemonset (spawn a Pod on each Node) with initContainers (with images as source) that will run on all Nodes and ensure that the images will be present on the machine.

    An example of such setup could be following:

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: pull-images
      labels:
        k8s-app: pull-images
    spec:
      # AS THIS DAEMONSET IS NOT SUPPOSED TO SERVE TRAFFIC I WOULD CONSIDER USING THIS UPDATE STRATEGY FOR SPEEDING UP THE DOWNLOAD PROCESS
      updateStrategy:
        type: RollingUpdate
        rollingUpdate:
          maxUnavailable: 100
      selector:
        matchLabels:
          name: pull-images
      template:
        metadata:
          labels:
            name: pull-images
        spec:
          initContainers:
          # PUT HERE IMAGES THAT YOU WANT TO PULL AND OVERRIDE THEIR ENTRYPOINT
          -  name: ubuntu
             image: ubuntu:20.04 # <-- IMAGE #1
             imagePullPolicy: Always # SPECIFY THE POLICY FOR SPECIFIC IMAGE
             command: ["/bin/sh", "-c", "exit 0"]
          -  name: nginx
             image: nginx:1.19.10 # <-- IMAGE #2 
             imagePullPolicy: IfNotPresent # SPECIFY THE POLICY FOR SPECIFIC IMAGE
             command: ["/bin/sh", "-c", "exit 0"]
          containers:
          # MAIN CONTAINER WITH AS SMALL AS POSSIBLE IMAGE SLEEPING
          - name: alpine
            image: alpine 
            command: [sleep] 
            args: 
            - "infinity" 
    

    Kubernetes Daemonset controller will ensure that the Pod will run on each Node. Before the image is run, the initContainers will act as a placeholders for the images. The images that you want to have on the Nodes will be pulled. The ENTRYPOINT will be overridden to not run the image continuously. After that the main container (alpine) will be run with a sleep infinity command.

    This setup will also work when the new Nodes are added.

    Following on that topic I would also consider checking following documentation on imagePullPolicy:

    A side note!

    I've set the imagePullPolicy for the images in initContainers differently to show you that you can specify the imagePullPolicy independently for each container. Please use the policy that suits your use case the most.


    Use tools like Ansible to pull the images with a playbook

    Assuming that you have SSH access to the Nodes you can consider using Ansible with it's community module (assuming that you are using Docker):

    • community.docker.docker_image

    Citing the documentation for this module:

    This plugin is part of the community.docker collection (version 1.3.0).

    To install it use: ansible-galaxy collection install community.docker.

    Synopsis

    Build, load or pull an image, making the image available for creating containers. Also supports tagging an image into a repository and archiving an image to a .tar file.

    -- Docs.ansible.com: Ansible: Collections: Community: Docker: Docker image module

    You can use it with a following example:

    • hosts.yaml
    all:
      hosts:
        node-1:
          ansible_port: 22
          ansible_host: X.Y.Z.Q
        node-2: 
          ansible_port: 22
          ansible_host: A.B.C.D
    
    • playbook.yaml
    - name: Playbook to download images
      hosts: all
      user: ENTER_USER
    
      tasks:
      - name: Pull an image
        community.docker.docker_image:
          name: "{{ item }}"
          source: pull
        with_items:
        - "nginx"
        - "ubuntu"
    

    A side note!

    In the ansible way, I needed to install docker python package:

    $ pip3 install docker


    Additional resources: