Kubernetes第七篇:Pod进阶Controller进阶Resource和Dashboard

Posted 毛奇志

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kubernetes第七篇:Pod进阶Controller进阶Resource和Dashboard相关的知识,希望对你有一定的参考价值。

文章目录

一、前言

本文介绍了Kubernetes中Pod进阶、Controller进阶、Resource和Dashboard等知识。

相关资源地址:https://download.csdn.net/download/qq_36963950/85546332

二、Pod进阶学习之路

2.1 Pod的生命周期Lifecycle

官网:https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/

  • 挂起(Pending):Pod 已被 Kubernetes 系统接受,但有一个或者多个容器镜像尚未创建。等待时间包括调度 Pod 的时间和通过网络下载镜像的时间,这可能需要花点时间。

  • 运行中(Running):该 Pod 已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态。

  • 成功(Succeeded):Pod 中的所有容器都被成功终止,并且不会再重启。

  • 失败(Failed):Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。

  • 未知(Unknown):因为某些原因无法取得 Pod 的状态,通常是因为与 Pod 所在主机通信失败。

注意:对于最小逻辑单元pod来说( kubectl get pod) 正常状态是 running;
对于最小物理单元node来说( kubectl get node),正常状态是 ready 。

2.2 Pod的重启策略RestartPolicy

官网https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy

A PodSpec has a restartPolicy field with possible values Always, OnFailure, and Never. The default value is Always. (默认是always) restartPolicy applies to all Containers in the Pod. restartPolicy only refers to restarts of the Containers by the kubelet on the same node. Exited Containers that are restarted by the kubelet are restarted with an exponential back-off delay (10s, 20s, 40s …) capped at five minutes, and is reset after ten minutes of successful execution. As discussed in the Pods document, once bound to a node, a Pod will never be rebound to another node.

小结:Pod中重启策略包括三种,如下:

  • Always:容器失效时重启(默认方式)
  • OnFailure:容器终止运行且退出码不为0时重启,即失败重启
  • Never:永远不重启

2.3 静态Pod

Pod分为两类,一类是普通Pod,通过yaml创建,一类是静态Pod(Static Pod)。

静态Pod
(1) 静态Pod是由kubelet进行管理的;
(2) 存在于特定的Node上,比如master节点Node;
(3) 无法与ReplicationController,Ddeployment或者DaemonSet进行关联,也无法进行健康检查。

普通Pod
(1) 通过API Server进行管理;
(2) 随机分配到某个node执行,除非使用 selectNode 属性指定运行在哪个node上;
(3) 可以与ReplicationController,Ddeployment或者DaemonSet进行关联,也无法进行健康检查。

静态Pod可以通过 kubectl get pods -o wide -n kube-system 来查看,这些都是 kubeadm-init 初始化安装的, 在 /etc/kubernetes/manifests 目录下, 里面有很多 yaml ,如下:

问题:开发中,程序员如何一眼判断哪些是静态Pod,哪些是普通Pod?
回答:静态Pod存在于特定的Node上,比如master节点Node。使用 kubectl get pod -o wide ,查看 IP 这一列,这一列都是内网ip,但是有不同,静态Pod都是使用的是具体的node的内网ip,普通Pod使用的都是 calico 生成的虚拟IP。

2.4 Pod的健康检查

pod的健康检查:deployment里面的一个可选属性,即是否开启健康检查。

官网https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes

Pod的健康检查是通过探针来完成的,针对运行中的容器,kubelet 可以选择是否执行以下三种探针(存活态探针、就绪态探针、启动探针 ),以及如何针对探测结果作出反应:

livenessProbe
指示容器是否正在运行。如果存活态探测失败,则 kubelet 会杀死容器, 并且容器将根据其重启策略(三种:Always、OnFailure、Never)决定未来。如果容器不提供存活探针, 则默认状态为 Success。

readinessProbe
指示容器是否准备好为请求提供服务。如果就绪态探测失败, 端点控制器将从与 Pod 匹配的所有服务的端点列表中删除该 Pod 的 IP 地址。 初始延迟之前的就绪态的状态值默认为 Failure。 如果容器不提供就绪态探针,则默认状态为 Success。

startupProbe
指示容器中的应用是否已经启动。如果提供了启动探针,则所有其他探针都会被 禁用,直到此探针成功为止。如果启动探测失败,kubelet 将杀死容器,而容器依其 重启策略进行重启。 如果容器没有提供启动探测,则默认状态为 Success。

2.5 ConfigMap

官网https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/

ConfigMaps allow you to decouple configuration artifacts from image content to keep containerized applications portable.

