推荐
系统支持:centos7.6以上 ubuntu16.04以上 内核推荐4.14以上
推荐配置:centos7.7
环境信息

主机名 IP地址
s201 192.168.231.201
s202 192.168.231.202
s203 192.168.231.203

image.png

1、初始化安装 k8s 集群的实验环境

vi /etc/sysconfig/network-scripts/ifcfg-ens33

  1. TYPE=Ethernet
  2. PROXY_METHOD=none
  3. BROWSER_ONLY=no
  4. BOOTPROTO=static
  5. DEFROUTE=yes
  6. IPV4_FAILURE_FATAL=no
  7. IPV6INIT=yes
  8. IPV6_AUTOCONF=yes
  9. IPV6_DEFROUTE=yes
  10. IPV6_FAILURE_FATAL=no
  11. IPV6_ADDR_GEN_MODE=stable-privacy
  12. NAME=ens33
  13. UUID=7ab7d641-c2cb-4ba6-9d07-daba5a1f8c76
  14. DEVICE=ens33
  15. ONBOOT=yes
  16. IPADDR=192.168.231.201
  17. NETMASK=255.255.255.0
  18. GATEWAY=192.168.231.2

修改配置文件之后需要重启网络服务才能使配置生效,重启网络服务命令如下:
service network restart

2、配置主机名

在 192.168.231.201 上执行如下:
hostnamectl set-hostname s201 && bash
在 192.168.231.202 上执行如下:
hostnamectl set-hostname s202 && bash
在 192.168.231.203 上执行如下:
hostnamectl set-hostname s203 && bash
通过配置文件进行修改(s201 s202 s203)

vi /etc/hostname
s201

3、配置主机 hosts 文件,相互之间通过主机名互相访问修

改每台机器的/etc/hosts 文件,增加如下三行:

192.168.231.201 s201
192.168.231.202 s202
192.168.231.203 s203

4、配置主机之间无密码登录

ssh-keygen #一路回车,不输入密码把
本地生成的密钥文件和私钥文件拷贝到远程主机

ssh-copy-id s201
ssh-copy-id s202
ssh-copy-id s203

5、闭交换分区 swap,提升性能[ s202 s203]

# 临时关闭swap
swapoff -a
# 永久关闭swap
sed -i.bak '/swap/s/^/#/' /etc/fstab
# 查看
free -g

问题 1:为什么要关闭 swap 交换分区?
Swap 是交换分区,如果机器内存不够,会使用 swap 分区,但是 swap 分区的性能较低,k8s 设计的时候为了能提升性能,默认是不允许使用交换分区的。Kubeadm 初始化的时候会检测 swap 是否关 闭,如果没关闭,那就初始化失败。如果不想要关闭交换分区,安装 k8s 的时候可以指定—ignore- preflight-errors=Swap 来解决。

6、修改机器内核参数

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

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

modprobe overlay
modprobe br_netfilter

设置必需的 sysctl 参数,允许iptables检查桥接流量,这些参数在重新启动后仍然存在

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

# 应用 sysctl 参数而无需重新启动
sudo sysctl --system

问题 1:sysctl 是做什么的? 在运行时配置内核参数
-p 从指定的文件加载系统参数,如不指定即从/etc/sysctl.conf 中加载

问题 2:为什么要执行 modprobe br_netfilter?
修改/etc/sysctl.d/k8s.conf 文件,增加如下三行参数:
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
sysctl -p /etc/sysctl.d/k8s.conf 出现报错:
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
解决方法:
modprobe br_netfilter

问题 3:为什么开启 net.bridge.bridge-nf-call-iptables 内核参数?
在 centos 下安装 docker,执行 docker info 出现如下警告:
WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled
解决办法:
vim /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1

问题 4:为什么要开启 net.ipv4.ip_forward = 1 参数?
kubeadm 初始化 k8s 如果报错:
image.png
就表示没有开启 ip_forward,需要开启。
net.ipv4.ip_forward 是数据包转发:
出于安全考虑,Linux系统默认是禁止数据包转发的。所谓转发即当主机拥有多于一块的网卡时, 其中一块收到数据包,根据数据包的目的 ip 地址将数据包发往本机另一块网卡,该网卡根据路由表继续发送数据包。这通常是路由器所要实现的功能。
要让 Linux 系统具有路由转发功能,需要配置一个 Linux 的内核参数 net.ipv4.ip_forward。这个参数指定了 Linux 系统当前对路由转发功能的支持情况;其值为 0 时表示禁止进行 IP 转发;如果是 1, 则说明 IP 转发功能已经打开。

