通过kubeadm在Ubuntu1604下构建k8s高可用集群

本文涉及的产品
云服务器 ECS,每月免费额度200元 3个月
云服务器ECS,u1 2核4GB 1个月
简介: 本文参考了https://github.com/cookeem/kubeadm-ha,https://kairen.github.io/2018/07/17/kubernetes/deploy/kubeadm-v1.11-ha/,以及 https://jamesdeng.github.io/2018/08/21/k8s-1.11-%E9%98%BF%E9%87%8C%E4%BA%91%E5%AE%89%E8%A3%85.html,特别是第三个方案,解决了我在阿里云部署K8s高可用集群的大问题。

本文参考了https://github.com/cookeem/kubeadm-ha,https://kairen.github.io/2018/07/17/kubernetes/deploy/kubeadm-v1.11-ha/,以及 https://jamesdeng.github.io/2018/08/21/k8s-1.11-%E9%98%BF%E9%87%8C%E4%BA%91%E5%AE%89%E8%A3%85.html,特别是第三个方案,解决了我在阿里云部署K8s高可用集群的大问题。

本地环境基于Haproxy+Keepalived可以轻松实现k8s的HA,但是在阿里云环境中,由于ECS不支持Keepalived,且阿里云内网的SLB,不支持后端ECS实例既作为Real Server又作为客户端向所在的负载均衡实例发送请求。因为返回的数据包只在云服务器内部转发,不经过负载均衡,在后端ECS实例上去访问负载均衡的服务地址是不通的。所以这里采用的是另起两台ECS部署Haproxy,并 设置内网SLB的后端为这两台ECS,这里通过docker运行haproxy容器,结合/etc/haproxy/haproxy.cfg配置。另外3台master节点的部署,这里采用一个比较巧妙的设计,设置kubeadm-init.yaml文件中的SLB地址为k8s-master-lb(对应/etc/hosts里面127.0.0.1),这里不能直接设置成SLB的内网IP地址,因为ECS的apiserver访问该SLB是不通的,即使第一台master可以添加,第二台还是会报错。通过k8s-master-lb这个指定本机ip的域名,成功生成第一个master节点的配置和certs之后,可以将/etc/kubernetes/pki+admin.conf,copy至其他两台master上,然后继续添加第二台、第三台,当然master节点上也需要部署haproxy,因为kubeadm-init.yaml文件中k8s-master-lb:8443的这个端口,是直接通过本机的Haproxy负载出来的。具体见下面第二套方案。

补充以下三点说明:

1. 虽然阿里云内网SLB不支持APIserver的四层负载均衡,但是这里采用了七层负载均衡(需要将第一台生成的apiserver的证书放置SLB中,且apiserver开启http访问),后续补充说明,目前环境部署成功。(后续会持续新增说明),且去除了第二套方案的Haproxy,因为采用了阿里云SLB,不需要再配置一个Haproxy。

2. 另外,这里考虑第一套的本地方案中,通过Keepalived可以获得一个可浮动的VIP,保证一台master掉了,可以浮动至另外两台master上,所以不需要再配置一个Haproxy,因为集群中还需要配置Nginx服务,外部访问集群直接访问VIP: Nginx-nodePort即可。

3. 目前本文方案的ETCD都是采用集群容器部署,可以考虑改成独立部署,比如直接通过系统的Systemd保证服务可用。

本文基于的环境:

Linux发行版本: Ubuntu1604

docker版本:17.03.0-ce

Kubernetes版本:V1.11.1

haproxy的docker容器:haproxy:1.7-alpine

本地环境的Keepalived容器:keepalived:1.4.5(阿里云不支持Keepalived,用它的内网SLB服务)

Flanneld网络组件:quay.io/coreos/flannel:v0.10.0-amd64

一、第一种使用场景,本地环境,一个局域网内采用Haproxy+keepalived,结合KubernetesV1.11.1的kubeadm HA实现。

首先规划3台master节点,同时3台node节点

192.168.0.1 master01 
192.168.0.2 master02
192.168.0.3 master03
192.168.0.4 node01
192.168.0.5 node02
192.168.0.6 node03

keepalived的VIP由自己设定,只要是同一网段内未使用的IP即可,本例中我设定为:192.168.0.100

这里介绍下KubernetesV1.11.1中的几个好用的新命令

# 通过yaml文件init出master节点
kubeadm init --config kubeadm-init.yaml
# 通过kubeadm 获取基础组件镜像清单
kubeadm config images list --kubernetes-version=v1.11.1
# 通过kubeadm 拉取基础镜像
kubeadm config images pull --kubernetes-version=v1.11.1

三台Master节点都需要做如下配置

  1. mkdir -p /etc/kubernetes/manifests
  2. mkdir -p /etc/haproxy
  3. 生成haproxy.conf配置文件
cat <<EOF > /etc/haproxy/haproxy.cfg
global
 log 127.0.0.1 local0 err
 maxconn 50000
 uid 99
 gid 99
global
 log 127.0.0.1 local0 err
 maxconn 50000
 uid 99
 gid 99
 #daemon
 nbproc 1
 pidfile haproxy.pid
defaults
 mode http
 log 127.0.0.1 local0 err
 maxconn 50000
 retries 3
 timeout connect 5s
 timeout client 30s
 timeout server 30s
 timeout check 2s

listen stats
 mode http
 bind 0.0.0.0:9090
 log 127.0.0.1 local0 err
 stats refresh 30s
 stats uri /haproxy-status
 stats realm Haproxy\ Statistics
 stats auth admin:admin123
 stats hide-version
 stats admin if TRUE

