2022-08-09

https://www.yuque.com/fairy-era/yg511q/od4gy0#72eaf3c6

在k8s集群中部署一个nginx,测试集群是否正常工作

通过expose暴露外部访问

查看service

浏览器访问节点ip:30355

Kubernetes中,所有的内容都抽象为资源

  • 用户可以在Kubernetes集群中部署各种服务。所谓的部署服务,其实就是在Kubernetes集群中运行一个个的容器,并将指定的程序跑在容器中。

  • Kubernetes的最小管理单元是Pod而不是容器,所以只能将容器放在Pod中,而Kubernetes一般也不会直接管理Pod,而是通过Pod控制器来管理Pod的。

  • Pod提供服务之后,就需要考虑如何访问Pod中的服务,Kubernetes提供了Service资源实现这个功能。

  • 当然,如果Pod中程序的数据需要持久化,Kubernetes还提供了各种存储系统。

学习kubernets的核心,就是学习如何对集群中的PodPod控制器Service存储等各种资源进行操作。

一些命令

-o wide 展示更多信息
-o json json格式详细信息
-o yaml yaml格式相信信息

创建和删除命名空间

describe中的event

scheduler分发pod到node
容器的创建和运行是由kubelet执行的

声明式管理资源

apiVersion: v1
kind: Namespace
metadata:
  name: dev
---
apiVersion: v1
kind: Pod
metadata:
  name: nginxpod
  namespace: dev
spec:
  containers:
    - name: nginx-containers
      image: nginx:1.17.1
kubectl apply -f nginxpod.yaml
kubectl get -f nginxpod.yaml
kubectl delete -f nginxpod.yaml

实现在node节点上执行kubectl

kubectl的运行需要配置文件:$HOME/.kube,如果想要在node节点上运行此命令,需要将master节点的.kube文件夹复制到node节点上,即在master节点上执行下面的操作:

scp -r $HOME/.kube k8s-node1:$HOME

namespace

pod

Pod可以认为是容器的封装,一个Pod中可以存在一个或多个容器

run创建的是pod,没有控制器(老版本使用run是有控制器的)

通过pod自身的ip访问pod

删除pod,由于没有控制器,不会再次创建

yaml描述

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: dev
spec:
  containers:
  - image: nginx:1.17.1
    imagePullPolicy: IfNotPresent
    name: pod
    ports: 
    - name: nginx-port
      containerPort: 80
      protocol: TCP
kubectl apply -f pod-nginx.yaml
kubectl delete -f pod-nginx.yaml

label

打标签

更新标签

筛选带指定标签的pod

删除标签

使用yaml声明标签

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: dev
  labels:
    version: "3.0"
    env: "test"        
spec:
  containers:
  - image: nginx:1.17.1
    imagePullPolicy: IfNotPresent
    name: pod
    ports: 
    - name: nginx-port
      containerPort: 80
      protocol: TCP

Deployment(Pod控制器)

Pod控制器用于Pod的管理,确保Pod资源符合预期的状态,当Pod的资源出现故障的时候,会尝试进行重启或重建Pod。

创建deploy(pod)

使用yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      run: nginx
  template:
    metadata:
      labels:
        run: nginx
    spec:
      containers:
      - image: nginx:1.17.1
        name: nginx
        ports:
        - containerPort: 80
          protocol: TCP

删除deploy会同时删除pod

用Deployment来创建一组Pod提供服务,每个Pod都会分配一个单独的Pod的IP地址,但是却存在如下的问题:

  • Pod的IP会随着Pod的重建产生变化
  • Pod的IP仅仅是集群内部可见的虚拟的IP,外部无法访问

Service来解决这个问题

Service可以看做是一组同类的Pod对外的访问接口,借助Service,应用可以方便的实现服务发现和负载均衡

service也是通过标签选择器机制关联pod

CLusterIP类型只能集群内部访问

--type=NodePort 支持集群外部访问
PORT(S)中80后的端口即为外部访问端口,可以通过node节点的ip+这个端口访问pod

pod

pod的结构

Pause容器是每个Pod都会有的一个根容器,它的作用有两个:
评估整个Pod的健康状况
可以在根容器上设置IP地址,其它容器都共享此IP,以实现Pod内部的网络通信

yml模板

apiVersion: v1     #必选,版本号,例如v1
kind: Pod         #必选,资源类型,例如 Pod
metadata:         #必选,元数据
  name: string     #必选,Pod名称
  namespace: string  #Pod所属的命名空间,默认为"default"
  labels:           #自定义标签列表
    - name: string                 