7、关闭 firewalld 防火墙(所有机器)

# 查看防火墙状态
firewall-cmd --state
# 临时停止防火墙
systemctl stop firewalld.service
# 禁止防火墙开机启动
systemctl disable firewalld.service

8、关闭 selinux (所有机器)

# 查看selinux状态
getenforce
# 临时关闭selinux
setenforce 0
# 永久关闭selinux
sed -i 's/^ *SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config

9、配置阿里云的 repo 源(所有机器)

yum -y install wget
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
yum clean all
yum makecache

10、配置安装 k8s 组件需要的阿里云的 repo 源 (所有机器)

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

scp /etc/yum.repos.d/kubernetes.repo s202:/etc/yum.repos.d/
scp /etc/yum.repos.d/kubernetes.repo s203:/etc/yum.repos.d/

11、配置时间同步(所有机器)

在 s201 上执行如下: 
#安装 ntpdate 命令 
[root@s201 ~]# yum install ntpdate -y 
#跟网络时间做同步 
[root@s201 ~]# ntpdate cn.pool.ntp.org 
#把时间同步做成计划任务
[root@s201 ~]# crontab -e 
* */1 * * * /usr/sbin/ntpdate cn.pool.ntp.org 
#重启 crond 服务 
[root@s201 ~]#service crond restart

12、 开启 ipvs (所有机器)

安装 k8s: 没有在内核加载 ipvs 模块,会自动适用 iptables 做代理,如果开启了 ipvs,那会使用ipvs 做规则
# 在 机器的/etc/sysconfig/modules/目录下创建ipvs.modules

cat <<EOF> /etc/sysconfig/modules/ipvs.modules
#!/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

# 安装了ipset软件包
yum install ipset -y

# 安装管理工具ipvsadm
yum install ipvsadm -y


image.png
问题 1:ipvs 是什么?
ipvs (IP Virtual Server) 实现了传输层负载均衡,也就是我们常说的 4 层 LAN 交换,作为 Linux 内核的一部分。ipvs 运行在主机上,在真实服务器集群前充当负载均衡器。ipvs 可以将基于 TCP 和 UDP 的服务请求转发到真实服务器上,并使真实服务器的服务在单个 IP 地址上显示为虚拟服务。

问题 2:ipvs 和iptable 对比分析
kube-proxy 支持 iptables 和 ipvs 两种模式, 在 kubernetes v1.8 中引入了 ipvs 模式,在v1.9 中处于 beta 阶段,在 v1.11 中已经正式可用了。iptables 模式在 v1.1 中就添加支持了,从v1.2 版本开始 iptables 就是 kube-proxy 默认的操作模式,ipvs 和 iptables 都是基于 netfilter 的,但是 ipvs 采用的是 hash 表,因此当 service 数量达到一定规模时,hash 查表的速度优势就会显现出来,从而提高 service 的服务性能。那么 ipvs 模式和 iptables 模式之间有哪些差异呢?
1、ipvs 为大型集群提供了更好的可扩展性和性能
2、ipvs 支持比 iptables 更复杂的复制均衡算法(最小负载、最少连接、加权等等)
3、ipvs 支持服务器健康检查和连接重试等功能

13 安装基础软件包(所有机器)

[root@s201 ~]# yum install -y yum-utils device-mapper-persistent-data lvm2 wget net-tools nfs-utils lrzsz gcc gcc-c++ make cmake libxml2-devel openssl-devel curl curl-devel unzip sudo ntp libaio-devel wget vim ncurses-devel autoconf automake zlib- devel python-devel epel-release openssh-server socat ipvsadm conntrack ntpdate telnet ipvsadm

14、安装containerd 服务(所有机器)

yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 查看最新版本
yum list containerd --showduplicates | sort -r
yum install containerd -y
# 安装了`containerd.io-1.5.11-3.1.el7.x86_64`
containerd config default > /etc/containerd/config.toml
systemctl start containerd
systemctl enable containerd

配置

