前置条件
安装准备工作需要在所有节点执行,基于KVM部署,可配置一台机器后作为模板来创建其他节点,具体参考:平台建设之基于Virsh工具管理KVM。

所有操作以root账户进行!

设置主机名

  • 设置Hostname

[root@K8S-PROD-M1 ~]# vi /etc/hostname
K8S-PROD-M1

hostnamectl --static set-hostname K8S-PROD-M1 //重新登陆即可生效


* 修改Host,解决主机名解析问题

[root@K8S-PROD-M1 ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain
::1 localhost6 localhost6.localdomain6 localhost6.localdomain

192.168.122.11 K8S-PROD-M1
192.168.122.12 K8S-PROD-M2
192.168.122.13 K8S-PROD-M3
192.168.122.21 K8S-PROD-W1
192.168.122.22 K8S-PROD-W2
192.168.122.23 K8S-PROD-W3
192.168.122.31 K8S-PROD-LB1
192.168.122.32 K8S-PROD-LB2


* 修改Host,添加私有Harbor域名解析

[root@K8S-PROD-M1 ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain
::1 localhost6 localhost6.localdomain6 localhost6.localdomain

192.168.122.11 K8S-PROD-M1
192.168.122.12 K8S-PROD-M2
192.168.122.13 K8S-PROD-M3
192.168.122.21 K8S-PROD-W1
192.168.122.22 K8S-PROD-W2
192.168.122.23 K8S-PROD-W3
192.168.122.31 K8S-PROD-LB1
192.168.122.32 K8S-PROD-LB2

192.168.122.90 harbor.cluster.local


注意: 如果部署时已经有私有Harbor,则添加,没有可不配置。

**设置防火墙**
**禁用防火墙、SELinux**

systemctl disable --now firewalld NetworkManager
setenforce 0

sed -i 's@^(SELINUX=).@\1disabled@' /etc/selinux/config
sed -i 's/SELINUX=.
/SELINUX=disabled/g' /etc/selinux/config
sed -ri '/^[^#]*SELINUX=/s#=.+$#=disabled#' /etc/selinux/config

firewall-cmd --state


**防火墙开启状态下设置**
**Master节点需要开放的端口**
![](https://s4.51cto.com/images/blog/202103/13/1db994a412081aebe1548e7dcf672f38.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
![](https://s4.51cto.com/images/blog/202103/13/514a97bd1ad01f532c56f8cf8acd96b0.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

k8s-export-port .png
**Worker节点需要开放的端口**
![](https://s4.51cto.com/images/blog/202103/13/ac5a51e63afe14b4c4291ce282adf088.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

**所有节点开启firewalld防火墙**

systemctl enable firewalld
systemctl restart firewalld
systemctl status firewalld


**所有Master节点设置防火墙策略**

开放端口策略

$ firewall-cmd --zone=public --add-port=16443/tcp --permanent
$ firewall-cmd --zone=public --add-port=6443/tcp --permanent
$ firewall-cmd --zone=public --add-port=4001/tcp --permanent
$ firewall-cmd --zone=public --add-port=2379-2380/tcp --permanent
$ firewall-cmd --zone=public --add-port=10250/tcp --permanent
$ firewall-cmd --zone=public --add-port=10251/tcp --permanent
$ firewall-cmd --zone=public --add-port=10252/tcp --permanent
$ firewall-cmd --zone=public --add-port=30000-32767/tcp --permanent
$ firewall-cmd --reload

查看端口开放状态

$ firewall-cmd --list-all --zone=public
public (active)
target: default
icmp-block-inversion: no
interfaces: ens2f1 ens1f0 nm-bond
sources:
services: ssh dhcpv6-client
ports: 4001/tcp 6443/tcp 2379-2380/tcp 10250/tcp 10251/tcp 10252/tcp 30000-32767/tcp
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:


**所有Worker节点设置防火墙策略**

开放端口策略

$ firewall-cmd --zone=public --add-port=10250/tcp --permanent
$ firewall-cmd --zone=public --add-port=30000-32767/tcp --permanent
$ firewall-cmd --reload

查看端口开放状态

$ firewall-cmd --list-all --zone=public
public (active)
target: default
icmp-block-inversion: no
interfaces: ens2f1 ens1f0 nm-bond
sources:
services: ssh dhcpv6-client
ports: 10250/tcp 30000-32767/tcp
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:


其他设置
所有节点必须清理iptables上的icmp禁止策略,否则会引起集群网络检测异常

为防止firewalld服务重启iptables被重置,把策略更新放在crontab中定期更新

$ crontab -e

          • /usr/sbin/iptables -D INPUT -j REJECT --reject-with icmp-host-prohibited

关闭Swap交换分区
Kubernetes1.8开始要求关闭系统的Swap交换分区,若不关闭则需要修改kubelet设定参数(–fail-swap-on设置为false来忽略swap on),在所有机器使用以下指令关闭swap并注释掉/etc/fstab中swap行,方法如下:

# 关闭swap
swapoff -a && echo "vm.swappiness=0" >> /etc/sysctl.conf && sysctl -p && free –h
sed -ri '/^[^#]*swap/s@^@#@' /etc/fstab

# 确认swap已经被禁用
$ cat /proc/swaps
Filename                Type        Size    Used    Priority

更新系统内核为4.19.x
升级说明

  • 旧內核版本建议不刪除,如果4.19.x內核运行异常,可切换到3.10.x上运行。

  • 如果是CentOS的话不想升级到的最新内核,则可以升级到保守内核,去掉update的--exclude=kernel*即可:
yum install epel-release -y
yum install wget git jq psmisc socat -y
yum update -y --exclude=kernel*

如果上面yum update没有加–exclude=kernel*就重启则加载保守内核:reboot

因为目前市面上包管理下内核版本会很低,安装Docker后无论CentOS还是Ubuntu会有如下bug,4.15的内核依然存在异常:

kernel:unregister_netdevice: waiting for lo to become free. Usage count = 1
所以建议先升级内核。

安装EPEL
yum install epel-release -y
安装ELRepo
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
yum install https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm
查看可用的内核
在YUM的ELRepo源中, Mainline为最新版本的内核,安装kernel。

yum --disablerepo="*" --enablerepo="elrepo-kernel" list available
yum --disablerepo="*" --enablerepo="elrepo-kernel" list available --showduplicates
yum --disablerepo="*" --enablerepo="elrepo-kernel" list available --showduplicates | grep -Po '^kernel-ml.x86_64\s+\K\S+(?=.el7)'

ipvs依赖于nf_conntrack_ipv4内核模块,4.19包括之后内核里改名为nf_conntrack,K8S1.13.1之前的kube-proxy的代码里 没有加判断一直用的nf_conntrack_ipv4,但是K8S1.13.1后的kube-proxy代码里增加了判断,根据测试是会去load nf_conntrack模块的,使用ipvs正常。

安装指定内核
RPM包安装
归档内核下载地址:

  • Ubuntu

http://kernel.ubuntu.com/~kernel-ppa/mainline/

  • RHEL

http://193.49.22.109/elrepo/kernel/el7/x86_64/RPMS/

执行安装指定版本:


export Kernel_Version=4.19.12-1
wget  http://mirror.rc.usf.edu/compute_lock/elrepo/kernel/el7/x86_64/RPMS/kernel-ml{,-devel}-${Kernel_Version}.el7.elrepo.x86_64.rpm
yum localinstall -y kernel-ml*

安装源安装

# 安装新版本内核kernel-ml-5.5.8-1.el7.elrepo
$ yum --disablerepo="*" --enablerepo="elrepo-kernel" install -y 5.8.0-1.el7.elrepo

修改内核启动顺序
默认启动的顺序应该为1,升级以后内核是往前面插入,为0:


grub2-set-default 0 && grub2-mkconfig -o /etc/grub2.cfg

确认默认启动内核

  • 使用下面命令看看确认下是否启动默认内核指向上面安装的内核

grubby --default-kernel

  • 开启User Namespace(可选)

Docker官方的内核检查脚本建议(RHEL7/CentOS7: User namespaces disabled; add ‘user_namespace.enable=1’ to boot command line),使用下面命令开启:


grubby --args="user_namespace.enable=1" --update-kernel="$(grubby --default-kernel)"
  • 重启并验证内核是否升级成功

reboot
uname -rp


**设置时间同步**
确保集群所有节点时间同步。

* Chrony方式(建议使用)

yum install chrony -y

修改/etc/chrony.conf配置文件, 增加如下内容:
server ntp.api.bz iburst
同时注释掉默认的Server:
#server 0.centos.pool.ntp.org iburst
#server 1.centos.pool.ntp.org iburst
#server 2.centos.pool.ntp.org iburst
#server 3.centos.pool.ntp.org iburst

开机启动:
systemctl start chronyd && systemctl enable chronyd && systemctl status chronyd


* Ntpdate方式

yum install -y ntpdate
systemctl start ntpdate && systemctl enable ntpdate && systemctl status ntpdate
ntpdate -u ntp.api.bz


**调整内核参数**
所有节点均需要设定/etc/sysctl.d/kubernetes.conf的系统内核参数:

https://github.com/moby/moby/issues/31208

修复ipvs模式下长连接timeout问题 小于900即可

ipvsadm -l --timout

cat > /etc/sysctl.d/kubernetes.conf << EOF
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 10
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
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.bridge.bridge-nf-call-arptables = 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

vm.swappiness = 0
vm.overcommit_memory=1
vm.panic_on_oom=0
EOF


执行以下命令使修改生效:

sysctl --system

内核在4.19.x以上不用执行下面命令

modprobe br_netfilter


查看效果:

内核在4.19.x以上下面命令无输出

[root@K8S-PROD-M1 ~]# lsmod | grep br_netfilter
br_netfilter 22256 0
bridge 151336 1 br_netfilter


**加载IPVS模块**
* 安装依赖包

yum install ipvsadm ipset sysstat conntrack libseccomp -y
* 加载IPVS模块(可选)

cat > /etc/sysconfig/modules/ipvs.modules << EOF
#!/bin/bash
ipvs_modules_dir="/usr/lib/modules/`uname -r`/kernel/net/netfilter/ipvs"
for i in `ls \$ipvs_modules_dir | sed -r 's#(.*).ko.xz#\1#'`; do
/sbin/modinfo -F filename \$i &> /dev/null 2>&1
if [ \$? -eq 0 ]; then
/sbin/modprobe \$i
fi
done
EOF


* 说明:     

* 上述脚本中:2>&1可不加。
* 4.19.x以上的内核不用执行此步。

* 生效:

chmod +x /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep ip_vs


**配置容器运行时**
**Cgroup驱动程序**
建议容器运行时、kubelet与节点上的其他进程统一使用systemd作为cgroup驱动,以此使系统更为稳定。

详情参考:https://kubernetes.io/zh/docs/setup/production-environment/container-runtimes/

**安装Docker**
根据https://github.com/kubernetes-sigs/kubespray/blob/master/roles/container-engine/docker/vars/redhat.yml中指定的稳定Docker版本,安装Docker。

**配置Service文件**
Docker从1.13版本开始调整了默认的防火墙规则,禁用了iptables filter表中FOWARD链,这样会引起Kubernetes集群中跨Node的Pod无法通信,因此Docker安装后,还需要手动修改iptables规则:

* 更新Docker启动文件

vi /usr/lib/systemd/system/docker.service
...
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

添加这行

ExecStartPost=/usr/sbin/iptables -P FORWARD ACCEPT
...

[Service]
......

kill only the docker process, not all processes in the cgroup

KillMode=process
......


**注意:** 如果在节点上禁用了防火墙,则这一步可不执行。

* 配置代理,访问gcr.io(可选配置)

[Service]
......
Environment="HTTP_PROXY=http://127.0.0.1:1080"
Environment="HTTPS_PROXY=http://127.0.0.1:1080"
......


**配置Docker参数**
所有节点均需要执行。

[root@K8S-PROD-M1 ~]# mkdir -p /etc/docker
[root@K8S-PROD-M1 ~]# mkdir -p /data/apps/docker

[root@K8S-PROD-M1 ~]# cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors": ["http://f1361db2.m.daocloud.io"],

"selinux-enabled": false,
"insecure-registries": [
    "harbor.cluster.local"
],

"storage-driver": "overlay2",
"storage-opts": [
    "overlay2.override_kernel_check=true"
],
"default-shm-size": "128M",
"data-root": "/data/apps/docker",

"max-concurrent-downloads": 10,
"max-concurrent-uploads": 5,
"oom-score-adjust": -1000,
"live-restore": true,
"debug": false,

"log-driver": "json-file",
"log-level": "warn",
"log-opts": {
    "max-size": "100m",
    "max-file": "3"
},

"exec-opts": [
    "native.cgroupdriver=systemd"
]

}
EOF


参数说明:

log-level:日志级别[error|warn|info|debug]。
insecure-registries: 配置私有镜像仓库,多个地址以“,”隔开。
registry-mirrors: 默认拉取镜像仓库地址
max-concurrent-downloads: 最大下载镜像数量
max-concurrent-uploads: 最大上传镜像数量
live-restore: Docker停止时保持容器继续运行,取值[true|false]
native.cgroupdriver: Docker存储驱动,该值需要与kubelet配置文件(kubelet-config.yml)中定义的cgroupDriver: systemd一致。
data-root: 设置Docker存储路径, 默认为/var/lib/docker,统一规划为:/data/apps/docker.


**重启Docker**

systemctl daemon-reload && systemctl enable docker && systemctl start docker && systemctl status docker


**安装Containerd**
**准备环境**

4.19+以上内核无需执行此步

cat > /etc/modules-load.d/containerd.conf <<EOF
overlay
br_netfilter
EOF

设置必需的sysctl参数,这些参数在重新启动后仍然存在。

说明:如果已经完成第7步:调整内核参数,此处可略过。

cat > /etc/sysctl.d/99-kubernetes-cri.conf <<EOF
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF

sysctl --system


**安装containerd**
Containerd安装使用与Docker相同的安装源,安装Docker时,该组件也被安装。

yum install -y containerd.io


**配置containerd**
* 生成配置文件

mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml


* 设置cgroup driver

[root@K8S-PROD-M1 ~]# mkdir -p /data/apps/containerd

vi /etc/containerd/config.toml

#设置工作目录
root = "/data/apps/containerd"
...

#设置使用systemd cgroup驱动
[plugins]
...
[plugins.cri]
...
systemd_cgroup = true //false改成true
...


启动containerd

systemctl daemon-reload && systemctl enable containerd && systemctl restart containerd && systemctl status containerd


**安装CRI-O(可选)**
**准备环境**

4.19+以上内核无需执行此步

modprobe overlay
modprobe br_netfilter

设置必需的sysctl参数,这些参数在重新启动后仍然存在。

说明:如果已经完成第7步:调整内核参数,此处可略过。

cat > /etc/sysctl.d/99-kubernetes-cri.conf <<EOF
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF

sysctl --system


**安装CRI-O**

Install prerequisites

curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/CentOS_7/devel:kubic:libcontainers:stable.repo
curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable:cri-o:1.18.repo https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:1.18/CentOS_7/devel:kubic:libcontainers:stable:cri-o:1.18.repo

Install CRI-O

yum install -y cri-o


**启动CRI-O**

systemctl daemon-reload && systemctl enable crio && systemctl start crio && systemctl status crio


**可选配置**
**安装工具包**

yum install -y jq wget vim gcc git tree lrzsz telnet rsync tcpdump net-tools bridge-utils bind-utils


说明:建议在管理的Master节点上安装这些工具包,因为jq在管理节点上部署CoreDNS时需要。

**关闭dnsmasq**
如果Linux系统开启了dnsmasq后(如GUI环境),将系统DNS Server 设置为127.0.0.1,这会导致Docker容器无法解析域名,需要关闭它:

systemctl disable --now dnsmasq


**安装证书管理工具**
K8S-PROD-M1节点上安装CFSSL工具:

wget -O /bin/cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
wget -O /bin/cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
wget -O /bin/cfssl-certinfo https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64

for cfssl in ls /bin/cfssl*; do chmod +x $cfssl; done;


**重启节点**

reboot


**创建其他节点**
以当前节点K8S-PROD-M1为模板,创建其他节点。具体参考:平台建设之基于Virsh工具管理KVM。

**集群节点互信**
所有机器彼此网络互通,并且K8S-PROD-M1节点上可SSH免密码登入其他节点。

* 所有Master节点各自生成密钥,需要三次回车

在所有master节点上创建本机公钥

$ ssh-keygen -t rsa -m PEM -P '' -f ~/.ssh/id_rsa


注意: 各节点的SSH Key必须唯一,如果是基于KVM复制的VM ,需要删除/root/.ssh/id_rsa*文件,然后重新生成。

* Master节点之间互信

在K8S-PROD-M1将id_rsa.pub(公钥)追加到授权key文件中

$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

在K8S-PROD-M1上将授权key文件复制到K8S-PROD-M2上

$ scp ~/.ssh/authorized_keys root@K8S-PROD-M2:~/.ssh/

在K8S-PROD-M2上将id_rsa.pub(公钥)追加到授权key文件中

$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

在K8S-PROD-M2上将授权key文件复制到K8S-PROD-M3上

$ scp ~/.ssh/authorized_keys root@K8S-PROD-M3:~/.ssh/

在K8S-PROD-M3上将id_rsa.pub(公钥)追加到授权key文件中

$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

在K8S-PROD-M3上将授权key文件复制到K8S-PROD-M1和K8S-PROD-M2上

$ scp ~/.ssh/authorized_keys root@K8S-PROD-M1:~/.ssh/
$ scp ~/.ssh/authorized_keys root@K8S-PROD-M2:~/.ssh/


* Master节点与Worker节点互信

ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.122.xxx


* 测试Master节点之间免密访问

在所有master节点上执行ssh,查看是否互信免密码登录

$ ssh K8S-PROD-M1 hostname && \
ssh K8S-PROD-M2 hostname && \
ssh K8S-PROD-M3 hostname


* 测试Master节点免密访问Worker节点

ssh root@192.168.122.x