概述

  • Kubernetes 集群架构组件

  • 容器运行时 CRI 新特性

  • Kubernetes v1.26 新特性

  • Kubernetes v1.24 之后不再支持Docker的解决方案

  • Kubernetes v1.26 高可用集群架构

  • 基于Kubernetes v1.26 和 Docker 部署高可用集群亲测案例

一 Kubernetes v1.26 新特性

1.1 Kubernetes 组件

1.1.1 Docker 的运行机制与原理

hook.png1.1.2 Kubernetes的设计初衷是支持可插拔架构,从而利于扩展kubernetes的功能。

Kubernetes_jiagou.png1.1.3 Kubernetes提供了三个特定功能的接口,Kubernetes通过调用这几个接口,来完成相应的功能。

  • 容器运行时接口CRI:Container Runtime Interface

    Kubernetes对于容器的解决方案,只是预留了容器接口,只要符合CRI标准的解决方案都可以使用;

  • 容器网络接口CNI:Container Network Interface

    Kubernetes 对于网络的解决方案,只是预留了网络接口,只要符合CNI标准的解决方案都可以用;

  • 容器存储接口CSI:Container Storage Interface

    Kubernetes 对于存储的解决方案,只是预留了存储接口,只要符合CSI标准的解决方案都可以使用此接口非必须。

1.1.4 容器运行时接口(CRI)

  • CRI是Kubernetes定义的一组gRPC服务。Kubelet作为客户端,基于gRPC协议通过socket和容器运行时通信。

  • CRI是一个插件接口,它使Kubelet能够使用各种容器运行时,无需重新编译集群组件。

  • Kubernetes 集群中需要在每个节点上都有一个可以正常工作的容器运行时,这样Kubelet能启动Pod及其容器。

  • 容器运行时接口(CRI)是 kubelet 和容器运行时之间通信的主要协议。

  • CRI 括两类服务:镜像服务(Image Service)和运行时服务(Runtime Service)。

  • 镜像服务提供下载、检查和删除镜像的远程程序调用。

  • 运行时服务包含用于管理容器生命周期,以及与容器交互的调用的远程程序调用。

1.1.5 OCI (Open Container Initiative,开放容器计划)定义了创建容器的格式和运行时的开源行业标准,包 括镜像规范(Image Specification)和运行时规范(Runtime Specification)。

  • 对于容器运行时主要有两个级别: Low Level(使用接近内核层) 和 High Level(使用接近用户层)目前,市 面上常用的容器引擎有很多,主要有下图的那几种。

  • Kubernetes_oci.png dockershim, containerd 和cri-o都是遵循CRI的容器运行时,我们称他们为高层级运行时(High-level Runtime)

其他的容器运营厂商最底层的runc仍然是Docker在维护的。

  • Google,CoreOS,RedHat都推出自已的运行时:lmctfy,rkt,cri-o,但到目前Docker仍然是最主流的容器引擎 技术。

Kubernetes_oci_cri.png1.2 Kubernetes v1.26 之后不再支持 Docker ?

  • 2014年 Docker & Kubernetes 蜜月期

    2015~2016年 Kubernetes & RKT vs Docker, 最终Docker 胜出

    2016年 Kubernetes逐渐赢得任务编排的胜利

    2017年 rkt 和 containerd 捐献给 CNCF

    2020年 kubernetes宣布废弃dockershim,但 Mirantis 和 Docker 宣布维护 dockershim

    2022年5月3日, Kubernetes v1.24正式发布,此版本提供了很多重要功能。该版本涉及46项增强功 能:其中14项已升级为稳定版, 15项进入beta阶段, 13项则刚刚进入alpha阶段。此外,另有2项功能 被弃用、 2项功能被删除。 v1.24 之前的 Kubernetes 版本包括与 Docker Engine 的直接集成,使用名为 dockershim 的组件。 值得注意的是v1.24 的 Kubernetes 正式移除对Dockershim的支持,即默认不 再支持 docker

    2022年8月24日,Kubernetes v1.25 正式发布

## 官方说明
https://kubernetes.io/zh-cn/docs/setup/production-environment/container- runtimes/
## 移除 Dockershim 的说明
https://kubernetes.io/zh-cn/blog/2022/02/17/dockershim-faq/
## Dockershim的历史背景
https://mp.weixin.qq.com/s/elkfBVzN8-zC30111zFpMw
  • Kubernetes 调用 runtime 的变化

Kubernetes_runtime.png1.3 Kubernetes v1.26 新变化

2022年8月24日,Kubernetes v1.25 正式发布

Kubernetes 1.25主题是Combiner,即组合器。

Kubernetes 1.25中包含多达40项增强功能

https://mp.weixin.qq.com/s/PKoNkhPU6OhjuuPzELP-Rg
  • PodSecurityPolicy被移除; Pod Security Admission毕业为稳定版

PodSecurityPolicy是在1.21版本中被决定弃用的,到1.25版本则将被正式删除。之所以删除此项功能, 是因为想要进一步提升其可用性,就必须引入重大变更。为了保持项目整体稳定,只得加以弃用。取而 代之的正是在1.25版本中毕业至稳定版的Pod Security Admission。如果你当前仍依赖 PodSecurityPolicy,请按照Pod Security Admission迁移说明[1]进行操作。

  • 临时容器迎来稳定版