spec:  #必选,Pod中容器的详细定义
  containers:  #必选,Pod中容器列表
  - name: string   #必选,容器名称
    image: string  #必选,容器的镜像名称
    imagePullPolicy: [ Always|Never|IfNotPresent ]  #获取镜像的策略 
    command: [string]   #容器的启动命令列表,如不指定,使用打包时使用的启动命令
    args: [string]      #容器的启动命令参数列表
    workingDir: string  #容器的工作目录
    volumeMounts:       #挂载到容器内部的存储卷配置
    - name: string      #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
      mountPath: string #存储卷在容器内mount的绝对路径,应少于512字符
      readOnly: boolean #是否为只读模式
    ports: #需要暴露的端口库号列表
    - name: string        #端口的名称
      containerPort: int  #容器需要监听的端口号
      hostPort: int       #容器所在主机需要监听的端口号,默认与Container相同
      protocol: string    #端口协议,支持TCP和UDP,默认TCP
    env:   #容器运行前需设置的环境变量列表
    - name: string  #环境变量名称
      value: string #环境变量的值
    resources: #资源限制和请求的设置
      limits:  #资源限制的设置
        cpu: string     #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
        memory: string  #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
      requests: #资源请求的设置
        cpu: string    #Cpu请求,容器启动的初始可用数量
        memory: string #内存请求,容器启动的初始可用数量
    lifecycle: #生命周期钩子
        postStart: #容器启动后立即执行此钩子,如果执行失败,会根据重启策略进行重启
        preStop: #容器终止前执行此钩子,无论结果如何,容器都会终止
    livenessProbe:  #对Pod内各容器健康检查的设置,当探测无响应几次后将自动重启该容器
      exec:         #对Pod容器内检查方式设置为exec方式
        command: [string]  #exec方式需要制定的命令或脚本
      httpGet:       #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
        path: string
        port: number
        host: string
        scheme: string
        HttpHeaders:
        - name: string
          value: string
      tcpSocket:     #对Pod内个容器健康检查方式设置为tcpSocket方式
         port: number
       initialDelaySeconds: 0       #容器启动完成后首次探测的时间,单位为秒
       timeoutSeconds: 0          #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
       periodSeconds: 0           #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
       successThreshold: 0
       failureThreshold: 0
       securityContext:
         privileged: false
  restartPolicy: [Always | Never | OnFailure]  #Pod的重启策略
  nodeName: <string> #设置NodeName表示将该Pod调度到指定到名称的node节点上
  nodeSelector: obeject #设置NodeSelector表示将该Pod调度到包含这个label的node上
  imagePullSecrets: #Pull镜像时使用的secret名称,以key:secretkey格式指定
  - name: string
  hostNetwork: false   #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
  volumes:   #在该pod上定义共享存储卷列表
  - name: string    #共享存储卷名称 (volumes类型有很多种)
    emptyDir: {}       #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
    hostPath: string   #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
      path: string                #Pod所在宿主机的目录,将被用于同期中mount的目录
    secret:          #类型为secret的存储卷,挂载集群与定义的secret对象到容器内部
      scretname: string  
      items:     
      - key: string
        path: string
    configMap:         #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
      name: string
      items:
      - key: string
        path: string
# 查看某种资源可以配置的一级配置
kubectl explain 资源类型 
# 查看属性的子属性
kubectl explain 资源类型.属性

在kubernetes中基本所有资源的一级属性都是一样的,主要包含5个部分:

  • apiVersion <string>:版本,有kubernetes内部定义,版本号必须用kubectl api-versions查询。
  • kind <string>:类型,有kubernetes内部定义,类型必须用kubectl api-resources查询。
  • metadata <Object>:元数据,主要是资源标识和说明,常用的有namenamespacelabels等。
  • spec <Object>:描述,这是配置中最重要的一部分,里面是对各种资源配置的详细描述。
  • status <Object>:状态信息,里面的内容不需要定义,由kubernetes自动生成。

在上面的属性中,spec是接下来研究的重点,继续看下它的常见子属性:

  • containers <[]Object>:容器列表,用于定义容器的详细信息。
  • nodeName <String>:根据nodeName的值将Pod调度到指定的Node节点上。
  • nodeSelector <map[]> :根据NodeSelector中定义的信息选择该Pod调度到包含这些Label的Node上。
  • hostNetwork <boolean>:是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络(要注意端口冲突)。
  • volumes <[]Object> :存储卷,用于定义Pod上面挂载的存储信息。
  • restartPolicy <string>:重启策略,表示Pod在遇到故障的时候的处理策略。
kubectl explain pod.spec.containers

# 返回的重要属性
KIND:     Pod
VERSION:  v1
RESOURCE: containers <[]Object>   # 数组,代表可以有多个容器FIELDS:
  name  <string>     # 容器名称
  image <string>     # 容器需要的镜像地址
  imagePullPolicy  <string> # 镜像拉取策略 
  command  <[]string> # 容器的启动命令列表,如不指定,使用打包时使用的启动命令
  args   <[]string> # 容器的启动命令需要的参数列表 
  env    <[]Object> # 容器环境变量的配置
  ports  <[]Object>  # 容器需要暴露的端口号列表
  resources <Object> # 资源限制和资源请求的设置

containers基本配置

apiVersion: v1
kind: Pod
metadata:
  name: pod-base
  namespace: dev
  labels:
    user: yimin
spec:
  containers:
    - name: nginx # 容器名称
      image: nginx:1.17.1 # 容器需要的镜像地址
    - name: busybox # 容器名称
      image: busybox:1.30 # 容器需要的镜像地址

imagePullPolicy

apiVersion: v1
kind: Pod
metadata:
  name: pod-imagepullpolicy
  namespace: dev
  labels:
    user: xudaxian
spec:
  containers:
    - name: nginx # 容器名称
      image: nginx:1.17.1 # 容器需要的镜像地址
      imagePullPolicy: IfNotPresent # 用于设置镜像的拉取策略
    - name: busybox # 容器名称
      image: busybox:1.30 # 容器需要的镜像地址
  • Always:总是从远程仓库拉取镜像
  • IfNotPresent:本地有则使用本地镜像,本地没有则从远程仓库拉取镜像
  • Never:只使用本地镜像,从不去远程仓库拉取,本地没有就报错

