title: kubernetes 1.18.3 集群部署 #标题tags: k8s #标签
date: 2020-06-14
categories: k8s # 分类

某个夜深人静的晚上,躺在床上的我翻来覆去无法入睡,思索再三,一个鲤鱼打挺,爬到了电脑前,写下了这篇文章。

kubernetes 1.18.3 集群部署 - 图1

环境准备

OS IP hostname
Centos 7.5 192.168.20.2 master01
Centos 7.5 192.168.20.3 node01
Centos 7.5 192.168.20.4 node02

注:上述主机名即为集群中的角色,也就是说192.168.20.2为k8s中的master节点,其余为k8s中的node节点。每个主机,最少2G内存,CPU不得低于2核心。

安装前准备

接下来的操作,若无特殊说明,均需在所有节点上执行。

升级内核

此博文是安装的kubernetes 1.18.3版本,需将内核版本升至最新,否则可能会出现kubelet无法启动或pod无法解析域名等问题,请参考博文Centos 7.5内核升级进行升级。

在进行接下来的操作前,请保证你的内核版本在4.4.xxx以上。

  1. $ uname -r
  2. 4.4.227-1.el7.elrepo.x86_64

修改hostname,并配置解析

  1. $ hostnamectl set-hostname your-new-host-name
  2. $ echo "127.0.0.1 $(hostname)" >> /etc/hosts

检查网络

必须保证所有节点上 Kubernetes 所使用的 IP 地址必须可以互通(无需 NAT 映射、无安全组或防火墙隔离)

是否安装k8s集群的硬性要求

必须满足以下几个硬性要求:

  • 内核版本大于4.4.xxx。
  • cpu核心数不低于2,内存不低于2G。
  • hostname不是localhost,且不包含下划线、小数点、大写字母。
  • 任意节点都有固定的内网IP地址。
  • 任意节点上kubelet使用的IP地址在同一局域网内,没有网络策略隔离。
  • 任意节点不会直接使用 docker run 或 docker-compose 运行容器。

安装docker 19.03

  1. # 卸载旧版本docker
  2. $ yum remove -y docker \
  3. docker-client \
  4. docker-client-latest \
  5. docker-ce-cli \
  6. docker-common \
  7. docker-latest \
  8. docker-latest-logrotate \
  9. docker-logrotate \
  10. docker-selinux \
  11. docker-engine-selinux \
  12. docker-engine
  13. # 设置 yum repository
  14. $ yum install -y yum-utils \
  15. device-mapper-persistent-data \
  16. lvm2
  17. yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
  18. # 安装 docker
  19. $ yum install -y docker-ce-19.03.8 docker-ce-cli-19.03.8 containerd.io
  20. # 修改 docker 镜像下载源
  21. $ [ -d /etc/docker ] || mkdir /etc/docker
  22. echo "{\"registry-mirrors\": [\"https://registry.cn-hangzhou.aliyuncs.com\",\"https://4grd6p3s.mirror.aliyuncs.com\"]}" >> /etc/docker/daemon.json
  23. # 修改docker的根目录(默认根目录为:/var/lib/docker),根据需要来确定是否要修改
  24. # 修改根目录,只是在启动命令后增加“--graph=/data/lib/docker”
  25. $ vim /usr/lib/systemd/system/docker.service # 跳转到14行,修改如下
  26. ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --graph=/data/lib/docker
  27. # 启动docker
  28. $ systemctl enable docker && systemctl start docker
  29. # 确认 docker 版本及镜像下载地址
  30. $ docker version
  31. $ docker info | grep -A1 'Registry Mirrors:'
  32. Registry Mirrors:
  33. https://registry.cn-hangzhou.aliyuncs.com/

加载ipvs模块

  1. # 若内核大于4.19替换nf_conntrack_ipv4为nf_conntrack:
  2. $ cat > /etc/sysconfig/modules/ipvs.modules <<EOF
  3. #!/bin/bash
  4. modprobe -- ip_vs
  5. modprobe -- ip_vs_rr
  6. modprobe -- ip_vs_wrr
  7. modprobe -- ip_vs_sh
  8. modprobe -- nf_conntrack
  9. EOF
  10. # 执行脚本
  11. $ chmod 755 /etc/sysconfig/modules/ipvs.modules
  12. /etc/sysconfig/modules/ipvs.modules
  13. lsmod | grep -e ip_vs -e nf_conntrack_ipv4
  14. # 安装相关管理工具
  15. $ yum install ipset ipvsadm -y

