
01.
我们在提到容器运行时(Container Runtime)时就会想到Docker,即使用于制作容器的LXC工具早于Docker,但Docker以其简单性将容器技术带入了主流,在过去的五年Docker也成为了运行容器的事实上的标准。
容器技术成为主流之后,容器圈进行了一系列政治斗争,感兴趣的读者可以网上查查,本文不再赘述。最终Docker的Swarm不敌Kubernetes,Docker公司把 containerd 项目捐给 CNCF社区,专心做Docker企业版。
最终由Kubernetes统治了容器圈,并制定了相关的标准
Container Runtime Interface:即容器运行时接口(CRI),Kubernetes v1.5版本推出,无论是docker、rkt或cri-o,只要能实现这个接口,谁都可以做 Runtime。
Open Container Initiative:即开放容器标准(OCI),Docker公司把libcontainer封装变成Runc捐献出来,作为 OCI 的参考实现,因为Runc能按照标准将符合标准的容器镜像运行起来。
当CRI标准提出后,Red Hat开始想构建一个更简单的运行时,且这个运行时仅为 Kubernetes所用,最初称为CRID,最后改为CRI-O,它实现了一个最小的 CRI 接口,由CNCF社区孵化。CRI-O设计比其他的方案都要小,遵循久经考验的Unix模块化编程哲学,实现组件重用。
02.
为什么选择CRI-O?
真正开放的项目:CRI-O是Kubernetes生态的一部分,成为其子项目,由CNCF社区孵化,Red Hat,SUSE,Intel ,Google,IBM等公司提供了大量的贡献者。
轻量: CRI-O由许多小型组件组成,每个组件都有特定的角色,并与其他组件一起工作,以提供完整的容器体验,相比之下,Docker引擎是一个重量级的守护程序。
更加安全:每个使用Docker CLI运行的容器都是该大型Docker Daemon的“子级”,这使得使用cgroup和安全约束等工具来为容器提供额外的保护层变得复杂或彻底受阻。由于CRI-O容器是产生它的进程(而不是守护进程)的子进程,因此它们与这些工具完全兼容,而不会产生复杂问题。对Kubernetes来说很完美,在Podman中使用也很“因吹斯汀”。
与Kubernetes保持一致:作为一个正式的Kubernetes项目,CRI-O与Kubernetes同步发布。

当创建一个POD时,kubelet通过kubernetes CRI将请求转发给CRI-O守护进程,以启动新的POD
CRI-O从镜像仓库(docker仓库、私有仓库等)拉取镜像
下载好的镜像被解压,通过挂载到容器的根文件系统中
为容器创建rootfs之后,CRI-O会生成OCI运行时规范config.jsonn文件,该文件描述了如何使用OCI Generate工具运行容器。(Runc通过读取这个json文件,获取该如何启动容器的信息)
然后,CRI-O按OCI标准通过Runc将镜像运行起来
每个容器都由一个独立的 conmon 进程监控,conmon 为容器中 pid 为 1 的进程提供一个 pty,同时它还负责处理容器的日志记录并记录容器进程的退出代码
03.