说白了就是用来保存配置数据的键值对,也可以保存单个属性,也可以保存配置文件。

所有的配置内容都存储在etcd中,创建的数据可以供Pod使用。

2.5.1 ConfigMap的创建

创建方式1:命令行创建configmap

# 创建一个名称为my-config的ConfigMap,key值时db.port,value值是'3306'   literal表示命令行
kubectl create configmap my-config --from-literal=db.port='3306'
kubectl get configmap
kubectl get configmap my-config -o yaml

创建方式2:根据配置文件中创建configmap

创建一个文件,名称为app.properties

name=jack
age=17
kubectl create configmap app --from-file=./app.properties
kubectl get configmap
kubectl get configmap app -o yaml

演示如下:

创建方式3:通过yaml文件创建configmap

configmaps.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  special.how: very
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: env-config
  namespace: default
data:
  log_level: INFO
kubectl apply -f configmaps.yaml
kubectl get configmap
kubectl get configmap special-config -o yaml
kubectl get configmap env-config -o yaml

演示如下:

2.5.2 ConfigMap的使用

  • 使用方式
(1)通过环境变量的方式,直接传递给pod
	使用configmap中指定的key
	使用configmap中所有的key
(2)通过在pod的命令行下运行的方式(启动命令中)
(3)作为volume的方式挂载到pod内
  • 注意
(1)ConfigMap必须在Pod使用它之前创建
(2)使用envFrom时,将会自动忽略无效的键
(3)Pod只能使用同一个命名空间的ConfigMap

使用方式1:环境变量env使用configmap

需要使用valueFrom、configMapKeyRef、name:
(1) valueFrom在最外层,表示是env某个key对应的value值
(2) configMapKeyRef 在 valueFrom 下面一层,表示这个 valueFrom 的值来自某个结构
(3) name 又在 configMapKeyRef 下面一层,

vi test-pod.yaml 
kubectl apply -f test-pod.yaml
kubectl logs pod-name
apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: busybox
      command: [ "/bin/sh", "-c", "env" ]
      env:
        # Define the environment variable
        - name: SPECIAL_LEVEL_KEY
          valueFrom:
            configMapKeyRef:
              # The ConfigMap containing the value you want to assign to SPECIAL_LEVEL_KEY
              name: special-config
              # Specify the key associated with the value
              key: special.how
  restartPolicy: Never

使用方式2:命令行command使用configmap

key的话指定要用到的key

vi test-pod.yaml 
kubectl apply -f test-pod2.yaml
kubectl logs pod-name
apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: busybox
      command: [ "/bin/sh", "-c", "env" ]
      env:
        # Define the environment variable
        - name: SPECIAL_LEVEL_KEY
          valueFrom:
            configMapKeyRef:
              # The ConfigMap containing the value you want to assign to SPECIAL_LEVEL_KEY
              name: special-config
              # Specify the key associated with the value
              key: special.how
  restartPolicy: Never

使用方式3:volume挂载使用configmap

vi pod-myconfigmap-v2.yaml 
kubectl apply -f pod-myconfigmap-v2.yaml
kubectl logs pod-name
apiVersion: v1
kind: Pod
metadata:
  name: pod-configmap2
spec:
  containers:
    - name: test-container
      image: busybox
      command: [ "/bin/sh", "-c", "ls /etc/config/" ]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        name: special-config
  restartPolicy: Never

2.6 Secret

2.6.1 Secret类型

  • Opaque:使用base64编码存储信息,可以通过base64 --decode解码获得原始数据,因此安全性弱。
  • kubernetes.io/dockerconfigjson:用于存储docker registry的认证信息。
  • kubernetes.io/service-account-token:用于被 serviceaccount 引用。serviceaccout 创建时 Kubernetes 会默认创建对应的 secret。Pod 如果使用了 serviceaccount,对应的 secret 会自动挂载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中。

2.6.2 第一种Secret类型:Opaque Secret

Opaque类型的Secret的value为base64位编码后的值

创建方式1:从文件中创建Secret

echo -n "admin" > ./username.txt
echo -n "1f2d1e2e67df" > ./password.txt
kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt
kubectl get secret

演示如下:

创建方式2:使用yaml文件创建Secret

(1)对数据进行64位编码

echo -n 'admin' | base64
echo -n '1f2d1e2e67df' | base64

(2)定义mysecret.yaml文件

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  username: YWRtaW4=
  password: MWYyZDFlMmU2N2Rm

(3)根据yaml文件创建资源并查看