调整系统其他配置

  1. # 安装nfs-utils
  2. $ yum install -y nfs-utils wget
  3. # 关闭防火墙
  4. $ systemctl stop firewalld
  5. systemctl disable firewalld
  6. # 关闭SeLinux
  7. $ setenforce 0
  8. sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config
  9. # 禁用swap分区
  10. $ swapoff -a
  11. yes | cp /etc/fstab /etc/fstab_bak
  12. cat /etc/fstab_bak |grep -v swap > /etc/fstab
  13. # 调整内核参数
  14. # 如果有配置,则修改
  15. sed -i "s#^net.ipv4.ip_forward.*#net.ipv4.ip_forward=1#g" /etc/sysctl.conf
  16. sed -i "s#^net.bridge.bridge-nf-call-ip6tables.*#net.bridge.bridge-nf-call-ip6tables=1#g" /etc/sysctl.conf
  17. sed -i "s#^net.bridge.bridge-nf-call-iptables.*#net.bridge.bridge-nf-call-iptables=1#g" /etc/sysctl.conf
  18. sed -i "s#^net.ipv6.conf.all.disable_ipv6.*#net.ipv6.conf.all.disable_ipv6=1#g" /etc/sysctl.conf
  19. sed -i "s#^net.ipv6.conf.default.disable_ipv6.*#net.ipv6.conf.default.disable_ipv6=1#g" /etc/sysctl.conf
  20. sed -i "s#^net.ipv6.conf.lo.disable_ipv6.*#net.ipv6.conf.lo.disable_ipv6=1#g" /etc/sysctl.conf
  21. sed -i "s#^net.ipv6.conf.all.forwarding.*#net.ipv6.conf.all.forwarding=1#g" /etc/sysctl.conf
  22. # 如果没有,则追加
  23. cat >> /etc/sysctl.conf << EOF
  24. net.ipv4.ip_forward = 1
  25. net.bridge.bridge-nf-call-ip6tables = 1
  26. net.bridge.bridge-nf-call-iptables = 1
  27. net.ipv6.conf.all.disable_ipv6 = 1
  28. net.ipv6.conf.default.disable_ipv6 = 1
  29. net.ipv6.conf.lo.disable_ipv6 = 1
  30. net.ipv6.conf.all.forwarding = 1
  31. EOF
  32. # 执行命令以应用
  33. $ sysctl -p

部署k8s

配置k8s的yum源

  1. $ cat <<EOF > /etc/yum.repos.d/kubernetes.repo
  2. [kubernetes]
  3. name=Kubernetes
  4. baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
  5. enabled=1
  6. gpgcheck=0
  7. repo_gpgcheck=0
  8. gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
  9. http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
  10. EOF

卸载旧版本

  1. $ yum remove -y kubelet kubeadm kubectl

安装kubelet、kubeadm、kubectl

  1. $ yum install -y kubelet-1.18.3 kubectl-1.18.3 kubeadm-1.18.3

yum安装的kubeadm,初始化集群后,有个比较烦人的事情,就是多数证书的有效期为1年,最多的证书有效期是十年,一年之后,就需要更新集群证书或者升级集群,所以还需要编译一下kubedam,以便可以更改证书有效期(上述之所以还用yum装kubeadm,是因为我们需要其安装的依赖,而不是kubeadn指令)。

修改kubeadm源码并编译

修改kubeadm源码及编译等操作,只需在任意一台机器上执行即可,等编译完成后,再将编译的kubeadm指令发送至其他节点即可。

  1. $ wget https://github.com/kubernetes/kubernetes/archive/v1.18.3.tar.gz
  2. $ tar zxf v1.18.3.tar.gz && cd kubernetes-1.18.3/

修改CA证书时间

  1. $ vim staging/src/k8s.io/client-go/util/cert/cert.go
  2. # 跳转至66行,将10修改为100(是将十年的ca证书修改为100年)
  3. 65 NotBefore: now.UTC(),
  4. 66 NotAfter: now.Add(duration365d * 100).UTC(),

具体位置如下:

kubernetes 1.18.3 集群部署 - 图2

修改其他证书有效期

  1. $ vim cmd/kubeadm/app/constants/constants.go
  2. # 跳转至49行,修改如下(追加 * 100):
  3. CertificateValidity = time.Hour * 24 * 365 * 100

具体位置如下:

kubernetes 1.18.3 集群部署 - 图3

编译kubeadm

可以采用容器运行一个go环境,如果你的宿主机有go环境,则用宿主机进行编译即可。

  1. wget https://dl.google.com/go/go1.13.9.linux-amd64.tar.gz
  2. tar zxf go1.13.9.linux-amd64.tar.gz -C /opt/
  3. cat >> /etc/profile << EOF
  4. export GOROOT=/opt/go
  5. export PATH=\$PATH:\$GOROOT/bin
  6. EOF
  7. source /etc/profile
  8. go version
  9. make all WHAT=cmd/kubeadm GOFLAGS=-v

执行上述命令后,等待1~2分钟,输入如下:

kubernetes 1.18.3 集群部署 - 图4

将编译生成的指令copy到指定目录
  1. # copy到本机
  2. mv /usr/bin/kubeadm{,.old}
  3. cp _output/local/bin/linux/amd64/kubeadm /usr/bin/
  4. # 分发到其他节点
  5. for i in 3 4;do rsync -az /usr/bin/kubeadm 192.168.20.${i}:/usr/bin/;done

好,接下来继续在所有节点上执行。

修改docker Cgroup Driver为systemd