临时容器是指在Pod中仅存在有限时长的容器。当我们需要检查另一容器,但又不能使用kubectlexec时 (例如在执行故障排查时),往往可以用临时容器替代已经崩溃、或者镜像缺少调试工具的容器。临时 容器在Kubernetes 1.23版本中已经升级至Beta版,这一次则进一步升级为稳定版。

  • cgroupsv2的稳定支持

自Linux内核cgroupsv2 API公布稳定版至今,已经过去两年多时间。如今,已经有不少发行版默认使用 此API, Kubernetes自然需要支持该内核才能顺利对接这些发行版。 Cgroups v2对cgroupsv1做出了多 项改进,更多细节请参见cgroupsv2说明文档[2]。虽然cgroupsv1将继续受到支持,但我们后续将逐步 弃用v1并全面替换为v2。

  • 更好的Windows系统支持

    性能仪表板添加了对Windows系统的支持

    单元测试增加了对Windows系统的支持

    一致性测试增加了对Windows系统的支持

    为Windows Operational Readiness创建了新的GitHub仓库

  • 将容器注册服务从k8s.gcr.io移动至registry.k8s.io

  • 1.25版本已经合并将容器注册服务从k8s.gcr.io移动至registry.k8s.io的变更。关于更多细节信息,请参 阅相应wiki页面[3],我们也通过Kubernetes开发邮件清单发出了全面通报。

  • SeccompDefault升级为Beta版

  • 网络策略中的endPort已升级为稳定版

网络策略中的endPort已经迎来GA通用版。支持endPort字段的网络策略提供程序,现可使用该字段来 指定端口范围以应用网络策略。在之前的版本中,每个网络策略只能指向单一端口。

请注意, endPort的起效前提是必须得到网络策略提供程序的支持。如果提供程序不支持endPort,而您 又在网络策略中指定了此字段,则会创建出仅覆盖端口字段(单端口)的网络策略。

  • 本地临时存储容量隔离迎来稳定版

本地临时存储容量隔离功能已经迎来GA通用版。这项功能最早于1.8版本中公布了alpha版,在1.10中升 级至beta,如今终于成为稳定功能。它通解为各Pod之间的本地临时存储提供容量隔离支持,例如 EmptyDir。因此如果Pod对本地临时存储容量的消耗超过了该上限,则会驱逐该Pod以限制其对共享资 源的占用。

CSI迁移是SIG Storage在之前多个版本中做出的持续努力,目标是将树内存储卷插件移动到树外CSI驱动 程序,并最终移除树内存储卷插件。此次核心CSI迁移已迎来GA通用版, GCE PD和AWS EBS的CSI迁移 功能也同步达到GA阶段。 vSphere的CSI迁移仍处于beta阶段(但也已经默认启用), Portworx的CSI迁 移功能同样处于beta阶段(默认关闭)。

  • CSI临时存储卷提升至稳定版

CSI临时存储卷功能,允许用户在临时用例的pod规范中直接指定CSI存储卷。如此一来,即可使用已安 装的存储卷直接在pod内注入任意状态,例如配置、机密、身份、变量或其他类似信息。这项功能最初 于1.15版本中推出alpha版,现已升级为GA通用版。某些CSI驱动程序会使用此功能,例如负责存储秘密 信息的CSI驱动程序。

  • CRD验证表达式语言升级至Beta版

CRD验证表达式语言现已升级为beta版,因此声明能够使用通用表达式语言(CEL)验证自定义资源。

  • 服务器端未知字段验证升级为Beta版

ServerSideFieldValidation功能门现已升级为Beta版(默认启用),允许用户在检测到未知字段时,有 选择地触发API服务器上的模式验证机制。如此一来,即可从kubectl中删除客户端验证,同时继续保持 对包含未知/无效字段的请求报错。

  • 引入KMS v2 API

引入KMS v2 alpha1 API以提升性能,实现轮替与可观察性改进。此API使用AES-GCM替代了AES-CBC, 通过DEK实现静态数据(即Kubernetes Secrets)加密。过程中无需额外用户操作,而且仍然支持通过 AES-GCM和AES-CBC进行读取。

1.4 Kubernetes v1.26 集群创建方案

1.4.1 Kubernetes v1.26 集群创建

  • 方式1: Containerd

    默认情况下,Kubernetes在创建集群的时候,使用的就是Containerd 方式。

  • 方式2: Docker

    Docker使用的普及率较高,虽然Kubernetes-v1.24 默认情况下废弃了kubelet对于Docker的支持,但 是我们还可以借助于Mirantis维护的cri-dockerd插件方式来实现Kubernetes集群的创建。

    Docker Engine 没有实现 CRI, 而这是容器运行时在 Kubernetes 中工作所需要的。 为此,必须安 装一个额外的服务 cri-dockerd。 cri-dockerd 是一个基于传统的内置 Docker 引擎支持的项目, 它在 1.24 版本从 kubelet 中移除

    项目站点: https://github.com/Mirantis/cri-dockerd

  • 方式3: CRI-O

    CRI-O的方式是Kubernetes创建容器最直接的一种方式,在创建集群的时候,需要借助于cri-o插件的 方式来实现Kubernetes集群的创建。

