在VMware虚拟机中的CentOS7集群部署高可用的k8s集群环境(v1.15)。

这里有两篇基础知识的补充和单master节点集群的搭建过程,有需要的同学可以看一下。

k8s重要概念及各组件简介

在CentOS7上部署k8s集群(v1.15)

前期工作

什么是高可用集群?

简单来说就是master节点不止一个的集群,我们知道k8s的node节点中,非master节点都需要听从master节点来进行任务的调度分配和负载均衡等操作,这样的好处就是我们只需要操作master节点就可以调度所有的node节点,坏处就是如果master节点崩了,那么整个集群也就崩掉了。所以这里的解决方案就是配置多个master节点,如果一个崩掉了还有别的备用备用节点顶上,不至于出现崩溃的情况。

集群机器

这里必须要说一下,k8s对每个节点的机器配置的最低要求是2C2G,即两核心的CPU,2G的内存,低于这个配置也不是不能用,只是在初始化的时候会警告而已。这里小七采用的是虚拟机的方法(穷学生没有真机集群),具体的配置如下表。

名称配置IP
VIP不需要虚拟机,留一个IP即可192.168.100.10
master208C4G,CentOS7.6192.168.100.20
master218C4G,CentOS7.6192.168.100.21
master228C4G,CentOS7.6192.168.100.22
node308C8G,CentOS7.6192.168.100.30
node318C8G,CentOS7.6192.168.100.31
node328C8G,CentOS7.6192.168.100.32

真机用的是一块渣渣i7-8700和64G的内存,勉强能撑一下。

集群间免密登录

之前专门写过一篇文章,这里不再赘述。多主机间实现SSH免密登录

需要注意的是,在hosts文件中,我们还需要为192.168.100.10添加一下解析。

echo "192.168.100.10  kubernetes.haproxy.com" >> /etc/hosts

这里的kubernetes.haproxy.com可以改成别的名字,但是注意后面要用到,建议改成有意义的名字。

时间同步(所有机器)

这里我们使用ntpdate来进行时间同步

# 使用yum安装ntpdate工具
yum install ntpdate -y

# 使用阿里云的源同步时间
ntpdate ntp1.aliyun.com

# 最后查看一下时间
hwclock

我们也可以在/etc/cron.hourly/下面直接新建一个文件,将ntpdate ntp1.aliyun.com这条命令写进去,这样cron就会每小时执行一次这个同步时间操作。关于cron可以点击这里了解。

cat >>/etc/cron.hourly/synctime <<EOF
ntpdate ntp1.aliyun.com
EOF

升级内核(所有机器)

建议直接升级centos官方的内核,这样兼容性最好。

# 查看当前内核版本
uname -r

# 更新yum源
yum update -y

# 升级yum源中的最新版内核
yum install -y kernel

此外我们还需要设置一下内核的namespace

grubby --args="user_namespace.enable=1" --update-kernel="$(grubby --default-kernel)"

# 重新加载内核
reboot

关闭防火墙(所有机器)

因为k8s涉及的端口非常多,我们先把防火墙关了,如果安装了iptable也先关掉。

# 关闭centos7自带的firewall防火墙
systemctl disable firewalld.service 
systemctl stop firewalld.service 

设置selinux(所有机器)

来自官网的说明,必须把selinux改为permissive(直接生效无需重启)或者disabled(需要重启生效)

通过命令 setenforce 0sed ... 可以将 SELinux 设置为 permissive 模式(将其禁用)。 只有执行这一操作之后,容器才能访问宿主的文件系统,进而能够正常使用 Pod 网络。您必须这么做,直到 kubelet 做出升级支持 SELinux 为止。

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

# 也可以直接修改/etc/selinux/config文件

关于SELinux的简单介绍,可以点击这里查看之前的博客。

关闭swap(所有机器)

k8s官方不推荐我们使用swap分区,所以这里我们也关闭掉。

swapoff -a

vim /etc/fstab
# 注释掉swap分区启动挂载的那一行

# 重启机器
reboot

