技术

云计算02

2025/11/27
3
0

基础镜像:

registry.cn-beijing.aliyuncs.com/xxhf/hello-world:latest

registry.cn-beijing.aliyuncs.com/xxhf/busybox:latest

registry.cn-beijing.aliyuncs.com/xxhf/centos:7

registry.cn-beijing.aliyuncs.com/xxhf/ubuntu:22.04

registry.cn-beijing.aliyuncs.com/xxhf/alpine:3.18

registry.cn-beijing.aliyuncs.com/xxhf/nginx:1.22.1

registry.cn-beijing.aliyuncs.com/xxhf/node-exporter:1.6.1

registry.cn-beijing.aliyuncs.com/xxhf/centos7-alirepo:7

registry.cn-beijing.aliyuncs.com/xxhf/redis:alpine

registry.cn-beijing.aliyuncs.com/xxhf/nginx:1.27.0-debian-12-r5

registry.cn-beijing.aliyuncs.com/xxhf/nginx:1.22.1-centos7

  • Rockylinux:9

ccr.ccs.tencentyun.com/chijinjing/rockylinux:9

registry.cn-beijing.aliyuncs.com/xxhf/rockylinux:9

  • Registry

registry.cn-beijing.aliyuncs.com/xxhf/registry:2

  • Python:

registry.cn-beijing.aliyuncs.com/xxhf/python:3.7-alpine

  • Go

registry.cn-beijing.aliyuncs.com/xxhf/golang:1.20

  • stress:

registry.cn-beijing.aliyuncs.com/xxhf/stress:latest

  • 优雅退出:

registry.cn-beijing.aliyuncs.com/xxhf/iojs:onbuild

  • wordpress:

registry.cn-beijing.aliyuncs.com/xxhf/mysql:5.7

registry.cn-beijing.aliyuncs.com/xxhf/mysql:8.0

registry.cn-beijing.aliyuncs.com/xxhf/wordpress:php7.4

  • nginx-hello:

registry.cn-beijing.aliyuncs.com/xxhf/nginx-hello:plain-text

  • http-app:

registry.cn-beijing.aliyuncs.com/xxhf/http-app:v1

registry.cn-beijing.aliyuncs.com/xxhf/http-app:v2

registry.cn-beijing.aliyuncs.com/xxhf/http-app:v3

registry.cn-beijing.aliyuncs.com/xxhf/http-app:v4

registry.cn-beijing.aliyuncs.com/xxhf/http-app:v5

  • Ingress-Controller:

registry.cn-beijing.aliyuncs.com/xxhf/controller:v1.6.4

registry.cn-beijing.aliyuncs.com/xxhf/kube-webhook-certgen:v20220916

  • metrics-server

registry.cn-beijing.aliyuncs.com/xxhf/metrics-server:v0.6.4

  • 蓝绿发布

registry.cn-beijing.aliyuncs.com/xxhf/rollouts-demo:green

registry.cn-beijing.aliyuncs.com/xxhf/rollouts-demo:blue

  • Dashboard

registry.cn-beijing.aliyuncs.com/xxhf/dashboard:v2.7.0

  • NFS-Provisioner:

registry.cn-beijing.aliyuncs.com/xxhf/nfs-subdir-external-provisioner:v4.0.2

  • example-app

registry.cn-beijing.aliyuncs.com/xxhf/instrumented_app:latest

  • Jenkins

ccr.ccs.tencentyun.com/chijinjing/jenkins:2.492.2-jdk17

  • Gitlab

ccr.ccs.tencentyun.com/chijinjing/gitlab-ce:17.9.3-ce.0

日期2025.08.20学习日志

  1. kubernetes 组件介绍

  2. 什么是容器编排

容器技术的核心概念是容器、镜像、仓库,使用这三大基本要素我们就可以轻松地完成应用的打包、分发工作,实现“一次构建,到处运行”的梦想

不过,当我们熟练地掌握了容器技术,信心满满地要在服务器集群里大规模实施的时候,却会发现容器技术的创新只是解决了运维部署工作中一个很小的问题。现实生产环境的复杂程度实在是太高了,除了最基本的安装,还会有各式各样的需求,比如服务发现、负载均衡、状态监控、健康检查、扩容缩容、应用迁移、高可用等等

虽然容器技术开启了云原生时代,但它也只走出了一小步,再继续前进就无能为力了,因为这已经不再是隔离一两个进程的普通问题,而是要隔离数不清的进程,还有它们之间互相通信、互相协作的超级问题,困难程度是指数级别的上升

这些容器之上的管理、调度工作,就是这些年最流行的词汇:“容器编排”(Container Orchestration)。 容器编排这个词听起来好像挺高大上,但如果你理解了之后就会发现其实也并不神秘。像我们在 Docker 课里使用 Docker Compose 部署 WordPress 网站的时候,就是一种在单机环境下的容器编排

面对单机上的几个容器,Docker Compose 还可以应付,但如果规模上到几百台服务器、成千上万的容器,处理它们之间的复杂联系就必须要依靠计算机了,而目前计算机用来调度管理的“事实标准”就是 Kubernetes

  1. 什么是 Kubernetes

Kubernetes 背后有 Borg 系统十多年生产环境经验的支持,技术底蕴深厚,理论水平也非常高,一经推出就引起了轰动。然后在 2015 年,Google 又联合 Linux 基金会成立了CNCF(Cloud Native Computing Foundation,云原生基金会),并把 Kubernetes 捐献出来作为种子项目。

有了 Google 和 Linux 这两大家族的保驾护航,再加上宽容开放的社区,作为 CNCF 的“头把交椅”,Kubernetes 旗下很快就汇集了众多行业精英,仅用了两年的时间就打败了同期的竞争对手 Apache MesosDocker Swarm,成为了这个领域的唯一霸主

Kubernetes 到底能够为我们做什么呢?

Kubernetes 就是一个生产级别的容器编排平台和集群管理系统不仅能够创建、调度容器,还能够监控、管理服务器,它凝聚了 Google 等大公司和开源社区的集体智慧,从而让中小型公司也可以具备轻松运维海量计算节点——也就是“云计算”的能力

Kubernetes 可以说是一个集群级别的操作系统,主要功能就是资源管理和作业调度