frontend kube-apiserver-https
 mode tcp
 bind :8443
 default_backend kube-apiserver-backend

backend kube-apiserver-backend
 mode tcp
 balance roundrobin
 server apiserver1 192.168.0.1:6443 weight 3 minconn 100 maxconn 50000 check inter 5000 rise 2 fall 5
 server apiserver2 192.168.0.2:6443 weight 3 minconn 100 maxconn 50000 check inter 5000 rise 2 fall 5
 server apiserver3 192.168.0.3:6443 weight 3 minconn 100 maxconn 50000 check inter 5000 rise 2 fall 5
EOF

4. 新建/etc/kubernetes/manifests/haproxy.yaml

cat <<EOF > /etc/kubernetes/manifests/haproxy.yaml
kind: Pod
apiVersion: v1
metadata:
 annotations:
 scheduler.alpha.kubernetes.io/critical-pod: ""
 labels:
 component: haproxy
 tier: control-plane
 name: kube-haproxy
 namespace: kube-system
spec:
 hostNetwork: true
 priorityClassName: system-cluster-critical
 containers:
 - name: kube-haproxy
 image: docker.io/haproxy:1.7-alpine
 resources:
 requests:
 cpu: 100m
 volumeMounts:
 - name: haproxy-cfg
 readOnly: true
 mountPath: /usr/local/etc/haproxy/haproxy.cfg
 volumes:
 - name: haproxy-cfg
 hostPath:
 path: /etc/haproxy/haproxy.cfg
 type: FileOrCreate
EOF

5. 新建/etc/kubernetes/manifests/keepalived.yaml

cat <<EOF > /etc/kubernetes/manifests/keepalived.yaml
kind: Pod
apiVersion: v1
metadata:
 annotations:
 scheduler.alpha.kubernetes.io/critical-pod: ""
 labels:
 component: keepalived
 tier: control-plane
 name: kube-keepalived
 namespace: kube-system
spec:
 hostNetwork: true
 priorityClassName: system-cluster-critical
 containers:
 - name: kube-keepalived
 image: docker.io/osixia/keepalived:1.4.5
 env:
 - name: KEEPALIVED_VIRTUAL_IPS
 value: 192.168.0.100
 - name: KEEPALIVED_INTERFACE
 value: eth1
 - name: KEEPALIVED_UNICAST_PEERS
 value: "#PYTHON2BASH:['192.168.0.1', '192.168.0.2', '192.168.0.3']"
 - name: KEEPALIVED_PASSWORD
 value: docker
 - name: KEEPALIVED_PRIORITY
 value: "100"
 - name: KEEPALIVED_ROUTER_ID
 value: "51"
 resources:
 requests:
 cpu: 100m
 securityContext:
 privileged: true
 capabilities:
 add:
 - NET_ADMIN
EOF
  • KEEPALIVED_VIRTUAL_IPS:Keepalived 提供的 VIPs。
  • KEEPALIVED_INTERFACE:VIPs 绑定的网卡。
  • KEEPALIVED_UNICAST_PEERS:其他 Keepalived 节点的单点传播 IP。
  • KEEPALIVED_PASSWORD: Keepalived auth_type 的 Password。
  • KEEPALIVED_PRIORITY:指定了备份发生時,接手的介面之順序,数字越大,优先级越高。这边master01为150,其余为100

以上的haproxy.yaml和keepalived.yaml文件直接放在/etc/kubernetes/manifests下,集群启动后,会自动加载这两个yaml文件,并部署Pod。

依次通过kubeadm部署三台Master节点,在每台master节点上执行(注意Kubernetes Control Plane新特性)

1. 在master01节点上执行

cat <<EOF > kubeadm-init.yaml
apiVersion: kubeadm.k8s.io/v1alpha2
kind: MasterConfiguration
kubernetesVersion: v1.11.1
apiServerCertSANs:
- "192.168.0.100"
api:
 controlPlaneEndpoint: "192.168.0.100:8443"
etcd:
 local:
 extraArgs:
 listen-client-urls: "https://127.0.0.1:2379,https://192.168.0.1:2379"
 advertise-client-urls: "https://192.168.0.1:2379"
 listen-peer-urls: "https://192.168.0.1:2380"
 initial-advertise-peer-urls: "https://192.168.0.1:2380"
 initial-cluster: "u212=https://192.168.0.1:2380"
 serverCertSANs:
 - master01
 - 192.168.0.1
 peerCertSANs:
 - master01
 - 192.168.0.1
networking:
 podSubnet: "172.168.0.0/16"
EOF

通过执行kubeadm init --config kubeadm-init.yaml,成功后记录生成的token

kubeadm join 192.168.0.100:8443 --token rolz18.bm9jxwlmzagrfslg --discovery-token-ca-cert-hash sha256:*

之后,将certs文件和admin.conf文件copy至其他master节点上