配置ipvs(所有机器)

# 使用yum源安装ipvs
yum install ipvsadm ipset -y
# 使配置生效
sysctl --system
# 加载模块
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4

# 查看是否加载
lsmod | grep ip_vs

# 配置开机自加载
cat <<EOF >> /etc/rc.local
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
EOF

chmod +x /etc/rc.d/rc.local

配置k8s相关网络参数(所有机器)

接着我们需要编辑一个k8s的配置文件

# 需要设定/etc/sysctl.d/k8s.conf的系统参数。
cat <<EOF > /etc/sysctl.d/k8s.conf
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 10
net.ipv4.neigh.default.gc_stale_time = 120
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_announce = 2
net.ipv4.ip_forward = 1
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 1024
net.ipv4.tcp_synack_retries = 2
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.netfilter.nf_conntrack_max = 2310720
fs.inotify.max_user_watches=89100
fs.may_detach_mounts = 1
fs.file-max = 52706963
fs.nr_open = 52706963
net.bridge.bridge-nf-call-arptables = 1
vm.swappiness = 0
vm.overcommit_memory=1
vm.panic_on_oom=0
EOF

配置iptables(所有机器)

保险起见,我们还需要配置iptables

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

yum install -y bridge-utils.x86_64
modprobe bridge
modprobe br_netfilter

sysctl -p

reboot

检查配置(所有机器)

# 检查系统内核和模块是否适合运行 docker (仅适用于 linux 系统)
curl https://raw.githubusercontent.com/docker/docker/master/contrib/check-config.sh > check-config.sh

bash ./check-config.sh

这里只需要保证必要项通过就可以了。

安装docker(所有机器)

安装docker

centos版本的decker-ce官方安装指导:

https://docs.docker.com/install/linux/docker-ce/centos/

这里我们主要是通过yum的方式来安装,如果出现无法连接docker官网的情况,建议检查一下网络,或者使用rpm的方式进行安装。

# 导入官网提供的repo
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# 安装docker及其相关组件
sudo yum install -y docker-ce docker-ce-cli containerd.io

# 启动docker
sudo systemctl start docker

# 跑个helloworld看看
sudo docker run hello-world

# 最后我们还要设置一下开机启动
sudo systemctl enable docker

配置cgroup

k8s推荐docker的cgroup驱动使用systemd,说是会更稳定,所以这里我们还需要修改一下。

## Create /etc/docker directory.
mkdir /etc/docker

# Setup daemon.
cat > /etc/docker/daemon.json <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2",
  "storage-opts": [
    "overlay2.override_kernel_check=true"
  ]
}
EOF

mkdir -p /etc/systemd/system/docker.service.d

# Restart Docker
systemctl daemon-reload
systemctl restart docker

配置普通用户

默认情况下,普通用户需要使用sudo才能操作docker,我们这里需要进行一些修改。

# 切换到普通用户
su 普通用户名

# 创建docker组
sudo groupadd docker

# 将当前用户加入docker用户组
sudo gpasswd -a ${USER} docker

# 重启docker服务
sudo systemctl daemon-reload
sudo systemctl restart docker

安装配置keepalived、haproxy(所有master节点)

安装

# 使用yum源直接安装
yum install socat keepalived haproxy -y

# 设置开机启动
systemctl enable haproxy
systemctl enable keepalived

# 备份一下原来的配置文件以防万一
mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak
mv /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak

编辑haproxy配置文件

首先我们开启系统的日志功能

vim /etc/rsyslog.conf     #为其添加日志功能
# Provides UDP syslog reception
$ModLoad imudp
$UDPServerRun 514                   ------>启动udp,启动端口后将作为服务器工作
 
# Provides TCP syslog reception
$ModLoad imtcp
$InputTCPServerRun 514            ------>启动tcp监听端口
local2.*                                                /var/log/haproxy.log

注意配置文件里面的IP要根据自己的master节点实际情况进行修改。