如果不修改,在添加 worker 节点时可能会碰到如下错误

  1. [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd".
  2. Please follow the guide at https://kubernetes.io/docs/setup/cri/

修改指令如下:

  1. $ sed -i "s#^ExecStart=/usr/bin/dockerd.*#ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --exec-opt native.cgroupdriver=systemd --graph=/data/lib/docker#g" /usr/lib/systemd/system/docker.service

确认docker的cgroup driver

  1. systemctl daemon-reload
  2. systemctl restart docker
  3. docker info | grep -i cgroup # 确认每个docker节点的cgroup driver为systemd
  4. Cgroup Driver: systemd

启动kubelet

  1. systemctl daemon-reload
  2. systemctl enable kubelet
  3. systemctl start kubelet

注:如果此时执行systemctl status kubelet命令,会得到 kubelet 启动失败的错误提示,请忽略此错误,因为必须完成后续步骤中 kubeadm init 的操作,kubelet 才能正常启动。

错误如下:

kubernetes 1.18.3 集群部署 - 图5

初始化master节点

注:接下来的操作,只需要在master节点上进行配置。

配置环境变量

注:export 命令只在当前 shell 会话中有效,开启新的 shell 窗口后,如果要继续安装过程,请重新执行此处的 export 命令。

  1. # 将192.168.20.2替换为你自己master节点的IP
  2. $ export MASTER_IP=192.168.20.2
  3. # 替换 apiserver.demo 为你想要的 dnsName
  4. $ export APISERVER_NAME=apiserver.demo
  5. # Kubernetes 容器组所在的网段,该网段安装完成后,由 kubernetes 创建,事先并不存在于我们的物理网络中
  6. $ export POD_SUBNET=10.100.0.1/16
  7. # 配置解析
  8. $ echo "${MASTER_IP} ${APISERVER_NAME}" >> /etc/hosts

执行初始化master
  1. # 由于后续可能会下载多个文件,所以创建新目录,以方便观察用到了哪些文件
  2. $ mkdir k8s_deploy && cd k8s_deploy
  3. # 准备kubeadm所需yaml文件
  4. cat <<EOF > ./kubeadm-config.yaml
  5. apiVersion: kubeadm.k8s.io/v1beta2
  6. kind: ClusterConfiguration
  7. kubernetesVersion: v1.18.3
  8. imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers
  9. controlPlaneEndpoint: "${APISERVER_NAME}:6443"
  10. networking:
  11. serviceSubnet: "10.96.0.0/16"
  12. podSubnet: "${POD_SUBNET}"
  13. dnsDomain: "cluster.local"
  14. EOF
  15. # kubeadm 初始化
  16. $ kubeadm init --config=kubeadm-config.yaml --upload-certs

配置kubectl
  1. rm -rf /root/.kube/
  2. mkdir /root/.kube/
  3. cp -i /etc/kubernetes/admin.conf /root/.kube/config

安装calico网络插件

和calico网络插件功能一样的还有一个叫做flannel网络插件,如果有兴趣,可以自行去github上查看。

好了,废话不多说,开始安装 calico 网络插件,参考:官方文档

注:你的k8s集群节点数量是大于50个还是小于50个,所需进行的配置是不一样的,建议去官方文档看一眼。

我这里3个节点,肯定是按照小于50的配置来的咯。

补充:在我按照此文档部署集群后的某一天,我的集群重启了一次,然后calicao组件就出现了问题,故写在这里,建议在部署calica组件时,就将这个坑填上。

具体故障问题: k8s/calico组件故障排查

  1. # 下面下载的是kuboard官方提供的yml文件,如果失效了,请替换为官方的地址:https://docs.projectcalico.org/manifests/calico.yaml
  2. $ wget https://kuboard.cn/install-script/calico/calico-3.13.1.yaml
  3. $ kubectl apply -f calico-3.13.1.yaml
  4. # 执行yaml文件后,请执行下面的操作,等待3-10分钟,直到所有的容器组处于 Running 状态
  5. $ watch kubectl get pod -n kube-system -o wide
  6. # 注:若网速不好,可能会导致镜像下载错误,这就不展开怎么解决了
  7. # 提示:可以手动将yaml文件中指定的镜像下载下来,然后修改镜像下载策略为imagePullPolicy: IfNotPresent
  8. # 然后执行指令 kubectl delete -f calico-3.13.1.yaml && kubectl apply -f calico-3.13.1.yaml 后继续观察。

必须保证所有容器处于running状态,如下:

kubernetes 1.18.3 集群部署 - 图6

如果初始化失败,请检查以下节点:

  • 环境变量 MASTER_IP 的值应该为 master 节点的 内网IP,如果不是,请重新 export
  • APISERVER_NAME 不能是 master 的 hostname
  • APISERVER_NAME 必须全为小写字母、数字、小数点,不能包含减号
  • POD_SUBNET 所使用的网段不能与 master节点/worker节点 所在的网段重叠。该字段的取值为一个 CIDR 值,如果对 CIDR 这个概念还不熟悉,请仍然执行 export POD_SUBNET=10.100.0.1/16 命令,不做修改
  • 然后重新初始化master节点,重新初始化前,请先执行 kubeadm reset -f 操作。

初始化worker节点

获取join命令参数
  1. # 在 master 节点上执行
  2. $ kubeadm token create --print-join-command
  3. # 输出如下:
  4. W0614 03:26:48.357692 27702 configset.go:202] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]
  5. # 我们需要的就是下面kubeadm join指令,每个集群初始化出来的指令都不一样,请复制自己master输出的指令
  6. kubeadm join apiserver.demo:6443 --token nihz20.sueqfz69toge9d15 --discovery-token-ca-cert-hash sha256:9960790c2fd65dfdc8dc8cd5bdcf89b5093539d8a108422ea9a93b7e28731c41
  7. # 该 token 的有效时间为 2 个小时,2小时内,您可以使用此 token 初始化任意数量的 worker 节点。

