深入K8S实战

发布于:2024-04-12 ⋅ 阅读:(140) ⋅ 点赞:(0)

K8S: 深入K8S实战进阶篇

1、搭建 Kubernetes 集群

1.1、搭建方案

1.1.1、minikube

minikube 是一个工具, 能让你在本地运行 Kubernetes。 minikube 在你的个人计算机(包括 Windows、macOS 和 Linux PC)上运行一个一体化(all-in-one)或多节点的本地 Kubernetes 集群,以便你来尝试 Kubernetes 或者开展每天的开发工作。

1.1.2、kubeadm

你可以使用 kubeadm 工具来创建和管理 Kubernetes 集群。 该工具能够执行必要的动作并用一种用户友好的方式启动一个可用的、安全的集群。

1.1.2.1、服务器要求
  • 3 台服务器(虚拟机)

    • k8s-master:192.168.113.120
    • k8s-node1:192.168.113.121
    • k8s-node2:192.168.113.122
  • 最低配置:2核、2G内存、20G硬盘

  • 最好能联网,不能联网的话需要有提供对应镜像的私有仓库

1.1.2.2、软件环境
  • 操作系统:CentOS 7
  • Docker:20+
  • k8s:1.23.6
1.1.2.3、安装步骤

安装 kubeadm 展示了如何安装 kubeadm 的过程。一旦安装了 kubeadm, 你就可以使用它来创建一个集群。

  1. 初始操作

    # 关闭防火墙
    systemctl stop firewalld
    systemctl disable firewalld
    # 关闭selinux
    sed -i 's/enforcing/disabled/' /etc/selinux/config  # 永久
    setenforce 0  # 临时
    # 关闭swap
    swapoff -a  # 临时
    sed -ri 's/.*swap.*/#&/' /etc/fstab    # 永久
    # 关闭完swap后,一定要重启一下虚拟机!!!
    # 根据规划设置主机名
    hostnamectl set-hostname 
    # 在master添加hosts
    cat >> /etc/hosts 
    192.168.171.128 k8s-master
    192.168.171.129 k8s-node1
    192.168.171.130 k8s-node2
    EOF
    # 将桥接的IPv4流量传递到iptables的链
    cat > /etc/sysctl.d/k8s.conf 
    net.bridge.bridge-nf-call-ip6tables = 1
    net.bridge.bridge-nf-call-iptables = 1
    EOF
    sysctl --system  # 生效
    # 时间同步
    yum install ntpdate -y
    ntpdate time.windows.com
    
  2. 安装基础软件(所有节点)

    1. 安装 Docker

    2. 添加阿里云 yum 源

      cat > /etc/yum.repos.d/kubernetes.repo 
      [kubernetes]
      name=Kubernetes
      baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
      enabled=1
      gpgcheck=0
      repo_gpgcheck=0
      gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
      EOF
      
    3. 安装 kubeadm、kubelet、kubectl

      yum install -y kubelet-1.23.6 kubeadm-1.23.6 kubectl-1.23.6
      systemctl enable kubelet
      # 查看当前kubelet版本
      kubelet --version 
      # 查看docker驱动信息
      docker info | grep Driver
      # 配置关闭 Docker 的 cgroups,修改 /etc/docker/daemon.json,加入以下内容, 因为k8s用cgroups会报错
      "exec-opts": ["native.cgroupdriver=systemd"]
      # 重启 docker
      systemctl daemon-reload
      systemctl restart docker
      
  3. 部署 Kubernetes Master

    –apiserver-advertise-address 指定apiserver地址直接写当前机器IP地址

    –image-repository 指定镜像仓库

    –service-cid是设置k8s的service的虚拟ip网段

    –pod-network-cidr是设置k8s的pod网段 这些ip网段是k8s集群内部通信用的

    # 在 Master 节点下执行
    kubeadm init \
          --apiserver-advertise-address=192.168.171.128 \
          --image-repository registry.aliyuncs.com/google_containers \
          --kubernetes-version v1.23.6 \
          --service-cidr=10.96.0.0/12 \
          --pod-network-cidr=10.244.0.0/16
    
    # kubeadm 初始化失败辅助命令
    # 查看kubelet状态
    systemctl status kubelet
    # 查看kubelet日志信息
    journalctl -xefu kubelet
    # 重启kubelet
    systemctl restart kubelet
    # 查看docker容器是否启动
    docker ps -a | grep kube | grep -v pause
    # 重置kubeadm, 重置以后, 必须要走上面的初始化命令
    kubeadm reset
    

    在这里插入图片描述

    # 安装成功后,复制如下配置并执行
    mkdir -p $HOME/.kube
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config
    kubectl get nodes
    

    在这里插入图片描述

  4. 加入 Kubernetes Node

    分别在 k8s-node1 和 k8s-node2 执行
    # 下方命令可以在 k8s master 控制台初始化成功后复制 join 命令
    kubeadm join 192.168.171.128:6443 --token ev6pil.4nmxoz7ogh668b8r --discovery-token-ca-cert-hash sha256:22450bc10c43a7ab8639411543618345280ad86cda235122fa6f43beae6647cc
    
    # 如果初始化的 token 不小心清空了,可以通过如下命令获取或者重新申请
    # 如果 token 已经过期,就重新申请
    kubeadm token create
    # token 没有过期可以通过如下命令获取
    kubeadm token list
    
    # 获取 --discovery-token-ca-cert-hash 值,得到值后需要在前面拼接上 sha256:
    openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | \
    openssl dgst -sha256 -hex | sed 's/^.* //'
    

    把node1, node2加入到master中

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

  5. 部署 CNI 网络插件

    # 获取组件状态
    kubectl get cs
    

    在这里插入图片描述

    # 查看指定名称空间下面的pods
    kubectl get pods -n 名称空间
    

    在这里插入图片描述

    # 在 master 节点上执行
    # 下载 calico 配置文件,可能会网络超时, 新地址
    curl https://raw.githubusercontent.com/projectcalico/calico/v3.26.0/manifests/calico.yaml -O
    # 下载 calico 配置文件,可能会网络超时, 原始地址
    curl https://docs.projectcalico.org/manifests/calico.yaml -O
    
    # 修改 calico.yaml 文件中的 CALICO_IPV4POOL_CIDR 配置,修改为与初始化的 cidr 相同
    # 修改 IP_AUTODETECTION_METHOD 下的网卡名称
    

    在这里插入图片描述

    # 找到它里面所有需要下载的镜像
    grep image calico.yaml
    

    在这里插入图片描述

    # 删除镜像 docker.io/ 前缀,避免下载过慢导致失败
    sed -i 's#docker.io/##g' calico.yaml
    

    在这里插入图片描述

  6. 测试 kubernetes 集群

    # 构建整个应用
    kubectl apply -f  calico.yaml
    

    在这里插入图片描述

    # 查看安装进度
    kubectl describe po pod名称 -n kube-system
    
    kubectl describe po calico-node-c924b -n kube-system
    

    出现下面这个情况就是centos7版本不对, 你的内核版本太低没有对应的挂载点, 换系统, 重复上面的操作

    在这里插入图片描述

    # 查看名称空间为kube-system下的pod信息
    kubectl get po -n kube-system
    

    在这里插入图片描述

    # 查看pod的详情
    kubectl describe po 名称 -n 名称空间
    kubectl describe po calico-kube-controllers-6fbdddcf6b-g2rbz -n kube-system
    

    在这里插入图片描述

    # 创建部署
    kubectl create deployment nginx --image=nginx
    # 暴露端口
    kubectl expose deployment nginx --port=80 --type=NodePort
    # 查看 pod 以及服务信息
    kubectl get pod,svc
    

    在这里插入图片描述

1.1.3、二进制安装

利用 k8s 官方 github 仓库下载二进制包安装,安装过程较复杂,但相对较为稳定,推荐生产环境使用。

1.1.4、命令行工具

1.2、命令行工具 kubectl

Kubernetes 提供 kubectl 是使用 Kubernetes API 与 Kubernetes 集群的控制面进行通信的命令行工具。

1.2.1、在任意节点使用 kubectl
  1. 将 master 节点中 /etc/kubernetes/admin.conf 拷贝到需要运行的服务器的 /etc/kubernetes 目录中

    scp /etc/kubernetes/admin.conf root@k8s-node1:/etc/kubernetes
    
  2. 在对应的服务器上配置环境变量

    echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
    
    source ~/.bash_profile
    
1.2.2、资源操作
  1. 创建对象

    $ kubectl create -f ./my-manifest.yaml           # 创建资源
    $ kubectl create -f ./my1.yaml -f ./my2.yaml     # 使用多个文件创建资源
    $ kubectl create -f ./dir                        # 使用目录下的所有清单文件来创建资源
    $ kubectl create -f https://git.io/vPieo         # 使用 url 来创建资源
    $ kubectl run nginx --image=nginx                # 启动一个 nginx 实例
    $ kubectl explain pods,svc                       # 获取 pod 和 svc 的文档
    # 从 stdin 输入中创建多个 YAML 对象
    $ cat 
    apiVersion: v1
    kind: Pod
    metadata:
      name: busybox-sleep
    spec:
      containers:
      - name: busybox
        image: busybox
        args:
        - sleep
        - "1000000"
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: busybox-sleep-less
    spec:
      containers:
      - name: busybox
        image: busybox
        args:
        - sleep
        - "1000"
    EOF
    # 创建包含几个 key 的 Secret
    $ cat 
    apiVersion: v1
    kind: Secret
    metadata:
      name: mysecret
    type: Opaque # 指定了 Secret 对象的类型为 Opaque,即不透明类型,意味着其数据内容不受特定格式的限制
    data:
      password: $(echo "s33msi4" | base64)
      username: $(echo "jane" | base64)
    
  2. 显示和查找资源

    # Get commands with basic output
    $ kubectl get services                          # 列出所有 namespace 中的所有 service
    $ kubectl get pods --all-namespaces             # 列出所有 namespace 中的所有 pod
    $ kubectl get pods -o wide                      # 列出所有 pod 并显示详细信息
    $ kubectl get deployment my-dep                 # 列出指定 deployment
    $ kubectl get pods --include-uninitialized      # 列出该 namespace 中的所有 pod 包括未初始化的
    # 使用详细输出来描述命令
    $ kubectl describe nodes my-node
    $ kubectl describe pods my-pod
    $ kubectl get services --sort-by=.metadata.name # List Services Sorted by Name
    # 根据重启次数排序列出 pod
    $ kubectl get pods --sort-by='.status.containerStatuses[0].restartCount'
    # 获取所有具有 app=cassandra 的 pod 中的 version 标签
    $ kubectl get pods --selector=app=cassandra rc -o \
      jsonpath='{.items[*].metadata.labels.version}'
    # 获取所有节点的 ExternalIP
    $ kubectl get nodes -o jsonpath='{.items[*].status.addresses[?(@.type=="ExternalIP")].address}'
    # 列出属于某个 PC 的 Pod 的名字
    # “jq”命令用于转换复杂的 jsonpath,参考 https://stedolan.github.io/jq/
    $ sel=${$(kubectl get rc my-rc --output=json | jq -j '.spec.selector | to_entries | .[] | "\(.key)=\(.value),"')%?}
    $ echo $(kubectl get pods --selector=$sel --output=jsonpath={.items..metadata.name})
    # 查看哪些节点已就绪
    $ JSONPATH='{range .items[*]}{@.metadata.name}:{range @.status.conditions[*]}{@.type}={@.status};{end}{end}' \
     && kubectl get nodes -o jsonpath="$JSONPATH" | grep "Ready=True"
    # 列出当前 Pod 中使用的 Secret
    $ kubectl get pods -o json | jq '.items[].spec.containers[].env[]?.valueFrom.secretKeyRef.name' | grep -v null | sort | uniq
    
    
  3. 更新资源

    $ kubectl rolling-update frontend-v1 -f frontend-v2.json           # 滚动更新 pod frontend-v1
    $ kubectl rolling-update frontend-v1 frontend-v2 --image=image:v2  # 更新资源名称并更新镜像
    $ kubectl rolling-update frontend --image=image:v2                 # 更新 frontend pod 中的镜像
    $ kubectl rolling-update frontend-v1 frontend-v2 --rollback        # 退出已存在的进行中的滚动更新
    $ cat pod.json | kubectl replace -f -                              # 基于 stdin 输入的 JSON 替换 pod
    # 强制替换,删除后重新创建资源。会导致服务中断。
    $ kubectl replace --force -f ./pod.json
    # 为 nginx RC 创建服务,启用本地 80 端口连接到容器上的 8000 端口
    $ kubectl expose rc nginx --port=80 --target-port=8000
    # 更新单容器 pod 的镜像版本(tag)到 v4
    $ kubectl get pod mypod -o yaml | sed 's/\(image: myimage\):.*$/\1:v4/' | kubectl replace -f -
    $ kubectl label pods my-pod new-label=awesome                      # 添加标签
    $ kubectl annotate pods my-pod icon-url=http://goo.gl/XXBTWq       # 添加注解
    $ kubectl autoscale deployment foo --min=2 --max=10                # 自动扩展 deployment “foo”
    
  4. 修补资源

    $ kubectl patch node k8s-node-1 -p '{"spec":{"unschedulable":true}}' # 部分更新节点
    # 更新容器镜像; spec.containers[*].name 是必须的,因为这是合并的关键字
    $ kubectl patch pod valid-pod -p '{"spec":{"containers":[{"name":"kubernetes-serve-hostname","image":"new image"}]}}'
    # 使用具有位置数组的 json 补丁更新容器镜像
    $ kubectl patch pod valid-pod --type='json' -p='[{"op": "replace", "path": "/spec/containers/0/image", "value":"new image"}]'
    # 使用具有位置数组的 json 补丁禁用 deployment 的 livenessProbe
    $ kubectl patch deployment valid-deployment  --type json   -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/livenessProbe"}]'
    
  5. 编辑资源

    $ kubectl edit svc/docker-registry                      # 编辑名为 docker-registry 的 service
    $ KUBE_EDITOR="nano" kubectl edit svc/docker-registry   # 使用其它编辑器
    
  6. scale 资源

    $ kubectl scale --replicas=3 deploy rs/foo                                 # Scale a replicaset named 'foo' to 3
    $ kubectl scale --replicas=3 -f foo.yaml                            # Scale a resource specified in "foo.yaml" to 3
    $ kubectl scale --current-replicas=2 --replicas=3 deployment/mysql  # If the deployment named mysql's current size is 2, scale mysql to 3
    $ kubectl scale --replicas=5 rc/foo rc/bar rc/baz                   # Scale multiple replication controllers
    
  7. 删除资源

    $ kubectl delete -f ./pod.json                                              # 删除 pod.json 文件中定义的类型和名称的 pod
    $ kubectl delete pod,service baz foo                                        # 删除名为“baz”的 pod 和名为“foo”的 service
    $ kubectl delete pods,services -l name=myLabel                              # 删除具有 name=myLabel 标签的 pod 和 serivce
    $ kubectl delete pods,services -l name=myLabel --include-uninitialized      # 删除具有 name=myLabel 标签的 pod 和 service,包括尚未初始化的
    $ kubectl -n my-ns delete po,svc --all                                      # 删除 my-ns namespace 下的所有 pod 和 serivce,包括尚未初始化的
    
