Loading

第19章: kubeadm方式部署K8S1.20高可用集群


1  架构说明

1.1 生产环境可部署Kubernetes集群的两种方式

1 kubeadm部署

(1) Kubeadm是一个K8s部署工具,提供kubeadm initkubeadm join,用于快速部署Kubernetes集群。这里采用kubeadm搭建集群。

(2) kubeadm工具功能
kubeadm init # 初始化一个Master节点
kubeadm join # 将工作节点加入集群
kubeadm upgrade # 升级K8s版本
kubeadm token # 管理 kubeadm join 使用的令牌
kubeadm reset # 清空 kubeadm init 或者 kubeadm join 对主机所做的任何更改
kubeadm version # 打印 kubeadm 版本
kubeadm alpha # 
预览可用的新功能

 

2 二进制包部署

github下载发行版的二进制包,手动部署每个组件,组成Kubernetes集群。

1.2 准备环境

1 服务器要求

建议最小硬件配置: 2CPU2G内存、30G硬盘
服务器最好可以访问外网,会有从网上拉取镜像需求,如果服务器不能上网,需要提前下载对应镜像并导入节点

 

2 服务器规划

操作系统: CentOS7.5

主机名

IP

软件

VIP

k8s-master1

(24G)

主网卡: 172.16.1.81
副网卡:
10.0.0.81

docker-ce-19.03.9kubernetes-1.20etcd(etcd-1)nginx + keepalived(master)

 

 

172.16.1.80

 

 

k8s-master2

(24G)

主网卡: 172.16.1.82
副网卡:
10.0.0.82

docker-ce-19.03.9kubernetes-1.20etcd(etcd-2)nginx + keepalived(backup)

k8s-node1

(48G)

主网卡: 172.16.1.83
副网卡:
10.0.0.83

docker-ce-19.03.9kubernetes-1.20etcd(etcd-3)

 

 

(1) 为了节省机器,etcd集群与K8s节点机器复用,也可以独立于k8s集群之外部署,只

apiserver能连接到就行。

(2) 为了节省机器,nginx+keepalivedK8s master节点机器复用,也可以独立于k8s

群之外部署,只要nginxapiserver能通信就行。

 

 

 

3 架构图

wps1 

1.3 操作系统初始化配置

172.16.1.81-83节点上操作

(1) 关闭防火墙
# systemctl stop firewalld
# systemctl disable firewalld

(2) 关闭selinux
# sed -i 's/enforcing/disabled/' /etc/selinux/config  # 永久
# setenforce 0  # 临时

(3) 关闭swap
# swapoff -a  # 临时
# sed -ri 's/.*swap.*/#&/' /etc/fstab    # 永久

(4) master添加hosts
cat >> /etc/hosts << EOF
172.16.1.81 k8s-master1
172.16.1.82 k8s-master2
172.16.1.83 k8s-node1
EOF

(5) 将桥接的IPv4流量传递到iptables的链
# cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
# sysctl --system  # 生效,手动加载所有的配置文件

(6) 时间同步
# yum install ntpdate -y
# ntpdate ntp.aliyun.com
# crontab -e
# crontab -l
*/5 * * * * /usr/sbin/ntpdate ntp.aliyun.com &>/dev/null

(7) 部署docker
这里使用Docker作为容器引擎,也可以换成别的,例如containerd
1) 安装依赖包
# yum install -y yum-utils device-mapper-persistent-data lvm2
2) 添加Docker软件包源
# yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
3) 更新为阿里云的源
# wget -O /etc/yum.repos.d/docker-ce.repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
4) 清理源缓存
# yum clean all
5) 安装指定版本的Docker CE
# yum list docker-ce --showduplicates | sort -r
# yum list docker-ce-cli --showduplicates | sort -r
# yum install docker-ce-19.03.9-3.el7 docker-ce-cli-19.03.9-3.el7 -y
6) 启动Docker服务并设置开机启动
# systemctl start docker
# systemctl enable docker
# docker version  # 可以看到docker客户端和服务端都是同一个版本
# docker info
7) 添加阿里云的镜像仓库
# mkdir -p /etc/docker
# tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://b1cx9cn7.mirror.aliyuncs.com"]
}
EOF
8) 重启docker
# systemctl daemon-reload
# systemctl restart docker

(8) 增加 iptables conntrack 表大小,防止iptables
性能不佳
参考网站: https://docs.projectcalico.org/maintenance/troubleshoot/troubleshooting#configure-networkmanager
# sysctl -w net.netfilter.nf_conntrack_max=1000000
# echo "net.netfilter.nf_conntrack_max=1000000" >> /etc/sysctl.conf