初始化worker节点

所有worker节点都执行下述指令,以便加入k8s集群。

  1. # 只在 worker 节点执行
  2. # 替换 192.168.20.2 为 master 节点的内网 IP
  3. $ export MASTER_IP=192.168.20.2
  4. # 替换 apiserver.demo 为初始化 master 节点时所使用的 APISERVER_NAME
  5. $ export APISERVER_NAME=apiserver.demo
  6. # 配置解析
  7. $ echo "${MASTER_IP} ${APISERVER_NAME}" >> /etc/hosts
  8. # 替换为 master 节点上 kubeadm token create 命令的输出
  9. $ kubeadm join apiserver.demo:6443 --token nihz20.sueqfz69toge9d15 --discovery-token-ca-cert-hash sha256:9960790c2fd65dfdc8dc8cd5bdcf89b5093539d8a108422ea9a93b7e28731c41

最终,在master上查看所有pod状态,全为running即可,如下:

kubernetes 1.18.3 集群部署 - 图7

查看node状态全为Ready:

  1. $ kubectl get nodes
  2. NAME STATUS ROLES AGE VERSION
  3. master Ready master 36m v1.18.3
  4. node01 Ready <none> 9m58s v1.18.3
  5. node02 Ready <none> 8m15s v1.18.3

确认集群证书有效期

查看集群证书有效期是否为100年

  1. $ kubeadm alpha certs check-expiration

输出如下:

kubernetes 1.18.3 集群部署 - 图8

worker节点不能join成功

如果遇到worker节点不能成功的join到k8s集群,那么请按照以下思路来解决问题。

在worker节点执行以下语句可验证worker节点是否能访问 apiserver

  1. $ curl -ik https://apiserver.demo:6443

如果不能,请在 master 节点上验证

  1. $ curl -ik https://apiserver.demo:6443

