一、Kubernetes简介
Kubernetes,又称为 k8s(首字母为 k、首字母与尾字母之间有 8 个字符。尾字母为s),主要用于自动部署、扩缩和管理容器化应用程序。简单的说就是,K8S就是个编排运行容器的集群。从本质上说,Kubernetes是“以应用为中心”的现代应用基础设施。
在Docker技术的基础上,Kubernetes为容器化的应用提供部署运行、资源调度、服务发现和动态伸缩等一系列完整功能,提高了大规模容器集群管理的便捷性。并且具有完备的集群管理能力,多层次的安全防护和准入机制、多租户应用支撑能力、透明的服务注册和发现机制、内建智能负载均衡器、强大的故障发现和自我修复能力、服务滚动升级和在线扩容能力、可扩展的资源自动调度机制以及多粒度的资源配额管理能力。
二、Kubernetes的特性(实现的功能)
2.1 自我修复
在节点故障时,重新启动失败的容器,替换和重新部署,保证预期的副本数量;杀死健康检查失败的容器,并且在未准备好之前不会处理用户的请求,确保线上服务不中断。
2.2 弹性伸缩
使用命令、UI或者基于CPU使用情况自动快速扩容和缩容应用程序实例,保证应用业务高峰并发时的高可用性;业务低峰时回收资源,以最小成本运行服务。
2.3 自动化上线和回滚
Kubernetes 会分步骤地将针对应用或其配置的更改上线,同时监视应用程序运行状况以确保你不会同时终止所有实例。如果出现问题,Kubernetes 会为你回滚所作更改。
2.4 服务发现和负载均衡
K8S为多个容器提供一个统一访问入口(内部IP地址和一个DNS名称),并且负载均衡关联的所有容器,使得用户无需考虑容器IP问题。
2.5 Secret和配置管理
管理Secret和应用程序配置,而无需把敏感数据暴露在镜像里,提高敏感数据的安全性。并可以将一些常用的配置存储在K8S中,方便应用程序使用。
2.6 存储编排
挂载外部存储系统,无论是来自本地存储,公有云(eg:AWS、GCP),还是网络存储(eg:NFS、Ceph),都作为集群资源的一部分使用,极大提高存储使用灵活性。
2.7 批处理
提供一次性任务,定时任务;满足批量数据处理和分析的场景。
三、Kubernetes的组件
先看Kubernetes的集群架构
按节点类型划分,可分为Master节点和Node(Minion)节点。
3.1 Master节点
Master 是 K8S 的集群控制节点,每个 K8S 集群里需要有一个 Master 节点来负责整个集群的管理和控制,基本上 K8S 所有的控制命令都是发给它,它来负责具体的执行过程。如果它不可用,那么所有的控制命令都将失效。拥有Etcd存储服务(可选)。Master节点运行Api Server进程、Controller Manager服务进程及Scheduler服务进程,分别介绍如下:
3.1.1 APIServer
APIServer是集群的统一入口(网关),各组件协调者。所有的组件之间不互相通信,只同APIServer进行交互。声明式API,基于https/https协议以 HTTP Rest 风格提供接口服务。所有对象资源的增、删、改、查和监听操作都交给 APIServer 处理后再提交给 Etcd 存储。
3.1.2 Controller Manager
Controller的集合,由一组Kubernetes内置的Controller集结而成。负责执行各类控制器。除调度之外的编排决策,几乎都由Controller负责实现。Controller是在集群上管理和运行容器的对象,Pod通过Controller来实现应用的运维比如伸缩,滚动升级等。Pod和Controller之间通过label标签建立联系。
简单地说就是Controller负责把用户通过API Server中遵循某个特定API而实例化的对象生产出来。Controller正是声明式API得以实现的根本原因所在。
需要进行的决策有很多种类型:相应的,控制器也存在很多类型:PV/PVC(Volume控制器)、StatefulSet(编排有状态应用)、Deployment(编排无状态应用)、Service(服务)、Namespace(命名空间)、Token(令牌),等等。
3.1.3 Scheduler
负责集群资源的调度和管理。根据调度算法为Pod 选择一个 Node 节点,可以任意部署,可以部署在同一个节点上,也可以部署在不同的节点上。
3.1.4 Etcd
(Kubernetes可选的第三方组件)是一个分布式的、一致的 key-value 存储,主要用途是共享配置和服务发现,保存集群状态数据,比如 Pod、Service 等对象信息。使用json格式存储。Kubernetes其他所有组件的通信是通过ApiServer进行通信的,不会直接和 Etcd 进行通信。
简单的总结下就是,Controller-Manager、Scheduler、kubelet、kube-proxy是API Server的客户端,而API Server又是Etcd的客户端。
3.2 Node节点
Node是Kubernetes的工作节点,负责接收来自Master节点的工作指令,并根据指令相应地创建和销毁Pod对象,以及调整网络规则进行合理路由和流量转发。Node节点运行docker engine服务、代理服务 kubelet及负载均衡器kube-proxy,分别介绍如下:
3.2.1 Kubelet
Kubelet 是 Master 在 Node 节点上的 Agent(代理,即与Master对接,能够成为让Master识别的节点),接收并执行来自Master节点的工作指令,定时上报本地 Node 和其运行的Pod的状态信息给 API Server。相关的事务执行&实现则需要借助各类插件(CRI、CSI、CNI)完成。
(主要功能)管理由Scheduler绑定至当前节点的Pod对象的容器(包括容器的创建、启停),与底层运行的容器(eg:Docker)进行通信。这个通信的过程也被 Kubernetes 抽象成了一个 CRI(Container Runtime Interface)的远程调用接口(ps:Kubernetes运行Pod容器集时,容器的运行需要借助容器运行时这个引擎来实现--Container Runtime,简称CR,CRI就是对接第三方CR的),这个接口里面定义了容器运行时的所有标准操作,比如创建容器、删除容器。所以对于 Kubernetes 来说他根本不关心你部署的到底是什么容器,只要你这个容器运行时可以实现 CRI 接口就可以被 Kubernetes 来管理。
Kubelet 的另外一个重要功能就是调用网络插件(CNI)和存储插件(CSI)为容器配置网络和存储功能,同样的 Kubelet 也是把这两个重要功能通过接口暴露给外部了,所以如果我们想要实现自己的网络插件,只需要使用 CNI 就可以很方便的对接到 Kubernetes 集群当中去。
3.2.2 Kube-Proxy
监听Apiserver 中 Service 和 Endpoint 的变化情况,创建路由规则以提供Service和负载均衡功能。其核心功能是将到某个Service的访问请求转发到后端的多个Pod实例上。
有两种工作模式:
- iptables模式:将Service资源的定义转化为适配当前节点视角的iptables规则
- ipvs模式:将Service资源的定义转化为适配当前节点视角的ipvs规则和少量iptables规则
换句话说,Service在每一个节点的内核上通过Kube-Proxy的转换去生成iptables/ipvs规则。
四、Kubernetes应用编排的基本工作逻辑
4.1 Pod
Pod,也叫容器集,是Kubernetes运行应用和应用调度的最小单元,本质上是共享Network、IPC(进程间通信)和UTS名称空间以及存储资源的容器集。
- 可将Pod想象成一台物理机或虚拟机,各容器就是该主机上的进程(应用)
- 每个Pod包含了一个Pause容器,Pause容器是Pod的父容器,主要负责僵尸进程的回收管理
- 通过Pause容器使同一个Pod内的容器共享网络协议栈、网络设备、路由、IP地址和端口等,但Mount、PID和USER仍隔离
- 每个Pod上还可附加一个存储卷(Volume)作为该“主机”的外部存储,独立于Pod的生命周期,可由Pod内的各容器共享
一个Pod可以运行一个或多个容器,这些容器都会自动分配到同一Node节点。但这些容器之间要具有“超亲密关系”。
对于“超亲密关系”的理解:简单的说,就是俩容器,谁离开谁都可能会有问题
“亲密关系”容器的特征(通过调度解决):
- 两个应用需要运行在同一台宿主机上
“超亲密关系”容器的特征(Pod解决):
- 会发生直接的文件交换;
- 使用 localhost 或者本地的Socket 进行通信;
- 会发生非常频繁的 RPC 调用;
- 会共享某些 Linux Namespace,比如一个容器需要加入另一个容器的Network Namespace
4.2 Service
Pod具有动态性,重启后ip地址会变,这也就意味着不方便直接采用pod的ip对服务进行访问。为了解决这个问题,kubernetes提供了Service资源(是一个抽象概念),Service会对提供同一个服务的多个pod进行聚合,并且提供一个统一的入口地址。通过访问Service的入口地址就能访问到后面的pod服务。CoreDNS(K8S集群的DNS服务器)会自动的给Service相关服务分配个主机名
- Service能够为一组提供相同服务的Pod提供负载均衡机制,其IP地址(Service IP,也称Cluster IP)即为客户端流量入口
- Service采用标签选择器(Label Selector)筛选并匹配Pod对象的标签(Label),从而发现Pod。注意:仅具有符合其标签选择器筛选条件的标签的Pod才可由Service对象作为后端端点使用
4.3 工作负载型控制器
Pod的生命周期管理和健康状态监测由kubelet负责完成,而诸如更新、扩缩容和重建等应用编排功能需要由专用的控制器实现,这类控制器即工作负载型控制器。
- ReplicaSet和Deployment #无状态控制器
- DaemonSet #系统级应用,每个节点运行一个
- StatefulSet #有状态控制器
- Job和CronJob # Job:一次性作业; CronJob:周期性作业
工作负载型控制器的核心功能是按照用户期望的副本数量,创建并运行Pod。当数量不足时依据Pod模板创建,超出时销毁多余的对象。而且工作负载型控制器也通过标签选择器筛选Pod标签从而完成关联。
4.4 部署并访问应用
部署应用的大体流程:
1st.依照编排需求,选定合适类型的工作负载型控制器。配置好Pod模板,配置好数量,配置标签选择器和标签
2nd.创建工作负载型控制器对象,由其确保运行合适数量的Pod对象
3rd.创建Service对象,为该组Pod对象提供固定的访问入口
五、Kubernetes网络基础
5.1 Kubernetes网络模型
Kubernetes集群上会存在三个分别用于节点、Pod和Service的网络。于Node节点上完成交汇,由节点内核中的路由模块,以及iptables/netfilter和ipvs等完成网络间的流量转发。
5.1.1 节点网络
- 集群节点间的通信网络,并负责打通与集群外部端点间的通信
- 网络及各节点地址需要于Kubernetes部署前完成配置,非由Kubernetes管理,因而需要由管理员手动进行,或借助于主机虚拟化管理程序(eg:公有云管理程序)进行
5.1.2 Pod网络
- 为集群上的Pod对象提供的网络
- 虚拟网络,需要经由CNI网络插件实现,eg:Flannel、Calico、Cilium
5.1.3 Service网络
- 在部署 Kubernetes 集群时指定,各Service 对象使用的地址将从该网络中分配
- Service对象的 IP 地址存在于其相关的 iptables 或ipvs 规则中
- 由Kubernetes集群自行管理
5.2 Kubernetes集群中的通信流量
Kubernetes网络中主要存在4种类型的通信流量:
- 同一Pod内的容器间通信
- Pod间的通信
通过Pod网络完成。
- Pod与Service间的通信
由于Kube-Proxy的存在,使得Service转化为ipvs规则并出现在集群每个节点的内核当中,所以每个节点都能看作是负载均衡器,其配置由Service实现。这样客户端Pod在流量发出之前在自己的内核中已经完成了目标地址转换,即目标地址由Service ip->后端Pod ip。而每一个节点所接受到的客户端请求在内核中完成向目标Pod的调度。
- 集群外部流量与Service间的通信
Pod网络需要借助于第三方兼容CNI规范的网络插件完成,这些插件需要满足以下功能要求:
1.所有Pod间均可不经NAT机制而直接通信
2.所有节点均可不经NAT机制直接与所有Pod通信
3.所有Pod对象都位于同一平面网络中
六、集群部署与应用编排
6.1 Kubernetes集群组件运行模式
6.1.1 独立组件模式
- 除Add-ons(必选附件)以外,各关键组件以二进制方式部署于节点上,并运行为守护进程
- 各Add-ons以Pod方式运行
6.1.2 静态Pod模式
- 控制平面各组件以静态Pod对象运行在Master节点
- Kubelet和Docker以二进制部署,运行为守护进程
- Kube-Proxy等组件以Pod方式运行
- 需要准备镜像。镜像地址:k8s.gcr.io,现在可以用registry.k8s.io
6.2 安装工具
有原生安装工具kubeadm、CNCF认证的安装工具
CNCF地址:https://landscape.cncf.io/
Kubeadm是Kubernetes社区提供的集群构建工具,它负责构建一个最小化可用集群并执行启动等必要的基本步骤。简单来讲,Kubeadm 是 Kubernetes 集群全生命周期管理工具,可用于实现集群的部署、升级/降级及卸载等。Kubeadm仅关心如何初始化并启动一个集群,为集群添加必要的核心附件CoreDNS和Kube-Proxy,其它附件由管理员自行部署。
kubeadm支持堆叠式etcd(每个Master节点均部署一个etcd)和外部etcd(etcd分布式存储在Kubernetes集群外的其它节点运行)两种高可用模型。
在Kubeadm的高可用模型中,每个Node节点只承担部分工作。对于Master节点的高可用,Master节点的组件说明如下:
- API Server:无状态,按需(访问量和单节点的承载能力进行扩展),2个或以上
- Scheduler:调度决策中心,只能有一个实例处于活动状态,余下的都是备用;内置的leader election机制;
- Controller Manager:编排决策中心,只能有一个实例处于活动状态,余下的都是备用;内置的leader election机制;
- Etcd:有状态的存储服务,强一致性;奇数个节点。Etcd可以与Master节点部署在一块儿,也可以在Kubernetes集群以外的机器部署
原本Node节点的Kubelet会与ApiServer通信,但由于ApiServer是无状态的,此时为多个Apiserver添加负载均衡器,这样各个Node节点与负载均衡器通信,负载均衡器将负载请求转到Apiserver即可。至于高可用问题,为负载均衡器加个Keepalived做漂移ip即可解决。也可以为Apiserver本身做Nginx(Haproxy)+Keepalived高可用(去掉负载均衡器)
6.3 部署前提
使用Kubeadm部署Kubernetes的前提条件
- >=2G内存,>2核CPU
- 各主机网络通信顺畅
- 独立的Hostname和MAC地址及product_uuid,主机名正常解析
- 放行Kubernetes使用的各个端口,或禁用防火墙
- 禁用各主机的swap
- 各主机时间同步
注意:
- kubeadm不仅支持集群部署,还支持集群升级、卸载、更新数字证书等功能。
- 目前,kubeadm为各节点默认生成的SSL证书的有效期限为1年,在到期之前需要renew这些证书。
6.4 Kubernetes集群环境介绍
OS:Ubuntu 22.04
Docker:26.0.0,CGroup Driver:systemd
Kubernetes:1.28.2
CRI:containerd.io 1.6.28(cri-dockerd亦可)
CNI:Flannel或Calico或Cilium
网络环境
• 节点网络:192.168.131.0/24
• Pod网络:10.244.0.0/16
• Service网络:10.96.0.0/12
ip地址 | 主机名 | 角色 |
192.168.131.11 | K8S-Master1,kubeapi.wxd.com | Master |
192.168.131.12 | K8S-Master2 | Master |
192.168.131.13 | K8S-Master3 | Master |
192.168.131.14 | K8S-Node1 | Node |
192.168.131.15 | K8S-Node2 | Node |
192.168.131.16 | K8S-Node3 | Node |
6.5 集群部署步骤
参考https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
6.5.1 时间同步
apt-get -y install chrony
systemctl enable –-now chrony
6.5.2 禁用fatab
编辑/etc/fstab配置文件,注释用于挂载Swap设备的所有行
##在Ubuntu20.04以后,若要彻底禁用Swap,执行如下命令
systemctl --type swap
#而后,将上面命令列出的每个设备,使用systemctl mask命令加以禁用
systemctl mask SWAP_DEV
6.5.3 禁用默认的防火墙服务
ufw disable
ufw status
6.5.4 安装容器运行时
以下两种容器运行时任选其一即可。这里就用容器运行时containerd。但为了方便起见,还是把两种容器运行时的部署方法都列出来。
6.5.4.1 容器运行时一:docker-ce和cri-dockerd
6.5.4.1.1 安装docker
#更新必要的系统工具
apt-get -y update
apt-get -y install apt-transport-https ca-certificates curl software-properties-common
#添加GPG 密钥
curl -fsSL https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
#设置存储库
add-apt-repository "deb [arch=amd64] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
#更新包索引
apt-get -y update
#查询docker-ce版本
apt-cache madison docker-ce
#安装指定版本docker
apt-get -y install docker-ce=5:26.0.0-1~ubuntu.22.04~jammy docker-ce-cli=5:26.0.0-1~ubuntu.22.04~jammy
##kubelet需要让docker容器引擎使用systemd作为CGroup的驱动,其默认值为cgroupfs,因而,我们还需要编辑docker的配置文件/etc/docker/daemon.json,添加如下内容,其中的registry-mirrors用于指明使用的镜像加速服务
echo '{
"registry-mirrors": [
"https://registry.docker-cn.com"
],
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "200m"
},
"storage-driver": "overlay2"
}
' > /etc/docker/daemon.json
#重启docker并设置开机自启
systemctl daemon-reload && systemctl start docker && systemctl enable docker
6.5.4.1.2 安装cri-dockerd
开始说到Kubelet时提到CRI和CR,其实支持CRI的 "container runtime"包括Docker、Containerd、CRI-O等。
Kubernetes自v1.24移除了对docker-shim的支持,而Docker Engine默认又不支持CRI规范,因而二者将无法直接完成整合。为此,Mirantis和Docker联合创建了cri-dockerd项目,用于为Docker Engine提供一个能够支持到CRI规范的垫片,从而能够让Kubernetes基于CRI控制Docker(即kubelet-->cri-dockerd-->docker-ce)。
cri-dockerd项目提供了预制的二进制格式的程序包,用户按需下载相应的系统和对应平台的版本即可完成安装。
wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.1/cri-dockerd_0.3.1.3-0.ubuntu-jammy_amd64.deb
dpkg -i cri-dockerd_0.3.1.3-0.ubuntu-jammy_amd64.deb
6.5.4.2 容器运行时二:containerd
Ubuntu 22.04上安装Containerd有两种选择,一是Ubuntu系统官方程序包仓库中的containerd,另一个则是Docker社区提供的containerd.io。本文将选择使用后者。
6.5.4.2.1 安装并启动Containerd.io
首先,生成containerd.io相关程序包的仓库,这里以阿里云的镜像服务器为例进行说明。
apt -y install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | apt-key add -
add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
apt -y update
安装相关的程序包,Ubuntu 22.04上要使用的程序包名称为containerd.io。
apt-get -y install containerd.io
6.5.4.2.2 配置containerd.io
接下来,编辑生成的配置文件(/etc/containerd/contig.toml),完成如下几项相关的配置
①修改containerd使用SystemdCgroup
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
②配置Containerd使用国内Mirror站点上的pause镜像及指定的版本
[plugins."io.containerd.grpc.v1.cri"]
sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.9"
③配置Containerd使用国内的Image加速服务,以加速Image获取
[plugins."io.containerd.grpc.v1.cri".registry]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://docker.mirrors.ustc.edu.cn", "https://registry.docker-cn.com"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.k8s.io"]
endpoint = ["https://registry.aliyuncs.com/google_containers"]
用containerd config dump | grep -iE "mirrors"命令检查配置
最后,重新启动containerd服务即可。
systemctl daemon-reload
systemctl restart containerd
6.5.4.2.3 配置crictl客户端
安装containerd.io时,会自动安装命令行客户端工具crictl,该客户端通常需要通过正确的unix sock文件才能接入到containerd服务。编辑配置文件/etc/crictl.yaml,添加如下内容即可。
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: true
随后即可正常使用crictl程序管理Image、Container和Pod等对象。
6.5.5 各节点安装kubeadm、kubelet、kubectl
在各主机上生成kubelet和kubeadm等相关程序包的仓库。这里用阿里云镜像仓库
curl -fsSL https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.29/deb/Release.key | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.29/deb/ /" | tee /etc/apt/sources.list.d/kubernetes.list
apt-get -y update
接着,在各主机安装kubelet、kubeadm和kubectl等程序包,并将其设置为随系统启动而自动引导。
apt install -y kubelet kubeadm kubectl
systemctl enable kubelet
6.5.6 整合kubelet和cri-dockerd(仅cri-dockerd需要)
仅支持CRI规范的kubelet需要经由遵循该规范的cri-dockerd完成与docker-ce的整合。
6.5.6.1 配置cri-dockerd
##配置cri-dockerd,确保其能够正确加载到CNI插件
#编辑/usr/lib/systemd/system/cri-docker.service文件,确保其Service配置段中的ExecStart的值类似如下内容。
ExecStart=/usr/bin/cri-dockerd --container-runtime-endpoint fd:// --network-plugin=cni --cni-bin-dir=/opt/cni/bin --cni-cache-dir=/var/lib/cni/cache --cni-conf-dir=/etc/cni/net.d --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.9
需要添加的各配置参数(各参数的值要与系统部署的CNI插件的实际路径相对应):
• --network-plugin:指定网络插件规范的类型,这里要使用CNI;
• --cni-bin-dir:指定CNI插件二进制程序文件的搜索目录;
• --cni-cache-dir:CNI插件使用的缓存目录;
• --cni-conf-dir:CNI插件加载配置文件的目录;
• --pod-infra-container-image:Pod中的pause容器要使用的Image,默认为registry.k8s.io上的pause仓库中的镜像;不能直接获取到该Image时,需要明确指定为从指定的位置加载,例如“registry.aliyuncs.com/google_containers/pause:3.9”。
#配置完成后,重载并重启cri-docker.service服务
systemctl daemon-reload && systemctl restart cri-docker.service
6.5.6.2 配置kubelet
配置kubelet,为其指定cri-dockerd在本地打开的Unix Sock文件的路径,该路径一般默认为“/run/cri-dockerd.sock“。编辑文件/etc/sysconfig/kubelet,为其添加如下指定参数
KUBELET_KUBEADM_ARGS="--container-runtime=remote --container-runtime-endpoint=/run/cri-dockerd.sock"
提示:若/etc/sysconfig目录不存在,则需要先创建该目录。
需要说明的是,该配置也可不进行,而是直接在后面的各kubeadm命令上使用“--cri-socket unix:///run/cri-dockerd.sock”选项。
6.5.7 初始化首个Master节点(在K8S-Master1节点操作)
在运行初始化命令之前先运行如下命令单独获取相关的镜像文件,而后再运行后面的kubeadm init命令,以便于观察到镜像文件的下载过程。
列出image信息,可指定镜像版本。由如下的命令结果可以看出,相关的Image都来自于registry.k8s.io,该服务上的Image通常需要借助于代理服务才能访问到。
kubeadm config images list [--kubernetes-version <version>]
若需要从国内的Mirror站点下载Image,还需要在命令上使用“--image-repository”选项来指定Mirror站点的相关URL。例如,下面的命令中使用了该选项将Image Registry指向国内可用的Aliyun的镜像服务,其命令结果显示的各Image也附带了相关的URL。
kubeadm config images list --image-repository=registry.aliyuncs.com/google_containers
下载相关镜像。当无法访问registry.k8s.io时,可以在如下命令中使用“--image-repository=registry.aliyuncs.com/google_containers”选项,以便从国内的镜像服务中获取各Image。如下命令中的cri-socket选项,仅在cri-dockerd运行时需明确指定,containerd.io无需指定。
kubeadm config images pull --cri-socket unix:///run/cri-dockerd.sock --image-repository=registry.aliyuncs.com/google_containers [--kubernetes-version <version>]
初始化Master节点。需要注意的是,若使用docker-ce和cri-dockerd运行时,则还要在如下命令上明确配置使用“--cri-socket=unix:///var/run/cri-dockerd.sock”选项。
kubeadm init --control-plane-endpoint="kubeapi.wxd.com" --kubernetes-version=v1.28.2 --pod-network-cidr=10.244.0.0/16 --service-cidr=10.96.0.0/12 --token-ttl=0 --upload-certs --image-repository=registry.aliyuncs.com/google_containers
命令中的各选项简单说明如下:
• --image-repository:指定要使用的镜像仓库,默认为registry.k8s.io;
• --kubernetes-version:kubernetes程序组件的版本号,它必须要与安装的kubelet程序包的版本号相同;
• --control-plane-endpoint:控制平面的固定访问端点,可以是IP地址或DNS名称,会被用于集群管理员及集群组件的kubeconfig配置文件的API Server的访问地址;单控制平面部署时可以不使用该选项;
• --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一类的网络插件需要手动指定该地址;
• --apiserver-advertise-address:apiserver通告给其他组件的IP地址,一般应该为Master节点的用于集群内部通信的IP地址,0.0.0.0表示节点上所有可用地址;
• --token-ttl:共享令牌(token)的过期时长,默认为24小时,0表示永不过期;为防止不安全存储等原因导致的令牌泄露危及集群安全,建议为其设定过期时长。未设定该选项时,在token过期后,若期望再向集群中加入其它节点,可以使用如下命令重新创建token,并生成节点加入命令
• --upload-certs:上传首个控制平面所生成的CA证书及相关信息,可传给其它节点使用
6.5.8 初始化完成后的操作
#第1个步骤提示, Kubernetes集群管理员认证到Kubernetes集群时使用的kubeconfig配置文件
mkdir -p $HOME/.kube
#kubeadm init命令初始化控制平面时会自动生成一个用于管理员权限的配置文件/etc/kubernetes/admin.conf,将它复制为常用用户的$HOME/.kube/config文件后即可以集群管理员身份进行访问
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
#第2个步骤提示,为Kubernetes集群部署一个网络插件,具体选用的插件则取决于管理员。这里使用Flannel(此步骤在每个节点执行)
mkdir /opt/bin
curl -L https://github.com/flannel-io/flannel/releases/download/v0.21.4/flanneld-amd64 -o /opt/bin/flanneld
chmod +x /opt/bin/flanneld
#在初始化的首个Master节点部署kube-flannel
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
#查看flannel运行状态,如下输出显示flannel正在运行。如果Pod状态为Pending说明正在下载镜像
kubectl get pod -n kube-flannel
#验证Master节点的就绪情况。如下输出说明Master节点已就绪
kubectl get nodes
#在token过期后,若期望再向集群中加入其它节点,可以使用如下命令重新创建token,并生成节点加入命令
kubeadm token create --print-join-command
6.5.9 添加节点到集群
以下命令在K8S-Node1、K8S-Node2、K8S-Node3节点执行。再次提示,若使用docker-ce和cri-dockerd运行时环境,则需要在如下命令中额外添加“--cri-socket=unix:///var/run/cri-dockerd.sock”选项。
kubeadm join kubeapi.wxd.com:6443 --token 704dr8.3s293ofh5vo0yxux --discovery-token-ca-cert-hash sha256:1a7ebb6439ff105e8bd1d472a1c0d6d1ffff6f8328ff64736dda23650e5c9b43
6.5.10 验证节点添加结果
当节点状态为NotReady时,说明此时正在下载镜像。镜像下载完成状态就Ready了。
6.5.11 Kubernetes集群使用Calico网络插件
6.5.11.1 重置集群
由于之前的集群使用了Flannel网络插件,需要先重置Node节点,再重置Master节点。最后还需一些清理操作,包括清理iptables规则或ipvs规则、删除相关的各文件等。
#Kubernetes集群重置命令,生产环境慎用!
kubeadm reset --cri-socket unix:///run/cri-dockerd.sock &&
rm -rf /etc/kubernetes/ /var/lib/kubelet /var/lib/dockershim /var/run/kubernetes /var/lib/cni /etc/cni/net.d
6.5.11.2 初始化Master节点
kubeadm init --control-plane-endpoint="kubeapi.wxd.com" --kubernetes-version=v1.27.1 --pod-network-cidr=192.168.0.0/16 --service-cidr=10.96.0.0/12 --token-ttl=0 --cri-socket unix:///run/cri-dockerd.sock --upload-certs
6.5.11.3 初始化完成后的操作
1st.准备kubeconfig配置文件。步骤同上。
2nd.准备calico网络插件
下载地址:https://docs.tigera.io/calico/latest/getting-started/kubernetes/self-managed-onprem/onpremises
此文件针对K8S集群小于50个节点使用
curl -O
https://raw.githubusercontent.com/projectcalico/calico/v3.25.1/manifests/calico.yaml
默认calico的子网掩码是26位,可以手动调整为24位。打开calico.yaml添加如下配置:
- name: CALICO_IPV4POOL_BLOCK_SIZE
value: "24"
之后kubectl apply -f calico.yaml即可
6.5.11.4 添加Node节点
#重新生成节点加入命令
kubeadm token create --print-join-command
kubeadm join kubeapi.wxd.com:6443 --token na0paf.33kf2yxunpxtkt4o --discovery-token-ca-cert-hash sha256:80497cf65bdc764ffa261dd2b853e5efd6e5fad3ce5f1cbf4f748e38ac4e12ef --cri-socket unix:///run/cri-dockerd.sock
6.5.11.5 添加Master节点,为后续做Master节点高可用做准备
#重新上传证书并生成新的解密密钥
kubeadm init phase upload-certs --upload-certs
[upload-certs] Storing the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace
[upload-certs] Using certificate key:
#这一串key后续添加Master节点会用到
4b36fc6116dcf9907631c49e27237eabdf3b2d44860e185697585b5dfbe65d55
#要加上--control-plane --certificate-key再跟certificate key的那一串,不然就会添加为Node节点
kubeadm join kubeapi.wxd.com:6443 --token na0paf.33kf2yxunpxtkt4o --discovery-token-ca-cert-hash sha256:80497cf65bdc764ffa261dd2b853e5efd6e5fad3ce5f1cbf4f748e38ac4e12ef --control-plane --certificate-key 4b36fc6116dcf9907631c49e27237eabdf3b2d44860e185697585b5dfbe65d55 --cri-socket unix:///run/cri-dockerd.sock
6.6 部署附加组件
6.6.1 部署OpenELB
OpenELB 是一个开源的云原生负载均衡器实现,可以在基于裸金属服务器、边缘以及虚拟化的 Kubernetes 环境中使用 LoadBalancer 类型的 Service 对外暴露服务。其核心功能如下:
- BGP模式和二层网络模式下的负载均衡
- ECMP路由和负载均衡
- IP地址池管理
- 基于CRD来管理BGP配置
#部署OpenELB到Kubernetes集群
kubectl apply -f https://raw.githubusercontent.com/openelb/openelb/master/deploy/openelb.yaml
#确认openelb-manager Pod已经处于Running状态,且容器已经Ready
kubectl get pod -n openelb-system
下面的示例基于layer2模式创建了一个Eip资源对象,它提供了一个地址池给LoadBalancer Service使用。
vim eip.yaml
apiVersion: network.kubesphere.io/v1alpha2
kind: Eip
metadata:
name: eip-pool
annotations:
# 指定当前Eip作为向LoadBalancer Server分配地址时使用默认的eip对象;
eip.openelb.kubesphere.io/is-default-eip: "true"
spec:
# 地址范围,也可以使用单个IP,或者带有掩码长度的网络地址;
address: 192.168.131.51-192.168.131.200
# 要使用的OpenELB模式,支持bgp、layer2和vip三种,默认为bgp;
protocol: layer2
# OpenELB侦听ARP或NDP请求时使用的网络接口名称,仅layer2模式下有效;
interface: ens33
disable: false
应用该清单并查看效果。
测试。创建Deployment和LoadBalancer Service,测试地址池是否已经能正常向Service分配LoadBalancer IP。
kubectl create deployment demoapp --image=ikubernetes/demoapp:v1.0 --replicas=2
kubectl create service loadbalancer demoapp --tcp=80:80
kubectl get service demoapp
此结果表明EIP地址分配已经能够正常进行。随后,即可于集群外部的客户端上通过IP地址192.168.131.51对demoapp服务发起访问测试。
删除测试资源
kubectl delete service/demoapp deployment/demoapp
6.6.2 部署Kuboard
kubectl apply -f https://raw.githubusercontent.com/iKubernetes/learning-k8s/master/Kuboard/deploy.yaml
查看相关资源的信息。看到分配的外部IP为192.168.131.51。
登录。管理员用户名为admin,密码为Kuboard123
登录之后添加集群。这里使用读取KubeConfig内容的方式添加。通过kubectl config view --raw命令读取kubeconfig配置,将其粘贴到网页的kubeconfig配置界面。
之后选择管理员->集群概要,就能显示集群的信息了。
此外,还可以通过Ingress-Nginx开放Kuboard(需要事先部署好Ingress-Nginx)。apply此清单之后再将kuboard.wxd.com域名解析至Ingress-Nginx相关的IP地址上,即可使用kuboard.wxd.com来访问kuboard服务。
vim kuboard-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kuboard
namespace: kuboard
spec:
ingressClassName: nginx
rules:
- host: kuboard.wxd.com
http:
paths:
- path: /
backend:
service:
name: kuboard-v3
port:
number: 80
pathType: Prefix
6.7 K8S集群运行Nginx
#创建deployment。名字为nginx,使用镜像是nginx:alpine,副本为3
kubectl create deployment nginx --image nginx:alpine --replicas=3
#查看pod的详细信息
kubectl get pods -o wide
问题在于,由于节点宕机或pod可能会被误删除等原因,pod的ip会发生变化。需要加一个固定的服务访问入口,即Service。
#创建nodeport类型的service。service名字与deployment的名字保持一致
#关于--tcp=80:80。前一个80是service的端口,后一个80是上游服务器端口
kubectl create service nodeport nginx --tcp=80:80
#查看service。svc即service的简写
kubectl get svc
通过31941端口可以在集群外部访问Service。访问方式为:集群任意节点ip:31941
6.8 集群管理相关的其它操作
6.8.1 证书管理
kubeadm部署集群时设定的证书通常在一年后到期。为此需要定期查看证书有效期并定期更新证书。
检查证书是否过期
kubeadm certs check-expiration
该命令显示 /etc/kubernetes/pki 文件夹中的客户端证书以及 kubeadm(admin.conf、controller-manager.conf 和 scheduler.conf) 使用的 kubeconfig 文件中嵌入的客户端证书的到期时间/剩余时间。
手动更新所有证书。注意:kubeadm会在控制平面升级时自动更新所有的证书。
kubeadm certs renew all