如果镜像tag为具体的版本号,默认策略是IfNotPresent。
如果镜像tag为latest,默认策略是Always。

https://www.yuque.com/fairy-era/yg511q/od4gy0

command

apiVersion: v1
kind: Pod
metadata:
  name: pod-command
  namespace: dev
  labels:
    user: xudaxian
spec:
  containers:
    - name: nginx # 容器名称
      image: nginx:1.17.1 # 容器需要的镜像地址
      imagePullPolicy: IfNotPresent # 设置镜像拉取策略
    - name: busybox # 容器名称
      image: busybox:1.30 # 容器需要的镜像地址
      command: ["/bin/sh","-c","touch /tmp/hello.txt;while true;do /bin/echo $(date +%T) >> /tmp/hello.txt;sleep 3;done;"]

command已经可以完成启动命令和传递参数的功能,为什么还要提供一个args选项,用于传递参数?
其实和Docker有点关系,kubernetes中的command和args两个参数其实是为了实现覆盖Dockerfile中的ENTRYPOINT的功能:
● 如果command和args均没有写,那么用Dockerfile的配置。
● 如果command写了,但是args没有写,那么Dockerfile默认的配置会被忽略,执行注入的command。
● 如果command没有写,但是args写了,那么Dockerfile中配置的ENTRYPOINT命令会被执行,使用当前args的参数。
● 如果command和args都写了,那么Dockerfile中的配置会被忽略,执行command并追加上args参数。

env

apiVersion: v1
kind: Pod
metadata:
  name: pod-env
  namespace: dev
  labels:
    user: xudaxian
spec:
  containers:
    - name: nginx # 容器名称
      image: nginx:1.17.1 # 容器需要的镜像地址
      imagePullPolicy: IfNotPresent # 设置镜像拉取策略
    - name: busybox # 容器名称
      image: busybox:1.30 # 容器需要的镜像地址
      command: ["/bin/sh","-c","touch /tmp/hello.txt;while true;do /bin/echo $(date +%T) >> /tmp/hello.txt;sleep 3;done;"]
      env:
        - name: "username"
          value: "admin"
        - name: "password"
          value: "123456"
kubectl exec -it pod-env -n dev -c busybox -it /bin/sh
echo $username
echo $password

containerPort

apiVersion: v1
kind: Pod
metadata:
  name: pod-ports
  namespace: dev
  labels:
    user: xudaxian
spec:
  containers:
    - name: nginx # 容器名称
      image: nginx:1.17.1 # 容器需要的镜像地址
      imagePullPolicy: IfNotPresent # 设置镜像拉取策略
      ports:
        - name: nginx-port # 端口名称,如果执行,必须保证name在Pod中是唯一的
          containerPort: 80 # 容器要监听的端口 (0~65536)
          protocol: TCP # 端口协议

可以通过pod的ip+containerPort访问容器

resources:对容器资源占用做限制
limits:用于限制运行的容器的最大占用资源,当容器占用资源超过limits时会被终止,并进行重启requests:用于设置容器需要的最小资源,如果环境资源不够,容器将无法启动

apiVersion: v1
kind: Pod
metadata:
  name: pod-resoures
  namespace: dev
  labels:
    user: xudaxian
spec:
  containers:
    - name: nginx # 容器名称
      image: nginx:1.17.1 # 容器需要的镜像地址
      imagePullPolicy: IfNotPresent # 设置镜像拉取策略
      ports: # 端口设置
        - name: nginx-port # 端口名称,如果执行,必须保证name在Pod中是唯一的
          containerPort: 80 # 容器要监听的端口 (0~65536)
          protocol: TCP # 端口协议
      resources: # 资源配额
        limits: # 限制资源的上限
          cpu: "2" # CPU限制,单位是core数
          memory: "10Gi" # 内存限制
        requests: # 限制资源的下限
          cpu: "1" # CPU限制,单位是core数 
          memory: "10Mi" # 内存限制

pod生命周期

  • 初始化容器(init container)
  • 运行主容器(main container)
    容器启动后钩子(post start)、容器终止前钩子(pre stop)
    容器的存活性探测(liveness probe)、就绪性探测(readiness probe)

● 在整个生命周期中,Pod会出现5种状态
○ 挂起(Pending):API Server已经创建了Pod资源对象,但它尚未被调度完成或者仍处于下载镜像的过程中。
○ 运行中(Running):Pod已经被调度到某节点,并且所有容器都已经被kubelet创建完成。
○ 成功(Succeeded):Pod中的所有容器都已经成功终止并且不会被重启。
○ 失败(Failed):所有容器都已经终止,但至少有一个容器终止失败,即容器返回了非0值的退出状态
○ 未知(Unknown):API Server无法正常获取到Pod对象的状态信息,通常由于网络通信失败所导致。

Pod的创建过程

① 用户通过kubectl或其他的api客户端提交需要创建的Pod信息给API Server。
② API Server开始生成Pod对象的信息,并将信息存入etcd,然后返回确认信息至客户端。
③ API Server开始反映etcd中的Pod对象的变化,其它组件使用watch机制来跟踪检查API Server上的变动。
④ Scheduler发现有新的Pod对象要创建,开始为Pod分配主机并将结果信息更新至API Server。
⑤ Node节点上的kubelet发现有Pod调度过来,尝试调度Docker启动容器,并将结果回送至API Server。
⑥ API Server将接收到的Pod状态信息存入到etcd中。