cat >> /etc/haproxy/haproxy.cfg <<EOF
global
    log	127.0.0.1	local2
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     1024
    user        haproxy
    group       haproxy
    daemon
    nbproc      1
    stats socket /var/lib/haproxy/stats

defaults
    mode                    tcp
    log                     global
    option                  tcplog
    option                  dontlognull
    option                  redispatch
    retries                 3
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout check           10s

listen stats
    mode   	http
    bind	0.0.0.0:12345
    stats   enable
	log		127.0.0.1	local2
	stats	realm  Haproxy\ Statistics
    stats   uri     /stats
    stats   auth    admin:admin
    stats   admin   if TRUE

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

backend k8s-https
    balance      roundrobin
	mode	tcp
    server master220 192.168.100.20:6443  check inter 10000 fall 2 rise 2 weight 1
    server master221 192.168.100.21:6443  check inter 10000 fall 2 rise 2 weight 1
    server master222 192.168.100.22:6443  check inter 10000 fall 2 rise 2 weight 1

EOF

编辑keepalived配置文件

注意,三个节点keepalived配置文件存在区别:

  • router_id分别为master20、master21、master22
  • state分别为MASTER、BACKUP、BACKUP
  • priority分别为100、90、80
cat >> /etc/keepalived/keepalived.conf <<EOF
global_defs {
   router_id master20
   script_user root
   enable_script_security
}

vrrp_script check_haproxy {
    script /etc/keepalived/check_haproxy.sh
    interval 3
}

vrrp_instance VI_1 {
    state MASTER
    interface ens32
    virtual_router_id 80
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.100.10/24
    }
    track_script {   
        check_haproxy
    }
}
EOF

此外我们还需要编辑一个检查的脚本来确保正常

cat >> /etc/keepalived/check_haproxy.sh <<EOF
#!/bin/bash
NUM=`ps -C haproxy --no-header |wc -l`
if [ $NUM -eq 0 ];then
    systemctl stop keepalived
fi
EOF

安装k8s(所有机器)

k8s官网提供的yum源并不太好用,我们这里使用阿里云的yum镜像源。

# 新建一个yum源
cat >> /etc/yum.repos.d/kubernetes.repo <<EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
exclude=kube*
EOF

yum clean all

yum repolist

yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
# 启动kubelet并设置开机启动
systemctl enable kubelet && systemctl start kubelet

关于SELinux的简单介绍,可以点击这里查看之前的博客。

获取默认配置文件

# 获得默认配置文件。
kubeadm config print init-defaults > kubeadm.conf

# 查看需要的镜像
kubeadm config images list --config kubeadm.conf

不知道为啥这里显示的居然是1.14版本的,小七安装的明明是1.15版本,我们把kubeadm.conf里面的版本号改成1.15再查看

编辑自定义配置文件

注意下面的ip地址和版本号需要根据实际情况来进行改动。

# 配置文件kubuadm_master20.conf

apiVersion: kubeadm.k8s.io/v1beta2
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 192.168.100.20
  bindPort: 6443
---
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
kubernetesVersion: v1.15.0
controlPlaneEndpoint: "kubernetes.haproxy.com:8443"
imageRepository: registry.aliyuncs.com/google_containers
apiServer:
  certSANs:
  - "master20"
  - "master21"
  - "master22"
  - 192.168.100.10
  - 192.168.100.20
  - 192.168.100.21
  - 192.168.100.22

networking:
  podSubnet: "10.244.0.0/16"
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes

etcd:
  local:
    extraArgs:
      listen-client-urls: "https://127.0.0.1:2379,https://192.168.100.20:2379"
      advertise-client-urls: "https://192.168.100.20:2379"
      listen-peer-urls: "https://192.168.100.20:2380"
      initial-advertise-peer-urls: "https://192.168.100.20:2380"
      initial-cluster: "master20=https://192.168.100.20:2380"
      initial-cluster-state: new
    serverCertSANs:
      - master20
      - 192.168.100.20
    peerCertSANs:
      - master20
      - 192.168.100.20
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs

初始化

# 拉取需要的镜像
kubeadm config images pull --config kubuadm_master20.conf