1.2.3、Pod 与集群
  1. 与运行的 Pod 交互

    $ kubectl logs my-pod                                 # dump 输出 pod 的日志(stdout)
    $ kubectl logs my-pod -c my-container                 # dump 输出 pod 中容器的日志(stdout,pod 中有多个容器的情况下使用)
    $ kubectl logs -f my-pod                              # 流式输出 pod 的日志(stdout)
    $ kubectl logs -f my-pod -c my-container              # 流式输出 pod 中容器的日志(stdout,pod 中有多个容器的情况下使用)
    $ kubectl run -i --tty busybox --image=busybox -- sh  # 交互式 shell 的方式运行 pod
    $ kubectl attach my-pod -i                            # 连接到运行中的容器
    $ kubectl port-forward my-pod 5000:6000               # 转发 pod 中的 6000 端口到本地的 5000 端口
    $ kubectl exec my-pod -- ls /                         # 在已存在的容器中执行命令(只有一个容器的情况下)
    $ kubectl exec my-pod -c my-container -- ls /         # 在已存在的容器中执行命令(pod 中有多个容器的情况下)
    $ kubectl top pod POD_NAME --containers               # 显示指定 pod 和容器的指标度量
    
  2. 与节点和集群交互

    $ kubectl cordon my-node                                                # 标记 my-node 不可调度
    $ kubectl drain my-node                                                 # 清空 my-node 以待维护
    $ kubectl uncordon my-node                                              # 标记 my-node 可调度
    $ kubectl top node my-node                                              # 显示 my-node 的指标度量
    $ kubectl cluster-info                                                  # 显示 master 和服务的地址
    $ kubectl cluster-info dump                                             # 将当前集群状态输出到 stdout                                    
    $ kubectl cluster-info dump --output-directory=/path/to/cluster-state   # 将当前集群状态输出到 /path/to/cluster-state
    # 如果该键和影响的污点(taint)已存在,则使用指定的值替换
    $ kubectl taint nodes foo dedicated=special-user:NoSchedule
    
1.2.4、资源类型与别名
  1. pods
    • po
  2. deployments
    • deploy
  3. services
    • svc
  4. namespace
    • ns
  5. nodes
    • no
1.2.5、格式化输出
  1. 输出 json 格式
    • -o json
  2. 仅打印资源名称
    • -o name
  3. 以纯文本格式输出所有信息
    • -o wide
  4. 输出 yaml 格式
    • -o yaml

1.3、API 概述

  1. 类型

    1. Alpha

      包含 alpha 名称的版本(例如v1alpha1)。
      该软件可能包含错误。启用一个功能可能会导致 bug。默认情况下,功能可能会被禁用。
      随时可能会丢弃对该功能的支持,恕不另行通知。
      API 可能在以后的软件版本中以不兼容的方式更改,恕不另行通知。
      该软件建议仅在短期测试集群中使用,因为错误的风险增加和缺乏长期支持。
      
    2. Beta

      包含 beta 名称的版本(例如 v2beta3)。
      该软件经过很好的测试。启用功能被认为是安全的。默认情况下功能是开启的。
      细节可能会改变,但功能在后续版本不会被删除
      对象的模式或语义在随后的 beta 版本或 Stable 版本中可能以不兼容的方式发生变化。如果这种情况发生时,官方会提供迁移操作指南。这可能需要删除、编辑和重新创建API对象。
      该版本在后续可能会更改一些不兼容地方,所以建议用于非关键业务,如果你有多个可以独立升级的集群,你也可以放宽此限制。
      大家使用过的 Beta 版本后,可以多给社区反馈,如果此版本在后续更新后将不会有太大变化。
      
    3. Stable

      该版本名称命名方式:vX 这里 X 是一个整数。
      Stable 版本的功能特性,将出现在后续发布的软件版本中。
      
  2. 访问控制

    • 认证
    • 授权
  3. 废弃 api 说明

    https://kubernetes.io/zh-cn/docs/reference/using-api/deprecation-guide/
    

2、深入 pod

2.1、Pod 配置文件

apiVersion: v1 # api 文档版本
kind: Pod  # 资源对象类型,也可以配置为像Deployment、StatefulSet这一类的对象
metadata: # Pod 相关的元数据,用于描述 Pod 的数据
  name: nginx-demo # Pod 的名称
  labels: # 定义 Pod 的标签
    type: app # 自定义 label 标签,名字为 type,值为 app
    test: 1.0.0 # 自定义 label 标签,描述 Pod 版本号
  namespace: 'default' # 命名空间的配置
spec: # 期望 Pod 按照这里面的描述进行创建
  containers: # 对于 Pod 中的容器描述
  - name: nginx # 容器的名称
    image: nginx:1.7.9 # 指定容器的镜像
    imagePullPolicy: IfNotPresent # 镜像拉取策略,指定如果本地有就用本地的,如果没有就拉取远程的
    command: # 指定容器启动时执行的命令
    - nginx
    - -g
    - 'daemon off;' # 执行的命令 nginx -g 'daemon off;'
    workingDir: /usr/share/nginx/html # 定义容器启动后的工作目录
    ports:
    - name: http # 端口名称
      containerPort: 80 # 描述容器内要暴露什么端口
      protocol: TCP # 描述该端口是基于哪种协议通信的
    env: # 环境变量
    - name: JVM_OPTS # 环境变量名称
      value: '-Xms128m -Xmx128m' # 环境变量的值
    reousrces:
      requests: # 最少需要多少资源
        cpu: 100m # 限制 cpu 最少使用 0.1 个核心
        memory: 128Mi # 限制内存最少使用 128兆
      limits: # 最多可以用多少资源
        cpu: 200m # 限制 cpu 最多使用 0.2 个核心
        memory: 256Mi # 限制 最多使用 256兆
  restartPolicy: OnFailure # 重启策略,只有失败的情况才会重启

创建pod

kubectl create -f nginx-demo.yaml

在这里插入图片描述

查看创建详情

kubectl describe po nginx-demo

在这里插入图片描述

2.2、探针

