[ตอนที่ 3]Change Container-runtimes from Docker to CRI-O (update 20210122)

Thanaphat Nuangjumnong
5 min readJun 17, 2020

* Update ข้อมูลล่าสุดจาก https://www.blognone.com/node/119921
พบประเด็นหลายอย่างกับ dockershim ทำให้ตัดสินใจว่าจะให้ระบบซัพพอร์ต Docker เข้าสู่สถานะ deprecated และเตรียมถอดออกจาก Kubernetes ในอนาคต
ทีมงานที่ดูแล Kube เลยตัดสินใจเลิกใช้ Docker runtime แล้วให้ Kubelet คุยกับ containerd ตรงๆ ผ่าน CRI (Container Runtime Interface) ผลคือ container/pod จะสามารถทำงานได้เร็วขึ้นและกิน CPU/memory น้อยลง โดยไม่ผ่าน dockershim

*สาเหตุหลักที่ทางทีมเราได้เปลี่ยนก่อนที่อื่นๆ เพราะพบปัญหา Worker node สามารถรับ load ได้ประมาณ 250 Pods แล้วเกิดปัญหา Service kubelet คุยกับ docker แล้วได้ response time ช้ากว่า 3 นาที

## Error log จาก Kubelet

kubelet[30996]: I0629 16:13:44.951131 30996 setters.go:518] Node became not ready: {Type:Ready Status:False LastHeartbeatTime:2019–06–29 16:13:44.951049211 +0700 +07 m=+239038.614749639 LastTransitionTime:2019–06–29 16:13:44.951049211 +0700 +07 m=+239038.614749639 Reason:KubeletNotReady Message:PLEG is not healthy: pleg was last seen active 3m5.396071016s ago; threshold is 3m0s}

