Skip to main content

Overview

This document entails steps and procedures to install k8s in an offline environment without internet access, whether in the cloud (public or private), or on bare-metal hardware.

System Parameters/Versions Used for this Example:

  • Rocky Linux: 8.10
  • K8s: 1.29.12
  • Containerd: 1.7.23
  • Docker: 27.2.0

Tools you will need

  • One computer/system with containerd/docker installed and internet access.
    • recommend to use a system with the same chipset as installation system (i.e. AMD64)
  • Destination offline system for installation (no internet access).

Prerequisites

The following packages/dependencies should already be completed:
  • base operating system (OS) updated and patched
  • containerd or docker installed (both on-line and off-line systems)
  • firewalld installed

Prepare K8S Images/Binaries

System with Internet Access

Download all required binaries/images. Perform the following steps from the system with internet access. This example uses a linux machine.

Step 1: Set Version

Set desired K8S version:
export K8S_VERSION=v1.29

Step 2: Download K8S Packages

Download all K8S packages for installation on Rocky 8. Set the repository:
# set repository and repo
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/$K8S_VERSION/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/$K8S_VERSION/rpm/repodata/repomd.xml.key
exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
EOF
Pull packages, saved in /k8s directory:
sudo dnf install -y --downloadonly --downloaddir=/k8s kubelet kubeadm kubectl --disableexcludes=kubernetes
Compress directory for easier transfer:
tar -zcvf /k8s.tar.gz /k8s

Step 3 (optional): Determine Dependencies

Required dependencies are already listed in the following step, but can verify if necessary. Check which version of K8S was downloaded:
ls /k8s | grep kubeadm
Output should look similar to the following:
kubeadm-1.29.12-150500.1.1.x86_64.rpm
In this example, using v1.29.12. Set variable for kubeadm version:
export KUBEADM_VERSION=v1.29.12
Download kubeadm binary, make executable, and move to bin:
# download
curl -L https://dl.k8s.io/release/$KUBEADM_VERSION/bin/linux/amd64/kubeadm -o kubeadm_$KUBEADM_VERSION

# move binary
sudo mv kubeadm_$KUBEADM_VERSION /usr/local/bin/kubeadm

# set permissions to execute
sudo chmod +x /usr/local/bin/kubeadm
List dependencies:
kubeadm config images list --kubernetes-version=$KUBEADM_VERSION
Output should be similar to the following:
registry.k8s.io/kube-apiserver:v1.29.12
registry.k8s.io/kube-controller-manager:v1.29.12
registry.k8s.io/kube-scheduler:v1.29.12
registry.k8s.io/kube-proxy:v1.29.12
registry.k8s.io/coredns/coredns:v1.11.1
registry.k8s.io/pause:3.9
registry.k8s.io/etcd:3.5.16-0

Step 4: Prepare Dependency Images

Pull all required images, can use Docker or containerd. Using Docker:
docker pull --platform=linux/amd64 registry.k8s.io/kube-apiserver:v1.29.12
docker pull --platform=linux/amd64 registry.k8s.io/kube-controller-manager:v1.29.12
docker pull --platform=linux/amd64 registry.k8s.io/kube-scheduler:v1.29.12
docker pull --platform=linux/amd64 registry.k8s.io/kube-proxy:v1.29.12
docker pull --platform=linux/amd64 registry.k8s.io/coredns/coredns:v1.11.1
docker pull --platform=linux/amd64 registry.k8s.io/pause:3.9
docker pull --platform=linux/amd64 registry.k8s.io/etcd:3.5.16-0
Save the images as compressed files so that they can be transferred to the offline system:
docker save -o kube-apiserver_v1.29.12.tar registry.k8s.io/kube-apiserver:v1.29.12
docker save -o kube-controller-manager_v1.29.12.tar registry.k8s.io/kube-controller-manager:v1.29.12
docker save -o kube-scheduler_v1.29.12.tar registry.k8s.io/kube-scheduler:v1.29.12
docker save -o kube-proxy_v1.29.12.tar registry.k8s.io/kube-proxy:v1.29.12
docker save -o coredns_v1.11.1.tar registry.k8s.io/coredns/coredns:v1.11.1
docker save -o pause_3.9.tar registry.k8s.io/pause:3.9
docker save -o etcd_3.5.16-0.tar registry.k8s.io/etcd:3.5.16-0
Using containerd:
ctr image pull --platform=linux/amd64 registry.k8s.io/kube-apiserver:v1.29.12
ctr image pull --platform=linux/amd64 registry.k8s.io/kube-controller-manager:v1.29.12
ctr image pull --platform=linux/amd64 registry.k8s.io/kube-scheduler:v1.29.12
ctr image pull --platform=linux/amd64 registry.k8s.io/kube-proxy:v1.29.12
ctr image pull --platform=linux/amd64 registry.k8s.io/coredns/coredns:v1.11.1
ctr image pull --platform=linux/amd64 registry.k8s.io/pause:3.9
ctr image pull --platform=linux/amd64 registry.k8s.io/etcd:3.5.16-0
Save the images as compressed files so that they can be transferred to the offline system:
ctr image export --platform=linux/amd64 kube-apiserver_v1.29.12.tar registry.k8s.io/kube-apiserver:v1.29.12
ctr image export --platform=linux/amd64 kube-controller-manager_v1.29.12.tar registry.k8s.io/kube-controller-manager:v1.29.12
ctr image export --platform=linux/amd64 kube-scheduler_v1.29.12.tar registry.k8s.io/kube-scheduler:v1.29.12
ctr image export --platform=linux/amd64 kube-proxy_v1.29.12.tar registry.k8s.io/kube-proxy:v1.29.12
ctr image export --platform=linux/amd64 coredns_v1.11.1.tar registry.k8s.io/coredns/coredns:v1.11.1
ctr image export --platform=linux/amd64 pause_3.9.tar registry.k8s.io/pause:3.9
ctr image export --platform=linux/amd64 etcd_3.5.16-0.tar registry.k8s.io/etcd:3.5.16-0

