kubernetes 集群搭建(kubeadm方式以containerd作为容器运行时)

0、 前置知识点

目前生产部署 Kubernetes 集群主要有两种方式:

1、kubeadm

Kubeadm 是一个 K8s 部署工具, 提供 kubeadm init 和 kubeadm join, 用于快速部 署 Kubernetes 集群。 官方地址: https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm/

1.1、kubeadm 部署方式介绍

kubeadm 是官方社区推出的一个用于快速部署 kubernetes 集群的工具, 这个工具能通 过两条指令完成一个 kubernetes 集群的部署: 第一、 创建一个 Master 节点 kubeadm init 第二, 将 Node 节点加入到当前集群中 $ kubeadm join <Master 节点的 IP 和端口 >

2、二进制包

从 github 下载发行版的二进制包, 手动部署每个组件, 组成 Kubernetes 集群。 Kubeadm 降低部署门槛, 但屏蔽了很多细节, 遇到问题很难排查。 如果想更容易可 控, 推荐使用二进制包部署 Kubernetes 集群, 虽然手动部署麻烦点, 期间可以学习很 多工作原理, 也利于后期维护。

1、部署实验环境

1.0、主机规划

系统CPUMem主机数量角色
centos7.3 161124G(生产:8G+)1master
centos7.3 161122G2node

主机列表

主机角色主机名主机IP
MASTERmaster192.168.245.100
NODE1node_1192.168.245.101
NODE2node_2192.168.245.102
  • kubernetes:v1.23.1
  • kubeadm:v1.23.1

1.1、主机名

[root@all ~]# hostnamectl set-hostname server_name

1.2、添加 hosts

[root@all ~]# cat >> /etc/hosts << EOF
192.168.23.106 k8s-master
192.168.23.107 k8s-node1
192.168.23.108 k8s-node2
EOF

1.3、关闭firewalld

[root@all ~]# systemctl stop firewalld
[root@all ~]# systemctl disable firewalld
[root@all ~]# firewall-cmd --state

1.4、关闭selinux

[root@all ~]# sed -i '/^SELINUX=/s/=.*/=disabled/' /etc/selinux/config

1.5、关闭swap

为每台主机关闭swap

#临时关闭
[root@all ~]# swapoff -a

#永久关闭:注释掉swap设置行
[root@all ~]# vim /etc/fstab
# /etc/fstab
# Created by anaconda on Wed Jul 24 10:32:24 2019
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/centos-root /                       xfs     defaults        0 0
UUID=146496df-1c2b-4822-9dab-1146e14f27d5 /boot                   xfs     defaults        0 0
#/dev/mapper/centos-swap swap                    swap    defaults        0 0

注释掉swap设置行,重启生效

1.6、安装iptables

[root@all ~]# yum -y install iptables-services
[root@all ~]# systemctl enable iptables
[root@all ~]# systemctl start iptables
[root@all ~]# iptables -nL

添加iptables规则

#清空规则
[root@all ~]# iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
#FORWARD设置为ACCEPT
[root@all ~]# iptables -P FORWARD ACCEPT
#保存设置
[root@all ~]# service iptables save

网桥过滤

#创建过滤规则
[root@all ~]# vim /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
vm.swappiness = 0

[root@all ~]# modprobe br_netfilter
[root@all ~]# lsmod | grep br_netfilter
[root@all ~]# sysctl -p /etc/sysctl.d/k8s.conf

将桥接的 IPv4 流量传递到 iptables 的链:

[root@all ~]# cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1net.bridge.bridge-nf-call-iptables = 1
EOF
[root@all ~]# sysctl --system # 生效$ 

1.7、时间同步

[root@all ~]# ntpdate 1 time1.aliyun.com

2、部署容器运行时

2.0、K8S CRI介绍

K8S发布CRI(Container Runtime Interface),统一了容器运行时接口,凡是支持CRI的容器运行时,皆可作为K8S的底层容器运行时。