2 部署Nginx+Keepalived高可用负载均衡器

172.16.1.81-82节点上操作

(1) Kubernetes作为容器集群系统,通过健康检查+重启策略实现了Pod故障自我修复能力,通过调度算法实现将Pod分布式部署,并保持预期副本数,根据Node失效状态自动在其他Node拉起Pod,实现了应用层的高可用性。
(2) 针对Kubernetes集群,高可用性还应包含以下两个层面的考虑:Etcd数据库的高可用性和Kubernetes Master组件的高可用性。而kubeadm搭建的K8s集群Etcd只起了一个,存在单点,所以我们这里会独立搭建一个Etcd集群。
(3) Master节点扮演着总控中心的角色,通过不断与工作节点上的Kubeletkube-proxy进行通信来维护整个集群的健康工作状态。如果Master节点故障,将无法使用kubectl工具或者API做任何集群管理。
(4) Master节点主要有三个服务kube-apiserverkube-controller-managerkube-scheduler,其中kube-controller-managerkube-scheduler组件自身通过选择机制已经实现了高可用,所以Master高可用主要针对kube-apiserver组件,而该组件是以HTTP API提供服务,因此对他高可用与Web服务器类似,增加负载均衡器对其负载均衡即可,并且可水平扩容。
(5) kube-apiserver高可用架构图:

wps2 

(6) Nginx是一个主流Web服务和反向代理服务器,这里用四层实现对apiserver实现负载均衡
Keepalived是一个主流高可用软件,基于VIP绑定实现服务器双机热备,在上述拓扑中,Keepalived主要根据Nginx运行状态判断是否需要故障转移(偏移VIP),例如当Nginx主节点挂掉,VIP会自动绑定在Nginx备节点,从而保证VIP一直可用,实现Nginx高可用

2.1 安装软件包

# yum install epel-release -y
# yum install nginx keepalived -y

2.2 Nginx配置文件

# cat > /etc/nginx/nginx.conf << "EOF"
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

# 四层负载均衡,为两台Master apiserver组件提供负载均衡
stream {

    log_format  main  '$remote_addr $upstream_addr - [$time_local] $status $upstream_bytes_sent';

    access_log  /var/log/nginx/k8s-access.log  main;

    upstream k8s-apiserver {
       server 172.16.1.81:6443;   # Master1 APISERVER IP:PORT
       server 172.16.1.82:6443;   # Master2 APISERVER IP:PORT
    }
   
    server {
       listen 16443;  # 由于nginxmaster节点复用,这个监听端口不能是6443,否则会冲突
       proxy_pass k8s-apiserver;
    }
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    server {
        listen       80 default_server;
        server_name  _;

        location / {
        }
    }
}
EOF

(1) 验证 nginx配置文件是否正确
# nginx -t
nginx: [emerg] unknown directive "stream" in /etc/nginx/nginx.conf:13
nginx: configuration file /etc/nginx/nginx.conf test failed
# 报错提示找不到stream这个模块

(2) 解决办法
# yum install nginx-mod-stream -y
# cat /usr/share/nginx/modules/mod-stream.conf
load_module "/usr/lib64/nginx/modules/ngx_stream_module.so";
# nginx 配置文件已经加载了stream模块,nginx -t 验证配置文件就不会报错了。

2.3 keepalived配置文件(NginxMaster)

172.16.1.81节点上操作

# cat > /etc/keepalived/keepalived.conf << EOF
global_defs {
   notification_email {
     acassen@firewall.loc
     failover@firewall.loc
     sysadmin@firewall.loc
   }
   notification_email_from Alexandre.Cassen@firewall.loc
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id NGINX_MASTER
}

vrrp_script check_nginx {
    script "/etc/keepalived/check_nginx.sh"
}

vrrp_instance VI_1 {
    #state MASTER
    state BACKUP  # 指定实例初始状态,实际的MASTERBACKUP是选举决定的
    nopreempt       # 设置master恢复后为不抢占VIP资源
    interface eth1  # 修改为实际网卡名
    virtual_router_id 51 # VRRP 路由 ID实例,每个实例是唯一的
    priority 100    # 优先级,备服务器设置 90
    advert_int 1    # 指定VRRP 心跳包通告间隔时间,默认1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    # 虚拟IP
    virtual_ipaddress {
        172.16.1.80/24
    }
    track_script {
        check_nginx
    }
}
EOF