容器内应用的监测机制,根据不同的探针来判断容器应用当前的状态
  1. 类型

    • StartupProbe 作用: 保证应用启动完成 (启动探针)

      k8s 1.16 版本新增的探针,用于判断应用程序是否已经启动了。
      当配置了 startupProbe 后,会先禁用其他探针,直到 startupProbe 成功后,其他探针才会继续。
      作用:由于有时候不能准确预估应用一定是多长时间启动成功,因此配置另外两种方式不方便配置初始化时长来检测,而配置了 statupProbe 后,只有在应用启动成功了,才会执行另外两种探针,可以更加方便的结合使用另外两种探针使用。
      startupProbe:
        httpGet:
          path: /api/startup
          port: 80
      
    • LivenessProbe 作用: 重启应用 (存活探针)

      用于探测容器中的应用是否运行,如果探测失败,kubelet 会根据配置的重启策略进行重启,若没有配置,默认就认为容器启动成功,不会执行重启策略。
      livenessProbe:
        failureThreshold: 5
        httpGet:
          path: /health
          port: 8080
          scheme: HTTP
        initialDelaySeconds: 60
        periodSeconds: 10
        successThreshold: 1
        timeoutSeconds: 5
      
    • ReadinessProbe 作用: 开放外部流量 (就绪探针)

      用于探测容器内的程序是否健康,它的返回值如果返回 success,那么就认为该容器已经完全启动,并且该容器是可以接收外部流量的。
      readinessProbe:
        failureThreshold: 3 # 错误次数
        httpGet:
          path: /ready
          port: 8181
          scheme: HTTP
        periodSeconds: 10 # 间隔时间
        successThreshold: 1
        timeoutSeconds: 1
      
  2. 探测方式

    • ExecAction

      在容器内部执行一个命令,如果返回值为 0,则任务容器时健康的。
      livenessProbe:
        exec:
          command:
            - cat
            - /health
      
    • TCPSocketAction

      通过 tcp 连接监测容器内端口是否开放,如果开放则证明该容器健康
      livenessProbe:
        tcpSocket:
          port: 80
      
    • HTTPGetAction

      生产环境用的较多的方式,发送 HTTP 请求到容器内的应用程序,如果接口返回的状态码在 200~400 之间,则认为容器健康。
      livenessProbe:
        failureThreshold: 5
        httpGet:
          path: /health
          port: 8080
          scheme: HTTP
          httpHeaders:
            - name: xxx
              value: xxx
      
  3. 参数配置

    initialDelaySeconds: 60 # 初始化时间
    timeoutSeconds: 2 # 超时时间
    periodSeconds: 5 # 监测间隔时间
    successThreshold: 1 # 检查 1 次成功就表示成功
    failureThreshold: 2 # 监测失败 2 次就表示失败
    
  4. 测试探针三种类型及方式

    1. 类型StartupProbe

      • 类型StartupProbe, 方式HTTPGetAction (注意我这里写的/api/path是nginx里面没有的接口, 我们有配置了重启策略, 所以这个pod是起不起来的, 会一直重启)

        apiVersion: v1 # api文档版本
        kind: Pod # 资源对象类型, 也可以配置为像Deployement、StatefulSet这一类的对象
        metadata: # pod 相关的元数据, 用于描述pod
          name: nginx-pod # pod的名称
          labels: # 定义pod的标签
            type: app # 自定义label标签, 名称为 type, 值为 app
            test: 1.0.0 # 自定义label标签, 描述 pod 版本号
          namespace: 'default' # 命名空间的配置
        spec: # 期望pod按照这里面的描述, 进行创建
          containers: # 对于pod中容器的描述
          - name: nginx # 容器的名称
            image: nginx:1.7.9 # 指定容器镜像
            imagePullPolicy: IfNotPresent # 如果本地有镜像就使用本地镜像,没有就拉取在线镜像。
            startupProbe: # 引用启动探针配置
              httpGet: # 探针方式 基于 http 请求探测
                path: /api/path # http 请求路径
                port: 80 # http 请求端口
              timeoutSeconds: 5 # 请求的超时时间
              periodSeconds: 5 # 监测间隔时间
              successThreshold: 1 # 多少次检测成功才算成功
              failureThreshold: 2 # 失败多少次才算真正失败
            command: # 指定容器启动时执行的命令
            - nginx
            - -g
            - 'daemon off;'  # 执行的命令就是 nginx -g 'daemon off;'
            workingDir: /usr/share/nginx/html # 定义容器启动后的工作目录
            ports:
            - name: http # 端口名称
              containerPort: 80 # 描述容器内要暴露什么端口
              protocol: TCP # 描述改端口是基于那种协议通信的
            env: # 环境变量
            - name: JVM_OPTS # 环境变量名称
              value: '-Xms128m -Xmx128m' # 环境变量的值
            resources:
              requests: # 最少需要多少资源
                cpu: 0.1  # 限制 cpu 最少使用 0.1 个核心  
                memory: 100Mi  # 限制内存最少使用 128 兆
              limits: # 最多可以用多少资源
                cpu: 0.2  # 限制 cpu 最多使用 0.2 个核心
                memory: 100Mi # 限制内存最多使用 200 兆
          restartPolicy: OnFailure # 重启策略, 只有失败的情况才会重启
        

        错误配置path, 导致pod起不起来, 一直重启

        在这里插入图片描述

        apiVersion: v1 # api文档版本
        kind: Pod # 资源对象类型, 也可以配置为像Deployement、StatefulSet这一类的对象
        metadata: # pod 相关的元数据, 用于描述pod
          name: nginx-pod # pod的名称
          labels: # 定义pod的标签
            type: app # 自定义label标签, 名称为 type, 值为 app
            test: 1.0.0 # 自定义label标签, 描述 pod 版本号
          namespace: 'default' # 命名空间的配置
        spec: # 期望pod按照这里面的描述, 进行创建
          containers: # 对于pod中容器的描述
          - name: nginx # 容器的名称
            image: nginx:1.7.9 # 指定容器镜像
            imagePullPolicy: IfNotPresent # 如果本地有镜像就使用本地镜像,没有就拉取在线镜像。
            startupProbe: # 引用启动探针配置
              httpGet: # 探针方式 基于 http 请求探测
                path: /index.html # http 请求路径
                port: 80 # http 请求端口
              timeoutSeconds: 5 # 请求的超时时间
              periodSeconds: 5 # 监测间隔时间
              successThreshold: 1 # 多少次检测成功才算成功
              failureThreshold: 2 # 失败多少次才算真正失败
            command: # 指定容器启动时执行的命令
            - nginx
            - -g
            - 'daemon off;'  # 执行的命令就是 nginx -g 'daemon off;'
            workingDir: /usr/share/nginx/html # 定义容器启动后的工作目录
            ports:
            - name: http # 端口名称
              containerPort: 80 # 描述容器内要暴露什么端口
              protocol: TCP # 描述改端口是基于那种协议通信的
            env: # 环境变量
            - name: JVM_OPTS # 环境变量名称
              value: '-Xms128m -Xmx128m' # 环境变量的值
            resources:
              requests: # 最少需要多少资源
                cpu: 0.1  # 限制 cpu 最少使用 0.1 个核心  
                memory: 100Mi  # 限制内存最少使用 128 兆
              limits: # 最多可以用多少资源
                cpu: 0.2  # 限制 cpu 最多使用 0.2 个核心
                memory: 100Mi # 限制内存最多使用 200 兆
          restartPolicy: OnFailure # 重启策略, 只有失败的情况才会重启
        

        启动成功

        在这里插入图片描述

      • 类型StartupProbe, 方式TCPSocketAction

        apiVersion: v1 # api文档版本
        kind: Pod # 资源对象类型, 也可以配置为像Deployement、StatefulSet这一类的对象
        metadata: # pod 相关的元数据, 用于描述pod
          name: nginx-pod # pod的名称
          labels: # 定义pod的标签
            type: app # 自定义label标签, 名称为 type, 值为 app
            test: 1.0.0 # 自定义label标签, 描述 pod 版本号
          namespace: 'default' # 命名空间的配置
        spec: # 期望pod按照这里面的描述, 进行创建
          containers: # 对于pod中容器的描述
          - name: nginx # 容器的名称
            image: nginx:1.7.9 # 指定容器镜像
            imagePullPolicy: IfNotPresent # 如果本地有镜像就使用本地镜像,没有就拉取在线镜像。
            startupProbe: # 引用启动探针配置
              tcpSocket: # 探针方式 基于 tcp socket 请求探测
                port: 80 # tcp socket 链接端口
              timeoutSeconds: 5 # 请求的超时时间
              periodSeconds: 5 # 监测间隔时间
              successThreshold: 1 # 多少次检测成功才算成功
              failureThreshold: 2 # 失败多少次才算真正失败
            command: # 指定容器启动时执行的命令
            - nginx
            - -g
            - 'daemon off;'  # 执行的命令就是 nginx -g 'daemon off;'
            workingDir: /usr/share/nginx/html # 定义容器启动后的工作目录
            ports:
            - name: http # 端口名称
              containerPort: 80 # 描述容器内要暴露什么端口
              protocol: TCP # 描述改端口是基于那种协议通信的
            env: # 环境变量
            - name: JVM_OPTS # 环境变量名称
              value: '-Xms128m -Xmx128m' # 环境变量的值
            resources:
              requests: # 最少需要多少资源
                cpu: 0.1  # 限制 cpu 最少使用 0.1 个核心  
                memory: 100Mi  # 限制内存最少使用 128 兆
              limits: # 最多可以用多少资源
                cpu: 0.2  # 限制 cpu 最多使用 0.2 个核心
                memory: 100Mi # 限制内存最多使用 200 兆
          restartPolicy: OnFailure # 重启策略, 只有失败的情况才会重启
        

        在这里插入图片描述

      • 类型StartupProbe, 方式ExecAction

        apiVersion: v1 # api文档版本
        kind: Pod # 资源对象类型, 也可以配置为像Deployement、StatefulSet这一类的对象
        metadata: # pod 相关的元数据, 用于描述pod
          name: nginx-pod # pod的名称
          labels: # 定义pod的标签
            type: app # 自定义label标签, 名称为 type, 值为 app
            test: 1.0.0 # 自定义label标签, 描述 pod 版本号
          namespace: 'default' # 命名空间的配置
        spec: # 期望pod按照这里面的描述, 进行创建
          containers: # 对于pod中容器的描述
          - name: nginx # 容器的名称
            image: nginx:1.7.9 # 指定容器镜像
            imagePullPolicy: IfNotPresent # 如果本地有镜像就使用本地镜像,没有就拉取在线镜像。
            startupProbe: # 引用启动探针配置
              exec: # 执行命令的方式
                command: # 命令行
                - sh
                - -c
                - "echo success > /inited" # 最终执行的命令  sh -c "echo success > /inited"
              timeoutSeconds: 5 # 请求的超时时间
              periodSeconds: 5 # 监测间隔时间
              successThreshold: 1 # 多少次检测成功才算成功
              failureThreshold: 2 # 失败多少次才算真正失败
            command: # 指定容器启动时执行的命令
            - nginx
            - -g
            - 'daemon off;'  # 执行的命令就是 nginx -g 'daemon off;'
            workingDir: /usr/share/nginx/html # 定义容器启动后的工作目录
            ports:
            - name: http # 端口名称
              containerPort: 80 # 描述容器内要暴露什么端口
              protocol: TCP # 描述改端口是基于那种协议通信的
            env: # 环境变量
            - name: JVM_OPTS # 环境变量名称
              value: '-Xms128m -Xmx128m' # 环境变量的值
            resources:
              requests: # 最少需要多少资源
                cpu: 0.1  # 限制 cpu 最少使用 0.1 个核心
                memory: 100Mi  # 限制内存最少使用 128 兆
              limits: # 最多可以用多少资源
                cpu: 0.2  # 限制 cpu 最多使用 0.2 个核心
                memory: 100Mi # 限制内存最多使用 200 兆
          restartPolicy: OnFailure # 重启策略, 只有失败的情况才会重启
        

        在这里插入图片描述

        在指定容器执行命令行

        kubectl exec -it pod名称 -c 容器名称 -- 命令行
        
        kubectl exec -it nginx-po -c nginx -- cat /inited
        
    2. 类型LivenessProbe

      • 类型LivenessProbe, 方式HTTPGetAction (其他, 同上)

        apiVersion: v1 # api文档版本
        kind: Pod # 资源对象类型, 也可以配置为像Deployement、StatefulSet这一类的对象
        metadata: # pod 相关的元数据, 用于描述pod
          name: nginx-liveness-pod # pod的名称
          labels: # 定义pod的标签
            type: app # 自定义label标签, 名称为 type, 值为 app
            test: 1.0.0 # 自定义label标签, 描述 pod 版本号
          namespace: 'default' # 命名空间的配置
        spec: # 期望pod按照这里面的描述, 进行创建
          containers: # 对于pod中容器的描述
          - name: nginx # 容器的名称
            image: nginx:1.7.9 # 指定容器镜像
            imagePullPolicy: IfNotPresent # 如果本地有镜像就使用本地镜像,没有就拉取在线镜像。
            startupProbe: # 引用启动探针配置
              exec: # 执行命令的方式
                command: # 命令行
                - sh
                - -c
                - "echo success > /inited" # 最终执行的命令  sh -c "echo success > /inited"
              timeoutSeconds: 5 # 请求的超时时间
              periodSeconds: 5 # 监测间隔时间
              successThreshold: 1 # 多少次检测成功才算成功
              failureThreshold: 2 # 失败多少次才算真正失败
            livenessProbe: # 引用存活探针配置
              httpGet: # 探针方式 基于 http 请求探测
                path: /started.html # http 请求路径
                port: 80 # http 请求端口
              timeoutSeconds: 5 # 请求的超时时间
              periodSeconds: 10 # 监测间隔时间
              successThreshold: 1 # 多少次检测成功才算成功
              failureThreshold: 3 # 失败多少次才算真正失败
            command: # 指定容器启动时执行的命令
            - nginx
            - -g
            - 'daemon off;'  # 执行的命令就是 nginx -g 'daemon off;'
            workingDir: /usr/share/nginx/html # 定义容器启动后的工作目录
            ports:
            - name: http # 端口名称
              containerPort: 80 # 描述容器内要暴露什么端口
              protocol: TCP # 描述改端口是基于那种协议通信的
            env: # 环境变量
            - name: JVM_OPTS # 环境变量名称
              value: '-Xms128m -Xmx128m' # 环境变量的值
            resources:
              requests: # 最少需要多少资源
                cpu: 0.1  # 限制 cpu 最少使用 0.1 个核心  
                memory: 100Mi  # 限制内存最少使用 128 兆
              limits: # 最多可以用多少资源
                cpu: 0.2  # 限制 cpu 最多使用 0.2 个核心
                memory: 100Mi # 限制内存最多使用 200 兆
          restartPolicy: OnFailure # 重启策略, 只有失败的情况才会重启
        

        刚开始没有started.html, 所以重启了4次, 当我创建好这个文件, 放到对应容器下的时候, 该pod启动成功

        在这里插入图片描述

    3. 类型ReadinessProbe

      • 类型ReadinessProbe, 方式HTTPGetAction (其他, 同上)

        apiVersion: v1 # api文档版本
        kind: Pod # 资源对象类型, 也可以配置为像Deployement、StatefulSet这一类的对象
        metadata: # pod 相关的元数据, 用于描述pod
          name: nginx-readiness-pod # pod的名称
          labels: # 定义pod的标签
            type: app # 自定义label标签, 名称为 type, 值为 app
            test: 1.0.0 # 自定义label标签, 描述 pod 版本号
          namespace: 'default' # 命名空间的配置
        spec: # 期望pod按照这里面的描述, 进行创建
          containers: # 对于pod中容器的描述
          - name: nginx # 容器的名称
            image: nginx:1.7.9 # 指定容器镜像
            imagePullPolicy: IfNotPresent # 如果本地有镜像就使用本地镜像,没有就拉取在线镜像。
            startupProbe: # 引用启动探针配置
              exec: # 执行命令的方式
                command: # 命令行
                - sh
                - -c
                - "echo success > /inited" # 最终执行的命令  sh -c "echo success > /inited"
              timeoutSeconds: 5 # 请求的超时时间
              periodSeconds: 5 # 监测间隔时间
              successThreshold: 1 # 多少次检测成功才算成功
              failureThreshold: 2 # 失败多少次才算真正失败
            readinessProbe: # 引用就绪探针配置
              httpGet: # 探针方式 基于 http 请求探测
                path: /started.html # http 请求路径
                port: 80 # http 请求端口
              timeoutSeconds: 5 # 请求的超时时间
              periodSeconds: 10 # 监测间隔时间
              successThreshold: 1 # 多少次检测成功才算成功
              failureThreshold: 3 # 失败多少次才算真正失败
            command: # 指定容器启动时执行的命令
            - nginx
            - -g
            - 'daemon off;'  # 执行的命令就是 nginx -g 'daemon off;'
            workingDir: /usr/share/nginx/html # 定义容器启动后的工作目录
            ports:
            - name: http # 端口名称
              containerPort: 80 # 描述容器内要暴露什么端口
              protocol: TCP # 描述改端口是基于那种协议通信的
            env: # 环境变量
            - name: JVM_OPTS # 环境变量名称
              value: '-Xms128m -Xmx128m' # 环境变量的值
            resources:
              requests: # 最少需要多少资源
                cpu: 0.1  # 限制 cpu 最少使用 0.1 个核心  
                memory: 100Mi  # 限制内存最少使用 128 兆
              limits: # 最多可以用多少资源
                cpu: 0.2  # 限制 cpu 最多使用 0.2 个核心
                memory: 100Mi # 限制内存最多使用 200 兆
          restartPolicy: OnFailure # 重启策略, 只有失败的情况才会重启
        

        当访问不到started.html, 它一直是不健康状态, 所以我们ready一直都是0, 当我们把对应的文件, 拷贝到对应容器下, 探针再次请求是, 找到了, ready就变成1

        在这里插入图片描述

2.2、生命周期

在这里插入图片描述

lifecycle: # 生命周期的配置
  postStart: # 容创建完成后执行的动作,不能保证该操作一定在容器的 command 之前执行,一般不使用
    exec: # 可以是 exec / httpGet / tcpSocket
      command:
        - sh
        - -c
        - "echo '<h1>pre stop</h1>' > /usr/share/nginx/html/prestop.html"
  preStop: # 在容器停止前执行的动作
    httpGet: # 发送一个 http 请求
      path: /
      port: 80
    exec: # 执行一个命令
      command:
        - sh
        - -c
        - "sleep 50; echo 'sleep finished...' >> /usr/share/nginx/html/prestop.html"

整个yaml

apiVersion: v1 # api文档版本
kind: Pod # 资源对象类型, 也可以配置为像Deployement、StatefulSet这一类的对象
metadata: # pod 相关的元数据, 用于描述pod
  name: nginx-prestop-pod # pod的名称
  labels: # 定义pod的标签
    type: app # 自定义label标签, 名称为 type, 值为 app
    test: 1.0.0 # 自定义label标签, 描述 pod 版本号
  namespace: 'default' # 命名空间的配置
spec: # 期望pod按照这里面的描述, 进行创建
  containers: # 对于pod中容器的描述
  - name: nginx # 容器的名称
    image: nginx:1.7.9 # 指定容器镜像
    imagePullPolicy: IfNotPresent # 如果本地有镜像就使用本地镜像,没有就拉取在线镜像。
    lifecycle: # 生命周期的配置
      postStart: # 生命周期启动阶段做的事情,  不一定在容器的 command 之前执行
        exec:
          command:
          - sh
          - -c
          - "echo '<h1>pre stop</h1>' > /usr/share/nginx/html/prestop.html"
      preStop: # 生命周期销毁阶段做的事情
        exec:
          command:
          - sh
          - -c
          - "sleep 50; echo 'sleep finished...' >> /usr/share/nginx/html/prestop.html"
    command: # 指定容器启动时执行的命令
    - nginx
    - -g
    - 'daemon off;'  # 执行的命令就是 nginx -g 'daemon off;'
    workingDir: /usr/share/nginx/html # 定义容器启动后的工作目录
    ports:
    - name: http # 端口名称
      containerPort: 80 # 描述容器内要暴露什么端口
      protocol: TCP # 描述改端口是基于那种协议通信的
    env: # 环境变量
    - name: JVM_OPTS # 环境变量名称
      value: '-Xms128m -Xmx128m' # 环境变量的值
    resources:
      requests: # 最少需要多少资源
        cpu: 0.1  # 限制 cpu 最少使用 0.1 个核心  
        memory: 100Mi  # 限制内存最少使用 128 兆
      limits: # 最多可以用多少资源
        cpu: 0.2  # 限制 cpu 最多使用 0.2 个核心
        memory: 100Mi # 限制内存最多使用 200 兆
  restartPolicy: OnFailure # 重启策略, 只有失败的情况才会重启
  1. Pod 退出流程

    • 删除操作

      • Endpoint 删除 pod 的 ip 地址

        当我们的销毁容器的时间大于删除pod的时间的时候prestop不会被执行, 因为pod不会等容器执行prestop从时间上也能看到, 原因就是默认terminationGracePeriodSeconds: 30。

        在这里插入图片描述

        在这里插入图片描述

      • Pod 变成 Terminating 状态

        变为删除中的状态后,会给 pod 一个宽限期,让 pod 去执行一些清理或销毁操作。
        配置参数:
        # 作用与 pod 中的所有容器
        terminationGracePeriodSeconds: 40
        containers:
          - xxx
        
        apiVersion: v1 # api文档版本
        kind: Pod # 资源对象类型, 也可以配置为像Deployement、StatefulSet这一类的对象
        metadata: # pod 相关的元数据, 用于描述pod
          name: nginx-prestop-pod # pod的名称
          labels: # 定义pod的标签
            type: app # 自定义label标签, 名称为 type, 值为 app
            test: 1.0.0 # 自定义label标签, 描述 pod 版本号
          namespace: 'default' # 命名空间的配置
        spec: # 期望pod按照这里面的描述, 进行创建
          terminationGracePeriodSeconds: 40 # 当 pod 被删除时, 给这个 pod 宽限多长时间
          containers: # 对于pod中容器的描述
          - name: nginx # 容器的名称
            image: nginx:1.7.9 # 指定容器镜像
            imagePullPolicy: IfNotPresent # 如果本地有镜像就使用本地镜像,没有就拉取在线镜像。
            lifecycle: # 生命周期的配置
              postStart: # 生命周期启动阶段做的事情,  不一定在容器的 command 之前执行
                exec:
                  command:
                  - sh
                  - -c
                  - "echo '<h1>pre stop</h1>' > /usr/share/nginx/html/prestop.html"
              preStop: # 生命周期销毁阶段做的事情
                exec:
                  command:
                  - sh
                  - -c
                  - "sleep 50; echo 'sleep finished...' >> /usr/share/nginx/html/prestop.html"
            command: # 指定容器启动时执行的命令
            - nginx
            - -g
            - 'daemon off;'  # 执行的命令就是 nginx -g 'daemon off;'
            workingDir: /usr/share/nginx/html # 定义容器启动后的工作目录
            ports:
            - name: http # 端口名称
              containerPort: 80 # 描述容器内要暴露什么端口
              protocol: TCP # 描述改端口是基于那种协议通信的
            env: # 环境变量
            - name: JVM_OPTS # 环境变量名称
              value: '-Xms128m -Xmx128m' # 环境变量的值
            resources:
              requests: # 最少需要多少资源
                cpu: 0.1  # 限制 cpu 最少使用 0.1 个核心  
                memory: 100Mi  # 限制内存最少使用 128 兆
              limits: # 最多可以用多少资源
                cpu: 0.2  # 限制 cpu 最多使用 0.2 个核心
                memory: 100Mi # 限制内存最多使用 200 兆
          restartPolicy: OnFailure # 重启策略, 只有失败的情况才会重启
        

        当我们把terminationGracePeriodSeconds: 40 的时候, 我们销毁容器的时间就是根据这个时间

        在这里插入图片描述

        在这里插入图片描述

      • 执行 preStop 的指令

  2. PreStop 的应用

    如果应用销毁操作耗时需要比较长,可以在 preStop 按照如下方式进行配置
    preStop:
      exec:
        command:
          - sh
          - -c
          - 'sleep 20; kill pgrep java'
    但是需要注意,由于 k8s 默认给 pod 的停止宽限时间为 30s,如果我们停止操作会超过 30s 时,不要光设置 sleep 50,还要将 terminationGracePeriodSeconds: 30 也更新成更长的时间,否则 k8s 最多只会在这个时间的基础上再宽限几秒,不会真正等待 50s
    
    • 注册中心下线
    • 数据清理
    • 数据销毁

