K8S基础概念

  1. 入门操作
    1. 安装
    2. 真机安装
  2. 概念
    1. 功能
    2. Ingress
    3. Endpoint
    4. Yaml文件
    5. K8S组件
    6. K8S对象
      1. 回收机制
      2. K8S API
    7. K8S架构
      1. 节点和控制面之间的通信
      2. 控制器
    8. 容器
      1. 镜像
      2. 容器环境
      3. 容器回调
    9. 工作负载
      1. Pod
        1. pod生命周期
        2. Init容器和Sidecar边车容器
        3. 临时容器
        4. 干扰,QoS类,命名空间 没怎么看,跳过了算是
        5. Downward API
      2. 工作负载管理
        1. Deployments
          1. 更新Deployment
          2. 翻转 滚动更新
          3. 回滚更新
          4. 缩放
          5. 暂停和恢复更新
          6. Deployment状态,清理策略,金丝雀部署,规范 简单过了下
        2. ReplicaSet
          1. 删除相关的过了一下
        3. StatefulSet
        4. DaemonSet
        5. JOB
          1. 外部管理器+Job模板
          2. CronJob
      3. 管理工作负载
      4. 自动扩缩
    10. 服务,负载均衡,联网
      1. Service
      2. Ingress
      3. Service和Ingress
      4. EndpointSlic
      5. DNS
      6. IPV6支持,感知路由,Windows,Cluster IP分配,跳过
      7. 同一Node中Pod的通信
    11. 存储
        1. hostPath 不能迁移到其他Node
        2. emptyDir POD移除时内容消失
      1. 持久卷
        1. 创建PV和PVC,POD申领PVC
        2. 节点亲和性
        3. 阶段
      2. StorageClass
      3. 存储类,PV,PVC,使用存储类进行动态卷制备
      4. 本地存储
      5. 投射卷
        1. Secret
        2. configMap
        3. downwardAPI
    12. 临时卷
    13. 卷属性类,Beta功能跳过
    14. 卷快照,卷快照类,CSI卷克隆,先跳过
  3. 配置
    1. ConfigMap
    2. Secret
    3. 资源
  4. 安全-暂时跳过
  5. 策略
    1. 范围限制 LimitRange
    2. 资源配额
    3. 节点资源管理器
  6. 调度,强占和驱逐
    1. 调度器
    2. 特定节点上运行POD
    3. POD开销
    4. POD调度就绪态
    5. POD拓扑分布约束,内容很多,简单过了下
    6. 污点和容忍度
    7. 调度框架
      1. 调度框架扩展点
    8. 动态资源分配如GPU,跳过
    9. 调度器性能调优
    10. 资源装箱,控制节点资源权重进而控制分数
    11. POD优先级和抢占,通过PriorityClass使高优先级POD驱逐低优先POD
    12. 节点压力驱逐
    13. API发起的驱逐
  7. 集群管理
    1. 节点关闭
    2. Node自动缩容和扩容
    3. 集群网络系统
    4. 日志架构
  • Helm
    1. 功能
    2. Chart
    3. Chart
      1. Chart文件结构
    4. Chart含dependencies的结构
      1. 模板文件和values文件和values.schema.json
      2. crd
    5. chart Hook
      1. 钩子
    6. chart test
    7. 库类型chart
    8. helm来源和完整性
    9. chart仓库,OCI
    10. helm渲染模板和values的合成覆盖流程
    11. 基于角色的访问控制
    12. Helm插件
      1. 惯例
  • 常用命令
    1. 日志查询
    2. 文件同步
  • 入门操作

    安装

    # install helm
    curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
    # install kubectl
    curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
    sudo install kubectl /usr/local/bin/kubectl
    # install minikube
    curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
    sudo install minikube-linux-amd64 /usr/local/bin/minikube && rm minikube-linux-amd64
    
    # start
    minikube start
    # start dashboard
    minikube dashboard
    # forward
    kubectl proxy --address 0.0.0.0 --disable-filter=true
    
    # fast create
    helm create mychart
    # install unstall
    helm install mychart ./mychart
    helm uninstall mychart
    # only render
    helm install --debug --dry-run goodly-guppy ./mychart

    真机安装

    # ubuntu
    swapoff /swap.img
    vim /etc/fstab
    
    sudo apt-get install -y apt-transport-https ca-certificates curl gpg
    curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.34/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
    echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.34/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
    apt-get update
    apt-get install -y kubelet kubeadm kubectl
    apt-mark hold kubelet kubeadm kubectl
    
    sed -i '/^\s*net\.ipv4\.ip_forward/s/^/#/' /etc/sysctl.d/99-sysctl.conf
    sed -i '/^\s*net\.ipv4\.ip_forward/s/^/#/' /etc/sysctl.conf
    cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
    br_netfilter
    EOF
    cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
    net.bridge.bridge-nf-call-ip6tables = 1
    net.bridge.bridge-nf-call-iptables = 1
    net.ipv4.ip_forward = 1
    EOF
    modprobe br_netfilter
    sysctl --system
    
    apt update
    apt install -y containerd
    mkdir -p /etc/containerd
    containerd config default | sudo tee /etc/containerd/config.toml
    sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
    systemctl restart containerd
    systemctl enable containerd
    
    kubeadm init --pod-network-cidr=192.168.0.0/16
    
    
    mkdir -p $HOME/.kube
    cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    
    kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.0/manifests/calico.yaml
    
    kubectl taint node master node-role.kubernetes.io/control-plane-
    # /etc/crictl.yaml
    runtime-endpoint: unix:///run/containerd/containerd.sock
    image-endpoint: unix:///run/containerd/containerd.sock

    概念

    文档

    文档

    功能

    1. 服务发现和负载均衡: Kubernetes可以通过DNS名称或IP地址暴露容器,并自动进行负载均衡,确保流量均匀分配,保持部署稳定。
    2. 存储编排: Kubernetes支持自动挂载各种存储系统,如本地存储和公共云存储,简化存储管理。
    3. 自动部署和回滚: Kubernetes允许描述容器的期望状态,并自动调整实际状态以匹配期望状态,支持自动化部署和回滚。
    4. 自动完成装箱计算: Kubernetes根据容器的CPU和内存需求,智能调度容器到集群中的节点,优化资源利用。
    5. 自我修复: Kubernetes会自动重启失败的容器、替换不健康的容器,并在服务准备好之前不将其通告给客户端。
    6. 密钥与配置管理: Kubernetes可以安全地存储和管理敏感信息,如密码和密钥,支持在不重建镜像的情况下更新配置。
    7. 批处理执行: Kubernetes不仅管理服务,还支持批处理和CI工作负载,自动替换失败的容器。
    8. 水平扩缩: Kubernetes支持通过简单命令、用户界面或根据CPU使用率自动扩缩应用。
    9. IPv4/IPv6双栈: Kubernetes为Pod和Service分配IPv4和IPv6地址,支持双栈网络。
    10. 为可扩展性设计: Kubernetes允许在不改变上游源代码的情况下添加功能,支持集群的可扩展性。

    Ingress

    控制Web流量达到工作负载,可以当做集群入口点。

    Endpoint

    云原生服务发现

    Yaml文件

    使用yaml定义一个pod,此时不会被Deployment控制器所管理,出现问题后不会重新创建。

    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
    spec:
      containers:
      - name: my-container
        image: my-image:latest
        ports:
        - containerPort: 80

    使用yaml定义一个Deployment,当pod崩溃或者被删除时,会自动创建来保证存在指定数量的pod。

    apiVersion: apps/v1
    kind: Deployment # 这里不一样
    metadata:
      name: my-deployment
    spec:
      replicas: 3 # Pod副本数量
      selector:
        matchLabels:
          app: my-app # 要与template.metadata.labels匹配,保证Deployment创建的pod能被正确管理。
      template:
        metadata:
          labels:
            app: my-app
        spec:
          containers:
          - name: my-container
            image: my-image:latest
            ports:
            - containerPort: 80

    K8S组件

    Node:工作机器
    Container:容器
    Pod:部署单元,一个应用可能有多个部署单元,一个部署单元可能包含一个或多个容器,容器共享相同的网络和存储单元。先有的部署单元,部署单元需要创建容器,容器位于节点上。一个Node上不同的Container之间怎么做的共享和隔离?
    Deployment:应用控制器,检测Pod的运行创建,出问题时自动创建。

    K8S集群由控制平面和一个或多个工作节点组成。

    1. 控制平面组件:管理集群的整体状态,负责资源调度,检测和响应集群事件
      1. kube-apiserver:公开 Kubernetes HTTP API 的核心组件服务器
      2. etcd:一致性和高可用的键值存储,用于API服务器的数据存储
      3. kube-scheduler:监听新创建的未指定运行Node的Pods,将Pod分配给合适的Node。资源需求,软硬件,策略约束,亲和,反亲和,数据位置,工作覆盖干扰,最后时限。东西还挺多,每个感觉都能看看
      4. kube-controller-manager:运行控制器来实现 Kubernetes API 行为。(不太懂
        1. Node控制器,在节点出现故障时进行响应
        2. Job控制器,啥玩意
        3. EndpointSlice控制器,填充EndpointSlice对象,提供Service和Pod之间的链接。
        4. ServiceAccount控制器,啥玩意
    2. Node 组件:运行在节点上,维护pod并提供k8s运行时环境
      1. kubelet:确保pod及其容器正常运行。保证容器都运行在pod中,啥玩意
      2. kube-proxy:维护节点网络规则来实现service功能,(Kubernetes中Service是将运行在一个或一组Pod上的应用可被客户端访问,Service提供一个虚拟的IP地址和端口,以及选择器selector如k8s-app: kube-dns带有此标签的服务A会被注册到这个Service实现转发的作用)。
    3. 插件
      1. DNS
      2. Web界面
      3. 容器资源监控
      4. 日志

    K8S对象

    描述了K8S中的一个实体,对应一个yaml文件。其中描述了实体的名称,期望状态等内容。

    对象管理

    • 指令式命令kubectl create deployment nginx --image nginx
    • 指令式对象配置:指定一个对象 kubectl create -f nginx.yaml
    • 声明式对象配置:制定目录

    Name定义了一个对象名,对应的实体使用UID标识。对象删除重建后,对象名不变,应用名会变。

    label标签,可以通过标签进行选择和过滤操作。"metadata": { "labels": {"K1": "value"} }

    annotations注解,用于存储非标识数据,不用于选择和过滤附加信息,"metadata": { "annotations": {"K1": "value"} }

    namespace,将同一集群中的资源划分为互相隔离的组,供不同用户来使用。

    回收机制

    pods的管理和回收机制,Finalizers,属主,附属

    K8S API

    K8S使用API查询和操纵其中对象的状态,kubectl这类命令行工具也是在调用API。kubectl获取并缓存API规范实现命令行补全

    两个机制,发现API,OpenAPI文档

    K8S架构

    节点和控制面之间的通信

    节点的API调用终止于API服务器

    API服务器到各个节点上的kubelet进程存在连接,作用:获取pod日志,挂接?,端口转发。

    控制器

    对象中存在spec字段,表示对象期望达到的状态,控制器负责确保其当前状态接近于期望状态。

    容器

    镜像

    Kubernetes 可以使用的一些镜像名称示例包括:

    名字 说明
    busybox 仅包含镜像名称,没有标签或摘要,Kubernetes 将使用 Docker 公共镜像仓库和 latest 标签。 (例如 docker.io/library/busybox:latest)
    busybox:1.32.0 带标签的镜像名称,Kubernetes 将使用 Docker 公共镜像仓库。 (例如 docker.io/library/busybox:1.32.0)
    registry.k8s.io/pause:latest 带有自定义镜像仓库和 latest 标签的镜像名称。
    registry.k8s.io/pause:3.5 带有自定义镜像仓库和非 latest 标签的镜像名称。
    registry.k8s.io/pause@sha256:1ff6c18fbef2045af6b9c16bf034cc421a29027b800e4f9b68ae9b1cb3e9ae07 带摘要的镜像名称。
    registry.k8s.io/pause:3.5@sha256:1ff6c18fbef2045af6b9c16bf034cc421a29027b800e4f9b68ae9b1cb3e9ae07 带有标签和摘要的镜像名称,镜像拉取仅参考摘要。

    镜像拉取策略imagePullPolicy

    • IfNotPresent:本地不存在才拉取(未指定且使用非latest标签时的默认项)
    • Always:查询镜像摘要,如果本地不存在对应摘要则拉取,存在并不会拉取。(未指定且使用latest标签时的默认项)(未指定且无标签时的默认项)
    • Never:只使用本地

    策略在对象初次创建时设置,此后更新Deployment的镜像标签时,拉取策略不会发生变化。

    容器环境

    pod中定义的环境变量可在容器中使用

    Foo服务器的环境变量,用于访问FOO服务器

    FOO_SERVICE_HOST=主机
    FOO_SERVICE_PORT=端口

    DNS插件

    容器回调

    回调:无参数,执行失败会杀掉容器

    • PostStart:容器创建之后被立即执行。执行时间过长或挂起,可能容器无法进入running状态。失败会发出FailedPostStartHook事件。

    • PreStop:容器被终止前调用。需要在限定时间内执行完成,时间一到即刻上路。失败会发出FailedPreStopHook事件。

    注册方式(执行方式)

    Exec,执行命令,HTTP,Sleep

    kubectl describe pod lifecycle-demo

    工作负载

    工作负载是运行程序,pod是一组运行状态的容器集合。一般不会直接管理pod,而是通过工作负载配置+控制器,自动管理pod

    工作负载配置类型

    • Deployment,ReplicaSet:管理无状态应用,pod都是等价的
    • StatefulSet:部署有状态服务,将Pod与PersistentVolume对应起来。可以将数据复制到同一StatefulSet中其他Pod来提高整体服务的可靠性,怎么复制?
    • DaemonSet:基础负载,添加新Node时,会自动在新Node部署一个pod
    • Job:定义一直运行到结束并停止的任务,CronJob:根据排期表,多次运行同一个job
    • 定制:CRD。如果你希望运行一组 Pod,但要求所有 Pod 都可用时才执行操作 (比如针对某种高吞吐量的分布式任务),你可以基于定制资源实现一个能够满足这一需求的扩展, 并将其安装到集群中运行。怎么定义感觉可以看看,CRD这个东西

    Pod

    pod生命周期

    Pod:定义的一个逻辑主机,容器的运行时环境,包含一个或多个应用容器,容器对应的紧密耦合在一起(共享网络(可以通过localhost通信)和存储(共享内存也行?))。Pod 类似于共享名字空间并共享文件系统卷的一组容器。

    除了应用容器:pod还可以在Pod启动期间运行init容器,还可以注入临时性容器来调试正在运行的pod。

    直接创建POD,不推荐:kubectl apply -f https://k8s.io/examples/pods/simple-pod.yaml

    POD名称DNS子域值(这是啥?)DNS标签规则

    livenessProbe:容器存活探针
    readinessProbe:就绪探针,探测失败时从Server/Endpoint/负责均衡中摘除,不分配流量。
    startupProbe:启动检测探针。容器启动时间过长时,会被上面两个探针误伤。当启用了启动检查探针时,存活和就绪探针将会在启动检查探针检测成功后启用。

    Pod.status.phase整体POD生命周期:起始于Pending,至少有一个主要容器正常启动后进入Running,之后有容器失败进入failed,没有则进入Succeeded。

    Pending:Pod被保存到了Etcd中,但是Pod中的容器不能被顺利创建
    Running:Pod已经创建成功,和Node进行绑定。所有容器都创建成功,至少有一个正在运行中
    Succeeded:所有容器正常运行完毕,并且退出了。常见于运行一次性任务。
    Failed:至少有一个容器以非0错误码退出
    Unknown:通信出现问题

    Pod.status.conditionsPOD健康条件:展示pod关键阶段和健康性。
    Ready:所有容器已经就绪,可以对外提供服务
    ContainersReady:所有业务容器就绪(不含init容器)
    PodScheduled:是否被调度到某一个Node上

    Pod.status.containerStatuses.state单个容器状态:直观展示容器的状态,不同于phase。waiting等待需要结合reason查看,running,反复启动失败可能会有CrashLoopBackOff,被删除会有Terminating
    livenessProbe失败会导致state切换到Terminated,之后按照restartPolicy处理。

    绑定:pod分配到特定节点

    调度:选择使用哪个节点

    kubectl describe pod <pod 名称>:查看pod的状态和时间

    kubectl logs <pod名称>: 查看pod的日志

    Init容器和Sidecar边车容器

    Init按顺序执行完毕之后退出,应用容器才会运行

    应用

    1. 运行shell检查并等待一个Service完成创建(Init运行结束之后,应用容器才会运行)
    2. curl注册POD到远程服务器
    3. sleep应用容器启动之前,等待一段时间。
    4. 克隆git仓库到卷(后面会有一大章节介绍)
    5. 渲染配置文件的模板,如模板需要POD的ip
    apiVersion: v1
    kind: Pod
    metadata:
      name: myapp-pod
      labels:
        app.kubernetes.io/name: MyApp
    spec:
      containers:
      - name: myapp-container
        image: busybox:1.28
        command: ['sh', '-c', 'echo The app is running! && sleep 3600']
      initContainers:
      - name: init-myservice
        image: busybox:1.28
        command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
      - name: init-mydb
        image: busybox:1.28
        # 指定成Always会变成边车容器
        restartPolicy: Always
        command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
    # 启动
    kubectl apply -f myapp.yaml
    # 检查状态
    kubectl get -f myapp.yaml
    # 查看pod内Init容器的日志
    kubectl logs myapp-pod -c init-myservice

    pod重启,init容器必须重新执行

    Init容器的restartPolicy设置成Always,就会在pod生命周期内持续运行

    临时容器

    Pod是一次性可替换的,一旦创建完成,无法添加新的容器到其中。

    缺少对资源或者执行的保证,永远不会自动重启,不用于构建应用程序,没有端口配置,临时容器被添加到pod后,不能更改或删除临时容器。

    干扰,QoS类,命名空间 没怎么看,跳过了算是

    Downward API

    将pod和容器字段暴露给运行中的容器

    1. 作为环境变量
    2. 作为downwardAPI卷中的文件

    工作负载管理

    Deployments:封装的ReplicaSet,提供了更新、回滚、恢复和暂停等能力。更新时创建新的RS用其中的POD逐步替换旧RS的POD。修改模板之后直接使用apply应用,会触发自动应用

    ReplicaSet:提供了维持POD数量的能力,修改POD模板之后需要删除旧POD才能触发新POD创建。

    StatefulSet:比起Deployments为它们的每个Pod维护了一个有粘性的永远不变的ID。

    Deployments vs StatefulSet

    身份标识

    • Deployments的POD名称随机生成(nginx-deploy-5d5b64cf8-xj7pw),重启后变化。无固定网络标识,IP动态分配,服务依赖Service负载均衡
    • StatefulSete的POD名称固定(mysql-0,mysql-1),重建后保持不变。提供稳定的DNS名称(<pod-name>.<svc-name>.namespace.svc.cluster.local)

    存储管理

    • Deployments默认使用临时存储(emptyDir),POD删除后数据丢失,持久化需要手动配置PVC,无法绑定到特定POD。
    • StatefulSet为每个POD绑定独立PVC,与POD生命周期解耦

    生命周期管理

    操作 Deployment StatefulSet
    启动/停止顺序 并行创建/删除,无顺序要求 严格按序号顺序(如先启动 web-0,再 web-1
    滚动更新 无序更新,支持多 Pod 同时替换 逆序更新(从最高序号 Pod 开始逐个更新)
    扩缩容 随机创建/删除 Pod 扩容:顺序新增 Pod(如新增 web-2); 缩容:逆序删除(先删 web-2

    Deployments

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment # 命名
      labels: # Deployment的标签
        app: nginx
    spec:
      replicas: 3 # 创建一个ReplicaSet,标明pod副本数量
      selector: # 定义ReplicaSet会管理所有带有后面标签的pod。如果先前通过其他方式创建过带有此标签的pod,且pod符合后面image和port的定义,也会被同时管理,不过此时相关NAME可能规范不同(如没有相关的HASH或者前缀)不建议这样做。假定你在ReplicaSet已经被部署之后创建Pod,并且你已经在ReplicaSet中设置了其初始的Pod副本数以满足其副本计数需要,新的Pod会被该ReplicaSet获取,并立即被ReplicaSet终止, 因为它们的存在会使得ReplicaSet中Pod个数超出其期望值。
        matchLabels:
          app: nginx
      template:
        metadata:
          labels: # 在模板中定义标签,这个是pod的标签
            app: nginx
        spec: 指定运行一个nginx容器并命名为nginx
          containers:
          - name: nginx
            image: nginx:1.14.2
            ports:
            - containerPort: 80

    kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml

    kubectl get deployments
    
    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment   0/3     0            0           1s
    • NAME: Deployment名称
    • READY:就绪个数/期望个数
    • UP-TO-DATE:为了达到期望状态已经更新的副本数
    • AVAILABLE:可用用户使用的副本数
    • AGE:运行时间
    kubectl get rs
    
    NAME                          DESIRED   CURRENT   READY   AGE
    nginx-deployment-75675f5897   3         3         3       18s
    • NAME: ReplicaSet名称,75675f5897是哈希,由Deployment名称-哈希组合而成
    • DESIRED:期望副本数
    • CURRENT:实际副本数
    • READY:可以为用户提供服务的副本数
    • AGE:显示应用运行时间的长度
    kubectl get pods --show-labels
    
    NAME                                READY     STATUS    RESTARTS   AGE       LABELS
    nginx-deployment-75675f5897-7ci7o   1/1       Running   0          18s       app=nginx,pod-template-hash=75675f5897
    nginx-deployment-75675f5897-kzszj   1/1       Running   0          18s       app=nginx,pod-template-hash=75675f5897
    nginx-deployment-75675f5897-qqcnn   1/1       Running   0          18s       app=nginx,pod-template-hash=75675f5897

    NAME:Pod名称,ReplicaSet名称-哈希

    Deployment控制器将pod-template-hash标签添加到Deployment所创建或收留的每个ReplicaSet此标签可确保Deployment的子ReplicaSet不重叠。标签是通过对ReplicaSet的PodTemplate进行哈希处理。所生成的哈希值被添加到ReplicaSet选择算符、Pod模板标签,并存在于在ReplicaSet可能拥有的任何现有Pod中

    更新Deployment

    kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1

    kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1

    kubectl edit deployment/nginx-deployment

    查看上线状态

    kubectl rollout status deployment/nginx-deployment

    kubectl get rs
    NAME                          DESIRED   CURRENT   READY   AGE
    nginx-deployment-1564180365   3         3         3       6s    这个是新的RS,已经创建完毕
    nginx-deployment-2035384211   0         0         0       36s   这个是旧的,已经全部归0
    翻转 滚动更新
    kubectl describe deployments nginx-deployment
    
    Normal  ScalingReplicaSet  2m    deployment-controller  Scaled up replica set nginx-deployment-2035384211 to 3  # 旧的创建到3个
    Normal  ScalingReplicaSet  24s   deployment-controller  Scaled up replica set nginx-deployment-1564180365 to 1  # 新的先创建1个
    Normal  ScalingReplicaSet  22s   deployment-controller  Scaled down replica set nginx-deployment-2035384211 to 2 # 旧的缩容到2个
    Normal  ScalingReplicaSet  22s   deployment-controller  Scaled up replica set nginx-deployment-1564180365 to 2 # 新的扩容到2个
    Normal  ScalingReplicaSet  19s   deployment-controller  Scaled down replica set nginx-deployment-2035384211 to 1 # 旧的缩容到1个
    Normal  ScalingReplicaSet  19s   deployment-controller  Scaled up replica set nginx-deployment-1564180365 to 3
    Normal  ScalingReplicaSet  14s   deployment-controller  Scaled down replica set nginx-deployment-2035384211 to 0

    更新了Deployment,控制标签匹配.sepc.selector, 模板不匹配.sepc.template。会进行缩容和扩容进行更新

    回滚更新

    检查上线状态

    kubectl rollout status deployment/nginx-deployment
    
    Waiting for rollout to finish: 1 out of 3 new replicas have been updated...

    获取rs信息

    kubectl get rs
    
    NAME                          DESIRED   CURRENT   READY   AGE
    nginx-deployment-1564180365   3         3         3       25s
    nginx-deployment-2035384211   0         0         0       36s
    nginx-deployment-3066724191   1         1         0       6s

    获取pod信息

    kubectl get pods
    
    NAME                                READY     STATUS             RESTARTS   AGE
    nginx-deployment-1564180365-70iae   1/1       Running            0          25s
    nginx-deployment-1564180365-jbqqo   1/1       Running            0          25s
    nginx-deployment-1564180365-hysrc   1/1       Running            0          25s
    nginx-deployment-3066724191-08mng   0/1       ImagePullBackOff   0          6s  # 新的RS中的新的POD卡在镜像拉取

    检查上线历史

    kubectl rollout history deployment/nginx-deployment
    
    deployments "nginx-deployment"
    REVISION    CHANGE-CAUSE
    1           kubectl apply --filename=https://k8s.io/examples/controllers/nginx-deployment.yaml
    2           kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
    3           kubectl set image deployment/nginx-deployment nginx=nginx:1.161

    查看修订历史的详细信息

    kubectl rollout history deployment/nginx-deployment --revision=2
    
    deployments "nginx-deployment" revision 2
      Labels:       app=nginx
              pod-template-hash=1159050644
      Annotations:  kubernetes.io/change-cause=kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
      Containers:
       nginx:
        Image:      nginx:1.16.1
        Port:       80/TCP
         QoS Tier:
            cpu:      BestEffort
            memory:   BestEffort
        Environment Variables:      <none>
      No volumes

    撤销当前上线,回滚到上一个版本
    kubectl rollout undo deployment/nginx-deployment

    回滚到指定的版本
    kubectl rollout undo deployment/nginx-deployment –to-revision=2

    缩放

    kubectl scale deployment/nginx-deployment –replicas=10

    暂停和恢复更新

    kubectl rollout pause deployment/nginx-deployment

    kubectl rollout resume deployment/nginx-deployment

    监视上线状态

    kubectl get rs –watch

    Deployment状态,清理策略,金丝雀部署,规范 简单过了下

    ReplicaSet

    维持在任何给定时间运行的一组稳定的设置数量且完全相同的副本Pod,通常用Deployment来自动管理

    会在pod上添加metadata.ownerReferences字段,来标注属于哪个ReplicaSet。如果POD上没有ownerReference或者其ownerReference不是一个控制器,匹配到某ReplicaSet的选择运算符,则该pod会被RS获得。

    apiVersion: apps/v1
    kind: ReplicaSet
    metadata:
      name: frontend
      labels:
        app: guestbook
        tier: frontend
    spec:
      # 按你的实际情况修改副本数
      replicas: 3
      selector:
        matchLabels:
          tier: frontend
      template:
        metadata:
          labels:
            tier: frontend
        spec:
          containers:
          - name: php-redis
            image: us-docker.pkg.dev/google-samples/containers/gke/gb-frontend:v5

    除了kind字段和Deployment章节的例子几乎完全一样,但是指定成ReplicaSet后,会失去Deployment的自动扩容和回滚等功能。ReplicaSet主要用于保证指定数量的pod副本运行。

    kubectl apply -f https://kubernetes.io/examples/controllers/frontend.yaml
    
    kubectl get rs
    NAME       DESIRED   CURRENT   READY   AGE
    frontend   3         3         3       6s
    
    kubectl describe rs/frontend
    
    kubectl get pods
    NAME             READY   STATUS    RESTARTS   AGE
    frontend-gbgfx   1/1     Running   0          10m
    frontend-rwz57   1/1     Running   0          10m
    frontend-wkl7w   1/1     Running   0          10m

    可以看到pods的命名里少了一节Deployment中RS的段,因为kind:ReplicaSet模式下定义的name直接就是RS的,而不是定义的Deployment,由Deployment来创建RS。

    假定你在ReplicaSet已经被部署之后创建Pod,并且你已经在ReplicaSet中设置了其初始的Pod副本数以满足其副本计数需要,新的Pod会被该ReplicaSet 获取,并立即被ReplicaSet终止, 因为它们的存在会使得ReplicaSet中Pod个数超出其期望值。

    删除相关的过了一下

    StatefulSet

    当个Web-0的phase进入Running,Condition变成Ready前,Web-0一直是Pending状态。

    和Deployment不同的是,StatefulSet为它们的每个Pod维护了一个有粘性的永远不变的ID。使用存储卷,这个存储卷是啥?

    • 稳定的、唯一的网络标识符。
    • 稳定的、持久的存储。
    • 有序的、优雅的部署和扩缩。
    • 有序的、自动的滚动更新。

    给定Pod的存储必须由PersistentVolume Provisioner基于所请求的storage class来制备,或者由管理员预先制备。删除或者扩缩StatefulSet并不会删除它关联的存储卷。这样做是为了保证数据安全,它通常比自动清除StatefulSet所有相关的资源更有价值。

    apiVersion: v1
    kind: Service
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      ports:
      - port: 80
        name: web
      clusterIP: None
      selector:
        app: nginx
    ---
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: web
    spec:
      selector:
        matchLabels:
          app: nginx # 必须匹配 .spec.template.metadata.labels
      serviceName: "nginx"
      replicas: 3 # 默认值是 1
      updateStrategy: RollingUpdate # 默认的滚动更新   OnDelete手动删除pod后控制器才会创建新的pod,这时才能响应.sepc.template的变动
      minReadySeconds: 10 # 默认值是 0
      template:
        metadata:
          labels:
            app: nginx # 必须匹配 .spec.selector.matchLabels
        spec:
          terminationGracePeriodSeconds: 10
          containers:
          - name: nginx
            image: registry.k8s.io/nginx-slim:0.24
            ports:
            - containerPort: 80
              name: web
            volumeMounts:
            - name: www
              mountPath: /usr/share/nginx/html
      volumeClaimTemplates: # 这个字段是创建PersistentVolumeClaim, PersistentVolume制备和PersistentVolumes是啥?卷相关的还比较多,后面有单独的章节,不急。
      - metadata:
          name: www
        spec:
          accessModes: [ "ReadWriteOnce" ]
          storageClassName: "my-storage-class"
          resources:
            requests:
              storage: 1Gi
    集群域名 服务(名字空间/名字) StatefulSet(名字空间/名字) StatefulSet 域名 Pod DNS Pod 主机名
    cluster.local default/nginx default/web nginx.default.svc.cluster.local web-{0..N-1}.nginx.default.svc.cluster.local web-{0..N-1}
    cluster.local foo/nginx foo/web nginx.foo.svc.cluster.local web-{0..N-1}.nginx.foo.svc.cluster.local web-{0..N-1}

    web-{0..N-1}扩容按顺序进行。缩容会逆序执行。当前执行完毕之后,才会处理下一个。

    按照与Pod终止相同的顺序,Kubernetes控制平面会等到被更新的Pod进入Running和Ready状态,然后再更新其前身。如果有minReadySeconds则还会进行额外等待。

    分区滚动更新

    .spec.updateStrategy.rollingUpdate.partition

    当StatefulSet的.spec.template被更新时,所有序号大于等于该分区序号的Pod都会被更新。所有序号小于该分区序号的Pod都不会被更新,并且即使它们被删除也会依据之前的版本进行重建。如果StatefulSet的.spec.updateStrategy.rollingUpdate.partition大于.spec.replicas,则对它的.spec.template的更新将不会传递到它的Pod。

    这里还是实操一下比较好

    稳定的存储 PersistentVolumeClaim保留

    对于StatefulSet中定义的每个VolumeClaimTemplate,每个Pod会收到基于storage class: my-storage-class分配的1GiB的PersistentVolume。当pod被调度(重新调度)到节点时,volumeMounts会挂载与PersistentVolumeClaim关联的PersistentVolume。pod或StatefulSet被删除时,与PersistentVolumeClaim关联的PersistentVolume不会被一起自动删除,只能手动删除。

    .spec.persistentVolumeClaimRetentionPolicy可以控制是否保留等,简单过了下,默认都是保留。

    StatefulSet的.spec.volumeClaimTemplates会自动创建PVC,而POD就有的.spec.volumes需要指定已经创建好的PVC

    # pv
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: nginx-pv
    spec:
      capacity:
        storage: 1Gi
      accessModes:
        - ReadWriteOnce
      persistentVolumeReclaimPolicy: Retain
      hostPath:
        path: /mnt/data
    
    # pvc  POD需要创建好的PVC
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: nginx-pvc
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 1Gi

    DaemonSet

    提供节点本地设施,新Node加入时会自动部署对应的pod。

    • 节点上运行集群守护进程
    • 节点上

    JOB

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: pi
    spec:
      # 这里没有selector了
      template:
        spec:
          containers:
          - name: pi
            image: resouer/ubuntu-bc 
            command: ["sh", "-c", "echo 'scale=10000; 4*a(1)' | bc -l "]
          restartPolicy: Never # 只能是Never或者OnFailure
      backoffLimit: 4 # 默认是6

    当restartPolicy指定Never时,会不断创建新的POD,间隔(10S,20S,40S,80S)重试4次。
    指定OnFailure时,会不断重启现有的容器,不会创建新的

    可以控制并行进行

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: pi
    spec:
      parallelism: 2 # 最大并行数量
      completions: 4 # 最小完成数量
      template:
        spec:
          containers:
          - name: pi
            image: resouer/ubuntu-bc
            command: ["sh", "-c", "echo 'scale=5000; 4*a(1)' | bc -l "]
          restartPolicy: Never
      backoffLimit: 4
    外部管理器+Job模板
    apiVersion: batch/v1
    kind: Job
    metadata:
      name: process-item-$ITEM
      labels:
        jobgroup: jobexample
    spec:
      template:
        metadata:
          name: jobexample
          labels:
            jobgroup: jobexample
        spec:
          containers:
          - name: c
            image: busybox
            command: ["sh", "-c", "echo Processing item $ITEM && sleep 5"]
          restartPolicy: Never

    使用工具对$ITEM进行替换后执行
    KubeFlow使用的这种方式

    拥有固定任务数目的并行 Job。没太看懂

    指定并行度(parallelism),但不设置固定的 completions 的值。

    CronJob
    apiVersion: batch/v1beta1
    kind: CronJob
    metadata:
      name: hello
    spec:
      schedule: "*/1 * * * *"
      jobTemplate:
        spec:
          template:
            spec:
              containers:
              - name: hello
                image: busybox
                args:
                - /bin/sh
                - -c
                - date; echo Hello from the Kubernetes cluster
              restartPolicy: OnFailure

    像是Deploymet管理RS。Cronjob管理job

    spec.concurrencyPolicy,控制上一个Job未完成的时候,新Job开始时的动作

    1. concurrencyPolicy=Allow,默认,Job 可以同时存在;
    2. concurrencyPolicy=Forbid,不会创建新的 Pod,该创建周期被跳过;
    3. concurrencyPolicy=Replace,新产生的 Job 会替换旧的、没有执行完的 Job。

    一次Job失败miss+1,当miss达到100就会停止创建Job。统计时间段可以由startingDeadlineSeconds指定。

    管理工作负载

    —可以分割多个负载放入一个文件中。

    自动扩缩

    水平扩缩:运行多个实例,通过HPA实现。垂直扩缩:调整容器的CPU和内存资源、VPA不过是插件形式。

    服务,负载均衡,联网

    POD会获得此集群下的一个唯一IP,POD内部容器可以通过localhost通信, POD之间可以相互通信。

    ServiceAPI可以为一个或多个后端POD提供一个稳定的IP地址或主机名。K8S自动管理EndpointSlice对象,提供Service的POD信息。服务代理实现通过操作系统或云平台API来拦截或重写数据包,监视Service和EndpointSlice对象集,在数据平面编程将服务流量路由到其后端。

    Gateway API(前身是Ingress):使得集群外能够访问Service

    NetworkPolic:控制POD之间的流量,POD和外部的流量

    Service

    apiVersion: v1
    kind: Service
    metadata:
      name: my-service
    spec:
      selector:
        app: my-app
      ports:
        - name: http
          protocol: TCP
          port: 80
          targetPort: 8080
      type: ClusterIP

    对集群中其他服务暴露80端口,转到selector筛选后pod的端口8080。K8S会为Service分配一个集群IP。

    Pod的定义

    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx
      labels:
        app.kubernetes.io/name: nginx-proxy
    spec:
      containers:
      - name: nginx
        image: nginx:stable
        ports:
          - containerPort: 80
            name: http-web-svc # 这里给80端口起了一个名字

    ClusterIP

    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-cluster
    spec:
      type: ClusterIP # ClusterIP是默认值,只能在集群内访问,可以使用Ingress或者GatewayAPI向外暴露服务。NodePort:通过Node上的IP和端口公开。ExternalName:映射到主机名
      selector:
        app.kubernetes.io/name: nginx-proxy
      ports:
      - name: name-of-service-port
        protocol: TCP
        port: 80
        targetPort: http-web-svc # 直接使用名字
    

    NodePort

    
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-nodeport
    spec:
      type: NodePort # NodePort:每个Node的kube-proxy监听nodePort并转发到符合selector的Pod的targetPort
      selector:
        app.kubernetes.io/name: nginx-proxy
      ports:
      - name: name-of-service-port
        protocol: TCP
        port: 80
        targetPort: http-web-svc # 直接使用名字
        nodePort: 30000
    

    lb

    
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-lb
    spec:
      type: LoadBalancer # 云厂商的CCM监听到后,会自动创建负载均衡,分配EXTERNAL-IP,通过EXTERNAL-IP调用时,会自动负载均衡到某一个pod
      selector:
        app.kubernetes.io/name: nginx-proxy
      ports:
      - name: http
        protocol: TCP
        port: 80
        targetPort: http-web-svc

    Ingress

    Ingress Controller通过Service(LoadBalance或者NodePort)对外暴露入口,根据其中设置的规则,将流量转发到指定的pod。

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: cafe-ingress
    spec:
      rules:
      - host: cafe.example.com # IngressRule的Key
        http:
          paths:
          - path: /tea
            backend:
              serviceName: tea-svc
              servicePort: 80
          - path: /coffee
            backend:
              serviceName: coffee-svc
              servicePort: 80

    Ingress对象更新后nginx-ingress-controller就会根据内容生成一个nginx配置

    Service和Ingress

    Service工作在四层,Ingress工作在七层,涉及TLS等HTTP内容是只能使用ingress

    EndpointSlic

    EndpointSlic对象是某个Service的后端网络断点的子集

    DNS

    cluster-domain默认为cluster.local.

    同一集群可以省略<cluster-domain>, 同一命名空间可以省略<namespace>

    服务的DNS名称格式为 <service-name>.<namespace>.svc.<cluster-domain>,短域名<service-name>.<namespace>,同一命名空间<service-name>

    Pod的DNS名称格式为 <pod-ip>.<namespace>.pod.<cluster-domain>
    同时还有端口的SRV记录_<port-name>._<protocol>.<service-name>.<namespace>.svc.cluster.local

    记录 A SRV PTR

    nslookup -type=A paifu
    Server:         9.166.175.254
    Address:        9.166.175.254#53
    
    Name:   paifu.gamematrix.svc.cluster.local
    Address: 9.166.174.123
    
    nslookup -type=SRV _http-metrics._tcp.cgi-common-sendsysmail.happygame
    Server:         9.166.175.254
    Address:        9.166.175.254#53
    
    _http-metrics._tcp.cgi-common-sendsysmail.happygame.svc.cluster.local   service = 0 100 9100 cgi-common-sendsysmail.happygame.svc.cluster.local.
    
    nslookup -type=PTR 9.166.169.229
    Server:         9.166.175.254
    Address:        9.166.175.254#53
    
    229.169.166.9.in-addr.arpa      name = 9-166-169-229.paifu.gamematrix.svc.cluster.local.
    229.169.166.9.in-addr.arpa      name = 9-166-169-229.service-hlsvr.gamematrix.svc.cluster.local.
    229.169.166.9.in-addr.arpa      name = 9-166-169-229.service-configagent.gamematrix.svc.cluster.local.

    Cluster IP的service
    <svc>.<namespace>.svc.cluster.local 指向Service的ClusterIP(VIP)

    Headless Service
    <svc>.<namespace>.svc.cluster.local 返回所有后端的Endpoints的IP列表

    Pod的记录
    <pod-ip-with-dashes>.<namespace>.pod.cluster.local, pod-ip-with-dashes: 将.替换成-,10.1.2.3 -> 10-1-2-3

    StatefulSet的格式
    <hostname>.<subdomain>.<namespace>.svc.cluster.local, subdomain一般是0,1,2,3

    IPV6支持,感知路由,Windows,Cluster IP分配,跳过

    同一Node中Pod的通信

    service中.spec.internalTrafficPolicy设置成Local,只会选择本Node中的Pod

    存储

    卷为POD中的容器提供了通过文件系统访问和共享数据的方式,可以进行数据的持久存储和共享。

    hostPath 不能迁移到其他Node

    spec:
      volumes:
        - hostPath:
            path: /data/corefile/  # 给Node的此目录命名
            type: ''
          name: corefiles
      containers:
        - volumeMounts:
            - name: corefiles
              mountPath: /data/corefile/ # 将Node目录挂载到容器的此目录
    

    emptyDir POD移除时内容消失

    spec:
      volumes:
        - name: share_empty # 从节点临时存储创建一个卷
          emptyDir: {}
      containers:
        - volumeMounts:
            - name: share_empty # 挂载卷,POD崩溃时卷内容依然存在,POD删除时内容移除,适合用来做缓存
              mountPath: /etc/config   

    持久卷

    存储如何制备的细节从其如何被使用中抽象出来

    持久卷(PersistentVolume,PV): 集群中的存储,可手动制备或使用存储类动态制备,拥有独立于任何使用PV的POD的生命周期。将物理存储方式隐藏起来,对外提供存储

    持久卷申领(PersistentVolumeClaim,PVC):POD会消耗Node资源,PVC可以设定大小或访问模式来消耗PV资源。

    保护:删除被某Pod使用的PVC对象,PVC申领不会被立即移除。PVC对象的移除会被推迟,直至其不再被任何Pod使用。删除已绑定到某PVC申领的PV卷,该PV卷也不会被立即移除。PV对象的移除也要推迟到该PV不再绑定到PVC。可以使用kubectl describe pvc hostpath查看

    PVC可以自动绑定到匹配的PV。也可以手动指定未通过claimRef预留给其他PVC的PV。

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: foo-pvc
      namespace: foo
    spec:
      storageClassName: "" # 此处须显式设置空字符串,否则会被设置为默认的 StorageClass
      volumeName: foo-pv
    
    ---
    
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: foo-pv
    spec:
      storageClassName: ""
      claimRef:
        name: foo-pvc
        namespace: foo

    创建PV和PVC,POD申领PVC

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: pv0003
    spec:
      capacity:
        storage: 5Gi
      volumeMode: Filesystem # Filesystem文件系统,可以被直接挂载。Block块,POD和卷之间不存在文件系统,原始块卷
      accessModes:
        - ReadWriteOnce # ReadWriteOnce被Node中多个Pod读写挂载,ReadOnlyMany,ReadWriteMany,ReadWriteOncePod被Node中一个POD读写挂载
      persistentVolumeReclaimPolicy: Retain # PVC被删除时PV依然保留,对应数据卷视为已经释放,卷存在此前申领人的数据,不能用于其他申领。
      storageClassName: slow
      mountOptions:
        - hard
        - nfsvers=4.1
      nfs:
        path: /tmp
        server: 172.17.0.2
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: myclaim
    spec:
      accessModes:
        - ReadWriteOnce
      volumeMode: Filesystem
      # volumeName: 指定要绑定的PV,不指定则会自动创建
      resources:
        requests:
          storage: 5Gi
      storageClassName: slow # PVC指定时,只有存在相同指定slow的PV,申领才能成功
      selector: # 选择算符,设置之后不会动态制备PV卷
        matchLabels:
          release: "stable"
        matchExpressions:
          - {key: environment, operator: In, values: [dev]}
    apiVersion: v1
    kind: Pod
    metadata:
      name: mypod
    spec:
      containers:
        - name: myfrontend
          image: nginx
          volumeMounts:
          - mountPath: "/var/www/html"
            name: mypd
      volumes:
        - name: mypd
          persistentVolumeClaim:
            claimName: myclaim

    节点亲和性

    限制那些节点可以访问此卷,使用这些卷的POD只会被调度到规则选择的节点上执行。.spec.nodeAffinity

    阶段

    持久卷阶段:Available,Bound,Release(已经被删除,关联的存储资源未被回收),Failed。

    kubectl describe persistentvolume <name> 查看绑定到PV的PVC的名称

    StorageClass

    可能会存在大量的PVC,如果每个PV都手动创建则非常繁琐。
    自动PV的机制核心是StorageClass。
    StorageClass实际是PV的模板。定义了PV的属性:存储类型,Volume大小。创建PV用到的存储插件。这样K8S就可以根据PVC的创建请求,找到StorageClass创建出PV。

    对于支持动态供应的存储系统,可以用来创建PV。
    使用不支持动态供应的节点本地存储,需要手动创建PV表示具体的存储资源,但此时StorageClass仍能用来定义一些内容。

    provisioner,parameters,reclaimPolicy是必须的字段

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: low-latency
      annotations:
        storageclass.kubernetes.io/is-default-class: "false" # true 设置成默认的,当PVC未指定时会使用
    provisioner: csi-driver.example-vendor.example # 指定制作PV的卷插件
    reclaimPolicy: Retain # 默认值是 Delete
    allowVolumeExpansion: true # 允许部分类型的卷调整PVC对象大小,申请新的,大容量的存储卷。
    mountOptions:
      - discard # 这可能会在块存储层启用 UNMAP/TRIM
    volumeBindingMode: WaitForFirstConsumer # 默认的Immediate是立刻绑定,可能导致PV与POD的可用区不同,速度降低。WaitForFirstConsumer将PVC的绑定从立刻绑定到PV,延迟到确定POD调度位置之后进行。
    parameters:
      guaranteedReadWriteLatency: "true" # 这是服务提供商特定的

    存储类,PV,PVC,使用存储类进行动态卷制备

    存储管理实际是PV负责抽象物理存储,PVC负责消费。存储类负责PVC消耗时匹配对应的PV,如果PV不存在且可以动态制备,存储类会创建PV,但此时也是PV负责抽象的物理存储

    PV和PVC也实现了职责分离,PVC更像是接口调用,PV提供接口。开发人员只需要调用接口,接口PV的维护则是运维处理。

    PVC:Pod想要的大小,权限
    PV:描述Volume的属性,Volume类型,挂载目录,远程服务器地址
    StorageClass:PV的模板。同属一个StorageClass的PV和PVC才能进行绑定

    本地存储

    PV,PVC,StorageClass使用的大多是远程存储来保证和节点无关,方便一个StorageClass在不同Node上使用。
    然而部分服务器需要高性能的本地存储,如部分服务会将数据落地磁盘缓存。而本地存储这个是和Node绑定的(通过 PV 的 nodeAffinity 实现)。不同Node的本地存储是互相隔离的。且由于数据在Node上,一旦Node出现问题,数据就会丢失。所以本地存储要求具备定时备份能力。

    延迟绑定:现在假设创建一个PVC,PVC会向Storageclass申请创建一个PV,此时由于没有Pod的信息,可能创建到了Node1上。Pod创建且使用此PVC时,会被直接约束在Node1上。延迟到POD创建时绑定,则可以根据POD的要求和选择更合适的PV进行绑定。避免被调度到不合适的Node上。

    不应该将宿主机的目录当做PV使用:宿主机目录不可控,PVC申请的资源可能会被侵占。缺乏配额保证,缺乏隔离会被其他容器修改。

    本地存储多为静态制备:PVC创建时会立刻与PV绑定,如果使用的是远程目录,立即绑定不会出现问题。使用本地目录则可能绑定到预期外的Node上,导致后续POD也被创建到此Node上。不过目前已经有provisioner支持动态制备。

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: local-storage
    provisioner: kubernetes.io/no-provisioner # 不支持动态制备
    volumeBindingMode: WaitForFirstConsumer
    
    ---
    
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: local-pv
    spec:
      capacity:
        storage: 1Ti
      accessModes:
        - ReadWriteOnce
      persistentVolumeReclaimPolicy: Retain
      storageClassName: local-storage
      local:
        path: /data
      nodeAffinity:
        required:
          nodeSelectorTerms:
          - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values:
              - 1.1.1.1
    
    ---
    
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: local-pvc
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 1Ti
      storageClassName: local-storage
    
    ---
    
    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
    spec:
      containers:
      - name: my-container
        image: nginx
        volumeMounts:
        - mountPath: /data
          name: my-volume
      volumes:
      - name: my-volume
        persistentVolumeClaim:
          claimName: local-pvc

    投射卷

    将多个不同内容来源,聚合到一个挂载目录。支持在一个目录下挂载多个来源

    支持的投射类型

    • configMap
    • secret
    • downwardAPI
    • serviceAccountToken
    Secret

    将etcd中的内容,映射到容器的某个目录上,提供了加密手段

    configMap

    于Secret几乎相同,不过是不需要加密的数据

    spec:
      volumes:
        - name: config-vol
          configMap:
            name: log-config # 声明一个卷config-vol,log-config中log_level条目会 只读 的保存到log_level.conf中
            items:
              - Key: log_level
                path: log_level.conf
      containers:
        - volumeMounts:
            - name: config-vol # 将卷config-vol挂载到容器中此目录,目录中存在log_level.conf文件
              mountPath: /etc/config   
    downwardAPI

    提供访问容器属性的方法

    apiVersion: v1
    kind: Pod
    metadata:
      name: test-downwardapi-volume
      labels:
        zone: us-est-coast
        cluster: test-cluster1
        rack: rack-22
    spec:
      containers:
        - name: client-container
          image: k8s.gcr.io/busybox
          command: ["sh", "-c"]
          args:
          - while true; do
              if [[ -e /etc/podinfo/labels ]]; then
                echo -en '\n\n'; cat /etc/podinfo/labels; fi;
              sleep 5;
            done;
          volumeMounts:
            - name: podinfo
              mountPath: /etc/podinfo
              readOnly: false
      volumes:
        - name: podinfo
          projected:
            sources:
            - downwardAPI:
                items:
                  - path: "labels"
                    fieldRef:
                      fieldPath: metadata.labels

    使用kubectl logs查看

    serviceAccountToken
    K8S为每个pod都默认挂载了serviceAccountToken到固定目录。为pod提供访问K8S API Server的token。容器中的进程如果需要使用K8S API Server就需要加载token。
    算是特殊的secret

    临时卷

    和POD保持统一生命周期,随POD创建和删除

    kind: Pod
    apiVersion: v1
    metadata:
      name: my-app
    spec:
      containers:
        - name: my-frontend
          image: busybox:1.28
          volumeMounts:
          - mountPath: "/scratch"
            name: scratch-volume
          command: [ "sleep", "1000000" ]
      volumes:
        - name: scratch-volume
          ephemeral: # 定义一个临时卷
            volumeClaimTemplate: # 使用模板可以自动创建PVC,使用persistentVolumeClaim则需要手动指定一个创建好的PVC
              metadata:
                labels:
                  type: my-frontend-volume
              spec:
                accessModes: [ "ReadWriteOnce" ]
                storageClassName: "scratch-storage-class"
                resources:
                  requests:
                    storage: 1Gi

    卷属性类,Beta功能跳过

    卷快照,卷快照类,CSI卷克隆,先跳过

    配置

    ConfigMap

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: game-demo
    data:
      # 类属性键;每一个键都映射到一个简单的值
      player_initial_lives: "3"
    
      # 类文件键
      game.properties: |
        enemy.types=aliens,monsters
        player.maximum-lives=5    
    
    
    apiVersion: v1
    kind: Pod
    metadata:
      name: configmap-demo-pod
    spec:
      containers:
          env:
            # 定义环境变量
            - name: PLAYER_INITIAL_LIVES # 请注意这里和 ConfigMap 中的键名是不一样的
              valueFrom:
                configMapKeyRef:
                  name: game-demo           # 这个值来自 ConfigMap
                  key: player_initial_lives # 需要取值的键
          volumeMounts:
          - name: config
            mountPath: "/config"
            readOnly: true
      volumes:
      # 你可以在 Pod 级别设置卷,然后将其挂载到 Pod 内的容器中
      - name: config
        configMap:
          # 提供你想要挂载的 ConfigMap 的名字
          name: game-demo
          # 来自 ConfigMap 的一组键,将被创建为文件
          items:
          - key: "game.properties"
            path: "game.properties"

    Secret

    apiVersion: v1
    kind: Secret
    metadata:
      name: dotfile-secret
    data:
      .secret-file: dmFsdWUtMg0KDQo=
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: secret-dotfiles-pod
    spec:
      volumes:
        - name: secret-volume
          secret:
            secretName: dotfile-secret
      containers:
        - name: dotfile-test-container
          image: registry.k8s.io/busybox
          command:
            - ls
            - "-l"
            - "/etc/secret-volume"
          volumeMounts:
            - name: secret-volume
              readOnly: true
              mountPath: "/etc/secret-volume"  # 最终表现为/etc/secret-volume/.secret-file文件

    资源

    为POD指定资源的Request后,kube-scheduler就会决定将POD调度到哪个节点上,如果节点有大于Request的剩余量,POD可以多使用一些。但是指定limit后确保资源不超过设定值。

    CPU限制:通过CPU节流机制强制执行

    CPU单位:1CPU = 1个物理核或者1个虚拟核,1 CPU=1000m CPU,即500m为半个核心。最小为1m。

    Memory限制:使用OOM终止机制执行

    Memory单位:400m表示0.4字节,400Mi表示400M直接

    apiVersion: v1
    kind: Pod
    metadata:
      name: frontend
    spec:
      containers:
      - name: app
        image: images.my-company.example/app:v4
        resources:
          requests:
            memory: "64Mi"
            cpu: "250m"
          limits:
            memory: "128Mi"
            cpu: "500m"

    安全-暂时跳过

    策略

    范围限制 LimitRange

    指定一个命名空间

    1. 设置POD或者Container的最小和最大的资源使用量
    2. PVC最大和最小的存储空间

    如果新创建的POD或者container不满足要求则会创建失败

    资源配额

    设定一个命名空间下,各种资源的上限或者下限

    节点资源管理器

    可以设置CPU调度相关,比如将POD绑定到某个核心上提高缓存使用效率。

    调度,强占和驱逐

    调度:确保POD匹配到合适的节点,以便kubelet(Node上的运行的代理,保证容器运行在POD中)能够运行POD。
    强占:终止低优先级的POD,以便运行高优先级的POD
    驱逐:资源匮乏的节点上,主动让一个或多个POD失效

    调度器

    通过Watch机制发现集群中新创建且未被调度到节点上的POD,将其调度到合适的节点上运行

    可调度节点:满足一个POD调度请求的节点。没有节点满足时,POD将停留在未调度状态

    绑定:可调度节点中打分,选出最高分的节点,通知kube-apiserver。

    特定节点上运行POD

    1. 节点标签,nodeSelector
    2. 亲和性
      1. requiredDuringSchedulingIgnoredDuringExecution:规则满足时执行调度,是语法表达能力更强的nodeSelector
      2. preferredDuringSchedulingIgnoredDuringExecution:找不到匹配节点时,仍会调度
    3. 反亲和性
      1. requiredDuringSchedulingIgnoredDuringExecution:满足规则是不执行调度
      2. preferredDuringSchedulingIgnoredDuringExecution:最好不调度到匹配的节点上
    apiVersion: v1
    kind: Pod
    metadata:
      name: with-node-affinity
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution: # 必须有
            nodeSelectorTerms:
            - matchExpressions:
              - key: topology.kubernetes.io/zone
                operator: In
                values:
                - antarctica-east1
                - antarctica-west1
          preferredDuringSchedulingIgnoredDuringExecution: # 最好有
          - weight: 1 # 最好有的里面存在多项时,每项的权重,权重越高得分越高
            preference:
              matchExpressions:
              - key: another-node-label-key
                operator: In
                values:
                - another-node-label-value

    topologyKey:拓扑域,hostname 节点级别,zone可用区级别,region区域级别。

    apiVersion: v1
    kind: Pod
    metadata:
      name: with-pod-affinity
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution: # 不调度到这个主机上
          - labelSelector:
              matchExpressions:
              - key: app # 符合标签描述的POD
                operator: In
                values:
                - my-app
            topologyKey: "kubernetes.io/hostname" # 符合标签描述的POD,其所属的节点(hostname域)会被反亲和,同节点的无法调度。
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: security
                  operator: In
                  values:
                  - S2
              topologyKey: topology.kubernetes.io/zone
    

    POD开销

    POD除了内部容器消耗请求的资源,POD本身也会消耗一些资源,调度时会将二者资源相加去寻找节点。

    kind: RuntimeClass进行配置

    POD调度就绪态

    通过yaml中的schedulingGates将就绪的POD放入等待列表,不是立即进行调度。删除后可以进行调度

    POD拓扑分布约束,内容很多,简单过了下

    将POD分布到不同的拓扑中以提高可用性,或者使得客户端就近调度

    污点和容忍度

    污点使得节点能够排斥一类特定的POD

    调度框架

    调度是串行的,绑定是并行。调度+绑定称为调度上下文

    调度框架扩展点

    EnqueueExtension:接口,插件实现此接口根据集群变化通过或者拒绝

    QueueingHint:集群中发生变化时,此回调函数被执行,能控制POD放入活跃或回退队列。

    1. 进入队列前:
      1. PreEnqueue:在POD被添加到内部活动队列之前调用,此队列中的POD被标记为准备好进行调度
    2. 队列排序:
      1. PreFilter:预处理POD或者检查相关条件
      2. Filter:标记不符合此POD的节点
      3. PostFilter:没有可用节点时调度
      4. PreScore:生成一个可共享状态给Score插件使用
      5. Score:评分
      6. NormalizeScore:可以修改分数
      7. Reserve:防止调度器等待绑定成功是发生竞争情况
      8. Permit:批准,拒绝,等待POD的绑定
    3. 绑定:
      1. PreBind:执行POD绑定前的工作
      2. Bind:进行绑定
      3. PostBind:收尾清理相关资源

    动态资源分配如GPU,跳过

    调度器性能调优

    通过配置减少调度流程中的操作项目,比如有一个可调度的Node就直接用,不用评估其他的Node

    资源装箱,控制节点资源权重进而控制分数

    POD优先级和抢占,通过PriorityClass使高优先级POD驱逐低优先POD

    节点压力驱逐

    根据节点压力驱逐

    API发起的驱逐

    API 发起的驱逐是一个先调用 Eviction API 创建 Eviction 对象,再由该对象体面地中止 Pod 的过程。

    集群管理

    1. 自己机器上尝试K8S还是构建高可用节点,或者是参与开发
    2. 使用开箱即用的集群还是管理自己的
    3. 本地还是云上
    4. 本地配置时要选取合适的网络模型
    5. 裸机还是虚拟机运行
    6. 熟悉运行所需的相关组件

    节点关闭

    基于优先级的体面关闭,非体面关闭

    Node自动缩容和扩容

    Node不足时创建新的Node,足够时关闭Node。配合负载自动缩容和扩容使用

    集群网络系统

    1. 高度耦合容器间通信:POD和localhost解决
    2. POD间通信
    3. POD与Service通信
    4. 外部和Service通信

    日志架构

    K8S支持将标准输入和输出定向到文件,也可以用过kubectl logs查看

    Helm

    功能

    包管理工具,定义一个k8s应用

    1. 简化部署:通过Helm,你可以使用预定义的配置文件来部署应用,而不需要手动编写和管理大量的Kubernetes YAML文件。
    2. 版本控制:Helm支持版本控制,你可以轻松地回滚到以前的版本。
    3. 依赖管理:Helm可以管理应用的依赖关系,确保所有依赖的服务都正确部署。
    4. 模板化:Helm使用Go模板引擎,可以根据不同的环境和需求生成动态的Kubernetes配置文件。

    功能

    1. chart创建,chart中含有K8S的全部模板信息
    2. config,包含了配置信息,用于和模板结合后生成最终K8S配置
    3. release,chart和config结合后的运行实例
    4. 打包chart为tgz
    5. 与存储chart的仓库交互
    6. 安装和卸载chart
    7. 管理helm安装的chart的生命周期

    Chart

    软件包

    1. Chart.yaml:元数据文件,包含名称、版本和描述等信息。
    2. values.yaml:配置文件,用来控制部署。
    3. templates/:K8S资源模板文件,可以在配置项中引用values.yaml中的Key。
      1. deployment.yaml:定义Deployment资源的模板
      2. service.yaml:定义Service资源的模板

    Chart:类似yum的rpm包

    Repository:存放Chart的地方,包含一个或多个打包的chart,存在index.yaml的文件,包含完整的包列表,用于检索和验证元数据。helm可以使用repo添加仓库,不过helm不提供上传chart到仓库的功能。

    Release:运行的chart的示例,每次install chart都会产生一个Release

    helm show values
    
    helm repo add bitnami https://charts.bitnami.com/bitnami
    helm search repo bitnami
    helm repo update
    
    # 每次执行都会创建一个新的发布版本,一个chart可以被多次安装,独立管理
    # helm生成名称
    helm install bitnami/mysql --generate-name
    # 指定名称
    helm install mysql_test bitnami/mysql
    
    # 查看发布的版本
    helm list
    NAME                NAMESPACE    REVISION    UPDATED                                 STATUS      CHART          APP VERSION
    mysql-1612624192    default      1           2021-02-06 16:09:56.283059 +0100 CET    deployed    mysql-8.3.0    8.0.23
    
    helm status mysql-1612624192
    
    helm get values mysql-1612624192
    
    helm upgrade -f x.yaml mysql-1612624192 bitnami/mysql
    
    helm history mysql-1612624192
    
    helm rollback mysql-1612624192 1
    
    # 会删除所有相关资源,service,Deployment,pod,版本历史
    helm uninstall mysql-1612624192

    使用helm管理chart

    helm create chart-a
    
    helm package chart-a
    x.tar.gz
    
    helm install chart-a ./x.tar.gz

    Chart

    Chart文件结构

    wordpress/
      Chart.yaml          # 包含了chart信息的YAML文件
      LICENSE             # 可选: 包含chart许可证的纯文本文件
      README.md           # 可选: 可读的README文件
      values.yaml         # chart 默认的配置值
      values.schema.json  # 可选: 一个使用JSON结构的values.yaml文件
      charts/             # 包含chart依赖的其他chart,dependencies中定义的
      crds/               # 自定义资源的定义
      templates/          # 模板目录, 当和values 结合时,可生成有效的Kubernetes manifest文件
      templates/NOTES.txt # 可选: 包含简要使用说明的纯文本文件
    # Chart.yaml
    
    apiVersion: chart API 版本 (必需)
    name: chart名称 (必需)
    version: 语义化2 版本(必需)
    kubeVersion: 兼容Kubernetes版本的语义化版本(可选)
    description: 一句话对这个项目的描述(可选)
    type: chart类型 (可选)
    keywords:
      - 关于项目的一组关键字(可选)
    home: 项目home页面的URL (可选)
    sources:
      - 项目源码的URL列表(可选)
    dependencies: # chart 必要条件列表 (可选)  helm dep up foochart将依赖的文件下载到charts目录
      - name: chart名称 (nginx)
        version: chart版本 ("1.2.3")
        repository: (可选)仓库URL ("https://example.com/charts") 或别名 ("@repo-name")
        condition: (可选) 解析为布尔值的yaml路径,用于启用/禁用chart (e.g. subchart1.enabled )
        tags: # (可选)
          - 用于一次启用/禁用 一组chart的tag
        import-values: # (可选)
          - ImportValue 保存源值到导入父键的映射。每项可以是字符串或者一对子/父列表项
        alias: (可选) chart中使用的别名。当你要多次添加相同的chart时会很有用
    maintainers: # (可选)
      - name: 维护者名字 (每个维护者都需要)
        email: 维护者邮箱 (每个维护者可选)
        url: 维护者URL (每个维护者可选)
    icon: 用做icon的SVG或PNG图片URL (可选)
    appVersion: 包含的应用版本(可选)。不需要是语义化,建议使用引号
    deprecated: 不被推荐的chart (可选,布尔值)
    annotations:
      example: 按名称输入的批注列表 (可选).

    Chart含dependencies的结构

    hlsjsvr/
    ├── Chart.yaml
    ├── values.yaml
    ├── charts/
    │   └── hlsvr-base/
    │       ├── Chart.yaml
    │       ├── values.yaml
    │       └── templates/
    │           └── ...(实际的K8s资源模板)
    
    # Chart.yaml 定义了dependencies
    dependencies:
    - name: hlsvr-base
      repository: http://helm.bkrepo.oa.com/public-cluster/public-cluster/
      version: 1.30.5
    # values.yaml
    hlsvr-base: # 这里的只会传递给dependencies的hlsvr-base中
      replicaCount: 2
      image:
        tag: "1.2.3"

    渲染时如果指定了外部values,会先覆盖hlsjsvr/values.yaml。发现charts中含有依赖下载依赖到charts目录,使用覆盖后的values.yaml再覆盖hlsvr-base的values.yaml,最终的values去渲染templates的内容

    模板文件和values文件和values.schema.json

    模板文件位于chart的templates目录中,helm渲染chart时,会遍历其中的每个文件

    apiVersion: v1
    kind: ReplicationController
    metadata:
      name: deis-database
      namespace: deis
      labels:
        app.kubernetes.io/managed-by: deis
    spec:
      replicas: 1
      selector:
        app.kubernetes.io/name: deis-database
      template:
        metadata:
          labels:
            app.kubernetes.io/name: deis-database
        spec:
          serviceAccount: deis-database
          containers:
            - name: deis-database
              image: {{ .Values.imageRegistry }}/postgres:{{ .Values.dockerTag }}
              imagePullPolicy: {{ .Values.pullPolicy }}
              ports:
                - containerPort: 5432
              env:
                - name: DATABASE_STORAGE
                  value: {{ default "minio" .Values.storage }}

    values文件可以为chart的依赖项目提供基础值。values.schema.json中可以定义Values文件字段的格式和规范

    title: "My WordPress Site" # Sent to the WordPress template
    
    # 相当于在每个chart中增加这个基础值。mysql的模板中可以使用{{.Values.global.app}}访问此内容
    global:
      app: MyWordPress
    
    mysql: # charts中的MySQL可以访问这两项内容,无法访问title和Apache的内容
      max_connections: 100 # Sent to MySQL
      password: "secret"
    
    apache:
      port: 8080 # Passed to Apache

    crd

    可以声明自定义资源类型,位于crds目录中。无法使用模板,只能是普通的yaml文档。

    创建出一个类似pod的资源类型,不过实际作用还是不太清楚。

    crontabs/
      Chart.yaml
      crds/
        crontab.yaml
      templates/
        mycrontab.yaml
    # crontab.yaml
    
    kind: CustomResourceDefinition
    metadata:
      name: crontabs.stable.example.com
    spec:
      group: stable.example.com
      versions:
        - name: v1
          served: true
          storage: true
      scope: Namespaced
      names:
        plural: crontabs
        singular: crontab
        kind: CronTab
    apiVersion: stable.example.com
    kind: CronTab
    metadata:
      name: {{ .Values.name }}
    spec:

    crd的安装是全局的,会受到以下的限制

    1. 不会重现安装,helm确认crds目录已经存在的时候(忽略版本),helm不会安装或升级。
    2. 不会在升级或回滚中安装,只会在安装时创建crd
    3. 不会被删除,自动删除crd会删除集群中所有命名空间中所有的crd内容,所以helm不会删除crd

    chart Hook

    Helm提供了hook机制允许chart开发者在发布生命周期的某些点干预。

    1. 安装时在加载其他chart之前加载配置映射或者秘钥。
    2. 安装新chart之前执行备份数据库的任务,升级之后执行第二个任务用于存储数据
    3. 删除发布之前执行一个任务以便在删除服务之前退出滚动。

    pre-install 在模板渲染之后,Kubernetes资源创建之前执行
    post-install 在所有资源加载到Kubernetes之后执行
    pre-delete 在Kubernetes删除之前,执行删除请求
    post-delete 在所有的版本资源删除之后执行删除请求
    pre-upgrade 在模板渲染之后,资源更新之前执行一个升级请求
    post-upgrade 所有资源升级之后执行一个升级请求
    pre-rollback 在模板渲染之后,资源回滚之前,执行一个回滚请求
    post-rollback 在所有资源被修改之后执行一个回滚请求
    test 调用Helm test子命令时执行 ( test文档)

    1. helm install foo
    2. helm库调用安装API
    3. 安装cards目录中的cad
    4. 验证后渲染foo模板
    5. 准备执行pre-install
    6. 按权重对钩子进行排序,资源种类排序,名称正序排列
    7. 加载最小权重的钩子(可以使用负数)
    8. 等到钩子READY状态,资源是JOB或者POD类型时,Helm会等到其运行完成。
    9. 加载资源到K8S中,设置–wait时会等到所有资源ready,且所有资源准备就绪后才会继续
    10. 执行post-install钩子
    11. 等到钩子ready状态
    12. 反馈发布对象到客户端
    13. 客户端退出

    钩子

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: "{{ .Release.Name }}"
      labels:
        app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
        app.kubernetes.io/instance: {{ .Release.Name | quote }}
        app.kubernetes.io/version: {{ .Chart.AppVersion }}
        helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
      annotations: # 在这里定义模板是钩子,否则是一个普通资源
        "helm.sh/hook": post-install
        "helm.sh/hook-weight": "-5"
        "helm.sh/hook-delete-policy": hook-succeeded # before-hook-creation:新钩子启动前删除之前的资源 (默认) hook-succeeded:钩子成功执行之后删除资源 hook-failed:如果钩子执行失败,删除资源
    spec:
      template:
        metadata:
          name: "{{ .Release.Name }}"
          labels:
            app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
            app.kubernetes.io/instance: {{ .Release.Name | quote }}
            helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
        spec:
          restartPolicy: Never
          containers:
          - name: post-install-job
            image: "alpine:3.3"
            command: ["/bin/sleep","{{ default "10" .Values.sleepyTime }}"]

    chart test

    验证chart安装,帮助用户理解chart的功能

    helm create demo
    
    .
    ├── charts
    ├── Chart.yaml
    ├── templates
    │   ├── deployment.yaml
    │   ├── _helpers.tpl
    │   ├── hpa.yaml
    │   ├── ingress.yaml
    │   ├── NOTES.txt
    │   ├── serviceaccount.yaml
    │   ├── service.yaml
    │   └── tests
    │       └── test-connection.yaml
    └── values.yaml

    include的内容在_helper.tpl中定义

    {{- define "demo.fullname" -}}
    {{- if .Values.fullnameOverride }}
    {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
    {{- else }}
    {{- $name := default .Chart.Name .Values.nameOverride }}
    {{- if contains $name .Release.Name }}
    {{- .Release.Name | trunc 63 | trimSuffix "-" }}
    {{- else }}
    {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
    {{- end }}
    {{- end }}
    {{- end }}
    # test-connection.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: "{{ include "demo.fullname" . }}-test-connection"
      labels:
        {{- include "demo.labels" . | nindent 4 }}
      annotations:
        "helm.sh/hook": test
    spec:
      containers:
        - name: wget
          image: busybox
          command: ['wget']
          args: ['{{ include "demo.fullname" . }}:{{ .Values.service.port }}']
      restartPolicy: Never
    $ sudo helm install demo demo
    NAME: demo
    LAST DEPLOYED: Mon May 12 16:34:29 2025
    NAMESPACE: default
    STATUS: deployed
    REVISION: 1
    NOTES:
    
    $ sudo helm test demo
    NAME: demo
    LAST DEPLOYED: Mon May 12 16:34:29 2025
    NAMESPACE: default
    STATUS: deployed
    REVISION: 1
    TEST SUITE:     demo-test-connection
    Last Started:   Mon May 12 16:34:49 2025
    Last Completed: Mon May 12 16:34:55 2025
    Phase:          Succeeded
    NOTES:

    部署时会使用values和tpl来渲染test-connection.yaml。values和tpl只是提供一些内容,实际起作用的是yaml文件

    库类型chart

    可以定义一些tpl模板放到库中,其他chart可以引用这些库中预先定义的内容。

    模板库的Chart.yaml中type为library

    引用时在yaml文件中使用include,同时在chart.yaml中添加dependencies

    helm来源和完整性

    helm package –sign –key进行签名,helm verify进行验证

    chart仓库,OCI

    https://example.com/charts/index.yaml 其中包含chart的信息和下载地址

    helm渲染模板和values的合成覆盖流程

    1. chart包中的values.yaml是默认值
    2. 使用-f(–values)指定外部的values文件,会覆盖默认值中的同名配置
    3. –set,–set-file会再覆盖前面的同名配置
    4. 合成的最终values用来渲染templates目录中的yaml文件

    基于角色的访问控制

    Helm插件

    Helm可以设置一个插件目录,插件放于目录中,运行helm的插件时会自动在其中寻找。

    惯例

    1. chart名称是小写字母和数字,单词之间使用-分割,如nginx-hello
    2. yaml使用双空格缩进而不是tab
    3. values
      1. 变量使用小写字母开头,单词驼峰区分。helloWorld: true
      2. Helm内置变量使用大写字母开头
      3. foo: false和foo: “false”不同。规避类型转换,最好统一使用字符串,即打引号。
    4. 模板

    常用命令

    日志查询

    kubectl logs riichipersonalpanel-0 -n riichi -c istio-proxy

    文件同步