Step 5: Transfer Binaries/Images to Offline System

Transfer downloaded binaries and images to offline system. This can be done via secure ssh or removable storage media.
  • k8s.tar.gz
  • kube-apiserver_v1.29.12.tar
  • kube-controller-manager_v1.29.12.tar
  • kube-scheduler_v1.29.12.tar
  • kube-proxy_v1.29.12.tar
  • coredns_v1.11.1.tar
  • pause_3.9.tar
  • etcd_3.5.16-0.tar

Install K8S

Offline System without Internet Access

Import all binaries and images from the system with internet access to the offline system. This example uses a linux machine. Commands have to be performed as root (since it involves installation of Kubernetes).
sudo su -

Step 1: Install K8S Packages

Unzip k8s.tar and install, then enable kubelet:
# unzip k8s components
tar -zxvf k8s.tar.gz

# install k8s
rpm -ivh --replacefiles --replacepkgs /k8s/*.rpm

# enable kubelet
systemctl enable kubelet.service
systemctl start kubelet.service

# check status
sudo systemctl status kubelet

Step 2: Load K8S Dependency Images

Load K8S images with either docker or containerd(using containerd for this example):
sudo ctr -n=k8s.io images import kube-apiserver_v1.29.12.tar
sudo ctr -n=k8s.io images import kube-controller-manager_v1.29.12.tar
sudo ctr -n=k8s.io images import kube-scheduler_v1.29.12.tar
sudo ctr -n=k8s.io images import kube-proxy_v1.29.12.tar
sudo ctr -n=k8s.io images import coredns_v1.11.1.tar
sudo ctr -n=k8s.io images import pause_3.9.tar
sudo ctr -n=k8s.io images import etcd_3.5.16-0.tar

Step 3: Initialize K8S

Initialize and setup cluster control-plane node:
CNI_CIDR="192.168.100.0/19"
SERVICE_CIDR="192.168.200.0/19"
NODE_NAME="my-node"
kubeadm init \
    --pod-network-cidr $CNI_CIDR \
    --service-cidr $SERVICE_CIDR \
    --node-name $NODE_NAME
NOTE: Ensure that CNI and Service CIDRs are consistent with previous or desired installation.
Set kubectl config:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
export KUBECONFIG=/etc/kubernetes/admin.conf
Verify that the cluster is running:
kubectl get nodes
Output should be similar to the following:
NAME                           STATUS     ROLES           AGE   VERSION
ip-172-31-9-184.ec2.internal   NotReady   control-plane   37m   v1.29.12
List running pods:
kubectl get pods -A
Output should be similar to the following:
NAMESPACE     NAME                                                   READY   STATUS    RESTARTS   AGE
kube-system   coredns-76f75df574-msppj                               0/1     Pending   0          37m
kube-system   coredns-76f75df574-pdn7f                               0/1     Pending   0          37m
kube-system   etcd-ip-172-31-9-184.ec2.internal                      1/1     Running   0          37m
kube-system   kube-apiserver-ip-172-31-9-184.ec2.internal            1/1     Running   0          37m
kube-system   kube-controller-manager-ip-172-31-9-184.ec2.internal   1/1     Running   0          37m
kube-system   kube-proxy-fj4k8                                       1/1     Running   0          37m
kube-system   kube-scheduler-ip-172-31-9-184.ec2.internal            1/1     Running   0          37m
NOTE: coredns pods will be in “Pending” state until flannel (or other CNI) is installed.
I