0%

使用kubeadm安装部署K8S集群——CentOS篇

kubeadm简介

《使用kubeadm升级K8S集群》一文中,了解了k8s集群中常见组件,并且使用kubeadm对k8s集群进行了升级。本文中,会学习使用kubeadm安装部署k8s集群。

Kubeadm is a tool built to provide kubeadm init and kubeadm join as best-practice “fast paths” for creating Kubernetes clusters.

更多内容,参考Overview of kubeadmInstalling kubeadm

安装流程

目标:搭建一个k8s集群,包括master和node01两个节点,节点系统为centos7.6.1810。
master节点ip为192.168.56.200,node01节点ip为192.168.56.201。

1、环境准备。

2、在master节点和node01节点安装kubeadm。

3、初始化master节点,创建k8s集群(记得安装网络插件)。

4、node01节点加入到k8s集群。

5、验证安装。

环境准备

1、配置主机名

2、配置IP地址

安装docker

参考Docker入门,安装Docker

允许iptables检查桥接流量

允许 iptables 检查桥接流量,允许流量转发

1
2
3
4
5
6
7
8
9
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF

cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sudo sysctl --system

所有节点都要执行。

安装kubeadm+kubelet+kubectl

参考安装kubeadm

准备kubernetes.repo配置

1
2
3
4
5
6
7
8
9
10
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-$basearch
enabled=1
gpgcheck=1
repo_gpgcheck=0
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF

如果不能连通google,kubernetes.repo中的baseurl就替换成aliyun

1
2
3
4
5
6
7
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
EOF

所有节点都要执行。

SELinux设置为permissive模式

将 SELinux 设置为 permissive 模式(相当于将其禁用)

1
2
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

安装kubeadm+kubelet+kubectl

1、安装默认版本的kubeadm+kubelet+kubectl

1
2
sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
sudo systemctl enable --now kubelet

centos安装这些组件时如果报错:[Errno -1] repomd.xml signature could not be verified for kubernetes
不考虑安全性的话,最简单的解决办法是修改 /etc/yum.repos.d/kubernetes.repo 文件,设置 repo_gpgcheck=0

2、查看kubelet版本
kubelet --version

如果想要安装指定版本的k8s,比如1.22.15,那么需要安装指定版本的kubeadm、kubelet和kubectl。

1
2
3
sudo yum remove -y kubelet kubeadm kubectl
sudo yum list kubeadm kubelet kubectl --showduplicates
sudo yum install -y kubeadm-1.22.15-0 kubelet-1.22.15-0 kubectl-1.22.15-0 --disableexcludes=kubernetes

下文中kubeadm.conf中的版本也需要同步修改
kubernetesVersion: 1.22.15

关闭swap

Swap disabled. You MUST disable swap in order for the kubelet to work properly.

如官方文档所说,kubelet正常工作的前提是关闭swap,否则kubeadm执行初始化时会报错:
“–cgroups-per-qos enabled, but –cgroup-root was not specified. defaulting to /“
“Failed to run kubelet” err=”failed to run Kubelet: running with swap on is not supported, please disable swap!
报错查看方法:

1
2
systemctl status kubelet
journalctl -xeu kubelet

1、临时关闭swap
swapoff -a

2、永久关闭swap
sed -i '/ swap / s/^/#/' /etc/fstab
或者编辑 /etc/fstab,手动注释掉swap配置。

1
#/dev/mapper/centos-swap swap swap defaults 0 0

无论是master节点,还是worker节点,记得都要关闭swap。

配置cgroup驱动

Both the container runtime and the kubelet have a property called “cgroup driver”, which is important for the management of cgroups on Linux machines.

如官方文档所说,cgroup驱动对于在linux中管理cgroups中非常重要。
因此需要正确配置 kubelet 的 cgroup 驱动以匹配 kubeadm 集群中的容器运行时的 cgroup 驱动,详情参考 配置 cgroup 驱动

否则kubeadm执行初始化时会报错:
[kubelet-check] It seems like the kubelet isn’t running or healthy.
The kubelet is not running
The kubelet is unhealthy due to a misconfiguration of the node in some way (required cgroups disabled)
这是因为, docker 和 kubelet 服务中的cgroup不一致,docker默认使用cgroupfs,kubelet默认使用systemd
cgroup驱动查看方法:

1
2
docker system info | grep -i driver
cat /var/lib/kubelet/config.yaml | grep cgroup

方法一:kubelet匹配docker
编辑kubeadm.conf,添加kubelet的cgroup配置,指定驱动为cgroupfs