kubectl create -f ./secret.yaml
kubectl get secret
kubectl get secret mysecret -o yaml

演示如下:

2.6.3 Secret使用的两种方式

  • 以Volume方式
  • 以环境变量方式

使用方式1:以Volume方式使用Secret

kubectl apply -f mypod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: redis
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    secret:
      secretName: mysecret
kubectl exec -it pod-name bash  ## 进去
ls /etc/foo
cat /etc/foo/username
cat /etc/foo/password

以Volume方式使用Secret,演示如下:

使用方式2:将Secret设置为环境变量

kubectl get secret mysecret -o yaml
vi secret-env-pod.yaml
kubectl apply -f secret-env-pod.yaml
kubectl get pod 
kubectl exec -it 具体pod名称 bash
apiVersion: v1
kind: Pod
metadata:
  name: secret-env-pod
spec:
  containers:
  - name: mycontainer
    image: redis
    env:
      - name: SECRET_USERNAME
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: username
      - name: SECRET_PASSWORD
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: password
  restartPolicy: Never

演示如下:

小结:无论configmap还是secret,都可以多种方式被创建,创建完之后都可以被pod里面的container去使用

使用的方式:环境变量(container下面的env)、参数(container下面的args)、volume目录挂载(container下面的volume)

2.6.4 第二种Secret类型:kubernetes.io/dockerconfigjson(了解即可)

kubernetes.io/dockerconfigjson用于存储docker registry的认证信息,可以直接使用kubectl create secret命令创建

2.6.5 第三种Secret类型:kubernetes.io/service-account-token(了解即可)

用于被 serviceaccount 引用。

serviceaccout 创建时 Kubernetes 会默认创建对应的 secret。Pod 如果使用了 serviceaccount,对应的 secret 会自动挂载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中。

kubectl get secret   # 可以看到service-account-token
kubectl run nginx --image nginx
kubectl get pods
kubectl exec -it nginx-pod-name bash
ls /run/secrets/kubernetes.io/serviceaccount
kubectl get secret
kubectl get pods pod-name -o yaml   
#  找到volumes选项,定位到-name,secretName
#  找到volumeMounts选项,定位到mountPath: /var/run/secrets/kubernetes.io/serviceaccount

小结:无论是ConfigMap,Secret,还是DownwardAPI,都是通过ProjectedVolume实现的,可以通过APIServer将信息放到Pod中进行使用。

三、Controller进阶学习之路

既然学习了Pod进阶,对于管理Pod的Controller肯定也要进阶一下,之前我们已经学习过的Controller有RC、RS和Deployment,除此之外还有吗?

官网https://kubernetes.io/docs/concepts/architecture/controller/

3.1 短暂性Pod:Job & CronJob

一次任务(主动触发) 完成了就是 completed 0/1 表示停止了,结束了。

持久性Pod 与 短暂性Pod

持久性Pod:就是启动之后,只要不销毁,就一直是Running,对这种Pod的管理,包括Deployment(无状态)、StatefulSet(有状态),其正常状态是Running

短暂性Pod:就是启动之后,先Running,Running完成之后就是Completed,对这种Pod的管理,包括Job,其正常状态是Completed

其中,Job也分为两种, 一次任务(主动触发) 就是 Job,定时任务(定时被动触发) 就是 CronJob。

3.1.1 Job

官网:https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/

A Job creates one or more Pods and ensures that a specified number of them successfully terminate. As pods successfully complete, the Job tracks the successful completions. When a specified number of successful completions is reached, the task (ie, Job) is complete. Deleting a Job will clean up the Pods it created.

对于RS,RC之类的控制器,能够保持Pod按照预期数目持久地运行下去,它们针对的是持久性的任务,比如web服务。

而有些操作其实不需要持久,比如压缩文件,我们希望任务完成之后,Pod就结束运行,不需要保持在系统中,此时就需要用到Job。

所以可以这样理解,Job是对RS、RC等持久性控制器的补充。

负责批量处理短暂的一次性任务,仅执行一次,并保证处理的一个或者多个Pod成功结束。

Have a try

Here is an example Job config. It computes π to 2000 places and prints it out. It takes around 10s to complete.

vi job.yaml
kubectl apply -f job.yaml # 运行
kubectl describe jobs/pi # 日志
kubectl logs pod-name # 日志

apiVersion: batch/v1
kind: Job     # 定义为job 这个pod执行完command就销毁 ,定义为deployment,这个pod执行完command一直存在
metadata:
  name: job-demo