正常输出结果如下:

  1. HTTP/1.1 403 Forbidden
  2. Cache-Control: no-cache, private
  3. Content-Type: application/json
  4. X-Content-Type-Options: nosniff
  5. Date: Sat, 13 Jun 2020 19:44:58 GMT
  6. Content-Length: 233
  7. {
  8. "kind": "Status",
  9. "apiVersion": "v1",
  10. "metadata": {
  11. },
  12. "status": "Failure",
  13. "message": "forbidden: User \"system:anonymous\" cannot get path \"/\"",
  14. "reason": "Forbidden",
  15. "details": {
  16. },
  17. "code": 403

可能原因

  • 如果 master 节点能够访问 apiserver、而 worker 节点不能,则请检查自己的网络设置

    • /etc/hosts 是否正确设置?
    • 是否有安全组或防火墙的限制?
  • worker 节点默认网卡

    • Kubelet使用的 IP 地址 与 master 节点可互通(无需 NAT 映射),且没有防火墙、安全组隔离,如果你使用 vmware 或 virtualbox 创建虚拟机用于 K8S 学习,可以尝试 NAT 模式的网络,而不是桥接模式的网络。

移除worker节点并重试

注:正常情况下,无需移除 worker 节点,如果添加到集群出错,可以移除 worker 节点,再重新尝试添加。

在准备移除的 worker 节点上执行

  1. # 只在 worker 节点执行
  2. $ kubeadm reset -f

在 master 节点上执行

  1. # 只在 master 节点执行,获取worker列表
  2. kubectl get nodes -o wide
  3. # 只在 master 节点执行,将demo-worker-x-x替换为你要移除的节点
  4. kubectl delete node demo-worker-x-x

部署k8s管理工具——kuboard

兼容性如下:

Kubernetes 版本 Kuboard 版本 兼容性 说明
v1.18 v1.0.x,v2.0.x 😄 已验证
v1.17 v1.0.x,v2.0.x 😄 已验证
v1.16 v1.0.x,v2.0.x 😄 已验证
v1.15 v1.0.x,v2.0.x 😄 已验证
v1.14 v1.0.x,v2.0.x 😄 已验证
v1.13 v1.0.x,v2.0.x 😄 已验证
v1.12 v1.0.x,v2.0.x 😐 Kuboard 不支持 Kubernetes v1.12
v1.11 v1.0.x,v2.0.x 😐 Kuboard 不支持 Kubernetes v1.11

安装kuboard

  1. # 安装
  2. $ kubectl apply -f https://kuboard.cn/install-script/kuboard.yaml
  3. $ kubectl apply -f https://addons.kuboard.cn/metrics-server/0.3.6/metrics-server.yaml
  4. # 查看kuboard运行状态,直到状态为running
  5. $ watch kubectl get pods -l k8s.kuboard.cn/name=kuboard -n kube-system
  6. NAME READY STATUS RESTARTS AGE
  7. kuboard-7bb89b4cc4-99l9n 1/1 Running 0 2m22s

获取Token

Token有两种类型,分别是管理员用户、只读用户的Token,这里将分别写下两种token的查看方式。

获取管理员用户的Token

此Token拥有 ClusterAdmin 的权限,可以执行所有操作。

  1. # 执行命令如下
  2. $ echo $(kubectl -n kube-system get secret $(kubectl -n kube-system get secret | grep kuboard-user | awk '{print $1}') -o go-template='{{.data.token}}' | base64 -d)
  3. # 输出如下(复制输出内容)
  4. eyJhbGciOiJSUzI1NiIsImtpZCI6IllWaUVoOXZtUUNlS25JaVpPZVhReGhnNzZjcExzSFVfZy1ycGJiZkp0ZEUifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJrdWJvYXJkLXVzZXItdG9rZW4tajRidHgiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoia3Vib2FyZC11c2VyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiNjMxNDM3ODQtMWM4My00NzRiLWExMGUtMDE0ZjY4MDA1NGUyIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmt1Ym9hcmQtdXNlciJ9.i6z0pUpyYdBlfwkMEH4FTjsz550J3fGn_e9uNrke_TpLasvvQlqfwQ8_kUOrjXyztW42ANcTZTVZ2z8lE7tsf53FpKwDnhZ3Swt0pcC018Cm-4q0YhkHqJlh6l4c6DiPqqPetYfvOOfXee-f9EbuQVCMVLqDfqZKwDM8Qa3gt81tk4oFwlDfahNdUmL0UQXXm_2LXQHqcXJ5slc7V1NDngou8aSxA1GgfFsQB8SxIjYlatD5mG_ZyIpX9gPZxiDWgOJDCogwIhrJGa2vDPnhZSayqJwZrIvsS2WLejeh5w7D0p6ZdNg53R_pPjOt5NLgeJZQCF3pvvo-touWNbnTPA

获取只读用户的Token

只读用户拥有的权限如下:

  • view 可查看名称空间的内容
  • system:node 可查看节点信息
  • system:persistent-volume-provisioner 可查看存储类和存储卷声明的信息

适用场景:

只读用户不能对集群的配置执行修改操作,非常适用于将开发环境中的 Kuboard 只读权限分发给开发者,以便开发者可以便捷地诊断问题。

  1. # 执行命令如下
  2. $ echo $(kubectl -n kube-system get secret $(kubectl -n kube-system get secret | grep kuboard-viewer | awk '{print $1}') -o go-template='{{.data.token}}' | base64 -d)
  3. # 复制输出的Token信息
  4. eyJhbGciOiJSUzI1NiIsImtpZCI6IllWaUVoOXZtUUNlS25JaVpPZVhReGhnNzZjcExzSFVfZy1ycGJiZkp0ZEUifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJrdWJvYXJkLXZpZXdlci10b2tlbi1tNzRkbCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJrdWJvYXJkLXZpZXdlciIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjNjMTI0NmExLTgzZTktNGZlZC1hNGQ2LTRkMjYzNzQ1YjBjZiIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlLXN5c3RlbTprdWJvYXJkLXZpZXdlciJ9.jpuVX2aYmpycjcXxTnMCnJre_F10OHiMZPgcOxnPJ3B_5ZeDHzj__06MCn2IF0x8yZZmJIqqr57HIWU5eGKk1jqxuC1OHCQGcG4RGL0e0hCcW-MW2nRT6YMWTiqGMGQ9Ooydt3pLaTEdJAg0ZnMXY5eoBIk9TX_UzoQASH0kkBnjqFDwaJ8-O6bybVB1cNQIlUug2mSgY2sWn-JvyA9doeq7qjS5mXrO_rGbGwUR2HL_KWNeFd9Ha_GWpnSHMdARMTCgDHiV_sznRFG72puWgg-J_2oSEC8pM8-VpBRSxzHbgEI5-ANP2fwjpcJDT8SdBHC5XntGT3ctA66de2T8vQ

访问Kuboard

Kuboard Service 使用了 NodePort 的方式暴露服务,NodePort 为 32567;可以按如下方式访问 Kuboard:

http://任意一个Worker节点的IP地址:32567/

访问登录页面:

kubernetes 1.18.3 集群部署 - 图9

登录后的首页如下:

kubernetes 1.18.3 集群部署 - 图10

不要以为就这些东西,很多地方都是可以点击进去的,如下:

kubernetes 1.18.3 集群部署 - 图11

kubernetes 1.18.3 集群部署 - 图12

加入节点至k8s集群中

上面部署的是一个master、两个node的k8s集群,那么后续根据业务需求,需要新增node节点或者说要把master做成高可用,那应该怎么弄呢?这里就来写一下,参考:

加入master节点

如果对master节点做高可用,那么至少要三个master节点,所以这里还需要新增两个master节点,并且呢,针对着三个master节点,还要做个VIP,以便将apiserver的解析记录指定为这个VIP。

实现VIP的方式有很多种:
1、自己写网卡配置文件,增加IPADDR1 选项,配置VIP,当节点宕掉后,可以将VIP配置到其他master节点,这样需要人工参与切换VIP,但不会新增其他服务,当然,这样的话,对于apiserever的请求只会落在那个VIP所在的节点,其他两个master处于空闲状态,这个没关系的,master的资源消耗本就不大。
2、使用keepalived,将三个master配置为一个虚拟组,由keepalived来控制vip绑定在哪个节点,以及VIP的自动切换,推荐此方式。
3、使用keepalived+nginx,需要新增两个nginx,轮询后端三个master节点,然后针对这两个nginx,通过keepalived来做到高可用,其中,nginx也可以换成其他负载方式,如:haporxy、lvs,不推荐此方式,需要依赖较多的组件,并且增加一层代理,转发效率将会受到影响。

我这里将采用第二种方式,将三个master节点通过keepalived,加入到一个备份组,VIP可以落在任意一个master节点上。

配置VIP

假设我这里新增两个节点:192.168.20.5、192.168.20.6 以master的角色加入到集群,并且主机名分别为 master02、master03,那么就需要将master01/2/3 作为一个热备组,以便VIP可以绑定在这三个master节点的任意一个。VIP地址为: 192.168.20.20。

安装keepalived

三个master节点都安装keepalived

  1. $ yum -y install keepalived

配置VIP到master01节点

由于现在master01已经是集群中的master角色,所以需要将VIP先绑定在master01上,才可以正确的进行后面的工作(其余两个节点由于还未加入集群,故先不配置keepalived)。

master01节点配置如下

关于keepalived的各项配置,可以参考博文:Keepalived配置详解

  1. # 修改keepalived配置文件
  2. $ cat > /etc/keepalived/keepalived.conf << EOF
  3. global_defs {
  4. script_user root
  5. router_id MASTER-01
  6. }
  7. vrrp_script chk_apiserver {
  8. script "/etc/keepalived/chk_apiserver.sh"
  9. interval 2
  10. }
  11. vrrp_instance VI_1 {
  12. state BACKUP
  13. interface ens33
  14. virtual_router_id 23
  15. priority 100
  16. nopreempt
  17. advert_int 1
  18. authentication {
  19. auth_type PASS
  20. auth_pass 1234
  21. }
  22. virtual_ipaddress {
  23. 192.168.20.20/24
  24. }
  25. track_script {
  26. chk_apiserver
  27. }
  28. }
  29. EOF
  30. # 定义apiserver健康检查脚本
  31. $ cat > /etc/keepalived/chk_apiserver.sh << 'EEE'
  32. keepalived_log=/etc/keepalived/vip.log
  33. apiserver_port=$(ss -lnpt | grep 6443 | wc -l) # 确保此处过滤出来的是你的进程
  34. if [[ ${apiserver_port} -eq 0 ]];then
  35. cat >> ${keepalived_log} << EOF
  36. apiserver stopped running at $(date '+%F %T')
  37. Stopping keepalived ...
  38. EOF
  39. systemctl stop keepalived
  40. fi
  41. EEE
  42. # 赋予脚本执行权限
  43. $ chmod +x /etc/keepalived/chk_apiserver.sh

启动keepalived

  1. $ systemctl start keepalived # 启动keepalived
  2. $ ip a # 确保VIP已经配置上

修改apiserver的解析IP

当VIP成功配置到master01后,就可以修改k8s集群中所有节点的apiserver.demo 域名解析到这个VIP了。自行操作即可。

  1. $ vim /etc/hosts
  2. 192.168.20.20 apiserver.demo

初始化第二、三个master节点

获得 master 节点的 join 命令

可以和第一个Master节点一起初始化第二、三个Master节点,也可以从单Master节点调整过来,只需要

  • 增加Master的 LoadBalancer(已通过VIP解决)
  • 将所有节点的 /etc/hosts 文件中 apiserver.demo 解析为 LoadBalancer 的地址(已修改为VIP的地址)
  • 添加第二、三个Master节点
  • 初始化 master 节点的 token 有效时间为 2 小时

和第一个master节点一起初始化

如果是在第一个master节点初始化后的两小时内,又要初始化第二个第三个节点,那么只需在新节点上进行如下操作即可:

按照此博文开头,进行安装docker、调整配置等操作,具体要做的如下:

  • 升级内核
  • 修改hostname,并配置解析
  • 检查网络
  • 是否安装k8s集群的硬性要求
  • 安装docker 19.03
  • 调整系统其他配置
  • 配置k8s的yum源
  • 卸载旧版本
  • 安装kubelet、kubeadm、kubectl
  • 修改docker Cgroup Driver为systemd
  • 确认docker的cgroup driver
  • 启动kubelet
  • 将master01编译后的kubeadm命令分发至master02和master03
  • 为了避免镜像下载时间过长,可以将calico相关的三个镜像,先从别的节点导入到要加入集群的节点。

当上面的工作都完成后,那么只需要进行如下操作了:

  1. # 只在第二、三个 master 节点 master01 和 master02 执行
  2. # 替换 x.x.x.x 为 VIP地址
  3. export APISERVER_IP=x.x.x.x
  4. # 替换 apiserver.demo 为 前面已经使用的 dnsName
  5. export APISERVER_NAME=apiserver.demo
  6. echo "${APISERVER_IP} ${APISERVER_NAME}" >> /etc/hosts
  7. # 使用初始化第一个master节点时获得的第二、三个 master 节点的 join 命令
  8. kubeadm join apiserver.demo:6443 --token ejwx62.vqwog6il5p83uk7y \
  9. --discovery-token-ca-cert-hash sha256:6f7a8e40a810323672de5eee6f4d19aa2dbdb38411845a1bf5dd63485c43d303 \
  10. --control-plane --certificate-key 70eb87e62f052d2d5de759969d5b42f372d0ad798f98df38f7fe73efdf63a13c
  11. # 只需要将上面的kubeadm命令替换为你初始化第一个master节点时输出的指令即可。

第一个master节点初始化2小时后再初始化

上面是初始化第一个master节点的两小时内,加入master的方案,那么如果在master01初始化已经过了很久了,此时需要新加入master节点,应该怎么做呢?

下面是具体配置过程。

按照此博文开头,进行安装docker、调整配置等操作,具体要做的如下:

  • 升级内核
  • 修改hostname,并配置解析
  • 检查网络
  • 是否安装k8s集群的硬性要求
  • 安装docker 19.03
  • 调整系统其他配置
  • 配置k8s的yum源
  • 卸载旧版本
  • 安装kubelet、kubeadm、kubectl
  • 修改docker Cgroup Driver为systemd
  • 确认docker的cgroup driver
  • 启动kubelet
  • 将master01编译后的kubeadm命令分发至master02和master03
  • 为了避免镜像下载时间过长,可以将calico相关的三个镜像,先从别的节点导入到要加入集群的节点。

当上述准备工作都完成后,即可进行如下操作:

  1. # master01 上执行,获取certificate key
  2. $ kubeadm init phase upload-certs --upload-certs # 只在 第一个 master 节点 master01 执行
  3. I0124 18:35:17.502961 82541 version.go:252] remote version is much newer: v1.20.2; falling back to: stable-1.18
  4. W0124 18:35:25.635218 82541 configset.go:202] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]
  5. [upload-certs] Storing the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace
  6. [upload-certs] Using certificate key: # 我们需要的就是下面的key
  7. 12fcb810e71cbd1a732aae6db92cb4a192634d9c2cf9591503bdcc9f84e34e51
  8. # 获取join命令
  9. $ kubeadm token create --print-join-command # 只在 第一个 master 节点 master01 执行
  10. W0124 18:36:48.528349 84266 configset.go:202] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]
  11. kubeadm join apiserver.demo:6443 --token 1gpxxr.ja1evfq98u2sra8n --discovery-token-ca-cert-hash sha256:44d8e65585d22541d833801dc4be2b66d28e7836ddcc3a2cc1992afe355d7f46