export DIR=/etc/kubernetes/
for NODE in master02 master03; do echo "------ ${NODE} ------"
 ssh ${NODE} "mkdir -p ${DIR}/pki/etcd"
 scp ${DIR}/pki/ca.crt ${NODE}:${DIR}/pki/ca.crt
 scp ${DIR}/pki/ca.key ${NODE}:${DIR}/pki/ca.key
 scp ${DIR}/pki/sa.key ${NODE}:${DIR}/pki/sa.key
 scp ${DIR}/pki/sa.pub ${NODE}:${DIR}/pki/sa.pub
 scp ${DIR}/pki/front-proxy-ca.crt ${NODE}:${DIR}/pki/front-proxy-ca.crt
 scp ${DIR}/pki/front-proxy-ca.key ${NODE}:${DIR}/pki/front-proxy-ca.key
 scp ${DIR}/pki/etcd/ca.crt ${NODE}:${DIR}/pki/etcd/ca.crt
 scp ${DIR}/pki/etcd/ca.key ${NODE}:${DIR}/pki/etcd/ca.key
 scp ${DIR}/admin.conf ${NODE}:${DIR}/admin.conf
 done

2. 在master02节点上执行

cat <<EOF > kubeadm-init.yaml
apiVersion: kubeadm.k8s.io/v1alpha2
kind: MasterConfiguration
kubernetesVersion: v1.11.1
apiServerCertSANs:
- "192.168.0.100"
api:
 controlPlaneEndpoint: "192.168.0.100:8443"
etcd:
 local:
 extraArgs:
 listen-client-urls: "https://127.0.0.1:2379,https://192.168.0.2:2379"
 advertise-client-urls: "https://192.168.0.2:2379"
 listen-peer-urls: "https://192.168.0.2:2380"
 initial-advertise-peer-urls: "https://192.168.0.2:2380"
 initial-cluster: "master01=https://192.168.0.2:2380,master02=https://192.168.0.2:2380"
 initial-cluster-state: existing
 serverCertSANs:
 - master02
 - 192.168.0.2
 peerCertSANs:
 - master02
 - 192.168.0.2
networking:
 podSubnet: "172.168.0.0/16"
EOF

然后通过kubeadm phase来启动master02的kubelet,注意要在以上kubeadm-init.yaml同一目录下运行

 kubeadm alpha phase certs all --config kubeadm-init.yaml
 kubeadm alpha phase kubelet config write-to-disk --config kubeadm-init.yaml
 kubeadm alpha phase kubelet write-env-file --config kubeadm-init.yaml
 kubeadm alpha phase kubeconfig kubelet --config kubeadm-init.yaml
 systemctl start kubelet

通过etcdctl命令,将master02的etcd添加到master01的etcd容器中

 export ETCD1_NAME=master01; export ETCD1_IP=192.168.0.1
 export ETCD2_NAME=master02; export ETCD2_IP=192.168.0.2
 export KUBECONFIG=/etc/kubernetes/admin.conf
 kubectl exec -n kube-system etcd-${ETCD1_NAME} -- etcdctl \
 --ca-file /etc/kubernetes/pki/etcd/ca.crt \
 --cert-file /etc/kubernetes/pki/etcd/peer.crt \
 --key-file /etc/kubernetes/pki/etcd/peer.key \
 --endpoints=https://${ETCD1_IP}:2379 member add ${ETCD2_NAME} https://${ETCD2_IP}:2380

kubeadm alpha phase etcd local --config kubeadm-init.yaml

成功后,可以通过如下命令查看etcd集群的member list和目前的isLeader

export ETCD1_NAME=master02; export ETCD1_IP=192.168.0.2
kubectl exec -n kube-system etcd-${ETCD1_NAME} -- etcdctl --ca-file /etc/kubernetes/pki/etcd/ca.crt --cert-file /etc/kubernetes/pki/etcd/peer.crt --key-file /etc/kubernetes/pki/etcd/peer.key --endpoints=https://${ETCD1_IP}:2379 member list

最后,执行以下命令来部署control plane

kubeadm alpha phase kubeconfig all --config kubeadm-init.yaml
kubeadm alpha phase controlplane all --config kubeadm-init.yaml
kubeadm alpha phase mark-master --config kubeadm-init.yaml

经过一段时间后,执行以下命令来使用kubeconfig

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

3. 在master03节点上执行

cat <<EOF > kubeadm-init.yaml
apiVersion: kubeadm.k8s.io/v1alpha2
kind: MasterConfiguration
kubernetesVersion: v1.11.1
apiServerCertSANs:
- "192.168.0.100"
api:
 controlPlaneEndpoint: "192.168.0.100:8443"
etcd:
 local:
 extraArgs:
 listen-client-urls: "https://127.0.0.1:2379,https://192.168.0.3:2379"
 advertise-client-urls: "https://192.168.0.3:2379"
 listen-peer-urls: "https://192.168.0.3:2380"
 initial-advertise-peer-urls: "https://192.168.0.3:2380"
 initial-cluster: "master01=https://192.168.0.1:2380,master02=https://192.168.0.2:2380,master03=https://192.168.0.3:2380"
 initial-cluster-state: existing
 serverCertSANs:
 - master03
 - 192.168.0.3
 peerCertSANs:
 - master03
 - 192.168.0.3
networking:
 podSubnet: "172.168.0.0/16"
EOF

然后通过kubeadm phase来启动master03的kubelet,注意要在以上kubeadm-init.yaml同一目录下运行

 kubeadm alpha phase certs all --config kubeadm-init.yaml
 kubeadm alpha phase kubelet config write-to-disk --config kubeadm-init.yaml
 kubeadm alpha phase kubelet write-env-file --config kubeadm-init.yaml
 kubeadm alpha phase kubeconfig kubelet --config kubeadm-init.yaml
 systemctl start kubelet