# 修改cgroups为systemd
sed -i 's#SystemdCgroup = false#SystemdCgroup = true#' /etc/containerd/config.toml
# 修改基础设施镜像
sed -i 's#sandbox_image = "k8s.gcr.io/pause:3.5"#sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.6"#' /etc/containerd/config.toml
systemctl daemon-reload
systemctl restart containerd

安装 CRI 客户端 crictl
选择版本 https://github.com/kubernetes-sigs/cri-tools/releases/

wget https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.23.0/crictl-v1.23.0-linux-amd64.tar.gz
tar zxvf crictl-v1.23.0-linux-amd64.tar.gz -C /usr/local/bin

cat <<EOF> /etc/crictl.yaml 
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
EOF

# 验证是否可用
crictl pull nginx:alpine
crictl images
crictl rmi nginx:alpine

15、安装初始化 k8s 需要的软件包(所有机器)

# 查看版本,最新版 1.23.5-0
yum list kubeadm --showduplicates | sort -r
yum install -y kubelet-1.23.5-0 kubectl-1.23.5-0 kubeadm-1.23.5-0
[root@master ~]# kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"23", GitVersion:"v1.23.5", GitCommit:"c285e781331a3785a7f436042c65c5641ce8a9e9", GitTreeState:"clean", BuildDate:"2022-03-16T15:57:37Z", GoVersion:"go1.17.8", Compiler:"gc", Platform:"linux/amd64"}

修改kubelet配置

cat <<EOF> /etc/sysconfig/kubelet
KUBELET_KUBEADM_ARGS="--container-runtime=remote --runtime-request-timeout=15m --container-runtime-endpoint=unix:///run/containerd/containerd.sock"
EOF

启动kubelet服务,并设置开机自启

systemctl start kubelet
systemctl enable kubelet

image.png
#上面可以看到 kubelet 状态不是 running 状态,这个是正常的,不用管,等 k8s 组件起来这个kubelet 就正常了。
注:每个软件包的作用
Kubeadm: kubeadm 是一个工具,用来初始化 k8s 集群的
kubelet: 安装在集群所有节点上,用于启动 Pod 的
kubectl: 通过 kubectl 可以部署和管理应用,查看各种资源,创建、删除和更新各种组件

16kubeadm 初始化 k8s 集群(只在master执行)

1. 通过配置文件初始化:

#使用 kubeadm 初始化 k8s 集群 
[root@s201 ~]# kubeadm config print init-defaults > kubeadm.yaml

根据我们自己的需求修改配置,比如修改imageRepository的值,kube-proxy的模式为ipvs

kubeadm config print init-defaults > kubeadm.yaml

修改为
cat <<EOF> kubeadm.yaml 
apiVersion: kubeadm.k8s.io/v1beta3
bootstrapTokens:
- groups:
  - system:bootstrappers:kubeadm:default-node-token
  token: abcdef.0123456789abcdef
  ttl: 24h0m0s
  usages:
  - signing
  - authentication
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 192.168.88.201 # apiserver 节点内网IP
  bindPort: 6443
nodeRegistration:
  criSocket: /run/containerd/containerd.sock  # 修改为containerd
  imagePullPolicy: IfNotPresent
  name: s201 #修改主机名
  taints:
  - effect: NoSchedule
    key: node-role.kubernetes.io/master
---
apiServer:
  timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns:
  type: CoreDNS # dns类型 type: CoreDNS
etcd:
  local:
    dataDir: /var/lib/etcd
imageRepository: registry.aliyuncs.com/google_containers # 修改这个镜像能下载
kind: ClusterConfiguration
kubernetesVersion: 1.23.5 # k8s版本
networking:
  dnsDomain: cluster.local
  podSubnet: 10.244.0.0/16  
  serviceSubnet: 10.96.0.0/12
scheduler: {}
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs  # kube-proxy 模式
EOF
kubeadm init --config kubeadm.yaml

基于 kubeadm.yaml 初始化 k8s 集群
[root@s201 ~]# kubeadm init —config=kubeadm.yaml
显示如下,说明安装完成:
image.png
#配置 kubectl 的配置文件 config,相当于对 kubectl 进行授权,这样 kubectl 命令可以使用这个证书对 k8s 集群进行管理
[root@s201~]# mkdir -p $HOME/.kube
[root@s201 ~]# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@s201~]# sudo chown $(id -u):$(id -g) $HOME/.kube/config
[root@s201 ~]# kubectl get nodes
此时集群状态还是NotReady状态,因为没有安装网络插件。
2. 直接初始化:
kube-proxy 模式是 iptables,可以通过kubectl edit configmap kube-proxy -n kube-system修改