# 初始化
kubeadm init --config kubuadm_master20.conf

这里的token需要记下来。然后我们需要切换到非root用户来进行配置。

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g)
 $HOME/.kube/config
# 添加kubectl的自动补全功能
echo "source <(kubectl completion bash)" >> ~/.bashrc

安装flannel网络(master20)

wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

我们先下载一下配置文件,为了保险起见,我们手动指定网卡

然后我们执行初始化安装操作。

kubectl apply -f kube-flannel.yml

这时候我们再查看节点就会发现,coredns已经正常工作了。

kubectl get pods -A

分发证书(master20)

我们在master20节点上编写一个脚本进行证书的分发,只需要分发到其他的master节点即可。注意里面的ip地址和用户名需要根据实际情况进行修改。

cat >> districert <<EOF
#!/bin/bash
for index in 21 22; do
  ip=192.168.100.${index}
  ssh $ip "mkdir -p /etc/kubernetes/pki/etcd/; mkdir -p /home/tinychen/.kube/"
  scp /etc/kubernetes/pki/ca.crt $ip:/etc/kubernetes/pki/ca.crt
  scp /etc/kubernetes/pki/ca.key $ip:/etc/kubernetes/pki/ca.key
  scp /etc/kubernetes/pki/sa.key $ip:/etc/kubernetes/pki/sa.key
  scp /etc/kubernetes/pki/sa.pub $ip:/etc/kubernetes/pki/sa.pub
  scp /etc/kubernetes/pki/front-proxy-ca.crt $ip:/etc/kubernetes/pki/front-proxy-ca.crt
  scp /etc/kubernetes/pki/front-proxy-ca.key $ip:/etc/kubernetes/pki/front-proxy-ca.key
  scp /etc/kubernetes/pki/etcd/ca.crt $ip:/etc/kubernetes/pki/etcd/ca.crt
  scp /etc/kubernetes/pki/etcd/ca.key $ip:/etc/kubernetes/pki/etcd/ca.key
  scp /etc/kubernetes/admin.conf $ip:/etc/kubernetes/admin.conf
  scp /etc/kubernetes/admin.conf $ip:/home/tinychen/.kube/config
done
EOF

配置master21

编辑自定义配置文件

注意下面的ip地址和版本号需要根据实际情况来进行改动。

# 配置文件kubeadm_master21.conf

apiVersion: kubeadm.k8s.io/v1beta2
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 192.168.100.21
  bindPort: 6443
---
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
kubernetesVersion: v1.15.0
controlPlaneEndpoint: "kubernetes.haproxy.com:8443"
imageRepository: registry.aliyuncs.com/google_containers
apiServer:
  certSANs:
  - "master20"
  - "master21"
  - "master22"
  - 192.168.100.10
  - 192.168.100.20
  - 192.168.100.21
  - 192.168.100.22
networking:
  podSubnet: "10.244.0.0/16"
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes

etcd:
  local:
    extraArgs:
      listen-client-urls: "https://127.0.0.1:2379,https://192.168.100.21:2379"
      advertise-client-urls: "https://192.168.100.21:2379"
      listen-peer-urls: "https://192.168.100.21:2380"
      initial-advertise-peer-urls: "https://192.168.100.21:2380"
      initial-cluster: "master20=https://192.168.100.20:2380,master21=https://192.168.100.21:2380"
      initial-cluster-state: existing
    serverCertSANs:
      - master21
      - 192.168.100.21
    peerCertSANs:
      - master21
      - 192.168.100.21
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs

配置非root用户

前面我们在脚本那里已经创建好了文件夹,我们这里只需要修改权限和添加自动补全就好了。

sudo chown $(id -u):$(id -g)
 $HOME/.kube/config
# 添加kubectl的自动补全功能
echo "source <(kubectl completion bash)" >> ~/.bashrc

初始化

注意这里的文件名和IP地址要根据实际情况进行修改。

