使用Containerd代替docker部署K8s集群
课程安排
- 1、k8s的容器运行时架构
- 2、CRI与OCI介绍
- 3、k8s弃用docker原因分析
- 4、dockershim、Containerd与CRI-O对比
- 5、使用containerd作为容器运行时部署k8s集群
- 6、使用crictl与ctr代替docker
一、k8s中容器运行时的选择
1、k8s的容器运行时架构
容器运行时(ContainerRuntime),运行于 kubernetes(k8s)集群的每个节点中,负责容器的整个生命周期。其中dockershim是目前应用最广的容器运行时,随着容器云的发展,越来越多的容器运行时涌现。为了解决这些容器运行时和 k8s 的集成问题,在 k8s1.5 版本中,社区推出了 CRI(ContainerRuntimeInterface,容器运行时接口),以支持更多的容器运行时。
下图是k8s的容器运行时架构:
2、CRI与OCI运行机制
下图是k8s中容器运行时的执行逻辑:
CRI是kubernetes 定义的一组 gRPC 服务。Kubelet作为客户端,基于gRPC 框架,通过 Socket 和容器运行时通信。它包括两类服务:镜像服务(ImageService)和运行时服务(Runtime Service)。镜像服务提供下载、检查和删除镜像的远程程序调用。运行时服务包含用于管理容器生命周期,以及与容器交互的远程调用。OCI(OpenContainerInitiative,开放容器计划)定义了创建容器的格式和运行时的开源行业标准,包括镜像规范(ImageSpecification)和运行时规范(RuntimeSpecification)。镜像规范定义了OCI镜像的标准。高层级运行时将会下载一个 OCI 镜像,并把它解压成 OCI 运行时文件系统包。运行时规范则描述了如何从 OCI运行时文件系统包运行容器程序,并且定义它的配置、运行环境和生命周期。如何为新容器设置命名空间(namepsaces)和控制组(cgroups),以及挂载根文件系统等等操作。
3、k8s弃用docker的原因
2020年底,Kubernetes官方发布公告,宣布自v1.20起放弃对Docker的支持,届时用户将收到 Docker 弃用警告,并需要改用其他容器运行时。但 Docker 作为容器镜像构建工具的作用将不受影响,用其构建的容器镜像将一如既往地在集群中与所有容器运行时正常运转。这里面说到了容器运行时,其实k8s要弃用的是dockershim这个容器运行时,而非docker, dockershim是Kubernetes的一个组件,主要目的是为了通过CRI操作Docker,具体逻辑情况下图:
从图中可以看出,CRI、dockershim、docker直接的调用关系。dockershim存在的目的是为了Kubernetes通过CRI操作Docker,所以Kubernetes任何的功能变动或Docker有任何的功能特性变更,
dockershim代码必须加以改动才能保证能够支持变更。此外,Kubernetes去调用dockershim跟Docker做沟通,Docker的底层运行时是containerd,可以发现最终都是要调用containerd,并且containerd自身也是可以支持CRI的。那为什么要先绕过一层Docker呢?是不是可以直接通过CRI跟Containerd 进行交互呢?这也是现在Kubernetes社区希望弃用dockershim的原因之一。
Dockershim中间件会一直保留到2021年末,直到Kubernetes发布1.23版本时才完全移除。不过,Kubernetes官方表示用户今后依然可以使用 Docker 来构建容器镜像,而Docker 生成的镜像实际上也是一个OCI(Open Container Initiative)镜像。无论使用什么工具来构建镜像,只要符合OCI标准的镜像在Kubernetes看来都是一样的。那么,Dockershim废弃后,可替代它的容器运行时有哪些呢,最常见的有containerd和CRI-O.
4、dockershim、Containerd与CRI-O对比
下图是这三个运行时的详细调用层级:
Docker 的多层封装和调用,导致其在可维护性上略逊一筹,增加了线上问题的定位难度,Containerd 和cri-o 的方案比起 docker 简洁很多。因此实际应用中更偏向于选用更加简单和纯粹的 containerd 和 cri-o作为我们的容器运行时。从功能性来讲,containerd 和 cri-o 都符合 CRI 和 OCI 的标准。从稳定性来说,cri-o没有足够的生产环境经验,而containerd一直在docker里使用,并且,docker的生产环境经验可以说比较充足。可见在稳定性上 containerd 略胜一筹。所以推荐大家选择containerd作为k8s的容器运行时。
二、 使用containerd作为容器运行时部署k8s集群
1、安装规划
此环境下需要3台主机,主机地址和角色如下表所示:
主机名 | IP地址 | 集群角色 | |
---|---|---|---|
master1 | master1 | ||
master1 | master2 | ||
Node1 | work1 | ||
Node2 | work2 | ||
Node3 | |||
Node4 |
2、升级系统内核版本
安装内核
wget https://elrepo.org/linux/kernel/el7/x86_64/RPMS/kernel-lt-5.4.114-1.el7.elrepo.x86_64.rpm
wget https://elrepo.org/linux/kernel/el7/x86_64/RPMS/kernel-lt-devel-5.4.114-1.el7.elrepo.x86_64.rpm
yum -y install kernel-lt-5.4.114-1.el7.elrepo.x86_64.rpm kernel-lt-devel-5.4.114-1.el7.elrepo.x86_64.rpm
调整默认内核启动
grub2-set-default "CentOS Linux (5.4.162-1.el7.elrepo.x86_64) 7 (Core)"
检查是否修改正确并重启系统
grub2-editenv list
reboot
3、开启IPVS支持
创建/etc/sysconfig/modules/ipvs.modules文件,内容如下:
#!/bin/bash
ipvs_modules="ip_vs ip_vs_lc ip_vs_wlc ip_vs_rr ip_vs_wrr ip_vs_lblc ip_vs_lblcr ip_vs_dh ip_vs_sh ip_vs_fo ip_vs_nq ip_vs_sed ip_vs_ftp nf_conntrack"
for kernel_module in ${ipvs_modules}; do
/sbin/modinfo -F filename ${kernel_module} > /dev/null 2>&1
if [ $? -eq 0 ]; then
/sbin/modprobe ${kernel_module}
fi
done
最后,执行如下命令使配置生效:
chmod 755 /etc/sysconfig/modules/ipvs.modules
sh /etc/sysconfig/modules/ipvs.modules
lsmod | grep ip_vs
4、关闭防火墙、selinux
# 所有节点都需要关闭防火墙,执行如下操作:
systemctl stop firewalld && systemctl disable firewalld
setenforce 0
sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config
# 接着,还需要关闭系统的交换分区,执行如下命令:
swapoff -a
cp /etc/fstab /etc/fstab.bak
cat /etc/fstab.bak | grep -v swap > /etc/fstab
# 没有采取注释的方式,是直接过滤掉swap行后重新写入新文件。
# 然后,还需要修改iptables设置,在/etc/sysctl.conf中添加如下内容:
vm.swappiness = 0
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
# 最后,执行如下命令,以使设置生效:
sysctl -p
5、主机名本地解析配置
每个主机的主机名以及IP地址都在上面环境介绍中给出来了,根据这些信息,在每个k8s集群节点添加如下主机名解析信息,将这些信息添加到每个集群节点的/etc/hosts文件中,主机名解析内容如下:
127.0.0.1 localhost
172.16.213.221 k8smaster
172.16.213.222 k8swork1
172.16.213.223 k8swork2
6、安装 Containerd
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum list | grep containerd
# 可以选择安装一个版本,比如我这里安装最新版本:
yum install containerd.io.x86_64 -y -y
7、创建containerd配置文件
# 先生成containerd配置文件:
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml
# 替换配置文件
sed -i "s#k8s.gcr.io/pause:3.2#winjay/pause-amd64:3.5#g" /etc/containerd/config.toml
sed -i '/containerd.runtimes.runc.options/a\ \ \ \ \ \ \ \ \ \ \ \ SystemdCgroup = true' /etc/containerd/config.toml
sed -i "s#https://registry-1.docker.io#https://ptgaj77b.mirror.aliyuncs.com#g"/etc/containerd/config.toml
# 启动Containerd:
systemctl daemon-reload && systemctl enable containerd && systemctl restart containerd
8、安装containerd命令行工具crictl
yum install cri-tools
# 然后,使用crictl连接containerd,需要创建/etc/crictl.yaml,写入以下内容;
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
# 这里注意runtime-endpoint 和image-endpoint必须与/etc/containerd/config.toml中对应项的配置保持一致。
9、安装Kubeadm、kubelet、kubectl工具
在确保 Containerd安装完成后,系统基础环境配置也完成后,现在我们就可以来安装 Kubeadm、kubelet了,我这里是通过指定yum 源的方式来进行安装,使用阿里云的源进行安装:
cat <<EOF > /etc/yum.repos.d/k8s.repo
[k8s]
name=k8s
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
EOF
# 安装kubernetes工具
yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
# 加入开机启动项
systemctl daemon-reload systemctl enable kubelet && systemctl start kubelet
systemctl enable --now kubelet
10、初始化k8s集群
执行如下命令:
kubeadm config print init-defaults
kubeadm config images list
kubeadm config images list --image-repository registry.aliyuncs.com/iivey
其中:
- 第一个命令用来查看安装k8s的相关信息,主要是安装源和版本。
- 第二条命令是查询需要的镜像,从输出可在,默认是从k8s.gcr.io这个地址下载镜像,此地址国内无法访问,因此需要修改默认下载镜像的地址。
- 第三条命令是设置k8s镜像仓库为阿里云镜像站地址,查看一下需要下载的镜像在阿里云镜像站中是否都有。
由此可知,通过kubeadm初始化集群,需要这7个镜像,由于gcr无法访问,因此,我将这些镜像统一放到了我的DockerHub仓库下。
接着,在 master 节点配置 kubeadm 初始化文件,可以通过如下命令导出默认的初始化配置:
kubeadm config print init-defaults > kubeadm.yaml
然后根据我们自己的需求修改配置,这里修改的有advertiseAddress、criSocket、name、imageRepository 的值。
同时,添加了kube-proxy的模式为ipvs,并且,需要注意的是,由于我们使用的containerd作为运行时,所以在初始化节点的时候需要指定cgroupDriver为systemd。
# 新增
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
在保证所需要的镜像都可以正常下载后,使用上面的配置文件进行初始化:
kubeadm init --config=kubeadm.yaml
初始化完成,根据提示,在master节点执行如下操作
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
为了使用更便捷,启用 kubectl 命令的自动补全功能。
[root@master ~]#
echo "source <(kubectl completion bash)" >> ~/.bashrc`
现在kubectl可以使用了
11、添加集群节点
初始化集群的操作是在master节点完成的,接下来,要将work节点加入到集群中,首先需要在每个node节点上执行基础配置工作,主要有关闭防火墙和selinux、禁用swap、配置主机名解析、启动网络桥接功能以及启动kubeket服务并设置开机自启,这些已经在前面介绍过,这里不再多说了。
下面介绍下如何添加nodes到集群中,执行如下命令:
kubeadm join 172.16.213.221:6443 --token bnefy8.d79yn6ylxlk7k8hr --discovery-token-ca-cert-hash
sha256:eaa17f4b308e9406891f85f664c0d2c97a49bd9e963f64c9453b7042509e106c
这里的–token来自前面kubeadm init输出提示,如果当时没有记录下来可以通过如下命令找回, token是有24小时有效期的:
kubeadm token create --ttl 0 --print-join-command
执行成功后运行 get nodes
命令
kubectl get node
NAME STATUS ROLES AGE VERSION
k8smaster NotReady control-plane,master 29m v1.21.0
k8swork1 NotReady <none> 28m v1.21.0
k8swork1 NotReady <none> 28m v1.21.0
可以看到是,两个节点都是NotReady 状态,这是因为还没有安装网络插件。
12、安装网络插件
接下来安装网络插件。网络插件可以选择calico和flannel,这里我们使用calico。
wget https://docs.projectcalico.org/manifests/calico.yaml
安装calico网络插件
kubectl apply -f calico.yaml
此插件的安装过程,需要下载三个镜像文件,下载完成,网络插件即可正常工作。等网络插件镜像下载完成以后,看到node的状态会变成ready,执行如下命令查看:
kubectl get node
如果发现某个节点还是处于NotReady状态,可以重启此节点的kubelet服务,然后此节点就会重新下载需要的镜像。
最后,执行如下命令,查看pod状态:
kubectl get pods -n kube-system
三、containerd中crictl与ctr的使用
1、 crictl与ctr介绍
ctr:是containerd本身的CLI
crictl :是Kubernetes社区定义的专门CLI工具
crictl提供了类似于 docker 的命令行工具,不需要通过 Kubelet 就可以通过 CRI 跟容器运行时通信。它是专门为Kubernetes 设计的,提供了Pod、容器和镜像等资源的管理命令,可以帮助用户和开发者调试容器应用或者排查异常问题。crictl 可以用于所有实现了 CRI 接口的容器运行时。
注意,crictl 并非 kubectl 的替代品,它只通过 CRI 接口与容器运行时通信,可以用来调试和排错,但并不用于运行容器。虽然 crictl 也提供运行 Pod 和容器的子命令,但这些命令仅推荐用于调试。
2、 crictl与ctr的使用
Crictl与docker命令对比
Containerd相比于Docker , 多了namespace概念, 每个image和container都会在各自的namespace下可见, 目前Crictl会使用k8s.io作为命名空间,而ctr的默认命名空间是default。也就是
说,使用ctr命令下载的镜像,不指定命名空间的话,使用Crictl工具是看不到的,看下面例子:
ctr -n k8s.io images pull docker.io/library/redis:6.2.1
crictl images ls
这种指定命名空间后,通过crictl命令是能看到下载的镜像的。
而如果执行如下命令:
ctr images pull docker.io/library/redis:6.2.1
下载下来的镜像,执行crictl images ls命令是看不到的。因为ctr下载的镜像默认放到了default命名空间了。
标记镜像:
ctr -n k8s.io i tag k8s.gcr.io/pause:3.2 registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2
导出镜像:
ctr -n k8s.io i export pause.tar registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2
导入镜像:
ctr -n k8s.io i import pause.tar
注意,上面的标记镜像、导入、导出镜像都是通过ctr工具实现的,原因是crictl并没有这些功能。所以,在执行ctr命令时,都要指定命名空间,因为crictl默认的命名空间是k8s.io。
四、在k8s集群中安装kubernetes-dashboard
1、下载kubernetes-dashboard
kubernetes-dashboard是k8s的UI看板,可以查看、编辑整个集群状态。
可从https://github.com/kubernetes/dashboard/releases/tag/v2.2.0 下载最新的dashboard/资源文件,然后进行安装。
下载下来的文件名为recommended.yaml,默认情况下此文件中的几个镜像地址,国内无法访问,需要修改,为方便大家学习,
执行如下命令进行安装:
kubectl apply -f recommended.yaml
安装完成后,执行如下命令,查看kubernetes-dashboard
随机的访问端口:
kubectl get svc -n kubernetes-dashboard
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dashboard-metrics-scraper ClusterIP 10.98.184.182 <none> 8000/TCP 150m
kubernetes-dashboard NodePort 10.100.209.10 <none> 443:32081/TCP 150m
此时,可以通过集群任意一个节点的ip加上32081端口访问kubernetes-dashboard 。
2、创建dashboard登录认证
访问dashboard需要认证,因此还需要创建一个认证机制,执行如下命令,创建一个ServiceAccount
用户dashboard-admin
:
kubectl create serviceaccount dashboard-admin -n kube-system
serviceaccount/dashboard-admin created
然后将dashboard-admin用户与角色绑定:
kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --
serviceaccount=kube-system:dashboard-admin
clusterrolebinding.rbac.authorization.k8s.io/dashboard-admin created
最后,查看Token令牌,执行如下组合命令:
kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret | awk '/dashboard-admin/{print $1}')
此命令输出中,token就是令牌,复制出来保存。有了令牌后,就可以在dashboard选择令牌登录了。
五、在k8s集群中安装Metrics Server监控
1、获取Metrics Server资源文件
Kubernetes Metrics Server 是 Cluster 的核心监控数据的聚合器,kubeadm 默认是不部署的。
这里通过容器方式部署metrics-server,从https://github.com/kubernetes-sigs/metrics-server/releases 下载所需的版本,我
这里用的是最新版本v0.4.3:
wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.4.3/components.yaml
接着,修改修改components.yaml文件,找到metrics-server的Deployment部分,在“--secure-port=4443”下面添加如下内容:
- --kubelet-insecure-tls
然后,找到metrics-server镜像的地址:
image: k8s.gcr.io/metrics-server/metrics-server:v0.5.2
修改为如下:
image: docker.io/winjay/metrics-server:v0.5.2
2、部署Metrics Server
修改完Metrics Server资源文件后,就可以安装metrics-server了。执行如下命令:
kubectl apply -f components.yaml
然后,查看metrics-server服务状态:,执行如下命令:
kubectl get pod -n kube-system | grep metrics-server
metrics-server-5c5b7cff87-c96b4 1/1 Running 0 22h
最后,执行以下命令,检查节点占用性能情况。
kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
master1 207m 0% 4308Mi 13%
master2 161m 1% 2542Mi 16%
node1 121m 0% 2468Mi 7%
node2 88m 0% 2078Mi 6%
至此,Metrics Server安装完成。
评论区