Kubernetes_Containerd.png

二 Kubernetes 高可用集群部署架构

本次实测实例Kubernetes集群部署环境如下:

  • 虚拟主机2G内存,2核CPU

  • OS:PRETTY_NAME="Ubuntu 22.04.1 LTS"

  • Kubernetes:v1.26.2

  • Container Runtime:Docker version 20.10.21

  • CRI:cri-dockerd v0.3.0

网络环境:

节点网络: 10.0.0.0.0/24
Pod网络: 10.244.0.0/16
Service网络: 10.96.0.0/12

Kubernetes_jiagoutu.png

IP

主机名

角色

192.168.100.35

master1.10691.cn

K8s 集群主节点 1,  Master和etcd

192.168.100.37

master2.10691.cn

K8s 集群主节点 2,  Master和etcd

192.168.100.33

master3.10691.cn

K8s 集群主节点 3,  Master和etcd

192.168.100.30

node1.10691.cn

K8s 集群工作节点 1

192.168.100.38

node2.10691.cn

K8s 集群工作节点 2

192.168.100.27

node3.10691.cn

K8s 集群工作节点 3

192.168.100.26

ha1.10691.cn

K8s 主节点访问入口 1,提供高可用及负载均衡

192.168.100.25

ha2.10691.cn

K8s 主节点访问入口 2,提供高可用及负载均衡

192.168.100.250

harbor.10691.cn

容器镜像仓库

192.168.100.222

k8s.10691.cn

VIP,在ha1和ha2主机实现

三 基于Kubeadm 实现 Kubernetes v1.26.2  

集群部署流程说明

官方说明

https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install- kubeadm/
https://kubernetes.io/zh-cn/docs/setup/production-
environment/tools/kubeadm/create-cluster-kubeadm/

使用  kubeadm ,能创建一个符合最佳实践的最小化 Kubernetes 集群。   事实上,你可以使用  kubeadm 配置一个通过 Kubernetes 一致性测试的集群。 kubeadm 还支持其他集群生命周期功能,   例如启动引 导令牌和集群升级。

  • Kubernetes集群API访问入口的高可用

    每个节点主机的初始环境准备

    在所有Master和Node节点都安装容器运行时,实际Kubernetes只使用其中的Containerd 在所有Master和Node节点安装kubeadm 、 kubelet、 kubectl

    在所有节点安装和配置 cri-dockerd

    在第一个 master 节点运行 kubeadm init 初始化命令 ,并验证 master 节点状态

    在第一个 master 节点安装配置网络插件

    在其它master节点运行kubeadm join 命令加入到控制平面集群中

    在所有 node 节点使用 kubeadm join 命令加入集群

    创建 pod 并启动容器测试访问 ,并测试网络通信

四 基于Kubeadm 部署 Kubernetes v1.26.2 高可用集群案例

4.1 部署 Kubernetes 集群 API 访问入口的高可用

在10.0.0.107和10.0.0.108上实现如下操作

4.1.1 安装 HAProxy

利用 HAProxy 实现 Kubeapi 服务的负载均衡

#修改内核参数
[root@ha1 ~]#cat >> /etc/sysctl.conf <<EOF
net.ipv4.ip_nonlocal_bind = 1
EOF
[root@ha1 ~]#sysctl -p
#安装配置haproxy [root@ha1 ~]#apt [root@ha1 ~]#apt	
update
-y install haproxy
##添加下面行
[root@ha1 ~]#cat >> /etc/haproxy/haproxy.cfg  <<EOF
listen stats
mode http
bind 0.0.0.0:8888
stats enable
log global
stats uri /status
stats auth admin:123456

listen  kubernetes-api-6443
bind 10.0.0.100:6443
mode tcp
server master1 10.0.0.101:6443 check inter 3s fall 3 rise 3
server master2 10.0.0.102:6443 check inter 3s fall 3 rise 3
server master3 10.0.0.103:6443 check inter 3s fall 3 rise 3
EOF

[root@ha1 ~]#systemctl restart  haproxy

4.1.2 安装 Keepalived

安装 keepalived 实现 HAProxy的高可用

[root@ha1 ~]#apt update
[root@ha1 ~]#apt -y install keepalived
[root@ha1 ~]#vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {
router_id ha1.wang.org  #指定router_id,#在ha2上为ha2.wang.org
}

vrrp_script check_haproxy {             #定义脚本
script "/etc/keepalived/check_haproxy.sh"
interval 1
weight -30
fall 3
rise 2
timeout 2
}

vrrp_instance VI_1 {
state MASTER      #在ha2上为BACKUP     
interface eth0
garp_master_delay 10
smtp_alert
virtual_router_id 66       #指定虚拟路由器ID,ha1和ha2此值必须相同 
priority 100               #在ha2上为80
advert_int 1
authentication {
auth_type PASS
auth_pass 123456           #指定验证密码,ha1和ha2此值必须相同
}
virtual_ipaddress {
10.0.0.100/24 dev          #eth0  label eth0:1  #指定VIP,ha1和ha2此值必须相同 
}
track_script {
check_haproxy              #调用上面定义的脚本
}
}


