Kubeadm

kubeadm 是 Kubernetes 社区提供的集群构建工具,它能够以最佳实践的方式部署一个最小化的可用 Kubernetes 集群。

但是 kubeadm 在设计上并未安装网络解决方案,所以需要用户自行安装第三方符合 CNI 的网络解决方案,如 flanal,calico,canal 等。

常见的 Kubernetes 集群的运行模式有三种:

  1. 独立组件模式:各组件直接以守护进程方式运行,如二进制部署。
  2. 静态 Pod 模式:各组件以静态 Pod 运行在 Master 节点,kubelet 和容器运行时以守护进程运行所有节点,kube-proxy 以 DaemonSet 形式托管在集群。
  3. 自托管(self-hosted)模式:和第二种类似,但各组件都运行为 Pod 对象(非静态),且这些 Pod 对象都以 DaemonSet 形式托管在集群。

kubeadm 能够部署第二种和第三种运行方式。一般用于测试环境部署使用,生产环境更推荐二进制安装,更容易排查问题。

安装 Kubeadm(YUM 源安装方式)

在安装之前,所有节点需要新增 kubeadm 的 yum 源:

cat > /etc/yum.repos.d/kubernetes.repo << EOF
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

此时查看支持的 kubeadm 版本:

yum list kubeadm.x86_64 --showduplicates

我在写本文的时候最新版本支持到了 1.25.2-0


所有节点安装 kubeadm:

yum -y install kubeadm-1.25.0-0 kubelet-1.25.0-0 kubectl-1.25.0-0

但是可能会因为网络问题,下载可能会很慢,可以使用第二种方式。

安装 Kubeadm(rpm 包安装方式)

通过下载过程可以看到一共需要 6 个 rpm 包,可以直接去阿里云仓库里面下载:

http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/Packages

也可以通过下面的链接进行下载:

包名

版本

下载地址

kubeadm

1.25.0-0

点击下载

kubectl

1.25.0-0

点击下载

kubelet

1.25.0-0

点击下载

cri-tools(依赖)

1.25.0-0

点击下载

kubernetes-cni(依赖)

1.1.1-0

点击下载

socat(依赖,隶属 CentOS 官方源)

1.7.3.2-2.el7

yum 安装

需要给所有服务器都创建用于存放这些 rpm 包的目录,并安装 socat:

mkdir /ezops/packages/kubeadm
yum -y install socat

然后将下载好的 5 个 rpm 安装包改好名字上传到 /ezops/packages/kubeadm 目录中,然后执行安装:

cd /ezops/packages/kubeadm
yum -y localinstall *

配置 Kubelet

由于本文使用 Containerd 作为容器运行时,所以需要对 kubelet 进行配置,如果不是则不需要执行。

所有节点都执行 kubelet 配置,Kubelet 将会以守护进程的方式运行在所有节点:

cat >/etc/sysconfig/kubelet<<EOF
KUBELET_KUBEADM_ARGS="--container-runtime=remote --runtime-request-timeout=15m --container-runtime-endpoint=unix:///run/containerd/containerd.sock"
EOF

设置 Kubelet 开机启动:

systemctl daemon-reload
systemctl enable --now kubelet
systemctl status kubelet

集群还未初始化,此时 Kunelet 还没有配置文件,是无法启动的,暂时不用管它。

集群初始化

所有节点创建初始化配置文件目录,该目录下面的文件只有在集群初始化的时候有用:

mkdir /ezops/kubeadm
cd /ezops/kubeadm

集群的初始化操作只需要在任意一个 Master 节点上执行即可,后面通过同步到其他节点完成配置,这里选择 master-01 执行。

master-01 新增配置文件如下:

cat > kubeadm-config-old.yaml << EOF
apiVersion: kubeadm.k8s.io/v1beta2
bootstrapTokens:
- groups:
  - system:bootstrappers:kubeadm:default-node-token
  # 加入集群的 Token
  token: 7t2weq.bjbawausm0jaxury
  # 加入集群的 Token 有效期
  ttl: 24h0m0s
  usages:
  - signing
  - authentication
kind: InitConfiguration
localAPIEndpoint:
  # 本机地址,这里只支持 IP
  advertiseAddress: 192.168.200.101
  # API Server 监听端口
  bindPort: 6443
nodeRegistration:
  # Containerd socket 文件地址
  criSocket: unix:///var/run/containerd/containerd.sock
  # 本机名称,需要能够解析通信
  name: master-01
  taints:
  - effect: NoSchedule
    key: node-role.kubernetes.io/control-plane
---
apiServer:
  certSANs:
  # VIP 地址,如果只有一个节点就写 IP 地址即可
  - 192.168.200.100
  timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta2
# 证书存放目录
certificatesDir: /etc/kubernetes/pki
# 集群名称
clusterName: kubernetes
# 配置高可用集群,使用可 Nginx SLB 代理了 API Server 端口
controlPlaneEndpoint: 192.168.200.100:16443
controllerManager: {}
dns:
  type: CoreDNS