3、资源调度

3.1、Label 和 Selector

  1. 标签(Label)

    • 配置文件

      在各类资源的 metadata.labels 中进行配置
      
    • kubectl

      • 临时创建 label

        kubectl label 资源类型 资源名称 标签key=标签value (看资源所属名称空间加 -n 名称空间)
        kubectl label po nginx-pod app=hello
        

        在这里插入图片描述

      • 修改已经存在的标签

        kubectl label 资源类型 节点名称 与存在的标签key=标签value --overwrite
        kubectl label po nginx-pod app=hello2 --overwrite
        

        在这里插入图片描述

      • 查看 label

        selector 按照 label 单值查找节点

        kubectl get po -A -l app=hello2
        

        在这里插入图片描述

        查看单个资源的 labels

        kubectl get po nginx-pod --show-labels
        

        在这里插入图片描述

        查看所有资源的 labels (查询指定名称空间lables 加 -n 名称空间)

        kubectl get po --show-labels
        

        在这里插入图片描述

        在这里插入图片描述

  2. 选择器(Selector)

    • 配置文件

      在各对象的配置 spec.selector 或其他可以写 selector 的属性中编写
      
    • kubectl

      # 匹配单个值,查找 app=hello 的 pod
      # -A 显示名称空间 -l 条件匹配
      kubectl get po -A -l app=hello
      
      # 匹配多个值 标签k8s-app 等于 metrics-server 或 kubernetes-dashboard 都显示出来
      kubectl get po -A -l 'k8s-app in (metrics-server, kubernetes-dashboard)'
      
      # 查找 version!=1 and app=nginx 的 pod 信息
      kubectl get po -l version!=1,app=nginx
      
      # 不等值 + 语句
      kubectl get po -A -l version!=1,'app in (busybox, nginx)'
      

3.2、Deployment

deployment包含replicaset包含pod, 从下图就能看出来 也 可以通过 kubectl get po,rs,deploy 命令查看对应的name

在这里插入图片描述

  1. 功能

    • 创建

      创建一个 deployment
      kubectl create deploy nginx-deploy --image=nginx:1.7.9
      或执行
      kubectl create -f xxx.yaml --record
      --record 会在 annotation 中记录当前命令创建或升级了资源,后续可以查看做过哪些变动操作。
      查看部署信息
      kubectl get deployments
      查看 rs
      kubectl get rs
      查看 pod 以及展示标签,可以看到是关联的那个 rs
      kubectl get pods --show-labels
      
    • 滚动更新

      在这里插入图片描述

      先把副本数改为3才能体现滚动更新的过程, 我这里随手随便也加了个自定义标签

      在这里插入图片描述

      在这里插入图片描述

      原来rs的值

      在这里插入图片描述

      只有修改了 deployment 配置文件中的 template 中的属性后,才会触发更新操作
      
      修改 nginx 版本号
      kubectl set image deployment/nginx-deploy nginx=nginx:1.9.1 --record
      或者通过 kubectl edit deployment/nginx-deploy 进行修改
      
      查看滚动更新的过程
      kubectl rollout status deploy <deploy name> <-n <namespace>>
      

      在这里插入图片描述

      查看部署描述,最后展示发生的事件列表也可以看到滚动更新过程
      kubectl describe deploy <deploy name> <-n <namespace>>
      

      在这里插入图片描述

      通过 kubectl get deploy <deploy name> <-n <namespace>> 获取部署信息,UP-TO-DATE 表示已经有多少副本达到了配置中要求的数目
      

      在这里插入图片描述

      滚动跟更新后rs的值

      通过 kubectl get rs 可以看到增加了一个新的 rs
      

      在这里插入图片描述

      通过 kubectl get pods 可以看到所有 pod 关联的 rs 变成了新的
      

      在这里插入图片描述

      • 多个滚动更新并行

        假设当前有 5 个 nginx:1.7.9 版本,你想将版本更新为 1.9.1,当更新成功第三个以后,你马上又将期望更新的版本改为 1.9.2,那么此时会立马删除之前的三个,并且立马开启更新 1.9.2 的任务
        
    • 回滚

      有时候你可能想回退一个Deployment,例如,当Deployment不稳定时,比如一直crash looping。
      
      默认情况下,kubernetes会在系统中保存前两次的Deployment的rollout历史记录,以便你可以随时会退(你可以修改revision history limit来更改保存的revision数)。
      
      案例:
      更新 deployment 时参数不小心写错,如 nginx:1.9.1 写成了 nginx:1.91
      kubectl set image deployment/nginx-deploy nginx=nginx:1.91 --record
      
      监控滚动升级状态,由于镜像名称错误,下载镜像失败,因此更新过程会卡住
      kubectl rollout status deployments nginx-deploy
      
      结束监听后,获取 rs 信息,我们可以看到新增的 rs 副本数是 2 个
      kubectl get rs
      

      在这里插入图片描述

      通过 kubectl get pods 获取 pods 信息,我们可以看到关联到新的 rs 的 pod,状态处于 ImagePullBackOff 状态
      

      在这里插入图片描述

      为了修复这个问题,我们需要找到需要回退的 revision 进行回退
      通过 kubectl rollout history deployment/nginx-deploy 可以获取 revison 的列表
      

      在这里插入图片描述

      通过 kubectl rollout history deployment/nginx-deploy --revision=2 可以查看详细信息
      

      在这里插入图片描述

      确认要回退的版本后,可以通过 kubectl rollout undo deployment/nginx-deploy 可以回退到上一个版本
      
      也可以回退到指定的 revision
      kubectl rollout undo deployment/nginx-deploy --to-revision=2
      
      再次通过 kubectl get deployment 和 kubectl describe deployment 可以看到,我们的版本已经回退到对应的 revison 上了
      

      在这里插入图片描述
      在这里插入图片描述

      可以通过设置 .spec.revisonHistoryLimit 来指定 deployment 保留多少 revison,如果设置为 0,则不允许 deployment 回退了。
      

      在这里插入图片描述

    • 扩容缩容

      通过 kube scale 命令可以进行自动扩容/缩容,以及通过 kube edit 编辑 replcas 也可以实现扩容/缩容
      kubectl scale --replicas=扩容/缩容数量 deploy deploy名称
      kubectl scale --replicas=3 deploy nginx-deploy
      
      
      扩容与缩容只是直接创建副本数,没有更新 pod template 因此不会创建新的 rs
      
    • 暂停与恢复

      由于每次对 pod template 中的信息发生修改后,都会触发更新 deployment 操作,那么此时如果频繁修改信息,就会产生多次更新,而实际上只需要执行最后一次更新即可,当出现此类情况时我们就可以暂停 deployment 的 rollout
      
      通过 kubectl rollout pause deploy <name>  就可以实现暂停,直到你下次恢复后才会继续进行滚动更新
      
      尝试对容器进行修改,然后查看是否发生更新操作了
      kubectl set image deploy <name>  nginx=nginx:1.17.9 --record
      kubectl get po 
      

      在这里插入图片描述

      通过以上操作可以看到实际并没有发生修改,此时我们再次进行修改一些属性,如限制 nginx 容器的最大cpu为 0.2 核,最大内存为 128M,最小内存为 64M,最小 cpu 为 0.1 核
      kubectl set resources deploy nginx-deploy --limits=cpu=200m,memory=128Mi --requests=cpu=100m,memory=64Mi --record
      
      通过格式化输出 kubectl get deploy -o yaml,可以看到配置确实发生了修改,再通过 kubectl get po 可以看到 pod 没有被更新
      

      在这里插入图片描述

      在这里插入图片描述

      在这里插入图片描述

      那么此时我们再恢复 rollout,通过命令 kubectl rollout resume deploy <name> 
      
      恢复后,我们再次查看 rs 和 po 信息,我们可以看到就开始进行滚动更新操作了
      kubectl get rs
      kubectl get po
      

      在这里插入图片描述

  2. 配置文件

    apiVersion: apps/v1 # deployment api 版本
    kind: Deployment # 资源类型为 deployment
    metadata: # 元信息
      labels: # 标签
        app: nginx-deploy # 具体的 key: value 配置形式
      name: nginx-deploy # deployment 的名字
      namespace: default # 所在的命名空间
    spec:
      replicas: 1 # 期望副本数
      revisionHistoryLimit: 10 # 进行滚动更新后,保留的历史版本数
      selector: # 选择器,用于找到匹配的 RS
        matchLabels: # 按照标签匹配
          app: nginx-deploy # 匹配的标签key/value
      strategy: # 更新策略
        rollingUpdate: # 滚动更新配置
          maxSurge: 25% # 进行滚动更新时,更新的个数最多可以超过期望副本数的个数/比例
          maxUnavailable: 25% # 进行滚动更新时,最大不可用比例更新比例,表示在所有副本数中,最多可以有多少个不更新成功
        type: RollingUpdate # 更新类型,采用滚动更新
      template: # pod 模板
        metadata: # pod 的元信息
          labels: # pod 的标签
            app: nginx-deploy
        spec: # pod 期望信息
          containers: # pod 的容器
          - image: nginx:1.7.9 # 镜像
            imagePullPolicy: IfNotPresent # 拉取策略
            name: nginx # 容器名称
          restartPolicy: Always # 重启策略
          terminationGracePeriodSeconds: 30 # 删除操作最多宽限多长时间
    

3.3、StatefulSet

在这里插入图片描述

  1. 功能

    • 创建

      kubectl create -f web.yaml 
      
      # 查看 service 和 statefulset => sts
      kubectl get service nginx
      kubectl get statefulset web
      
      # 查看 PVC 信息
      kubectl get pvc
      
      # 查看创建的 pod,这些 pod 是有序的
      kubectl get pods -l app=nginx
      
      # 查看这些 pod 的 dns
      # 运行一个 pod,基础镜像为 busybox 工具包,利用里面的 nslookup 可以看到 dns 信息
      kubectl run -it --image busybox:1.28.4 dns-test # 永久的
      kubectl run -it --image busybox:1.28.4 dns-test --restart=Never --rm /bin/sh # 退出以后自动删除
      nslookup web-0.nginx
      

      在这里插入图片描述

    • 扩容缩容

      # 扩容
      kubectl scale statefulset web --replicas=5
      # 缩容
      kubectl scale statefulset web --replicas=2
      
      或者
      
      # 扩容
      kubectl patch statefulset web -p '{"spec":{"replicas":5}}'
      # 缩容
      kubectl patch statefulset web -p '{"spec":{"replicas":2}}'
      
    • 镜像更新

      # 镜像更新(目前还不支持直接更新 image,需要 patch 来间接实现)
      
      kubectl patch sts 名称 --type='什么类型的操作' -p='[{"op": "什么操作", "path": "要替换标签的路径(这里写了个0代表是第0个容器)", "value":"对应标签的值"}]'
      
      # /spec/template/spec/containers/0/image 意思是spec下的template下的spec下的containers下的第0个容器的image
      
      kubectl patch sts web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"nginx:1.9.1"}]'
      
      或者
      
      kubectl edit sts 名称
      kubectl edit sts web
      
      通过 kubectl rollout history sts web  可以获取 revison 的列表
      
      通过 kubectl rollout history sts web --revision=2 可以查看指定版本详细信息
      
      • RollingUpdate (滚动更新)

        StatefulSet  也可以采用滚动更新策略,同样是修改 pod template 属性后会触发更新,但是由于 pod 是有序的,在 StatefulSet 中更新时是基于 pod 的顺序倒序更新的
        
        • 灰度发布 (金丝雀发布)

          在这里插入图片描述

          利用滚动更新中的 partition 属性,可以实现简易的灰度发布的效果
          
          **例如我们有 5 个 pod,如果当前 partition 设置为 3,那么此时滚动更新时,只会更新那些 序号 >= 3 的 pod
          
          **利用该机制,我们可以通过控制 partition 的值,来决定只更新其中一部分 pod,确认没有问题后再主键增大更新的 pod 数量,最终实现全部 pod 更新
          

          这里设置的是0标识全部更新

          在这里插入图片描述

          我们先把副本数搞5个出来

          在这里插入图片描述

          然后通过edit修改镜像和partition属性

          在这里插入图片描述

          在这里插入图片描述

          查看3, 4

          在这里插入图片描述

          查看0, 1, 2

          在这里插入图片描述

          当这个属性partition在设置多少的时候就更新多少, 设置为0表示全部更新

      • OnDelete

        只有在 pod 被删除时会进行更新操作
        

        把更新策略改为OnDelete

        在这里插入图片描述

        我们在次edit编辑把镜像改为1.9.1

        在这里插入图片描述

        我们查看web-4它并没有更新为1.9.1

        在这里插入图片描述

        当我们删除web-4以后, 发现它会自动帮我们按照修改后的yaml创建一个1.9.1的pod

        在这里插入图片描述

        在这里插入图片描述

        但是我们查看0, 1, 2, 3, 还是没有更新, 想要更新, 全部都直接删除, 它会自动帮我们按照新的yaml创建新的pod

        在这里插入图片描述

    • 删除

      # 删除 StatefulSet 和 Headless Service
      # 级联删除:删除 statefulset 时会同时删除 pods
      kubectl delete statefulset web
      
      # 删除 service
      kubectl delete service nginx
      

      在这里插入图片描述

      # 非级联删除:删除 statefulset 时不会删除 pods,删除 sts 后,pods 就没人管了,此时再删除 pod 不会重建的
      kubectl delete sts web --cascade=false
      
      # 删除对应的pod
      kubectl delete po web-0 web-1
      
      # 删除 service
      kubectl delete service nginx
      

      在这里插入图片描述

    • 删除 pvc

      # StatefulSet删除后PVC还会保留着,数据不再使用的话也需要删除
      kubectl delete pvc www-web-0 www-web-1
      
  2. 配置文件web.xml

    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      ports:
      - port: 80
        name: web
      clusterIP: None
      selector:
        app: nginx
    ---
    apiVersion: apps/v1 # StatefulSet api 版本
    kind: StatefulSet # 资源类型为 StatefulSet
    metadata:
      name: web # StatefulSet 对象的名字
    spec:
      serviceName: "nginx" # 使用那个 service 来管理dns
      replicas: 2 # 期望副本数
      selector:
        matchLabels: # 匹配labels
          app: nginx
      template: # pod 模板
        metadata: # pod 的元信息
          labels:  # pod 的标签
            app: nginx
        spec:  # pod 期望信息
          containers:  # pod 的容器
          - name: nginx # 容器名称
            image: nginx:1.7.9 # 镜像
            ports: # 容器内部要暴露的端口
            - containerPort: 80 # 具体暴露的端口号
              name: web # 该端口配置的名字
    #        volumeMounts: # 加载数据卷
    #        - name: www # 指定加载那个数据卷
    #          mountPath: /usr/share/nginx/html # 加载到容器中的那个目录 
    #  volumeClaimTemplates: # 数据卷模版
    #  - metadata: # 数据卷描述
    #      name: www # 数据卷的名称
    #      annotations: # 数据卷的注解
    #        volume.alpha.kubernetes.io/storage-class: anything
    #    spec: # 数据卷的规约
    #      accessModes: [ "ReadWriteOnce" ] # 访问模式
    #      resources:
    #        requests: # 最少需要多少资源
    #          storage: 1Gi # 需要 1G 的存储资源
    