[root@ha1 ~]# cat > /etc/keepalived/check_haproxy.sh <<EOF #!/bin/bash
/usr/bin/killall -0 haproxy  || systemctl restart haproxy EOF
[root@ha1 ~]# chmod a+x /etc/keepalived/check_haproxy.sh

[root@ha1 ~]# systemctl restart keepalived

4.1.3 测试访问

浏览器访问验证,用户名密码: admin:123456

http://kubeapi.10691.cn:8888/status

4.2 所有主机初始化

4.2.1 配置 ssh key 验证

配置 ssh key 验证,方便后续同步文件

ssh-keygen -t rsa -C "11288**22@qq.com
ssh-copy-id -i ~/.ssh/id_rsa.pub root@10.0.0.102
.....

4.2.2 设置主机名和解析

hostnamectl set-hostname master1.10691.cn

cat > /etc/hosts <<EOF
10.0.0.100 kubeapi.10691.cn kubeapi
10.0.0.101 master1.10691.cn master1
10.0.0.102 master2.10691.cn master2
10.0.0.103 master2.10691.cn master3
10.0.0.104 node1.10691.cn node1
10.0.0.105 node2.10691.cn node2
10.0.0.106 node3.10691.cn node3
10.0.0.107 ha1.10691.cn ha1
10.0.0.108 ha2.10691.cn ha2
EOF

for i in {102..108};do scp /etc/hosts 10.0.0.$i:/etc/ ;done

4.2.3 禁用 swap

sudo swapoff -a
sduo sed -i '/swap/s/^/#/' /etc/fstab
#或者
sudo systemctl disable --now swap.img.swap
sduo systemctl mask swap.target

4.2.4 时间同步

#借助于chronyd服务(程序包名称chrony)设定各节点时间精确同步
apt -y install chrony
chronyc sources -v

4.2.5 禁用防火墙

#禁用默认配置的iptables防火墙服务
sudo ufw disable
sudo ufw status

4.2.6 内核参数调整(可选)

允许 iptables 检查桥接流量,若要显式加载此模块,需运行 sudo modprobe br_netfilter,通过运行 lsmod  | grep br_netfilter 来验证 br_netfilter 模块是否已加载

sudo modprobe br_netfilter
lsmod | grep br_netfilter

为了让 Linux 节点的 iptables 能够正确查看桥接流量,请确认 sysctl 配置中的 net.bridge.bridge-nf- call-iptables 设置为 1。

sudo cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

# 设置所需的 sysctl 参数,参数在重新启动后保持不变
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

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

4.3 所有主机安装 Docker 并修改配置

配置 cgroup 驱动程序,容器运行时和 kubelet 都具有名字为 "cgroup driver" 的属性,该属性对于在 Linux 机器上管理 CGroups 而言非常重要。

警告:你需要确保容器运行时和 kubelet 所使用的是相同的 cgroup 驱动,否则 kubelet 进程会失败。 范例:

#Ubuntu20.04可以利用内置仓库安装docker
sudo apt update
sudo apt -y install docker.io
#自Kubernetes v1.22版本开始,未明确设置kubelet的cgroup driver时,则默认即会将其设置为 systemd。所有主机修改加速和cgroupdriver
sudo cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors" : [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com",
"https://reg-mirror.qiniu.com",
"https://registry.docker-cn.com"
],
"exec-opts" : ["native.cgroupdriver=systemd"]
}
EOF

for i in {102..106};do scp /etc/docker/daemon.json 10.0.0.$i:/etc/docker/ ;done

sudo systemctl restart docker.service

#验证修改是否成功
sudo docker info  |grep Cgroup
Cgroup Driver: systemd
Cgroup Version: 2

4.4 所有主机安装 kubeadmkubelet 和 kubectl

通过国内镜像站点阿里云安装的参考链接:

https://developer.aliyun.com/mirror/kubernetes

范例: Ubuntu 安装

sudo apt-get update && apt-get install -y apt-transport-https
curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add - 
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF

for i in {102..106};do scp /etc/apt/sources.list.d/kubernetes.list 10.0.0.$i:/etc/apt/sources.list.d/;done
sudo apt-get update

#查看版本
sudo apt-cache madison kubeadm|head
   kubeadm |  1.26.2-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages
   kubeadm |  1.26.1-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages
   kubeadm |  1.26.0-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages
   kubeadm |  1.25.7-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages
   kubeadm |  1.25.6-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages
   kubeadm |  1.25.5-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages
   kubeadm |  1.25.4-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages
   kubeadm |  1.25.3-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages
   kubeadm |  1.25.2-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages
   kubeadm |  1.25.1-00 | https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages
#安装指定版本
sudo apt install -y  kubeadm=1.25.1-00 kubelet=1.25.1-00 kubectl=1.25.1-00

#安装最新版本
sudo apt-get install -y kubelet kubeadm kubectl

范例: CentOS / RHEL / Fedora系统安装

cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[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
EOF
setenforce 0
yum install -y kubelet kubeadm kubectl
systemctl enable kubelet && systemctl start kubelet

4.5 所有主机安装 cri-dockerd

Kubernetes自v1.24移除了对docker-shim的支持,而Docker Engine默认又不支持CRI规范,因而二者 将无法直接完成整合。为此,  Mirantis和Docker联合创建了cri-dockerd项目,用于为Docker Engine提 供一个能够支持到CRI规范的垫片,从而能够让Kubernetes基于CRI控制Docker 。

项目地址:  https://github.com/Mirantis/cri-dockerd

cri-dockerd项目提供了预制的二制格式的程序包,用户按需下载相应的系统和对应平台的版本即可完成 安装,这里以Ubuntu 20.04 64bits系统环境,以及cri-dockerd目前最新的程序版本v0.3.0为例。

curl -LO https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.0/cri-dockerd_0.3.0.3-0.ubuntu-jammy_amd64.deb
dpkg -i cri-dockerd_0.3.0.3-0.ubuntu-jammy_amd64.deb

[root@master1 ~]# for i in {102..106};do scp cri-dockerd_0.3.0.3-0.ubuntu-jammy_amd64.deb 10.0.0.$i: ; ssh 10.0.0.$i "dpkg -i cri-dockerd_0.3.0.3-0.ubuntu-jammy_amd64.deb";done
#完成安装后,相应的服务cri-dockerd.service便会自动启动。

4.6 所有主机配置 cri-dockerd

众所周知的原因,从国内 cri-dockerd 服务无法下载 k8s.gcr.io上面相关镜像,导致无法启动,所以需要修改 cri-dockerd 使用国内镜像源

vim /lib/systemd/system/cri-docker.service
#修改ExecStart行如下
ExecStart=/usr/bin/cri-dockerd --container-runtime-endpoint fd:// --pod-infra-container-image registry.aliyuncs.com/google_containers/pause:3.7
sudo systemctl daemon-reload && sudo systemctl restart cri-docker.service

#同步至所有节点
[root@master1 ~]#for i in {102..106};do scp /lib/systemd/system/cri-docker.service 10.0.0.$i:/lib/systemd/system/cri-docker.service; ssh 10.0.0.$i "systemctl daemon-reload && systemctl restart cri-docker.service";done

如果不配置,会出现下面日志提示

Aug 21 01:35:17 ubuntu2004 kubelet[6791]: E0821 01:35:17.999712    6791
remote_runtime.go:212] "RunPodSandbox from runtime service f      ailed" err="rpc error: code = Unknown desc = failed pulling image \"k8s.gcr.io/pause:3.6\": Error response from daemon: Get \"https:
//k8s.gcr.io/v2/\": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)"

4.7 提前准备 Kubernetes 初始化所需镜像(可选)

##Kubernetes-v1.24.X查看需要下载的镜像,发现k8s.gcr.io无法从国内直接访问
[root@master1 ~]#kubeadm  config images list
k8s.gcr.io/kube-apiserver:v1.24.3
k8s.gcr.io/kube-controller-manager:v1.24.3
k8s.gcr.io/kube-scheduler:v1.24.3
k8s.gcr.io/kube-proxy:v1.24.3
k8s.gcr.io/pause:3.7
k8s.gcr.io/etcd:3.5.3-0
k8s.gcr.io/coredns/coredns:v1.8.6

#Kubernetes-v1.26.2下载镜像地址调整为 registry.k8s.io,但仍然无法从国内直接访问
[root@master1 ~]#kubeadm  config images list
registry.k8s.io/kube-apiserver:v1.26.2
registry.k8s.io/kube-controller-manager:v1.26.2
registry.k8s.io/kube-scheduler:v1.26.2
registry.k8s.io/kube-proxy:v1.26.2
registry.k8s.io/pause:3.9
registry.k8s.io/etcd:3.5.6-0
registry.k8s.io/coredns/coredns:v1.9.3

#查看国内镜像
[root@master1 ~]# sudo kubeadm  config images list  --image-repository registry.aliyuncs.com/google_containers
registry.aliyuncs.com/google_containers/kube-apiserver:v1.26.2
registry.aliyuncs.com/google_containers/kube-controller-manager:v1.26.2
registry.aliyuncs.com/google_containers/kube-scheduler:v1.26.2
registry.aliyuncs.com/google_containers/kube-proxy:v1.26.2
registry.aliyuncs.com/google_containers/pause:3.9
registry.aliyuncs.com/google_containers/etcd:3.5.6-0
registry.aliyuncs.com/google_containers/coredns:v1.9.3

#从国内镜像站拉取镜像,1.24以上还需要指定--cri-socket路径
[root@master1 ~]# sudo kubeadm config images pull --kubernetes-version=v1.26.2 --image-repository registry.aliyuncs.com/google_containers --cri-socket unix:///run/cri-dockerd.sock

#查看拉取的镜像
[root@master1 ~]# sudo docker images
REPOSITORY                                                        TAG       IMAGE ID       CREATED        SIZE
registry.aliyuncs.com/google_containers/kube-apiserver            v1.26.2   63d3239c3c15   2 weeks ago    134MB
registry.aliyuncs.com/google_containers/kube-scheduler            v1.26.2   db8f409d9a5d   2 weeks ago    56.3MB
registry.aliyuncs.com/google_containers/kube-controller-manager   v1.26.2   240e201d5b0d   2 weeks ago    123MB
registry.aliyuncs.com/google_containers/kube-proxy                v1.26.2   6f64e7135a6e   2 weeks ago    65.6MB
registry.aliyuncs.com/google_containers/etcd                      3.5.6-0   fce326961ae2   3 months ago   299MB
registry.aliyuncs.com/google_containers/pause                     3.9       e6f181688397   5 months ago   744kB
registry.aliyuncs.com/google_containers/coredns                   v1.9.3    5185b96f0bec   9 months ago   48.8MB