kubeadm init \
--kubernetes-version v1.23.5 \
--apiserver-advertise-address 192.168.88.201 \
--control-plane-endpoint s201 \
--image-repository registry.aliyuncs.com/google_containers \
--pod-network-cidr 10.244.0.0/16 \
--cri-socket /run/containerd/containerd.sock
  • —kubernetes-version:指定的版本
  • —apiserver-advertise-address:K8S主节点的地址
  • —pod-network-cidr:pod的网络IP范围
  • —image-repository:指定下载源 | 如果您的网络运行在192.168..,需要将 pod-network-cidr 设置为10.0.0.0/16;
    如果您的网络是10.0..使用192.168.0.0/16 | | —- |

17 扩容 k8s 集群-添加第一个工作节点

在 s201上查看加入节点的命令:
[root@s201~]# kubeadm token create —print-join-command
显示如下:
kubeadm join 192.168.121.201:6443—tokenvulvta.9ns7da3saibv4pg1—— discovery-token-
ca-cert-hash sha256:72a0896e27521244850b8f1c3b600087292c2d10f2565adb56381f1f4ba7057a
把 s202加入 k8s 集群:
[root@s202~]# kubeadmjoin192.168.40.180:6443- tokenvulvta.9ns7da3saibv4pg1
—discovery-token-ca-cert-hash sha256:72a0896e27521244850b8f1c3b600087292c2d10f2565adb56381f1f4ba7057a
image.png
#看到上面说明 s202节点已经加入到集群了,充当工作节点

在 s201上查看集群节点状况:
[root@s201~]# kubectl get nodes

可以对 s202、s203打个标签,显示 work
[root@s201~]# kubectl label nodes s202 node-role.kubernetes.io/work=work
[root@s201~]# kubectl get nodes

19 安装 kubernetes 网络组件-Calico

mkdir -p /root/i && cd /root/i
# 下载
curl https://docs.projectcalico.org/manifests/calico.yaml -o /root/i/calico.yaml
查看一下版本`v3.22.2`,如果不是替换不生效
# 修改镜像
sed -i 's#docker.io/calico/cni:v3.22.2#registry.cn-shanghai.aliyuncs.com/wanfei/cni:v3.22.2#' /root/i/calico.yaml
sed -i 's#docker.io/calico/pod2daemon-flexvol:v3.22.2#registry.cn-shanghai.aliyuncs.com/wanfei/pod2daemon-flexvol:v3.22.2#' /root/i/calico.yaml
sed -i 's#docker.io/calico/node:v3.22.2#registry.cn-shanghai.aliyuncs.com/wanfei/node:v3.22.2#' /root/i/calico.yaml
sed -i 's#docker.io/calico/kube-controllers:v3.22.2#registry.cn-shanghai.aliyuncs.com/wanfei/kube-controllers:v3.22.2#' /root/i/calico.yaml
# 执行
kubectl apply -f /root/i/calico.yaml

等几分钟
kubectl get pods -n kube-system
image.png
再次查看集群状态。
[root@s201~]# kubectl get nodes
image.png

案例

1、测试网络

1.1 把 busybox-1-28.tar.gz 上传到 s202 s203节点,手动解压
[root@s201~]# ctr images import busybox-1-28.tar.gz
image.png

kubectl run busybox --image busybox:1.28 --restart=Never --rm -it busybox -- sh

image.png
注意:containerd使用ctr工具和crictl工具列出信息一致问题,命令比较
解释
ctr是containerd自带的工具,有命名空间的概念,若是k8s相关的镜像,都默认在k8s.io这个命名空间
crictl是k8s社区的专用CLI工具
所以:
crictl images 与 ctr i list 不同
crictl images 等价于 ctr -n k8s.io i list
image.png
2、域名解析出ip
nslookup kubernetes.default.svc.cluster.local
image.png
image.png
# 注意 :busybox要用指定的1.28版本,不能用最新版本,最新版本,nslookup会解析不到dns和ip