notification_email # 设置报警邮件地址即报警邮件接收者,可设置多个,每行一个;如果要开启邮件报警功能,需要开启本机的postfix或者sendmail服务;

notification_email_from # 用于设置邮件的发送地址,即报警邮件发送者;

smtp_server # 用于设置邮件的SMTP Server地址;

smtp_connect_timeout # 设置连接SMTP Server的超时时间;

router_id # 表示运行keepalived服务器的一个标识,是发邮件时显示在邮件主题中的信息;

vrrp_script # 指定检查nginx工作状态脚本(根据nginx状态判断是否故障转移)

virtual_ipaddress # 虚拟IP(VIP)

nopreempt # 通常如果master服务死掉后backup会变成master,但是当master服务又好了的时候master此时会抢占VIP,这样就会发生两次切换对业务繁忙的网站来说是不好的。所以我们要在Master节点配置文件加入nopreempt非抢占,但是这个参数只能用于statebackup,故我们在用HA的时候最好masterbackupstate都设置成backup让其通过priority(优先级)来竞争。

 

检查nginx运行状态的脚本

# cat > /etc/keepalived/check_nginx.sh  << "EOF"
#!/bin/bash
count=$(ss -antp |grep 16443 |egrep -cv "grep|$$")

if [ "$count" -eq 0 ];then
    exit 1
else
    exit 0
fi
EOF

# chmod +x /etc/keepalived/check_nginx.sh

: 
keepalived根据脚本返回状态码(0为工作正常,非0不正常)判断是否故障转移。

2.4 keepalived配置文件(NginxBackup)

172.16.1.82节点上操作

# cat > /etc/keepalived/keepalived.conf << EOF
global_defs {
   notification_email {
     acassen@firewall.loc
     failover@firewall.loc
     sysadmin@firewall.loc
   }
   notification_email_from Alexandre.Cassen@firewall.loc
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id NGINX_BACKUP
}

vrrp_script check_nginx {
    script "/etc/keepalived/check_nginx.sh"
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth1
    virtual_router_id 51 # VRRP 路由 ID实例,每个实例是唯一的
    priority 90
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        172.16.1.80/24
    }
    track_script {
        check_nginx
    }
}
EOF

 

配置检查nginx运行状态的脚本

# cat > /etc/keepalived/check_nginx.sh  << "EOF"
#!/bin/bash
count=$(ss -antp |grep 16443 |egrep -cv "grep|$$")

if [ "$count" -eq 0 ];then
    exit 1
else
    exit 0
fi
EOF

#
chmod +x /etc/keepalived/check_nginx.sh

2.5 启动并设置开机启动

# systemctl start nginx
# systemctl start keepalived
# systemctl enable nginx
# systemctl enable keepalived

: 
因为nginx为无状态应用,keepalived可以做开机自启动。如果做的是有状态应用的高可用,

keepalived不要设置开机自启动,防止主从切换问题。

2.6 查看keepalived工作状态

(1) 172.16.1.81 (NginxMaster)节点
[root@k8s-master1 ~]# systemctl status keepalived.service
wps3

[root@k8s-master1 ~]# ip addr
wps4

(2) 172.16.1.82(NginxBackup)节点
[root@k8s-master2 ~]# systemctl status keepalived.service
wps5

[root@k8s-master2 ~]# ip addr
wps6

(3) 通过keepalived状态可以看到,172.16.1.81节点的eth1网卡绑定了虚拟IP 172.16.1.80172.16.1.82节点的状态为BACKUP。说明Keepalived+N
ginx高可用配置正常。

2.7 Nginx+Keepalived高可用测试

1 杀掉172.16.1.81(NginxMaster)节点上的nginx进程

[root@k8s-master1 ~]# systemctl stop nginx
[root@k8s-master1 ~]# systemctl status keepalived.service
wps7
# keepalived释放vip

[root@k8s-master1 ~]#
ip addr
wps8

 

2 172.16.1.82(NginxBackup)上查看VIP已经成功绑定到eth1网卡

[root@k8s-master2 ~]# systemctl status keepalived.service
wps9
# eth1成功绑定vip

[root@k8s-master2 ~]# ip
addr
wps10

 

3 启动172.16.1.81(NginxMaster)节点上的nginx,发现keepalived变为BACKUP状态

[root@k8s-master1 ~]# systemctl start nginx
[root@k8s-master1 ~]# systemctl status keepalived.service
wps11

[root@k8s-master1 ~]# ip
addr
wps12

 

4 同理,当172.16.1.82(NginxBackup)节点nginx进程停止后会释放VIP资源,同时172.16.1.81(NginxMaster)节点会重新接管VIP资源。当172.16.1.82(NginxBackup)节点nginx启动后其keepalived状态会变为BACKUP状态。