3.4、DaemonSet

在这里插入图片描述

在这里插入图片描述

  1. 配置文件

    apiVersion: apps/v1 # # daemonset api 版本
    kind: DaemonSet # 创建 DaemonSet 资源
    metadata:
      name: fluentd # 名字
    spec:
      selector: # 选择器,用于找到匹配的 pod
        matchLabels: # 按照标签匹配
          app: logging # # 匹配的标签key/value
      template:
        metadata: # pod 的元信息
          labels: # pod 的标签
            app: logging
            id: fluentd
          name: fluentd # pod 名称
        spec:
          containers:
          - name: fluentd-es # 容器名称
            image: agilestacks/fluentd-elasticsearch:v1.3.0 # 镜像
            env: # 环境变量配置
             - name: FLUENTD_ARGS # 环境变量的 key
               value: -qq # 环境变量的 value
            volumeMounts: # 加载数据卷, 避免数据丢失
             - name: containers # 数据卷的名字
               mountPath: /var/lib/docker/containers # 将数据卷挂载到容器内的那个目录
             - name: varlog
               mountPath: /varlog
          volumes: # 定义数据卷
             - hostPath: # 数据卷类型, 主机路径模式, 也就是与 node 共享目录
                 path: /var/lib/docker/containers # node 中的共享目录
               name: containers # 定义的数据卷的名称
             - hostPath:
                 path: /var/log
               name: varlog
    

    当我不指定Node节点时创建daemonset, 它会在每一个节点中创建

    在这里插入图片描述

  2. 指定 Node 节点

    DaemonSet 会忽略 Node 的 unschedulable 状态,有两种方式来指定 Pod 只运行在指定的 Node 节点上:
        ● nodeSelector:只调度到匹配指定 label 的 Node 上
        ● nodeAffinity:功能更丰富的 Node 选择器,比如支持集合操作
        ● podAffinity:调度到满足条件的 Pod 所在的 Node 上
    
    • nodeSelector

      先为 Node 打上标签
      kubectl label nodes k8s-node1 type=microservices
      

      在这里插入图片描述

      然后再 daemonset 配置中设置 nodeSelector
      spec:
        template:
          spec:
            nodeSelector:
              type: microservices
      

      通过edit编辑对应的daemonset, 新增上面的配置保存

      在这里插入图片描述

      发现只有k8s-node1有了, k8s-node2节点没了, 只要我们给k8s-node2也加上标签type: microservices, 它会自动帮我们在k8s-node2节点中部署daemonset

      在这里插入图片描述

    • nodeAffinity

      nodeAffinity 目前支持两种:requiredDuringSchedulingIgnoredDuringExecution 和 preferredDuringSchedulingIgnoredDuringExecution,分别代表必须满足条件和优选条件。
      比如下面的例子代表调度到包含标签 wolfcode.cn/framework-name 并且值为 spring 或 springboot 的 Node 上,并且优选还带有标签 another-node-label-key=another-node-label-value 的Node。
      apiVersion: v1
      kind: Pod
      metadata:
        name: with-node-affinity
      spec:
        affinity:
          nodeAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
              nodeSelectorTerms:
              - matchExpressions:
                - key: wolfcode.cn/framework-name
                  operator: In
                  values:
                  - spring
                  - springboot
            preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 1
              preference:
                matchExpressions:
                - key: another-node-label-key
                  operator: In
                  values:
                  - another-node-label-value
        containers:
        - name: with-node-affinity
          image: pauseyyf/pause
      
    • podAffinity

      podAffinity 基于 Pod 的标签来选择 Node,仅调度到满足条件Pod 所在的 Node 上,支持 podAffinity 和 podAntiAffinity。这个功能比较绕,以下面的例子为例:
      如果一个 “Node 所在空间中包含至少一个带有 auth=oauth2 标签且运行中的 Pod”,那么可以调度到该 Node
      不调度到 “包含至少一个带有 auth=jwt 标签且运行中 Pod”的 Node 上
      apiVersion: v1
      kind: Pod
      metadata:
        name: with-pod-affinity
      spec:
        affinity:
          podAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                - key: auth
                  operator: In
                  values:
                  - oauth2
              topologyKey: failure-domain.beta.kubernetes.io/zone
          podAntiAffinity:
            preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 100
              podAffinityTerm:
                labelSelector:
                  matchExpressions:
                  - key: auth
                    operator: In
                    values:
                    - jwt
                topologyKey: kubernetes.io/hostname
        containers:
        - name: with-pod-affinity
          image: pauseyyf/pause
      
      
  3. 滚动更新

    不建议使用 RollingUpdate,建议使用 OnDelete 模式,这样避免频繁更新 ds
    

3.5、HPA 自动扩/缩容

通过观察 pod 的 cpu、内存使用率或自定义 metrics 指标进行自动的扩容或缩容 pod 的数量。

通常用于 Deployment,不适用于无法扩/缩容的对象,如 DaemonSet

控制管理器每隔30s(可以通过–horizontal-pod-autoscaler-sync-period修改)查询metrics的资源使用情况
  1. 开启指标服务

    # 下载 metrics-server 组件配置文件
    wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml -O metrics-server-components.yaml
    # 修改镜像地址为国内的地址
    sed -i 's/registry.k8s.io\/metrics-server/registry.cn-hangzhou.aliyuncs.com\/google_containers/g' metrics-server-components.yaml
    
    # 修改容器的 tls 配置,不验证 tls,在 containers 的 args 参数中增加 --kubelet-insecure-tls 参数
    

    在这里插入图片描述

    # 安装组件
    kubectl apply -f metrics-server-components.yaml
    # 查看 pod 状态
    kubectl get pods --all-namespaces | grep metrics
    

    在这里插入图片描述

  2. cpu、内存指标监控

    实现 cpu 或内存的监控,首先有个前提条件是该对象必须配置了 resources.requests.cpu 或 resources.requests.memory 才可以,可以配置当 cpu/memory 达到上述配置的百分比后进行扩容或缩容
    
    创建一个 HPA:
        1. 先准备一个好一个有做资源限制的 deployment
        2. 执行命令 kubectl autoscale deploy nginx-deploy --cpu-percent=20 --min=2 --max=5 # 自动扩容 deploy类型的名字为nginx-deploy, 只要它cpu超过20%自动自动伸缩, 扩容到最小为2, 最大为5个副本
        3. 通过 kubectl get hpa 可以获取 HPA 信息
    

    在这里插入图片描述

    在这里插入图片描述

    由于现在副本有两个, 我们请求只能请求一个所以这里写个service配置

    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-svc
      labels:
        app: nginx
    spec:
      selector:
        app: nginx-deploy # 匹配 pod 标签带 app=nginx-deploy 的pod
      ports:
      - port: 80
        targetPort: 80
        name: web
      type: NodePort
    

    找到对应的ip端口直接死循环请求

    在这里插入图片描述

    测试:找到对应服务的 service,编写循环测试脚本提升内存与 cpu 负载
    while true; do wget -q -O- http:// <ip:port> > /dev/null ; done
    
    可以通过多台机器执行上述命令,增加负载,当超过负载后可以查看 pods 的扩容情况 kubectl get pods
    
    查看 pods 资源使用情况
    kubectl top pods
    

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    扩容测试完成后,再关闭循环执行的指令,让 cpu 占用率降下来,然后过 5 分钟后查看自动缩容情况
    

    当我把2个请求都关闭后, 有会变成2个副本

    在这里插入图片描述

    在这里插入图片描述

  3. 自定义 metrics

    控制管理器开启–horizontal-pod-autoscaler-use-rest-clients
    控制管理器的–apiserver指向API Server Aggregator
    在API Server Aggregator中注册自定义的metrics API
    

4、服务发布

4.1、Service

在这里插入图片描述

负责东西流量(同层级/内部服务网络通信)的通信

  1. Service 的定义

    apiVersion: v1
    kind: Service # 资源类型为service
    metadata: # Service 描述
      name: nginx-svc # service 名字
      labels: # 定义 service 自己本身的标签
        app: nginx
    spec:
      selector: # 匹配那些 pod 会被该 service 代理
        app: nginx-deploy # 所有匹配到这些标签的 pod 都可以通过该 service 进行访问
      ports: # 端口映射
      - port: 80 # service 自己的端口, 在使用内网 ip 访问时使用
        targetPort: 80 # 目标 pod 的端口
        name: web # 为端口起个名字
      type: NodePort # 随机启动一个端口 (30000-32767), 映射到 ports 中的端口, 该端口是直接绑定在 node 上的, 且集群中的每一个 node 都会绑定这个端口
                     # 它也可以用于将服务暴露给外部访问, 但是这种方式实际生产环境不推荐, 效率较低, 而且 service 是四层负载
    
    • 命令操作

      # 创建 service
      kubectl create -f nginx-svc.yaml
      
      # 查看 service 信息,通过 service 的 cluster ip 进行访问
      kubectl get svc 
      
      # 查看 pod 信息,通过 pod 的 ip 进行访问
      kubectl get po -owide
      
      # 创建其他 pod 通过 service name 进行访问(推荐)
      kubectl exec -it dns-test -- sh
      curl http://nginx-svc
      
      # 默认在当前 namespace 中访问,如果需要跨 namespace 访问 pod,则在 service name 后面加上 . 即可
      curl http://nginx-svc.default
      

      在这里插入图片描述

      在这里插入图片描述

    • Endpoint

      在这里插入图片描述

  2. 代理 k8s 外部服务

    实现方式:
        1. 编写 service 配置文件时,不指定 selector 属性就不会自动帮我们创建 endpoint
        2. 自己创建 endpoint
    

    在这里插入图片描述

    endpoint 配置:
    apiVersion: v1
    kind: Endpoints # 资源类型为endpoints
    metadata:
      labels:
        app: nginx # 与 service 一致
      name: nginx-svc-external # 与 service 一致
      namespace: default # 与 service 一致
    subsets:
    - addresses:
      - ip: 120.78.159.117 # 目标 ip 地址
      ports: # 与 service 一致
      - name: web # 与 service 一致
        port: 80
        protocol: TCP
    

    在这里插入图片描述

    在这里插入图片描述

    • 各环境访问名称统一
    • 访问 k8s 集群外的其他服务
    • 项目迁移
  3. 反向代理外部域名

    apiVersion: v1
    kind: Service # 资源类型为service
    metadata:  # Service 描述
      labels: # 定义 service 自己本身的标签
        app: wolfcode-external-domain
      name: wolfcode-external-domain # service 名字
    spec:
      type: ExternalName # 定义目标的 CNAME 别名,可以配置为域名
      externalName: www.wolfcode.cn # 目标域名
    

    在这里插入图片描述

  4. 常用类型

    • ClusterIP

      • 只能在集群内部使用,不配置类型的话默认就是 ClusterIP
    • ExternalName

      • 返回定义的 CNAME 别名,可以配置为域名
    • NodePort

      • 会在所有安装了 kube-proxy 的节点都绑定一个端口,此端口可以代理至对应的 Pod,集群外部可以使用任意节点 ip + NodePort 的端口号访问到集群中对应 Pod 中的服务。

      • 当类型设置为 NodePort 后,可以在 ports 配置中增加 nodePort 配置指定端口,需要在下方的端口范围内,如果不指定会随机指定端口

      • 端口范围:30000~32767

      • 端口范围配置在 /usr/lib/systemd/system/kube-apiserver.service 文件中

    • LoadBalancer

      • 使用云服务商(阿里云、腾讯云等)提供的负载均衡器服务

4.2、Ingress

Ingress 大家可以理解为也是一种 LB 的抽象,它的实现也是支持 nginx、haproxy 等负载均衡服务的