Kubernetes 的官网(https://kubernetes.io/zh/

  • Borg

Borg 是谷歌内部的大规模集群管理系统,负责对谷歌内部很多核心服务的调度和管理。Borg的目的是让用户能够不必操心资源管理的问题,让他们专注于自已的核心业务,并且做到跨多个数据中心的资源利用率最大化

图示

AI 生成的内容可能不正确。

  • Kubernetes优点:

轻量级、开源、弹性伸缩、负载均衡

文本

AI 生成的内容可能不正确。

#Pod可以理解为容器,运行的任务

  1. kubernetes宏观架构:

图示

AI 生成的内容可能不正确。

:一共有Master Node、和Worker Node两种角色

#不管有几台服务器都有以上两种角色

  • Master Node(控制面):管理集群

  • Worker Node(数据面):运行用户的任务

#k8s里面高可用,至少使用三个master,并且配置相同

#整个woeker节点属于是一个资源池,运行任务时需要多少资源,就通过调度器找资源池的节点去运行任务

  1. 微观架构

图示

AI 生成的内容可能不正确。

master节点中有一个APIServer和scheduler和contorllers和etcd属于控制面的四个组件

  1. Kubernetes 的基本架构

图示

AI 生成的内容可能不正确。

#API Server是整个集群的入口,kuberctl作为客户端管理集群,去连接API Server

#数据面的kubelet去和master做数据交互。kube proxy做代理使用,外部的应用访问通过代理进行访问。调度器就是负责调度,控制器(controller manger)就是进行故障自愈和扩缩容等,整个集群的数据都放在etcd里面。

  • 工作流程:

  1. 每个 Node 上的 kubelet 会定期向 apiserver 上报节点状态,apiserver 再存到 etcd 里。

  2. 每个 Node 上的 kube-proxy 实现了 TCP/UDP 反向代理,让容器对外提供稳定的服务。

  3. scheduler 通过 apiserver 得到当前的节点状态,调度 Pod,然后 apiserver 下发命令给某个Node的kubelet,kubelet调用 container-runtime 启动容器。

  4. controller-manager 也通过 apiserver 得到实时的节点状态,监控可能的异常情况,再使用相应的手段去调节恢复。

  • Master Node控制面四个组件:

  • kube-apiserver(API服务器):是Master 节点——同时也是整个 Kubernetes 系统的唯一入口,它对外公开了一系列的 RESTful API,并且加上了验证、授权等功能,所有其他组件都只能和它直接通信,可以说是 Kubernetes 里的联络员

图形用户界面, 文本, 应用程序

AI 生成的内容可能不正确。

  • kube-scheduler(调度器):负责容器的编排工作,检查节点的资源状态,把 Pod 调度到最适合的节点上运行,相当于部署人员。因为节点状态和 Pod 信息都存储在 etcd 里,所以 scheduler 必须通过apiserver 才能获得

  • kube-controller-manager(控制管理器):负责维护容器和节点等资源的状态,实现故障检测、服务迁移、应用伸缩等功能,相当于监控运维人员。同样地,它也必须通过apiserver 获得存储在 etcd 里的信息,才能够实现对资源的各种操作

文本

AI 生成的内容可能不正确。

#自动重试功能会一直对无法启动的服务器进行重启

  • etcd(集群数据存储):是一个高可用的分布式 Key-Value 数据库,用来持久化存储系统里的各种资源对象和状态,相当于 Kubernetes 里的配置管理员。注意它只与 apiserver 有直接联系,也就是说任何其他组件想要读写 etcd 里的数据都必须经过 apiserver

#分布式场景下保证数据一致性,使用Raft共识算法

  • ectd角色:

leader:领导者 #整个集群稳定下来后只有一个领导者

#集群所有的修改都要经过leader

follower:除去领导者都是follower

candidate:候选

#当集群中没有领导者时,就会进入候选状态

#当数据库的Entry达到一定的量时就会自动生成一个快照

  • Worker Node数据面三个组件:

  • kubelet:负责管理 Node 相关的绝大部分操作,Node 上只有它能够与 apiserver 通信,实现状态报告、命令下发、启停容器等功能,负责 Pod 生命周期管理,执行任务并将 Pod 状态报告给Master节点,通过容器运行时(拉取镜像、启动、停止容器等)来运行这些容器。

  • kube-proxy:是 Node的网络代理,只负责管理容器的网络通信,简单来说就是为 Pod 转发 TCP/UDP数据包,在主机上维护网络规则并执行连接转发。

  • CR (ContainerRuntime):容器运行时:是容器和镜像的实际使用者,在kubelet 的指挥下创建容器,管理 Pod 的生命周期,是真正干活的。

#通过cr进行创建容器

  1. kubernetes核心对象

#写的yaml文件就是给对象写入的文件

  1. 命令式和声明式

  • 什么是API对象

作为一个集群操作系统,Kubernetes 归纳总结了Google 多年的经验,在理论层面抽象出了很多个概念,用来描述系统的管理运维工作,这些概念就叫做“API对象”。

kubectl api-resources 查看系统支持的API对象

目前的Kubernetes 1.23 版本有50 多种 APl对象,全面地描述了集群的节点、应用、配置、服务、账号等等信息,apiserver 会把它们都存储在数据库 etcd 里,然后kubelet、scheduler、controller-manager 等组件通过 apiserver 来操作它们,就在 APl 对象这个抽象层次实现了对整个集群的管理。

  • 如何描述API对象

运行一个pod,观察API请求

  1. kubernetes API对象的四大属性

API 对象是Kubernetes集群中的管理操作单元。

Kubernetes 集群系统每支持一项新功能,引入一项新技术,一定会新引入对应的API对象,支持该功能的管理操作。

  • API对象的四大属性:

#每一个API对象都有四大属性

  • TypeMeta:

Kubernetes对象的最基本定义,它通过引入GKV(Group、Kind、Version)模型定义了一个对象的类型。

  1. Group:放置组名

Kubernetes定义了非常多的对象,如何将这些对象进行归类是一门学问,将对象依据其功能范围归入不同的分组,比如把支撑最基本功能的对象归入core 组,把与应用部署相关的对象归入apps 组,会使这些对象的可维护性和可理解性更高。

#core核心组,平时使用时省略。apps

  1. Kind:定义一个对象的基本类型

#定义创建资源对象

#kind的写法都是大驼峰,所有的key都是小驼峰

#小驼峰出第一个单词之外,其他单词首字母大写,

  1. Version:

社区每个季度会推出一个Kubernetes版本,随着Kubernetes版本的演进,对象从创建之初到能够完全生产化就绪的版本是不断变化的。与软件版本类似,通常社区提出一个模型定义以后,随着该对象不断成熟,其版本可能会从vlalpha1到vqaplha2,或者到v1beta1,最终变成生产就绪版本v1。

  • MetaData:(源信息,基础信息)

Metadata中有两个最重要的属性:Namespace和Name,分别定义了对象Namespace归属及对象名字,这两个属性唯一定义了某个对象实例

#一个项目使用一个namespace,默认命名空间defult

#这两个属性是必须的

  1. Labels:顾名思义就是给对象打标签,一个对象可以有任意对标签,其存在形式是键值对。

Labels定义了对象的可识别属性,Kubernetes API支持以Label作为过滤条件查询对象。

#标签可以随意去定义

  1. Annotation:(注解):Annotation与Label一样用键值对来定义,但Annotation是作为属性扩展,更多面向系统管理员和开发人员,因此需要像其他属性一样做合理归类。

#Annotations 是key/value 形式附加于对象的注解。

:不同于 Labels用于标志和选择对象,Annotation则是用来记录一些附加信息,用来辅助应用部署、安全策略以及调度策略等

  • Spec:(详细信息,资源的期望状态)

Spec 和 Status 才是对象的核心。

Spec 是用户的期望状态:由创建对象的用户端来定义。

Status 是对象的实际状态:由对应的控制器收集实际状态并更新。

文本, 信件

AI 生成的内容可能不正确。

#与TypeMeta和Metadata等通用属性不同,Spec和Status是每个对象独有的。

  • Status:(实际状态)

#kuberlet定时上报给apiserver的,从而得到实时状态的数据

  1. 如何编写YAML

权威:Kubernetes官方文档:https://kubernetes.io/docs/reference/kubernetes-api/

技巧一:kubectl api-resources

#查看对象的APIVERSION,可结合grep进行过滤

技巧二:kubectl explain 对象名

#使用explain就可以查到使用的对象用法和后面可以使用的属性

kubectl explain pod

kubectl explain pod.metadata

kubectl explain pod.spec

kubectl explain pod.spec.containers

技巧三:kubectl run 生成样板文件

kubectl run ngxXx --image=nginx:1.22.1 --dry-run=client -o yaml

日期2025.08.21学习日志

  1. kubernetes集群部署

  2. 部署相关流程:

  • 环境准备

所谓的多节点集群,要求服务器应该有两台或者更多,为了简化我们只取最小值,所以这个Kubernetes 集群就只有两台主机,一台是 Master 节点,另一台是 Worker 节点

#此次使用两个主机进行实验

基于模拟生产环境的考虑,在 Kubernetes 集群之外还需要有一台起辅助作用的服务器。它的名字叫 Console,意思是控制台,我们要在上面安装命令行工具 kubectl,所有对Kubernetes 集群的管理命令都是从这台主机发出去的。这也比较符合实际情况,因为安全的原因,集群里的主机部署好之后应该尽量少直接登录上去操作。要提醒你的是,Console 这台主机只是逻辑上的概念,不一定要是独立,完全可以复用 Master/Worker 节点作为控制

  • kubeadm工具:官方安装工具

  • kubectl:客户端

#通过客户端连接到集群中进行命令的操作,一般使用在集群外面进行访问

  • 容器创建过程

docker run > docker-daemon > containerd > runc

  • 配置主机名

  1. 执行:hostnamectl set-hostname master-01

  2. 执行:hostnamectl set-hostname worker-01

#所有节点主机名是唯一

  • 关闭防火墙

  1. 执行:systemctl disable --now firewalld

  2. 关闭selinux:执行:sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config

  3. 关闭交换分区:swapoff -a; sed -i '/swap/d' /etc/fstab

  • 配置时间同步器

  1. yum -y install chrony :默认安装,没有安装执行

  2. 执行:vim /etc/chrony.conf修改配置文件,添加以下内容

#可以直接在配置文件里面修改,相关参数

server ntp.aliyun.com iburst

server ntp1.aliyun.com iburst

server ntp2.aliyun.com iburst

  1. systemctl restart chronyd:重载配置文件

  2. systemctl enable chrony:启动服务开机自启

  3. 执行:chronyc tracking:检查状态

  • 修改内核参数(master和worker都需执行)

  1. 执行:cat >>/etc/sysctl.d/kubernetes.conf<<EOF

net.bridge.bridge-nf-call-ip6tables = 1

net.bridge.bridge-nf-call-iptables = 1

net.ipv4.ip_forward = 1

EOF

sysctl --system

# net.ipv4.ip_forward = 1 启用了IPv4的IP转发功能,允许服务器作为网络路由器转发数据包。

# net.bridge.bridge-nf-call-iptables = 1 当使用网络桥接技术时,将数据包传递到iptables进行处理。

  • 配置 hosts 本地解析 (不是必须添加)(master和worker都需要执行)

  1. 执行下面命令:

cat > /etc/hosts <<EOF

127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4

::1 localhost localhost.localdomain localhost6 localhost6.localdomain6

192.168.81.132 master-01

192.168.131.133 worker-01

EOF

#以上命令添加后会减少一些报错

  • 安装容器运行时:containerd(master和woker都执行)

我们就直接使用 docker 公司提供的 yum 仓库安装, containerd 是 Docker 公司捐献给 CNCF 的

  1. 执行:dnf install -y yum-utils

#使用 阿里云仓库

  1. 执行:dnf config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# 安装 containerd

  1. 执行:dnf -y install containerd.io-1.7.25

  • 修改containerd配置文件(master和worker都执行)

  1. cd /etc/containerd

  2. mv config.toml config.toml.orig

  3. containerd config default > /etc/containerd/config.toml

#创建默认配置文件

  1. 执行:sed -i "s#SystemdCgroup\ \=\ false#SystemdCgroup\ \=\ true#g" /etc/containerd/config.toml

#修改 Containerd cgroup 配置

# # grep -i SystemdCgroup /etc/containerd/config.toml

# SystemdCgroup = true # false 改为 true

  1. 执行:sed -i "s#registry.k8s.io#registry.aliyuncs.com/google_containers#g" /etc/containerd/config.toml

#修改 sandbox 沙箱镜像地址(就是 pause 镜像地址

# grep -i sandbox_image /etc/containerd/config.toml

# sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.8"

# 修改镜像仓库 从 registry.k8s.io 修改为 阿里云

  • 启动 containerd 服务

  1. 执行:systemctl enable --now containerd:启动服务

  2. 执行:systemctl status containerd:查看运行状态

  3. 执行:ctr version

#ctr的命令就是containerd的客户端

  • containerd 引入 namespace 概念 default

  • ctr -n default image ls

  • ctr -n k8s.io image import image.tar #导入镜像

#不使用-n命令会去默认的命名空间去找

nerdctr命令containerd官方设计和docker类似的命令

  • nerdctr命令的安装:#使用准备好的安装包

  1. 执行:tar -xf nerdctl-2.0.3-linux-amd64.tar.gz

  2. 执行:mv nerdctl /usr/local/bin

nerdctl -n k8s.io ps:查看k8s中正在运行的容器

  • 安装 kubeadm 和 k8s 组件(master和worker都执行)

#k8s 官方的仓库访问受限,我们使用阿里云的仓库

  1. 执行以下内容:

cat <<EOF | tee /etc/yum.repos.d/kubernetes.repo

[kubernetes]

name=Kubernetes

baseurl=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.32/rpm/

enabled=1

gpgcheck=1

gpgkey=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.32/rpm/repodata/repomd.xml.key

EOF

  1. 执行:dnf install -y kubeadm-1.32.2 kubelet-1.32.2 kubectl-1.32.2

  2. 执行:systemctl enable --now kubelet:启动服务

  3. Master 节点初始化 (只在 master 节点执行)

  4. kubeadm config print init-defaults > kubeadm-config.yaml:生成kubeadm初始化的配置文件

  5. 执行:kubeadm-config.yaml:修改配置文件:修改以下内容

advertiseAddress: 192.168.81.132

#通告:告诉apiserver的入口节点在哪,此处时master的ip。公有云时内网地址

nodeRegistration:

name: master-01

#此处项的name就是注册节点时的名字

imageRepository: registry.aliyuncs.com/google_containers

#此处的镜像仓库改为国内阿里云的仓库

kubernetesVersion: 1.32.2

#此处版本改为精确的版本,不修改就去官方找最新的最新的

networking:

podSubnet: 10.244.0.0/16

#在网络中添加一个pod网络cidr地址

  • 下载集群初始化所需镜像

  1. 执行:kubeadm config --config=kubeadm-config.yaml images list

#查看 Kubernetes 初始化需要用到的镜像

  1. 执行:kubeadm config --config=kubeadm-config.yaml images pull:下载初始化所需要的镜像 #自动去阿里云拉取镜像

  2. 执行:nerdctl -n k8s.io image list:查看下载后的镜像

#镜像默认下载到k8s.io里面,不使用-n无法查看

  • 集群初始化

  1. kubeadm init --config=kubeadm-config.yaml:执行命令进行初始化

#初始化成功

注:集群初始化可能会出现失败,可提前执行tail -f /var/log/messages打开日志进行

  • 配置kubectl的认证文件

  1. 执行:mkdir -p $HOME/.kube

  2. 执行:sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

  3. 执行:sudo chown $(id -u):$(id -g) $HOME/.kube/config

#会生成文件 $HOME/.kube/config ,kubectl 需要使用此文件连接集群。

  • 验证集群

  1. 执行:kubectl get node:进行命令验证

#可以看到 master-01 节点已经成功加入集群

#worker节点进行执行kubectl命令也需要上述文件

报错信息:

#需要一个健康的kubelet

  • worker节点加入集群(worker节点执行)

#在 worker 节点 只需要执行在集群初始化成功输出的 kubeadm join 命令即可

  1. 执行:kubeadm join 192.168.81.132:6443 --token 50cp39.t13jclz0hqvs35tf --discovery-token-ca-cert-hash sha256:086e4bc51a41222215273c9edc9ccad1c1dba994558e8909afba1142ffb97539#join后面是master节点ip,token是一个令牌,有问题也会卡四分钟

执行成功后输出:

  1. master节点执行:kubectl get nodes

表格

AI 生成的内容可能不正确。

#可以发现worker节点也成功加入集群

注:上面节点的状态是 NotReady , 没有就绪,在这种状态下集群 还无法正常工作,我们需要在集群中安装一个网络插件,才可以让节点的状态变成 Ready

  1. 安装网络插件(安装在master),worker节点也要执行

#我们使用 Calico 网络插件,calico用到的镜像在 hub.docker.com 上,国内需要配置加速器,或者导入离线镜像,此处使用离线安装

  1. 执行:tar -xf calico-3.29.2.image.tgz

  2. 执行:ctr -n k8s.io image import calico-3.29.2.image

  3. 执行:kubectl create -f calico.yaml:安装安装 calico 插件

  4. 执行:kubectl -n kube-system get pods -o wide:验证calico是否安装成功

  1. kubectl get nodes:再次检查节点状态显示为Ready

  1. 验证集群安装结果

  2. 执行:kubectl get cs

文本

AI 生成的内容可能不正确。

#控制面组件状态显示 Healthy

  1. 执行:kubectl get pods -A

表格

AI 生成的内容可能不正确。

#所有 Pod 状态为 Running

  1. 常见故障处理

  • 镜像拉取失败

如果 Pod 状态显示 ImagePullBackOff,表示容器所有的节点 镜像拉取失败,需要到对应节点上手动拉取镜像或者导入离线镜像即可

  • Master 节点初始化失败

在 master 节点初始化过程中,常见的故障是 卡在如下界面,此处是正在等待 kube-apiserver 启动成功,如果apiserver启动失败,这里会一直等待,直到4分钟超时会有报错。 排错的时候需要查看 messages 日志定位具体原因,在初始化的过程中建议打开一个shell 终端运行 tail -f /var/log/messages 命令,注意观察报错信息

  • Worker 节点加入集群失败

Worker 节点在加入集群过程中需要成功运行 kubelet 服务,再连接 kube-apiserver,任何一步失败都无法加入集群,因此在执行 kubeadm join 时也需要打开一个shell 终端运行 tail -f /var/log/messages 命令,观察日志中的报错信息

文本

AI 生成的内容可能不正确。

  • 加入报错:

图片包含 文本

AI 生成的内容可能不正确。

解决:

  • 重置集群

如果找到了报错原因,需要重新初始化集群或是worker节点重新加入集群, 都需要先执行 kubeadm reset(清理当前节点上的 Kubernetes 服务,进行重新初始化,worker节点执行) 命令,再执行 kubeadm init(创建一个新集群) 或是 kubeadm join

#它会停止 kubelet、删除容器、清除网络配置以及删除所有通过 kubeadm init 或 join 创建的数据

注:加入新节点时最好改下主机名

  • 重新生成 join 命令

#初始化时生成的 kubeadm join 命令,有效期是 24 小时,超时后命令中的token 就失效了,如果 24小时后有节点加入集群, 我们需要执行以下命令,重新生成可用的 token

[root@master-01 ~]# kubeadm token create --print-join-command

注:在使用kubeadm join加入集群时,会自动生成配置文件(kubeconfig文件),如使用克隆方式复制的节点,需先执行kubeadm reset -f

  • dnf localinstall ~/rpms/*.rpm:批量安装本地的rpm包

#使用离线下载时使用

  1. 参考文档

Containerd 官网: https://containerd.io/

Containerd 官方文档: https://github.com/containerd/containerd/blob/main/docs/getting-started.md

Kubeadm 官方文档: https://kubernetes.io/zh-cn/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/

Calico 官方文档: https://docs.tigera.io/calico/latest/getting-started/kubernetes/self-managed-onprem/onpremises#install-calico

图片包含 图形用户界面

AI 生成的内容可能不正确。

https://mp.weixin.qq.com/s/d44ngzDbW_ublUsw-KrCJQ

https://mp.weixin.qq.com/s/DYHSP8s-3PCUkVF-ierZtg

https://mp.weixin.qq.com/s/OIC1M0FYd9IJJEKt2Yi6sQ

  1. Pod-Kubernetes里最核心的概念

  2. 介绍 Pod

为了解决多应用联合运行的问题,同时还要不破坏容器的隔离,就需要在容器外面再建立一个收纳舱,让多个容器既保持相对独立,又能够小范围共享网络、存储等资源,而且永远是“绑在一起”的状态

#需要多个进程一起去工作

最小单位:pod:同时运行多个容器,多个进程一起工作,实现共享网络,共享存储

#pod相当于一个虚拟机,但pod是一个逻辑型对象

  • Pod 是 Kubernetes 的核心对象

#因为 Pod 是对容器的“打包”,里面的容器是一个整体,总是能够一起调度、一起运行,绝不会出现分离的情况,而且 Pod 属于 Kubernetes,可以在不触碰下层容器的情况下任意定制修改。所以有了 Pod 这个抽象概念,Kubernetes 在集群级别上管理应用就会“得心应手”了

Kubernetes 让 Pod 去编排处理容器,然后把 Pod 作为应用调度部署的最小单位,Pod 也因此成为了 Kubernetes 世界里的“原子”,基于Pod 就可以构建出更多更复杂的业务形态了

#只有集群才认识pod

图示

AI 生成的内容可能不正确。

  1. 如何使用 YAML 描述 Pod

用命令 kubectl explain 来查看资源对象的详细说明,所以接下来我们一起看看写 YAML 时 Pod 里的一些常用字段。

例:kubectl explain Pod.spec

因为 Pod 也是 API 对象,所以它也必然具有 apiVersion、kind、metadata、spec 这四个基本组成部分。

apiVersion”和“kind”这两个字段很简单,对于 Pod 来说分别是固定的值 v1 和 Pod,而一般来说,“metadata”里应该有 name 和 labels 这两个字段

  • 下面这段 YAML 代码就描述了一个简单的 Pod,名字是“busy-pod”,再附加上一些标签:

文本

AI 生成的内容可能不正确。

# metadata”一般写上 name 和 labels 就足够了,而“spec”字段由于需要管理、维护 Pod 这个Kubernetes 的基本调度单元,里面有非常多的关键信息

  • “containers”是一个数组,里面的每一个元素又是一个 container 对象,也就是容器

注:和 Pod 一样,container 对象也必须要有一个 name 表示名字,然后当然还要有一个 image 字段来说明它使用的镜像,这两个字段是必须要有的,否则 Kubernetes 会报告数据验证错误

  • container对象常用值(属性):(必须属性)

#里面有数组的后面可以继续跟键和值

ports:列出容器对外暴露的端口,和 Docker 的 -p 参数有点像(数组)

  1. containerPort:80 #容器中应用的监听端口

  2. protocol: TCP #应用的协议

  3. name: http #给80端口起个名字,通过名字可以找到端口

  • imagePullPolicy:指定镜像的拉取策略,可以是Always/Never/IfNotPresent,一般默认是 IfNotPresent,也就是说只有本地不存在才会远程拉取镜像,可以减少网络消耗

ENUM: 枚举

Always: #kubelet 拉取镜像 ,总是去 仓库 拉取最新的镜像

IfNotPresent: #如果本地没有镜像 ,再从仓库拉取最新的镜像

Never: #只用本地镜像 ,不主动 拉取

  • env:定义 Pod 的环境变量,和 Dockerfile 里的 ENV 指令类似(数组)

#name必须属性,环境变量的名称

#数组里面定义对象

  • command:定义容器启动时要执行的命令,相当于 Dockerfile 里的ENTRYPOINT 指令 #里面写数组字符串,设置后没有手到agrs的参数,容器启动会立即退出

#默认命令是/bin/bash

  • args:它是 command 运行时的参数,相当于 Dockerfile 里的 CMD 指令,这两个命令和Docker 的含义不同,要特别注意 #里面写数组字符串

注:一个属性里面有required就是代表这个属性是必须的

key value 类型 []Container #早期版本[]object 数组对象

containers <[]Container> -required-

  • 编写“busy-pod”的 spec 部分,添加 env、command、args 等字段:

文本

AI 生成的内容可能不正确。

形状

AI 生成的内容可能不正确。

#[]类型代表一个容器数组,containers后面的一个值代表一个容器

#每个数组代表一个容器,每个容器名称都是唯一的

#有容器还需要有一个镜像属性images

  • 完整yaml描述

图片包含 表格

AI 生成的内容可能不正确。

  1. 如何使用 kubectl 操作 Pod

  • 创建pod:

kubectl apply -f busy-pod.yaml(yaml文件)

#apply既支持创建又支持更新,当文件发生变化时可以使用此命令更新。不是所有属性都支持,create只支持创建

  • 查看pod列表和运行状态:

kuberctl get pods

#此出名名称就是子啊metadata里面定义的名字,pod名不能重复,在命令空间是唯一的

#此处pod没有启动

kuberctl get pods -o wide:#添加选项可以显示更多参数

#正常情况下kubectl命令在外部执行,pod是跑在worker上面

#IP:pod的ip、NODE:pod运行在哪个节点

  • 显示pod标准输出信息:(输出日志)

[root@master-01 04-pod]# kubectl logs busy-pod

NAME=xinxianghf, ADDRESS=beijing

  • restartPolicy :重启策略(pod里面的值)

#启用相关重启策略后删除pod在重启就会看到状态完成

ENUM:

Always #一直重启

OnFailure #容器启动时命令返回的状态码 $? 非 0时 才会重启

Never

  • 删除pod

kubectl delete -f busy-pod.yaml(yaml文件)

kubectl delete pod busy-pod

#我们在 YAML 里定义了“name”字段,所以也可以在删除的时候直接指定名字来删除

  • 查看描述信息(检查详细状态):

kubectl describe pods nginx-pod(pod名称)

图形用户界面

AI 生成的内容可能不正确。

#事件信息,生产环境中会对一些事件信息进行监控

  • 实时显示对象状态

kubectl get pods -w

kubectl 也提供与 docker 类似的 cp 和 exec 命令kubectl cp 可以把本地文件拷贝进 Pod,kubectl exec 是进入 Pod 内部执行 Shell 命令,用法也差不多

例:echo "demo" >> a.txt

kubectl cp a.txt nginx-pod:/tmp

#比如我有一个“a.txt”文件,那么就可以使用 kubectl cp 拷贝进 Pod 的“/tmp”目录里

日期2025.08.22学习日志

  1. Pod-Kubernetes里最核心的概念

  2. 如何进入pod里面

:kubectl exec 的命令格式与 Docker 有一点小差异,需要在 Pod 后面加上 --,把kubectl 的命令与 Shell 命令分隔开,使用时需要注意一下

kubectl exec -it nginx-pod(pod名字) -- sh #进入pod里面

  • 查看pod日志

kubectl logs nginx-pod

  • 查看具体时间的日志

kubectl logs -f nginx-pod --since=1m

  1. label标签:用于快速查询对象

对于微服务架构,部署的微服务数量可以轻松超过20个甚至更多。这些组件可能是副本(部署同一组件的多个副本)和多个不同的发布版本(stable、beta、canary等)同时运行。这样一来可能会导致我们在系统中拥有数百个pod,如果没有可以有效组织这些组件的机制,将会导致产生巨大的混乱

release、environment(环境)、tier(前端)、language(语言):使用率较高的标签

  • 介绍标签

标签是一种简单却功能强大的Kubernetes特性,不仅可以组织pod,也可以组织所有其他的Kubernetes资源。详细来讲,标签是可以附加到资源的任意键值对,用以选择具有该确切标签的资源(这是通过标签选择器完成的)。只要标签的key在资源内是唯一的,一个资源便可以拥有多个标签。通常在我们创建资源时就会将标签附加到资源上,但之后我们也可以再添加其他标签,或者修改现有标签的值,而无须重新创建资源

通过给pod添加标签,可以得到一个更组织化的系统,以便我们理解。此时每个pod都标有两个标签

  • app:它指定pod属于哪个应用、组件或微服务。

  • env:它显示在pod中运行的环境是 dev、production 还是 qa

  • 查看pod的标签

kubectl get pod --show-labels

#使用查看命令时加--show-labels

  • 如何打标签

  1. YAML #通过yaml文件放肆添加标签,可以直接修改

  2. kubectl label pod nginx-pod tier=front

#通过命令行去打标签

  • 修改标签

  1. 修改yaml文件

  2. kubectl label pod nginx-pod tier=backend --overwrite

#通过命令方式去覆盖原有的标签 --overwrite去覆盖

  • 删除标签

kubectl label pod nginx-pod tier-

#在标签的key后面加-就可以删除

  1. 标签选择运算符(利用标签进行对象查询)

目前支持两种类型的选择算符:基于等值的基于集合的

例:启动多个pod使用以下两种查询方式验证

  • 基于等值:

基于等值基于不等值的需求允许按标签键和值进行过滤。 匹配对象必须满足所有指定的标签约束,尽管它们也可能具有其他标签。 可接受的运算符有 =、== 和 != 三种。 前两个表示相等(并且是同义词),而后者表示不相等

例如:

Kubectl get pods -l env=dev --show-lables

#通过等值进行条件过滤,就可以得到想要的结果

#查找存在owner的标签

environment = production

tier != frontend

  • 基于集合:

基于集合的标签需求允许你通过一组值来过滤键。 支持三种操作符:in、notin 和 exists(只可以用在键标识符上)

例如:

查看 env 在一个范围内 dev fat:

kubectl get pods -l 'env in (dev,fat)' --show-labels

#一个条件需要放到单引号里面,查找在一个范围内

kubectl get pods -l 'env notin (dev,fat)' --show-labels

#对一个示例进行取反

environment in (production, qa)

tier notin (frontend, backend)

partition

!partition

  1. 使用命名空间组织 Pod ( namespace )

  • 介绍:

Kubernetes 的命名空间并不是一个实体对象,只是一个逻辑上的概念。它可以把集群切分成一个个彼此独立的区域,然后我们把对象放到这些区域里,就实现了类似容器技术里 namespace 的隔离效果,应用只能在自己的命名空间里分配资源和运行,不会干扰到其他命名空间里的应用

#此处命名空间是k8s的一个匿名对象

  • 名空间可以划分为两种类型:系统级命名空间和用户自定义命名空间

  • 系统级的命名空间是 K8s 集群默认创建的命名空间,主要用来隔离系统级的对象和业务对象,系统级的命名空间下面四种

NAME

default:默认的

kube-system:控制面组件 重要系统类组件

kube-node-lease:预留的 不使用(和集群扩展相关的命名空间)

kube-public:预留的不使用(开放的命名空间,所有的用户都可以读取)

#自己创建的namespace一般使用项目名称进行创建

#一个namespace可以理解为一个项目,把大集群分为小集群去管理,pod放到命名空间里面。可配置多个环境(开发、测试),把环境和项目名进行划分

  • 查看命名空间

kubectl get ns

  • 创建命名空间

kubectl create namespace dev-ns(名称)

#使用命令创建阿ns也会保存到etcd里面,也可以直接在yaml里面写

  • 将数据库的ns的yaml文件取出

kubectl get ns dev-ns -o yaml

格式:命令 对象类型 命名空间 -o yaml

  • 获取命名空间详细信息

kubectl describe ns 空间名称

  • 将 Pod 运行在指定的命名空间中(对象放入命名空间)

[root@master-01 04-pod]# kubectl -n dev-ns apply -f nginx-pod.yaml

[root@master-01 04-pod]# kubectl -n dev-ns get pods

文本

AI 生成的内容可能不正确。

#两种方式放入

  • Pod 停止和移除

使用标签选择器删除:

kubectl get pods --show-labels

kubectl delete pods -l env=dev

删除命名空间所有 Pod:

kubectl delete namespace dev-ns

  1. 特殊容器类型

  • Pause容器

介绍:核心职责

在Kubernetes中,pause 容器作为你的 pod 中所有容器的“父容器”。pause 容器有两个核心职责。首先,它是 pod 中Linux 名称空间共享网络的基础其次,启用了PID(进程ID)命名空间共享后,它为每个pod充当 PID 1,并接收僵尸进程

#Pause 容器 启动后 创建 network namespace , Pod 中剩下的容器 会加入到这个 network namespace中 ,Pod中所有的容器在一个 network namespace

例:验证实验:pause容器用途

图形用户界面, 文本, 应用程序, 电子邮件

AI 生成的内容可能不正确。

#网络共享和pid也共享,

图片包含 日历

AI 生成的内容可能不正确。

#以上进程都可以互相看到

#pod第一个启动,其他启动后自动加入到pod命名空间中,实现共享网络

  1. Init Containers:初始化容器

  • 什么是 init Containers

Pod 能够具有多个容器,应用运行在容器里面,但是它也可能有一个或多个先于应用容器启动的 Init 容器

Init 容器与普通的容器非常像,除了如下两点:

  1. Init 容器总是运行到成功完成为止。

  2. 每个 Init 容器都必须在下一个 Init 容器启动之前成功完成

如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止。然而,如果 Pod 对应的 restartPolicy 为 Never,它不会重新启

形状

AI 生成的内容可能不正确。

#里面的Init Containers 在yaml里面定义初始化,后面跟数组对象

  • Init 容器能做什么?

因为 Init 容器具有与应用程序容器分离的单独镜像,所以它们的启动相关代码具有如下优势:

  1. 等待其他模块Ready这个可以用来解决服务之间的依赖问题,比如我们有一个 Web 服务,该服务又依赖于另外一个数据库服务,但是在我们启动这个 Web 服务的时候我们并不能保证依赖的这个数据库服务就已经启动起来了,所以可能会出现一段时间内 Web 服务连接数据库异常。要解决这个问题的话我们就可以在 Web 服务的 Pod 中使用一个InitContainer,在这个初始化容器中去检查数据库是否已经准备好了,准备好了过后初始化容器就结束退出,然后我们的主容器 Web 服务被启动起来,这个时候去连接数据库就不会有问题了。

  2. 做初始化配置:比如集群里检测所有已经存在的成员节点,为主容器准备好集群的配置信息,这样主容器起来后就能用这个配置信息加入集群。

  3. 其它场景:如将Pod注册到一个中央数据库、配置中心等

例:

图片包含 文本

AI 生成的内容可能不正确。

#在启用calico时,状态中init:0/3就是,代表定义了三个初始化,逐步执行初始化

文本

AI 生成的内容可能不正确。

:在 Pod 启动过程中,Init 容器会按顺序在网络和数据卷初始化之后启动。每个容器必须在下一个容器启动之前成功退出。如果由于运行时或失败退出,将导致容器启动失败,它会根据 Pod 的 restartPolicy 指定的策略进行重试。然而,如果 Pod 的 restartPolicy 设置为 Always,Init 容器失败时会使用 RestartPolicy 策略。

在所有的 Init 容器没有成功之前,Pod 将不会变成 Ready 状态。正在初始化中的 Pod 处于 Pending 状态,但应该会将 Initializing 状态设置为 true。

如果 Pod 重启,所有 Init 容器必须重新执行。

对 Init 容器 spec 的修改被限制在容器 image 字段,修改其他字段都不会生效。更改 Init 容器的 image 字段,等价于重启该 Pod。

因为 Init 容器可能会被重启、重试或者重新执行,所以 Init 容器的代码应该是 幂等

Init Containers 初始化容器 启动时间 比 containers 早:

kubectl set env daemonset/calico-node -n kube-system IP_AUTODETECTION_METHOD=interface=ens192

  • 强制删除pod:

kubectl delete pods init-pod3 --force --grace-period 0

  1. Pod生命周期

pod阶段:

Pod 的 status 字段是一个 PodStatus 对象,其中包含一个 phase 字段

Pod 的阶段(Phase)是 Pod 在其生命周期中所处位置的简单概述:

Pod 遵循预定义的生命周期,起始于 Pending 阶段, 如果至少其中有一个主要容器正常启动,则进入 Running,之后取决于 Pod 中是否有容器以失败状态结束而进入 Succeeded 或者 Failed 阶段。

在 Pod 运行期间,kubelet 能够重启容器以处理一些失效场景。 在 Pod 内部,Kubernetes 跟踪不同容器的状态并确定使 Pod 重新变得健康所需要采取的动作

Pod 在其生命周期中只会被调度一次。 一旦 Pod 被调度(分派)到某个节点,Pod 会一直在该节点运行,直到Pod 停止或者被终止

下面几种状态:

  1. 挂起(Pending):Pod 信息已经提交给了集群,但是还没有被调度器调度到合适的节点或者 Pod 里的镜像正在下载

  2. 运行中(Running):该 Pod 已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态

  3. 成功(Succeeded):Pod 中的所有容器都被成功终止,并且不会再重启

  4. 失败(Failed):Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止

  5. 未知(Unknown):因为某些原因无法取得 Pod 的状态,通常是因为与 Pod 所在主机通信失败导致的

  • 容器状态

一旦调度器将 Pod 分派给某个节点,kubelet 就通过容器运行时开始为 Pod 创建容器。容器的状态有三种:Waiting(等待)、Running(运行中)和 Terminated(已终止)

Waiting (等待)

如果容器并不处在 Running 或 Terminated 状态之一,它就处在 Waiting 状态。 处于 Waiting 状态的容器仍在运行它完成启动所需要的操作:例如, 从某个容器镜像仓库拉取容器镜像,或者向容器应用 Secret 数据等等。 当你使用 kubectl 来查询包含 Waiting 状态的容器的 Pod 时,你也会看到一个 Reason 字段,其中给出了容器处于等待状态的原因

Running(运行中)

Running 状态表明容器正在执行状态并且没有问题发生。 如果配置了 postStart 回调,那么该回调已经执行且已完成。 如果你使用 kubectl 来查询包含 Running 状态的容器的 Pod 时, 你也会看到关于容器进入 Running 状态的信息

Terminated(已终止)

处于 Terminated 状态的容器已经开始执行并且或者正常结束或者因为某些原因失败。 如果你使用 kubectl 来查询包含 Terminated 状态的容器的 Pod 时, 你会看到容器进入此状态的原因、退出代码以及容器执行期间的起止时间

#如果容器配置了 preStop 回调,则该回调会在容器进入 Terminated 状态之前执行

  1. 容器生命周期回调(Hook) 钩子函数

#容器的生命周期中加入了两个hook

有两个回调暴露给容器:

  • PostStart #容器启动前

这个回调在容器被创建之后立即被执行。 但是,不能保证回调会在容器入口点(ENTRYPOINT)之前执行

  • PreStop #优雅退出

在容器被终止之前,此回调会被调用。在容器终止之前调用,常用于在容器结束前优雅的释放资源

:postStart 指的是,在容器启动后,立刻执行一个指定的操作。需要明确的是,postStart 定义的操作,虽然是在 Docker 容器 ENTRYPOINT 执行之后,但它并不严格保证顺序。也就是说,在 postStart 启动时,ENTRYPOINT 有可能还没有结束。当然,如果 postStart 执行超时或者错误,Kubernetes 会在该 Pod 的 Events 中报出该容器启动失败的错误信息,导致 Pod 也处于失败的状态。

:preStop 发生的时机,则是容器被杀死之前(比如,收到了 SIGKILL 信号)。而需要明确的是,preStop 操作的执行,是同步的。所以,它会阻塞当前的容器杀死流程,直到这个 Hook 定义操作完成之后,才允许容器被杀死,这跟 postStart 不一样

#执行命令查看钩子函数有没有被触发

#pod里面可以放置多个容器

#pod启动过程中先启动infra容器(pod容器),再启动初始化容器,再去启动主容器。主容器启动时放置一个钩子函数,退出时放置一个钩子函数。中间部分就是容器正在runing

  1. 附录

  • Kubectl 命令补全

dnf -y install bash-completion

echo "source <(kubectl completion bash)" >> ~/.bashrc

source ~/.bashrc

bash

  • restartPolicy

Pod通过restartPolicy字段指定重启策略,重启策略类型为:Always、OnFailure 和 Never,默认为 Always

restartPolicy 仅指通过同一节点上的 kubelet 重新启动容器

  • Nerdctl run 参数

--net=container:<container_name>:容器与另一个指定容器共享网络命名空间。这意味着两个容器共享相同的网络栈,可以直接通信。使用此模式时,两个容器可以看到彼此的网络接口和端口。

--ipc=container:<container_name>:容器与另一个指定容器共享IPC命名空间。这使得两个容器可以直接进行IPC通信,共享相同的IPC资源。例如,可以使用这个选项在容器之间共享内存段。

--pid=container:<container_name>:容器与另一个指定容器共享PID命名空间。这使得两个容器可以共享相同的进程命名空间,进程在两个容器之间是可见的。例如,可以使用此选项在一个容器中监视和管理另一个容器的进程。

文本

AI 生成的内容可能不正确。

kubectl set env daemonset/calico-node -n kube-system IP_AUTODETECTION_METHOD=interface=ens192

  1. job-运行离线业务

离线任务job 云原生操作系统

k8s linux

一次性 离线任务job: at

周期性离线任务:cronjob: cronta

在线任务 7 * 24 一直运行

  1. 使用yaml描述job

  • Job 的 YAML“文件头”部分还是那几个必备字段:

  1. apiVersion 不是 v1,而是 batch/v1。

  2. kind 是 Job,这个和对象的名字是一致的。

  3. metadata 里仍然要有 name 标记名字,也可以用 labels 添加任意的标签。

  • job对象模板生成:

例:用 busybox 创建一个“echo-job”

kubectl create job echo-job --image=busybox:latest --dry-run=client -o yaml

格式:命令 job名称 job使用的镜像 --dry-run=client -o yaml:只创建不运行

# 生成 job YAML模板

#第一层的缩进属于job

# Job 的描述与 Pod 很像,但又有些不一样,主要的区别就在“spec”字段里,多了一个 template 字段,然后又是一个“spec”

:单一职责每个对象只关注自己的职责Pod管理容器,job 管理一次性任务

  • 创建job:

kubectl apply -f job.yaml

#用生成的jod的yaml文件创建

:Kubernetes 就会从 YAML 的模板定义中提取 Pod,在 Job 的控制下运行 Pod,你可以用 kubectl get job、kubectl get pod 来分别查看 Job 和 Pod 的状态:

#显示为 Completed 表示任务完成,而 Job 里也会列出运行成功的作业数量,这里只有一个作业,所以就是 1/1

  • job离线作业控制参数:spec的详细信息

  1. activeDeadlineSeconds,设置 job 运行的超时时间。

  2. backoffLimit,设置 Pod 的失败重试次数。

  3. completions,Job 完成需要运行多少个 Pod,默认是 1 个。

  4. parallelism,它与 completions 相关,表示允许并发运行的 Pod 数量,避免过多占用资源。

例:

:下面我再创建一个 Job 对象,名字叫“sleep-job”,它随机睡眠一段时间再退出,模拟运行时间较长的作业。Job 的参数设置成 15 秒超时,最多重试 2 次,总共需要运行完 4 个 Pod,但同一时刻最多并发 2 个 Pod:

#使用 kubectl apply 创建 Job 之后,我们可以用 kubectl get pod -w 来实时观察 Pod 的状态,看到 Pod 不断被排队、创建、运行的过程:

kubectl apply -f sleep-job.yaml

kubectl get pod -w

文本, 聊天或短信

AI 生成的内容可能不正确。

等到 4 个 Pod 都运行完毕,我们再用 kubectl get 来看看 Job 和 Pod 的状态:

文本

AI 生成的内容可能不正确。

#就会看到 Job 的完成数量如同我们预期的是 4,而 4 个 Pod 也都是完成状态

  1. 使用 YAML 描述 CronJob

  • cronjob 实现cron > job > pod > container

  • 使用命令 kubectl create 来创建 CronJob 的样板

kubectl create cronjob echo-cj --image=busybox:latest --schedule="*/2 * * * *" --dry-run=client -o yaml

#因为 CronJob 的名字有点长,所以 Kubernetes 提供了简写 cj这个简写也可以使用命令 kubectl api-resources 看到;第二,CronJob 需要定时运行,所以我们在命令行里还需要指定参数 --schedule

#有参数模板可以直接使用

然后我们编辑这个 YAML 样板,生成 CronJob 对象:

文本

AI 生成的内容可能不正确。

:我们还是重点关注它的 spec 字段,你会发现它居然连续有三个 spec 嵌套层次:

  1. 第一个 spec 是 CronJob 自己的对象规格声明

  2. 第二个 spec 从属于“jobTemplate”,它定义了一个 Job 对象。

  3. 第三个 spec 从属于“template”,它定义了 Job 里运行的 Pod。

#看归哪个控制器就看,controlled by

CronJob 其实是又组合了 Job 而生成的新对象,通过以下图像进行理解:

:除了定义 Job 对象的“jobTemplate”字段之外,CronJob 还有一个新字段就是“schedule”,用来定义任务周期运行的规则。它使用的是标准的 Cron 语法,指定分钟、小时、日、月、周,和 Linux 上的 crontab 是一样的。像在这里我就指定每分钟运行一次

除了名字不同,CronJob 和 Job 的用法几乎是一样的,使用 kubectl apply 创建 CronJob,使用 kubectl get cj、kubectl get pod 来查看状态:

文本

AI 生成的内容可能不正确。

  1. 总结:

通过这种嵌套方式,Kubernetes 里的这些 API 对象就形成了一个“控制链”:CronJob 使用定时规则控制 Job,Job 使用并发数量控制 Pod,Pod 再定义参数控制容器,容器再隔离控制进程,进程最终实现业务功能,链条里的每个环节都各司其职,在 Kubernetes 的统一指挥下完成任务

  1. Pod 是 Kubernetes 的最小调度单元,但为了保持它的独立性,不应该向它添加多余的功能。

  2. Kubernetes 为离线业务提供了 Job 和 CronJob 两种 API 对象,分别处理“临时任务”和“定时任务”。

  3. Job 的关键字段是 spec.template,里面定义了用来运行业务的 Pod 模板,其他的重要字段有 completions、parallelism 等

  4. CronJob 的关键字段是 spec.jobTemplate 和 spec.schedule,分别定义了 Job 模板和定时运行的规则

  5. ConfigMap 和 Secret - 应用配置文件

#给pod提供配置文件

  • ConfigMap:明文配置,也就是不保密,可以任意查询修改,比如服务端口、运行参数、文件路径等等

  • Secret:机密配置,由于涉及敏感信息需要保密,不能随便查看,比如密码、密钥、证书等等

  1. 什么是 ConfigMap

:先来看 ConfigMap,我们仍然可以用命令 kubectl create 来创建一个它的 YAML 样板。注意,它有简写名字“cm”,所以命令行里没必要写出它的全称:

kubectl create cm info --dry-run=client -o yaml

#命令中添加--from-literal=key=value,就可以配置中写键和值,在yaml配置文件中直接写值就可以

  • 创建出模板:

图片包含 图形用户界面

AI 生成的内容可能不正确。

ConfigMap 要存储数据,我们就需要用另一个含义更明确的字段“data”

#要生成带有“data”字段的 YAML 样板,你需要在 kubectl create 后面多加一个参数 --from-literal ,表示从字面值生成一些数据:

kubectl create cm info --from-literal=k=v --dry-run=client -o yaml

注意,因为在 ConfigMap 里的数据都是 Key-Value 结构,所以 --from-literal 参数需要使用 k=v 的形式

apiVersion: v1

kind: ConfigMap

metadata:

name: info

data: #data属性放配置文件

key: value

图片包含 日程表

AI 生成的内容可能不正确。

  • 通过kubectl apply 把这个 YAML 交给 Kubernetes,创建 ConfigMap 对象:

kubectl apply -f cm.yaml

  • 查看configmap状态:

文本

AI 生成的内容可能不正确。

图形用户界面, 文本

AI 生成的内容可能不正确。

#可以看到,现在 ConfigMap 的 Key-Value 信息就已经存入了 etcd 数据库,后续就可以被其他 API 对象使用

  • 创建configmap

使用字面值创建:

kubectl create configmap cm-conf --from-literal=debug=on --from-literal=count=10

从目录创建:

kubectl create configmap nginx-config --from-file=nginx-conf/文件

#多行文本,保存到configmap中方式

查看configmap:

kubectl get cm nginx-config #看不见内容,只能看有几个key

kubectl describe cm nginx-config

从文件创建:

kubectl create configmap nginx-config-2 --from-file=nginx-conf/default.conf

图表, 散点图

AI 生成的内容可能不正确。

kubectl get cm info -o yaml:可以把configmap的yaml在数据库中拿出来

#以数据库中的yaml为准

  • 修改configmap

kubectl apply -f

kubectl edit cm info:修改数据库中的yaml

#使用此命令修改后后会自动去apply更新

#在没有yaml文件的情况下使用

  • 删除configmap

kubectl delete -f

kubectl delete cm info

日期2025.08.25学习日志

  1. 什么是secret

#保存密钥和私钥,和证书等配置配置文件时使用secret

:了解了 ConfigMap 对象,我们再来看 Secret 对象就会容易很多,它和 ConfigMap 的结构和用法很类似,不过在 Kubernetes 里 Secret 对象又细分出很多类,比如 :

Secret 有四种类型:

  • Service Account Token:用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中;令牌登录 Kubernetes 集群,做验证使用

#只能通过yaml创建

用途:身份识别的凭证信息

  • Opaque [oʊˈpeɪk]:base64 编码格式的 Secret,用来存储密码、密钥等; key: value #类似于configmap,此处的value是加密的(使用编码)

用途:一般的机密信息

  • kubernetes.io/dockerconfigjson:用来存储私有 docker registry 的认证信息。保存私有仓库的用户名和密码 #工作中一般使用私有

用途:访问私有镜像仓库的认证信息

  • TLS(传输层安全):用于存储 TLS 证书和私钥,以支持加密通信。它可以用于需要TLS证书的场景。 Https

用途:HTTPS 通信的证书和私钥

#使用前要考虑保存成什么类型

  • 命令对应创建类型

docker-registry:kubernetes.io/dockerconfigjson

generic:Opaque Create a secret from a local file, directory, or literal value

tls:TLS Create a TLS secret

  • 示例:

创建Opaque 类型的,创建 YAML 样板的命令是 kubectl create secret generic ,同样,也要使用参数--from-literal 给出 Key-Value 值:

  1. kubectl create secret generic user --from-literal=username=root --dry-run=client -o yaml

#使用此命令可以直接创建一个模板

  1. 创建secret对象如下:

图片包含 Word

AI 生成的内容可能不正确。

#Secret 对象第一眼的感觉和 ConfigMap 非常相似,只是“kind”字段由“ConfigMap”变成了“Secret”,后面同样也是“data”字段,里面也是 Key-Value 的数据

#这串“乱码”就是 Secret 与 ConfigMap 的不同之处,不让用户直接看到原始数据,起到一定的保密作用。不过它的手法非常简单,只是做了 Base64 编码,根本算不上真正的加密,我们可以直接使用 Linux 命令"base64" 来解密 :

  1. 解码验证

图形用户界面, 应用程序

AI 生成的内容可能不正确。

#自定义去写yaml文件时,编码时需要加-n去除换行符

  1. 使用 kubectl apply、kubectl get、kubectl describe 创建和查看对象

kubectl get secrets user(名称) -o yaml:可查看详细yaml文件内容

图片包含 图形用户界面

AI 生成的内容可能不正确。

文本

AI 生成的内容可能不正确。

#这样一个存储敏感信息的 Secret 对象也就创建好了,而且因为它是保密的,使用 kubectl describe 不能直接看到内容只能看到数据的大小,你可以和 ConfigMap 对比一下

  • 创建Secret

docker registry 认证的 secret:

kubectl create secret docker-registry(docker仓库) my-registry-secret(名称) --docker-server=reg.xxhf.cc --docker-username=admin --docker-password=password --docker-email=chijj@xxhf.cn

语法格式:kubectl create secret docker-registry NAME --docker-username=user #仓库用户名

--docker-password=password #仓库密码

--docker-email=email #添加email

--docker-server=string #仓库的url

[--from-file=[key=]source] #可选

[--dry-run=server|client|none] [options] #可选

#secrets名称可写多个,拉取镜像验证就使用secret

#kubelet负责拉取镜像

#如何告诉kubulet拉取镜像,使用my-registry-secret就可以

#创建后组要给pod上的应用提供配置文件

# 需要configmap secret 挂载到 pod 中 挂载到 容器 中

#以pod.spec.imagePullSecrets去使用dockerconfigjson

两种方式:env:环境变量 挂载到 容器 中 , 适合 简单的key=value

Volume:卷挂载到pod中多行文本更适合使用Volume

  1. 如何使用ConfigMap 和 Secret 对象

:ConfigMap 和 Secret 只是一些存储在 etcd 里的字符串,所以如果想要在运行时产生效果,就必须要以某种方式“注入”到 Pod 里,让应用去读取。在这方面的处理上 Kubernetes 和Docker 是一样的,也是两种途径:环境变量和加载文件

  • 以环境变量的方式

valueFrom”字段指定了环境变量值的来源,可以是“configMapKeyRef”或者“secretKeyRef”,然后你要再进一步指定应用的 ConfigMap/Secret 的“name”和它里面的“key”

#由于“valueFrom”字段在 YAML 里的嵌套层次比较深,初次使用最好看一下 kubectl explain 对它的说明:

kubectl explain pod.spec.containers.env.valueFrom

示例:以下引用了 ConfigMap 和 Secret 对象的 Pod 定义:

#来自congfigmap中的count key中的value找到赋值给count

#也可以来自secret

  1. 根据上述yaml用 kubectl apply 创建 Pod,再用 kubectl exec 进入 Pod,验证环境变量是否生效:

#如有配置好的yaml文件可直接使用

文本

AI 生成的内容可能不正确。

#这张截图就显示了 Pod 的运行结果,可以看到在 Pod 里使用 echo 命令确实输出了我们在两个 YAML 里定义的配置信息,也就证明 Pod 对象成功组合了 ConfigMap 和 Secret 对象

#多行文本不适合使用env方式,适合简单的key=value,可使用卷挂载的方式

  • 以 Volume 的方式

#Kubernetes 为 Pod 定义了一个“Volume”的概念,可以翻译成是“存储卷”。如果把 Pod 理解成是一个虚拟机,那么 Volume 就相当于是虚拟机里的磁盘

注:Volume 属于 Pod,不属于容器,所以它和字段“containers”是同级的,都属于“spec”。

示例:

  1. 以下定义两个 Volume,分别引用 ConfigMap 和 Secret,名字是 cm-vol 和 sec-vol:

#configmap下name的名字info就是把info变为cinfigmap变成卷

#每一个卷都需要一个唯一的名字

  1. 使用 “volumeMounts”字段来挂载卷

#可以把定义好的 Volume 挂载到容器里的某个路径下,所以需要在里面用“mountPath” “name”明确地指定挂载路径和 Volume 的名字

#把“volumes”和“volumeMounts”字段都写好之后,配置信息就可以加载成文件了

#以上数组里面的容器都可以使用卷

  1. 下面是 Pod 的完整 YAML 描述,然后使用 kubectl apply 创建它

kubectl apply -f vol-pod.yaml

  1. 创建之后,我们还是用 kubectl exec 进入 Pod,看看配置信息被加载成了什么形式

# ConfigMap 和 Secret 都变成了目录的形式,而它们里面的 Key-Value 变成了一个个的文件,而文件名就是 Key

  • 如果配置文件发生变化,Pod 中加载的数据是否会同步更新 ? 热更新

  1. 以环境变量方式挂载 不支持热更新

  2. 以 volume 方式 挂载 支持热更新

  3. 总结

Kubernetes 里管理配置信息的 API 对象 ConfigMap 和 Secret,它们分别代表了明文信息和机密敏感信息,存储在 etcd 里,在需要的时候可以注入Pod 供 Pod 使用

  1. ConfigMap 记录了一些 Key-Value 格式的字符串数据,描述字段是“data”,不是“spec”。

  2. Secret 与 ConfigMap 很类似,也使用“data”保存字符串数据,但它要求数据必须是 Base64编码,起到一定的保密效果。

  3. 在 Pod 的 “env.valueFrom” 字段中可以引用 ConfigMap 和 Secret,把它们变成应用可以访问的环境变量。

  4. 在 Pod 的 “spec.volumes” 字段中可以引用 ConfigMap 和 Secret,把它们变成存储卷,然后在 “spec.containers.volumeMounts” 字段中加载成文件的形式。

  5. ConfigMap 和 Secret 对存储数据的大小没有限制,但小数据用环境变量比较适合,大数据应该用存储卷,可根据具体场景灵活应用。 1MB etcd

  6. 实战一 部署 Wordpress

图形用户界面, 图示

AI 生成的内容可能不正确。

WordPress、MySQL 这两个应用被封装成了 Pod(由于它们都是在线业务),运行所需的环境变量保存在 ConfigMap中,统一用“声明式”来管理,比起 Shell 脚本更容易阅读和版本化管理

#wordpress和mysql放到pod里面,

  • 操作执行流程:

  1. mysql创建一个congigmap

电脑屏幕的照片上有字

AI 生成的内容可能不正确。

#使用的环境变量放置到congfigmap中

  1. 执行:Kubectl apply -f 01-mysql-cm.yaml:启动configmap

  2. 执行:Kubectl apply -f 02-mysql-pod.yaml:启动mysql的pod

文本

AI 生成的内容可能不正确。

文本

AI 生成的内容可能不正确。

  1. 执行:kubectl get pods -o wide:查看ip

电脑萤幕画面

AI 生成的内容可能不正确。

#wordpress访问需要拿到ip地址,后续不使用ip

  1. 执行:vim 01-wp-cm.yaml:创建wordpress的configap

形状

AI 生成的内容可能不正确。

#此处的IP地址要按实际修改

  1. 执行:kubectl apply -f 01-wp-pod.yaml:启动wordpress的pod

文本

AI 生成的内容可能不正确。

  1. 执行:kubectl port-forward --address 0.0.0.0 pod/mypod 8080:80

#使用私网地址无法进行访问需要进行地址转发,将pod映射到宿主机

  • 报错查询:

  1. 连接找不到mysql去看提供的环境变量是否正确

#进入容器里面去查看

#使用delete -f可以针对目录

  • 从外部访问 wordpress 使用 kubectl port-forward 命令

kubectl port-forward --address 0.0.0.0 pod/mypod 8888:5000

#wordpress需要在浏览器访问。使用此命令,宿主机的0.0.0.0监听8888地址映射到容器中的5000,这样就可以在web段访问

  1. Deployment - 让应用永不宕机

  • Deployment:是专门用来部署应用程序的,能够让应用永不宕机,多用来发布无状态的应用

#无状态应用可以自由伸缩

  1. 介绍:为什么要有 Deployment

:在线业务远不是单纯启动一个 Pod 这么简单,还有多实例、高可用、版本更新等许多复杂的操作。比如最简单的多实例需求,为了提高系统的服务能力,应对突发的流量和压力,我们需要创建多个应用的副本,还要即时监控它们的状态。如果还是只使用 Pod,那就会又走回手工管理的老路,没有利用好 Kubernetes 自动化运维的优势

  1. 使用 YAML 描述 Deployment

  2. 使用命令 kubectl api-resources 来看看 Deployment 的基本信息:

kubectl api-resources | grep deploy

Deployment 的简称是“deploy”,它的 apiVersion 是“apps/v1”,kind 是“Deployment” #属于apps组

  1. Deployment的yaml头部信息写法

图片包含 图形用户界面

AI 生成的内容可能不正确。

  1. 执行kubectl create 来创建 Deployment 的 YAML 样板

kubectl create deploy nginx-dep --image=nginx:1.22.1 --dry-run=client -o yaml

图形用户界面, 文本

AI 生成的内容可能不正确。

# selector:标签选择器 根据标签 选择 当前的 Deployment 管理 哪些 Pod

#spec的app和tempiate标签要保持一致

# strategy: {}空对象 控制 更新策略,此处使用默认值

spec:

replicas: 10 #副本创建 10 个 Pod

selector: #标签选择器根据标签 选择 当前的 Deployment 管理 哪些 Pod

matchLabels:

app: nginx-dep #匹配的Pod的标签

strategy: #空对象控制 更新策略

rollingUpdate: #滚动更新

maxSurge: 1 # 25% * replicas 4 = 1 #在滚动控制期间,比用户期望多几个,更新时就是这个控制的,可以百分数可以整数

maxUnavailable: 0 # 默认25% replicas 4 = 1,一般使用0

type: RollingUpdate

  • 创建deployment

  1. 执行:kubectl apply -f nginx-dep.yaml

  2. 执行:kubectl get deployments:进行查看

# READY 表示运行的 Pod 数量,前面的数字是当前数量,后面的数字是期望数量,所以“2/2”的意思就是要求有两个 Pod 运行,现在已经启动了两个 Pod

# UP-TO-DATE 指的是当前已经更新到最新状态的 Pod 数量。因为如果要部署的 Pod 数量很多或者 Pod 启动比较慢,Deployment 完全生效需要一个过程,UP-TO-DATE 就表示现在有多少个 Pod 已经完成了部署,达成了模板里的“期望状态”

# AVAILABLE 要比 READY、UP-TO-DATE 更进一步,不仅要求已经运行,还必须是健康状态,能够正常对外提供服务,它才是我们最关心的 Deployment 指标

# AGE 表示 Deployment 从创建到现在所经过的时间,也就是运行的时间

  1. 执行:kubectl get pod:命令来看看 Pod 的状态:

表格

AI 生成的内容可能不正确。

  • 验证Deployment 部署的应用是否真的可以做到“永不宕机

  1. kubectl delete pods nginx-dep-6c758d7589-d82x4

#删除后等待一会再次查看还是正常数量pod

#被删除的 Pod 确实是消失了,但 Kubernetes 在 Deployment 的管理之下,很快又创建出了一个新的 Pod,保证了应用实例的数量始终是我们在 YAML 里定义的数量

  • controller-manager:用户期望状态和实际的状态一致

#通过查看时间状态可以看到所依赖的控制器

  • 手工扩缩容

Scale up:扩容

Scale down:缩容

#通过扩缩容进行副本数修改,增加节点

修改方式:

  1. 修改 YAML , apply

  2. kubectl edit deployment

  3. kubectl scale deployment nginx-dep --replicas 10

  4. 应用滚动升级

#应用更细重要的是版本

  • 如何定义应用版本

:在 Kubernetes 里应用都是以 Pod 的形式运行的,而 Pod 通常又会被 Deployment 等对象来管理,所以应用的“版本更新”实际上更新的是整个 Pod

:应用的版本变化就是 template 里 Pod 的变化,哪怕 template 里只变动了一个字段,那也会形成一个新的版本,也算是版本变化

Kubernetes 使用了“摘要”功能,用摘要算法计算 template 的 Hash 值作为“版本号”

#代码层面版本v1.3 v1.32 v1.33

#在pod属性里面可以看到哈希值,更新指的是后端更新

  • 如何实现应用更新(示例)

  1. 部署应用 http-app:v1,实例数设为 4

http-app-v1.yaml

  • 部署应用

  1. 执行:kubectl apply -f http-app-v1.yaml

  • 通过curl可以观察到应用的版本号

# 端口映射

  1. kubectl port-forward --address 0.0.0.0 deployment/http-app-dep 8080:80

# curl 127.0.0.1:8080

{"hostname":"http-app-dep-68b9b69985-5j8pc","version":"v1"}

  1. 编写一个新版本 http-app-v2.yaml,修改镜像的版本为 v2

#需要添加一个字段 minReadySeconds,让 Kubernetes 在更新过程中等待一点时间,确认 Pod 没问题才继续其余 Pod 的创建工作

背景图案

AI 生成的内容可能不正确。

# minReadySeconds设置,给应用启动一定的时间

  1. 执行:kubectl apply -f http-app-v2.yaml

  2. 执行:kubectl get pods -w:进行查看

表格

AI 生成的内容可能不正确。

#pod的版本都更新为了新的版本

  1. kubectl rollout status deployment http-app-dep

#更新时在另一终端执行此命令可以观察到更新过程

#仔细查看 kubectl rollout status 的输出信息,你可以发现,Kubernetes 不是把旧 Pod 全部销毁再一次性创建出新 Pod,而是在逐个地创建新 Pod,同时也在销毁旧 Pod,保证系统里始终有足够数量的 Pod 在运行,不会中断服务

图示

AI 生成的内容可能不正确。

#“滚动更新”就是由 Deployment 控制的两个同步进行的“应用伸缩”操作,老版本缩容到 0,同时新版本扩容到指定值,大家通过下面这张图再理解一下 滚动更新 的过程

#新版本有bug可以进行暂停,让少量用户更新

  1. 如何管理应用更新

在应用更新的过程中,我们可以随时使用 kubectl rollout pause 来暂停更新,检查、修改Pod,或者测试验证,如果确认没问题,再用 kubectl rollout resume 来继续更新

kubectl rollout pause:暂停更新

kubectl rollout resume:来继续更新

kubectl rollout history:查看更新历史命令

#更新时有问题需要进行回滚

#revision:修订版本号,递增

kubectl rollout history 的列表输出的有用信息太少,可以在命令后加上参数 --revision 来查看每个版本的详细信息,包括标签、镜像名、环境变量、存储卷等等,通过这些就可以大致了解每次都变动了哪些关键字段:

文本

AI 生成的内容可能不正确。

:如果我们刚上线的v2版本发现有BUG,希望回退到V1版本,可以使用命令 kubectl rollout undo,也可以加上参数 --to-revision 回退到任意一个历史版本

kubectl rollout undo deployment 应用 --to-revision 版本号:退回任意历史版本

图形用户界面, 文本

AI 生成的内容可能不正确。

annotations: #注解功能

kubernetes.io/change-cause: version=v3 #标准注解

kubernetes.io/abc: 123455 #注解不认识就会忽略

REVISION CHANGE-CAUSE:默认只保存 10 个版本

  • 从 v2 到 v1 版本降级的过程:

图示

AI 生成的内容可能不正确。

#回滚v1的版本启动一个在杀掉一个v2版本,逐步降级

  • 滚动更新

优点:Kubernetes 原生支持

缺点:无法控制有多少流量进入到新版本

  1. 添加更新描述

:kubectl rollout history 的版本列表好像有点太简单了呢?只有一个版本更新序号,而另一列 CHANGE-CAUSE 总是显示成 <none> ,能不能加上说明信息,当然是可以的,只需要在 Deployment 的 metadata 里加上一个新的字段 annotations

annotations 字段的含义是“注解” “注释”,形式上和 labels 一样,都是 Key-Value,也都是给 API 对象附加一些额外的信息,但是用途上区别很大

  • annotations:添加的信息一般是给内部的各种对象使用的,有点像是“扩展属性”;

  • labels:主要用来筛选、过滤对象的;

图片包含 文本

AI 生成的内容可能不正确。

#annotations 里的值可以任意写,Kubernetes 会自动忽略不理解的 Key-Value,但要编写更新说明就需要使用特定的字段 kubernetes.io/change-cause

日期2025.08.26学习日志

  1. Deployment - 让应用永不宕机

  2. 控制滚动更新的参数

spec:

replicas: 10 #副本创建 10 个 Pod

selector: #标签选择器根据标签 选择 当前的 Deployment 管理 哪些 Pod

matchLabels:

app: nginx-dep #匹配的Pod的标签

strategy: #空对象控制 更新策略

rollingUpdate: #滚动更新

maxSurge: 1 # 25% * replicas 4 = 1 #在滚动控制期间,比用户期望多几个,更新时就是这个控制的,可以百分数可以整数

maxUnavailable: 0 # 默认25% replicas 4 = 1,一般使用0

type: RollingUpdate

http-app-v4.yaml:

图形用户界面, 文本, 应用程序

AI 生成的内容可能不正确。

  1. 应用部署策略

  • 滚动部署 (k8s 原生支持 )

:在滚动部署中,应用的新版本逐步替换旧版本。实际的部署发生在一段时间内。在此期间,新旧版本会共存,而不会影响功能和用户体验。这个过程可以轻易的回滚

:但是滚动升级有一个问题,在开始滚动升级后,流量会直接流向已经启动起来的新版本,但是这个时候,新版本是不一定可用的,比如需要进一步的测试才能确认。那么在滚动升级期间,整个系统就处于非常不稳定的状态,如果发现了问题,也比较难以确定是新版本还是老版本造成的问题

  1. 蓝绿部署

:蓝绿发布提供了一种零宕机的部署方式。不停老版本,部署新版本进行测试,确认OK,将流量切到新版本,然后老版本同时也升级到新版本。始终有两个版本同时在线,有问题可以快速切换

  • 蓝绿发布的特点:

:在部署应用的过程中,应用始终在线。并且新版本上线过程中,不会修改老版本的任何内容,在部署期间老版本状态不受影响。只要老版本的资源不被删除,可以在任何时间回滚到老版本

:以下示意图可描述蓝绿发布的大致流程:先切分20%的流量到新版本,若表现正常,逐步增加流量占比,继续测试新版本表现。若新版本一直很稳定,那么将所有流量都切分到新版本,并下线老版本

图形用户界面

AI 生成的内容可能不正确。

切分20%的流量到新版本后,新版本出现异常,则快速将流量切回老版本

图形用户界面

AI 生成的内容可能不正确。

#蓝绿部署要求在升级过程中,同时运行两套程序,对硬件的要求就是日常所需的二倍,比如日常运行时,需要10台服务器支撑业务,那么使用蓝绿部署,你就需要购置二十台服务器

#蓝绿发布依赖于ELB,负债均衡器,控制流量进入哪个环境

  1. 金丝雀 / 灰度 发布

:在生产环境上引一部分实际流量对一个新版本进行测试,测试新版本的性能和表现,在保证系统整体稳定运行的前提下,尽早发现新版本在实际环境上的问题

  • 金丝雀发布的特点:

金丝雀发布,又称为灰度发布。它能够缓慢的将修改推广到一小部分用户,验证没有问题后,再推广到全部用户,以降低生产环境引入新功能带来的风险

图形用户界面, 文本, 应用程序, 聊天或短信

AI 生成的内容可能不正确。

#可以实现v1和v2的共存,不需要两套环境

  1. 步骤一:部署少量副本的金丝雀版本的应用;

  2. 步骤二:根据不同策略,将流量引入金丝雀副本。策略可以根据情况指定,比如随机样本策略(随机引入)、狗粮策略(就是内部用户或员工先尝鲜)、分区策略(不同区域用户使用不同版本)、用户特征策略(这种比较复杂,需要根据用户个人资料和特征进行分流,类似于千人千面)

  3. 步骤三:金丝雀副本应用 验证通过后,增加金丝雀应用的副本数,增加导流的比例,减少旧版本的流量和副本的数量,最终完成版本的切换

图示

AI 生成的内容可能不正确。

  1. 应用保障策略

  • 容器资源配额

  1. 保障应用资源。

#应用运行至少需要 2C4G 资源 , 如何保障 Pod 正常运行,最少需要 2C4G,在调度时 就需要考虑kube-scheduler

  1. 保障应用在运行过程中不会宕机。 #探针

  • 如何限制容器对资源的使用

#Kubernetes如何限制容器对资源的需求,只要在 Pod 容器的描述部分添加一个新字段 resources 就可以了

#requests最少要满足的条件

containers.resources,它下面有两个字段:

  • “requests”:意思是容器要申请的资源,也就是说要求 Kubernetes 在创建 Pod 的时候必须分配这里列出的资源,否则容器就无法运行。

  • “limits”:意思是容器使用资源的上限,不能超过设定值,否则就有可能被强制停止运行

#limits一定要大于等于requests

cpu:1000m=1核心

memory: 2Gi

  • Pod 在调度时,kube-scheduler 使用 requests 中的值作为调度要求。调度时目标节点的剩余资源 >= requests

#如果不满足资源就会被排除出去

  1. 容器的服务质量

  • QoS 服务质量分为三类

  • Guaranteed 保证的

# limits = requests就是Guaranteed,只有limits,自动补全 requests也是Guaranteed

  • Burstable:突发的、峰值的

#limits大于requests,只有requests没有limits是Burstable,不会自动补全

  • BestEffort:进来而为的

#没有设置resources就是属于BestEffort

#不建议使用besteffort

  • 为什么要给pod设置QOS

:驱逐时使用

#一个节点会跑多个pod,会导致操作系统资源不足,避免这个情况,资源不足时把一些节点驱逐,对pod进行分类驱逐。最先驱逐BestEffort

Guaranteed 的 Pod:

  1. Pod 中的每个容器都必须指定内存限制和内存请求。

  2. 对于 Pod 中的每个容器,内存限制必须等于内存请求

  3. Pod 中的每个容器都必须指定 CPU 限制和 CPU 请求。

  4. 对于 Pod 中的每个容器,CPU 限制必须等于 CPU 请求

图形用户界面, 应用程序

AI 生成的内容可能不正确。

#只有limits,自动补全 requests

Burstable 的 Pod:

  1. Pod 不符合 Guaranteed QoS 类的标准。

  2. Pod 中至少一个容器具有内存或 CPU 请求

图表

AI 生成的内容可能不正确。

BestEffort 的 Pod:

  1. 没有设置内存和 CPU 限制或请求

图形用户界面

AI 生成的内容可能不正确。

  1. Kubernetes 资源超卖

:Kubernetes 在计算资源时是使用 request 字段进行计算的。 一个 worker 节点如果有 10 个 CPU 的资源。 Pod A 申请 request:5,limit:5, Pod B 申请 request 5,limit 5,是可以申请成功的。 而如果再启动一个 Pod C 申请 request 5, limit 5, 就会失败(Pod 处于 pending 状态, 一直在等待资源)。 因为 kubernetes 并不是按 limit 字段来计算资源用量而是使用 request 字段进行计算

#上面的资源申请方式在 Kubernetes 就被称作 资源超卖

资源超卖 的意思就是说本来系统只有 10 个 CPU 的资源, 但是容器 A、B、C、D 都各自需要申请 5 个 CPU 的资源,这明显不够用。 但是如果 A、B、C、D 不可能在同一时刻都占满 5 个 CPU 资源, 因为每个服务都有它业务的高峰期和低谷期的。 高峰期的时候可以占满 5 个 CPU, 但是服务大部分时间都处于低谷期,可能只占用 1,2 个 CPU。 所以如果直接写 request:5 的话,很多时候资源是浪费的( kubernetes 里即便容器没有使用到那么多资源, 也会为容器预留 request 字段的资源)。 所以我们可以为容器申请这样的资源: request:1, limit:5。 这样上面 4 个容器加起来只申请了 4 个 CPU 的资源, 而系统里有 10 个 CPU, 是完全可以申请到的。 而每个容器的 limit 又设置成了 5, 所以每个容器又都可以去使用 5 个 CPU 资源

形状

AI 生成的内容可能不正确。

# 建议使用Burstable方式提高资源的利用率

  1. 容器状态探针

  • 什么是容器探针

Kubernetes 用来判断应用是否“健康”的功能被命名为“探针”(Probe),也可以叫“探测器”

Kubernetes 为检查应用状态定义了三种探针,它们分别对应容器不同的状态:

  1. Startup Probe:启动探针:用来检查应用是否已经启动成功,适合那些有大量初始化工作要做,启动很慢的应用。

#容器启动时生效,没有探针是用minReadySeconds: 10

  1. Liveness Probe:存活探针:用来检查应用是否正常运行,是否存在死锁、死循环。

  2. Readiness Probe:就绪探针:用来检查应用是否可以接收流量,Pod是否能够对外提供服务

#需要注意这三种探针是递进的关系:应用程序先启动,加载完配置文件等基本的初始化数据就进入了 Startup 状态,之后如果没有什么异常就是 Liveness 存活状态,但可能有一些准备作没有完成,还不一定能对外提供服务,只有到最后的 Readiness 状态才是一个容器最健康可用的状态

图示

AI 生成的内容可能不正确。

  • Kubernetes 在启动容器后就会不断地调用探针来检查容器的状态:

  • Startup探测成功:接下来 LivenessProbe、 readinessProbe 开始工作,如果 Startup 探针失败,Kubernetes 会认为容器没有正常启动,就会尝试反复重启,当然其后面的 Liveness 探针和 Readiness 探针也不会启动。

  • Liveness探测成功:下个周期接着探测,如果 Liveness 探针失败,Kubernetes 就会认为容器发生了异常,也会重启容器。

  • Readiness探测成功: 下个周期接着探测,如果 Readiness 探针失败,就会把容器从 Service 对象的负载均衡集合中排除,不会给它分配流量

注:以上三种类型的探针都需要配置

图示

AI 生成的内容可能不正确。

  1. 使用容器探针:探测参数

  • startupProbe、livenessProbe、readinessProbe,关键字段有这么几个:

#这三种探针的配置方式都是一样的

  1. periodSeconds:执行探测动作的时间间隔,默认是 10 秒探测一次。

  2. timeoutSeconds:探测动作的超时时间,如果超时就认为探测失败,默认是 1 秒。

  3. successThreshold:连续几次探测成功才认为是正常,对于 startupProbe 和livenessProbe 来说它只能是 1。 成功阈值

  4. failureThreshold:连续探测失败几次才认为是真正发生了异常,默认是 3 次。 失败阈值

  5. initialDelaySeconds:初始化延迟时间 #应用启动慢给初始化的一个秒数

  • 探测方式:Kubernetes 支持 3 种:exec、TCP Socket、HTTP GET,它们也需要在探针里配置:

  1. exec:执行一个 Linux 命令,比如 ps、cat 等等,和 container 的 command 字段很类似。

  2. tcpSocket:使用 TCP 协议尝试连接容器的指定端口。 Telnet ip port

  3. httpGet:连接端口并发送 HTTP GET 请求。 Curl http://ip:port

#跟具状态码判断有没有成功,建议优先使用httpGet

示例:

#以 Nginx 作为示例,用 ConfigMap 编写一个配置文件

nginx-conf-cm.yaml

nginx-dep-probe.yaml

图片包含 图形用户界面

AI 生成的内容可能不正确。

图形用户界面, 文本

AI 生成的内容可能不正确。

  • StartupProbe:使用了 Shell 方式,使用 cat 命令检查 Nginx 存在磁盘上的进程号文件(/var/run/nginx.pid),如果存在就认为是启动成功,它的执行频率是每2秒探测一次。

  • LivenessProbe:使用了 TCP Socket 方式,尝试连接 Nginx 的 80 端口,每 5 秒探测一次。

  • ReadinessProbe:使用的是 HTTP GET 方式,访问容器的 /ready 路径,每 5 秒发一次请求

  1. 使用 kubectl apply 创建 nginx deployment

kubectl apply -f nginx-conf-cm.yaml

kubectl apply -f nginx-dep-probe.yaml

  • 观察pod状态

  1. 执行:kuberctl get pods

  • 使用 kubectl logs 命令查看 nginx 日志,可以看到探针的执行情况

文本

AI 生成的内容可能不正确。

#通过上图可以看到 Kubernetes 正是以大约 5 秒一次的频率,向 URI /ready 发送 HTTP 请求,不断地检查容器是否处于就绪状态

  • 验证其他探针:

#可以修改探针,比如把命令改成检查错误的文件、错误的端口号:

图形用户界面, 文本

AI 生成的内容可能不正确。

#当 StartupProbe 探测失败的时候,Kubernetes 就会不停地重启容器,现象就是 RESTARTS 次数不停地增加,而 livenessProbe 和 readinessProbePod 没有执行,Pod 虽然是 Running 状态,也永远不会 READY:

文本

AI 生成的内容可能不正确。

  1. 测试 Liveness 和 readinessProbe 执行频率

雷达图

AI 生成的内容可能不正确。

  1. ReplicaSet 控制器

:Kubernetes 中的 ReplicaSet 主要的作用是维持一组 Pod 副本的运行,它的主要作用就是保证一定数量的 Pod 能够在集群中正常运行,它会持续监听这些 Pod 的运行状态,在 Pod 发生故障重启数量减少时重新运行新的 Pod 副本

Deployment > replicasets > pod #控制链

deployment-controller > Scaled up replicaset > replicaset-controller > create pods

#控制连,deployment控制replicaset滚动更新

#滚动更新时会自动创建一个replicaset控制pod的数量

nginx-reps.yaml

图片包含 图形用户界面

AI 生成的内容可能不正确。

文本

AI 生成的内容可能不正确。

:Deployment 是一个可以拥有 ReplicaSet 并使用声明式方式在服务器端完成对 Pod 滚动更新的对象。 尽管 ReplicaSet 可以独立使用,目前它们的主要用途是提供给 Deployment 作为编排 Pod 创建、删除和更新的一种机制。当使用 Deployment 时,你不必关心如何管理它所创建的 ReplicaSet,Deployment 拥有并管理其ReplicaSet。 因此,建议你在需要 ReplicaSet 时使用 Deployment

图示

AI 生成的内容可能不正确。

#deployment控制版本更新,会创建一个replicaset控制pod数量

  • ReplicationController 控制器

图形用户界面, 文本

AI 生成的内容可能不正确。

  1. DaemonSet-忠实可靠的看门狗

Deployment

replicaset

DaemonSet

#都是apps组,都和应用部署相关

  1. DaemonSet 应用场景

DaemonSet 的目标是在集群的每个节点上运行且仅运行一个Pod,就好像是为节点配上一只“看门狗”,忠实地“守护”着节点,这就是DaemonSet 名字的由来

#监控节点数量变化

  • 应用场景:

  • 网络代理(如 kube-proxy):必须每个节点都运行一个 Pod,否则节点就无法加入Kubernetes 网络。

  • 监控应用(如 node-exporter):必须每个节点都有一个 Pod 用来监控节点的状态,实时上报信息。

  • 网络插件:CNI calico-node

  • 日志应用(如 filebeat):必须在每个节点上运行一个 Pod,才能够搜集容器运行时产生的日志数据。

  • 安全应用:同样的,每个节点都要有一个 Pod 来执行安全审计、入侵检查、漏洞扫描等工作

  1. 使用 YAML 描述 DaemonSet

:DaemonSet 和 Deployment 都属于在线业务,所以它们也都是“apps”组,使用命令 kubectl api-resources 可以知道它的简称是 ds ,所以 YAML 文件头信息应该是:

图形用户界面, 应用程序

AI 生成的内容可能不正确。

  • 官网模板修改:

图片包含 图形用户界面

AI 生成的内容可能不正确。

:我们比较一下Daemonset和Deployment的YAML就会看到,DaemonSet 在 spec 里没有 replicas 字段,这是它与Deployment 的一个关键不同点,意味着它不会在集群里创建多个 Pod 副本,而是要在每个节点上只创建出一个 Pod 实例

:也就是说,DaemonSet 仅仅是在 Pod 的部署调度策略上和 Deployment 不同,其他的都是相同的,某种程度上我们也可以把 DaemonSet 看做是 Deployment 的一个特例

图形用户界面, 图示

AI 生成的内容可能不正确。

  • 部署DaemonSet

  1. 执行命令 kubectl apply 来创建 DaemonSet 对象,再用 kubectl get 查看对象的状态:

电脑萤幕截图

AI 生成的内容可能不正确。

#没有指定 DaemonSet 里 Pod 要运行的数量,但它自己就会去查找集群里的节点,在节点里创建 Pod。因为我们的环境里有一个 Master 一个 Worker,所以 DaemonSet 就在每个节点上生成了一个 Pod

:master不能跑pod,数据都是在worker节点上。如何实现:

master集群搭建完成后会给master打上一个污点tain,污点打上后新的pod就不会调度到master上。节点有污点还需要运行,就需要配置。

#daemonset会自动观看集群中节点的数量,如果发现节点变化,就会自动启动一个pod

监控mysql:安装mysql-exporter #promethues 加一个 Job,去抓取数据

#redis-exporter

  • 控制面Pod是如何 管理 的 ?

运行:kubectl -n kube-system describe pods coredns-6766b7b6bb-gnrkf

#Controlled By: Node/master-01 kubelet管理 显示对象归谁管理

  • kubelet如何知道pod的

表格

AI 生成的内容可能不正确。

#四个yaml对应着控制面的四个组件

# /etc/kubernetes/manifests/:控制面配置文件位置 。

# manifests使用 kubeadm初始化集群时创建的

:manifests 资源清单 #描述文件就是资源清单

  • kubelet启动参数

/usr/bin/kubelet

--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf #放置apiserver的信息,安全相关信息

--config=/var/lib/kubelet/config.yaml #kubelet的配置文件

--container-runtime-endpoint=unix:///var/run/containerd/containerd.sock

--pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.10

kubeconfig #容器镜像

kubectl > apiserver 安全相关

kubelet > apiserver

静态 Pod

staticPodPath: /etc/kubernetes/manifests

#直接写的yaml

日期2025.08.27学习日志

  1. service、ingress

  2. 什么是 Service

:在 Kubernetes 集群里 Pod 的生命周期是比较“短暂”的,虽然 Deployment 和 DaemonSet 可以维持 Pod 总体数量的稳定,但在运行过程中,难免会有 Pod 销毁又重建,这就会导致 Pod集合处于动态的变化之中。 Pod 的 IP 地址经常变来变去,客户端该怎么访问呢?如果不处理好这个问题,Deployment 和 DaemonSet 把 Pod 管理得再完善也是没有价值的

:其实,这个问题在业内早就有解决方案来针对这样“不稳定”的后端服务,那就是“负载均衡”,典型的应用有 LVS、Nginx 等等。它们在前端与后端之间加入了一个“中间层”,屏蔽后端的变化,为前端提供一个稳定的服务

图示

AI 生成的内容可能不正确。

#四层使用service做网络代理

#客户端访问clusterIP,通过clusterIP进行负债均衡向后端pod做代理

  1. 使用 YAML 描述 Service

:用命令 kubectl api-resources 查看它的基本信息,可以知道它的简称是svc,apiVersion 是 v1。注意,这说明它与 Pod 一样,属于 Kubernetes 的核心对象

  • Service 的 YAML 文件

图片包含 图形用户界面

AI 生成的内容可能不正确。

:使用 kubectl expose 指令来创建service模板文件,需要用参数 --port 和 --target-port 分别指定映射端口和容器端口,而 Service 自己的 IP 地址和后端 Pod 的 IP 地址可以自动生成,用法上和Docker 的命令行参数 -p 很类似

kubectl expose deploy nginx-dep(deploy的名字) --port=80(clusterIP的端口) --target-port=80(容器中应用的端口) --dry-run=client -o yaml

#做代理就需要暴露一个端口,expose对外暴露一个deploy。deploy管理pod

#创建一个deployment就会创建一个service。访问service就会把请求转发到deployment的pod

图形用户界面

AI 生成的内容可能不正确。

#app:nginx-dep把流量转给哪些pod,通过标签选择器把流量给后端的pod

Service 的定义非常简单,在“spec”里只有两个关键字段,selector 和 ports

:selector 是用来过滤出要代理的那些 Pod,因为我们指定要代理 Deployment,所以 Kubernetes 就为我们自动填上了 nginx-dep 的标签,会选择这个 Deployment 对象部署的所有 Pod

图示

AI 生成的内容可能不正确。

#selector通过标签去选择哪个pod的标签,有这个标签都是要转发的

图形用户界面, 图表

AI 生成的内容可能不正确。

:客户端访问service负载调度器,在把请求轮询到后端pod

  1. 在 Kubernetes 里使用 Service

  2. 查看 Service 的效果,我们添加一个Nginx的配置文件,使用ConfigMap来定义,通过Volume 挂载到 Pod中

图片包含 图形用户界面

AI 生成的内容可能不正确。

  1. 在 Deployment 中通过 “template.volumes”定义存储卷,使用“volumeMounts” 挂载到容器中

雷达图

AI 生成的内容可能不正确。

图片包含 图形用户界面

AI 生成的内容可能不正确。

  1. 部署 Deployment 之后,使用 kubectl apply 创建 Service 对象了

kubectl apply -f nginx-svc.yaml

  1. 执行:kubectl get svc:查看对象状态

# Kubernetes 会自动为 Service 对象分配一个IP地址“10.111.193.124”,这个地址段是独立于Pod地址段的(在kubeadm 安装的配置文件里指定的)。Service 对象的 IP 地址还有一个特点,它是一个“虚地址”,不存在实体,只能用来转发流量

#type:svc的类型、cluster-IP:集群内可以使用的vip、poers:svc对外的端口

  1. 执行:kubectl describe svc nginx-svc:查看Service 代理了哪些后端的Pod

文本

AI 生成的内容可能不正确。

#通过截图可以看到 Service管理了两个 endpoint 对象,10.244.171.7:80 和 10.244.184.72:80

#可以自动找到后端的pod

  • endpoints:#负载均衡清单,缩写时ep

#只要负载均衡的副本有变化,清单就会自动去调整

  • 只要有selector标签就会创建endpoints

  • 测试这两个地址是不是实际 Pod 的地址?

  1. 执行:kubectl get pods -o wide

#通过上面的截图我们就能够验证 Service 确实用一个静态 IP 地址代理了两个 Pod 的动态 IP 地址

图示

AI 生成的内容可能不正确。

  1. 测试 Service 的负载均衡效果

  2. 使用 curl 命令在 master 节点或是 worker 节点上执行以下命令来访问 Service:

curl 10.111.193.124

文本

AI 生成的内容可能不正确。

#用 curl 访问 Service 的 IP 地址,就会看到它把数据转发给后端的 Pod,输出信息会显示具体是哪个 Pod 响应了请求,就表明 Service 确实完成了对 Pod 的负载均衡任务

  1. 我们再删除一个 Pod,看看 Service 是否会更新后端 Pod 的信息,实现自动化的服务发现:

kubectl delete pod nginx-dep-b4bfd684c-pncv8

文本

AI 生成的内容可能不正确。

#Pod 被删除后,Deployment 对象会自动创建一个新的 Pod,Service 会实时监控 Pod 的变化,所以它也会立即更新后端代理的 Pod 地址。这样后端的 Pod 数量就可以按业务需要自由伸缩,对用户是无感的

  1. 以域名的方式使用 Service

#使用svc如果删除了svc就会导致ip发生变化,所以通过域名进行使用service

:给每个svc创建一个唯一的域名,屏蔽svc的clusterIP

  • dns (coredns) :域名 clusterip

图片包含 文本

AI 生成的内容可能不正确。

#因为 DNS 是一种层次结构,为了避免太多的域名导致冲突,Kubernetes 就把名字空间作为域名的一部分,减少了重名的可能性

  • DNS 是在 Kubernetes 集群内部生效,所以要测试需要在 Pod 内验证

文本

AI 生成的内容可能不正确。

#可以看到,现在我们就不再关心 Service 对象的 IP 地址,只需要知道它的名字,就可以用DNS 的方式去访问后端服务

  • 域名完整格式:

对象名.(svc名字) 命名空间. svc. (域名的类型) cluster.local(集群的域名)

nginx-svc. default. svc. cluster.local

#集群域名可以根据需求修改

#每个k8s集群都可以定义一个域名

集群中每一个pod都会自动配置一个DNS服务器:

屏幕的截图

AI 生成的内容可能不正确。

#coredns是由一个deploy管理,此处是用的svc的ip地址

#访问10.96.0.10就会转到coredns

  • suffix:dns的后缀

搜索域:

search default.svc.cluster.local svc.cluster.local cluster.local

#写前一端通过搜索域将域名自动补全,不同的域名空间需要手写一些域名空间,最终都是完整的域名使用,

#域名只能在集群内使用

clusterip可以在节点和pod中使用

  1. 集群外如何访问集群内的应用(让service对外暴露服务)

:Service 是一种负载均衡技术,它不仅能够管理 Kubernetes 集群内部的服务,还能够向集群外部暴露服务

#svs的类型是有多个的

:Service 对象有一个关键字段“type”,表示 Service 是哪种类型的负载均衡。前面我们创建 Service 都使用的默认值“ClusterIP”,这种类型的 Service 地址只能在集群内访问

kubectl explain service.spec.type:查看字段属性

文本

AI 生成的内容可能不正确。

  • svc type

ClusterIP:默认类型只能在集群内使用

LoadBalancer:集群外访问集群内应用负载均衡器依赖云厂商

NodePort:集群外访问集群内应用,集群中任意node节点IP + port

ExternalName:别名类似CNAME

#默认使用clusterIP

#生产环境建议使用LoadBalancer,内网环境建议使用NodePort

  • NodePort

修改一下 Service 的 YAML 文件,加上 “type” 字段:测试

图表, 雷达图

AI 生成的内容可能不正确。

更新对象,查看状态:

kubectl apply -f nginx-svc.yaml

kubectl get svc

文本

AI 生成的内容可能不正确。

#可以看到 nginx-svc 的 “TYPE” 变成了 “NodePort”,而在 “PORT” 列里的端口信息也不一样,除了集群内部使用的“80”端口,还多出了一个“32119”端口,这就是 Kubernetes 在节点上为 Service 创建的专用映射端口

#在所有的node上面都会监听32119端口,访问集群时加上32119都可以访问

#因为这个端口号属于节点,外部能够直接访问,所以现在我们就不需要登录集群节点或者进入 Pod 内部,直接在集群外使用任意一个节点的 IP 地址,就能够访问 Service 和它代理的后端服务了

:NodePort端口范围是30000~32767”这个范围内随机分配

图示

AI 生成的内容可能不正确。

#建议使用worker节点测试

  • ExternalName

:ExternalName Service 是 Kubernetes 中一个特殊的 service 类型,它不需要指定 selector 去选择哪些 Pod 实例提供服务,而是使用 DNS CNAME 机制把自己 CNAME 到你指定的另外一个域名上,你可以提供集群内的名字,比如mysql.db.svc 这样的建立在db命名空间内的 MySQL 服务,也可以指定 http://www.baidu.com 这样的外部真实域名

  1. 我们需要使用 ping 和nslookup 命令,所以部署一个 busybox 的 deployment,busybox 镜像中提供很多常用的命令可以使用

图片包含 地图

AI 生成的内容可能不正确。

  1. 创建一个 External Service

图表

AI 生成的内容可能不正确。

  1. 登录到 Pod 中验证 External Service

kubectl exec -it busy-dep-7cdbb85ff-ffhck -- sh

文本

AI 生成的内容可能不正确。

文本

AI 生成的内容可能不正确。

#可以看到 external-svc 会被解析到一个 CNAME 指向 www.baidu.com

  • LoadBalancer

  1. 修改 service 的类型为 LoadBalancer 测试下效果

图片包含 雷达图

AI 生成的内容可能不正确。

  1. 更新svc

kubectl apply -f nginx-svc-lb.yaml

手机屏幕截图

AI 生成的内容可能不正确。

# PORT 列没有变化,但是 EXTERNAL-IP 列会显示 pending,因为 LoadBalancer 类型的负载均衡需要云服务商提供,我们的环境会显示为 pending状态,但是 LoadBalancer 也是用了 NodePort 的实现方式,因为 PORT 列还保留了 NodePort 的端口

#只有使用云厂商提供的集群才会创建负载调度器LoadBalancer,会把负载调度器的公网ip放到external-IP里面

图示

AI 生成的内容可能不正确。

:LoadBalancer作为公网的一个入口,跳转到nodeport,在跳转到集群进入pod里面

  • 不同 Service 类型的对比

  1. ClusterIP:只能在集群内部使用。clusterIP 域名

  2. NodePort:可以作为集群流量入口,但也有一些缺点

  • 端口数量有限。默认只在“30000~32767”这个范围内随机分配,只有 2000 多个,而且都不是标准端口号。

  • 需要在每个节点上都开端口,然后使用 kube-proxy 路由到真正的后端 Service,这对于大规模集群来说如果Pod 频繁变更,Service 收敛速度就会变慢。

  • 需要向外界暴露节点的 IP 地址,这在很多时候是不可行的,为了安全还需要在集群外再搭一个反向代理,增加了方案的复杂度

#虽然有这些缺点,但 NodePort 仍然是 Kubernetes 对外提供服务的一种简单易行的方式,在没有更好的方案出现之后,我们暂且使用这种方式

  1. ExternalName: 只是一个CNAME,应用场景有限。

  2. LoadBalancer:依赖云厂商实现。 生产环境

  • Service 的三个 port

图片包含 雷达图

AI 生成的内容可能不正确。

  • port:表示 Service 暴露的服务端口,也是客户端访问用的端口,例如 Cluster IP:port 是提供给集群内部客户访问 Service 的入口 。 需要注意的是, port 不仅是 Cluster IP 上暴露的端口,还可以是 external IP 和 Load Balancer IP 。 Service 的 port 并不监听在节点 IP 上,即无法通过节点 IP:port 的方式访问 Service 。

  • NodePort:是 Kubemetes 提供给集群外部访问 Service 的入口的一种方式(另 一种方式是 Load Balancer ),所以可以通过 Node IP:nodePort 的方式提供集群外访问 Service 的入口 。 需要注意的是,我们这里说的集群外指的是 Pod 网段外,例如 Kubemetes 节点或因特网 。

  • targetPort:很好理解,它是应用程序实际监听 Pod 内流量的端口,从 port 和 NodePort 上到来的数据,最终经过 Kube-proxy 流入后端 Pod 的 targetPort 进入容器

  1. svc底层实现原理:

:在 Kubernetes 集群中,每个 Node 运行一个 kube-proxy 进程。kube-proxy 负责为 Service 实现了一种 VIP(虚拟 IP)

  • service底层技术

  • userspace #早期使用

  • iptables 默认

  • LVS IPVS SVC:比较多的场景 ,建议使用 IPVS 模式

  • iptables

:这种模式,kube-proxy 会监听 apiserver 对 Service 对象和 Endpoints 对象的添加和移除。对每个 Service,它会添加上 iptables 规则,从而捕获到达该 Service 的 clusterIP(虚拟 IP)和端口的请求,进而将请求重定向到 Service 的一组 backend 中的某一个 Pod 上面。我们还可以使用 Pod readiness 探针 验证后端 Pod 是否可以正常工作,以便 iptables 模式下的 kube-proxy 仅看到正常运行的后端,这样做意味着可以避免将流量通过 kube-proxy 发送到已知失败的 Pod 中,所以对于线上的应用来说一定要做 readiness 探针

iptables 模式的 kube-proxy 默认的策略是,随机选择一个后端 Pod

:当创建 backend Service 时,Kubernetes 会给它指派一个虚拟 IP 地址,比如 10.0.0.10。假设 Service 的端口是 1234,该 Service 会被集群中所有的 kube-proxy 实例观察到。当 kube-proxy 看到一个新的 Service,它会安装一系列的 iptables 规则,从 VIP 重定向到 Service 规则。 该 Service 规则连接到 Endpoint 规则,该 Endpoint 规则会重定向(目标 NAT)到后端的 Pod

  • 查看 Kube-proxy 当前运行模式

[root@master-01 manifests]# curl 127.0.0.1:10249/proxyMode

iptables

#请求一个地址,kube-proxy的一个地址

如何调用iptables实现: #iptables规则分析

图形用户界面, 文本, 应用程序

AI 生成的内容可能不正确。

# kube-proxy 针对 service 流量入口专门创建了 KUBE-SERVICES 链

#如果 访问地址 10.109.113.191/32,目标端口是 80,则会进入KUBE-SVC-HL5LMXD5JFHQZ6LN

#这里利用了 iptables 的 random 模块,使连接有 33.3% 的概率进入KUBE-SEP-CJDFZCCVLCELCYBF

# 50% 概率进入KUBE-SEP-3VMCJLNCH76FUSTT

#最后百分百匹配

DNAT:

图形用户界面, 文本, 应用程序

AI 生成的内容可能不正确。

访问流程:KUBE-SERVICES > KUBE-SVC > KUBE-SEP

#clusterip 轮询 DNAT Pod

  • NodrPort 的访问方式

手机屏幕的截图

AI 生成的内容可能不正确。

#修改类型为NodePort

文本

AI 生成的内容可能不正确。

文本

AI 生成的内容可能不正确。

访问跳转流程:KUBE-NODEPORTS > KUBE-SVC > KUBE-SEP

# 30000+端口监听 轮询 DNAT地址转换

  • iptables 模式最主要的链是:KUBE-SERVICES 、 KUBE-SVC-*和 KUBE-SEP-*

  • KUBE-SERVICES 链是访问集群内服务的数据包入口点,它会根据匹配到的目标 IP :port 将数据包分发到相应的 KUBE-SVC-*链;

  • KUBE-SVC-*链相当于一个负载均衡器,它会将数据包平均分发到 KUBE-SEP-* 链 。 每个 KUBE-SVC-* 链后面的 KUBE-SEP-*链都和 Service 的后端 Pod 数量一样;

  • KUBE-SEP-*链通过 DNAT 将连接的目的地址和端口从 Service 的 IP:port 替换为后端Pod 的 IP : port ,从而将流量转发到相应的 Pod

  • iptabales vs IPVS

表格

AI 生成的内容可能不正确。

  1. IPVS

介绍:除了 iptables 模式之外,kubernetes 也支持 ipvs 模式,在 ipvs 模式下,kube-proxy 监视 Kubernetes 服务和端点,调用 netlink 接口相应地创建 IPVS 规则, 并定期将 IPVS 规则与 Kubernetes 服务和端点同步。该控制循环可确保 IPVS 状态与所需状态匹配。访问服务时,IPVS 将流量定向到后端 Pod 之一

:IPVS 代理模式基于类似于 iptables 模式的 netfilter 钩子函数,但是使用哈希表作为基础数据结构,并且在内核空间中工作。 所以与 iptables 模式下的 kube-proxy 相比,IPVS 模式下的 kube-proxy 重定向通信的延迟要短,并且在同步代理规则时具有更好的性能。与其他代理模式相比,IPVS 模式还支持更高的网络流量吞吐量。所以对于较大规模的集群会使用 ipvs 模式的 kube-proxy,只需要满足节点上运行 ipvs 的条件,然后我们就可以直接将 kube-proxy 的模式修改为 ipvs,如果不满足运行条件会自动降级为 iptables 模式,现在都推荐使用 ipvs 模式,可以大幅度提高 Service 性能

IPVS 提供了更多选项来平衡后端 Pod 的流量,默认是 rr,有如下一些策略:

  • rr:轮询调度

  • lc:最小连接数

  • dh:目标哈希

  • sh:源哈希

  • sed:最短期望延迟

  • nq: 不排队调度

图示

AI 生成的内容可能不正确。

注意: ipvs模式假定在运行kube-proxy之前在节点上都已经安装了IPVS内核模块。当kube-proxy以ipvs代理模式启动时,kube-proxy将验证节点上是否安装了IPVS模块,如果未安装,则kube-proxy将回退到iptables代理模式。

  • Kube-proxy 切换到 IPVS 模式

#iptables切换成ipvs模式

  1. 修改 kube-proxy 配置文件 configmap

文本

AI 生成的内容可能不正确。

  1. 执行:kubectl -n kube-system edit cm kube-proxy:修改以下

@

#默认使用iptanles

  1. 执行:kubectl -n kube-system delete pods kube-proxy-5glmk:删除pod

  2. 执行:kubectl1-n kube-systemget pod:重新启动pod

#可以让配置快速生效

验证:

表格

AI 生成的内容可能不正确。

clusterip SVC

服务发现

服务A 服务 B

Deployment Deployment

  1. Ingress

  2. 什么是什么是 Ingress

:Service 本质上是一个由 kube-proxy 控制的四层负载均衡,但在四层上的负载均衡功能还是太有限了,只能够依据 IP 地址和端口号做一些简单的判断和组合,而现在的绝大多数应用都是跑在七层的 HTTP/HTTPS 协议上的,有更多的高级路由条件,比如主机名、URI、请求头、证书等等

:Service 比较适合代理集群内部的服务。如果想要把服务暴露到集群外部,就只能使用 NodePort 或者 LoadBalancer 这两种方式 ,而这两种方式也都有各自的缺点,不能满足所有的场景

Kubernetes 就引入一个新的 API 对象,在七层上做负载均衡

图示, 示意图

AI 生成的内容可能不正确。

图形用户界面, 图示, PowerPoint

AI 生成的内容可能不正确。

Ingress 作为流量的总入口,统管集群的进出口数据

:用户通过客户端请求进入七层的ingress,ingress根据配置决定请求转给哪个service,

  • 实现:

七层:通过对象ingress,通过ingress-controller实现,通过实现交给社区

四层:通过对象service,通过实现kube-proxy。每个节点启动一个deploy

  • 什么是 Ingress Controller

Service 本身是没有服务能力的,它只是一些 iptables 规则,真正配置、应用这些规则的实际上是节点上的 kube-proxy 组件

:Ingress 也只是声明了一些 HTTP 路由规则,相当于一份静态的配置文件,要把这些规则在集群里实施运行,还需要有另外一个组件,这就是 Ingress Controller,它的作用就相当于 Service 的 kube-proxy,能够读取、应用 Ingress 规则,处理、调度流量

  • Ingress Controller:主要由社区来实现,比如我们熟悉的 Nginx, 就有 Nginx Ingress Controller

#以下几种方案

  1. Kubernetes 社区: Ingress NGINX Controller http https

#里面会用到nginx

  1. Nginx 官方:NGINX Ingress Controller http https

  2. traefik:基于http的反向代理和负载均衡

  3. kong

图形用户界面, 图示, 应用程序

AI 生成的内容可能不正确。

图形用户界面, 应用程序, PowerPoint

AI 生成的内容可能不正确。

#七层通过ingress进行规则声明,使用ingress controller进行实现。通过yaml写入

  • 为什么要有 IngressClass

:一个集群里有一个 Ingress Controller,再给它配上许多不同的 Ingress 规则,应该就可以解决请求的路由和分发问题了。 但随着 Ingress 在实践中的大量应用,很多用户发现这种用法会带来一些问题,比如:

  • 由于某些原因,项目组需要引入不同的 Ingress Controller,但 Kubernetes 不允许这样做;

  • Ingress 规则太多,都交给一个 Ingress Controller 处理会让它不堪重负;

  • 多个 Ingress 对象没有很好的逻辑分组方式,管理和维护成本很高;

  • 集群里有不同的用户,他们对 Ingress 的需求差异很大甚至有冲突,无法部署在同一个 Ingress Controller 上

:kubernetes 又提出了一个 Ingress Class 的概念,让它插在 Ingress 和 IngressController 中间,让它来协调流量规则和控制器,解除了 Ingress 和 Ingress Controller 的强绑定关系

Kubernetes 用户可以转向管理 Ingress Class,用它来定义不同的业务逻辑分组,简化 Ingress 规则的复杂度。比如说,我们可以用 Class A 处理订单流量、Class B 处理物流流量、Class C 处理购物流量

图示

AI 生成的内容可能不正确。

#安装一个实现就会创建一个ingressclass,在ingress声明规则时就需要写一个ingressclassName就会找到所创建的ingressclass

#这样实现了规则和class之间的绑定,class和controller是绑定的,间接实现和规则就是绑定的

Ingress Controller 是一个要实际干活、处理流量的应用程序,由Deployment 对象来管理。

我们部署 Kubernetes 官网维护的 Ingress NGINX Controller

注:安装插件版本时要选择合适的支持版本

  1. 使用 YAML 描述 Ingress/Ingress Class

  2. 执行:kubectl api-resources :查看基本信息

#NAMESPACED这一列代表对象

  • 对象分类:

命名空间级别:true

集群级别:false

#命名空间级别使用时必须要加namespace的属性

#false不受命名空间约,可以在任意命名空间中使用这个对象

  1. 执行:kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.13.1/deploy/static/provider/cloud/deploy.yaml :安装插件

#此处使用的时官方的yaml

  1. 执行:kubectl -n ingress-nginx get pods

# Ingress-nginx-controller 默认会创建到 ingress-nginx 的命名空间中

#以上controller就安装完成了

#controller就是将nginx的配置文件转为可识别的

  1. 执行:kubectl apply -f nginx-conf.yaml -f nginx-dep.yaml

  1. 执行:kubectl apply -f nginx-svc.yaml

  2. 执行:kubectl get svc:进行查看

  • 测试:保证四层畅通

创建一个ingress对象:

  1. kubectl create ingress nginx-ing --rule="nginx.example.com/=nginx-svc:80" --class=nginx --dry-run=client -o yaml

# --rule="nginx.example.com 7层域名入,四层svc : port ingressclass

  1. 执行:kubectl get ingress

#通过查看ingress就创建出来了

通过域名进行访问:nginx.example.com/

#域名要解析到哪个Ip上面

#LB无法使用,使用NodePort

#可以解析到任意节点,在本机的hosts写入域名和ip

#我们可以使用 ClusterIP 或者 NodePort地址 来测试,因为我们的环境里没有LoadBalance,如果是在云上部署,建议使用 LoadBalance。

我们创建的 Ingress rules 是通过域名来访问 ,因此测试时需要修改 hosts 文件

使用 NodePort 地址:http访问

图形用户界面

AI 生成的内容可能不正确。

  • 如何判断请求进入了七层:通过以下日志进行分析

#此选项域名只有解析到本机节点才会通,解析到其他节点不会通

externalTrafficPolicy:Local #只有使用节点上运行了你想访问Pod的节点工上

externalTrafficPolicy: Cluster # NodePort集群中任意节点IP

  • Case 2 HTTPS

图形用户界面, 应用程序

AI 生成的内容可能不正确。

:部署两个应用,客户端外部通过七层访问,使用coffee和tea两个域名对内进行访问,经过ingress转到后方,可以跳到不同的svc上

  • 应用部署

  1. 执行:Kubectl apply -f café-dep.yaml:启动应用

#使用配置好的yaml文件

  1. 执行:Kubectl get pods:进行查看pod应用

截图里有图片

AI 生成的内容可能不正确。

  1. 执行:kubectl get svc:进行查看

屏幕的截图

AI 生成的内容可能不正确。

  • 配置ingress的yaml文件

  1. 执行:kubectl apply -f café-ingress.yaml:创建出ingress

图片包含 图形用户界面

AI 生成的内容可能不正确。

  1. 执行:kubectl get ingress:进行查看

测试访问:

形状, 矩形

AI 生成的内容可能不正确。

#通过域名可以去访问tea

  1. 执行:Kubectl -n ingress-nginx logs -f ingress-nginx-controller-7f7cbcb485-p7qf9

#通过日志查看是否是通过七层进入的

#浏览器请求后可以查看到日志,通过修改路径进行访问

  • 如何让ingress支持https

#需要配置证书和私钥

#在yaml文件里面添加tls属性和select保存证书和私钥

TLS: select

  1. 执行:kubectl create secret tls cafa-secret --cert= cafe.xxhf.cc_bundle.crt

  2. (证书保存位置) --key= cafe.xxhf.cc.key(私钥保存位置):创建出tls类型的select

  3. 执行:kubectl get secrets:进行查看

日程表

AI 生成的内容可能不正确。

#里面的证书和密钥都转为了base64的编码

  1. 执行:vim cafa-ingress-tls.yaml

图片包含 文本

AI 生成的内容可能不正确。

#修改ingress告诉修改了tls地属性,

  1. 执行:kubectl apply -f café-ingress-tls.yaml

执行:Kubectl get ingress:进行查看

#可以看到有了443的加密,支持https

#访问端口进行转变

浏览器进行测试:

图形用户界面

AI 生成的内容可能不正确。

#可以进行正常访问和轮询

#使用loadbalancer可以进行443的重定向跳转

  • 如何直接访问80向443进行跳转

apiserver的启动方式:

hostNetwork: true:可以把容器端口直接映射到宿主机上

#pod属性里面有这个属性就是容器与宿主机不做网络隔离

#不进行隔离就会使用宿主机的80和443。通过这样进行直接访问80向443跳转

  1. 执行:vim ingress-nginx-controller/deploy.yaml

#修改ingress-controller的yaml配置文件

文本

AI 生成的内容可能不正确。

#添加hostNetwork: true的属性,容器的端口直接在宿主机上

#容器很底层属性不能直接修改

#修改后进行查看

  1. 执行:kubectl apply-f ingress-nginx-controller/deploy.yaml:重新生成

  2. 执行:kubectl -n ingress-nginx get pods -wide

电视游戏的萤幕截图

AI 生成的内容可能不正确。

#通过查看被调用到了work-01上面

浏览器测试:

图形用户界面, 应用程序

AI 生成的内容可能不正确。

#有需求可以使用这种方式实现

请求通信:

:使用外网环境域名如何会解析到哪里:最先解析到防火墙的公网IP,通过DNAT进行转换进入集群,指向到ingress-controller的入口,ingress-svc使用的是NodePort,可以指向任意的一个节点,进入集群。为了高可用,在防火墙后面设置负载均衡服务器,请求到vip上后,把流量转发到后面的Node中

#里面会有很多的node节点

日期2025.08.28学习日志

:ingress-controller本质上是一个nginx,可以配置很多参数。写入yaml文件后会被转为nginx的配置。需要修改nginx的参数就需要修改yaml的文件

#这些参数会影响nginx的参数

  • 通过ingress去实现

文本

AI 生成的内容可能不正确。

  • 产生一个select执行以下操作:

  1. annotaion

nginx.ingress.kubernetes.io/affinity: "cookie"

# Annotations - Ingress-Nginx Controller

  1. 创建htpasswd文件

htpasswd -c auth xxhf:生成认证文件

#生成一个文件auth

  1. 创建secret文件

kubectl create secret generic basic-auth --from-file=auth

手机屏幕的截图

AI 生成的内容可能不正确。

#创建后并进行查看

  1. 创建ingress

图形用户界面, 文本, 应用程序

AI 生成的内容可能不正确。

#select里面就保存了我们设置的用户名和密码

  • nginx.ingress.kubernetes.io/auth-type:认证类型,可以是basic和digest。

  • nginx.ingress.kubernetes.io/auth-secret:密码文件的Secret名称。

  • nginx.ingress.kubernetes.io/auth-realm:需要密码认证的消息提醒

  1. 执行:kubectl apply -f auth-ingress.yaml

  2. 执行:kubectl get ingress:进行查看

文本

AI 生成的内容可能不正确。

#需要在hosts文件中配置解析

  1. 测试连接

图形用户界面, 应用程序

AI 生成的内容可能不正确。

  1. 附录:

  • 生产环境 ingrss 入口流量

图示

AI 生成的内容可能不正确。

图表

AI 生成的内容可能不正确。

请求通信:

:使用外网环境域名如何会解析到哪里:最先解析到防火墙的公网IP,通过DNAT进行转换进入集群,指向到ingress-controller的入口,ingress-svc使用的是NodePort,可以指向任意的一个节点,进入集群。为了高可用,在防火墙后面设置负载均衡服务器,请求到vip上后,把流量转发到后面的Node中

#里面会有很多的node节点

Kubernetes 中 ingress 请求入口流量详解: https://mp.weixin.qq.com/s/uyXugwITl6jMcol9Uw6mEg

注:连接中可查看详细讲解

  • 下一代 Ingress -- Gateway API

https://mp.weixin.qq.com/s/-PPIdsSts2TlRzbecPxTHQ

  • 如何部署多个 ingress controller

社区维护:ingress-nginx:

文本

AI 生成的内容可能不正确。

安装Nginx官方ingress controller:

图片包含 文本

AI 生成的内容可能不正确。

Ingress Controller

Kubernetes 社区维护: https://github.com/kubernetes/ingress-nginx

Nginx官方维护: https://docs.nginx.com/nginx-ingress-controller/

Traefik: https://github.com/traefik/traefik

  1. 存储:解决数据持久化问题

  2. 什么是 PersistentVolume

介绍:因为 Pod 里的容器是由镜像产生的,而镜像文件本身是只读的,进程要读写磁盘只能用一个临时的存储空间,一旦 Pod 销毁,临时存储也就会立即回收释放,数据也就丢失了

:为了保证即使 Pod 销毁后重建数据依然存在,我们就需要找出一个解决方案,让 Pod产生的数据可以持久化存储

:在 ConfiMap 的章节用过 Kubernetes 的 Volume ,它只是定义了有这么一个“存储卷”,而这个“存储卷”是什么类型、有多大容量、怎么存储,我们都可以自由发挥。Pod 不需要关心那些专业、复杂的细节,只要设置好 volumeMounts,就可以把 Volume 加载进容器里使用

kubernetes 就顺着 Volume 的概念,延伸出了 PersistentVolume 对象(持久化卷)它专门用来表示持久存储设备,但隐藏了存储的底层实现,我们只需要知道它能安全可靠地保管数据就可以了

:作为存储的抽象,PV 实际上就是一些存储设备、文件系统,比如 Ceph、GlusterFS、MFS、NFS,或是本地磁盘,管理它们已经超出了 Kubernetes 的能力范围,所以,一般会由系统管理员单独维护,然后再在 Kubernetes 里创建对应的 PV

:PV 属于集群的系统资源,是和 Node 平级的一种对象,Pod 对它没有管理权,只有使用权

  • 存储:如何给pod提供持久化的存储

  • 存储设备:磁盘、目录、NFS、MFS、Ceph、JuiceFS

#以上都可以为pod提供存储

  1. 什么是 PersistentVolumeClaim/StorageClass

PersistentVolumeClaim,简称 PVC,从名字上看比较好理解,就是用来向 Kubernetes 申请存储资源的。PVC 是给 Pod 使用的对象,它相当于是 Pod 的代理,代表 Pod 向系统申请 PV。一旦资源申请成功,Kubernetes 就会把 PV 和 PVC 关联在一起,这个动作叫做“绑定”(bound)#声明,更接近用户的需求

存储执行流程:

:应用部署时,提对存储的需求,使用pvc.yaml文件进行描述,k8s集群会根据pvc的声明自动给我们去找pv,找到pvc就会给我们绑定pv。找不到pvc就会进入pending挂起状态。pvc变成一个卷挂载到pod里面

#pv是集群层面的,pvc是命名空间层面的,pod要使用pvc

:系统里的存储资源非常多,如果要 PVC 去直接遍历查找合适的 PV 也很麻烦,所以就要用到 StorageClass

StorageClass 的作用有点像 IngressClass,它抽象了特定类型的存储系统(比如 Ceph、NFS),对pvc进行一个分类在 PVC 和 PV 之间充当“协调人”的角色,帮助 PVC 找到合适的 PV。也就是说它可以简化 Pod 挂载“虚拟盘”的过程,让 Pod 看不到 PV 的实现细节

#对pvc进行一个分类,在哪个类别去找

  1. 使用 YAML 描述 PersistentVolume

#PV 对象只能用 kubectl api-resources、kubectl explain 查看 PV 的字段说明

  • pv描述文件

文本

AI 生成的内容可能不正确。

#如果使用hostpath选项,在pod被调用成功时就会自动创建指定的目录

storageClassName:就是刚才说过的,对存储类型的抽象 StorageClass,名称可以自定义

accessModes:定义了存储设备的访问模式,简单来说就是虚拟盘的读写权限,和 Linux 的文件访问模式差不多

  • accessModes的访问模式:

  • ReadWriteOnce:存储卷可读可写,(读写一次)但只能被一个节点上的 Pod 挂载。 本机存储

  • ReadOnlyMany:存储卷只读不可写,可以被任意节点上的 Pod 多次挂载。

  • ReadWriteMany:存储卷可读可写,(读写多次)也可以被任意节点上的 Pod 多次挂载。 网络存储

  • 在 Kubernetes 里使用 PersistentVolume

#现在我们已经准备好了 PV 和 PVC,就可以让 Pod 实现持久化存储了

  1. 执行:kubectl apply -f host-10m-pv.yaml:启动应用

  2. 执行:kubectl get pv:进行查看

#reclaim policy:回收次数,retain:保留。如果这个pv被删除,这个相对应的目录也要被删除

#claim:pvc绑定的名字

#状态status开始时可以用的,找到pv后就会变为bound

  • 创建pvc

  1. 执行:kubectl apply -f host-10m-pvc.yaml

  1. 执行:kubectl get pvc:进行查看

#一旦 PVC 对象创建成功,Kubernetes 就会立即通过 StorageClass、resources 等条件在集群里查找符合要求的 PV,如果找到合适的存储对象就会把它俩“绑定”在一起

  • 为pod挂载PersistentVolum存储

#先要在 pod的里面spec.volumes 定义存储卷,然后在 containers.volumeMounts 挂载进容器

  1. 执行:kubectl apply -f nginx-dep.yaml :挂载卷

#在pod里面写一个pvc,把pvc变成一个卷。容器使用时用volumeMounts进行挂载

  1. 执行:kubectl get pods -o wide:查看应用备被调用到了哪个节点

#如果使用hostpath选项,在pod被调用成功时就会自动创建指定的目录

测试文件写入:

  1. 执行:kubectl exec -it nginx-dep-5c4fc7b8dc-5f196 -- sh:进入容器

  2. 进入容器进入挂载目录并创建一个文件

worker节点进行查看:

#可以看到创建的文件,目录挂载进去了。pod被删除,容器还在

注:使用hostpath是跟节点进行绑定的,启动的容器被调用到其他节点,会创建一个新的目录,但无法看到之前节点的文件,数据是不同步的。多个副本不建议使用

  1. 使用网络存储方式:(使用NFS)

  • 修复hostpath数据不能同步问题

:要想让存储卷真正能被 Pod 任意挂载,我们需要变更存储的方式,不能限定在本地磁盘,而是要改成网络存储,这样 Pod 无论在哪里运行,只要知道 IP 地址或者域名,就可以通过网络通信访问存储设备

  • 安装 NFS 服务器

注:工作中使用NFS服务器搭建在k8s外面

  1. 执行:dnf install -y nfs-utils #所有节点都要安装

  2. 执行:mkdir /data/nfs:创建一个共享目录

  3. 执行:echo "/data/nfs 192.168.11.0/24(rw,sync,no_subtree_check,no_root_squash,insecure)" >> /etc/exports:修改nfs的配置文件

  4. 执行:systemctl enable --now nfs-server:启动nfs服务

  • 客户端测试目录挂载

  • 如何使用 NFS 存储卷

#nfs搭建好后,可以用它来创建新的pv存储对象

#先来手工分配一个存储卷,需要指定 storageClassName 是 nfs,而 accessModes 可以设置成 ReadWriteMany,这是由 NFS 的特性决定的,它支持多个节点同时访问一个共享目录。

因为这个存储卷是 NFS 系统,所以我们还需要在 YAML 里添加 nfs 字段,指定 NFS 服务器的 IP 地址和共享目录名。

这里我在 NFS 服务器的 /tmp/nfs 目录里又创建了一个新的目录 5g-pv,表示分配了 5GB 的可用存储空间,相应的,PV 里的 capacity 也要设置成同样的数值,也就是 5Gi

  1. 使用yaml文件描述NFS

  2. 执行:kubectl apply -f nfs-static-pv.yml

  1. 执行:kubectl get pv:进行查看

  • 创建pvc

  1. 执行:kubectl apply -f nfs-static-pvc.yaml

#使用 resources.request 来表示希望要有多大的容量,这里我写成 5GB,和 PV 的容量相同:

  • 把 PVC 挂载到 Pod

  1. 执行:kubectl apply -f nginx-dep.yaml

测试数据挂载:

  1. 进入容器中的挂载目录中,创建一个文件

  1. 节点查看

#可以看创建的文件

调整副本数进行查看:

  1. 执行:kubectlscale deployment nginx-dep --replicas 3

#有部分容器调用到了其他节点上面

  1. 执行命令进行查看:

#可以看到文件,通过readwritemany选项,支持被多个容器进行挂载

  1. 如何部署NFS provisioner

:Kubernetes 里就是“动态存储卷”的概念,它可以用 StorageClass 绑定一个 Provisioner 对象,而这个 Provisioner 就是一个能够自动管理存储、创建 PV 的应用,代替了原来系统管理员的手工劳动

:有了“动态存储卷”的概念,前面我们讲的手工创建的 PV 就可以称为“静态存储卷”

:Kubernetes 里每类存储设备都有相应的 Provisioner 对象,对于 NFS 来说,它的 Provisioner 就是“NFS subdir external provisioner”,你可以在 GitHub 上找到这个项目

#只要写pvc的yaml就可以自动创建pv,就需要使用StorageClass,pvc就会绑定StorageClass这个对象

YAML调用关系:

PVC > storageClass YAML > Provisioner提供者(需要安装) > 自动创建PV

注:pv不同Provisioner也不同,要根据pv的类型安装Provisioner

#根据pv的类型部署Provisioner

  • 以NFS为例NFS provisioner

#自动在nfs服务器上创建子目录,一个子目录代表一个pv

  1. nfs服务器已搭建好前提下执行

  2. 在GitHub上下载相关的yaml文件,进行手动部署:执行以下命令

kubectl apply -f 01-rbac.yaml

kubectl apply -f 02-deployment.yaml

#02-deployment.yaml文件中的nfs服务器的IP和共享目录需要修改

#命名空间也可以去手动修改一下

  1. 执行命令查看

  • 如何使用NFS动态存储卷:定义:StorageClass ,写一个yaml

  1. 执行:kubectl apply -f nfs-client-deleted-sc.yaml

#provisioner:StorageClass要去调用provisioner,要知道在哪。可以装多个提供者,要和StorageClass绑定在一起就可以

#parameters属性,参数

#YAML 里的关键字段是 provisioner,它指定了应该使用哪个 Provisioner。另一个字段 parameters 是调节 Provisioner 运行的参数,需要参考文档来确定具体值,在这里的 archiveOnDelete: "false" 就是自动回收存储空间

文本

AI 生成的内容可能不正确。

:理解了 StorageClass 的 YAML 之后,你也可以不使用默认的 StorageClass,而是根据自己的需求,任意定制具有不同存储特性的 StorageClass,比如添加字段 onDelete: "retain" 暂时保留分配的存储,之后再手动删除:

图形用户界面, 文本, 应用程序

AI 生成的内容可能不正确。

  1. 执行:kubectl get sc:进行查看

定义一个pvc:

  1. kubect lapply -f nfs-dynamic-pvc.yaml

形状

AI 生成的内容可能不正确。

#使用的是deleted的class,pvc删除后目录会被删除

  1. 开启一个新的视窗:执行kubectl get pv -w:查看实时创建过程

图形用户界面, 文本

AI 生成的内容可能不正确。

#查看节点创建了一个新的目录

测试删除pvc,pv是否被删除:

  1. kubectl delete -f nfs-dynamic-pvc.yaml

  2. 在调用的节点查看

#创建的目录也被删除

图形用户界面, 文本, 应用程序, 电子邮件

AI 生成的内容可能不正确。