初始化容器

初始化容器是在Pod的主容器启动之前要运行的容器,主要是做一些主容器的前置工作,它具有两大特征:
① 初始化容器必须运行完成直至结束,如果某个初始化容器运行失败,那么kubernetes需要重启它直至成功完成。
② 初始化容器必须按照定义的顺序执行,当且仅当前一个成功之后,后面的一个才能运行。

假设要以主容器来运行Nginx,但是要求在运行Nginx之前要能够连接上MySQL和Redis所在的服务器。

apiVersion: v1
kind: Pod
metadata:
  name: pod-initcontainer
  namespace: dev
  labels:
    user: xudaxian
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
      resources:
        limits:
          cpu: "2"
          memory: "10Gi"
        requests:
          cpu: "1"
          memory: "10Mi"
  initContainers: # 初始化容器配置
    - name: test-mysql
      image: busybox:1.30
      command: ["sh","-c","until ping 192.168.18.103 -c 1;do echo waiting for mysql ...;sleep 2;done;"]
      securityContext:
        privileged: true # 使用特权模式运行容器
    - name: test-redis
      image: busybox:1.30
      command: ["sh","-c","until ping 192.168.18.104 -c 1;do echo waiting for redis ...;sleep 2;done;"]
kubectl create -f pod-initcontainer.yaml
kubectl describe pod pod-initcontainer -n dev

此时pod会卡在运行test-mysql(ping不通)

钩子函数
○ post start:容器创建之后执行,如果失败会重启容器。
○ pre stop:容器终止之前执行,执行完成之后容器将成功终止,在其完成之前会阻塞删除容器的操作。

钩子处理器支持使用下面的三种方式定义动作

……
  lifecycle:
     postStart: 
        exec:
           command:
             - cat
             - /tmp/healthy
……
…… 
   lifecycle:
      postStart:
         tcpSocket:
            port: 8080
……
…… 
   lifecycle:
      postStart:
         httpGet:
            path: / #URI地址
            port: 80 #端口号
            host: 192.168.109.100 #主机地址  
            scheme: HTTP #支持的协议,http或者https
……

例子:在nginx容器启动后修改主页内容

apiVersion: v1
kind: Pod
metadata:
  name: pod-hook-exec
  namespace: dev
  labels:
    user: xudaxian
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
      resources:
        limits:
          cpu: "2"
          memory: "10Gi"
        requests:
          cpu: "1"
          memory: "10Mi"
      lifecycle: # 生命周期配置
        postStart: # 容器创建之后执行,如果失败会重启容器
          exec: # 在容器启动的时候,执行一条命令,修改掉Nginx的首页内容
            command: ["/bin/sh","-c","echo postStart ... > /usr/share/nginx/html/index.html"]
        preStop: # 容器终止之前执行,执行完成之后容器将成功终止,在其完成之前会阻塞删除容器的操作
          exec: # 在容器停止之前停止Nginx的服务
            command: ["/usr/sbin/nginx","-s","quit"]
kubectl apply -f pod-hook-exec.yml 
[root@node1 ~]# kubectl get pod pod-hook-exec -n dev -o wide
NAME            READY   STATUS    RESTARTS   AGE   IP           NODE    NOMINATED NODE   READINESS GATES
pod-hook-exec   1/1     Running   0          66s   10.244.1.4   node1   <none>           <none>
[root@node1 ~]# curl 10.244.1.4
postStart ...

容器探测

容器探测用于检测容器中的应用实例是否正常工作,是保障业务可用性的一种传统机制。kubernetes提供了两种探针来实现容器探测,分别是:
○ liveness probes:存活性探测,用于检测应用实例当前是否处于正常运行状态,如果不是,k8s会重启容器。
○ readiness probes:就绪性探测,用于检测应用实例是否可以接受请求,如果不能,k8s不会转发流量

exec方式

apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness-exec
  namespace: dev
  labels:
    user: xudaxian
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
      livenessProbe: # 存活性探针
        exec:
          command: ["/bin/cat","/tmp/hello.txt"] # 执行查看文件的命令,一定失败,因为没有这个文件

上述命令返回码非0,存活性探测会认为不健康,会一直重启容器(默认重启策略)

tcpSocket方式

apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness-tcpsocket
  namespace: dev
  labels:
    user: xudaxian
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
      livenessProbe: # 存活性探针
        tcpSocket:
          port: 8080 # 尝试访问8080端口,一定失败,因为Pod内部只有一个Nginx容器,而且只是监听了80端口

httpGet方式

apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness-httpget
  namespace: dev
  labels:
    user: xudaxian
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
      livenessProbe: # 存活性探针
        httpGet: # 其实就是访问http://127.0.0.1:80/hello
          port: 80 # 端口号
          scheme: HTTP # 支持的协议,HTTP或HTTPS
          path: /hello # URI地址
          host: 127.0.0.1 # 主机地址

livenessProbe的其他可选项

kubectl explain pod.spec.containers.livenessProbe