通过etcdctl命令,将master03的etcd添加到master01的etcd容器中

 export ETCD1_NAME=master01; export ETCD1_IP=192.168.0.1
 export ETCD2_NAME=master03; export ETCD2_IP=192.168.0.3
 export KUBECONFIG=/etc/kubernetes/admin.conf
 kubectl exec -n kube-system etcd-${ETCD1_NAME} -- etcdctl \
 --ca-file /etc/kubernetes/pki/etcd/ca.crt \
 --cert-file /etc/kubernetes/pki/etcd/peer.crt \
 --key-file /etc/kubernetes/pki/etcd/peer.key \
 --endpoints=https://${ETCD1_IP}:2379 member add ${ETCD2_NAME} https://${ETCD2_IP}:2380

kubeadm alpha phase etcd local --config kubeadm-init.yaml

成功后,可以通过如下命令查看etcd集群的member list和目前的isLeader

export ETCD1_NAME=master03; export ETCD1_IP=192.168.0.3
kubectl exec -n kube-system etcd-${ETCD1_NAME} -- etcdctl --ca-file /etc/kubernetes/pki/etcd/ca.crt --cert-file /etc/kubernetes/pki/etcd/peer.crt --key-file /etc/kubernetes/pki/etcd/peer.key --endpoints=https://${ETCD1_IP}:2379 member list

最后,执行以下命令来部署control plane

kubeadm alpha phase kubeconfig all --config kubeadm-init.yaml
kubeadm alpha phase controlplane all --config kubeadm-init.yaml
kubeadm alpha phase mark-master --config kubeadm-init.yaml

经过一段时间后,执行以下命令来使用kubeconfig

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

至此,三台master节点的配置完成,但是都是NotReady状态,需要安装网络插件,这里选择flanneld

#直接下载官网的kube-flannel.yaml文件,不过需要制定网卡,可以制定多个网卡,因为发现新安装的ubuntu1604会有eth0,eno1,enp3s0,eth1等各个网卡。
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.10.0/Documentation/kube-flannel.yml
#可以先curl -O https://raw.githubusercontent.com/coreos/flannel/v0.10.0/Documentation/kube-flannel.yml
然后找到如下:
image: quay.io/coreos/flannel:v0.10.0-amd64
command:
- /opt/bin/flanneld
args:
- --ip-masq
- --kube-subnet-mgr
- --iface=eth0
- --iface=eth1
- --iface=eno1

Node节点的加入,根据master01 init之后的join命令

  • export KUBE_VERSION="1.11.1"
    apt-get update && apt-get install -y kubelet=${KUBE_VERSION}-00 kubeadm=${KUBE_VERSION}-00
  • mkdir -p /etc/kubernetes/manifests/
  • 下载crictl-v1.11.1-linux-amd64.tar.gz,解决一个报错,解压后将mv crictl /usr/bin/
  • kubeadm join 192.168.0.100:8443 --token *.*--discovery-token-ca-cert-hash sha256:*

至此3台master节点的高可用,etcd集群的高可用配置完成。

验证也比较简单

1. 直接将poweroff master01,然后在查看k8s集群是否正常,etcd的isLeader属性是否正常,且自动切换。

2. 或者通过停止服务,systemctl stop kubelet,docker stop myhaproxy,此时master01会变成NotReady状态,且etcd的isLeader已经切换。

小技巧

如果忘记初始master节点时的node节点加入集群命令时,可以通过如下命令找回,只是这个token可能24小时已经过期,可以通过kubeadm token create --ttl 0生成永不过期的token,这里也可以在kubeadm-init.yaml文件中,添加ttl参数,在kubeadm init第一个master时生成一个永不过期的token

kubeadm token create --print-join-command
kubeadm token create --ttl 0

二、第二种使用场景,阿里云ECS服务器Ubuntu1604采用Haproxy+阿里云内网SLB,结合KubernetesV1.11.1的kubeadm HA实现。

我参考的原文作者中说要加上region,我这边没有成功,而是直接用的/etc/hostname,且主机名用的小写,阿里云限制不能修改,否则会出现意想不到的问题。

我们的云上环境有三台master,三台Node,且提供一台用于安装Haproxy服务,避免内网SLB和ECS服务器直接出现请求回环,阿里云SLB的流量只能在ECS直接流转,ECS中的apiserver无法访问到内网SLB的IP。

master01 10.252.1.100 iz1111dddd01
master02 10.252.2.100 iz2222dddd02
master03 10.51.3.66 iz3333dddd03
 
node01 10.21.1.100 iz3333dddd04
node02 10.21.2.100 iz3333dddd05
node03 10.21.3.100 iz3333dddd06

node0x 10.100.3.100 iz1234567800

内网SLB IP 100.150.150.100

配置时,经常出现出错的情况,可能需要reset并清理生成的文件,以免下次init时出错或干扰

#常用命令
kubeadm reset
ifconfig cni0 down
ip link delete cni0
ifconfig flannel.1 down
ip link delete flannel.1
rm -rf /var/lib/cni/
rm -rf /etc/kubernetes/
systemctl stop kubelet;
docker rm -f -v $(docker ps -q);
find /var/lib/kubelet | xargs -n 1 findmnt -n -t tmpfs -o TARGET -T | uniq | xargs -r umount -v;
rm -rf /var/lib/kubelet /var/lib/etcd;

关闭ECS上的防火墙,配置转发规则

cat <<EOF >> /etc/sysctl.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl -p

加载ipvs相关内核模块

#加载ipvs模块
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4

# to check loaded modules, use
lsmod | grep -e ipvs -e nf_conntrack_ipv4
# or
cut -f1 -d " " /proc/modules | grep -e ip_vs -e nf_conntrack_ipv4
lsmod | grep ip_vs


