kubernetes 高可用集群搭建---kubeadm方式

本文所使用的配置文件,在GiHub项目中 https://github.com/aidansu/kubernetes-kubeadm-install
Kubernetes 版本为 1.14

服务器说明

我这里使用的是4台centos-7.5的虚拟机,具体信息如下表:

系统类型 IP地址 节点角色 CPU Memory Hostname
centos-7.5 192.168.0.51 master >=2 >=2G manager1
centos-7.5 192.168.0.60 harbor >=2 >=2G harbor
centos-7.5 192.168.0.61 worker >=2 >=2G worker1
centos-7.5 192.168.0.62 worker >=2 >=2G worker2

集群数量可以根据自己的实际情况而定,建议最少应有一个master和两个worker。

系统设置(所有节点)

主机名

主机名必须每个节点都不一样,并且保证所有点之间可以通过hostname互相访问。

1
2
3
4
5
6
7
8
9
10
# 查看主机名
$ hostname
# 修改主机名
$ hostnamectl set-hostname <your_hostname>
# 配置host,使所有节点之间可以通过hostname互相访问
$ vim /etc/hosts
# <node-ip> <node-hostname>

1
2
3
4
5
#hosts文件内容追加如下数据 所有虚拟机都需要加入
192.168.0.51 manager1
192.168.0.60 reg.aidansu.com
192.168.0.61 worker1
192.168.0.62 worker2

安装依赖包

1
2
3
4
5
6
7
8
9
10
11
12
# 配置yum源,先备份原配置
$ mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
# 下载阿里云yum配置文件
$ wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
# 生成缓存
$ yum clean all
$ yum makecache
# 安装依赖包
$ yum install -y conntrack ipvsadm ipset jq sysstat curl iptables libseccomp

关闭防火墙、swap,重置iptables

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 关闭防火墙
$ systemctl stop firewalld && systemctl disable firewalld
# 重置iptables
$ iptables -F && iptables -X && iptables -F -t nat && iptables -X -t nat && iptables -P FORWARD ACCEPT
# 关闭swap
$ swapoff -a
$ sed -i '/swap/s/^\(.*\)$/#\1/g' /etc/fstab
# 关闭selinux
$ setenforce 0
# 关闭dnsmasq(否则可能导致docker容器无法解析域名)
$ service dnsmasq stop && systemctl disable dnsmasq

系统参数设置

1
2
3
4
5
6
7
8
9
10
11
12
13
# 制作配置文件
$ cat > /etc/sysctl.d/kubernetes.conf <<EOF
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1
vm.swappiness=0
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_watches=89100
EOF
# 生效文件
$ sysctl -p /etc/sysctl.d/kubernetes.conf

如果生效文件时出现以下错误

1
2
sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-ip6tables: No such file or directory
sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-iptables: No such file or directory

执行以下代码后 再执行生效文件

1
2
3
4
$ modprobe br_netfilter
$ ls /proc/sys/net/bridge
# 生效文件
$ sysctl -p /etc/sysctl.d/kubernetes.conf

安装docker

如果安装过程遇到问题可以参阅官方文档:https://docs.docker.com/engine/install/centos/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 配置yum源
$ yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 清理原有版本
$ yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine \
container-selinux
# 查看版本列表
$ yum list docker-ce --showduplicates | sort -r
# 根据kubernetes对docker版本的兼容测试情况,我们选择18.09版本
$ yum install docker-ce-18.09.9 docker-ce-cli-18.09.9 containerd.io
# 开机启动
$ systemctl enable docker

设置参数,如最大分区是/,下面的设置可以跳过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 1.查看磁盘挂载
$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda2 98G 2.8G 95G 3% /
devtmpfs 63G 0 63G 0% /dev
/dev/sda5 1015G 8.8G 1006G 1% /tol
/dev/sda1 197M 161M 37M 82% /boot
# 2.选择比较大的分区
$ mkdir -p /tol/docker-data
$ cat <<EOF > /etc/docker/daemon.json
{
"graph": "/tol/docker-data"
}
EOF
# 启动docker服务
$ systemctl restart docker.service