在Kubernetes 1.24,Dockershim组件正式从kubelet中移除。从Kubernetes 1.24开始,默认将无法使用Docker Engine作为容器运行。
K8S为什么要放弃使用Docker作为容器运行时,而使用containerd呢?

Dockershim组件一直以来,扮演着Docker、containerd 和CRI之间的翻译官角色,但事实上新版本的containerd 兼容CRI接口标准,可以绕开Docker直接与CRI对接,如果你使用Docker作为K8S容器运行时的话,kubelet需要先要通过dockershim去调用Docker,再通过Docker去调用containerd。如果你使用containerd作为K8S容器运行时的话,由于containerd内置了CRI插件,kubelet可以直接调用containerd。
使用containerd不仅性能提高了(调用链变短了),而且资源占用也会变小(Docker不是一个纯粹的容器运行时,具有大量其他功能)。

Docker Engine 没有实现 CRI, 而这是容器运行时在 Kubernetes 中工作所需要的。 为此,必须安装一个额外的服务 cri-dockerd。 cri-dockerd 是一个基于传统的内置 Docker 引擎支持的项目, 它在 1.24 版本从 kubelet 中移除。

你的容器运行时必须至少支持 v1alpha2 版本的容器运行时接口。

Kubernetes 1.26 默认使用 v1 版本的 CRI API。如果容器运行时不支持 v1 版本的 API, 则 kubelet 会回退到使用(已弃用的)v1alpha2 版本的 API

2.1、使用containerd作为K8S的容器运行时

本节概述了使用 containerd 作为 CRI 运行时的必要步骤。

使用以下命令在系统上安装 Containerd:

Step 1: 在[CentOS]使用dnf方法安装containerd.io

Step 2.1.1: 卸载旧版本的Docker
$ sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
Step 2.1.2: 设置docker yum源
$ sudo yum install -y yum-utils

$ sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
Step 2.1.3: 安装 containerd.io
 $ sudo yum install  containerd.io 
 
 $ sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Step 2: 安装CNI 插件

下载安装包: cni-plugins-<OS>-<ARCH>-<VERSION>.tgz

下载链接: https://github.com/containernetworking/plugins/releases , 并在“/opt/cni/bin”下解压它:

$ mkdir -p /opt/cni/bin
$ wget  https://github.com/containernetworking/plugins/releases/cni-plugins-<OS>-<ARCH>-<VERSION>.tgz
$ tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-v1.1.1.tgz

使用源码包安装等更多方法请参考:容器运行时containerd的部署和使用

创建有效的配置文件 config.toml 后返回此步骤。

你可以在路径 /etc/containerd/config.toml 下找到此文件。

$ ll /etc/containerd/config.toml

在 Linux 上,containerd 的默认 CRI 套接字是 /run/containerd/containerd.sock。 在 Windows 上,默认 CRI 端点是 npipe://./pipe/containerd-containerd

Step 2.2.1、配置 systemd cgroup 驱动

