容器化技术(No.3) -- Kubernetes 进阶(一) Pod 对象与常用控制器

前言

今天的分享希望大家能够:

  • 理解和掌握 Pod 对象的使用
  • 深入了解和使用常用控制器的使用

回顾

容器化技术(No.2) – Kubernetes 基础

Pod 对象

Pod 概述

Pod 是一个逻辑概念, 也是我们最长打交道的部分之一. 示例如下

  ...
  template:
    metadata:
      labels:
        app: ms-lbs
    spec:
      containers:
      - image: ms-lbs-service:latest
        imagePullPolicy: Always
        name: lbs 
  • 最小部署单元
  • 一组容器的集合
  • 一个Pod中的容器共享网络命名空间
  • Pod 是短暂的
  • 为亲密性应用而存在

什么是亲密性

> - 两个应用之间发生文件交互
> - 两个应用需要通过127.0.0.1或者socket通信
> - 两个应用需要发生频繁的调用

Pod 详解

刚才说到, Pod 是一组容器的集合, 他是一个逻辑概念, 我们知道容器之间是通过 Namespace 隔离的, Pod要想解决上述应用场景, 那么就要让Pod里的容器之间高效共享.

具体分为两个部分:网络和存储. Kubernetes 是如何实现的呢?

实现策略
  • 共享网络
    kubernetes 的方案是这样的:会在每个 Pod 里先启动一个 infrastructure container 容器 pause (700+KB), 然后让其他的容器连接进来这个网络命名空间, 然后其他容器看到的网络试图就完全一样了, 即网络设备、IP地址、Mac地址等, 这就是解决网络共享问题. 在 Pod 的 IP 地址就是 infrastructure container 的 IP 地址.

每次启动 pod 时都会启动一个 pause 容器.
共享网络

如下示例:

[root@10-255-20-158 ~]# docker ps|grep flannel
409bec1f9110        ff281650a721                                               "/opt/bin/flanneld -…"   3 weeks ago         Up 3 weeks                              k8s_kube-flannel_kube-flannel-ds-amd64-wrhfc_kube-system_dc83ec9d-df8d-4757-9dd5-b0a087c2c7b2_9
4d58e801b677        registry.aliyuncs.com/google_containers/pause:3.1          "/pause"                 3 weeks ago         Up 3 weeks                              k8s_POD_kube-flannel-ds-amd64-wrhfc_kube-system_dc83ec9d-df8d-4757-9dd5-b0a087c2c7b2_9
  • 共享存储
    通过挂载共享 volume, 使得大家到共享目录的内容一样. 如下方示例:
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: write
    image: centos
    command: ["bash","-c","for i in {1..100};do echo $i >> /data/count;sleep 1;done"]
    volumeMounts:
      - name: data
        mountPath: /data

  - name: read
    image: centos
    command: ["bash","-c","tail -f /data/count"]
    volumeMounts:
      - name: data
        mountPath: /data
  
  volumes:
  - name: data
    emptyDir: {}

上述示例中有两个容器, write 容器负责提供数据, read 消费数据, 通过数据卷将写入数据的目录和读取数据的目录都放到了该卷中, 这样每个容器都能看到该目录.

验证:

$ kubectl apply -f pod.yaml
$ kubectl logs my-pod -c read -f
  • 在 Pod 中容器分为以下几个类型:

- Infrastructure Container:基础容器, 维护整个Pod网络空间, 对用户不可见, 即 pause 容器.
- InitContainers:初始化容器, 先于业务容器开始执行, 一般用于业务容器的初始化工作.
- Containers:业务容器, 具体跑应用程序的镜像, 并行启动.

镜像拉取策略
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
    - name: nginx
      image: nginx
      imagePullPolicy: IfNotPresent

imagePullPolicy 字段有三个可选值:

  • IfNotPresent:默认值, 镜像在宿主机上不存在时才拉取
  • Always:每次创建 Pod 都会重新拉取一次镜像
  • Never: Pod 永远不会主动拉取这个镜像

如果拉取公开的镜像, 直接按照上述示例即可, 但要拉取私有的镜像, 是必须认证镜像仓库才可以, 即 docker login, 而在 Kubernetes 集群中会有多个 Node, 显然这种方式是很不放方便的!为了解决这个问题, Kubernetes 实现了自动拉取镜像的功能. 以 secret 方式保存到 Kubernetes 中, 然后传给 kubelet.

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  imagePullSecrets:
    - name: nexus-registrykey
  containers:
    - name: nginx
      image: nginx:latest
      imagePullPolicy: IfNotPresent

上述中名为 nexus-registrykey 的 secret 是由 kubectl create secret docker-registry 命令创建:

$ kubectl create secret docker-registry nexus-registrykey --docker-username=admin --docker-password=admin@1324 --docker-email=admin@nexus.com --docker-server=192.168.0.13