安装必要工具(所有节点)

工具说明

  • kubeadm: 部署集群用的命令
  • kubelet: 在集群中每台机器上都要运行的组件,负责管理pod、容器的生命周期
  • kubectl: 集群管理工具(可选,只要在控制集群的节点上安装即可)

安装方法

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
# 配置yum源
$ cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[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
# 安装工具
# 找到要安装的版本号
$ yum list kubeadm --showduplicates | sort -r
# 安装指定版本(这里用的是1.14.0)
$ yum install kubelet-1.14.0-0 -y && yum install kubectl-1.14.0-0 -y && yum install kubeadm-1.14.0-0 -y
# 设置kubelet的cgroupdriver(kubelet的cgroupdriver默认为systemd,如果上面没有设置docker的exec-opts为systemd,这里就需要将kubelet的设置为cgroupfs)
# 由于各自的系统配置不同,配置位置和内容都不相同
# 1. /etc/systemd/system/kubelet.service.d/10-kubeadm.conf(如果此配置存在的情况执行下面命令:)
$ sed -i "s/cgroup-driver=systemd/cgroup-driver=cgroupfs/g" /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
# 2. 如果1中的配置不存在,则此配置应该存在(不需要做任何操作):/usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf
# 启动kubelet
$ systemctl enable kubelet && systemctl start kubelet

部署master

部署keepalived - apiserver高可用(两个master节点以上 单一master节点跳过这一步)

重要:如果是云环境,一般不支持自定义虚拟ip。这一步可以跳过了。下面所有用到虚拟ip的地方设置为其中某一台master的ip即可。

安装keepalived

1
2
# 在两个主节点上安装keepalived(一主一备)
$ yum install -y keepalived

创建keepalived配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 创建目录
$ ssh <user>@<master-ip> "mkdir -p /etc/keepalived"
$ ssh <user>@<backup-ip> "mkdir -p /etc/keepalived"
# 分发配置文件
$ scp target/configs/keepalived-master.conf <user>@<master-ip>:/etc/keepalived/keepalived.conf
$ scp target/configs/keepalived-backup.conf <user>@<backup-ip>:/etc/keepalived/keepalived.conf
# 分发监测脚本
$ scp target/scripts/check-apiserver.sh <user>@<master-ip>:/etc/keepalived/
$ scp target/scripts/check-apiserver.sh <user>@<backup-ip>:/etc/keepalived/
# 添加可执行权限
$ chmod 644 /etc/keepalived/keepalived.conf
$ chmod +x /etc/keepalived/check-apiserver.sh

启动keepalived

1
2
3
4
5
6
7
8
9
10
11
# 分别在master和backup上启动服务
$ systemctl enable keepalived && service keepalived start
# 检查状态
$ service keepalived status
# 查看日志
$ journalctl -f -u keepalived
# 查看虚拟ip
$ ip a

部署master节点

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
37
38
39
40
# 创建 yaml文件进行init
$ cat <<EOF > /root/kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
kubernetesVersion: v1.14.0
controlPlaneEndpoint: "192.168.0.50:6443"
networking:
podSubnet: "10.240.0.0/16"
imageRepository: registry.aliyuncs.com/google_containers
EOF
$ cd /root
# 部署master
$ kubeadm init --config=kubeadm-config.yaml --experimental-upload-certs
# 记录下master的地址和token 后面创建master节点和node节点时会使用到 初始化时会有提示
kubeadm join 192.168.0.50:6443 --token 7oj9qy.3kcewe0nj10mol5z \
--discovery-token-ca-cert-hash sha256:41a588def5f6bfedfa2382f263f5f4c378c4f2095b90b0f9452c8897bd3c7ddb \
--experimental-control-plane --certificate-key 701088dcbed429bfa5306cfe39889b0c7880d23d0825ca6d03b1c9e2e976e6c8
kubeadm join 192.168.0.50:6443 --token 7oj9qy.3kcewe0nj10mol5z \
--discovery-token-ca-cert-hash sha256:41a588def5f6bfedfa2382f263f5f4c378c4f2095b90b0f9452c8897bd3c7ddb
# copy 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 pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-8686dcc4fd-k778p 0/1 Pending 0 25m
kube-system coredns-8686dcc4fd-nm7lb 0/1 Pending 0 25m
kube-system etcd-manager1 1/1 Running 2 24m
kube-system kube-apiserver-manager1 1/1 Running 2 24m
kube-system kube-controller-manager-manager1 1/1 Running 2 24m
kube-system kube-proxy-ss6tr 1/1 Running 2 25m
kube-system kube-scheduler-manager1 1/1 Running 2 24m
$ curl -k https://localhost:6443/healthz
ok

如需重置master节点 执行以下操作

1
2
$ kubeadm reset
$ rm -rf $HOME/.kube

部署网络插件(calico 或 weave)

  • calico : 性能、灵活性高,功能全面,不仅提供主机和pod之间的网络连接,还涉及网络安全和管理。
  • weave : 配置简便,提供了许多内置和自动配置的功能,因此除了添加网络规则之外,用户无需进行其他配置。

部署 calico

我们使用calico官方的安装方式来部署。

1
2
3
4
5
6
7
8
9
10
11
12
# 创建目录(在配置了kubectl的节点上执行)
$ mkdir -p /etc/kubernetes/addons
# 上传calico配置到配置好kubectl的节点(一个节点即可)
$ scp target/addons/calico* <user>@<node-ip>:/etc/kubernetes/addons/
# 部署calico
$ kubectl apply -f /etc/kubernetes/addons/calico-rbac-kdd.yaml
$ kubectl apply -f /etc/kubernetes/addons/calico.yaml
# 查看状态
$ kubectl get pods -n kube-system

部署 weave

1
2
# 执行以下命令即可一键部署 weave
$ kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"

部署node节点

加入master

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 5.2 部署master记录下的token
$ kubeadm join 192.168.0.50:6443 --token 7oj9qy.3kcewe0nj10mol5z \
--discovery-token-ca-cert-hash sha256:41a588def5f6bfedfa2382f263f5f4c378c4f2095b90b0f9452c8897bd3c7ddb
# 忘记token可以到master执行命令获取当前的token
$ kubeadm token list
2smik0.a4rb4f8mpx7b7py3
# 获取ca证书sha256编码hash值
$ openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
a1e5a9dc138d2eb6ff6ff9f522e5021549137be9f6a7f89138a0e671a106a61c
# 如果没有token或已过期,则创建一个新的token
$ kubeadm token create
$ kubeadm init phase upload-certs --experimental-upload-certs
# 最后到node节点执行join命令
$ kubeadm join 192.168.8.170:6443 --token 2smik0.a4rb4f8mpx7b7py3 \
--discovery-token-ca-cert-hash sha256:a1e5a9dc138d2eb6ff6ff9f522e5021549137be9f6a7f89138a0e671a106a61c

在master查看节点状态

1
2
3
4
5
6
# 成功加入集群的node status应为Ready 此时worker2未开机 则为NotReady
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
manager1 Ready master 23h v1.14.0
worker1 Ready <none> 23h v1.14.0
worker2 NotReady <none> 23h v1.14.0

使用 kubectl describe 命令来查看节点(Node)对象的详细信息、状态和事件(Event)

1
$ kubectl describe node <node-name>

查看集群状态 确认各个组件都处于healthy状态

1
2
3
4
5
6
$ kubectl get cs
NAME STATUS MESSAGE ERROR
controller-manager Healthy ok
scheduler Healthy ok
etcd-0 Healthy {"health":"true"}

使用 kubectl get pod 命令查看各节点上各个系统 Pod 的状态

1
$ kubectl get pod --all-namespaces -o wide

如果有pod提示Init:ImagePullBackOff,说明这个pod的镜像在对应节点上拉取失败,我们可以通过 kubectl describe pod 查看 Pod 具体情况,以确认拉取失败的镜像

1
$ kubectl describe pod <podname> --namespace=<namespace>

加载ipvs相关模块

由于ipvs已经加入到了内核的主干,所以为kube-proxy开启ipvs的前提需要加载以下的内核模块:
在所有的Kubernetes节点执行以下脚本:

1
2
3
4
5
6
7
8
9
10
11
$ cat > /etc/sysconfig/modules/ipvs.modules <<EOF
#!/bin/bash
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
EOF
#执行脚本
$ chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep -e ip_vs -e nf_conntrack_ipv4

上面脚本创建了/etc/sysconfig/modules/ipvs.modules文件,保证在节点重启后能自动加载所需模块。 使用lsmod | grep -e ip_vs -e nf_conntrack_ipv4命令查看是否已经正确加载所需的内核模块。
接下来还需要确保各个节点上已经安装了ipset软件包。 为了便于查看ipvs的代理规则,最好安装一下管理工具ipvsadm。

kube-proxy开启ipvs

修改ConfigMap的kube-system/kube-proxy中的config.conf,mode: “ipvs”:

1
2
$ kubectl edit cm kube-proxy -n kube-system
configmap/kube-proxy edited

之后重启各个节点上的kube-proxy pod:

1
$ kubectl get pod -n kube-system | grep kube-proxy | awk '{system("kubectl delete pod "$1" -n kube-system")}'

查看日志:

1
2
3
4
5
6
7
$ kubectl get pod -n kube-system | grep kube-proxy
kube-proxy-22xkv 1/1 Running 0 42s
kube-proxy-6ngbx 1/1 Running 0 57s
kube-proxy-rw6zb 1/1 Running 0 48s
# 查看对应的 kube-proxy-xxxxx 日志 如有 Using ipvs Proxier.说明ipvs模式已经开启。
$ kubectl logs <podname> -n kube-system

测试集群各个组件

首先验证kube-apiserver, kube-controller-manager, kube-scheduler, pod network 是否正常:
部署一个 Nginx Deployment,包含2个Pod
参考:https://kubernetes.io/docs/concepts/workloads/controllers/deployment/

1
2
3
4
$ kubectl create deployment nginx --image=nginx:alpine
deployment.apps/nginx created
$ kubectl scale deployment nginx --replicas=2
deployment.extensions/nginx scaled

验证Nginx Pod是否正确运行,并且会分配集群IP

1
2
3
4
5
6
7
$ kubectl get pods -l app=nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-77595c695-7jpm7 1/1 Running 0 6s 10.38.0.1 worker2 <none> <none>
nginx-77595c695-nfzs2 1/1 Running 0 12s 10.32.0.2 worker1 <none> <none>
# 查看状态
$ kubectl describe deployments.apps nginx

再验证一下kube-proxy是否正常:以 NodePort 方式对外提供服务

1
2
3
4
5
$ kubectl expose deployment nginx --port=80 --type=NodePort
service/nginx exposed
$ kubectl get services nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx NodePort 10.109.249.233 <none> 80:31864/TCP 8s

检查各种ip连通性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 检查各 Node 上的 Pod IP 连通性
$ kubectl get pods -o wide
# 在每个节点上ping pod ip
$ ping <pod-ip>
# 检查service可达性
$ kubectl get svc
# 在每个节点上访问服务
$ curl <service-ip>:<port>
# 在每个节点检查node-port可用性
$ curl <node-ip>:<port>

可以通过任意 NodeIP:Port 在集群外部访问这个服务:

1
2
3
$ curl 192.168.0.51:31864
$ curl 192.168.0.61:31864
$ curl 192.168.0.62:31864

最后验证一下dns, pod network是否正常:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 运行Busybox并进入交互模式
$ kubectl run -it curl --image=radial/busyboxplus:curl
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
# 输入nslookup nginx查看是否可以正确解析出集群内的IP,以验证DNS是否正常
$ nslookup nginx
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: nginx
Address 1: 10.109.249.233 nginx.default.svc.cluster.local
# 通过服务名进行访问,验证kube-proxy是否正常
$ curl http://nginx/
# 分别访问一下2个Pod的内网IP,验证跨Node的网络通信是否正常
$ curl 10.38.0.1
$ curl 10.32.0.2
# 退出后启用
kubectl attach <podname> -c curl -i -t

Pod调度到Master节点
出于安全考虑,默认配置下Kubernetes不会将Pod调度到Master节点。查看Taints字段默认配置:

1
$ kubectl describe node manager1

如果希望将manager1也当作Node节点使用,可以执行如下命令,其中manager1是主机节点hostname:

1
$ kubectl taint node manager1 node-role.kubernetes.io/master-

如果要恢复Master Only状态,执行如下命令:

1
$ kubectl taint node manager1 node-role.kubernetes.io/master=:NoSchedule

移除节点

1
2
3
4
5
#移除节点和集群 以移除worker1节点为例,在Master节点上运行:
$ kubectl drain worker1 --delete-local-data --force --ignore-daemonsets
$ kubectl delete node worker1
#上面两条命令执行完成后,在worker1节点执行清理命令,重置kubeadm的安装状态:
$ kubeadm reset

在master上删除node并不会清理worker1运行的容器,需要在删除节点上面手动运行清理命令。
如果你想重新配置集群,使用新的参数重新运行kubeadm init或者kubeadm join即可。
移除podpod

1
2
3
#查看pod列表
$ kubectl get pod --all-namespaces -o wide
$ kubectl delete -n <namespace> pod <name>

删除label删除应用

1
$ kubectl delete deployments -l app=nginx

部署dashboard可视化工具

部署服务

准备 /etc/kubernetes/addons/dashboard-all.yaml 文件

其中 image 为镜像仓库地址 这里是用的是:
registry.cn-qingdao.aliyuncs.com/wangxiaoke/kubernetes-dashboard-amd64:v1.10.0

创建服务 (node节点会自动拉取镜像)

1
$ kubectl apply -f /etc/kubernetes/addons/dashboard-all.yaml

查看服务运行情况

1
2
3
4
$ kubectl get deployment kubernetes-dashboard -n kube-system
$ kubectl --namespace kube-system get pods -o wide
$ kubectl get services kubernetes-dashboard -n kube-system
$ netstat -ntlp|grep 30005

访问dashboard

为了集群安全,从 1.7 开始,dashboard 只允许通过 https 访问,我们使用nodeport的方式暴露服务,可以使用 https://NodeIP:NodePort 地址访问
关于自定义证书
默认dashboard的证书是自动生成的,肯定是非安全的证书,如果大家有域名和对应的安全证书可以自己替换掉。使用安全的域名方式访问dashboard。
在dashboard-all.yaml中增加dashboard启动参数,可以指定证书文件,其中证书文件是通过secret注进来的。

- –tls-cert-file
- dashboard.cer
- –tls-key-file
- dashboard.key

登录dashboard

Dashboard 默认只支持 token 认证,所以如果使用 KubeConfig 文件,需要在该文件中指定 token,我们这里使用token的方式登录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 创建service account
$ kubectl create sa dashboard-admin -n kube-system
# 创建角色绑定关系
$ kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin
# 查看dashboard-admin的secret名字
$ ADMIN_SECRET=$(kubectl get secrets -n kube-system | grep dashboard-admin | awk '{print $1}')
# 打印secret的token
$ kubectl describe secret -n kube-system ${ADMIN_SECRET} | grep -E '^token' | awk '{print $2}'
eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3......
# 登录 https://<masterIp>:30005 使用token登录
https://192.168.0.50:30005
# 选择令牌登录

坚持原创技术分享,您的支持将鼓励我继续创作!