结合 runc 使用 systemd cgroup 驱动,在 /etc/containerd/config.toml 中设置:

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
  ...
  [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
    SystemdCgroup = true

如果你使用 cgroup v2,则推荐 systemd cgroup 驱动。

说明:

如果你使用RPM包安装 containerd,可能会发现其中默认禁止了 CRI 集成插件。

你需要启用 CRI 支持才能在 Kubernetes 集群中使用 containerd。 要确保 cri 没有出现在 /etc/containerd/config.toml 文件中 disabled_plugins 列表内。如果你更改了这个文件,也请记得要重启 containerd

如果你在初次安装集群后或安装 CNI 后遇到容器崩溃循环,则随软件包提供的 containerd 配置可能包含不兼容的配置参数。考虑按照 getting-started.md 中指定的 containerd config default > /etc/containerd/config.toml 重置 containerd 配置,然后相应地设置上述配置参数。

如果你应用此更改,请确保重新启动 containerd:

sudo systemctl restart containerd

当使用 kubeadm 时,请手动配置 kubelet 的 cgroup 驱动

Step 2.2.2、重载沙箱(pause)镜像

在你的 containerd 配置中, 你可以通过设置以下选项重载沙箱镜像:

[plugins."io.containerd.grpc.v1.cri"]
  sandbox_image = "registry.k8s.io/pause:3.2"

一旦你更新了这个配置文件,可能就同样需要重启 containerdsystemctl restart containerd

Step 2.2.3、containerd使用
containerd使用

如果你之前用过Docker,你只要稍微花5分钟就可以学会containerd了,接下来我们学习下containerd的使用。

其实只要把我们之前使用的docker命令改为crictl命令即可操作containerd,
比如查看所有运行中的容器;
crictl psCONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID4ca73ded41bb6 3b0b04aa3473f Less than a second ago Running helm 20 21103f00588723bb5767a81954 296a6d5035e2d About a minute ago Running coredns 1 af887263bd869a5e34c24be371 0346349a1a640 About a minute ago Running nginx 1 89defc6008501
查看所有镜像;
crictl imagesIMAGE TAG IMAGE ID SIZEdocker.io/library/nginx 1.10 0346349a1a640 71.4MBdocker.io/rancher/coredns-coredns 1.8.0 296a6d5035e2d 12.9MBdocker.io/rancher/klipper-helm v0.4.3 3b0b04aa3473f 50.7MBdocker.io/rancher/local-path-provisioner v0.0.14 e422121c9c5f9 13.4MBdocker.io/rancher/metrics-server v0.3.6 9dd718864ce61 10.5MBdocker.io/rancher/pause 3.1 da86e6ba6ca19 327kB
进入容器内部执行bash命令,这里需要注意的是只能使用容器ID,不支持使用容器名称;
crictl exec -it a5e34c24be371 /bin/bash
查看容器中应用资源占用情况,可以发现占用非常低。
crictl statsCONTAINER CPU % MEM DISK INODES3bb5767a81954 0.54 14.27MB 254B 14a5e34c24be371 0.00 2.441MB 339B 16总结

从Docker转型containerd非常简单,基本没有什么门槛。只要把之前Docker命令中的docker改为crictl基本就可以了,果然是同一个公司出品的东西,用法都一样。所以不管K8S到底弃用不弃用Docker,对我们开发者使用来说,基本没啥影响!

2.2、使用CRI-O作为K8S的容器运行时

本节包含安装 CRI-O 作为容器运行时的必要步骤。

要安装 CRI-O,请按照 CRI-O 安装说明执行操作。

2.2.1、cgroup 驱动

CRI-O 默认使用 systemd cgroup 驱动,这对你来说可能工作得很好。 要切换到 cgroupfs cgroup 驱动,请编辑 /etc/crio/crio.conf 或在 /etc/crio/crio.conf.d/02-cgroup-manager.conf 中放置一个插入式配置,例如:

[crio.runtime]
conmon_cgroup = "pod"
cgroup_manager = "cgroupfs"

你还应该注意当使用 CRI-O 时,并且 CRI-O 的 cgroup 设置为 cgroupfs 时,必须将 conmon_cgroup 设置为值 pod。 通常需要保持 kubelet 的 cgroup 驱动配置(通常通过 kubeadm 完成)和 CRI-O 同步。

对于 CRI-O,CRI 套接字默认为 /var/run/crio/crio.sock

2.2.2、重载沙箱(pause)镜像

在你的 CRI-O 配置中, 你可以设置以下配置值:

[crio.image]
pause_image="registry.k8s.io/pause:3.6"

这一设置选项支持动态配置重加载来应用所做变更:systemctl reload crio。 也可以通过向 crio 进程发送 SIGHUP 信号来实现。

2.3、使用Docker作为K8S的容器运行时

在没有特殊需求的情况下,还是推荐大家使用containerd 或 CRI-O等受支持的容器运行时软件。
如果您依赖Docker Engine,也可以使用cri-dockerd这样的软件来解决。不管您使用哪种方式,云君都建议您做好一些兼容性测试工作,以确保Kubernetes 1.24集群的正常运行。

参考:https://www.cnblogs.com/fenghua001/p/16849875.html

2.3.1、安装 Docker

[root@all ~]# wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
[root@all ~]# yum -y install docker-ce-18.06.1.ce-3.el7
[root@all ~]# systemctl enable docker && systemctl start docker
[root@all ~]# docker --version
Docker version 18.06.1-ce, build e68fc7a

2.3.2、安装cri-dockerd

方法一:

到下面的链接下载最新版cri-docker
https://github.com/Mirantis/cri-dockerd/releases

wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.2.6/cri-dockerd-0.2.6.amd64.tgz

tar -xf cri-dockerd-0.2.6.amd64.tgz
cp cri-dockerd/cri-dockerd /usr/bin/

chmod +x /usr/bin/cri-dockerd

 #配置启动文件

vim /usr/lib/systemd/system/cri-docker.service
[Unit]
Description=CRI Interface for Docker Application Container Engine
Documentation=https://docs.mirantis.com
After=network-online.target firewalld.service docker.service
Wants=network-online.target
Requires=cri-docker.socket

[Service]
Type=notify

ExecStart=/usr/bin/cri-dockerd --network-plugin=cni --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.8

ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always

StartLimitBurst=3

StartLimitInterval=60s

LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity

TasksMax=infinity
Delegate=yes
KillMode=process

[Install]
WantedBy=multi-user.target


 #生成socket文件

vim /usr/lib/systemd/system/cri-docker.socket

[Unit]
Description=CRI Docker Socket for the API
PartOf=cri-docker.service

[Socket]
ListenStream=%t/cri-dockerd.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker

[Install]
WantedBy=sockets.target

 

 # 启动cri-docker并设置开机自动启动

systemctl daemon-reload ; systemctl enable cri-docker --now

systemctl is-active cri-docke

如果是多master 需要操作下面步骤

#先在master上解压出cri-docker,然后拷贝到其他节点
[root@k8s-master01 ~]# tar -zxf cri-dockerd-0.2.5.amd64.tgz
[root@k8s-master01 ~]# cp cri-dockerd/cri-dockerd /usr/bin/
[root@k8s-master01 ~/cri-dockerd]# scp /usr/bin/cri-dockerd root@k8s-node01:/usr/bin/
[root@k8s-master01 ~/cri-dockerd]# scp /usr/bin/cri-dockerd root@k8s-node02:/usr/bin/
#创建cri-docker启动文件,然后拷贝到其他节点
[root@k8s-master01 ~]# cat /usr/lib/systemd/system/cri-docker.service

[root@k8s-master01 ~]# cat /usr/lib/systemd/system/cri-docker.socket

 

方法二:

wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.2.6/cri-dockerd-0.2.6-3.el7.x86_64.rpm

rpm -ivh cri-dockerd-0.2.6-3.el7.x86_64.rpm
systemctl enable cri-docker

重载沙箱

vim /usr/lib/systemd/system/cri-docker.service  # 修改如下
ExecStart=/usr/bin/cri-dockerd --network-plugin=cni --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.8 --container-runtime-endpoint fd://

systemctl start cri-docker

3、 所有节点安装 kubeadm、kubelet 和 kubectl

3.1、添加阿里云 YUM 软件源

设置仓库地址

[root@all ~]# cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"]
}
EOF