exec 
tcpSocket  
httpGet    
initialDelaySeconds    # 容器启动后等待多少秒执行第一次探测
timeoutSeconds      # 探测超时时间。默认1秒,最小1秒
periodSeconds       # 执行探测的频率。默认是10秒,最小1秒
failureThreshold    # 连续探测失败多少次才被认定为失败。默认是3。最小值是1
successThreshold    # 连续探测成功多少次才被认定为成功。默认是1

重启策略

在容器探测中,一旦探测出现了问题,kubernetes就会对容器所在的Pod进行重启,其实这是由Pod的重启策略决定的,Pod的重启策略有3种,分别如下:
○ Always:容器失效时,自动重启该容器,默认值
○ OnFailure:容器终止运行且退出码不为0时重启。
○ Never:不论状态如何,都不重启该容器。

例子:指定重启策略为Never

apiVersion: v1
kind: Pod
metadata:
  name: pod-restart-policy
  namespace: dev
  labels:
    user: xudaxian
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
      livenessProbe: # 存活性探测
        httpGet:
          port: 80
          path: /hello
          host: 127.0.0.1
          scheme: HTTP
  restartPolicy: Never # 重启策略

Pod的调度

默认情况下,Pod在哪个Node节点上运行,是由Scheduler组件计算出来的。
在实际使用中,我们想控制某些Pod到达某些节点上,那么应该怎么做?这就要求了解kubernetes对Pod的调度规则,kubernetes提供了四大类调度方式。
○ 自动调度:运行在哪个Node节点上完全由Scheduler经过一系列的算法计算得出。
○ 定向调度:NodeName、NodeSelector。
○ 亲和性调度:NodeAffinity、PodAffinity、PodAntiAffinity。
○ 污点(容忍)调度:Taints、Toleration。

nodeName(强制调度)

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodename
  namespace: dev
  labels:
    user: xudaxian
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
  nodeName: k8s-node1 # 指定调度到k8s-node1节点上

nodeSelector(强制调度)

# 先给node1打标签
kubectl label node k8s-node1 nodeenv=pro
apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeselector
  namespace: dev
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
  nodeSelector:
    nodeenv: pro # 指定调度到具有nodeenv=pro的Node节点上,即node1上

虽然定向调度的两种方式,使用起来非常方便,但是也有一定的问题,那就是如果没有满足条件的Node,那么Pod将不会被运行,即使在集群中还有可用的Node列表也不行。

亲和性调度在nodeSelector的基础之上进行了扩展,优先选择满足条件的Node进行调度,如果没有,也可以调度到不满足条件的节点上,使得调度更加灵活。(保证pod能够运行)

关于亲和性和反亲和性的使用场景的说明:
亲和性:如果两个应用频繁交互,那么就有必要利用亲和性让两个应用尽可能的靠近,这样可以较少因网络通信而带来的性能损耗。
反亲和性:当应用采用多副本部署的时候,那么就有必要利用反亲和性让各个应用实例打散分布在各个Node上,这样可以提高服务的高可用性

nodeAffinity例子

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeaffinity-required
  namespace: dev
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
  affinity: # 亲和性配置
    nodeAffinity: # node亲和性配置
      requiredDuringSchedulingIgnoredDuringExecution: # Node节点必须满足指定的所有规则才可以,硬规则,类似于定向调度
        nodeSelectorTerms: # 节点选择列表
          - matchExpressions:
              - key: nodeenv # 匹配存在标签的key为nodeenv的节点,并且value是"xxx"或"yyy"的节点
                operator: In #关系符 支持In, NotIn, Exists, DoesNotExist, Gt, Lt  
                values:
                  - "xxx"
                  - "yyy"

此时apply创建pod,再describe查看pod,会观察到pod运行失败,因为没有节点上有nodeenv=xxx或yyy的标签

而使用preferredDuringSchedulingIgnoredDuringExecution时,当没有节点满足条件时,总会选择其中一个节点运行pod(不会因为匹配不到节点导致运行失败运行失败)

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeaffinity-preferred
  namespace: dev
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
  affinity: # 亲和性配置
    nodeAffinity: # node亲和性配置
      preferredDuringSchedulingIgnoredDuringExecution: # 优先调度到满足指定的规则的Node,相当于软限制 (倾向)
        - preference: # 一个节点选择器项,与相应的权重相关联
            matchExpressions:
              - key: nodeenv
                operator: In
                values:
                  - "xxx"
                  - "yyy"
          weight: 1 #倾向权重,在范围1-100。

podAffinity
以运行的Pod为参照,实现让新创建的Pod和参照的Pod在一个区域

先创建一个参照pod,设置标签 podenv=pro

apiVersion: v1
kind: Pod
metadata:
  name: pod-podaffinity-target
  namespace: dev
  labels:
    podenv: pro # 设置标签
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
  nodeName: k8s-node1 # 将目标pod定向调度到k8s-node1

创建目标pod,调度到具有podenv=pro或yyy的pod所在的node上,即node1

apiVersion: v1
kind: Pod
metadata:
  name: pod-podaffinity-requred
  namespace: dev
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
  affinity: # 亲和性配置
    podAffinity: # Pod亲和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
        - labelSelector:
            matchExpressions: # 该Pod必须和拥有标签podenv=xxx或者podenv=yyy的Pod在同一个Node上,显然没有这样的Pod
              - key: podenv
                operator: In
                values:
                  - "pro"
                  - "yyy"
          topologyKey: kubernetes.io/hostname #以Node节点为区分范围