或者也可以通过修改configmap中的mode: "ipvs" 
kubectl edit configmap kube-proxy -n kube-system

iptables防止FORWARD链被drop

iptables -P FORWARD ACCEPT
sed -i "/ExecStart=/a\ExecStartPost=/sbin/iptables -P FORWARD ACCEPT" /lib/systemd/system/docker.service
systemctl daemon-reload
systemctl enable docker 
systemctl restart docker

依次通过kubeadm部署三台Master节点,在每台master节点上执行(注意Kubernetes Control Plane新特性)

1. 在master01节点上执行

#生成配置文件
CP0_IP="10.252.1.100"
CP0_HOSTNAME="iz1111dddd01"
cat >kubeadm-init.yaml<<EOF
apiVersion: kubeadm.k8s.io/v1alpha2
kind: MasterConfiguration
kubernetesVersion: v1.11.1
apiServerCertSANs:
- "iz1111dddd01"
- "iz2222dddd02"
- "iz3333dddd03"
- "10.252.1.100"
- "10.252.2.100"
- "10.51.3.66"
- "100.150.150.100"
- "127.0.0.1"
- "k8s-master-lb"
api:
 advertiseAddress: $CP0_IP
 controlPlaneEndpoint: k8s-master-lb:8443
etcd:
 local:
 extraArgs:
 listen-client-urls: "https://127.0.0.1:2379,https://$CP0_IP:2379"
 advertise-client-urls: "https://$CP0_IP:2379"
 listen-peer-urls: "https://$CP0_IP:2380"
 initial-advertise-peer-urls: "https://$CP0_IP:2380"
 initial-cluster: "$CP0_HOSTNAME=https://$CP0_IP:2380"
 serverCertSANs:
 - $CP0_HOSTNAME
 - $CP0_IP
 peerCertSANs:
 - $CP0_HOSTNAME
 - $CP0_IP
controllerManagerExtraArgs:
 node-monitor-grace-period: 10s
 pod-eviction-timeout: 10s
networking:
 podSubnet: 10.244.0.0/16
kubeProxy:
 config:
 mode: ipvs
EOF

通过执行kubeadm init --config kubeadm-init.yaml,成功后记录生成的token

kubeadm join k8s-master-lb:8443 --token rolz18.bm9jxwlmzagrfslg --discovery-token-ca-cert-hash sha256:*

之后,将certs文件和admin.conf文件copy至其他master节点上

export DIR=/etc/kubernetes/
for NODE in master02 master03; do echo "------ ${NODE} ------"
 ssh ${NODE} "mkdir -p ${DIR}/pki/etcd"
 scp ${DIR}/pki/ca.crt ${NODE}:${DIR}/pki/ca.crt
 scp ${DIR}/pki/ca.key ${NODE}:${DIR}/pki/ca.key
 scp ${DIR}/pki/sa.key ${NODE}:${DIR}/pki/sa.key
 scp ${DIR}/pki/sa.pub ${NODE}:${DIR}/pki/sa.pub
 scp ${DIR}/pki/front-proxy-ca.crt ${NODE}:${DIR}/pki/front-proxy-ca.crt
 scp ${DIR}/pki/front-proxy-ca.key ${NODE}:${DIR}/pki/front-proxy-ca.key
 scp ${DIR}/pki/etcd/ca.crt ${NODE}:${DIR}/pki/etcd/ca.crt
 scp ${DIR}/pki/etcd/ca.key ${NODE}:${DIR}/pki/etcd/ca.key
 scp ${DIR}/admin.conf ${NODE}:${DIR}/admin.conf
 done

2. 在master02节点上执行

CP0_IP="10.252.1.100"
CP0_HOSTNAME="iz1111dddd01"
CP1_IP="10.252.2.100"
CP1_HOSTNAME="iz2222dddd02"
cat > kubeadm-init.yaml<<EOF
apiVersion: kubeadm.k8s.io/v1alpha2
kind: MasterConfiguration
kubernetesVersion: v1.11.1
apiServerCertSANs:
- "iz1111dddd01"
- "iz2222dddd02"
- "iz3333dddd03"
- "10.252.1.100"
- "10.252.2.100"
- "10.51.3.66"
- "100.150.150.100"
- "127.0.0.1"
- "k8s-master-lb"
api:
 advertiseAddress: $CP0_IP
 controlPlaneEndpoint: k8s-master-lb:8443
etcd:
 local:
 extraArgs:
 listen-client-urls: "https://127.0.0.1:2379,https://$CP1_IP:2379"
 advertise-client-urls: "https://$CP1_IP:2379"
 listen-peer-urls: "https://$CP1_IP:2380"
 initial-advertise-peer-urls: "https://$CP1_IP:2380"
 initial-cluster: "$CP0_HOSTNAME=https://$CP0_IP:2380,$CP1_HOSTNAME=https://$CP1_IP:2380"
 initial-cluster-state: existing
 serverCertSANs:
 - $CP1_HOSTNAME
 - $CP1_IP
 peerCertSANs:
 - $CP1_HOSTNAME
 - $CP1_IP
controllerManagerExtraArgs:
 node-monitor-grace-period: 10s
 pod-eviction-timeout: 10s
networking:
 podSubnet: 10.244.0.0/16
kubeProxy:
 config:
 mode: ipvs
EOF