则,第二、三个 master 节点的 join 命令如下(先将命令拼凑好,还不可以执行哦):

  • 如下命令中,--control-plane --certificate-key为手动新增配置,--control-plane --certificate-key 前面来自于上面获得的join命令,--control-plane --certificate-key之后的来自于上面获得的 certificate key。
  1. $ kubeadm join apiserver.demo:6443 --token 1gpxxr.ja1evfq98u2sra8n \
  2. --discovery-token-ca-cert-hash sha256:44d8e65585d22541d833801dc4be2b66d28e7836ddcc3a2cc1992afe355d7f46 \
  3. --control-plane --certificate-key 12fcb810e71cbd1a732aae6db92cb4a192634d9c2cf9591503bdcc9f84e34e51

初始化第二、三个 master 节点

  1. # 只在master02和master03 这两个未加入集群的master节点上执行
  2. $ export APISERVER_IP=192.168.20.20 # 此IP为VIP地址
  3. $ export APISERVER_NAME=apiserver.demo # 替换 apiserver.demo 为 前面已经使用的 dnsName
  4. $ echo "${APISERVER_IP} ${APISERVER_NAME}" >> /etc/hosts
  5. # 执行前面拼凑好的join命令
  6. $ kubeadm join apiserver.demo:6443 --token 1gpxxr.ja1evfq98u2sra8n \
  7. --discovery-token-ca-cert-hash sha256:44d8e65585d22541d833801dc4be2b66d28e7836ddcc3a2cc1992afe355d7f46 \
  8. --control-plane --certificate-key 12fcb810e71cbd1a732aae6db92cb4a192634d9c2cf9591503bdcc9f84e34e51
  9. # 当join成功后,执行如下命令,以便master02/03可以操作集群
  10. mkdir -p $HOME/.kube
  11. sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  12. sudo chown $(id -u):$(id -g) $HOME/.kube/config

