k8s配置文件用法详解
作者:_BugMan
namespace
k8s中有命名空间这个概念,用来做资源隔离,k8s的所有资源操作,诸如get、delete等,都是要跟上-n参数来表示命名空间的,如果没有跟这个参数默认是操作的default这个命名空间。
工程实践一般是测试环境一个namespace,正式环境一个namespace,用来进行隔离避免误操作。
namespace.yaml:
用来创建namespace,创建了后面就能用了。
apiVersion: v1 kind: Namespace metadata: name: db
deployment
部署发布命令:
kubectl apply -f eurekaserver-deployment.yaml
eurekaserver-deployment.yaml:
# 指定使用的Kubernetes API版本,Deployment资源属于apps/v1版本
apiVersion: apps/v1
# 定义资源类型为Deployment,用于部署和管理Pod副本集
kind: Deployment
# 元数据部分,定义Deployment的基本信息
metadata:
# Deployment的名称,在命名空间中必须唯一
name: eurekaserver
# 部署到的命名空间,默认为default
namespace: default
# 标签集合,用于标识和选择此Deployment
labels:
# 应用标识标签
app: eurekaserver
# 环境标识标签
environment: production
# 注解,用于存储非识别性元数据
annotations:
# 描述信息
description: "Deployment for the main eurekaserver web server"
# 规格部分,定义Deployment的期望状态
spec:
# 期望的Pod副本数量
replicas: 1
# Pod就绪后需要等待的秒数才被视为可用
minReadySeconds: 5
# 更新策略配置
strategy:
# 更新类型:RollingUpdate(滚动更新)或Recreate(先删除后创建)
type: RollingUpdate
# 滚动更新具体配置
rollingUpdate:
# 更新过程中可以额外创建的Pod数量(相对于replicas)
maxSurge: 1
# 更新过程中最多允许不可用的Pod数量
maxUnavailable: 0
# 保留的旧ReplicaSet历史记录数量,用于回滚
revisionHistoryLimit: 5
# 标签选择器,定义如何找到由该Deployment管理的Pod
selector:
matchLabels:
# 选择所有拥有app: eurekaserver标签的Pod
app: eurekaserver
# Pod模板,定义Deployment创建的Pod的规格
template:
# Pod的元数据
metadata:
# Pod的标签,必须匹配上面的selector.matchLabels
labels:
app: eurekaserver
environment: production
# Pod的规格
spec:
# 容器列表
containers:
# 第一个容器定义
- name: eurekaserver # 容器名称
image: eurekaserver:1.0 # 容器镜像及标签
imagePullPolicy: IfNotPresent # 镜像拉取策略: Always, IfNotPresent, Never
# 容器暴露的端口列表
ports:
- containerPort: 9001 # 容器内监听的端口
protocol: TCP # 协议类型
# 环境变量列表
env:
- name: ENV_VAR_1 # 环境变量名称
value: "value1" # 环境变量值
# 资源请求和限制
resources:
# 请求的资源量,调度器根据此值决定Pod放在哪个节点
requests:
cpu: "250m" # 250 milliCPU (0.25个CPU核心)
memory: "256Mi" # 256 Mebibytes
# 资源使用上限
limits:
cpu: "500m" # 500 milliCPU (0.5个CPU核心)
memory: "512Mi" # 512 Mebibytes
# 存活性探针,检查容器是否还在正常运行
livenessProbe:
httpGet: # 使用HTTP GET请求进行检查
path: / # 请求的路径
port: 9001 # 请求的端口
initialDelaySeconds: 15 # 容器启动后等待多少秒才开始第一次探测
periodSeconds: 20 # 每次执行探测的间隔时间(秒)
# 就绪性探针,检查容器是否已准备好接收流量
readinessProbe:
httpGet:
path: /
port: 9001
initialDelaySeconds: 5 # 容器启动后等待多少秒才开始第一次探测
periodSeconds: 10 # 每次执行探测的间隔时间(秒)
# Pod内容器的重启策略,对于Deployment只能是Always
restartPolicy: Always
# 收到终止信号后,等待容器正常关闭的优雅时间(秒)
terminationGracePeriodSeconds: 30可以把yaml文件想象成一份工厂的生产订单。
头文件
描述这是什么订单?告诉 Kubernetes 这篇文章(YAML 文件)的类型和格式。
apiVersion: apps/v1 # -> 我们要使用 Kubernetes 的 "apps" 部门的 "v1" 版订单格式。 kind: Deployment # -> 订单的类型:我们要生产的是【一套可复制的应用部署】,而不是单个产品(Pod)或一个服务(Service)。
元数据(metadata)
描述订单的基本信息,定义这个 Deployment 对象的身份信息,比如它叫什么、在哪、有什么标签。
metadata:
name: nginx-deployment # -> 这套部署的名字叫 "nginx-deployment"。这是它的唯一标识,后续操作(如更新、查看)都要用这个名字。
namespace: default # -> 把它部署到名为 "default" 的车间里。如果不指定,就默认放这个车间。
labels: # -> 给这个订单贴上个标签,方便以后筛选和查找。
app: nginx # 例如:贴上一个 "app=nginx" 的标签。
annotations: # -> 给管理员看的备注信息,Kubernetes 本身不使用这些信息来识别对象。
description: "Deployment for the main NGINX web server" # 例如:备注一下这是给主服务器用的。规格(spec)
规格 (Spec),是最核心的部分,它定义了期望的应用状态。
strategy,定义了应用的策略。
spec:
replicas: 3 # -> 我希望任何时候都保持有 3 个完全一样的产品(Pod)在运行。
strategy: # -> 当需要升级产品时,采用以下策略:
type: RollingUpdate # 【滚动更新】:逐台替换,保证服务不中断。而不是【Recreate】:全部停机再更新。
rollingUpdate:
maxSurge: 1 # 更新时,最多允许比 3 台多 1 台(即最多有 4 台在运行)。
maxUnavailable: 0 # 更新时,最多允许 0 台不可用(即必须保证至少有 3 台随时能服务)。
revisionHistoryLimit: 5 # -> 保留 5 份旧的订单记录,方便以后出问题时回退到之前的版本。strategy定义应用的副本数和更新策略,确保高可用和平滑升级。
k8s原生支持两种部署策略:
RollingUpdate,滚动更新,、逐步用新版本的 Pod 替换旧版本的 Pod,实现服务的无中断。可以通过以下两个关键参数来控制更新的节奏和可用性:
- maxUnavailable:指定在更新过程中不可用 Pod 的最大数量或比例。这保证了在更新时至少有一定数量的旧版 Pod 仍能处理请求。
- maxSurge:指定在更新过程中可以创建的超出期望 Pod 数量的最大数量或比例。这允许在删除旧 Pod 的同时提前启动一些新 Pod 以加速更新过程47。
Recreate,先一次性终止所有旧版本的 Pod,等待它们被完全删除后,再启动所有新版本的 Pod,在更新过程中服务会中断一段时间。
Selector ,描述如何找到生产的产品。
selector: # -> 这是我的“产品筛选器”。
matchLabels: # 我管理的所有产品(Pod)都必须贴有下面这个标签。
app: nginx # 标签是 "app=nginx"。Kubernetes 会持续检查,确保所有带这个标签的 Pod 都是 3 个。Selector 建立 Deployment 和它管理的 Pod 之间的关联关系。
template,定义单个 Pod 是什么样子。
Pod 的元数据 (Template Metadata)
template: # -> 以下是一个产品的设计图(Pod 模板)。
metadata:
labels: # -> 【必须】根据这张图生产出的每一个产品,都要贴上这些标签。
app: nginx # 这个标签 `app: nginx` 必须和上面的 selector.matchLabels 完全一致!
environment: production # 还可以贴其他标签,比如标注这是生产环境用的。template为每个Pod定义身份标签。这里的labels必须匹配上面 selector 的选择条件。
Pod 的规格 (Template Spec)
spec: # -> 产品的详细规格。
containers: # -> 这个产品里要安装的【容器】(可以装多个)。
- name: nginx # 第一个容器的名字叫 "nginx"。
image: nginx:1.25.2 # 使用哪个镜像文件来安装这个容器?—— `nginx` 软件的 `1.25.2` 版本。
ports: # 这个容器开放了哪个端口?—— 80 端口。(这主要是说明文档,不影响实际网络)
- containerPort: 80
resources: # -> 【生产环境必填】这个容器最多能占用多少硬件资源?(防止它挤占其他容器的资源)
requests: # 最少需要多少资源才能开机?
cpu: "250m" # 需要 0.25 个 CPU 核心。
memory: "64Mi" # 需要 64MB 内存。
limits: # 运行时最多不能超过多少资源?
cpu: "500m" # 最多能用 0.5 个 CPU 核心。
memory: "128Mi" # 最多能用 128MB 内存。
livenessProbe: # -> 【存活探针】—— 如何检查这个容器是“死”是“活”?如果检查失败,就重启它。
httpGet: # 检查方法:发送一个 HTTP GET 请求。
path: / # 请求的路径是根目录 "/"。
port: 80 # 请求的端口是 80。
initialDelaySeconds: 15 # 容器启动后,等 15 秒再执行第一次检查(给程序启动留出时间)。
readinessProbe: # -> 【就绪探针】—— 如何检查这个容器是否“准备好接待客户”?如果没准备好,就先不让流量进来。
httpGet:
path: /
port: 80
initialDelaySeconds: 5 # 启动后 5 秒开始检查。Template Spec是最核心的配置块,定义了应用本身——它是什么、需要什么资源、如何检查它是否健康。
总结与类比
| 配置块 | 类比 | 作用 |
|---|---|---|
| 文件头 (apiVersion, kind) | 订单部门 | 定义这是一个什么类型的订单(Deployment 订单)。 |
| 元数据 (metadata) | 订单抬头 | 定义订单名称(name)、存放位置(namespace)和标签(labels)。 |
| 副本与策略 (replicas, strategy) | 生产要求 | 要生产多少份(replicas),以及如何更新换代(strategy)。 |
| 标签选择器 (selector) | 产品追踪器 | 定义一个规则,如何找到由这个订单生产的所有产品(Pod)。 |
| Pod 模板 (template) | 产品设计蓝图 | 核心中的核心。定义每一个产品(Pod)的具体规格,包括里面运行什么程序(containers)、需要多少资源(resources)、如何检查质量(probes)。 |
最重要的关系:selector 就像一个追踪器,它说“我要管理所有带 app=nginx 标签的 Pod”。而 template 里定义的 Pod 在出生时就会被贴上 app=nginx 的标签。这样,Deployment 就知道哪些 Pod 是归它管的了。
service
deployment.yaml用来声明配置部署相关的内容,service用来声明配置网络相关的配置:
配置完service的name后,k8s内部的服务之间可以相互通过这个service的name来访问,避免了IP动态变化带来的问题,k8s内部自带一个CoreDNS组件用来解析域名。
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: order-service # Service 的名称,配置名称后可以用配置的名称来访问服务,从而摆脱对IP的强依赖
namespace: default # 可指定命名空间,不指定则默认为 default
spec:
type: NodePort # 服务类型,此处为 NodePort,允许从外部访问
selector: # 标签选择器,用于选择拥有以下标签的 Pod
app: orderserver # 必须与你的 Pod 的标签匹配
ports:
- name: http # 端口名称,可自定义,多端口时必须唯一
protocol: TCP # 协议
port: 80 # Service 自身的端口,在集群内部通过此端口访问
targetPort: 9002 # 目标端口,即 Pod 中容器实际监听的端口(你的应用端口)
# nodePort: 30180 # 可选项:手动指定节点端口。若不指定,Kubernetes 会自动分配一个spec.type,service的类型,包含以下几种:
ClusterIP(默认类型):
- 功能:为Service分配一个仅在集群内部可以访问的虚拟IP地址。
- 用途:用于集群内部的服务间通信。例如,前端Pod需要访问后端的API服务。这是最常用的类型。
NodePort:
- 功能:在
ClusterIP的基础上,在每个Node(节点)上打开一个静态端口(NodePort)。访问任何Node的IP地址的这个NodePort,流量都会被自动转发到该Service,最终到达后端Pod。 - 用途:用于从集群外部直接访问服务。它是实现外部访问的最基础方式。
LoadBalancer:
- 功能:在 NodePort的基础上,利用云服务商(如AWS, GCP, Azure, 阿里云等)的负载均衡器。云商会自动创建一个外部的负载均衡器,并分配一个外部IP地址,所有访问这个外部IP的流量都会均衡到各个节点的NodePort上。
- 用途:在公有云上对外暴露服务的最佳方式,通常需要付费。
k8s对service的访问自带负载均衡的能力:

ingress
pod被分配到的IP地址是k8s集群内部的ip地址,要对外暴露pod需要使用到ingress:

【question】为什么配置service后,还需要扩展组件来对外暴露网络?
【answer】核心组件和概念组件都可以理解为是对k8s内部的,扩展组件才是对外部的,由于k8s是个复杂的集群,需要核心组件来维持集群的内部工作,所以核心组件是不对外的。
由于ingress是扩展组件,需要先下载
Secret
secret用来存Base64编码后的配置,只是对value做一个简单的Base64编码,还是很容易被破解的,只是比明文好些罢了。
secret.yaml:
apiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque data: username: YWxpY2U= # Base64 编码后的值 password: UyFCXKpkJHpEc2I9
PersistentVolumeClaim
持久卷(PersistentVolume),可以理解为k8s对物理机存储的一种抽象,用它来定义物理机上的一块存储。
持久卷声明(PVC,PersistentVolumeClaim),可以理解为应用对要用到的存储的一种声明。
持久卷(PV,PersistentVolume)和持久卷声明(PVC,PersistentVolumeClaim)它们之间的关系可以概括为:PV 是集群中的实际存储资源,由管理员提供;PVC 是用户对存储资源的请求通过 PVC,用户无需关心底层存储细节,Kubernetes 会自动为其绑定合适的 PV。
# ========================
# 持久卷(PV)配置
# ========================
apiVersion: v1 # Kubernetes API版本
kind: PersistentVolume # 资源类型:持久卷
metadata:
name: postgres-pv # 持久卷名称
spec:
capacity:
storage: 10Gi # 存储容量:10GB
accessModes:
- ReadWriteOnce # 访问模式:单节点读写[11](@ref)
persistentVolumeReclaimPolicy: Retain # 回收策略:保留(删除PVC后PV保留)[11](@ref)
storageClassName: "" # 存储类名称(空字符串)
hostPath: # 使用节点本地目录作为存储[11](@ref)
path: /mnt/postgres-data # 节点上的主机路径
---
# ========================
# 持久卷声明(PVC)配置
# ========================
apiVersion: v1 # Kubernetes API版本
kind: PersistentVolumeClaim # 资源类型:持久卷声明
metadata:
name: postgres-pvc # PVC名称
namespace: db # 所属命名空间
spec:
accessModes:
- ReadWriteOnce # 访问模式:单节点读写
resources:
requests:
storage: 10Gi # 请求的存储容量:10GBpv需要关注的配置:
accessModes,访问模式,节点以何种方式(读写或只读)挂载该存储卷。
- ReadWriteOnce (RWO):卷可以被单个节点以读写模式挂载,这是块存储(如 AWS EBS、GCP PD)或本地存储(如
hostPath)的常见模式 - ReadOnlyMany (ROX):卷可以被多个节点以只读模式挂载适用于需要被多个应用实例同时读取的静态数据。
- ReadWriteMany (RWX):卷可以被多个节点以读写模式挂载文件存储(如 NFS、CephFS)通常支持此模式适用于需要跨多个 Pod 共享并写入数据的应用。
persistentVolumeReclaimPolicy,回收策略,
- Retain (保留):保持 PV 和其中的数据不变PV 状态变为
Released,无法被新的 PVC 绑定,需管理员手动清理数据后,才能重新使用这是静态配置 PV(如你的hostPath卷)时常用且安全的策略。 - Delete (删除):自动删除 PV 对象以及后端存储资源此策略通常由动态供应存储的 StorageClass 使用(如云提供商中的存储卷)
- hostPath,物理机上的实际存储路基,
pvc需要关注的配置:
accessModes
- ReadWriteOnce (RWO):卷可以被单个节点以读写模式挂载,这是块存储(如 AWS EBS、GCP PD)或本地存储(如
hostPath)的常见模式 - ReadOnlyMany (ROX):卷可以被多个节点以只读模式挂载适用于需要被多个应用实例同时读取的静态数据。
- ReadWriteMany (RWX):卷可以被多个节点以读写模式挂载文件存储(如 NFS、CephFS)通常支持此模式适用于需要跨多个 Pod 共享并写入数据的应用。
注意:pv和pvc的accessModes必须对齐。
StatefulSet
k8s集群中配置service后,应用之间可以通过service的name来相互访问,从而应对IP动态变化的问题,但是无法解决有状态集群的问题。因为service会结合coreDNS将请求负载均衡的给service下的所有pod,无法区分出各个pod的角色,流量会均分给master和slove。这时候就要用StatefulSet来做pod的状态管理。
StatefulSet可以给pod:
有序创建和命名: StatefulSet 中的 Pod 是按顺序(从 0 到 N-1)创建和扩展的。每个 Pod 会获得一个固定的名称:<statefulset-name>-<ordinal-index>。
- 例如,一个名为
mysql的 StatefulSet 的三个 Pod 将被命名为mysql-0,mysql-1,mysql-2。
稳定的DNS主机名: 每个 Pod 都会基于其名称和 Headless Service 获得一个唯一的、稳定的 DNS 域名。
- 格式:
<pod-name>.<service-name>.<namespace>.svc.cluster.local - 示例:Pod
mysql-0的完整域名为mysql-0.mysql.default.svc.cluster.local。无论这个 Pod 被调度到哪个节点,甚至重启后IP地址变了,这个域名都保持不变,并且总会解析到它当前唯一的 IP 地址。
这样k8s集群中的应用就可以用每个pod自己独特的DNS来访问对应pod了。
Headless Service (无头服务)
StatefulSet必须配合无头服务(Headless Service),它不同于service的其他type,是一个特殊的service它不提供负载均衡,允许直接通过 DNS 发现所有 Pod 的个体地址。
apiVersion: v1
kind: Service
metadata:
name: mysql # 这个名称会被用于Pod的DNS域名
spec:
clusterIP: None # 这就是Headless Service的定义
selector:
app: mysql
ports:
- port: 3306
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: "mysql" # StatefulSet必须通过这个字段知道它属于哪个Headless Service
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
...
volumeClaimTemplates: # 存储卷声明模板
- metadata:
name: data # PVC的名称会是 `data-mysql-0`, `data-mysql-1`, etc.
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "fast-ssd" # 指定存储类,由管理员提供
resources:
requests:
storage: 20Gi如何把master精准的暴露出去:
一个pod可以有多个service,所以为Master Pod创建独立的NodePort Service即可
识别并标记您的Master Pod 首先,确保您的Master Pod有一个唯一标签,以便Service可以精确选中它。通常,StatefulSet中的第一个Pod(如 mysql-0)是主节点。 您可以给它打上一个 role: master 的标签:
kubectl label pod mysql-0 role=master
创建NodePort Service 编写一个YAML文件(例如 mysql-master-svc.yaml),创建一个新的Service,其选择器(selector)精确匹配带有 role=master 标签的Pod。
apiVersion: v1
kind: Service
metadata:
name: mysql-master-external # 这是一个新的、用于外部访问的Service
spec:
type: NodePort # 关键:类型为NodePort,用于对外暴露
selector:
app: mysql # 必须匹配您的Pod标签
role: master # 关键:只选择Master Pod,确保流量不会跑到从节点
ports:
- protocol: TCP
port: 3306 # Service监听的端口
targetPort: 3306 # Pod上的端口
# nodePort: 30000 # 可选:指定一个NodePort端口(范围30000-32767)。不指定则随机分配。应用这个配置:
kubectl apply -f mysql-master-svc.yaml
运维
查看pod的ip:
kubectl get pods -o wide

kubectl get deployment <deployment-name> -n <namespace> -o yaml
查看出了什么问题:
deployment、service这些资源出于pending状态等非running状态一般都是pod启动失败了,这时候要去查看pod出了什么问题。
- running状态的pod可以通过:kubectl logs -f <pod>来查看日志
- 非running状态的pod只能通过:kubectl describe pod -n <namespace> <pod>来查看具体情况
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