etcd:
  local:
    dataDir: /var/lib/etcd
# 指定国内的镜像仓库
imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers
kind: ClusterConfiguration
# 该版本需要和 kubeadm 一致
kubernetesVersion: v1.25.0
networking:
  dnsDomain: cluster.local
  # Pod 网段(可用IP个数 65534,172.16.0.1 - 172.16.255.254)
  podSubnet: 172.16.0.0/16
  # Service 网段,注意不能和自己的网络冲突(可用IP个数 65534,10.10.0.1 - 10.10.255.254)
  serviceSubnet: 10.10.0.0/16
scheduler: {}
EOF

如果 Pod 网段和 Service 网段知道怎么划分,可以使用 IP 计算器:

http://tools.jb51.net/aideddesign/ip_net_calc/


更新配置文件:

kubeadm config migrate --old-config kubeadm-config-old.yaml --new-config kubeadm-config-new.yaml

此时配置文件就会生成新版本,将新版本的配置文件传输给其他 Master 节点。

scp kubeadm-config-new.yaml root@192.168.200.102:/ezops/kubeadm/
scp kubeadm-config-new.yaml root@192.168.200.103:/ezops/kubeadm/


在所有 Master 节点通过刚生成的配置文件拉取镜像,这样的好处在于之后集群初始化的时候更快:

kubeadm config images pull --config /ezops/kubeadm/kubeadm-config-new.yaml

该命令会自动从阿里云镜像仓库中下载以下镜像:

  • registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.25.0
  • registry.cn-hangzhou.aliyuncs.com/google_containers/kube-controller-manager:v1.25.0
  • registry.cn-hangzhou.aliyuncs.com/google_containers/kube-scheduler:v1.25.0
  • registry.cn-hangzhou.aliyuncs.com/google_containers/kube-proxy:v1.25.0
  • registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.8
  • registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.5.4-0
  • registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:v1.9.3


master-01 节点执行初始化操作:

kubeadm init --config /ezops/kubeadm/kubeadm-config-new.yaml --upload-certs

初始化完成之后会生成一系列的指令,需要将提示的内容记录下来,后面会用到:

kubernetes安装jenkins kubernetes集群安装_kubernetes

此时会涉及到几个重要的目录:

  • Kubelet 配置文件目录:/var/lib/kubelet
  • Kubernetes 配置文件目录:/etc/kubernetes
  • Kubernetes master 组件配置文件目录:/etc/kubernetes/manifests
  • Kubernetes 证书目录:/etc/kubernetes/pki

如果初始化失败可以执行下面命令进行清理初始化内容:

kubeadm reset -f
ipvsadm --clear
rm -rf ~/.kube


master-01 执行后续配置:

cat >> /etc/profile << EOF
# Kubeadm 配置
export KUBECONFIG=/etc/kubernetes/admin.conf
EOF

source /etc/profile

此时执行 kubectl 命令查看运行情况:

kubectl get node

如图所示:

kubernetes安装jenkins kubernetes集群安装_kubernetes安装jenkins_02

此时显示 NotReady 状态,暂时不用管。

kubectl get pods -n kube-system

如图所示:

kubernetes安装jenkins kubernetes集群安装_k8s_03

所有的系统组件均以容器的方式运行并且在 kube-system 命名空间内。

加入 Master 节点

其他 Master 节点加入集群,只需要将 master-01 初始化的时候生成的加入命令在对应的节点上面执行即可:

kubeadm join 192.168.200.100:16443 --token 7t2weq.bjbawausm0jaxury --discovery-token-ca-cert-hash sha256:5fcdf9802c95be278bd618c5f8e98e6ab31f4e390b4cf1ec0787422087f9a24d --control-plane --certificate-key 3fb7858fa126081e39d456f316d0182b24ed2b488acc7354537aea6077fc97df

注意,拷贝命令的时候需要删除换行符 \,否则会报错:

accepts at most 1 arg(s), received 3
To see the stack trace of this error execute with --v=5 or higher

Master 节点加入集群之后,也会让执行相关的命令:

kubernetes安装jenkins kubernetes集群安装_kubernetes_04

不推荐那种配置方式,建议使用 master-01 那样设置环境变量的方式:

cat >> /etc/profile << EOF
# Kubeadm 配置
export KUBECONFIG=/etc/kubernetes/admin.conf
EOF

# 生效配置文件
source /etc/profile

加入完成后执行命令查看:

# 查看节点信息
kubectl get nodes

# 查看 pod 信息
kubectl get pods -n kube-system -o wide

如图所示:

kubernetes安装jenkins kubernetes集群安装_k8s_05

可以发现每个 Master 节点都运行了之前所说的 Master 节点应该运行的组件。且 kubeadm 安装的 Kubernetes 高可用集群 ETCD 和 CoreDNS 是以插件的形式托管在集群上的。

