云其它

关注公众号 jb51net

关闭
首页 > 网站技巧 > 服务器 > 云和虚拟化 > 云其它 > k8s配置文件

k8s配置文件用法详解

作者:_BugMan

文章主要介绍了Kubernetes中的命名空间、资源操作、Deployment、Service、Ingress、Secret、PersistentVolumeClaim、StatefulSet等核心概念和配置文件的使用方法

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,实现服务的无中断。可以通过以下两个关键参数来控制更新的节奏和可用性:

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(默认类型):

NodePort:

LoadBalancer:

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  # 请求的存储容量:10GB

pv需要关注的配置

accessModes,访问模式,节点以何种方式(读写或只读)挂载该存储卷。

persistentVolumeReclaimPolicy,回收策略,

pvc需要关注的配置

accessModes

注意: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>

稳定的DNS主机名: 每个 Pod 都会基于其名称和 Headless Service 获得一个唯一的、稳定的 DNS 域名。

这样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出了什么问题。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文