#导出镜像
[root@master1 ~]#docker image save `docker image ls --format "{{.Repository}}: {{.Tag}}"` -o k8s-images-v1.24.3.tar
[root@master1 ~]#gzip k8s-images-v1.24.3.tar

4.8 在第一个 master 节点初始化 Kubernetes 集群

kubeadm init  命令参考说明

--kubernetes-version:#kubernetes程序组件的版本号,它必须要与安装的kubelet程序包的版本号 相同
--control-plane-endpoint:#多主节点必选项 ,用于指定控制平面的固定访问地址,可是IP地址或DNS名 称,会被用于集群管理员及集群组件的kubeconfig配置文件的API Server的访问地址 ,如果是单主节点的控 制平面部署时不使用该选项 ,注意 :kubeadm 不支持将没有 --control-plane-endpoint 参数的单个控制 平面集群转换为高可用性集群。
--pod-network-cidr:#Pod网络的地址范围,其值为CIDR格式的网络地址,通常情况下Flannel网络插 件的默认为10.244.0.0/16,Calico网络插件的默认值为192.168.0.0/16
--service-cidr:#Service的网络地址范围,其值为CIDR格式的网络地址,默认为10.96.0.0/12;通 常,仅Flannel一类的网络插件需要手动指定该地址
--service-dns-domain string #指定k8s集群域名,默认为cluster.local,会自动通过相应的DNS 服务实现解析
--apiserver-advertise-address:#API 服务器所公布的其正在监听的 IP 地址。如果未设置,则使 用默认网络接口。 apiserver通告给其他组件的IP地址,一般应该为Master节点的用于集群内部通信的IP地 址, 0.0.0.0表示此节点上所有可用地址 ,非必选项
--image-repository string #设置镜像仓库地址,默认为 k8s.gcr.io,此地址国内可能无法访问 ,可 以指向国内的镜像地址
--token-ttl #共享令牌(token)的过期时长,默认为24小时, 0表示永不过期;为防止不安全存储等原因 导致的令牌泄露危及集群安全,建议为其设定过期时长。未设定该选项时,在token过期后,若期望再向集群 中加入其它节点,可以使用如下命令重新创建token,并生成节点加入命令。 kubeadm token create -- print-join-command
--ignore-preflight-errors=Swap” #若各节点未禁用Swap设备,还需附加选项“从而让kubeadm忽略 该错误
--upload-certs #将控制平面证书上传到 kubeadm-certs Secret
--cri-socket  #v1.24版之后指定连接cri的socket文件路径 ,注意;不同的CRI连接文件不同
#如果是cRI是containerd,则使用 --cri-socket unix:///run/containerd/containerd.sock #如果是cRI是docker,则使用 --cri-socket unix:///var/run/cri-dockerd.sock
#如果是CRI是CRI-o,则使用 --cri-socket unix:///var/run/crio/crio.sock
#注意:CRI-o与containerd的容器管理机制不一样,所以镜像文件不能通用。

范例: 初始化集群

[root@master1 ~]#kubeadm init --control-plane-endpoint="kubeapi.wang.org" --  kubernetes-version=v1.25.0  --pod-network-cidr=10.244.0.0/16 --service-       cidr=10.96.0.0/12 --token-ttl=0   --cri-socket unix:///run/cri-dockerd.sock -- image-repository registry.aliyuncs.com/google_containers  --upload-certs
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy

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 the control-plane node running the following command on each as root:
kubeadm join kubeapi.wang.org:6443 --token ihbe5g.6jxdfwym49epsirr \
--discovery-token-ca-cert-hash
sha256:b7a7abccfc394fe431b8733e05d0934106c0e81abeb0a2bab4d1b7cfd82104c0 \
--control-plane --certificate-key
ae34c01f75e9971253a39543a289cdc651f23222c0e074a6b7ecb2dba667c059

Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use
"kubeadm init phase upload-certs --upload-certs" to reload certs afterward.

Then you can join any number of worker nodes by running the following on each as root:
kubeadm join kubeapi.wang.org:6443 --token ihbe5g.6jxdfwym49epsirr \
--discovery-token-ca-cert-hash
sha256:b7a7abccfc394fe431b8733e05d0934106c0e81abeb0a2bab4d1b7cfd82104c0
#如果有工作节点 ,先在工作节点执行 ,再在control节点执行下面操作
kubeadm reset -f --cri-socket unix:///run/cri-dockerd.sock
rm -rf  /etc/cni/net.d/  $HOME/.kube/config
reboot

4.9 在第一个 master 节点生成 kubectl命令的授权文件