然后通过kubeadm phase来启动master02的kubelet,注意要在以上kubeadm-init.yaml同一目录下运行

 kubeadm alpha phase certs all --config kubeadm-init.yaml
 kubeadm alpha phase kubelet config write-to-disk --config kubeadm-init.yaml
 kubeadm alpha phase kubelet write-env-file --config kubeadm-init.yaml
 kubeadm alpha phase kubeconfig kubelet --config kubeadm-init.yaml
 systemctl start kubelet

通过etcdctl命令,将master02的etcd添加到master01的etcd容器中

CP0_IP="10.252.1.100"
CP0_HOSTNAME="iz1111dddd01"
CP1_IP="10.252.2.100"
CP1_HOSTNAME="iz2222dddd02"
KUBECONFIG=/etc/kubernetes/admin.conf kubectl exec -n kube-system etcd-${CP0_HOSTNAME} -- etcdctl --ca-file /etc/kubernetes/pki/etcd/ca.crt --cert-file /etc/kubernetes/pki/etcd/peer.crt --key-file /etc/kubernetes/pki/etcd/peer.key --endpoints=https://${CP0_IP}:2379 member add ${CP1_HOSTNAME} https://${CP1_IP}:2380

kubeadm alpha phase etcd local --config kubeadm-init.yaml

成功后,可以通过如下命令查看etcd集群的member list和目前的isLeader

export ETCD1_NAME=iz2222dddd02; export ETCD1_IP=10.252.2.100
kubectl exec -n kube-system etcd-${ETCD1_NAME} -- etcdctl --ca-file /etc/kubernetes/pki/etcd/ca.crt --cert-file /etc/kubernetes/pki/etcd/peer.crt --key-file /etc/kubernetes/pki/etcd/peer.key --endpoints=https://${ETCD1_IP}:2379 member list

最后,执行以下命令来部署control plane

kubeadm alpha phase kubeconfig all --config kubeadm-init.yaml
kubeadm alpha phase controlplane all --config kubeadm-init.yaml
kubeadm alpha phase mark-master --config kubeadm-init.yaml

经过一段时间后,执行以下命令来使用kubeconfig

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

3. 在master03节点上执行

CP0_IP="10.252.1.100"
CP0_HOSTNAME="iz1111dddd01"
CP1_IP="10.252.2.100"
CP1_HOSTNAME="iz2222dddd02"
CP2_IP="10.51.3.66"
CP2_HOSTNAME="iz3333dddd03"
cat > kubeadm-init.yaml<<EOF
apiVersion: kubeadm.k8s.io/v1alpha2
kind: MasterConfiguration
kubernetesVersion: v1.11.1
apiServerCertSANs:
- "iz1111dddd01"
- "iz2222dddd02"
- "iz3333dddd03"
- "10.252.1.100"
- "10.252.2.100"
- "10.51.3.66"
- "100.150.150.100"
- "127.0.0.1"
- "k8s-master-lb"
api:
 advertiseAddress: $CP0_IP
 controlPlaneEndpoint: k8s-master-lb:8443
etcd:
 local:
 extraArgs:
 listen-client-urls: "https://127.0.0.1:2379,https://$CP2_IP:2379"
 advertise-client-urls: "https://$CP2_IP:2379"
 listen-peer-urls: "https://$CP2_IP:2380"
 initial-advertise-peer-urls: "https://$CP2_IP:2380"
 initial-cluster: "$CP0_HOSTNAME=https://$CP0_IP:2380,$CP1_HOSTNAME=https://$CP1_IP:2380,$CP2_HOSTNAME=https://$CP2_IP:2380"
 initial-cluster-state: existing
 serverCertSANs:
 - $CP2_HOSTNAME
 - $CP2_IP
 peerCertSANs:
 - $CP2_HOSTNAME
 - $CP2_IP
controllerManagerExtraArgs:
 node-monitor-grace-period: 10s
 pod-eviction-timeout: 10s
networking:
 podSubnet: 10.244.0.0/16
kubeProxy:
 config:
 mode: ipvs
EOF

然后通过kubeadm phase来启动master03的kubelet,注意要在以上kubeadm-init.yaml同一目录下运行

 kubeadm alpha phase certs all --config kubeadm-init.yaml
 kubeadm alpha phase kubelet config write-to-disk --config kubeadm-init.yaml
 kubeadm alpha phase kubelet write-env-file --config kubeadm-init.yaml
 kubeadm alpha phase kubeconfig kubelet --config kubeadm-init.yaml
 systemctl start kubelet

通过etcdctl命令,将master03的etcd添加到master01的etcd容器中

CP0_IP="10.252.1.100"
CP0_HOSTNAME="iz1111dddd01"
CP1_IP="10.51.3.66"
CP1_HOSTNAME="iz3333dddd03"
KUBECONFIG=/etc/kubernetes/admin.conf kubectl exec -n kube-system etcd-${CP0_HOSTNAME} -- etcdctl --ca-file /etc/kubernetes/pki/etcd/ca.crt --cert-file /etc/kubernetes/pki/etcd/peer.crt --key-file /etc/kubernetes/pki/etcd/peer.key --endpoints=https://${CP0_IP}:2379 member add ${CP1_HOSTNAME} https://${CP1_IP}:2380

kubeadm alpha phase etcd local --config kubeadm-init.yaml

成功后,可以通过如下命令查看etcd集群的member list和目前的isLeader