3 部署Etcd集群

172.16.1.81-83节点上操作

 

Etcd是一个分布式键值存储系统,Kubernetes使用Etcd进行数据存储,kubeadm搭建默认情况下只启动一个Etcd Pod,存在单点故障,生产环境强烈不建议,所以我们这里使用3台服务器组建集群,可容忍1台机器故障,当然,你也可以使用5台组建集群,可容忍2台机器故障。

3.1 准备cfssl证书生成工具

172.16.1.81节点上操作

cfssl是一个开源的证书管理工具,使用json文件生成证书,相比openssl更方便使用。

# wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
# wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
# wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
# chmod +x cfssl_linux-amd64 cfssljson_linux-amd64 cfssl-certinfo_linux-amd64
# mv cfssl_linux-amd64 /usr/local/bin/cfssl
# mv cfssljson_linux-amd64 /usr/local/bin/cfssljson
# mv cfssl-certinfo_linux-amd64 /usr/bin/cfssl-certinfo

3.2 生成Etcd证书

172.16.1.81节点上操做

1 创建工作目录

# mkdir -p /root/etcd_tls/
# cd /root/etcd_tls/

 

2 自签证书颁发机构(CA)

(1) 自签CA属性配置文件
# cat > ca-config.json << EOF
{
  "signing": {
    "default": {
      "expiry": "876000h"
    },
    "profiles": {
      "server": {
         "expiry": "876000h",
         "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ]
      }
    }
  }
}
EOF

(2) 自签CA生成配置文件
# cat > ca-csr.json << EOF
{
    "CN": "etcd CA",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "Beijing",
            "ST": "Beijing"
        }
    ]
}
EOF

: "CN": "etcd CA" 表示证书颁发机构(CA)的名称。

(3) 生成CA
# cfssl gencert -initca ca-csr.json | cfssljson -bare ca
wps13
生成以ca开头证书颁发机构(CA)的文件有ca.csrca-key.pem
ca.pem

 

2 使用自签CA签发Etcd HTTPS证书

(1) 创建证书申请文件(CSR)
cat > etcd-csr.json << EOF
{
    "CN": "etcd",
    "hosts": [
    "172.16.1.81",
    "172.16.1.82",
    "172.16.1.83"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "BeiJing",
            "ST": "BeiJing"
        }
    ]
}
EOF

:
1) 上述文件hosts字段中IP为所有etcd节点的集群内部通信IP,一个都不能少,为了方便后
期扩容可以多写几个预留的IP
2) "CN": "etcd" 表示CA签发Etcd HTTPS证书的域名。

(2) 生成证书
# cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server etcd-csr.json | cfssljson -bare etcd
wps14
生成以etcd开头的文件etcd.csretcd-key.pemetcd.pem

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

3 验证CA签发的Etcd HTTPS证书etcd.pem

验证网站: https://myssl.com/cert_decode.html
验证信息如下:
wps15

3.3 Github下载Etcd二进制文件

# 下载地址
https://github.com/etcd-io/etcd/releases/download/v3.5.0/etcd-v3.5.0-linux-amd64.tar.gz

3.4 部署Etcd集群

1 创建工作目录并解压二进制包

# mkdir -p /usr/local/etcd/{bin,cfg,ssl,default.etcd}
# tar -xzf etcd-v3.5.0-linux-amd64.tar.gz
# cp -a etcd-v3.5.0-linux-amd64/{etcd,etcdctl} /usr/local/etcd/bin/
# useradd -M -s /sbin/nologin etcd
# id etcd
uid=1000(etcd) gid=1000(etcd) groups=1000(etcd)
#
chown -R etcd.etcd /usr/local/etcd/

 

2 创建etcd配置文件

cat > /usr/local/etcd/cfg/etcd.conf << EOF
#[Member]
ETCD_NAME="etcd-1"
# 节点名称,集群中唯一,172.16.1.81-83节点名分别为etcd-1etcd-2etcd-3
ETCD_DATA_DIR="/usr/local/etcd/default.etcd"
# 数据目录
ETCD_LISTEN_PEER_URLS="https://172.16.1.81:2380"
# 集群通信监听地址,172.16.1.81-83节点分别为各自的IP
ETCD_LISTEN_CLIENT_URLS="https://172.16.1.81:2379"
# 客户端访问监听地址,172.16.1.81-83节点分别为各自的IP