在这里插入图片描述

  1. 安装 ingress-nginx

    https://kubernetes.github.io/ingress-nginx/deploy/#using-helm
    
    • 添加 helm 仓库

      # 添加仓库
      helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
      # 查看仓库列表
      helm repo list
      # 搜索 ingress-nginx
      helm search repo ingress-nginx
      
    • 下载包

      # 下载安装包
      helm pull ingress-nginx/ingress-nginx
      
    • 配置参数

      # 将下载好的安装包解压
      tar xf ingress-nginx-xxx.tgz
      # 解压后,进入解压完成的目录
      cd ingress-nginx
      # 修改 values.yaml
      # 镜像地址:修改为国内镜像
      registry: registry.cn-hangzhou.aliyuncs.com
      image: google_containers/nginx-ingress-controller
      image: google_containers/kube-webhook-certgen
      tag: v1.3.0
      
      hostNetwork: true
      dnsPolicy: ClusterFirstWithHostNet
      
      修改部署配置的 kind: DaemonSet
      nodeSelector:
        ingress: "true" # 增加选择器,如果 node 上有 ingress=true 就部署
        
      将 admissionWebhooks.enabled 修改为 falseservice 中的 type 由 LoadBalancer 修改为 ClusterIP,如果服务器是云平台才用 LoadBalancer
      

      在这里插入图片描述

      在这里插入图片描述

      在这里插入图片描述

      在这里插入图片描述

      在这里插入图片描述

      在这里插入图片描述

      在这里插入图片描述

      在这里插入图片描述

      在这里插入图片描述

      在这里插入图片描述

    • 创建 Namespace

      # 为 ingress 专门创建一个 namespace
      kubectl create ns ingress-nginx
      

      在这里插入图片描述

    • 安装 ingress

      # 为需要部署 ingress 的节点上加标签 (注意, 因为污点原因, 它不能装在master上)
      kubectl label node k8s-node1 ingress=true
      # 安装 ingress-nginx 这个点代表从当前目录下找对应的values.yaml
      helm install ingress-nginx  -n ingress-nginx .
      

      在这里插入图片描述

      在这里插入图片描述

      在这里插入图片描述

  2. 基本使用

    • 创建一个 ingress (注意:记得域名在hosts文件配置, 因为这个域名是我们随便写的)

      apiVersion: networking.k8s.io/v1
      kind: Ingress # 资源类型为 Ingress
      metadata:
        name: xiaoge-nginx-ingress
        annotations:
          kubernetes.io/ingress.class: "nginx" # 固定写法
          nginx.ingress.kubernetes.io/rewrite-target: / # 把匹配到的路径转发的时候都是转发到对应service中 / 开始
      spec:
        rules: # ingress 规则配置,可以配置多个
        - host: k8s.xiaoge.cn # 域名配置,可以使用通配符 *
          http:
            paths: # 相当于 nginx 的 location 配置,可以配置多个
            - pathType: Prefix # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
              backend:
                service: 
                  name: nginx-svc # 代理到哪个 service
                  port: 
                    number: 80 # service 的端口
              path: /api # 等价于 nginx 中的 location 的路径前缀匹配
      

      在这里插入图片描述

      在这里插入图片描述

    • 多域名配置 (注意: Prefix和Exec同时存在, 优先匹配Exact)

      apiVersion: networking.k8s.io/v1
      kind: Ingress # 资源类型为 Ingress
      metadata:
        name: xiaoge-nginx-ingress
        annotations:
          kubernetes.io/ingress.class: "nginx"
          nginx.ingress.kubernetes.io/rewrite-target: / # 把匹配到的理解转发的时候都是转发到对应service中 / 开始
      spec:
        rules: # ingress 规则配置,可以配置多个
        - host: k8s.xiaoge.cn # 域名配置,可以使用通配符 *
          http:
            paths: # 相当于 nginx 的 location 配置,可以配置多个
            - pathType: Prefix # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
              backend:
                service: 
                  name: nginx-svc # 代理到哪个 service
                  port: 
                    number: 80 # service 的端口
              path: /api # 等价于 nginx 中的 location 的路径前缀匹配
            - pathType: Exact # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配>,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
              backend:
                service:
                  name: nginx-svc # 代理到哪个 service
                  port:
                    number: 80 # service 的端口
              path: /
        - host: api.xiaoge.cn # 域名配置,可以使用通配符 *
          http:
            paths: # 相当于 nginx 的 location 配置,可以配置多个
            - pathType: Prefix # 路径类型,按照路径类型进行匹配 ImplementationSpecific 需要指定 IngressClass,具体匹配规则以 IngressClass 中的规则为准。Exact:精确匹配>,URL需要与path完全匹配上,且区分大小写的。Prefix:以 / 作为分隔符来进行前缀匹配
              backend:
                service:
                  name: nginx-svc # 代理到哪个 service
                  port:
                    number: 80 # service 的端口
              path: /
      

5、配置与存储

5.1、配置管理

5.1.1、ConfigMap

一般用于去存储 Pod 中应用所需的一些配置信息,或者环境变量,将配置于 Pod 分开,避免应为修改配置导致还需要重新构建 镜像与容器。

5.1.1.1、创建
使用 kubectl create configmap -h 查看示例,构建 configmap 对象
# 根据目录创建ConfigMap
kubectl create configmap xiaoge-test-config --from-file=/opt/k8s/config/test/

在这里插入图片描述

在这里插入图片描述

# 根据指定文件创建configMap
kubectl create configmap xiaoge-test-yml-config --from-file=/opt/k8s/config/application.yml

在这里插入图片描述

在这里插入图片描述

# 给data去别名创建configMap
kubectl create configmap xiaoge-test-alias-config --from-file=app.yml=/opt/k8s/config/application.yml

在这里插入图片描述

# 自己手写key/value
kubectl create configmap my-config --from-literal=username=xiaoge --from-literal=password=123456

在这里插入图片描述

5.1.1.2、使用 ConfigMap
  • 使用ConfigMap引用key的形式

    apiVersion: v1
    kind: Pod
    metadata:
      name: test-env-po
    spec:
      containers:
        - name: env-test
          image: alpine
          command: ["/bin/sh", "-c", "env;sleep 3600"]
          imagePullPolicy: IfNotPresent
          env:
          - name: JAVA_VM_OPTS # 环境变量的 key
            valueFrom:  # 环境变量的值从哪里来
              configMapKeyRef: # 从 ConfigMap 中来
                name: my-test-env-config # ConfigMap 的名字
                key: JAVA_OPTS_TEST # 表示从 name 的 ConfigMap 中获取名字为 key 的 value , 将其赋值给本地环境变量 JAVA_VM_OPTS
          - name: APP
            valueFrom:
              configMapKeyRef:
                name: my-test-env-config
                key: APP_NAME
      restartPolicy: Never
    

    在这里插入图片描述

  • 使用ConfgMap file的形式

    apiVersion: v1
    kind: Pod
    metadata:
      name: test-file-po
    spec:
      containers:
        - name: file-test
          image: alpine
          command: ["/bin/sh", "-c", "env;sleep 3600"]
          imagePullPolicy: IfNotPresent
          env:
          - name: JAVA_VM_OPTS # 环境变量的 key
            valueFrom:  # 环境变量的值从哪里来
              configMapKeyRef: # 从 ConfigMap 中来
                name: my-test-env-config # ConfigMap 的名字
                key: JAVA_OPTS_TEST # 表示从 name 的 ConfigMap 中获取名字为 key 的 value , 将其赋值给本地环境变量 JAVA_VM_OPTS
          - name: APP
            valueFrom:
              configMapKeyRef:
                name: my-test-env-config
                key: APP_NAME
          volumeMounts: # 加载数据卷
          - name: db-config # 表示加载 volumes 属性中那个数据卷
            mountPath: "/usr/local/mysql/conf" # 想要将数据卷中的文件加载到那个目录下
            readOnly: true # 是否只读
      volumes: # 数据卷挂载 configmap secret
        - name: db-config # 数据卷的名字, 随意设置
          configMap: # 数据卷类型为 ConfigMap
            name: xiaoge-test-config # configMap 的名字, 必须跟想要加载的 configmap 相同
            items: # 对 configmap 中的 key 进行映射, 如果不指定, 默认会将 configmap 中所有 key 全部转换为一个个同名的文件 (不写items, 默认会将所有的key转换成一个个同名文件, 指定了, 就会只转换指定的key)
            - key: "db.properties" # configMap 中的 key
              path: "db.properties" # 将该 key 的值转换为文件
      restartPolicy: Never
    

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

5.1.2、加密数据配置 Secret

与 ConfigMap 类似,用于存储配置信息,但是主要用于存储敏感信息、需要加密的信息,Secret 可以提供数据加密、解密功能。

在创建 Secret 时,要注意如果要加密的字符中,包含了有特殊字符,需要使用转义符转移,例如 $ 转移后为 $,也可以对特殊字符使用单引号描述,这样就不需要转移例如 1$289-! 转换为 '1$289-!'**

# secret 名称为 harbor-secret
kubectl create secret docker-registry harbor-secret --docker-username=admin --docker-password=admin --docker-email=xiaoge@tengxun.cn 

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

上面只是告诉你怎么创建 secret, 后面k8s拉取镜像时需要用到

我们手动登录把本地的nginx镜像打包, 上传到我们自己的harbor远程仓库, (docker怎么安装harbor自己百度)

在这里插入图片描述

在harbor上创建一个opensource的项目, 现在这里面是一个镜像都没有的

在这里插入图片描述

先给当前nginx镜像打一个自己的标签

在这里插入图片描述

在这里插入图片描述

先登入到对应的harbor的仓库服务器

报错显示https, 我们就要让它用http

在这里插入图片描述

# 打开 daemon.json
vi /etc/docker/daemon.json

在这里插入图片描述

systemctl daemon-reload

systemctl restart docker

# 然后再检harbor相关的容器是否都启动成功, 然后再docker login
docker login -uadmin 192.168.171.129:8089

在这里插入图片描述

把我们复制出来的tag镜像上传到远程仓库harbor上

在这里插入图片描述

在这里插入图片描述

上面的只是演示, 现在开始创建真正的secret拉取harbor的镜像

创建secret添加服务地址

在这里插入图片描述

在这里插入图片描述

正常拉取私有仓库镜像是需要认证的 (harbor-secret 就是我们刚刚创建的docker仓库的secret)

# 只需要配置这两行, 再去拉取私有仓库镜像就不需要手动认证了
imagePullSecrets: # 配置仓库 docker registry 的 secret
  - name: harbor-secret # 指定我们创建的secret 
apiVersion: v1
kind: Pod
metadata:
  name: private-image-pull-pod
spec:
  imagePullSecrets: # 配置仓库 docker registry 的 secret
  - name: harbor-secret # 指定我们创建的secret 
  containers:
    - name: nginx
      image: 192.168.171.129:8089/opensource/nginx:1.9.1
      command: ["/bin/sh", "-c", "env;sleep 3600"]
      imagePullPolicy: IfNotPresent
      env:
      - name: JAVA_VM_OPTS # 环境变量的 key
        valueFrom:  # 环境变量的值从哪里来
          configMapKeyRef: # 从 ConfigMap 中来
            name: my-test-env-config # ConfigMap 的名字
            key: JAVA_OPTS_TEST # 表示从 name 的 ConfigMap 中获取名字为 key 的 value , 将其赋值给本地环境变量 JAVA_VM_OPTS
      - name: APP
        valueFrom:
          configMapKeyRef:
            name: my-test-env-config
            key: APP_NAME
      volumeMounts: # 加载数据卷
      - name: db-config # 表示加载 volumes 属性中那个数据卷
        mountPath: "/usr/local/mysql/conf" # 想要将数据卷中的文件加载到那个目录下
        readOnly: true # 是否只读
  volumes: # 数据卷挂载 configmap secret
    - name: db-config # 数据卷的名字, 随意设置
      configMap: # 数据卷类型为 ConfigMap
        name: xiaoge-test-config # configMap 的名字, 必须跟想要加载的 configmap 相同 
        items: # 对 configmap 中的 key 进行映射, 如果不指定, 默认会将 configmap 中所有 key 全部转换为一个个同名的文件
        - key: "db.properties" # configMap 中的 key
          path: "db.properties" # 将该 key 的值转换为文件
  restartPolicy: Never

在这里插入图片描述

在这里插入图片描述

这里没有认证信息是因为我们之前通过docker login 认证过

5.1.3、SubPath 的使用
# 创建 configMap  nginx.conf就是普通nginx.conf内容
kubectl create cm nginx-config-cm --from-file=./nginx.conf

使用 ConfigMap 或 Secret 挂载到目录的时候,会将容器中源目录给覆盖掉,此时我们可能只想覆盖目录中的某一个文件,但是这样的操作会覆盖整个文件,因此需要使用到 SubPath

配置方式:
定义 volumes 时需要增加 items 属性,配置 key 和 path,且 path 的值不能从 / 开始
在容器内的 volumeMounts 中增加 subPath 属性,该值与 volumes 中 items.path 的值相同
containers:
  ......
  volumeMounts: # 挂载数据卷
  - name: nginx-conf # 使用哪个 configmap 或 secret  (如果volumes指定了名称, 那么这里就写volumes的名称)
    mountPath: '/etc/nginx/nginx.conf' # 挂载的路径 (使用了subPath, 一定要写你要替换文件的完整路径)
    subPath: etc/nginx/nginx.conf # 与 volumes.[0].items.path 相同
volumes: # 数据卷定义
- name: nginx-conf # 数据卷名称
  configMap:  # 数据卷类型为 configMap
    name: nginx-config-cm # configMap 名字
    items: # 要将 configmap 中的那些数据挂在进来
      key: nginx.conf # 指定挂在那些 key
      path: etc/nginx/nginx.conf # subPath 路径
5.1.4、配置的热更新
我们通常会将项目的配置文件作为 configmap 然后挂载到 pod,那么如果更新 configmap 中的配置,会不会更新到 pod 中呢?

这得分成几种情况:
默认方式:会更新,更新周期是更新时间 + 缓存时间
subPath:不会更新
变量形式:如果 pod 中的一个变量是从 configmap 或 secret 中得到,同样也是不会更新的 

对于 subPath 的方式,我们可以取消 subPath 的使用,将配置文件挂载到一个不存在的目录,避免目录的覆盖,然后再利用软连接的形式,将该文件链接到目标位置

但是如果目标位置原本就有文件,可能无法创建软链接,此时可以基于前面讲过的 postStart 操作执行删除命令,将默认的吻技安删除即可
5.1.4.1、通过 edit 命令直接修改 configmap
5.1.4.2、通过 replace 替换
由于 configmap 我们创建通常都是基于文件创建,并不会编写 yaml 配置文件,因此修改时我们也是直接修改配置文件,而 replace 是没有 --from-file 参数的,因此无法实现基于源配置文件的替换,此时我们可以利用下方的命令实现

# 该命令的重点在于 --dry-run 参数,该参数的意思打印 yaml 文件,但不会将该文件发送给 apiserver,再结合 -oyaml 输出 yaml 文件就可以得到一个配置好但是没有发给 apiserver 的文件,然后再结合 replace 监听控制台输出得到 yaml 数据即可实现替换
kubectl create cm configMap名称 --from-file=文件 --dry-run -oyaml | kubectl replace -f-

kubectl create cm xiaoge-test-config --from-file=db.properties --dry-run -oyaml | kubectl replace -f-
5.1.5、不可变的 Secret 和 ConfigMap
对于一些敏感服务的配置文件,在线上有时是不允许修改的,此时在配置 configmap 时可以设置 immutable: true 来禁止修改

在这里插入图片描述

5.2、持久化存储

5.2.1、Volumes
5.2.1.1、HostPath

将节点上的文件或目录挂载到 Pod 上,此时该目录会变成持久化存储目录,即使 Pod 被删除后重启,也可以重新加载到该目录,该目录下的文件不会丢失

配置文件

apiVersion: v1
kind: Pod
metadata:
  name: test-volume-pd
spec:
  containers:
  - image: nginx
    name: nginx-volume
    volumeMounts:
    - mountPath: /test-pd # 挂载到容器的哪个目录
      name: test-volume # 挂载哪个 volume
  volumes:
  - name: test-volume
    hostPath: # 与主机共享目录, 加载主机中的指定目录到容器中(主机在这个目录中修改什么东西, 容器马上能感知, 容器中修改什么东西, 主机也马上能感知)
      path: /data # 节点中的目录
      type: DirectoryOrCreate # 检查类型,在挂载前对挂载目录做什么检查操作,有多种选项,默认为空字符串,不做任何检查
类型:
空字符串:默认类型,不做任何检查
DirectoryOrCreate:如果给定的 path 不存在,就创建一个 755 的空目录
Directory:这个目录必须存在
FileOrCreate:如果给定的文件不存在,则创建一个空文件,权限为 644
File:这个文件必须存在
Socket:UNIX 套接字,必须存在
CharDevice:字符设备,必须存在
BlockDevice:块设备,必须存在
5.2.1.2、EmptyDir