–docker-server: 指定docke仓库地址
–docker-username: 指定docker仓库账号
–docker-password: 指定docker仓库密码
–docker-email: 指定邮件地址(选填)

资源限制

Pod 资源限制配置分为两类:

  • 申请配额: 调度时使用, 参考是否有节点满足该配置
    spec.containers[].resources.requests.cpu
    spec.containers[].resources.requests.memory
    
  • 限制配额: 容器能使用的最大配置
    spec.containers[].resources.limits.cpu
    spec.containers[].resources.limits.memory
    

示例:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128M"
        cpu: 0.5

其中cpu值比较抽象, 可以这么理解:

1核 = 1000m
1.5核 = 1500m

那上面限制配置就是1核的二分之一(500m), 即该容器最大使用半核CPU.

该值也可以写成浮点数, 更容易理解:

半核 = 0.5
1核 = 1
1.5核 = 1.5

启用资源限制, 避免某容器资源利用率异常突发影响其他容器, 可能会产生雪崩效应!

重启策略
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
    - name: nginx
      image: nginx
    restartPolicy: Always

restartPolicy 有三种选项:

  • Always:默认策略. 当容器终止退出后, 总是重启容器.
  • OnFailure:当容器异常退出(退出状态码非0)时, 才重启容器. 适于job
  • Never:当容器终止退出, 从不重启容器. 适于job
健康检查

默认情况下, kubelet 根据容器状态作为健康依据(而不是容器中应用程序状态), 因此当出现类似程序假死的情况, 就会导致无法提供服务, 丢失流量的问题. 因此引入健康检查机制确保容器健康存活.

健康检查有两种类型:

  • livenessProbe
    如果检查失败, 将杀死容器, 根据Pod的restartPolicy来操作.
  • readinessProbe
    如果检查失败, Kubernetes会把Pod从service endpoints中剔除.

这两种类型支持三种检查方法:

  • httpGet
    发送HTTP请求, 返回200-400范围状态码为成功.
  • exec
    执行Shell命令返回状态码是0为成功.
  • tcpSocket
    发起TCP Socket建立成功.

示例:

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 60
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5

上述示例:启动容器第一件事创建文件, 停止30s, 删除该文件, 再停止60s, 确保容器还在运行中.

验证现象:容器启动正常, 30s后异常, 会restartPolicy策略自动重建, 容器继续正常, 反复现象.

调度策略

创建一个 Pod 的工作流程:
创建 Pod 流程

Pod根据调度器默认算法将Pod分配到合适的节点上, 一般是比较空闲的节点. 但有些情况我们希望将Pod分配到指定节点, 这里就需要用到如下调度策略.

  • nodeName
  • nodeSelector
  • taint & tolerations

1. nodeName

nodeName 用于将 Pod 调度到指定的 Node 名称上.

例如:下面示例会绕过调度系统, 直接分配到 k8s-node1 节点.

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: busybox
  name: busybox
  namespace: default
spec:
  nodeName: k8s-node1
  containers:
  - image: busybox
    name: bs
    command:
    - "ping"
    - "www.baidu.com"

2. nodeSelector

nodeSelector用于将Pod调度到匹配Label的Node上.

先给规划node用途, 然后打标签, 例如将两台node划分给不同团队使用:

$ kubectl label nodes k8s-node1 group=lab
$ kubectl label nodes k8s-node2 group=hive

然后在创建Pod只会被调度到含有 group=lab 标签的节点上.

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  namespace: default
spec:
  nodeSelector: 
    group: lab
  containers:
  - image: busybox
    name: test-box
    command:
    - "ping"
    - "www.baidu.com"

3. taint(污点)与tolerations(容忍)

污点应用场景:节点独占, 例如具有特殊硬件设备的节点, 如GPU

设置污点命令:

kubectl taint node [node] key=value[effect] 

其中[effect] 可取值:

  • NoSchedule :一定不能被调度.
  • PreferNoSchedule:尽量不要调度.
  • NoExecute:不仅不会调度, 还会驱逐Node上已有的Pod.

示例:

先给节点设置污点, 说明这个节点不是谁都可以调度过来的:

$ kubectl taint node k8s-node1 nodelable=gpu:NoSchedule

查看污点:

$ kubectl describe node k8s-node1 |grep Taints

然后在创建Pod只有声明了容忍污点(tolerations), 才允许被调度到 nodelable=gpu 污点节点上.

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: busybox
  name: busybox3
  namespace: default
spec:
  tolerations:
  - key: "nodelable"
    operator: "Equal"
    value: "gpu"
    effect: "NoSchedule"
  containers:
  - image: busybox
    name: busybox
    command:
    - "ping"
    - "www.baidu.com"