#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://172.16.1.81:2380"
# 集群通告地址,172.16.1.81-83节点分别为各自的IP
ETCD_ADVERTISE_CLIENT_URLS="https://172.16.1.81:2379"
# 客户端通告地址,172.16.1.81-83节点分别为各自的IP
ETCD_INITIAL_CLUSTER="etcd-1=https://172.16.1.81:2380,etcd-2=https://172.16.1.82:2380,etcd-3=https://172.16.1.83:2380"
# 集群节点地址,172.16.1.81-83节点的IP
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
# 集群Token
ETCD_INITIAL_CLUSTER_STATE="new"
# 
加入集群的当前状态,new是新集群,existing表示加入已有集群
EOF

 

3 systemd管理etcd

cat > /usr/lib/systemd/system/etcd.service << EOF
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
EnvironmentFile=/usr/local/etcd/cfg/etcd.conf
ExecStart=/usr/local/etcd/bin/etcd \
--cert-file=/usr/local/etcd/ssl/etcd.pem \
--key-file=/usr/local/etcd/ssl/etcd-key.pem \
--peer-cert-file=/usr/local/etcd/ssl/etcd.pem \
--peer-key-file=/usr/local/etcd/ssl/etcd-key.pem \
--trusted-ca-file=/usr/local/etcd/ssl/ca.pem \
--peer-trusted-ca-file=/usr/local/etcd/ssl/ca.pem \
--logger=zap

ExecReload=/bin/kill -HUP "\$MAINPID"
KillMode=process
Restart=on-failure
LimitNOFILE=65536
User=etcd
Group=etcd

[Install]
WantedBy=multi-user.target
EOF

 

4 拷贝生成的证书

172.16.1.81节点上操作

# cp -a /root/etcd_tls/ca.pem /root/etcd_tls/etcd*pem /usr/local/etcd/ssl/
# scp -p -P 22 /root/etcd_tls/ca.pem /root/etcd_tls/etcd*pem root@172.16.1.82:/usr/local/etcd/ssl/
# scp -p -P 22 /root/etcd_tls/ca.pem /root/etcd_tls/etcd*pem root@172.16.1.83:
/usr/local/etcd/ssl/

 

5 启动并设置开机启动

# systemctl daemon-reload
# systemctl start etcd
# systemctl enable etcd

 

6 查看集群状态

172.16.1.81-83上任意一个节点上都可以查看

# ETCDCTL_API=3 /usr/local/etcd/bin/etcdctl --cacert=/usr/local/etcd/ssl/ca.pem \
--cert=/usr/local/etcd/ssl/etcd.pem \
--key=/usr/local/etcd/ssl/etcd-key.pem \
--endpoints="https://172.16.1.81:2379,https://172.16.1.82:2379,https://172.16.1.83:2379" \
endpoint health --write-out=table

wps16

: 
如果输出上面信息,就说明集群部署成功。如果有问题第一步先看日志:"/var/log/message""journalctl -u etcd"

4 安装kubeadm/kubelet/kubectl

172.16.1.81-83节点上操作

4.1 添加阿里云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=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

# yum clean all
#
yum makecache

4.2 安装

由于版本更新频繁,这里指定版本号部署

# yum install kubelet-1.20.0 kubeadm-1.20.0 kubectl-1.20.0 -y
# systemctl enable kubelet.service

5 部署Kubernetes Master

172.16.1.81-82节点上操作

5.1 初始化Master1

172.16.1.81节点上操作

1 生成初始化配置文件

[root@k8s-master1 ~]# cat > kubeadm-config.yaml << EOF
apiVersion: kubeadm.k8s.io/v1beta2
bootstrapTokens:
- groups:
  - system:bootstrappers:kubeadm:default-node-token
  token: 9037x2.tcaqnpaqkra9vsbw
  ttl: 24h0m0s
  usages:
  - signing
  - authentication
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 172.16.1.81
  bindPort: 6443
nodeRegistration:
  criSocket: /var/run/dockershim.sock
  name: k8s-master1
  taints:
  - effect: NoSchedule
    key: node-role.kubernetes.io/master
---
apiServer:
  certSANs:  # 包含所有Master/LB/VIP IP,一个都不能少为了方便后期扩容可以多写几个预留的IP
  - k8s-master1
  - k8s-master2
  - 172.16.1.81
  - 10.0.0.81
  - 172.16.1.82
  - 10.0.0.82
  - 172.16.1.80
  - 127.0.0.1
  extraArgs:
    authorization-mode: Node,RBAC
  timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta2
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controlPlaneEndpoint: 172.16.1.80:16443 # 负载均衡虚拟IPVIP)和端口
controllerManager: {}
dns:
  type: CoreDNS