注:Kubernetes安装过程略,本文只讲CRI-O替代Docker
初始化环境
内核参数优化
[root@kube-master01 ~]# modprobe overlay
[root@kube-master01 ~]# modprobe br_netfilter
[root@kube-master01 ~]# 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
[root@kube-master01 ~]# sysctl --system
安装依赖包
[root@kube-master01 ~]# yum install btrfs-progs-devel container-selinux device-mapper-devel gcc git glib2-devel glibc-devel glibc-static gpgme-devel json-glib-devel libassuan-devel libgpg-error-devel libseccomp-devel make pkgconfig skopeo-containers tar wget -y
[root@kube-master01 ~]# yum install golang-github-cpuguy83-go-md2man golang -y
编译安装runc
[root@kube-master01 ~]# git clone https://github.com/opencontainers/runc /root/src/github.com/opencontainers/runc
[root@kube-master01 ~]# cd /root/src/github.com/opencontainers/runc
[root@kube-master01 runc]# export GOPATH=/root
[root@kube-master01 runc]# make BUILDTAGS="seccomp selinux"
[root@kube-master01 runc]# make install
[root@kube-master01 runc]# ln -sf /usr/local/sbin/runc /usr/bin/runc
[root@kube-master01 runc]#
编译安装cri-o
[root@kube-master01 ~]# git clone https://github.com/cri-o/cri-o /root/src/github.com/cri-o/cri-o
[root@kube-master01 ~]# cd /root/src/github.com/cri-o/cri-o
[root@kube-master01 cri-o]# git checkout master
[root@kube-master01 cri-o]# make
[root@kube-master01 cri-o]# make install
[root@kube-master01 cri-o]# make install.systemd
[root@kube-master01 cri-o]# make install.config
编译安装conmon
[root@kube-master01 ~]# git clone http://github.com/containers/conmon /root/src/github.com/conmon
[root@kube-master01 ~]# cd /root/src/github.com/conmon
[root@kube-master01 conmon]# make
[root@kube-master01 conmon]# make install
安装crictl工具
[root@kube-master01 ~]# wget https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.16.1/crictl-v1.16.1-linux-amd64.tar.gz
[root@kube-master01 ~]# tar -zxvf crictl-v1.16.1-linux-amd64.tar.gz
[root@kube-master01 conmon]# chown root.root crictl
[root@kube-master01 conmon]# mv crictl /usr/local/sbin/crictl
修改cri-o配置
[root@kube-master01 ~]# cd /etc/crio/
[root@kube-master01 crio]# vim crio.conf
cgroup_manager = "systemd"
storage_driver = "overlay2"
storage_option = [ "overlay2.override_kernel_check=1" ]
registries = ['registry.access.redhat.com', 'docker.io']
#pause_image默认镜像为"k8s.gcr.io/pause:3.1",因为国内网络原因,需要修改
pause_image = "gcr.azk8s.cn/google_containers/pause-amd64:3.1"
[root@kube-master01 ~]# mkdir -p /usr/share/containers/oci/hooks.d
修改kubelet配置
#kubelet添加以下参数
--network-plugin=cni \
--container-runtime=remote \
--container-runtime-endpoint=/var/run/crio/crio.sock \
--runtime-request-timeout=5m \
--image-service-endpoint=/var/run/crio/crio.sock \
--runtime-cgroups=/systemd/system.slice \
--kubelet-cgroups=/systemd/system.slice \
启动cri-o、kubelet
[root@kube-master01 ~]# systemctl daemon-reload
[root@kube-master01 ~]# systemctl enable crio
[root@kube-master01 ~]# systemctl start crio
[root@kube-master01 ~]# systemctl status crio
[root@kube-master01 ~]# systemctl enable kubelet
[root@kube-master01 ~]# systemctl start kubelet
[root@kube-master01 ~]# systemctl status kubelet
查看节点
[root@kube-master01 ~]# crictl --runtime-endpoint unix:///var/run/crio/crio.sock version
Version: 0.1.0
RuntimeName: cri-o
RuntimeVersion: 1.17.0-dev
RuntimeApiVersion: v1alpha1
[root@kube-master01 ~]#
[root@kube-master01 ~]# kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
kube-master01 Ready master 3h26m v1.17.0 172.20.143.102 <none> CentOS Linux 7 (Core) 4.19.88 cri-o://1.17.0-dev
[root@kube-master01 ~]#
安装calico
[root@kube-master01 ~]# curl https://docs.projectcalico.org/v3.10/manifests/calico.yaml -O
#POD的网络默认为192.168.0.0/16,需要改为你定义的网段
[root@kube-master01 ~]# POD_CIDR="<your-pod-cidr>"
[root@kube-master01 ~]# sed -i -e "s?192.168.0.0/16?$POD_CIDR?g" calico.yaml
[root@kube-master01 ~]# kubectl apply -f calico.yaml
查看calico
[root@kube-master01 ~]# kubectl get pod -n kube-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
calico-kube-controllers-68649775ff-5hn5v 1/1 Running 0 164m 192.168.237.65 kube-master01 <none> <none>
calico-node-fbxhf 1/1 Running 0 164m 172.20.143.102 kube-master01 <none> <none>
coredns-585ccc4656-gmcrc 1/1 Running 0 164m 192.168.237.66 kube-master01 <none> <none>
[root@kube-master01 ~]#
至此,CRI-O代替docker成为Kubernetes Runtime安装完毕。
即使有了CRI-O、containerd-plugin精简轻量的Runtime架构,但Docker仍是Kubernetes 默认的 Runtime 实现,因为它经受了最多生产环境考验。
大势所趋,相信不久的将来,CRI-O会替代Docker成为Kubernetes默认的Runtime。
有空再更新Kubernetes 1.17版本功能。





