Who needs Docker to run K8S? I don't.

It's quite simple to setup, and brings additional benefits, including hassle-free upgrades for k8s 1.20+, which recently announced dropping a support for Docker.

Lets start from a quick guide.

Install CRI-ContainerD

cat > /etc/modules-load.d/containerd.conf <<EOF

modprobe overlay
modprobe br_netfilter

# Setup required sysctl params, these persist across reboots.
cat > /etc/sysctl.d/99-kubernetes-cri.conf <<EOF
net.bridge.bridge-nf-call-iptables  = 1
net.ipv4.ip_forward                 = 1
net.bridge.bridge-nf-call-ip6tables = 1

sysctl --system

export VERSION=1.4.1

curl -LO https://github.com/containerd/containerd/releases/download/v${VERSION}/cri-containerd-cni-${VERSION}-linux-amd64.tar.gz
sudo tar --no-overwrite-dir -C / -xzf cri-containerd-cni-${VERSION}-linux-amd64.tar.gz
sudo mkdir -p /etc/containerd/
containerd config default | sudo tee /etc/containerd/config.toml
sudo systemctl enable --now containerd
sudo systemctl status containerd
crictl version

Install Kubernetes

sudo apt-get update && sudo apt-get install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

# KubeADM to create cluster;
kubeadm init
# update kubeconfig
rm -rf .kube/
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# Apply networking plugin. I use weave
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
# Untaint master
kubectl taint nodes --all node-role.kubernetes.io/master-

Persistent storage: (Poor mans single node version)

kubectl create -f https://raw.githubusercontent.com/xor22h/hostpath-provisioner/master/manifests/rbac.yaml
kubectl create -f https://raw.githubusercontent.com/xor22h/hostpath-provisioner/master/manifests/deployment.yaml
kubectl create -f https://raw.githubusercontent.com/xor22h/hostpath-provisioner/master/manifests/storageclass.yaml

Prepare HELM:

curl -LO https://get.helm.sh/helm-v3.2.2-linux-amd64.tar.gz
tar -xvzf helm-v3.2.2-linux-amd64.tar.gz
mv linux-amd64/helm /usr/local/bin/helm
chmod +x /usr/local/bin/helm
helm repo add stable https://kubernetes-charts.storage.googleapis.com

# Metrics (kubectl top support)
helm upgrade --install metrics --namespace=kube-system stable/metrics-server --set args="{--v=2,--kubelet-insecure-tls=true,--kubelet-preferred-address-types=InternalIP,--metric-resolution=10s}"

Add NGINX / CertManager

# Some variables
export EMAIL=admin@xor22h.net 

# Install CertManager

kubectl create namespace cert-manager
helm repo add jetstack https://charts.jetstack.io
helm install \
  cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --version v1.0.1 \
  --set installCRDs=true

echo -e "apiVersion: cert-manager.io/v1
kind: ClusterIssuer
  name: letsencrypt-prod
    server: https://acme-v02.api.letsencrypt.org/directory
    email: ${EMAIL}
      name: letsencrypt-prod
    - http01:
         class: nginx"  | kubectl apply -f -

# Install nginx-ingress-controller
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm upgrade --install --namespace kube-system nginx ingress-nginx/ingress-nginx --set controller.stats.enabled=true,controller.metrics.enabled=true,controller.hostNetwork=true,controller.kind=DaemonSet,controller.service.type=ClusterIP

These steps covers basic daily needs.

Why using this way?

  • Updating ContainerD doesn't require to restart all running containers. With a Docker thats a main problem for me.
  • ContainerD cli (crictl) offers a very easy way to remove unused images. crictl rmi --prune is everything you need.
  • Works well with K8S 1.20+