etcd:
  external:  # 使用外部etcd
    endpoints:
    - https://172.16.1.81:2379 # etcd集群3个节点
    - https://172.16.1.82:2379
    - https://172.16.1.83:2379
    caFile: /usr/local/etcd/ssl/ca.pem # 连接etcd所需证书
    certFile: /usr/local/etcd/ssl/etcd.pem
    keyFile: /usr/local/etcd/ssl/etcd-key.pem
imageRepository: registry.aliyuncs.com/google_containers # 由于默认拉取镜像地址k8s.gcr.io国内无法访问,这里指定阿里云镜像仓库地址
kind: ClusterConfiguration
kubernetesVersion: v1.20.0 # K8s版本,与上面安装的一致
networking:
  dnsDomain: cluster.local
  podSubnet: 10.244.0.0/16  # Pod网络,与下面部署的CNI网络组件yaml中保持一致
  serviceSubnet: 10.96.0.0/12  # 集群内部虚拟网络,Pod统一访问入口
scheduler: {}
EOF

 

2 使用配置文件进行初始化

(1) 进行初始化
[root@k8s-master1 ~]# kubeadm init --config kubeadm-config.yaml

(2) 初始化出现警告
1)
警告内容
[WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/
2) 原因
表示,更改设置,令容器运行时和kubelet使用systemd作为cgroup驱动,以此使系统更为稳定。 请注意在docker下设置native.cgroupdriver=systemd选项。
3) 解决办法
方法1:
编辑"/etc/docker/daemon.json"文件,追加"exec-opts"配置。
{
  "exec-opts": ["native.cgroupdriver=systemd"]
}
方法2:
编辑"/usr/lib/systemd/system/docker.service"文件,在ExecStart后追加
"--exec-opt native.cgroupdriver=systemd"
配置。
4) 使配置生效
# systemctl daemon-reload.service
# systemctl restart docker.service
5) 验证
# docker info | grep Cgroup
Cgroup Driver: systemd
: 验证成功,不要忘记在docker各个节点上都要做配置

(3) 清空kubeadm init 所做的更改
[root@k8s-master1 ~]# kubeadm reset

(4) 重新进行初始化
[root@k8s-master1 ~]#  kubeadm init --config kubeadm-config.yaml

……(省略的日志
)
Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

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

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

You can now join any number of control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:

  kubeadm join 172.16.1.80:16443 --token 9037x2.tcaqnpaqkra9vsbw \
    --discovery-token-ca-cert-hash sha256:a5669a292020ec7facec1584461ffe6c18791e721c4e1d135a11970897fbcfc7 \
    --control-plane 

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 172.16.1.80:16443 --token 9037x2.tcaqnpaqkra9vsbw \
--discovery-token-ca-cert-hash sha256:a5669a292020ec7facec1584461ffe6c18791e721c4e1d135a11970897fbcfc7


: 初始化完成后,会有两个join的命令,带有"--control-plane"是用于加入组建多master
群的,不带的是加入节点的。

 

3 拷贝kubectl使用的连接k8s认证文件到默认路径

[root@k8s-master1 ~]# mkdir -p $HOME/.kube
[root@k8s-master1 ~]# cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@k8s-master1 ~]# chown $(id -u):$(id -g) $HOME/.kube/config
[root@k8s-master1 ~]# kubectl get node
NAME          STATUS     ROLES                  AGE   VERSION
k8s-master1   NotReady   control-plane,master   45m   v1.20.0

5.2 初始化Master2

172.16.1.82节点上操作

1 Master1节点生成的证书拷贝到Master2

[root@k8s-master2 ~]# scp -rp -P 22 root@172.16.1.81:/etc/kubernetes/pki /etc/kubernetes/

 

2 复制加入master1初始化时输出的join命令在master2执行

[root@k8s-master2 ~]# kubeadm join 172.16.1.80:16443 --token 9037x2.tcaqnpaqkra9vsbw \
--discovery-token-ca-cert-hash sha256:a5669a292020ec7facec1584461ffe6c18791e721c4e1d135a11970897fbcfc7 \
--control-plane

……(省略的日志)
This node has joined the cluster and a new control plane instance was created:

* Certificate signing request was sent to apiserver and approval was received.
* The Kubelet was informed of the new secure connection details.
* Control plane (master) label and taint were applied to the new node.
* The Kubernetes control plane instances scaled up.


To start administering your cluster from this node, you need to run the following as a regular user:

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