如果不配置容忍污点, 则永远不会调度到k8s-node1.

去掉污点:

# kubectl taint node [node] key:[effect]-
$ kubectl taint node k8s-node1 abc:NoSchedule-
故障排查常用命令
# 查看事件, 可用于大部分资源
kubectl describe TYPE/NAME    
# 如果pod启动失败, 先查看日志
kubectl logs TYPE/NAME [-c CONTAINER]  
# 进入到容器中debug
kubectl exec POD [-c CONTAINER] -- COMMAND [args...]  

控制器

Pod 与 controller 的关系

  • controllers:在集群上管理和运行容器的对象 (有时也称为工作负载 - workload)
  • 通过 label-selector 相关联, 如下图所示.
  • Pod 通过控制器实现应用的运维, 如伸缩, 滚动升级等
    控制器与 Pod 关系

无状态应用部署控制器 Deployment

Deployment功能:

  • 部署无状态应用(无状态应用简单来讲, 就是Pod可以漂移任意节点, 而不用考虑数据和IP变化)
  • 管理Pod和ReplicaSet(副本数量管理控制器)
  • 具有上线部署、副本设定、滚动升级、回滚等功能
  • 提供声明式更新, 例如只更新一个新的Image

应用场景:Web服务, 微服务

如下示例为 Deployment 标准 YAML, 通过标签与 Pod 关联.

# 控制器定义
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3    # 设置副本数
  selector:
    matchLabels:
      app: web
# 被控制对象
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - image: nginx
        name: nginx

将这个应用暴露到集群外部访问:

apiVersion: v1
kind: Service
metadata:
  labels:
    app: web
  name: web
spec:
  ports:
  - port: 80             # 集群内容访问应用端口
    protocol: TCP
    targetPort: 8080     # 容器镜像端口
    nodePort: 30008      # 对外暴露的端口
  selector:
    app: web
  type: NodePort

查看资源:

$ kubectl get pods,svc
NAME                       READY   STATUS    RESTARTS   AGE
pod/web-7dc5f5b565-cxh9t   1/1     Running   0          9s
pod/web-7dc5f5b565-gl4jz   1/1     Running   0          9s
pod/web-7dc5f5b565-qw6dq   1/1     Running   0          12s

NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
service/kubernetes   ClusterIP   10.99.103.5   <none>        443/TCP        1m
service/web          NodePort    10.1.147.15   <none>        80:30008/TCP   48s

浏览器输入:http://NodeIP:30008 即可访问到该应用.

# 升级项目, 即更新最新镜像版本, 这里换一个nginx镜像为例:
$ kubectl set image deployment/web nginx=nginx:1.15
$ kubectl rollout status deployment/web # 查看升级状态

# 如果该版本发布失败想回滚到上一个版本可以执行:
$ kubectl rollout undo deployment/web   # 回滚最新版本

# 也可以回滚到指定发布记录:
$ kubectl rollout history deployment/web  # 查看发布记录
$ kubectl rollout undo deployment/web --revision=2  # 回滚指定版本

# 扩容/缩容:
$ kubectl scale deployment nginx-deployment --replicas=5 
# --replicas设置比现在值大就是扩容, 反之就是缩容. 

kubectl set image触发滚动更新.

滚动更新原理其实很简单, 利用新旧两个replicaset, 例如副本是 3 个, 首先 Scale Up 增加新 RS 副本数量为 1, 准备就绪后, Scale Down 减少旧 RS 副本数量为 2, 以此类推, 逐渐替代, 最终旧 RS 副本数量为 0, 新 RS 副本数量为 3, 完成本次更新. 这个过程可通过 kubectl describe deployment web 看到.

守护进程控制器 DaemonSet

DaemonSet功能:

  • 在每一个Node上运行一个Pod
  • 新加入的Node也同样会自动运行一个Pod

应用场景:Agent, 例如监控采集工具, 日志采集工具

任务控制器 Job & CronJob

Job: 一次性执行

应用场景: 离线数据处理, 视频解码等业务

apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    spec:
      containers:
      - name: pi
        image: perl
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never   # 作业失败后会不再尝试创建新的Pod
  backoffLimit: 4   # .spec.backoffLimit字段限制重试次数. 默认情况下, 这个字段默认值是6. 

上述示例中将 π 计算到 2000 个位置并将其打印出来. 完成大约需要10秒.

查看任务:

$ kubectl get pods,job 

CronJob: 定时任务, 像 Linux 的 Crontab 一样.

应用场景:通知, 备份

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox
            args:
            - /bin/sh
            - -c
            - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure  # 作业失败并返回状态码非0时, 尝试创建新的Pod运行任务

上述示例中将每分钟打印一次 Hello.

查看任务:

$ kubectl get pods,cronjob

总结

Kubernetes  进阶(一)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值