spec:
  template:
    metadata:
      name: job-demo
    spec:
      restartPolicy: Never
      containers:
      - name: counter
        image: busybox
        command:
        - "bin/sh"
        - "-c"
        - "for i in 9 8 7 6 5 4 3 2 1; do echo $i; done"

  • 非并行Job:
    • 通常只运行一个Pod,Pod成功结束Job就退出。
  • 固定完成次数的并行Job:
    • 并发运行指定数量的Pod,直到指定数量的Pod成功,Job结束。
  • 带有工作队列的并行Job:
    • 用户可以指定并行的Pod数量,当任何Pod成功结束后,不会再创建新的Pod
    • 一旦有一个Pod成功结束,并且所有的Pods都结束了,该Job就成功结束。
    • 一旦有一个Pod成功结束,其他Pods都会准备退出。

3.1.2 CronJob

官网:https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/

A Cron Job creates Jobs on a time-based schedule.

One CronJob object is like one line of a crontab (cron table) file. It runs a job periodically on a given schedule, written in Cron format.

cronJob是基于时间进行任务的定时管理。

  • 在特定的时间点运行任务
  • 反复在指定的时间点运行任务:比如定时进行数据库备份,定时发送电子邮件等等。

3.2 有状态的Pod:StatefulSet

Nginx 是平等的,无状态的,如下:

因为nginx是不存储数据的,只是做路由转发,做负载均衡,即使是运行服务端的tomcat也是无状态的。

官网https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/

StatefulSet is the workload API object used to manage stateful applications.

Manages the deployment and scaling of a set of Pods, and provides guarantees about the ordering and uniqueness of these Pods.
  • Stable, unique network identifiers.
  • Stable, persistent storage.
  • Ordered, graceful deployment and scaling.
  • Ordered, automated rolling updates.

之前接触的Pod的管理对象比如RC、Deployment、DaemonSet和Job都是面向无状态的服务,但是现实中有很多服务是有状态的,比如mysql集群、MongoDB集群、ZK集群等,都是存储数据的,它们都有以下共同的特点:

  • 每个节点都有固定的ID,通过该ID,集群中的成员可以互相发现并且通信(不平等,每个id不同)
  • 集群的规模是比较固定的,集群规模不能随意变动
  • 集群里的每个节点都是有状态的,通常会持久化数据到永久存储中(持久化存储)
  • 如果磁盘损坏,则集群里的某个节点无法正常运行,集群功能受损

而之前的RC/Deployment没办法满足要求,所以从Kubernetes v1.4版本就引入了PetSet资源对象,在v1.5版本时更名为StatefulSet。从本质上说,StatefulSet可以看作是Deployment/RC对象的特殊变种

  • StatefulSet里的每个Pod都有稳定、唯一的网络标识,可以用来发现集群内其他的成员(不平等,每个id不同)
  • Pod的启动顺序是受控的,操作第n个Pod时,前n-1个Pod已经是运行且准备好的状态
  • StatefulSet里的Pod采用稳定的持久化存储卷,通过PV/PVC来实现,删除Pod时默认不会删除与StatefulSet相关的存储卷
  • StatefulSet需要与Headless Service配合使用

日志监控每个pv pvc 会报错,找不到bound pv

pv pvc 是持久化存储 statefulSet是有状态,其完成持久化存储必须借助pv pvc

deployment 无法满足,因为deployment里面的pod都是没有状态的

集群内唯一标识id + pod启动顺序受控制 + 持久化存储

Have a try

vi nginx-st.yaml
kubectl apply nginx-st.yaml
watch kubectl get pods # 观察pod的创建顺序,以及pod的名字(重要)

# 定义Service    service暴露出去statefulSet,和之前暴露deployment一样
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
# 定义StatefulSet
apiVersion: apps/v1
kind: StatefulSet  
metadata:
  name: web #  这里定义StatefulSet的名称,启动起来之后带了序号(状态性,每个不平等),而且顺序就是序号(有序性)
spec:
  selector:
    matchLabels:
      app: nginx 
  serviceName: "nginx"  
  replicas: 3 
  template:
    metadata:
      labels:
        app: nginx 
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
          name: web

3.3 每个Node都有的Pod:DaemonSet

官网:https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/

A DaemonSet ensures that all (or some) Nodes run a copy of a Pod. As nodes are added to the cluster, Pods are added to them. As nodes are removed from the cluster, those Pods are garbage collected. Deleting a DaemonSet will clean up the Pods it created.