หลังจากพบปัญหาทางทีมเราเลย Research ว่ามี Kubernetes ลองรับ container-runtimes อะไรบ้าง (Ref . https://kubernetes.io/docs/setup/production-environment/container-runtimes/) ในนี้พวกเราเลือกที่จะใช้งาน cri-o มาใช้งานแทน docker เพราะ lightweight และถูกพัฒนามาใช้เฉพาะทาง

มีบทความการเปรียบเทียบ container-runtimes (docker-vs-cri-o-vs-containerd) อ่านต่อ

CRI-O คืออะไร
CRI-O เป็นการใช้งานของ Kubernetes CRI (อินเตอร์เฟสรันไทม์ของคอนเทนเนอร์) เพื่อเปิดใช้งานการใช้รันไทม์ที่เข้ากันได้ของ OCI (Open Container Initiative) มันเป็นทางเลือกที่มีน้ำหนักเบาในการใช้ Docker เป็นรันไทม์สำหรับ kubernetes จะช่วยให้ Kubernetes ใช้รันไทม์ที่เข้ากันได้กับ OCI ใด ๆ เป็นรันไทม์คอนเทนเนอร์สำหรับเรียกใช้ Pods อ่านต่อ

https://www.docker.com/blog/docker-engine-1-11-runc/
https://cri-o.io/

## How to migrate docker to crio

kubectl drain [node-name] --ignore-daemonsets
systemctl stop kubelet

## Remove docker and mount point on the worker node

docker ps -a -q|xargs -I{} docker stop {}
docker ps -a -q|xargs -I{} docker stop {}
docker ps -a -q|xargs -I{} docker rm {}
systemctl disable docker
systemctl stop docker
yum remove docker-ce -y
yum remove docker-ce-cli -y

## Step Install cri-o

  • * เลือก CRI-O Version ให้เท่ากับ Kubernetes Version ในที่นี้ ผมเลือก (cri-o:1.18) มาทดสอบครับ
  1. Export env for crio install
export OS=CentOS_7
export VERSION=1.16

2. Add repo

curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/devel:kubic:libcontainers:stable.repocurl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.repo https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$VERSION/$OS/devel:kubic:libcontainers:stable:cri-o:$VERSION.repo

Prerequisites and re-check your config

cat /etc/sysctl.d/99-sysctl.conf
net.ipv4.ip_forward=1
net.ipv4.ip_local_reserved_ports=30000–32767
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-arptables=1
net.bridge.bridge-nf-call-ip6tables=1

##If you don’t have that parameter let’s run step below

modprobe overlay
modprobe br_netfilter
# Set up 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
EOF
sysctl --system

## Yum install

## Install & remove
yum install cri-o -y

## Configuration CRI-O โดยอ่านต่อที่ Document Link

vi /etc/sysconfig/crio

** ข้อมูลด้านล่างตัวอย่างเท่านั้น

# /etc/sysconfig/crio# use "--enable-metrics" and "--metrics-port value"
#CRIO_METRICS_OPTIONS="--enable-metrics"
#CRIO_NETWORK_OPTIONS=
#CRIO_STORAGE_OPTIONS=
CRIO_METRICS_OPTIONS=" --enable-metrics --metrics-port=9090"
CRIO_NETWORK_OPTIONS=" --cni-plugin-dir=/opt/cni/bin"
CRIO_STORAGE_OPTIONS=" --storage-driver=overlay"
CRIO_API_OPTIONES=" --listen=/var/run/crio/crio.sock"
CRIO_RUNTIME_OPTIONS=" --cgroup-manager=systemd --pids-limit=2048"
##if you need out going to internet via proxy please uncomment#HTTP_PROXY=”http://proxy:80"
#HTTPS_PROXY=”http://proxy:80"

## config registry

vi /etc/containers/registries.conf unqualified-search-registries = ["docker.io"]

##Start CRI-O

sudo systemctl daemon-reload
sudo systemctl enable crio
sudo systemctl start crio

## know issue

Jan 22 14:55:11 k8s-master-lab-03 crio[96454]: time=”2021–01–22 14:55:11.074969255+07:00" level=fatal msg=”runtime config: invalid hooks_dir: stat /usr/share/containers/oci/hooks.d: no such file or directory: stat /usr/share/containers/oci/hooks.d: no such file or directory”

## Resolve by

mkdir -p /usr/share/containers/oci/hooks.d

##Test

sudo curl -v --unix-socket /var/run/crio/crio.sock http://localhost/info | jq

## Download crio-tool package

export VERSION="v1.16.0"
wget https://github.com/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-$VERSION-linux-amd64.tar.gz
sudo tar zxvf crictl-$VERSION-linux-amd64.tar.gz -C /usr/local/bin
rm -f crictl-$VERSION-linux-amd64.tar.gz

## verfity crictl

$crictl version
Version: 0.1.0
RuntimeName: cri-o
RuntimeVersion: 1.16.6
RuntimeApiVersion: v1alpha1
$crictl pull nginx
Image is up to date for docker.io/library/nginx@sha256:0b159cd1ee1203dad901967ac55eee18c24da84ba3be384690304be93538bea8

## when you start kubelet found the error in below

systemctl start kubelet
systemctl status kubelet -l
  • *Step ต่อไปเราต้องการแกะ Service kubelet ว่ามี Env ไป Connect Docker อยู่ส่วนไหน
systemctl status kubelet

##check all env file

EnvironmentFile=-/etc/kubernetes/kubelet.env

## ADD container-runtime=remote / container-runtime-endpoint=unix:///var/run/crio/crio.sock /cgroup-driver=systemd

KUBELET_ARGS="--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf \
--config=/etc/kubernetes/kubelet-config.yaml \
--kubeconfig=/etc/kubernetes/kubelet.conf \
--pod-infra-container-image=k8s.gcr.io/pause:3.1 \
--runtime-cgroups=/systemd/system.slice \
--container-runtime=remote \
--container-runtime-endpoint=unix:///var/run/crio/crio.sock \
--cgroup-driver=systemd \

***เปลี่ยน cgroup-driver เป็น systemd / container-runtime-endpoint เป็นใช้ crio.sock

Ref. https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#configure-cgroup-driver-used-by-kubelet-on-control-plane-node

Ref. https://github.com/cri-o/cri-o#getting-started

## Reload / restart

systemctl daemon-reload
systemctl start kubelet

## Verify Kubelet log

journalctl -fu kubelet

## Verify K8S node

kubectl get node -o wide

## Verify node and pods

kubectl  get pod -A

Done!!!

ขอบคุณสำหรับแหล่งที่มาของข้อมูล

Ref.
https://cri-o.io/
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#configure-cgroup-driver-used-by-kubelet-on-control-plane-node
https://computingforgeeks.com/docker-vs-cri-o-vs-containerd/

--

--