Run 'kubectl get nodes' to see this node join the cluster.

 

3 拷贝kubectl使用的连接k8s认证文件到默认路径

[root@k8s-master2 ~]# mkdir -p $HOME/.kube
[root@k8s-master2 ~]# cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@k8s-master2 ~]# chown $(id -u):$(id -g) $HOME/.kube/config
[root@k8s-master2 ~]#
kubectl get node
NAME          STATUS     ROLES                  AGE    VERSION
k8s-master1   NotReady   control-plane,master   105m   v1.20.0
k8s-master2   NotReady   control-plane,master   101m   v1.20.0

注:由于网络插件还没有部署,还没有准备就绪 NotReady

5.3 访问负载均衡器测试

K8s集群中任意一个节点,使用curl查看K8s版本测试,使用VIP访问

这里在172.16.1.83节点上测试

[root@k8s-node1 ~]# curl -k https://172.16.1.80:16443/version
{
  "major": "1",
  "minor": "20",
  "gitVersion": "v1.20.0",
  "gitCommit": "af46c47ce925f4c4ad5cc8d1fca46c7b77d13b38",
  "gitTreeState": "clean",
  "buildDate": "2020-12-08T17:51:19Z",
  "goVersion": "go1.15.5",
  "compiler": "gc",
  "platform": "linux/amd64"
}

 

可以正确获取到K8s版本信息,说明负载均衡器搭建正常。

该请求数据流程为: curl->vip(nginx)->apiserver,通过

查看Nginx日志也可以看到转发apiserver IP

通过"systemctl status keepalived"命令得知VIPmaster1(172.16.1.81)节点上。
[root@k8s-master1 ~]# tail /var/log/nginx/k8s-access.log -f
172.16.1.83 172.16.1.81:6443 - [21/Aug/2021:16:48:49 +0800] 200 419
172.16.1.83 172.16.1.82:6443 - [21/Aug/2021:16:48:50 +0800] 200 419
172.16.1.83 172.16.1.81:6443 - [21/Aug/2021:16:48:50 +0800] 200 419

6 加入Kubernetes Node

172.16.1.83(k8s-node1)节点上操作

向集群添加新节点,执行在kubeadm init输出的kubeadm join命令

[root@k8s-node1 ~]# kubeadm join 172.16.1.80:16443 --token 9037x2.tcaqnpaqkra9vsbw \
--discovery-token-ca-cert-hash sha256:a5669a292020ec7facec1584461ffe6c18791e721c4e1d135a11970897fbcfc7

……(省略的日志)
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

后续其他节点也是这样加入。默认token有效期为24小时,当过期之后,该token就不可用了。

这时就需要重新创建token,可以直接使用命令快捷生成: kubeadm token create --print-join-command

7 部署网络组件

master1master2节点上操作都可,我这里在172.16.1.81节点上操作

7.1 网络通信机制

k8s中的网络主要涉及到pod的各种访问需求,如同一pod的内部(单容器或者多容器)
信、pod Apod B的通信、从外部网络访问pod以及从pod访问外部网络。k8s的网络
基于第三方插件实现,该规范有CoreOSGoogle联合定制,叫做CNI(Container Network
Interface)。目前常用的的CNI网络插件有calicoflannel

7.2 calico简介

1 calico是一个纯三层的网络解决方案,为容器提供多node间的访问通信,calico将每一个
node节点都当做为一个路由器(router),各节点通过BGP(Border Gateway Protocol) 边界
网关协议学习并在node节点生成路由规则,从而将不同node节点上的pod连接起来进
行通信,是目前Kubernetes主流的网络方案。

2 BGP是一个去中心化的协议,它通过自动学习和维护路由表实现网络的可用性,但是并不
是所有的网络都支持BGP,另外为了跨网络实现更大规模的网络管理,calico 还支持IP-in-IP
的叠加模型,简称IPIPIPIP可以实现跨不同网段建立路由通信,但是会存在安全性问题,其
在内核内置,可以通过Calico的配置文件设置是否启用IPIP,在公司内部如果k8snode
点没有跨越网段建议关闭IPIP,默认IPIP
为启用。

7.3 部署Calico

1 由于我采用了https来安装etcd,所以要下载支持httpsyaml文件

(1) 官方文档
https://docs.projectcalico.org/getting-started/kubernetes/self-managed-onprem/onpremises

(2) 下载
# wget https://docs.projectcalico.org/manifests/calico-etcd.yaml
# 我这里使用的版本为3
.20.0

 

2修改calico-etcd.yaml文件

(1) 修改secret
wps17