添加kubernetes yum 源

[root@all ~]# cat > /etc/yum.repos.d/kubernetes.repo << EOF
[kubernetes_aliyun]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg

[kubernetes_tuna]
name=kubernetes
baseurl=https://opentuna.cn/kubernetes/yum/repos/kubernetes-el7-$basearch
enabled=1
gpgcheck=0
EOF

3.2、安装 kubeadm, kubelet 和 kubectl

#这里安装的三个程序的版本,需要和最终安装的集群版本一致,如果对集群版本有要求,这里就需要指定版本安装
[root@all ~]# yum install -y kubelet kubeadm kubectl

#启动kubelet服务
[root@all ~]# systemctl start  kubelet
[root@all ~]# systemctl enable kubelet

[root@all ~]# systemctl status kubelet

4、 初始化kubeadm(部署 Kubernetes Master节点)

4.1、在Master执行

由于默认拉取镜像地址 k8s.gcr.io 国内无法访问, 这里指定阿里云镜像仓库地址。

[root@master ~]# 
kubeadm init \ 
--apiserver-advertise-address=192.168.245.100 \
--image-repository registry.aliyuncs.com/google_containers \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16 \
--kubernetes-version v1.26.1 

初始化参数详解

--apiserver-advertise-address string 
	设置 apiserver 绑定的 IP.(Master节点IP)