DaemonSet应用场景

  • 运行集群存储 daemon,例如在每个节点上运行 glusterdceph
  • 在每个节点上运行日志收集 daemon,例如fluentdlogstash
  • 在每个节点上运行监控 daemon,例如 Prometheus Node Exportercollectd、Datadog 代理、New Relic 代理,或 Ganglia gmond

效果:就是pod在每个node节点上都运行,如下:

应用场景:普罗米修斯的日志收集,node-operator,需要pod在每个node节点上都运行。

四、Resource和Dashboard

4.1 Resource

Pod资源两要素: cpu + 内存
Pod共享两要素:网络+磁盘持久化

因为K8S的最小操作单元是Pod,所以这里主要讨论的是Pod的资源

官网https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/

在K8S的集群中,Node节点的资源信息会上报给APIServer

requests&limits

可以通过这两个属性设置cpu和内存

vi resource.yaml
kubectl apply -f resource.yaml
kubctl get pod -o wide
kubectl describe node pod所在node节点
apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
 containers:
  - name: db
    image: mysql
    env:
      - name: MYSQL_ROOT_PASSWORD
        value: "password"
    resources:
      requests:
        memory: "6Mi"     # 表示6M需要内存
        cpu: "25m"        # 表示需要0.025核的CPU
      limits:
        memory: "12Mi"    
        cpu: "50m"

limits 是上限,request是最小需要(即下限)

4.2 Dashboard

可视化:dashboard是简单的,普罗米修斯是复杂的

官网https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/

Dashboard is a web-based Kubernetes user interface. You can use Dashboard to deploy containerized applications to a Kubernetes cluster, troubleshoot your containerized application, and manage the cluster resources. You can use Dashboard to get an overview of applications running on your cluster, as well as for creating or modifying individual Kubernetes resources (such as Deployments, Jobs, DaemonSets, etc). For example, you can scale a Deployment, initiate a rolling update, restart a pod or deploy new applications using a deploy wizard.

(1)根据yaml文件创建资源
vi dashboard.yaml (比较大,放在CSDN资源文件中下载)
kubectl apply -f dashboard.yaml

(2)查看资源

kubectl get pods -n kube-system
kubectl get pods -n kube-system -o wide
kubectl get svc -n kube-system
kubectl get deploy kubernetes-dashboard -n kube-system

(3)使用火狐浏览器访问 (因为k8s中使用的是https 443,所以宿主机需要 https://宿主机ip:3008/)

https://192.168.100.151:30018/

特别注意1:在chrome浏览器中输入时,如果输入 https://192.168.100.151:30018 而不是 192.168.100.151:30018 ,即需要手动补上 https://

特别注意2:输入 https://192.168.100.151:30018 ,遇到这种情况,如下:

当前页面点击任意空白处,直接键盘输入“thisisunsafe”即可解决(不是在chrome浏览器搜索栏输入,而是选中网页,然后输入)。

原理是chrome认为这个网站是不安全的,不让你访问。而你输入了这句话,就类似于签了生死状,了解了风险。chrome就放你进去,但那之后再出问题也就没有责任了。

(4)生成登录需要的token

# 创建service account
kubectl create sa dashboard-admin -n kube-system

# 创建角色绑定关系
kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin

# 查看dashboard-admin的secret名字
ADMIN_SECRET=$(kubectl get secrets -n kube-system | grep dashboard-admin | awk 'print $1')
echo ADMIN_SECRET

# 打印secret的token
kubectl describe secret -n kube-system $ADMIN_SECRET | grep -E '^token' | awk 'print $2'

效果演示:

这里注意,dashboard.yaml 需要一个镜像 k8s.gcr.io/kubernetes-dashboard-amd64:v1.8.3 ,这个在国外,我一般是使用 docker load -i xxx.tar(或者xxx.tar.gz) 导入进去的,然后docker tag + docker push放到自己的阿里云镜像仓库,修改一下 dashboard.yaml 的 images 字段就可以使用了。


五、尾声

Kubernetes第七篇:Pod进阶、Controller进阶、Resource和Dashboard,完成了。
天天打码,天天进步!!

以上是关于Kubernetes第七篇:Pod进阶Controller进阶Resource和Dashboard的主要内容,如果未能解决你的问题,请参考以下文章

Kubernetes第七篇:使用kubernetes部署prometheus+grafana监控系统(Kubernetes工作实践类)

Kubernetes第七篇:使用kubernetes部署prometheus+grafana监控系统(Kubernetes工作实践类)

python基础-第七篇-7.2面向对象(进阶篇)

测开之函数进阶篇・第七篇《装饰器》

Kubernetes之Pod控制器应用进阶

Python之路第七篇--Python基础之面向对象及相关