云原生技术与应用-Kubernetes架构原理与集群环境部署
目录
一.为什么需要kubernetes
1.对于开发人员
2.对于运维人员
二.kubernetes带来的挑战
三.kubernetes架构解析
1.master节点的组件
2.node节点包含的组件
3.kubernetes网络插件
四.kubernetes快速安装kubernetes集群
1.部署docker环境
2.部署kubernetes集群
五.Metrics-server部署
1.修改yaml文件并安装
2.测试安装结果
一.为什么需要kubernetes
很多人会有疑问,有了 Docker 为什么还用 Kubernetes?
在业务开始进行容器化时,前期需要容器化的项目可能并不多,涉及的容器也并不多,此时基于 Docker 容器直接部署至宿主机也能实现基本的需求。但是随着项目越来越多,管理的容器也会越来越多,此时使用 “裸容器” 部署的方式管理起来就显得很吃力,并且随着业务量的增加,会明显体会到 “裸容器” 的不足。比如:
-
宿主机宕机造成该宿主机上的容器不可用,且无法自动恢复。
-
容器明明在运行,接口就是不通(健康检查做得不到位)
-
应用程序部署、回滚、扩缩容困难。
-
成百上千的容器和涉及的端口难以维护。
上面的问题知识做一个简单的罗列,真正使用时还有很多其他的问题。大家也可能使用过 Docker - compose、Docker - swarm 等编排工具,但是这些工具的功能和 Kubernetes 比起来还是相差很多的。所以注定 Kubernetes 编排工具将成为主流的容器编排工具。
1.对于开发人员
对于开发人员而言,Kubernetes 是提升开发效率、保障应用稳定交付的重要助力,核心价值体现在以下方面:
一、环境一致性,告别 “本地能跑线上崩”
开发时用 Docker 打包应用及依赖成镜像,K8s 能让镜像在开发、测试、生产环境以统一方式运行,消除环境差异导致的调试成本,开发人员只需专注代码逻辑,无需反复适配环境。
二、简化复杂应用部署
开发微服务等复杂应用,涉及多个服务、依赖,K8s 可通过配置文件(如 Deployment、Service),定义服务副本数、网络规则等,一键部署整套应用,无需手动逐个启动容器、配置网络,降低部署复杂度。
2.对于运维人员
对于运维人员来说,Kubernetes 是大幅提升运维效率、保障系统稳定可靠的 “利器”,核心价值体现在以下关键场景:
一、自动化运维,解放人力
-
批量部署与管理:面对成百上千容器,无需逐台操作。通过 K8s 配置文件(如 Deployment),定义应用副本数、资源限额等,一键部署 / 更新多实例,轻松管理复杂应用集群。
-
故障自愈:自动监控容器、节点状态,容器崩溃自动重启,节点故障时迁移容器到健康节点,无需人工值守排查、重启,减少服务中断时间。
二、资源精细化管控
-
资源调度:智能分配容器到集群节点,平衡 CPU、内存负载,避免节点过载或闲置,提升服务器资源利用率(比如把低负载容器调度到空闲节点)。
-
资源隔离:为不同应用 / 服务设置 CPU、内存限额(Requests/Limits),防止某一应用 “抢占” 资源导致其他服务故障,保障多业务稳定共存。
二.kubernetes带来的挑战
Kubernetes 从诞生至今,一路突飞猛进,在容器编排的领域过关斩将,最终拿下了容器编排的冠军宝座,成为最无可替代、不可撼动的佼佼者,但是针对 Kubernetes 的学习和使用始终是一个很大的难题。
首先,Kubernetes 本身的学习就很困难,因为 Kubernetes 概念太多,涉及的知识面也非常广泛,可能学习了一个月也无法入门,甚至连集群也搭建不出来,使人望而却步。并且 Kubernetes 的技术能力要求也比较高,因为运维不仅仅均线于传统运维,有时候可能要修改业务代码、制定业务上线体系、给研发人员在开发应用中提供更好的建议等。需要掌握的知识也有很多,可能需要掌握公司内所有使用带的代码,比如代码如何进行编译、如何正确发布、如何修改代码配置文件等,这对于运维人员也是一种挑战。Kubernetes 的诞生把运维从传统的运维转变到了 DevOps 方向,需要面临的问题更多,需要面临的新技术也很多,但是当真正掌握 Kubernetes 的核心和涉及理念,就会收益终身。
三.kubernetes架构解析
1.master节点组件
master 节点是 Kubernetes 集群的控制节点,在生产环境中不建议部署集群核心组件外的任何容器(在 kubeadm 安装方式下,系统组件以容器方式运行在 master 节点的宿主机器上;二进制安装方式下,系统组件以守护进程的方式运行,master 节点可以不运行任何容器 ),公司业务程序的容器是不建议部署在 master 节点上,以避免升级或者维护时对业务造成影响。
(1) API server
API server 提供了集群网关,是整个集群的控制中枢,提供集群中各个模块之间的数据交换,并将集群信息存储到 ETCD 集群中。同时,它也是集群管理、资源配额、提供完备的集群安全机制的入口,为集群各类资源对象提供增删改查,API server 在客户端对集群进行访问。客户端需要通过认证,并使用 API server 作为访问节点和 pod (以及服务)的堡垒和代理 / 通道。
-
API 服务器公开 Kubernetes API。
-
REST/kubectl 的入口点 —— 它是 Kubernetes 控制平面的前端。
-
它跟踪所有集群组件的状态并管理它们之间的交互。
-
它旨在水平扩展。
-
它使用 YAML/JSON manifest 文件。
-
它验证和处理通过 API 发出的请求。
(2) Scheduler
Scheduler 主要功能是资源调度,将 pod 调度到对应的主机上。依据请求资源的可用性、服务请求的质量等约束条件,k8s 也支持用户自己提供的调度器。
-
它将 pod 调度到工作节点。
-
它监视 api-server 以查找没有分配节点的新创建的 Pod,并选择一个健康的节点让它们运行。
-
如果没有合适的节点,则 Pod 将处于挂起状态,直到出现这样一个健康的节点。
-
它监视 API Server 的新工作任务。
(3) Controller Manager
Controller Manager 负责维护集群的状态,比如故障检测、内存垃圾回收、滚动更新等,也执行 API 业务逻辑;k8s 默认提供 replication controller、replicaset controller、daemonset controller 等控制器。
-
它监视它管理的对象的期望状态并通过 API 服务器监视它们的当前状态。
-
采取纠正措施以确保当前状态与所需状态相同。
-
它是控制器的控制器。
-
它运行控制器进程,从逻辑上讲,每个控制器都是一个单独的进程,但为了降低复杂性,它们都被编译成一个二进制文件并在单个进程中运行。
(4) etcd
etcd 用于可靠的存储集群的配置数据,是一种持久性、轻量级、分布式的键值数据存储组件,可以理解为一种分布式的非关系型数据库。etcd 是集群的状态,k8s 默认使用分布式的 etcd 集群整体存储用来实现发现服务和共享配置集群的所有状态都存储在 etcd 实例中,并具有监控的能力,因此当 etcd 中的信息发生变化时,能够快速地通知集群中相关的组件。
-
它是一个一致的、分布式的、高度可用的键值存储。
-
它是有状态的持久存储,用于存储所有 Kubernetes 集群数据(集群状态和配置 )。
-
它是集群的真相来源。
-
它可以是控制平面的一部分,也可以在外部进行配置。
etcd 集群最少 3 个节点,容错点才会有 1 个。3 个节点和 4 个节点的容错能力是一样的,所以有时候保持奇数节点更好,从这里可以判断出我们在部署 k8s 的时候,至少有 3 个节点,才保证 etcd 有 1 个节点容错性。
另外,etcd 的 Leader 选举和数据写入都需要半数以上的成员投票通过确认,因此,集群最好由奇数个成员组成,以确保集群内部一定能够产生多数投票通过的场景。所以 etcd 集群至少需要 3 个以上的奇数个成员。
如果使用偶数个节点,可能出现以下问题:
-
偶数个节点集群不可用风险更高,表现在选主(Leader 选举)过程中,有较大概率的等额选票,从而触发下一轮选举。
-
偶数个节点集群在某些网络分割的场景下无法正常工作。当网络分割发生后,将集群节点对半分割开,形成脑裂。
2.node节点包含的组件
Node 节点也被成为 worker 节点,是主要负责部署容器的主机,集群中的每个节点都必须具备容器的 Runtime(运行时),比如 docker
kubelet 作为守护进程运行在每个 Node 节点上,负责监测该节点上所有的 pod,同时负责上报该节点上所有 pod 的运行状态,确保节点上的所有容器都能正常运行。当 Node 节点宕机或故障时,该节点上运行的 pod 会被自动转移到其他节点上。
(1)容器运行时
docker 引擎是本地的容器运行时环境,负责镜像管理以及 pod 和容器的真正运行。K8s 本身并不提供容器运行时环境,但提供了接口,可以插入所选择的容器运行时环境,目前支持 Docker 和 rkt。容器运行时是负责运行容器(在 Pod 中)的软件,为了运行容器,每个工作节点都有一个容器运行时引擎,它从容器镜像注册表(container image registry)中提取镜像并启动和停止容器。
Kubernetes 支持多种容器运行时:
-
Docker
-
containerd
-
CRI - O
-
Kubernetes CRI(Container Runtime Interface,容器运行时接口)的任何实现。
(2)kubelet
kubelet 是 node 节点上最主要的工作代理,用于汇报节点状态并负责维护 pod 的生命周期,也负责 volume(CVI)和网络(CNI)的管理。kubelet 是 pod 和节点 API 的主要实现者,负责驱动容器执行层。作为基本的执行单元,pod 可以拥有多个容器和存储卷,能够方便地在每个容器中打包一个单一的应用,从而解脱了应用构建时和部署时所关心的事项,方便在物理机或虚拟机之间进行迁移。
-
它是在集群中的每个节点上运行的代理。
-
它充当着 API Server 和节点之间的管道。
-
它确保容器在 Pod 中运行并且它们是健康的。
-
它实例化并执行 Pod。
-
它监视 API Server 的工作任务。
-
它从主节点那里得到指令并报告给主节点。
(3)kube - proxy 代理
kube - proxy 代理对抽象的应用地址的访问,服务提供了一种访问一群 pod 的途径,kube - proxy 负责为服务提供集群内部的服务发现和应用的负载均衡(通常利用 iptables 规则),实现服务到 pod 的路由和转发,此方式通过创建一个虚拟的 IP 来实现,客户端能够访问此 IP,并能够将服务透明地代理至 pod。
-
它是网络组件,在网络中起着至关重要的作用。
-
它管理 IP 转换和路由。
-
它是运行在集群中每个节点上的网络代理。
-
它维护节点上的网络规则,这些网络规则允许从集群内部或外部与 Pod 进行网络通信。
-
它确保每个 Pod 获取唯一的 IP 地址。
-
这使得 pod 中的所有容器共享一个 IP 成为可能。
-
它促进了 Kubernetes 网络服务和服务中所有 pod 的负载平衡。
-
它处理单个主机子网并确保服务可供外部各方使用。
3.kubernetes网络插件
CNI(容器网络接口)是一个云原生计算基金会项目,它包含了一些规范和库,用于编写在 Linux 容器中配置网络接口的一系列插件。CNI 只关注容器的网络连接,并在容器被删除时移除所分配的资源。Kubernetes 使用 CNI 作为网络提供商和 Kubernetes Pod 网络之间的接口。
(1) Flannel 网络
由 CoreoSk 开发的一个项目,很多部署工具或者 k8s 的发行版都是默认安装,flannel 是可以用集群现有的 etcd,利用 api 方式存储自身状态信息,不需要专门的数据存储,是配置第三层的 ipv4 Overlay 网络,在此网络内,每个节点一个子网,用于分配 ip 地址,配置 pod 时候,节点上的网桥接口会为每个新容器分配一个地址,同一主机中的 pod 可以使用网桥通信,不同主机的 pod 流量封装在 udp 数据包中,路由到目的地。
Flannel 通过每个节点上启动一个 flnnel 的进程,负责给每一个节点上的子网划分、将子网网段等信息保存至 etcd,具体的报文转发是后端实现,在启动时可以通过配置文件指定不同的后端进行通信,目前有 UDP、VXLAN、host-gateway 三种,VXLAN 是官方推荐,因为性能良好,不需人工干预。UDP、VXLAN 是基于三层网络即可实现,host-gateway 模式需要集群所有机器都在同一个广播域、就是需要在二层网络在同一个交换机下才能实现,host-gateway 用于对网络性能要求较高的常见,需要基础网络架构支持,UDP 用于测试或者不支持 VXLAN 的 linux 内核。反正一般小规模集群是完全够用的,直到很多功能无法提供时在考虑其他插件。
(2) Calico 网络
虽然 falnnel 很好,但是 calico 因为其性能、灵活性都好而备受欢迎,calico 的功能更加全面,不但具有提供主机和 pod 间网络通信的功能,还有网络安全和管理的功能,而且在 CNI 框架之内封装了 calico 的功能,calico 还能与服务网络技术 Istio 集成,不但能够更加清楚的看到网络架构也能进行灵活的网络策略的配置,calico 不使用 Overlay 网络,配置在第三层网络,使用 BGP 路由协议在主机之间路由数据包,意味着不需要包装额外的封装层。主要点在网络策略配置这一点,可以提高安全性和网络环境的控制。
如果集群规模较大,选择 calico 没错,当然 calico 提供长期支持,对于一次配置长期使用的目的来说,是个很好的选择。
四.kubeadm快速安装kubernetes集群
主机名 | IP 地址 | 操作系统 | 主要软件 |
---|---|---|---|
k8s-master | 192.168.10.101 | CentOS7.9 两核、4G | Docker CE, Kube-apiserver, Kube-controller-manager, Kube-scheduler, Kubelet, Etcd, Kube-proxy |
k8s-node01 | 192.168.10.102 | CentOS7.9 两核、2G | Docker CE , Kubectl , Kube-proxy,Calico |
k8s-node02 | 192.168.10.103 | CentOS7.9 两核、2G | Docker CE , Kubectl , Kube-proxy,Calico |
1. 部署docker环境(此步骤在三个节点都执行)
(1)关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
(2)禁用selinux
sed -i '/^SELINUX=/s/enforcing/disabled/' /etc/selinux/config
setenforce 0
(3)安装docker
下载docker的repo文件
curl -o /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-cd.repo
替换仓库地址
sed -i 's/$releasever/8/g' /etc/yum.repos.d/docker-ce.repo
sed -i 's/$basearch/x86_64/g' /etc/yum.repos.d/docker-ce.repo
更新索引文件并安装docker
dnf clean all
dnf makecache
dnf -y install docker-ce
添加国内镜像站
mkdir /etc/docker/
vim /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"registry-mirrors": [
"https://docker.m.daocloud.io",
"https://docker.imgdb.de",
"https://docker-0.unsee.tech",
"https://docker.hlmirror.com"
]
}
开启docker服务
systemctl daemon-reload
systemctl restart docker
systemctl enable docker
docker version
优化内核参数
vim /etc/sysctl.conf
net.ipv4.ip_forward=1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
sysctl -p
2.部署kubernetes集群
(1)配置三台主机的主机名
主机一
hostnamectl set-hostname k8s-master
bash
主机二
hostnamectl set-hostname k8s-node01
bash
主机三
hostnamectl set-hostname k8s-node02
bash
(2)在三台主机上绑定hosts
vim /etc/hosts
192.168.10.101 k8s-master
192.168.10.102 k8s-node01
192.168.10.103 k8s-node02
(3)关闭交换分区
swapoff -a
sed -i '/swap/s/^/#/' /etc/fstab
(4)配置kubernetes的yum源
操作节点:k8s-master,k8s-node01,k8s-node02
vim /etc/yum.repos.d/kubernetes.repo
[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
dnf clean all
(5)安装kubelet,kubeadm和kubectl
操作节点:k8s-master,k8s-node01,k8s-node02
dnf -y install kubelet-1.23.0 kubeadm-1.23.0 kubectl-1.23.0
(6)kubelet设置开机启动
操作节点:k8s-master,k8s-node01,k8s-node02
systemctl enable kubelet
(7)生成初始化配置文件
操作节点:k8s-master
kubeadm config print init-defaults > init-config.yaml
(8)修改初始化配置文件
操作节点:k8s-master
vim init-config.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.10.101
bindPort: 6443
nodeRegistration:
criSocket: /var/run/dockershim.sock
name: k8s-master
taints: nullapiServer:
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns:
type: CoreDNS
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.aliyuncs.com/google_containers
kind: ClusterConfiguration
kubernetesVersion: v1.23.0networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12
podSubnet: 10.244.0.0/16
scheduler: {}
(9)拉取所需镜像
操作节点:k8s-master
kubeadm config images list --config init-config.yaml
(10) 初始化k8s-master
操作节点:k8s-master
kubeadm init --config=init-config.yaml
(11)复制配置文件到用户的home目录
操作节点:k8s-master
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
(12)node节点加入集群
kubeadm join 192.168.10.101:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash \
sha256:8b17b7d607ab7f79c2249c58d74525368bbb15ad884c365aaa1a968b9833d107
(13)在k8s-master节点设置环境变量并查看节点信息
echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
source ~/.bash_profile
kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master NotReady master 13m v1.19.4
k8s-node01 NotReady <none> 2m30s v1.19.4
k8s-node02 NotReady <none> 21s v1.19.4kubectl get pod -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-6d8c4cb4d-7swl9 0/1 Pending 0 3m58s
kube-system coredns-6d8c4cb4d-rrlpp 0/1 Pending 0 3m58s
kube-system etcd-k8s-master 1/1 Running 1 (85s ago) 4m11s
kube-system kube-apiserver-k8s-master 1/1 Running 1 (75s ago) 4m12s
kube-system kube-controller-manager-k8s-master 1/1 Running 1 (84s ago) 4m12s
kube-system kube-proxy-5hgbq 1/1 Running 1 (82s ago) 3m54s
kube-system kube-proxy-sdq9b 1/1 Running 1 (79s ago) 3m46s
kube-system kube-proxy-txdcr 1/1 Running 1 (85s ago) 3m58s
kube-system kube-scheduler-k8s-master 1/1 Running
(14)部署calico网络插件
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
[root@k8s-master ~]# kubectl create -f calico.yamlkubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane,master 22h v1.23.0
k8s-node01 Ready <none> 22h v1.23.0
k8s-node02 Ready <none> 22h v1.23.0kubectl get pod --all-namespaces
五. Metrics-server部署
1.修改yaml文件并安装
vim components.yaml
spec:
containers:
- args:
- --kubelet-insecure-tls ##添加
- --cert-dir=/tmp
- --secure-port=4443
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --kubelet-use-node-status-port- --metric-resolution=15s
image: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server:v0.6.3
kubectl create -f components.yaml
2. 测试安装结果
kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
k8s-master 99m 4% 1201Mi 31%
k8s-node01 57m 2% 1597Mi 42%
k8s-node02 37m 3% 616Mi 16%kubectl top pod -A
NAMESPACE NAME CPU(cores) MEMORY(bytes)
kube-system calico-kube-controllers-64cc74d646-vtjgc 1m 27Mi
kube-system calico-node-jswkq 17m 156Mi
kube-system calico-node-kfcr7 18m 169Mi
kube-system calico-node-sr28f 15m 161Mi
kube-system coredns-6d8c4cb4d-gggss 2m 64Mi
kube-system coredns-6d8c4cb4d-l6plx 2m 21Mi
kube-system etcd-k8s-master 14m 64Mi
kube-system kube-apiserver-k8s-master 37m 361Mi
kube-system kube-controller-manager-k8s-master 9m 55Mi
kube-system kube-proxy-4vn4c 1m 23Mi
kube-system kube-proxy-5dgbm 1m 69Mi
kube-system kube-proxy-tbqkz 1m 24Mi
kube-system kube-scheduler-k8s-master 3m 25Mi
kube-system metrics-server-66bdc46d86-4mfqw 3m 25Mi