podAntiAffinity和podAffinity作用相反,让新创建的Pod和参照的Pod不在一个区域,此时参照pod在node1,按照以下配置,目标pod会被调度到node2

apiVersion: v1
kind: Pod
metadata:
  name: pod-podantiaffinity-requred
  namespace: dev
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
  affinity: # 亲和性配置
    podAntiAffinity: # Pod反亲和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
        - labelSelector:
            matchExpressions:
              - key: podenv
                operator: In
                values:
                  - "pro"
          topologyKey: kubernetes.io/hostname

污点

  • 前面的调度方式都是站在Pod的角度上,通过在Pod上添加属性,来确定Pod是否要调度到指定的Node上,其实我们也可以站在Node的角度上,通过在Node上添加污点属性拒绝Pod调度进来,甚至可以将已经存在的Pod驱逐出去。

  • 污点的格式为:key=value:effect,key和value是污点的标签,effect描述污点的作用,支持如下三个选项:

  • PreferNoSchedule:尽量避免把Pod调度到具有该污点的Node上,除非没有其他节点可以调度。

  • NoSchedule:不会把Pod调度到具有该污点的Node上,但是不会影响当前Node上已经存在的Pod。

  • NoExecute:不会把Pod调度到具有该污点的Node上,同时也会将Node上已经存在的Pod驱逐。

例子

设置污点,尽量不要调度过来

kubectl taint node k8s-node1 tag=xudaxian:PreferNoSchedule

此时创建pod1,如果node2可用,将会调度到node2,否则只能调度到node1

kubectl run pod1 --image=nginx:1.17.1 -n dev

为k8s-node1取消污点(PreferNoSchedule),并设置污点(NoSchedule)

kubectl taint node k8s-node1 tag:PreferNoSchedule-
kubectl taint node k8s-node1 tag=xudaxian:NoSchedule

此时创建pod2,如果node2可用,将会调度到node2,否则运行失败,pod2将一直处于pending状态

kubectl run pod2 --image=nginx:1.17.1 -n dev

为k8s-node1取消污点(NoSchedule),并设置污点(NoExecute)

kubectl taint node k8s-node1 tag:NoSchedule-
kubectl taint node k8s-node1 tag=xudaxian:NoExecute

此时创建pod3,如果node2可用,将会调度到node2,否则运行失败,pod3将一直处于pending状态,并且原node1上的pod会被删除

kubectl run pod3 --image=nginx:1.17.1 -n dev

使用kubeadm搭建的集群,默认就会给Master节点添加一个污点标记,所以Pod默认不会调度到Master节点上。

在Node上添加污点用来拒绝Pod调度,但是如果就是想让一个Pod调度到一个有污点的Node上去,这时就需要使用到容忍。

污点就是拒绝,容忍就是忽略,Node通过污点拒绝Pod调度上去,Pod通过容忍忽略拒绝。

在上面的污点中,已经给k8s-node1打上了NoExecute的污点,Pod是调度不上去的,此时可以通过在Pod中添加容忍,将Pod调度上去。

apiVersion: v1
kind: Pod
metadata:
  name: pod-toleration
  namespace: dev
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
  tolerations: # 容忍
    - key: "tag" # 要容忍的污点的key
      operator: Equal # 操作符
      value: "xudaxian" # 要容忍的污点的value
      effect: NoExecute # 添加容忍的规则,这里必须和标记的污点规则相同

Pod控制器的介绍

Pod的创建方式有两种:
○ 自主式Pod:即直接创建Pod,这种Pod删除后就没有了。
○ 控制器创建Pod:通过Pod控制器创建的Pod,这种Pod删除之后还会自动重建。

Pod控制器是管理Pod的中间层,它就会创建出满足条件的Pod并确保每一个Pod处于期望的状态。如果Pod在运行中出现故障,控制器会基于指定的策略重启或重建Pod。

常见的pod控制器有下面这些:
○ ReplicationController:比较原始的Pod控制器,已经被废弃,由ReplicaSet替代。
ReplicaSet:保证指定数量的Pod运行。
Deployment:通过控制ReplicaSet来控制Pod,并支持滚动升级、版本回退。
Horizontal Pod Autoscaler:可以根据集群负载自动调整Pod的数量,实现削峰填谷。
DaemonSet:在集群中的指定Node上都运行一个副本,一般用于守护进程类的任务。
Job:它创建出来的Pod只要完成任务就立即退出,用于执行一次性任务。
CronJob:它创建的Pod会周期性的执行,用于执行周期性的任务。
StatefulSet:管理有状态的应用。

replicaset

apiVersion: apps/v1 # 版本号 
kind: ReplicaSet # 类型 
metadata: # 元数据 
  name: # rs名称
  namespace: # 所属命名空间 
  labels: #标签 
    controller: rs 
spec: # 详情描述 
  replicas: 3 # 副本数量 
  selector: # 选择器,通过它指定该控制器管理哪些po
    matchLabels: # Labels匹配规则 
      app: nginx-pod 
    matchExpressions: # Expressions匹配规则 
      - {key: app, operator: In, values: [nginx-pod]} 