EmptyDir 主要用于一个 Pod 中不同的 Container 共享数据使用的由于只是在 Pod 内部使用,因此与其他 volume 比较大的区别是,当 Pod 如果被删除了,那么 emptyDir 也会被删除。

存储介质可以是任意类型,如 SSD、磁盘或网络存储。可以将 emptyDir.medium 设置为 Memory 让 k8s 使用 tmpfs(内存支持文件系统),速度比较快,但是重启 tmpfs 节点时,数据会被清除,且设置的大小会计入到 Container 的内存限制中。

配置文件

apiVersion: v1
kind: Pod
metadata:
  name: empty-dir-pd
spec:
  containers:
  - image: alpine
    name: nginx-emptydir1
    command: ["/bin/sh", "-c", "sleep 3600;"]
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  - image: alpine
    name: nginx-emptydir2
    command: ["/bin/sh", "-c", "sleep 3600;"]
    volumeMounts:
    - mountPath: /opt
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}
    
    
# nginx-emptydir1容器中的/cache和nginx-emptydir2容器中的/opt目录共享, cache中目录里面东西发生改变, opt也跟跟着变, 同理opt发生改变cache目录也会跟着变

# 进入单个容器中
# kubectl exec -it pod名称 -c 容器名称 -- sh  
# kubectl exec -it empty-dir-pd -c nginx-emptydir1 -- sh 
5.2.2、NFS 挂载

nfs 卷能将 NFS (网络文件系统) 挂载到你的 Pod 中。 不像 emptyDir 那样会在删除 Pod 的同时也会被删除,nfs 卷的内容在删除 Pod 时会被保存,卷只是被卸载。 这意味着 nfs 卷可以被预先填充数据,并且这些数据可以在 Pod 之间共享。

5.2.2.1、安装 nfs
# 安装 nfs
yum install nfs-utils -y
# 启动 nfs
systemctl start nfs-server
# 查看 nfs 版本
cat /proc/fs/nfsd/versions
# 创建共享目录
mkdir -p /data/nfs
cd /data/nfs
mkdir rw
mkdir ro
# 设置共享目录 export
vim /etc/exports
/data/nfs/rw 192.168.113.0/24(rw,sync,no_subtree_check,no_root_squash)
/data/nfs/ro 192.168.113.0/24(ro,sync,no_subtree_check,no_root_squash)
# 重新加载
exportfs -f
systemctl reload nfs-server
# 到其他测试节点安装 nfs-utils 并加载测试
mkdir -p /mnt/nfs/rw
mkdir -p /mnt/nfs/ro

mount -t nfs 192.168.171.130:/data/nfs/rw /mnt/nfs/rw
mount -t nfs 192.168.171.130:/data/nfs/ro /mnt/nfs/ro
5.2.2.2、配置文件
apiVersion: v1
kind: Pod
metadata:
  name: nfs-test-pd1
spec:
  containers:
  - image: nginx
    name: test-container
    volumeMounts:
    - mountPath: /usr/share/nginx/html
      name: test-volume
  volumes:
  - name: test-volume
    nfs:
      server: 192.168.171.130 # 网络存储服务地址
      path: /data/nfs/rw/www/xiaoge # 网络存储路径
      readOnly: false # 是否只读
     
# 把nfs中的/data/nfs/rw/www/xiaoge目录, 替换容器中的/usr/share/nginx/html目录, 只要xiaoge目录下的内容修改, 容器中html内容也会跟着更改
5.2.3、PV 与 PVC

持久卷(PersistentVolume,PV) 是集群中的一块存储,可以由管理员事先制备, 或者使用存储类(Storage Class)来动态制备。 持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样, 也是使用卷插件来实现的,只是它们拥有独立于任何使用 PV 的 Pod 的生命周期。 此 API 对象中记述了存储的实现细节,无论其背后是 NFS、iSCSI 还是特定于云平台的存储系统。

持久卷申领(PersistentVolumeClaim,PVC) 表达的是用户对存储的请求。概念上与 Pod 类似。 Pod 会耗用节点资源,而 PVC 申领会耗用 PV 资源。Pod 可以请求特定数量的资源(CPU 和内存);同样 PVC 申领也可以请求特定的大小和访问模式 (例如,可以要求 PV 卷能够以 ReadWriteOnce、ReadOnlyMany 或 ReadWriteMany 模式之一来挂载,参见访问模式)。