kubectl是kube-apiserver的命令行客户端程序,实现了除系统部署之外的几乎全部的管理操作,是       kubernetes管理员使用最多的命令之一。  kubectl需经由API server认证及授权后方能执行相应的管理操 作,  kubeadm部署的集群为其生成了一个具有管理员权限的认证配置文件/etc/kubernetes/admin.conf,它可由kubectl通过默认的“$HOME/.kube/config”的路径进行加载。 当然,用户也可在kubectl命令上使用--kubeconfig选项指定一个别的位置。

下面复制认证为Kubernetes系统管理员的配置文件至目标用户(例如当前用户root)的家目录下:

#可复制4.8的结果执行下面命令
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

4.10 实现 kubectl 命令补全

kubectl 命令功能丰富,默认不支持命令补会,可以用下面方式实现

kubectl completion bash > /etc/profile.d/kubectl_completion.sh
. /etc/profile.d/kubectl_completion.sh
exit

4.11 在第一个 master 节点配置网络组件

Kubernetes系统上Pod网络的实现依赖于第三方插件进行,这类插件有近数十种之多,较为著名的有     flannel、calico、canal和kube-router等,简单易用的实现是为CoreOS提供的flannel项目。下面的命令 用于在线部署flannel至Kubernetes系统之上:

首先,下载适配系统及硬件平台环境的flanneld至每个节点,并放置于/opt/bin/目录下。我们这里选用 flanneld-amd64,目前最新的版本为v0.19.1 ,因而,我们需要在集群的每个节点上执行如下命令:

提示:下载flanneld的地址为 https://github.com/flannel-io/flannel/releases

随后,在初始化的第一个master节点k8s-master01上运行如下命令,向Kubernetes部署kube- flannel。

#默认没有网络插件 ,所以显示如下状态
[root@master1 ~]#kubectl get nodes
NAME
master1.wang.org	STATUS  NotReady	ROLES        control-plane	AGE
17m	VERSION
v1.24.3
[root@master1 ~]#kubectl apply -f https://raw.githubusercontent.com/flannel- io/flannel/master/Documentation/kube-flannel.yml
#稍等一会儿 ,可以看到下面状态
[root@master1 ~]#kubectl get nodes
NAME
master1.wang.org	STATUS Ready	ROLES        control-plane	AGE
23m	VERSION
v1.24.3

4.12 将所有worker 节点加入 Kubernetes 集群

在所有worker节点执行下面操作,加上集群

#复制上面第4.8步的执行结果 ,额外添加--cri-socket选项修改为下面执行
[root@node1 ~]#kubeadm join kubeapi.10691.cn:6443 --token
ihbe5g.6jxdfwym49epsirr \
--discovery-token-ca-cert-hash
sha256:b7a7abccfc394fe431b8733e05d0934106c0e81abeb0a2bab4d1b7cfd82104c0  --cri-
socket unix:///run/cri-dockerd.sock