export ETCD1_NAME=iz3333dddd03; export ETCD1_IP=10.51.3.66
kubectl exec -n kube-system etcd-${ETCD1_NAME} -- etcdctl --ca-file /etc/kubernetes/pki/etcd/ca.crt --cert-file /etc/kubernetes/pki/etcd/peer.crt --key-file /etc/kubernetes/pki/etcd/peer.key --endpoints=https://${ETCD1_IP}:2379 member list

最后,执行以下命令来部署control plane

kubeadm alpha phase kubeconfig all --config kubeadm-init.yaml
kubeadm alpha phase controlplane all --config kubeadm-init.yaml
kubeadm alpha phase mark-master --config kubeadm-init.yaml

在三台节点上都执行

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

至此,三台master节点的配置完成,但是都是NotReady状态,需要安装网络插件,这里选择flanneld

#直接下载官网的kube-flannel.yaml文件,不过需要制定网卡,可以制定多个网卡,因为发现新安装的ubuntu1604会有eth0,eno1,enp3s0,eth1等各个网卡。
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.10.0/Documentation/kube-flannel.yml
#可以先curl -O https://raw.githubusercontent.com/coreos/flannel/v0.10.0/Documentation/kube-flannel.yml
然后找到如下:
image: quay.io/coreos/flannel:v0.10.0-amd64
command:
- /opt/bin/flanneld
args:
- --ip-masq
- --kube-subnet-mgr
- --iface=eth0
- --iface=eth1
- --iface=eno1

这里还需要配置一台专门作为Haproxy的ECS,且在以上三台Master上,也要docker run一个Haproxy

mkdir /etc/haproxy
docker pull haproxy:1.7.8-alpine
cat >/etc/haproxy/haproxy.cfg<<EOF
global
 log 127.0.0.1 local0 err
 maxconn 50000
 uid 99
 gid 99
 #daemon
 nbproc 1
 pidfile haproxy.pid

defaults
 mode http
 log 127.0.0.1 local0 err
 maxconn 50000
 retries 3
 timeout connect 5s
 timeout client 30s
 timeout server 30s
 timeout check 2s

listen admin_stats
 mode http
 bind 0.0.0.0:1080
 log 127.0.0.1 local0 err
 stats refresh 30s
 stats uri /haproxy-status
 stats realm Haproxy\ Statistics
 stats auth admin:admin123
 stats hide-version
 stats admin if TRUE

frontend k8s-https
 bind 0.0.0.0:8443
 mode tcp
 #maxconn 50000
 default_backend k8s-https

backend k8s-https
 mode tcp
 balance roundrobin
 server lab1 10.252.1.100:6443 weight 3 minconn 100 maxconn 50000 check inter 5000 rise 2 fall 5
 server lab2 10.252.2.100:6443 weight 2 minconn 100 maxconn 50000 check inter 5000 rise 2 fall 5
 server lab3 10.51.3.66:6443 weight 1 minconn 100 maxconn 50000 check inter 5000 rise 2 fall 5
EOF

#并通过docker运行
docker run -d --name myhaproxy \
-v /etc/haproxy:/usr/local/etc/haproxy:ro \
-p 8443:8443 \
-p 1080:1080 \
--restart always \
haproxy:1.7.8-alpine

#可以访问Haproxy的管理页面,任一台master上都运行了Haproxy,都可以登录Haproxy的管理页面
10.100.3.100:1080/haproxy-status

在阿里云SLB的配置页面,将10.100.3.100的8443作为其后端ECS服务器即可。

Node节点的加入,根据master01 init之后的join命令

  • export KUBE_VERSION="1.11.1"
    apt-get update && apt-get install -y kubelet=${KUBE_VERSION}-00 kubeadm=${KUBE_VERSION}-00
  • mkdir -p /etc/kubernetes/manifests/
  • 下载crictl-v1.11.1-linux-amd64.tar.gz,解决一个报错,解压后将mv crictl /usr/bin/
  • kubeadm join k8s-master-lb:8443 --token *.*--discovery-token-ca-cert-hash sha256:* (注意这里需要在/etc/hosts配置k8s-master-lb对应的SLB的IP: 100.115.129.111)

至此3台master节点的高可用,etcd集群的高可用配置完成。

验证也比较简单

1. 直接将poweroff master01,然后在查看k8s集群是否正常,etcd的isLeader属性是否正常,且自动切换。

2. 或者通过停止服务,systemctl stop kubelet,docker stop myhaproxy,此时master01会变成NotReady状态,且etcd的isLeader已经切换。

小技巧

如果忘记初始master节点时的node节点加入集群命令时,可以通过如下命令找回,只是这个token可能24小时已经过期,可以通过kubeadm token create --ttl 0生成永不过期的token

kubeadm token create --print-join-command
kubeadm token create --ttl 0

至此,大功告成!

附录:

通过git clone git@github.com:cookeem/kubeadm-ha.git之后,cd kubeadm-ha目录

主要修改create-config.sh文件,根据以上的Ip和hostname

# 这个ip是keeplived的虚拟的Ip,可以是任何的ip,这里设置成一个网段的ip export K8SHA_VIP=192.168.0.222

# master01 ip address export K8SHA_IP1=192.168.0.1

# master02 ip address export K8SHA_IP2=192.168.0.2

# master03 ip address export K8SHA_IP3=192.168.0.3

# master keepalived virtual ip hostname export K8SHA_VHOST=k8s-master-lb

# master01 hostname export K8SHA_HOST1=master01

# master02 hostname export K8SHA_HOST2=maste02

# master03 hostname export K8SHA_HOST3=maste03

# master01 network interface name export K8SHA_NETINF1=eth0

# master02 network interface name export K8SHA_NETINF2=eth0