配置master02的keepalived
  1. cat > /etc/keepalived/keepalived.conf << EOF
  2. global_defs {
  3. script_user root
  4. router_id MASTER-02
  5. }
  6. vrrp_script chk_apiserver {
  7. script "/etc/keepalived/chk_apiserver.sh"
  8. interval 2
  9. }
  10. vrrp_instance VI_1 {
  11. state BACKUP
  12. interface ens33
  13. virtual_router_id 23
  14. priority 100
  15. nopreempt
  16. advert_int 1
  17. authentication {
  18. auth_type PASS
  19. auth_pass 1234
  20. }
  21. virtual_ipaddress {
  22. 192.168.20.20/24
  23. }
  24. track_script {
  25. chk_apiserver
  26. }
  27. }
  28. EOF
  29. # 定义apiserver健康检查脚本
  30. $ cat > /etc/keepalived/chk_apiserver.sh << 'EEE'
  31. keepalived_log=/etc/keepalived/vip.log
  32. apiserver_port=$(ss -lnpt | grep 6443 | wc -l) # 确保此处过滤出来的是你的进程
  33. if [[ ${apiserver_port} -eq 0 ]];then
  34. cat >> ${keepalived_log} << EOF
  35. apiserver stopped running at $(date '+%F %T')
  36. Stopping keepalived ...
  37. EOF
  38. systemctl stop keepalived
  39. fi
  40. EEE
  41. # 赋予脚本执行权限
  42. $ chmod +x /etc/keepalived/chk_apiserver.sh
  43. # 启动keepalived
  44. $ systemctl restart keepalived