template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本 
  metadata: 
    labels: 
      app: nginx-pod 
  spec: 
    containers: 
      - name: nginx 
        image: nginx:1.17.1 
        ports: 
        - containerPort: 80

为了更好的解决服务编排的问题,kubernetes在v1.2版本开始,引入了Deployment控制器。值得一提的是,Deployment控制器并不直接管理Pod,而是通过管理ReplicaSet来间接管理Pod,即:Deployment管理ReplicaSet,ReplicaSet管理Pod。所以Deployment的功能比ReplicaSet强大。

apiVersion: apps/v1 # 版本号 
kind: Deployment # 类型 
metadata: # 元数据 
  name: # rs名称 
  namespace: # 所属命名空间 
  labels: #标签 
    controller: deploy 
spec: # 详情描述 
  replicas: 3 # 副本数量 
  revisionHistoryLimit: 3 # 保留历史版本,默认为10 
  paused: false # 暂停部署,默认是false 
  progressDeadlineSeconds: 600 # 部署超时时间(s),默认是600 
  strategy: # 策略 
    type: RollingUpdate # 滚动更新策略 
    rollingUpdate: # 滚动更新 
      maxSurge: 30% # 最大额外可以存在的副本数,可以为百分比,也可以为整数 maxUnavailable: 30% # 最大不可用状态的    Pod 的最大值,可以为百分比,也可以为整数 
  selector: # 选择器,通过它指定该控制器管理哪些pod 
    matchLabels: # Labels匹配规则 
      app: nginx-pod 
    matchExpressions: # Expressions匹配规则 
      - {key: app, operator: In, values: [nginx-pod]} 
  template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本 
    metadata: 
      labels: 
        app: nginx-pod 
    spec: 
      containers: 
      - name: nginx 
        image: nginx:1.17.1 
        ports: 
        - containerPort: 80

使用scale扩容或缩容,或直接修改yml中的replicas,再重新apply

kubectl scale deploy pc-deployment --replicas=5 -n dev

strategy指定镜像的更新策略,可选Recreate和rollingUpdate,默认rollingUpdate
Recreate:在创建出新的Pod之前会先杀掉所有已经存在的Pod
RollingUpdate:滚动更新,就是杀死一部分,就启动一部分,在更新过程中,存在两个版本的Pod

strategy: 
  type: RollingUpdate
  rollingUpdate: #当type为RollingUpdate的时候生效,用于为rollingUpdate设置参数,支持两个属性:
    maxUnavailable: 25% #用来指定在升级过程中不可用的Pod的最大数量,默认为25%。
    maxSurge: 25% #用来指定在升级过程中可以超过期望的Pod的最大数量,默认为25%。

镜像升级

kubectl set image deployment pc-deployment nginx=nginx:1.17.2 -n dev

或修改yml中的iamge,重新apply

版本回退

kubetl rollout 参数 deploy xx  # 支持下面的选择
# status 显示当前升级的状态
# history 显示升级历史记录
# pause 暂停版本升级过程
# resume 继续已经暂停的版本升级过程
# restart 重启版本升级过程
# undo 回滚到上一级版本 (可以使用--to-revision回滚到指定的版本)

关于滚动更新和版本回退:https://www.jianshu.com/p/0043c2508ef2

Horizontal Pod Autoscaler(HPA)

手动执行kubectl scale命令实现Pod的扩缩容不符合kubernetes的定位目标–自动化和智能化。kubernetes可以通过监测Pod的使用情况,实现Pod数量的自动调整,于是就产生了HPA这种控制器。

HPA可以获取每个Pod的利用率,然后和HPA中定义的指标进行对比,计算出需要伸缩的具体值,实现Pod的数量的调整。

安装metrics-server(监控集群中的资源使用情况)

wget https://github.com/kubernetes-sigs/metrics-server/archive/v0.3.6.tar.gz
tar -zxvf v0.3.6.tar.gz
cd metrics-server-0.3.6/deploy/1.8+/
vim metrics-server-deployment.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: metrics-server
  namespace: kube-system
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: metrics-server
  namespace: kube-system
  labels:
    k8s-app: metrics-server
spec:
  selector:
    matchLabels:
      k8s-app: metrics-server
  template:
    metadata:
      name: metrics-server
      labels:
        k8s-app: metrics-server
    spec:
      hostNetwork: true
      serviceAccountName: metrics-server
      volumes:
      # mount in tmp so we can safely use from-scratch images and/or read-only containers
      - name: tmp-dir
        emptyDir: {}
      containers:
      - name: metrics-server
        image: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server-amd64:v0.3.6 
        imagePullPolicy: Always
        args:
        - --kubelet-insecure-tls 
        - --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
        volumeMounts:
        - name: tmp-dir
          mountPath: /tmp
#报错时执行
kubectl delete -f ./
sed -i 's#rbac.authorization.k8s.io/v1beta1#rbac.authorization.k8s.io/v1#' auth-reader.yaml
sed -i 's#rbac.authorization.k8s.io/v1beta1#rbac.authorization.k8s.io/v1#' auth-delegator.yaml
sed -i 's#apiregistration.k8s.io/v1beta1#apiregistration.k8s.io/v1#' metrics-apiservice.yaml

kubectl apply -f ./

查看资源使用情况


创建deployment

apiVersion: apps/v1 # 版本号
kind: Deployment # 类型
metadata: # 元数据
  name: nginx # deployment的名称
  namespace: dev # 命名类型