# 配置证书
kubeadm init phase certs all --config kubeadm_master21.conf
# 配置etcd
kubeadm init phase etcd local --config kubeadm_master21.conf
# 生成kubelet配置文件
kubeadm init phase kubeconfig kubelet --config kubeadm_master21.conf
# 启动kubelet
kubeadm init phase kubelet-start --config kubeadm_master21.conf

然后这一步要切换到非root用户

# 将master21的etcd加入集群
kubectl exec -n kube-system etcd-master20 -- 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://192.168.100.20:2379 member add master21 https://192.168.100.21:2380

# 启动 kube-apiserver、kube-controller-manager、kube-scheduler
kubeadm init phase kubeconfig all --config kubeadm_master21.conf
kubeadm init phase control-plane all --config kubeadm_master21.conf

# 将节点标记为master
kubeadm init phase mark-control-plane --config kubeadm_master21.conf

配置master22

编辑自定义配置文件

注意下面的ip地址和版本号需要根据实际情况来进行改动。

# 配置文件kubeadm_master22.conf

apiVersion: kubeadm.k8s.io/v1beta2
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 192.168.100.22
  bindPort: 6443
---
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
kubernetesVersion: v1.15.0
controlPlaneEndpoint: "kubernetes.haproxy.com:8443"
imageRepository: registry.aliyuncs.com/google_containers
apiServer:
  certSANs:
  - "master20"
  - "master21"
  - "master22"
  - 192.168.100.10
  - 192.168.100.20
  - 192.168.100.21
  - 192.168.100.22
networking:
  podSubnet: "10.244.0.0/16"
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes

etcd:
  local:
    extraArgs:
      listen-client-urls: "https://127.0.0.1:2379,https://192.168.100.22:2379"
      advertise-client-urls: "https://192.168.100.22:2379"
      listen-peer-urls: "https://192.168.100.22:2380"
      initial-advertise-peer-urls: "https://192.168.100.22:2380"
      initial-cluster: "master20=https://192.168.100.20:2380,master21=https://192.168.100.21:2380,master22=https://192.168.100.22:2380"
      initial-cluster-state: existing
    serverCertSANs:
      - master22
      - 192.168.100.22
    peerCertSANs:
      - master22
      - 192.168.100.22
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs

配置非root用户

前面我们在脚本那里已经创建好了文件夹,我们这里只需要修改权限和添加自动补全就好了。

sudo chown $(id -u):$(id -g)
 $HOME/.kube/config
# 添加kubectl的自动补全功能
echo "source <(kubectl completion bash)" >> ~/.bashrc

初始化

注意这里的文件名和IP地址要根据实际情况进行修改。

# 配置证书
kubeadm init phase certs all --config kubeadm_master22.conf
# 配置etcd
kubeadm init phase etcd local --config kubeadm_master22.conf
# 生成kubelet配置文件
kubeadm init phase kubeconfig kubelet --config kubeadm_master22.conf
# 启动kubelet
kubeadm init phase kubelet-start --config kubeadm_master22.conf

然后这一步要切换到非root用户

# 将master22的etcd加入集群

kubectl exec -n kube-system etcd-master20 -- 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://192.168.100.20:2379 member add master22 https://192.168.100.22:2380
# 启动 kube-apiserver、kube-controller-manager、kube-scheduler
kubeadm init phase kubeconfig all --config kubeadm_master22.conf
kubeadm init phase control-plane all --config kubeadm_master22.conf

# 将节点标记为master
kubeadm init phase mark-control-plane --config kubeadm_master22.conf

添加node节点

node节点的添加我们只需要切换到root用户执行之前master20初始化成功提示的指令即可。

kubeadm join kubernetes.haproxy.com:8443 --token m42q2v.y8sffomwkgjlhx8h \
    --discovery-token-ca-cert-hash sha256:1829cbaf37e968b43f91e6f0b65e2f2b7985a2d3d17ec66f3af70e0d15db01de 

查看最终效果

查看节点

查看pods

查看集群

kubectl exec -n kube-system etcd-master20 \
 -- 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://192.168.100.20:2379 member list

查看ipvs情况