# master03 network interface name export K8SHA_NETINF3=eth0

# keepalived auth_pass config export K8SHA_KEEPALIVED_AUTH=412f7dc3bfed32194d1600c483e10ad1d

# 这个没有用到,就设置成网关ip export K8SHA_CALICO_REACHABLE_IP=192.168.0.1

# kubernetes CIDR pod subnet, if CIDR pod subnet is "172.168.0.0/16" please set to "172.168.0.0" # 这个参数后续的flannel中也需要对应修改,默认的是10.244.0.0/16 export K8SHA_CIDR=172.168.0.0

执行./create-config.sh

就会生成一个config目录,里面对应是master三台节点的配置,包含一个kubeadm-config.yaml文件,当然这里不用这个方法,只是作为一种生成yaml配置的方式,可以使用。

本文转自开源中国-通过kubeadm在Ubuntu1604下构建k8s高可用集群

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务&nbsp;ACK 容器服务&nbsp;Kubernetes&nbsp;版(简称&nbsp;ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情:&nbsp;https://www.aliyun.com/product/kubernetes
相关文章
|
3天前
|
存储 运维 Kubernetes
Kubernetes 集群的持续性能优化实践
【4月更文挑战第22天】在动态且复杂的微服务架构中,确保 Kubernetes 集群的高性能运行是至关重要的。本文将深入探讨针对 Kubernetes 集群性能优化的策略与实践,从节点资源配置、网络优化到应用部署模式等多个维度展开,旨在为运维工程师提供一套系统的性能调优方法论。通过实际案例分析与经验总结,读者可以掌握持续优化 Kubernetes 集群性能的有效手段,以适应不断变化的业务需求和技术挑战。
16 4
|
21天前
|
数据库 存储 监控
什么是 SAP HANA 内存数据库 的 Delta Storage
什么是 SAP HANA 内存数据库 的 Delta Storage
16 0
什么是 SAP HANA 内存数据库 的 Delta Storage
|
2天前
|
存储 运维 Kubernetes
Kubernetes 集群的监控与维护策略
【4月更文挑战第23天】 在微服务架构日益盛行的当下,容器编排工具如 Kubernetes 成为了运维工作的重要环节。然而,随着集群规模的增长和复杂性的提升,如何确保 Kubernetes 集群的高效稳定运行成为了一大挑战。本文将深入探讨 Kubernetes 集群的监控要点、常见问题及解决方案,并提出一系列切实可行的维护策略,旨在帮助运维人员有效管理和维护 Kubernetes 环境,保障服务的持续可用性和性能优化。
|
11天前
|
Kubernetes Linux 网络安全
kubeadm安装k8s
该文档提供了一套在CentOS 7.6上安装Docker和Kubernetes(kubeadm)的详细步骤,包括安装系统必备软件、关闭防火墙和SELinux、禁用swap、开启IP转发、设置内核参数、配置Docker源和加速器、安装指定版本Docker、启动Docker、设置kubelet开机启动、安装kubelet、kubeadm、kubectl、下载和配置Kubernetes镜像、初始化kubeadm、创建kubeconfig文件、获取节点加入集群命令、下载Calico YAML文件以及安装Calico。这些步骤不仅适用于v1.19.14,也适用于更高版本。
64 1
|
12天前
|
Kubernetes 监控 Cloud Native
构建高效云原生应用:基于Kubernetes的微服务治理实践
【4月更文挑战第13天】 在当今数字化转型的浪潮中,企业纷纷将目光投向了云原生技术以支持其业务敏捷性和可扩展性。本文深入探讨了利用Kubernetes作为容器编排平台,实现微服务架构的有效治理,旨在为开发者和运维团队提供一套优化策略,以确保云原生应用的高性能和稳定性。通过分析微服务设计原则、Kubernetes的核心组件以及实际案例,本文揭示了在多变的业务需求下,如何确保系统的高可用性、弹性和安全性。
16 4
|
11天前
|
Kubernetes 搜索推荐 Docker
使用 kubeadm 部署 Kubernetes 集群(二)k8s环境安装
使用 kubeadm 部署 Kubernetes 集群(二)k8s环境安装
53 17
|
23天前
|
Kubernetes Ubuntu 应用服务中间件
Ubuntu 22.04 利用kubeadm方式部署Kubernetes(v1.28.2版本)
Ubuntu 22.04 利用kubeadm方式部署Kubernetes(v1.28.2版本)
97 0
|
23天前
|
消息中间件 Kubernetes Kafka
Terraform阿里云创建资源1分钟创建集群一键发布应用Terraform 创建 Kubernetes 集群
Terraform阿里云创建资源1分钟创建集群一键发布应用Terraform 创建 Kubernetes 集群
16 0
|
24天前
|
Kubernetes 安全 网络安全
搭建k8s集群kubeadm搭建Kubernetes二进制搭建Kubernetes集群
搭建k8s集群kubeadm搭建Kubernetes二进制搭建Kubernetes集群
106 0
|
26天前
|
运维 Kubernetes 持续交付
构建高效自动化运维体系:基于Docker和Kubernetes的最佳实践
在现代云计算环境中,自动化运维成为保障系统稳定性与提升效率的关键。本文深入探讨了如何利用Docker容器化技术和Kubernetes容器编排工具构建一个高效、可靠的自动化运维体系。文中不仅介绍了相关的技术原理,还结合具体案例分析了实施过程中的常见问题及解决方案,为读者提供了一套行之有效的最佳实践指南。