spec: # 详细描述
  selector: # 选择器,通过它指定该控制器可以管理哪些Pod
    matchLabels: # Labels匹配规则
      app: nginx-pod
  template: # 模块 当副本数据不足的时候,会根据下面的模板创建Pod副本
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
        - name: nginx # 容器名称
          image: nginx:1.17.1 # 容器需要的镜像地址
          ports:
            - containerPort: 80 # 容器所监听的端口
          resources: # 资源限制
            requests:
              cpu: "100m" # 100m表示100millicpu,即0.1个CPU

创建service

kubectl expose deployment nginx --name=nginx --type=NodePort --port=80 --target-port=80 -n dev

部署HPA,关联deployment,实现自动扩缩容

apiVersion: autoscaling/v1 # 版本号
kind: HorizontalPodAutoscaler # 类型
metadata: # 元数据
  name: pc-hpa # deployment的名称
  namespace: dev # 命名类型
spec:
  minReplicas: 1 # 最小Pod数量
  maxReplicas: 10 # 最大Pod数量
  targetCPUUtilizationPercentage: 3 # CPU使用率指标
  scaleTargetRef:  # 指定要控制的Nginx的信息
    apiVersion: apps/v1
    kind: Deployment
    name: nginx

DaemonSet
每向集群中添加一个节点,指定的Pod副本也将添加到该节点上。
当节点从集群中移除的时候,Pod也会被回收。

apiVersion: apps/v1 # 版本号
kind: DaemonSet # 类型
metadata: # 元数据
  name: # 名称
  namespace: #命名空间
  labels: #标签
    controller: daemonset
spec: # 详情描述
  revisionHistoryLimit: 3 # 保留历史版本
  updateStrategy: # 更新策略
    type: RollingUpdate # 滚动更新策略
    rollingUpdate: # 滚动更新
      maxUnavailable: 1 # 最大不可用状态的Pod的最大值,可用为百分比,也可以为整数
  selector: # 选择器,通过它指定该控制器管理那些Pod
    matchLabels: # Labels匹配规则
      app: nginx-pod
    matchExpressions: # Expressions匹配规则
      - key: app
        operator: In
        values:
          - nginx-pod
  template: # 模板,当副本数量不足时,会根据下面的模板创建Pod模板
     metadata:
       labels:
         app: nginx-pod
     spec:
       containers:
         - name: nginx
           image: nginx:1.17.1
           ports:
             - containerPort: 80

Job
Job会记录成功结束的Pod数量。
当成功结束的Pod达到指定的数量时,Job将完成执行。

apiVersion: batch/v1 # 版本号
kind: Job # 类型
metadata: # 元数据
  name:  # 名称
  namespace:  #命名空间
  labels: # 标签
    controller: job
spec: # 详情描述
  completions: 1 # 指定Job需要成功运行Pod的总次数,默认为1
  parallelism: 1 # 指定Job在任一时刻应该并发运行Pod的数量,默认为1
  activeDeadlineSeconds: 30 # 指定Job可以运行的时间期限,超过时间还没结束,系统将会尝试进行终止
  backoffLimit: 6 # 指定Job失败后进行重试的次数,默认为6
  manualSelector: true # 是否可以使用selector选择器选择Pod,默认为false
  selector: # 选择器,通过它指定该控制器管理那些Pod
    matchLabels: # Labels匹配规则
      app: counter-pod
    matchExpressions: # Expressions匹配规则
      - key: app
        operator: In
        values:
          - counter-pod
  template: # 模板,当副本数量不足时,会根据下面的模板创建Pod模板
     metadata:
       labels:
         app: counter-pod
     spec:
       restartPolicy: Never # 重启策略只能设置为Never或OnFailure
       containers:
         - name: counter
           image: busybox:1.30
           command: ["/bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1;do echo $i;sleep 20;done"]

CronJob控制器借助Job控制器管理Pod,可以在特定的时间点反复去执行Job任务。

apiVersion: batch/v1beta1 # 版本号
kind: CronJob # 类型
metadata: # 元数据
  name: pc-cronjob # 名称
  namespace: dev  #命名空间
spec: # 详情描述
  schedule: "*/1 * * * * " # cron格式的作业调度运行时间点,用于控制任务任务时间执行
  jobTemplate: # job控制器模板,用于为cronjob控制器生成job对象,下面其实就是job的定义
    metadata: {}
    spec:
      template: # 模板,当副本数量不足时,会根据下面的模板创建Pod模板
        spec:
          restartPolicy: Never # 重启策略只能设置为Never或OnFailure
          containers:
            - name: counter
              image: busybox:1.30
              command: [ "/bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1;do echo $i;sleep 2;done" ]

StatefulSet创建的pod有唯一标识

apiVersion: v1
kind: Service
metadata:
  name: service-headliness
  namespace: dev
spec:
  selector:
    app: nginx-pod
  clusterIP: None # 将clusterIP设置为None,即可创建headliness Service,StatefulSet需要用到
  type: ClusterIP
  ports:
    - port: 80 # Service的端口
      targetPort: 80 # Pod的端口
---

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: pc-statefulset
  namespace: dev
spec:
  replicas: 3
  serviceName: service-headliness
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
        - name: nginx
          image: nginx:1.17.1
          ports:
            - containerPort: 80
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容