--image-repository string 
	选择拉取 control plane images 的镜像repo (default "k8s.gcr.io")
--kubernetes-version string 
	选择K8S版本. (default "stable-1")
--service-cidr string 
	指定service 的IP 范围. (default "10.96.0.0/12")
--pod-network-cidr string 
	指定 pod 的网络, control plane 会自动将 网络发布到其他节点的node,让其上启动的容器使用此网络


--apiserver-bind-port int32 
	设置apiserver 监听的端口. (默认 6443)
--apiserver-cert-extra-sans strings 
	api证书中指定额外的Subject Alternative Names (SANs) 可以是IP 也可以是DNS名称。 证书是和SAN绑定的。
--cert-dir string 
	证书存放的目录 (默认 "/etc/kubernetes/pki")
--certificate-key string 
	kubeadm-cert secret 中 用于加密 control-plane 证书的key
--config string 
	kubeadm 配置文件的路径.
--cri-socket string 
	CRI socket 文件路径,如果为空 kubeadm 将自动发现相关的socket文件; 只有当机器中存在多个 CRI socket 或者 存在非标准 CRI socket 时才指定.
--dry-run 
	测试,并不真正执行;输出运行后的结果.
--feature-gates string 
	指定启用哪些额外的feature 使用 key=value 对的形式。
--help -h 
	帮助文档
--ignore-preflight-errors strings 
	忽略前置检查错误,被忽略的错误将被显示为警告. 例子: 'IsPrivilegedUser,Swap'. Value 'all' ignores errors from all checks.
--node-name string 
	指定node的名称,默认使用 node 的 hostname.
--service-dns-domain string 
	指定 service 的 dns 后缀, e.g. "myorg.internal". (default "cluster.local")
--skip-certificate-key-print 
	不打印 control-plane 用于加密证书的key.
--skip-phases strings 
	跳过指定的阶段(phase)
--skip-token-print 
	不打印 kubeadm init 生成的 default bootstrap token 
--token string 
	指定 node 和control plane 之间,简历双向认证的token ,格式为 [a-z0-9]{6}\.[a-z0-9]{16} - e.g. abcdef.0123456789abcdef
--token-ttl duration 
	token 自动删除的时间间隔。 (e.g. 1s, 2m, 3h). 如果设置为 '0', token 永不过期 (default 24h0m0s)
--upload-certs 
	上传 control-plane 证书到 kubeadm-certs Secret.
–-node-name string 
	指定当前节点的名称。

4.2、使用 kubectl 工具:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
$ kubectl get nodes

5、 安装 Pod 网络插件( CNI)

$ kubectl apply – f
https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kubeflannel.yml

确保能够访问到 quay.io 这个 registery。 如果 Pod 镜像下载失败, 可以改这个镜像地址

6、 加入 Kubernetes Node

( 1) 在 192.168.31.62/63( Node) 执行 向集群添加新节点, 执行在 kubeadm init 输出的 kubeadm join 命令:

$ kubeadm join 192.168.31.61:6443 --token esce21.q6hetwm8si29qxwn \
--discovery-token-ca-cert-hash
sha256:00603a05805807501d7181c3d60b478788408cfe6cedefedb1f97569708be9c5

7、 测试 kubernetes 集群

在 Kubernetes 集群中创建一个 pod, 验证是否正常运行:

$ kubectl create deployment nginx --image=nginx
$ kubectl expose deployment nginx --port=80 --type=NodePort
$ kubectl get pod,svc

访问地址: http://NodeIP:Port