1
2
3
4
5
---
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
#cgroupDriver: systemd
cgroupDriver: cgroupfs

方法二:docker匹配kubelet
编辑 /etc/docker/daemon.json ,添加:

1
2
3
4
5
{
"exec-opts": [
"native.cgroupdriver=systemd"
]
}

重启docker

1
2
systemctl daemon-reload
systemctl restart docker

这里选择方法二,因为官方更加推荐,可以避免后续kubeadm升级可能引发的cgroup驱动问题。

初始化master节点

参考Installing kubeadm on your hosts

下载镜像文件

kubeadm默认从gcr.io下载k8s组件镜像,国内需要科学上网,或者更改为国内源。本文选择更改为国内源。

1、导出一份默认配置文件
kubeadm config print init-defaults > kubeadm.conf

默认配置内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
apiVersion: kubeadm.k8s.io/v1beta3
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
token: abcdef.0123456789abcdef
ttl: 24h0m0s
usages:
- signing
- authentication
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 1.2.3.4
bindPort: 6443
nodeRegistration:
criSocket: /var/run/dockershim.sock
imagePullPolicy: IfNotPresent
name: node
taints: null
---
apiServer:
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns: {}
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: k8s.gcr.io
kind: ClusterConfiguration
kubernetesVersion: 1.23.0
networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12
scheduler: {}

2、下载地址改为国内镜像源
编辑kubeadm.conf,imageRepository改为国内源

1
imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers

3、指定配置文件,执行下载
kubeadm config images pull --config kubeadm.conf

[config/images] Pulled registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.23.0
[config/images] Pulled registry.cn-hangzhou.aliyuncs.com/google_containers/kube-controller-manager:v1.23.0
[config/images] Pulled registry.cn-hangzhou.aliyuncs.com/google_containers/kube-scheduler:v1.23.0
[config/images] Pulled registry.cn-hangzhou.aliyuncs.com/google_containers/kube-proxy:v1.23.0
[config/images] Pulled registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.6
[config/images] Pulled registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.5.1-0
[config/images] Pulled registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:v1.8.6

k8s集群配置

编辑kubeadm.conf,指定k8s集群配置,详情参考kubeadm 配置 (v1beta2)

advertiseAddress

修改 localAPIEndpoint.advertiseAddress 字段,也就是apiserver对外开放的地址,这里改为master节点地址(因为没有配置高可用)

1
2
3
localAPIEndpoint:
advertiseAddress: 192.168.56.200
bindPort: 6443

如果在执行初始前不指定可用的advertiseAddress,那么kubeadm init初始化时会报错:
Error getting node” err=”node “node” not found

指定节点名称

修改 nodeRegistration.name 字段,这个字段会作为执行初始化的这个master节点的名称。建议改为master节点的主机名,否则默认就会叫node。

1
2
3
4
5
nodeRegistration:
criSocket: /var/run/dockershim.sock
imagePullPolicy: IfNotPresent
name: master
taints: null

如果在执行初始化前没有指定节点名字,想要修改的话,需要修改kubeadm.conf后重新部署k8s集群。

不重新部署k8s集群,是否可以直接编辑修改节点的名称?
kubectl edit nodes/node,修改如下:

1
2
3
4
metadata:
labels:
kubernetes.io/hostname: master
name: master

很遗憾,不可以,会报错:
error: At least one of apiVersion, kind and name was changed

指定pod ip范围

添加 networking.podSubnet 字段,指定pod ip范围(pod-network-cidr)

1
2
3
4
networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12
podSubnet: "10.244.0.0/16"

关于pod ip范围和servcie ip范围的设置,可以参考子网划分详解与子网划分实例精析详解网络分类ABC

如果在执行初始化前没有指定pod ip范围,也是可以正常初始化的,但是后面会导致CNI插件无法正常启动。比如kube-flannel会报错:
Error registering network: failed to acquire lease: node “node” pod cidr not assigned
后期想要修改的话,需要修改kubeadm.conf后重新部署k8s集群。

不重新部署k8s集群,能否补救?这个是可以的
编辑 /etc/kubernetes/manifests/kube-controller-manager.yaml ,添加参数:

1
2
3
- command:
- --allocate-node-cidrs=true
- --cluster-cidr=10.244.0.0/16

然后重启kubelet:
systemctl restart kubelet

执行初始化

1
2
3
#rm -rf /etc/kubernetes/manifests/ 
#kubeadm reset
kubeadm init --config kubeadm.conf

完成后,屏幕输出会提示创建配置文件,以及添加worker node的join命令,记录下来。
例如:

1
2
kubeadm join 192.168.56.200:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:6743eaae41ba8fd99e495e3df94ff9a996878e7c9cf8ac590a3c52b97ea8012e

PS:如果忘记了添加worker node的join命令,可以重新生成。

1
2
kubeadm token create --help
kubeadm token create --print-join-command

生成新的join命令后,之前的join命令同样可以使用。

创建配置文件

1
2
3
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config

验证安装

1
2
3
docker ps -a
kubectl get nodes
kubectl get pods --namespace kube-system

验证发现问题

问题一:coredns处于pending状态
查看coredns报错信息:

1
2
3
4
kubectl get deployment/coredns -n kube-system -o yaml
kubectl get pods -n kube-system
kubectl describe pods coredns-65c54cc984-srzl4 -n kube-system
kubectl logs pods coredns-65c54cc984-srzl4 -n kube-system

Warning FailedScheduling 2m57s (x36 over 38m) default-scheduler 0/1 nodes are available: 1 node(s) had taint {node.kubernetes.io/not-ready: }, that the pod didn’t tolerate.
原来是coredns默认无法部署在master节点,因为没有配置容忍。参考污点和容忍度进行配置即可。
kubectl edit deployment/coredns -n kube-system -o yaml
tolerations部分添加:

1
2
3
tolerations:
- effect: NoSchedule
key: node.kubernetes.io/not-ready

问题二:coredns无法启动
问题一解决后,coredns可以调度了,但是无法启动。
kubectl describe pods/coredns-55b7b56cf8-jv2dc -n kube-system
network is not ready: container runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized

仔细研读使用 kubeadm 创建集群,原来问题一是符合预期的,master节点还没有ready,因为缺少cni插件。

安装CNI插件

参考集群网络系统选择一个cni插件,这里我们选择flannel。

1
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml

node01加入k8s集群

1、使用join命令,添加node01节点到集群

1
2
kubeadm join 192.168.56.200:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:6743eaae41ba8fd99e495e3df94ff9a996878e7c9cf8ac590a3c52b97ea8012e

2、验证结果
在master节点执行:
kubectl get nodes
看到master节点和node01节点都是Ready的状态,说明安装成功。

开发模式

出于安全原因,k8s集群默认不会在控制节点(master节点)上调度Pod。如果我们希望可以在master节点上调度Pod,比如在开发测试时,可以去掉master节点的污点。
kubectl taint nodes --all node-role.kubernetes.io/master-

验证安装

手动验证

1
2
3
4
5
6
7
kubectl get nodes
kubectl get pods --all-namespaces
service kube-apiserver status
service kube-controller-manager status
service kube-scheduler status
service kubelet status
service kube-proxy status
1
2
3
4
5
6
7
kubectl run nginx
kubectl get pods
kubectl scale --replicas=3 deploy/nginx
kubectl get pods
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get service
curl http://node01:31850

test-infra

源码地址:kubernetes/test-infra

1、拉取源码
go get -u k8s.io/test-infra/kubetest

2、执行kubetest

1
2
3
4
5
6
7
kubetest --extract=v1.11.3
cd kubernetes
export KUBE_MASTER_IP="192.168.56.200:6443"
export KUBE_MASTER=kube-master
kubetest --test --provider=skeleton > testout.txt
kubetest --test --provider=skeleton --test_args="ginkgo.focus=Secrets" > testout.txt
cat testout.txt

Smoke Test

按照Smoke Test文档操作一遍。

sonobuoy

官网地址:sonobuoy
源码地址:vmware-tanzu/sonobuoy

节点重启后coredns启动问题

master节点重启后,发现coredns无法正常启动。
Warning Unhealthy 2m1s (x22 over 5m) kubelet Readiness probe failed: HTTP probe failed with statuscode: 503
[ERROR] plugin/errors: HINFO: read udp 10.244.0.7:48010->202.106.195.68:53: i/o timeout
[INFO] plugin/ready: Still waiting on: “kubernetes”

参考How to solve CoreDNS always stuck at “waiting for kubernetes”?,发现需要关闭防火墙,低级错误!

1
2
3
systemctl status firewalld
systemctl stop firewalld
systemctl disable firewalld

集群配置更改

执行kubeadm init初始化后,kubeadm.conf中的内容就写入到了k8s集群了configmap,可以通过kubectl命令查看。
kubectl get cm kubeadm-config -n kube-system -oyaml

如果想要修改配置,可以直接修改kubeadm-config这个configmap,详情参考重新配置 kubeadm 集群