同时也可以发现 CoreDNS 不属于 READY 状态,这也是正常的,因为缺少网络插件。

加入 Worker 节点

和加入 Master 节点类似,执行初始化时候生成的命令即可:

kubeadm join 192.168.200.100:16443 --token 7t2weq.bjbawausm0jaxury --discovery-token-ca-cert-hash sha256:5fcdf9802c95be278bd618c5f8e98e6ab31f4e390b4cf1ec0787422087f9a24d

Worker 节点加入集群不需要后续操作,可以在任意 Master 上面查看节点情况:

kubectl get nodes
kubectl get pods -A -o wide

如图所示:

kubernetes安装jenkins kubernetes集群安装_容器_06

可以看到在 Worker 节点有运行 kube-proxy(由于电脑配置问题,这里只运行了两个 worker 节点)。

安装 Calico

开始在介绍 kubeadm 的时候说过,kubeadm 需要用户自己安装网络插件,比如 flanal,calico,canal 等。目前业内比较推荐 calico。

Calico 是一个纯三层的数据中心网络方案(不需要 Overlay),并且与 OpenStack、Kubernetes、AWS、GCE 等 IaaS 和容器平台都有良好的集成。

Calico 通过在每一个计算节点利用 Linux Kernel 实现了一个高效的 vRouter 来负责数据转发,每个 vRouter 再通过 BGP 协议负责把自己上运行的 workload 的路由信息向整个 Calico 网络内传播。小规模部署可以直接互联,大规模下可通过指定的 BGP route reflector 来完成。这样的做法保证了最终所有的 workload 之间的数据流量都是通过 IP 路由的方式完成互联的。

Calico 节点组网可以直接利用数据中心的网络结构(无论是 L2 或者 L3),不需要额外的 NAT,隧道或者 Overlay Network。

此外,Calico 基于 iptables 还提供了丰富而灵活的网络 Policy,保证通过各个节点上的 ACLs 来提供 Workload 的多租户隔离、安全组以及其他可达性限制等功能。

https://projectcalico.docs.tigera.io/about/about-calico

本文编写的时候目前 Calico 最新版本为 3.24,通过官方文档可以看到其对 Kubernetes 版本的支持情况,如果版本不对可能会出现问题:

https://projectcalico.docs.tigera.io/getting-started/kubernetes/requirements

官方文档有这样的说明:

由于 Kubernetes API 的变化,Calico v3.24 将无法在 Kubernetes v1.15 或更低版本上运行。v1.16-v1.18 可能有效,但不再经过测试。较新的版本也可以工作,但我们建议升级到针对较新的 Kubernetes 版本进行测试的 Calico 版本。

Calico 的安装只需要在任意 Master 节点执行即可,这里选择在 master-01 上面执行:

cd /ezops/kubeadm/
wget https://projectcalico.docs.tigera.io/archive/v3.24/manifests/calico.yaml
kubectl apply -f calico.yaml

由于网络问题,这个过程会很慢,集群也可能变卡,过程中 Master 节点的组件还可能会被重启,等待安装完成即可。

kubernetes安装jenkins kubernetes集群安装_k8s_07

此时可以发现,集群中的所有组件都处于 Running 状态。

kubernetes安装jenkins kubernetes集群安装_kubernetes_08

各个节点也变成了 Ready 状态。

开启自动生成 Token

从 v1.24.0 开始,ServiceAccount 不再自动生成 Secret。如果你还想要自动生成 Secret,那么可以给 kube-controller-manager 配置特性 LegacyServiceAccountTokenNoAutoGeneration=false。

https://kubernetes.feisky.xyz/concepts/objects/serviceaccount

修改所有主节点的 kube-controller-manager 资源清单:

vim /etc/kubernetes/manifests/kube-controller-manager.yaml

在 command 下面新增配置:--feature-gates=LegacyServiceAccountTokenNoAutoGeneration=false

- command:
    - kube-controller-manager
    - --feature-gates=LegacyServiceAccountTokenNoAutoGeneration=false

修改完成后 K8S 集群会自动滚动更新 kube-controller-manager,不需要重启。

修改 Kube-proxy 模式

通过命令查看 kube-proxy 的模式:

curl 127.0.0.1:10249/proxyMode

可以看到其模式为:iptables,需要将其改为 ipvs。

在 master-01 上面修改:

kubectl edit cm kube-proxy -n kube-system

找到 mode 配置,修改:

mode: ipvs

更新配置:

kubectl patch daemonset kube-proxy -p "{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"date\":\"`date +'%s'`\"}}}}}" -n kube-system

再次使用 curl 命令查看就能发现 mode 已经变成 ipvs 了。到此,Kubeadm 集群安装完成!

集群问题

当然这个集群还是存在很多问题的:

  1. 证书问题,kubeadm 安装的集群,证书有效期默认是一年,一年之后就需要更新证书,如果没更新集群就会出问题。
  2. 节点扩缩容问题。
  3. Token 过期问题等。

以上问题将在后面单独写。