配置master03的keepalived
  1. cat > /etc/keepalived/keepalived.conf << EOF
  2. global_defs {
  3. script_user root
  4. router_id MASTER-03
  5. }
  6. vrrp_script chk_apiserver {
  7. script "/etc/keepalived/chk_apiserver.sh"
  8. interval 2
  9. }
  10. vrrp_instance VI_1 {
  11. state BACKUP
  12. interface ens33
  13. virtual_router_id 23
  14. priority 100
  15. nopreempt
  16. advert_int 1
  17. authentication {
  18. auth_type PASS
  19. auth_pass 1234
  20. }
  21. virtual_ipaddress {
  22. 192.168.20.20/24
  23. }
  24. track_script {
  25. chk_apiserver
  26. }
  27. }
  28. EOF
  29. # 定义apiserver健康检查脚本
  30. $ cat > /etc/keepalived/chk_apiserver.sh << 'EEE'
  31. keepalived_log=/etc/keepalived/vip.log
  32. apiserver_port=$(ss -lnpt | grep 6443 | wc -l) # 确保此处过滤出来的是你的进程
  33. if [[ ${apiserver_port} -eq 0 ]];then
  34. cat >> ${keepalived_log} << EOF
  35. apiserver stopped running at $(date '+%F %T')
  36. Stopping keepalived ...
  37. EOF
  38. systemctl stop keepalived
  39. fi
  40. EEE
  41. # 赋予脚本执行权限
  42. $ chmod +x /etc/keepalived/chk_apiserver.sh
  43. # 启动keepalived
  44. $ systemctl restart keepalived

加入worker节点

  1. # 在任意master节点执行,以便获取work加入集群的指令
  2. $ kubeadm token create --print-join-command # 我们需要的就是下面的指令
  3. kubeadm join apiserver.demo:6443 --token uxz2wd.95nz40pjfugdaoa2 --discovery-token-ca-cert-hash sha256:44d8e65585d22541d833801dc4be2b66d28e7836ddcc3a2cc1992afe355d7f46

按照此博文开头,针对要加入集群的worker节点进行安装docker、调整配置等操作,具体要做的如下:

  • 升级内核
  • 修改hostname,并配置解析
  • 检查网络
  • 是否安装k8s集群的硬性要求
  • 安装docker 19.03
  • 调整系统其他配置
  • 配置k8s的yum源
  • 卸载旧版本
  • 安装kubelet、kubeadm、kubectl
  • 修改docker Cgroup Driver为systemd
  • 确认docker的cgroup driver
  • 启动kubelet
  • 将master01编译后的kubeadm命令分发至master02和master03
  • 为了避免镜像下载时间过长,可以将calico相关的三个镜像,先从别的节点导入到要加入集群的节点。

初始化woker节点

以下操作在要加入集群的worker节点执行即可。

  1. $ export APISERVER_IP=192.168.20.20 # 此IP为VIP地址
  2. $ export APISERVER_NAME=apiserver.demo # 替换 apiserver.demo 为 前面已经使用的 dnsName
  3. $ echo "${APISERVER_IP} ${APISERVER_NAME}" >> /etc/hosts
  4. # 加入集群
  5. $ kubeadm join apiserver.demo:6443 --token uxz2wd.95nz40pjfugdaoa2 --discovery-token-ca-cert-hash sha256:44d8e65585d22541d833801dc4be2b66d28e7836ddcc3a2cc1992afe355d7f46

验证集群

查看node节点运行情况

  1. $ kubectl get nodes -o wide

返回如下:

kubernetes 1.18.3 集群部署 - 图13

查看pod运行情况

  1. $ kubectl get pod -n kube-system -o wide

返回如下:

kubernetes 1.18.3 集群部署 - 图14

验证etcd集群

  1. $ kubectl -n kube-system exec etcd-master02 -- etcdctl --endpoints=https://192.168.20.2:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key member list -wtable

返回如下:

kubernetes 1.18.3 集群部署 - 图15

  1. $ kubectl -n kube-system exec etcd-master02 -- etcdctl --endpoints=https://192.168.20.2:2379,https://192.168.20.5:2379,https://192.168.20.6:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key endpoint status

返回如下:

kubernetes 1.18.3 集群部署 - 图16

验证集群转发模式

查看kube-proxy日志,输出信息包含Using ipvs Proxier,则表示使用的是ipvs转发模式,效率最好。输出信息包含Using iptables Proxier.则表示使用的iptables模式,相比较ipvs,效率较低。

  1. # pod名称根据自己的实际名称来定
  2. $ kubectl -n kube-system logs kube-proxy-wlmdm

iptables模式的话,返回如下:

kubernetes 1.18.3 集群部署 - 图17