When setting up Kubernetes cluster with kubeadmin, an init command option is used to set up the Kubernetes control plane. Kubernetes has a number of Container images that will be used while bootstrapping a cluster.
In an environment where internet access is not reliable or when you have a restricted internet access like when using Proxy servers, or if your Kubernetes nodes doesn’t have internet access at all, it makes sense to pre-pull the container images to be used.
First you’ll need to print a list of images kubeadm will use ( on a machine with kubeadm installed).

  1. $ sudo kubeadm config images list
  2. k8s.gcr.io/kube-apiserver:v1.17.0
  3. k8s.gcr.io/kube-controller-manager:v1.17.0
  4. k8s.gcr.io/kube-scheduler:v1.17.0
  5. k8s.gcr.io/kube-proxy:v1.17.0
  6. k8s.gcr.io/pause:3.1
  7. k8s.gcr.io/etcd:3.4.3-0
  8. k8s.gcr.io/coredns:1.6.5

The default registry used is k8s.gcr.io, you have an option to use a different registry. E.g using docker:

  1. $ sudo kubeadm config images list --image-repository docker.io
  2. docker.io/kube-apiserver:v1.17.0
  3. docker.io/kube-controller-manager:v1.17.0
  4. docker.io/kube-scheduler:v1.17.0
  5. docker.io/kube-proxy:v1.17.0
  6. docker.io/pause:3.1
  7. docker.io/etcd:3.4.3-0
  8. docker.io/coredns:1.6.5

This will use the latest stable version of Kubernetes. You can also specify the version of Kubernetes to use, e.g stable, latest

  1. $ sudo kubeadm config images list --kubernetes-version latest

Pull container images with kubeadm command

If your Kubernetes machines have access to internet for pulling Container images, you can use the kubeadm command to pre-pull the required images:

  1. ------- Pull from default registry: k8s.gcr.io -------
  2. $ sudo kubeadm config images pull
  3. ------- Pull from a different registry, e.g docker.io or internal -------
  4. $ sudo kubeadm config images pull --image-repository docker.io

For docker you may need to login to pull the images:

  1. $ sudo docker login
  2. Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
  3. Username: jmutai
  4. Password:
  5. WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
  6. Configure a credential helper to remove this warning. See
  7. https://docs.docker.com/engine/reference/commandline/login/#credentials-store
  8. Login Succeeded

Note that if you change a container repository, you’ll need to do the same when running init.

  1. $ sudo kubeadm init --image-repository <registry> <options>

Pull container images with docker / podman command

For Kubernetes nodes without internet access, you’ll need to download images from you Local machine and upload the to your Kubernetes nodes.

  • List images to be used on machine with kubeadm

    1. sudo kubeadm config images list
  • Download images locally

    1. for image in k8s.gcr.io/kube-apiserver:v1.17.0 \
    2. k8s.gcr.io/kube-controller-manager:v1.17.0 \
    3. k8s.gcr.io/kube-scheduler:v1.17.0 \
    4. k8s.gcr.io/kube-proxy:v1.17.0 \
    5. k8s.gcr.io/pause:3.1 \
    6. k8s.gcr.io/etcd:3.4.3-0 \
    7. k8s.gcr.io/coredns:1.6.5; do
    8. sudo docker pull $image;
    9. done

    If using podman:

    1. for image in k8s.gcr.io/kube-apiserver:v1.17.0 \
    2. k8s.gcr.io/kube-controller-manager:v1.17.0 \
    3. k8s.gcr.io/kube-scheduler:v1.17.0 \
    4. k8s.gcr.io/kube-proxy:v1.17.0 \
    5. k8s.gcr.io/pause:3.1 \
    6. k8s.gcr.io/etcd:3.4.3-0 \
    7. k8s.gcr.io/coredns:1.6.5; do
    8. sudo docker pull $image;
    9. done
  • Save images as .tar files

    1. # Example
    2. mkdir ~/k8s-images
    3. docker save k8s.gcr.io/kube-apiserver:v1.17.0 > ~/k8s-images/kube-apiserver.tar
    4. # Do the same for all other images
  • Upload saved images to Kubernetes nodes

    1. rsync -av ~/k8s-images/* k8s-node:~/k8s-images/
  • Import .tar image files into Docker.

    1. cd k8s-images/
    2. ls * | while read image; do sudo docker load < $image; done

    Here is a sample load output.

    1. # ls * | while read image; do docker load < $image; done
    2. 225df95e717c: Loading layer [==================================================>] 336.4kB/336.4kB
    3. 7c9b0f448297: Loading layer [==================================================>] 41.37MB/41.37MB
    4. Loaded image: k8s.gcr.io/coredns:1.6.5
    5. fe9a8b4f1dcc: Loading layer [==================================================>] 43.87MB/43.87MB
    6. ce04b89b7def: Loading layer [==================================================>] 224.9MB/224.9MB
    7. 1b2bc745b46f: Loading layer [==================================================>] 21.22MB/21.22MB
    8. Loaded image: k8s.gcr.io/etcd:3.4.3-0
    9. fc4976bd934b: Loading layer [==================================================>] 53.88MB/53.88MB
    10. f103db1d7ea4: Loading layer [==================================================>] 118.6MB/118.6MB
    11. Loaded image: k8s.gcr.io/kube-apiserver:v1.17.0
    12. 01b437934b9d: Loading layer [==================================================>] 108.5MB/108.5MB
    13. Loaded image: k8s.gcr.io/kube-controller-manager:v1.17.0
    14. ac06623e44c6: Loading layer [==================================================>] 42.1MB/42.1MB
    15. Loaded image: k8s.gcr.io/kube-scheduler:v1.17.0
    16. 682fbb19de80: Loading layer [==================================================>] 21.06MB/21.06MB
    17. 2dc2f2423ad1: Loading layer [==================================================>] 5.168MB/5.168MB
    18. ad9fb2411669: Loading layer [==================================================>] 4.608kB/4.608kB
    19. 597151d24476: Loading layer [==================================================>] 8.192kB/8.192kB
    20. 0d8d54147a3a: Loading layer [==================================================>] 8.704kB/8.704kB
    21. 6bc5ae70fa9e: Loading layer [==================================================>] 37.81MB/37.81MB
    22. Loaded image: k8s.gcr.io/kube-proxy:v1.17.0
    23. e17133b79956: Loading layer [==================================================>] 744.4kB/744.4kB
    24. Loaded image: k8s.gcr.io/pause:3.1

    Confirm the images are imported:

    1. # docker images
    2. REPOSITORY TAG IMAGE ID CREATED SIZE
    3. k8s.gcr.io/kube-proxy v1.17.0 7d54289267dc 4 weeks ago 116MB
    4. k8s.gcr.io/kube-apiserver v1.17.0 0cae8d5cc64c 4 weeks ago 171MB
    5. k8s.gcr.io/kube-controller-manager v1.17.0 5eb3b7486872 4 weeks ago 161MB
    6. k8s.gcr.io/kube-scheduler v1.17.0 78c190f736b1 4 weeks ago 94.4MB
    7. k8s.gcr.io/coredns 1.6.5 70f311871ae1 2 months ago 41.6MB
    8. k8s.gcr.io/etcd 3.4.3-0 303ce5db0e90 2 months ago 288MB
    9. k8s.gcr.io/pause 3.1 da86e6ba6ca1 2 years ago 742kB

    You can then proceed with your Kubernetes installation with locally added images. Depending on the CNI you use, you may need to pull its image as well in advance if doing offline installations.