5.2.3.1、生命周期
  • 构建

    • 静态构建

      集群管理员创建若干 PV 卷。这些卷对象带有真实存储的细节信息, 并且对集群用户可用(可见)。PV 卷对象存在于 Kubernetes API 中,可供用户消费(使用)。

    • 动态构建

      • 如果集群中已经有的 PV 无法满足 PVC 的需求,那么集群会根据 PVC 自动构建一个 PV,该操作是通过 StorageClass 实现的。

      • 想要实现这个操作,前提是 PVC 必须设置 StorageClass,否则会无法动态构建该 PV,可以通过启用 DefaultStorageClass 来实现 PV 的构建。

  • 绑定

    • 当用户创建一个 PVC 对象后,主节点会监测新的 PVC 对象,并且寻找与之匹配的 PV 卷,找到 PV 卷后将二者绑定在一起。

    • 如果找不到对应的 PV,则需要看 PVC 是否设置 StorageClass 来决定是否动态创建 PV,若没有配置,PVC 就会一致处于未绑定状态,直到有与之匹配的 PV 后才会申领绑定关系。

  • 使用

    • Pod 将 PVC 当作存储卷来使用,集群会通过 PVC 找到绑定的 PV,并为 Pod 挂载该卷。

    • Pod 一旦使用 PVC 绑定 PV 后,为了保护数据,避免数据丢失问题,PV 对象会受到保护,在系统中无法被删除。

  • 回收策略

    当用户不再使用其存储卷时,他们可以从 API 中将 PVC 对象删除, 从而允许该资源被回收再利用。PersistentVolume 对象的回收策略告诉集群, 当其被从申领中释放时如何处理该数据卷。 目前,数据卷可以被 Retained(保留)、Recycled(回收)或 Deleted(删除)。

    • 保留(Retain)

      • 回收策略 Retain 使得用户可以手动回收资源。当 PersistentVolumeClaim 对象被删除时,PersistentVolume 卷仍然存在,对应的数据卷被视为"已释放(released)"。 由于卷上仍然存在这前一申领人的数据,该卷还不能用于其他申领。 管理员可以通过下面的步骤来手动回收该卷:

        • 删除 PersistentVolume 对象。与之相关的、位于外部基础设施中的存储资产 (例如 AWS EBS、GCE PD、Azure Disk 或 Cinder 卷)在 PV 删除之后仍然存在。

        • 根据情况,手动清除所关联的存储资产上的数据。

        • 手动删除所关联的存储资产。

      • 如果你希望重用该存储资产,可以基于存储资产的定义创建新的 PersistentVolume 卷对象。

    • 删除(Delete)

      • 对于支持 Delete 回收策略的卷插件,删除动作会将 PersistentVolume 对象从 Kubernetes 中移除,同时也会从外部基础设施(如 AWS EBS、GCE PD、Azure Disk 或 Cinder 卷)中移除所关联的存储资产。 动态制备的卷会继承其 StorageClass 中设置的回收策略, 该策略默认为 Delete。管理员需要根据用户的期望来配置 StorageClass; 否则 PV 卷被创建之后必须要被编辑或者修补。
    • 回收(Recycle)

      • 警告: 回收策略 Recycle 已被废弃。取而代之的建议方案是使用动态制备。
      • 如果下层的卷插件支持,回收策略 Recycle 会在卷上执行一些基本的擦除 (rm -rf /thevolume/*)操作,之后允许该卷用于新的 PVC 申领。
5.2.3.2、PV
  • 状态

    • Available:空闲,未被绑定
    • Bound:已经被 PVC 绑定
    • Released:PVC 被删除,资源已回收,但是 PV 未被重新使用
    • Failed:自动回收失败
  • 配置文件

    apiVersion: v1
    kind: PersistentVolume # 描述资源对象为 PV 类型
    metadata:
      name: pv0001 # PV 的名字
    spec:
      capacity: # 容量配置
        storage: 5Gi # pv 的容量
      volumeMode: Filesystem # 存储类型为文件系统
      accessModes: # 访问模式:ReadWriteOnce、ReadWriteMany、ReadOnlyMany
        - ReadWriteOnce # 可被单节点独写
      persistentVolumeReclaimPolicy: Retain # 回收策略
      storageClassName: slow # 创建 PV 的存储类名,需要与 pvc 的相同
      mountOptions: # 加载配置
        - hard
        - nfsvers=4.1
      nfs: # 连接到 nfs
        path: /data/nfs/rw/test-pv # 存储路径
        server: 192.168.171.130 # nfs 服务地址
    

    ReadWriteOnce: 只能同时被一个pvc绑定, 被一个pvc使用, 意味着这个pv只能被一个pvc用

    ReadWriteMany: 同时被多个pvc绑定, 被多个pvc使用, 意味着这个pv能被多个pvc用

    ReadOnlyMany: 同时被多个pvc绑定只读, 被多个pvc使用只读, 意味着这个pv能被多个pvc用只读

5.2.3.3、PVC
  • Pod 绑定 PVC

    在 pod 的挂载容器配置中,增加 pvc 挂载
    containers:
      ......
      volumeMounts:
        - mountPath: /tmp/pvc
          name: nfs-pvc-test
    volumes:
      - name: nfs-pvc-test
        persistentVolumeClaim:
          claimName: nfs-pvc # pvc 的名称
          
          
          
    #apiVersion: v1
    #kind: Pod
    #metadata:
    #  name: test-pvc-pd
    #spec:
    #  containers:
    #  - image: nginx
    #    name: nginx-volume
    #    volumeMounts:
    #    - mountPath: /usr/share/nginx/html # 挂载到容器的哪个目录
    #      name: test-volume # 挂载哪个 volume
    #  volumes:
    #  - name: test-volume
    #    persistentVolumeClaim:
    #      claimName: nfs-pvc # pvc 的名称
    
  • 配置文件

    apiVersion: v1
    kind: PersistentVolumeClaim # 资源类型为 PVC
    metadata:
      name: nfs-pvc
    spec:
      accessModes:
        - ReadWriteOnce # 权限需要与对应的 pv 相同
      volumeMode: Filesystem
      resources:
        requests:
          storage: 5Gi # 资源可以小于 pv 的,但是不能大于,如果大于就会匹配不到 pv
      storageClassName: slow # 名字需要与对应的 pv 相同
    #  selector: # 使用选择器选择对应的 pv
    #    matchLabels:
    #      release: "stable"
    #    matchExpressions:
    #      - {key: environment, operator: In, values: [dev]
    
5.2.3.4、StorageClass

k8s 中提供了一套自动创建 PV 的机制,就是基于 StorageClass 进行的,通过 StorageClass 可以实现仅仅配置 PVC,然后交由 StorageClass 根据 PVC 的需求动态创建 PV。

  • 制备器(Provisioner)

    • 每个 StorageClass 都有一个制备器(Provisioner),用来决定使用哪个卷插件制备 PV。
  • NFS 动态制备案例

    • nfs-provisioner

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: nfs-client-provisioner
        namespace: default
        labels:
          app: nfs-client-provisioner
      spec:
        replicas: 1
        strategy:
          type: Recreate
        selector:
          matchLabels:
            app: nfs-client-provisioner
        template:
          metadata:
            labels:
              app: nfs-client-provisioner
          spec:
            serviceAccountName: nfs-client-provisioner
            containers:
              - name: nfs-client-provisioner
                image: quay.io/external_storage/nfs-client-provisioner:latest
                volumeMounts:
                  - name: nfs-client-root
                    mountPath: /persistentvolumes
                env:
                  - name: PROVISIONER_NAME
                    value: fuseim.pri/ifs
                  - name: NFS_SERVER
                    value: 192.168.171.130
                  - name: NFS_PATH
                    value: /data/nfs/rw
            volumes:
              - name: nfs-client-root
                nfs:
                  server: 192.168.171.130
                  path: /data/nfs/rw
      
    • StorageClass 配置

      apiVersion: storage.k8s.io/v1
      kind: StorageClass
      metadata:
        name: managed-nfs-storage
        namespace: kube-system
      provisioner: fuseim.pri/ifs # 外部制备器提供者,编写为提供者的名称
      parameters:
        archiveOnDelete: "false" # 是否存档,false 表示不存档,会删除 oldPath 下面的数据,true 表示存档,会重命名路径
      reclaimPolicy: Retain # 回收策略,默认为 Delete 可以配置为 Retain
      volumeBindingMode: Immediate # 默认为 Immediate,表示创建 PVC 立即进行绑定,只有 azuredisk 和 AWSelasticblockstore 支持其他值
      
    • RBAC 配置

      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: nfs-client-provisioner
        namespace: default
      ---
      kind: ClusterRole
      apiVersion: rbac.authorization.k8s.io/v1
      metadata:
        name: nfs-client-provisioner-runner
        namespace: default
      rules:
        - apiGroups: [""]
          resources: ["persistentvolumes"]
          verbs: ["get", "list", "watch", "create", "delete"]
        - apiGroups: [""]
          resources: ["persistentvolumeclaims"]
          verbs: ["get", "list", "watch", "update"]
        - apiGroups: ["storage.k8s.io"]
          resources: ["storageclasses"]
          verbs: ["get", "list", "watch"]
        - apiGroups: [""]
          resources: ["events"]
          verbs: ["create", "update", "patch"]
      ---
      kind: ClusterRoleBinding
      apiVersion: rbac.authorization.k8s.io/v1
      metadata:
        name: run-nfs-client-provisioner
        namespace: default
      subjects:
        - kind: ServiceAccount
          name: nfs-client-provisioner
          namespace: default
      roleRef:
        kind: ClusterRole
        name: nfs-client-provisioner-runner
        apiGroup: rbac.authorization.k8s.io
      ---
      kind: Role
      apiVersion: rbac.authorization.k8s.io/v1
      metadata:
        name: leader-locking-nfs-client-provisioner
        namespace: default
      rules:
        - apiGroups: [""]
          resources: ["endpoints"]
          verbs: ["get", "list", "watch", "create", "update", "patch"]
      ---
      kind: RoleBinding
      apiVersion: rbac.authorization.k8s.io/v1
      metadata:
        name: leader-locking-nfs-client-provisioner
        namespace: default
      subjects:
        - kind: ServiceAccount
          name: nfs-client-provisioner
      roleRef:
        kind: Role
        name: leader-locking-nfs-client-provisioner
        apiGroup: rbac.authorization.k8s.io
      
    • PVC 处于 Pending 状态

      在 k8s 1.20 之后,出于对性能和统一 apiserver 调用方式的初衷,移除了对 SelfLink 的支持,而默认上面指定的 provisioner 版本需要 SelfLink 功能,因此 PVC 无法进行自动制备。

      • 配置 SelfLink

        修改 apiserver 配置文件
        vim /etc/kubernetes/manifests/kube-apiserver.yaml
        spec:
          containers:
          - command:
            - kube-apiserver
            - --feature-gates=RemoveSelfLink=false # 新增该行
            ......
        修改后重新应用该配置
        kubectl apply -f /etc/kubernetes/manifests/kube-apiserver.yaml
        
      • 不需要 SelfLink 的 provisioner

        将 provisioner 修改为如下镜像之一即可
        gcr.io/k8s-staging-sig-storage/nfs-subdir-external-provisioner:v4.0.0
        
        registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
        
    • PVC 测试配置

      apiVersion: v1
      kind: PersistentVolumeClaim
      metadata:
        name: auto-pv-test-pvc
      spec:
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: 300Mi
        storageClassName: managed-nfs-storage
      

6、高级调度

6.1、CronJob 计划任务

在 k8s 中周期性运行计划任务,与 linux 中的 crontab 相同

注意点:CronJob 执行的时间是 controller-manager 的时间,所以一定要确保 controller-manager 时间是准确的,另外 cronjob

6.1.1、cron 表达式
# ┌───────────── 分钟 (0 - 59)
# │ ┌───────────── 小时 (0 - 23)
# │ │ ┌───────────── 月的某天 (1 - 31)
# │ │ │ ┌───────────── 月份 (1 - 12)
# │ │ │ │ ┌───────────── 周的某天 (0 - 6)(周日到周一;在某些系统上,7 也是星期日)
# │ │ │ │ │                          或者是 sun,mon,tue,web,thu,fri,sat
# │ │ │ │ │
# │ │ │ │ │
# * * * * *
6.1.2、cron 表达式
apiVersion: batch/v1
kind: CronJob
metadata:
  name: hello
spec:
  concurrencyPolicy: Allow # 并发调度策略:Allow 允许并发调度,Forbid:不允许并发执行,Replace:如果之前的任务还没执行完,就直接执行新的,放弃上一个任务
  failedJobsHistoryLimit: 1 # 保留多少个失败的任务
  successfulJobsHistoryLimit: 3 # 保留多少个成功的任务
  suspend: false # 是否挂起任务,若为 true 则该任务不会执行
#  startingDeadlineSeconds: 30 # 间隔多长时间检测失败的任务并重新执行,时间不能小于 10
  schedule: "* * * * *" # 调度策略
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox:1.28
            imagePullPolicy: IfNotPresent
            command:
            - /bin/sh
            - -c
            - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure

6.2、初始化容器 InitContainer

在真正的容器启动之前,先启动 InitContainer,在初始化容器中完成真实容器所需的初始化操作,完成后再启动真实的容器。

相对于 postStart 来说,首先 InitController 能够保证一定在 EntryPoint 之前执行,而 postStart 不能,其次 postStart 更适合去执行一些命令操作,而 InitController 实际就是一个容器,可以在其他基础容器环境下执行更复杂的初始化功能。

在 pod 创建的模板中配置 initContainers 参数:

spec:
  initContainers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    command: ["sh", "-c", "echo 'inited;' >> ~/.init"]
    name: init-test

在这里插入图片描述

6.3、污点和容忍

k8s 集群中可能管理着非常庞大的服务器,这些服务器可能是各种各样不同类型的,比如机房、地理位置、配置等,有些是计算型节点,有些是存储型节点,此时我们希望能更好的将 pod 调度到与之需求更匹配的节点上。

此时就需要用到污点(Taint)和容忍(Toleration),这些配置都是 key: value 类型的。

6.3.1、污点(Taint)
污点:是标注在节点上的,当我们在一个节点上打上污点以后,k8s 会认为尽量不要将 pod 调度到该节点上,除非该 pod 上面表示可以容忍该污点,且一个节点可以打多个污点,此时则需要 pod 容忍所有污点才会被调度该节点。
# 为节点打上污点
kubectl taint node k8s-master key=value:NoSchedule
# 移除污点
kubectl taint node k8s-master key=value:NoSchedule-
# 查看污点
kubectl describe no k8s-master

污点的影响:
NoSchedule:不能容忍的 pod 不能被调度到该节点,但是已经存在的节点不会被驱逐

NoExecute:不能容忍的节点会被立即清除,能容忍且没有配置 tolerationSeconds 属性,则可以一直运行,设置了 tolerationSeconds: 3600 属性,则该 pod 还能继续在该节点运行 3600
  • NoSchedule

    • 如果不能容忍该污点,那么 Pod 就无法调度到该节点上
  • NoExecute

    • 如果 Pod 不能忍受这类污点,Pod 会马上被驱逐。

    • 如果 Pod 能够忍受这类污点,但是在容忍度定义中没有指定 tolerationSeconds, 则 Pod 还会一直在这个节点上运行。

    • 如果 Pod 能够忍受这类污点,而且指定了 tolerationSeconds, 则 Pod 还能在这个节点上继续运行这个指定的时间长度。

6.3.2、容忍(Toleration)
容忍:是标注在 pod 上的,当 pod 被调度时,如果没有配置容忍,则该 pod 不会被调度到有污点的节点上,只有该 pod 上标注了满足某个节点的所有污点,则会被调度到这些节点
# pod 的 spec 下面配置容忍
tolerations:
- key: "污点的 key"
  value: "污点的 value"
  offect: "NoSchedule" # 污点产生的影响
  operator: "Equal" # 表是 value 与污点的 value 要相等,也可以设置为 Exists 表示存在 key 即可,此时可以不用配置 value
  • Equal
    • 比较操作类型为 Equal,则意味着必须与污点值做匹配,key/value都必须相同,才表示能够容忍该污点
  • Exists
    • 容忍与污点的比较只比较 key,不比较 value,不关心 value 是什么东西,只要 key 存在,就表示可以容忍。

6.4、亲和力(Affinity)

6.4.1、NodeAffinity

节点亲和力:进行 pod 调度时,优先调度到符合条件的亲和力节点上

  • RequiredDuringSchedulingIgnoredDuringExecution

    • 硬亲和力,即支持必须部署在指定的节点上,也支持必须不部署在指定的节点上
  • PreferredDuringSchedulingIgnoredDuringExecution

    • 软亲和力:尽量部署在满足条件的节点上,或尽量不要部署在被匹配的节点上
  • 应用

    • 匹配类型

      • In
        • 部署在满足条件的节点上
      • NotIn
        • 匹配不在条件中的节点,实现节点反亲和性
      • Exists
        • 只要存在 key 名字就可以,不关心值是什么
      • DoesNotExist
        • 匹配指定 key 名不存在的节点,实现节点反亲和性
      • Gt
        • value 为数值,且节点上的值小于指定的条件
      • Lt
        • value 为数值,且节点上的值大于指定条件
    • 配置模板

      apiVersion: v1
      kind: Pod
      metadata:
        name: with-node-affinity
      spec:
        affinity: # 亲和力配置
          nodeAffinity: # 节点亲和力
            requiredDuringSchedulingIgnoredDuringExecution: # 节点必须匹配下方配置
              nodeSelectorTerms: # 选择器
              - matchExpressions: # 匹配表达式
                - key: kubernetes.io/os # 匹配 label 的 key
                  operator: In # 匹配方式,只要匹配成功下方的一个 value 即可
                  values:
                  - linux # 匹配的 value
            preferredDuringSchedulingIgnoredDuringExecution: # 节点尽量匹配下方配置
            - weight: 1 # 权重[1,100],按照匹配规则对所有节点累加权重,最终之和会加入优先级评分,优先级越高被调度的可能性越高
              preference:
                matchExpressions: # 匹配表达式
                - key: label-1 # label 的 key
                  operator: In # 匹配方式,满足一个即可
                  values:
                  - key-1 # 匹配的 value
            - weight: 50 # 权重[1,100],按照匹配规则对所有节点累加权重,最终之和会加入优先级评分,优先级越高被调度的可能性越高
              preference:
                matchExpressions: # 匹配表达式
                - key: label-2 # label 的 key
                  operator: In # 匹配方式,满足一个即可
                  values:
                  - key-2 # 匹配的 value
              ......
        containers:
        - name: with-node-affinity
          image: pause:2.0
      
6.4.2、PodAffinity

Pod 亲和力:将与指定 pod 亲和力相匹配的 pod 部署在同一节点。

  • RequiredDuringSchedulingIgnoredDuringExecution

    • 必须将应用部署在一块
  • PreferredDuringSchedulingIgnoredDuringExecution

    • 尽量将应用部署在一块
  • 配置模板

    apiVersion: v1
    kind: Pod
    metadata:
      name: with-pod-affinity
    spec:
      affinity: # 亲和力配置
        podAffinity: # pod 亲和力配置
          requiredDuringSchedulingIgnoredDuringExecution: # 当前 pod 必须匹配到对应条件 pod 所在的 node 上
          - labelSelector: # 标签选择器
              matchExpressions: # 匹配表达式
              - key: security # 匹配的 key
                operator: In # 匹配方式
                values: # 匹配其中的一个 value
                - S1
            topologyKey: topology.kubernetes.io/zone # 节点上面必须要有这个标签
        podAntiAffinity: # pod 反亲和力配置
          preferredDuringSchedulingIgnoredDuringExecution: # 尽量不要将当前节点部署到匹配下列参数的 pod 所在的 node 上
          - weight: 100 # 权重
            podAffinityTerm: # pod 亲和力配置条件
              labelSelector: # 标签选择器
                matchExpressions: # 匹配表达式
                - key: security # 匹配的 key
                  operator: In # 匹配的方式
                  values:
                  - S2 # 匹配的 value
              topologyKey: topology.kubernetes.io/zone # 节点上面必须要有这个标签
      containers:
      - name: with-pod-affinity
        image: pause:2.0
    
6.4.3、PodAntiAffinity

Pod 反亲和力:根据策略尽量部署或不部署到一块

  • RequiredDuringSchedulingIgnoredDuringExecution

    不要将应用与之匹配的部署到一块
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
        matchExpressions:
        - key: security
          operator: In
          values:
          - S1
      topologyKey: topology.kubernetes.io/zone
    
  • PreferredDuringSchedulingIgnoredDuringExecution

    • 尽量不要将应用部署到一块

7、身份认证与权限

Kubernetes 中提供了良好的多租户认证管理机制,如 RBAC、ServiceAccount 还有各种策略等。

通过该文件可以看到已经配置了 RBAC 访问控制

/usr/lib/systemd/system/kube-apiserver.service

  • 认证

    所有 Kubernetes 集群有两类用户:由 Kubernetes 管理的Service Accounts (服务账户)和(Users Accounts) 普通账户。
    
    普通账户是假定被外部或独立服务管理的,由管理员分配 keys,用户像使用 Keystone 或 google 账号一样,被存储在包含 usernames 和 passwords 的 list 的文件里。
    
    需要注意:在 Kubernetes 中不能通过 API 调用将普通用户添加到集群中。
       - 普通帐户是针对(人)用户的,服务账户针对 Pod 进程。
       - 普通帐户是全局性。在集群所有namespaces中,名称具有惟一性。
       - 通常,群集的普通帐户可以与企业数据库同步,新的普通帐户创建需要特殊权限。服务账户创建目的是更轻量化,允许集群用户为特定任务创建服务账户。
       - 普通帐户和服务账户的审核注意事项不同。
       - 对于复杂系统的配置包,可以包括对该系统的各种组件的服务账户的定义。
    
    • User Accounts

    • Service Accounts

      • Service Account 自动化

        • Service Account Admission Controller

          通过 Admission Controller 插件来实现对 pod 修改,它是 apiserver 的一部分。创建或更新 pod 时会同步进行修改 pod。当插件处于激活状态(在大多数发行版中都默认情况)创建或修改 pod 时,会按以下操作执行:
          
          1. 如果 pod 没有设置 ServiceAccount,则将 ServiceAccount 设置为 default。
          
          2. 确保 pod 引用的 ServiceAccount 存在,否则将会拒绝请求。
          
          3. 如果 pod 不包含任何 ImagePullSecrets,则将ServiceAccount 的 ImagePullSecrets 会添加到 pod 中。
          
          4. 为包含 API 访问的 Token 的 pod 添加了一个 volume。
          
          5. 把 volumeSource 添加到安装在 pod 的每个容器中,挂载在/var/run/secrets/kubernetes.io/serviceaccount。
          
        • Token Controller

          TokenController 作为 controller-manager 的一部分运行。异步行为:
          
          观察 serviceAccount 的创建,并创建一个相应的 Secret 来允许 API 访问。
          
          观察 serviceAccount 的删除,并删除所有相应的ServiceAccountToken Secret
          
          观察 secret 添加,并确保关联的 ServiceAccount 存在,并在需要时向 secret 中添加一个 Token。
          
          观察 secret 删除,并在需要时对应 ServiceAccount 的关联
          
        • Service Account Controller

          Service Account Controller 在 namespaces 里管理ServiceAccount,并确保每个有效的 namespaces 中都存在一个名为 “default” 的 ServiceAccount。
          
  • 授权(RBAC)

    • Role

      代表一个角色,会包含一组权限,没有拒绝规则,只是附加允许。它是 Namespace 级别的资源,只能作用与 Namespace 之内。
      # 查看已有的角色信息
      kubectl get role -n ingress-nginx -oyaml
      
      • 配置文件

        apiVersion: rbac.authorization.k8s.io/v1
        kind: Role
        metadata:
          labels:
            app.kubernetes.io/name: ingress-nginx
            app.kubernetes.io/part-of: ingress-nginx
          name: nginx-ingress
          namespace: ingress-nginx
        roles:
        - apiGroups:
          - ""
          resources:
          - configmaps
          - pods
          - secrets
          - namespaces
          verbs:
          - get
        - apiGroups:
          - ""
          resourceNames:
          - ingress-controller-label-nginx
          resources:
          - configmaps
          verbs:
          - get
          - update
        - apiGroups:
          - ""
          resources:
          - configmaps
          verbs:
          - create
        
    • ClusterRole

      功能与 Role 一样,区别是资源类型为集群类型,而 Role 只在 Namespace
      # 查看某个集群角色的信息
      kubectl get clusterrole view -oyaml
      
    • RoleBinding

      Role 或 ClusterRole 只是用于制定权限集合,具体作用与什么对象上,需要使用 RoleBinding 来进行绑定。
      作用于 Namespace 内,可以将 Role 或 ClusterRole 绑定到 User、Group、Service Account 上。
      # 查看 rolebinding 信息
      kubectl get rolebinding --all-namespaces
      
      # 查看指定 rolebinding 的配置信息
      kubectl get rolebinding  --all-namespaces -oyaml
      
      • 配置文件

        apiVersion: rbac.authorization.k8s.io/v1
        kind: RoleBinding
        metadata:
          ......
        roleRef:
          apiGroup: rbac.authorization.k8s.io
          kind: Role
          name nginx-ingress-role
        subjects:
        - kind: ServiceAccount
          name: nginx-ingress-serviceaccount
          namespace: ingress-nginx
        
    • ClusterRoleBinding

      与 RoleBinding 相同,但是作用于集群之上,可以绑定到该集群下的任意 User、Group 或 Service Account
      

网站公告

今日签到

点亮在社区的每一天
去签到