(2) 修改etcd数据库地址及认证证书路径
wps18

(3) 修改集群网段
wps19

(4) 
添加calico环境变量的配置
wps20


- name: KUBERNETES_SERVICE_HOST
  value: "172.16.1.80"
- name: KUBERNETES_SERVICE_PORT
  value: "16443"
- name: KUBERNETES_SERVICE_PORT_HTTPS
  value: "16443"

 

3 部署

[root@k8s-master1 ~]# kubectl apply -f calico.yaml
[root@k8s-master1 ~]#
kubectl get pods -n kube-system

 

4 查看Calico Pod都为Running

[root@k8s-master1 ~]# kubectl get pod -A -o wide
wps21

 

5 补充

(1) 后续如果发生异常时,可以用到的命令
1) 查看pod产生的日志
# kubectl logs -f <PodName> -n kube-system
2) 查看pod的具体描述
# kubectl describe pod  <PodName> -n kube-system
3) 查看集群环境输出
# kubectl get ev -n kube-system

(2) coredns pod起不来
1)
查看pod描述信息,报错如下
network for pod "coredns-7f89b7bc75-bspm8": networkPlugin cni failed to set up pod "coredns-7f89b7bc75-bspm8_kube-system" network: stat /var/lib/calico/nodename: no such file or directory: check that the calico/node container is running and has mounted /var/lib/calico/
2) 报错原因
calico pod正常运行时会在宿主机上生成路径为"/var/lib/calico/nodename"的文件,如果
calico pod没有正常运行,会导致coredns pod无法挂载宿主机上的"/var/lib/calico/"卷。
3) 解决办法
calico pod 运行正常的情况下删除coredns pod,让coredns 
pod自动创建新的。

 

6 节点准备就绪

[root@k8s-master1 ~]# kubectl get node
wps22

8 部署 Dashboard

master1master2节点上操作都可,我这里在172.16.1.81节点上操作

8.1 说明

Dashboard是官方提供的一个UI,可用于基本管理K8s资源。

 

1 官方文档

https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/

 

2 gitlab项目地址

https://github.com/kubernetes/dashboard

 

3 版本兼容

https://github.com/kubernetes/dashboard/releases/tag/v2.3.1
wps23

4 下载

# wget -O kubernetes-dashboard.yaml \
https://raw.githubusercontent.com/kubernetes/dashboard/v2.3.1/aio/deploy/recommended.yaml

8.2 部署

1 修改kubernetes-dashboard.yaml配置

由于默认kubernetes-dashboard只能集群内部访问,因此修改ServiceNodePort类型,暴露
k8s集群外部进行访问。
wps24

 

2 应用kubernetes-dashboard.yaml

[root@k8s-master1 ~]# kubectl apply -f kubernetes-dashboard.yaml
# 查看pod状态
[root@k8s-master1 ~]# kubectl get pod -n kubernetes-dashboard -o wide
wps25

: kubernetes dashboard pod运行正常,访问地址: 
https://NodeIP:30001

 

3 创建访问dashboard的token

(1) 创建serviceaccount并赋权
1) kube-system命名空间中创建serviceaccount/dashboard-admin
# kubectl create serviceaccount dashboard-admin -n kube-system
2) 绑定kube-system命名空间中serviceaccount/dashboard-admin到集群角色cluster-admin
# kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin \
--serviceaccount=kube-system:dashboard-admin

(2) 获取访问token
1) 获取kube-system命名空间中serviceaccount/dashboard-adminsecrets名称
# kubectl describe serviceaccount dashboard-admin -n kube-system



wps26

2) 获取kube-system命名空间中secrets/dashboard-admin-token-ld7hk登录k8s集群的token
# kubectl describe secrets dashboard-admin-token-ld7hk -n kube-system

3) 补充: 一条命令获取token
# kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret | awk '/dashboard-admin/{print $1}')

8.3 token登录Dashboard

wps27 

https://kubernetes.io/docs/reference/access-authn-authz/authentication/

wps28 

9 补充

自此使用kubeadm方式部署K8S1.20高可用集群就完成了。

9.1 master1节点查看k8s集群中所有的pod

172.16.1.81节点

[root@k8s-master1 ~]# kubectl get pod -A -o wide

wps29 

9.2 master2节点查看k8s集群中所有的pod

172.16.1.82节点

[root@k8s-master2 ~]# kubectl get pod -A -o wide

wps30 

 

 

 

 

 

 

 

posted @ 2021-08-24 16:55  云起时。  阅读(2028)  评论(0编辑  收藏  举报