[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[kubelet-start] Writing kubelet configuration to file
"/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file
"/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...

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.



[root@node1 ~]#docker images			
REPOSITORY	TAG	IMAGE ID	
CREATED         SIZE			
rancher/mirrored-flannelcni-flannel	v0.19.1	252b2c3ee6c8	12
days ago     62.3MB			
registry.aliyuncs.com/google_containers/kube-proxy
weeks ago     110MB	v1.24.3	2ae1ba6417cb	5
rancher/mirrored-flannelcni-flannel-cni-plugin	v1.1.0	fcecffc7ad4a	2
months ago    8.09MB			
registry.aliyuncs.com/google_containers/pause	3.7	221177c6082a	5
months ago    711kB			
registry.aliyuncs.com/google_containers/coredns	v1.8.6	a4ca41631cc7	10
months ago   46.8MB			

#可以将镜像导出到其它worker节点实现加速
[root@node1 ~]#docker image save `docker image ls --format "{{.Repository}}: {{.Tag}}"` -o k8s-images-v1.24.3.tar
[root@node1 ~]#gzip  k8s-images-v1.24.3.tar
[root@node1 ~]#scp k8s-images-v1.24.3.tar.gz node2:
[root@node1 ~]#scp k8s-images-v1.24.3.tar.gz node3:
[root@node2 ~]#docker load -i k8s-images-v1.24.3.tar.gz

[root@master1 ~]#kubectl get nodes

NAME	STATUS	ROLES	AGE	VERSION
master1.wang.org	Ready	control-plane	58m	v1.24.3
node1.wang.org	Ready	<none>	44m	v1.24.3
node2.wang.org	Ready	<none>	18m	v1.24.3
node3.wang.org	Ready	<none>	65s	v1.24.3

4.13 测试应用编排及服务访问

至此一个master附带有三个worker的kubernetes集群基础设施已经部署完成,用户随后即可测试其核 心功能。

demoapp是一个web应用,可将demoapp以Pod的形式编排运行于集群之上,并通过在集群外部进行访 问:

[root@master1 ~]#kubectl create deployment demoapp --
image=ikubernetes/demoapp:v1.0 --replicas=3

[root@master1 ~]#kubectl get pod -o wide
NAME                       READY   STATUS    RESTARTS   AGE     IP           NODE
NOMINATED NODE   READINESS GATES

demoapp-78b49597cf-7pdww	1/1	Running	0	2m39s	10.244.2.2
node2.wang.org   <none>		<none>			
demoapp-78b49597cf-wcjkp	1/1	Running	0	2m39s	10.244.2.3
node2.wang.org   <none>		<none>			
demoapp-78b49597cf-zmlmv	1/1	Running	0	2m39s	10.244.1.4
node3.wang.org   <none>		<none>			

[root@master1 ~]#curl 10.244.2.2
iKubernetes demoapp v1.0 !! ClientIP: 10.244.0.0, ServerName: demoapp- 78b49597cf-7pdww, ServerIP: 10.244.2.2!
[root@master1 ~]#curl 10.244.2.3
iKubernetes demoapp v1.0 !! ClientIP: 10.244.0.0, ServerName: demoapp- 78b49597cf-wcjkp, ServerIP: 10.244.2.3!
[root@master1 ~]#curl 10.244.1.4
iKubernetes demoapp v1.0 !! ClientIP: 10.244.0.0, ServerName: demoapp- 78b49597cf-zmlmv, ServerIP: 10.244.1.4!

#使用如下命令了解Service对象demoapp使用的NodePort,格式:<集群端口>:<POd端口>,以便于在集群 外部进行访问
[root@master1 ~]#kubectl create service nodeport demoapp --tcp=80:80
[root@master1 ~]#kubectl
NAME
demoapp   kubernetes	TYPE
NodePort
ClusterIP
get svc
CLUSTER-IP
10.110.101.190
10.96.0.1
EXTERNAL-IP
<none>
<none>
PORT(S)     80:30037/TCP 443/TCP
AGE
102s
67m

[root@master1 ~]#curl 10.110.101.190
iKubernetes demoapp v1.0 !! ClientIP: 10.244.0.0, ServerName: demoapp- 78b49597cf-wcjkp, ServerIP: 10.244.2.3!
[root@master1 ~]#curl 10.110.101.190
iKubernetes demoapp v1.0 !! ClientIP: 10.244.0.0, ServerName: demoapp- 78b49597cf-zmlmv, ServerIP: 10.244.1.4!
[root@master1 ~]#curl 10.110.101.190
iKubernetes demoapp v1.0 !! ClientIP: 10.244.0.0, ServerName: demoapp- 78b49597cf-7pdww, ServerIP: 10.244.2.2!

#用户可以于集群外部通过“http://NodeIP:30037”这个URL访问demoapp上的应用,例如于集群外通过浏 览器访问“http://<kubernetes-node>:30037”。
[root@rocky8 ~]#curl 10.0.0.100:30037
iKubernetes demoapp v1.0 !! ClientIP: 10.244.0.0, ServerName: demoapp- 78b49597cf-wcjkp, ServerIP: 10.244.2.3!
[root@rocky8 ~]#curl 10.0.0.101:30037
iKubernetes demoapp v1.0 !! ClientIP: 10.244.1.0, ServerName: demoapp- 78b49597cf-7pdww, ServerIP: 10.244.2.2!
[root@rocky8 ~]#curl 10.0.0.102:30037
iKubernetes demoapp v1.0 !! ClientIP: 10.244.2.0, ServerName: demoapp- 78b49597cf-zmlmv, ServerIP: 10.244.1.4!

#扩容
[root@master1 ~]#kubectl scale deployment demoapp --replicas 5 deployment.apps/demoapp scaled
[root@master1 ~]#kubectl get pod

NAME	READY	STATUS	RESTARTS	AGE
demoapp-78b49597cf-44hqj	1/1	Running	0	41m
demoapp-78b49597cf-45jd8	1/1	Running	0	9s
demoapp-78b49597cf-49js5	1/1	Running	0	41m
demoapp-78b49597cf-9lw2z	1/1	Running	0	9s
demoapp-78b49597cf-jtwkt	1/1	Running	0	41m

#缩容
[root@master1 ~]#kubectl scale deployment demoapp --replicas 2 deployment.apps/demoapp scaled
#可以看到销毁pod的过程
[root@master1 ~]#kubectl get pod
#再次查看 ,最终缩容成功
[root@master1 ~]#kubectl get pod

4.14 扩展 Kubernetes 集群为多主模式

https://kubernetes.io/zh-cn/docs/setup/production-environment/tools/kubeadm/high- availability/#manual-certs

在 master2 和 master3 重复上面的 4.2-4.7 步后,再执行下面操作加入集群

[root@master2 ~]#kubeadm join kubeapi.10691.cn:6443 --token
ihbe5g.6jxdfwym49epsirr \
--discovery-token-ca-cert-hash
sha256:b7a7abccfc394fe431b8733e05d0934106c0e81abeb0a2bab4d1b7cfd82104c0 --
control-plane \
--certificate-key
ae34c01f75e9971253a39543a289cdc651f23222c0e074a6b7ecb2dba667c059 \ --cri-socket unix:///run/cri-dockerd.sock

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 label and taint were applied to the new node.
* The Kubernetes control plane instances scaled up.
* A new etcd member was added to the local/stacked etcd cluster.

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.

[root@master2 ~]#mkdir -p $HOME/.kube
[root@master2 ~]#sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config [root@master2 ~]#sudo chown $(id -u):$(id -g) $HOME/.kube/config
[root@master1 ~]#kubectl get nodes

浏览器访问验证,用户名密码: admin:123456

http://kubeapi.10691.cn:8888/status