【Kubernetes学习笔记】

文章目录

入门实战-namespace

一、Namespace

(1)、namespace概述

  • name是Kubernetes系统中非常重要的组成部分,它的主要作用就是用来实现多种不同的租户资源进行隔离
  • 默认情况下,Kubernetes集群中所有的pod都是可以互相访问的,但实际情况下,需要对两个不同的pod进行隔离,这个时候就将两个pod划分到不同的namespace下,Kubernetes通过将集群内部的资源分配到不同的namespace中,可以形成逻辑上的组,乙方宝不同组的资源进行隔离使用和管理。
  • 可以通过kubernetes的授权机制,将不同的namespace交给不同租户进行管理,这样就实现了多租户的资源隔离。此时还能结合kubernetes的资源配额机制,限定不同租户能占用的资源,例如CPU使用星、内存使用呈
    等,来实现租户可用资源的管理。

在这里插入图片描述

二、查看namespace

  • 在Kubernetes集群启动之后,系统会默认创建几个namespace
[root@master ~]# kubectl get namespaces 
NAME                   STATUS   AGE
default                Active   4d3h #  所有未指定Namespace的对    象都会被分配在default命名空间
dev                    Active   60m  #  之前手动创建的
kube-node-lease        Active   4d3h #  查看个集群之间的状态又称心跳维护
kube-public            Active   4d3h #  此命名空间下的资源可以被所有人访问(包括未认证用户)
kube-system            Active   4d3h #  所有由Kubernetes系统创建的资源都处于这个命名空间
kubernetes-dashboard   Active   3d1h #  部署图形化管理界面生成的namespace
  • 、查看namespace下的kube-system的集群组件
[root@master ~]# kubectl get pods -n kube-system -o wide
NAME                             READY   STATUS    RESTARTS   AGE    IP            NODE      NOMINATED NODE   READINESS GATES
coredns-bccdc95cf-hf8fx          1/1     Running   4          4d3h   10.244.0.29   master    <none>           <none>
coredns-bccdc95cf-sqpkz          1/1     Running   3          4d3h   10.244.0.30   master    <none>           <none>
etcd-master                      1/1     Running   2          4d3h   10.0.0.10     master    <none>           <none>
kube-apiserver-master            1/1     Running   2          4d3h   10.0.0.10     master    <none>           <none>
kube-controller-manager-master   1/1     Running   2          4d3h   10.0.0.10     master    <none>           <none>
kube-flannel-ds-8jpqb            1/1     Running   3          4d3h   10.0.0.10     master    <none>           <none>
kube-flannel-ds-qm56c            1/1     Running   0          4d3h   10.0.0.20     worker1   <none>           <none>
kube-flannel-ds-t7nts            1/1     Running   0          4d3h   10.0.0.30     worker2   <none>           <none>
kube-proxy-dnpxl                 1/1     Running   0          4d3h   10.0.0.20     worker1   <none>           <none>
kube-proxy-r7szb                 1/1     Running   2          4d3h   10.0.0.10     master    <none>           <none>
kube-proxy-stbzr                 1/1     Running   0          4d3h   10.0.0.30     worker2   <none>           <none>
kube-scheduler-master            1/1     Running   2          4d3h   10.0.0.10     master    <none>           <none>

  • 查看所有的namespace
[root@master ~]# kubectl get ns
NAME                   STATUS   AGE
default                Active   4d4h
dev                    Active   70m
kube-node-lease        Active   4d4h
kube-public            Active   4d4h
kube-system            Active   4d4h
kubernetes-dashboard   Active   3d2h
  • 查看指定的namespace
[root@master ~]# kubectl get namespaces dev
NAME   STATUS   AGE
dev    Active   70m
  • 查看namespace test输出指定的格式
[root@master ~]# kubectl get namespaces dev -o yaml
apiVersion: v1
kind: Namespace
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"dev"}}
  creationTimestamp: "2022-05-10T14:16:03Z"
  name: dev
  resourceVersion: "24807"
  selfLink: /api/v1/namespaces/dev
  uid: 6594adea-6cd3-432c-a034-0745e6429222
spec:
  finalizers:
  - kubernetes
status:
  phase: Active
  • 查看namespace test的描述信息
[root@master ~]# kubectl describe ns kubernetes-dashboard
Name:         kubernetes-dashboard
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"kubernetes-dashboard"}}
Status:       Active ==>Active状态表示正在运行,Terminating表示正在删除

No resource quota.

No resource limits.

[root@master ~]# kubectl describe ns dev
Name:         dev
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"dev"}}
Status:       Active

# ResourceQuota针对namespace做的资源限制
# LimitRange针对namespace中的每个组件做的资源限制
No resource quota.

No resource limits.

三、创建和删除namespace test

  • 创建
[root@master ~]# kubectl create ns power
namespace/power created
#查看状态
[root@master ~]# kubectl get ns power 
NAME    STATUS   AGE
power   Active   8s
  • 删除
[root@master ~]# kubectl delete ns power 
namespace "power" deleted
#验证是否删除
[root@master ~]# kubectl get ns power 
Error from server (NotFound): namespaces "power" not found
  • 使用配置文件创建一个namespace test
[root@master ~]# vim ns-power.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: power
#创建namespace test
[root@master ~]# kubectl create -f ns-power.yaml 
namespace/power created

#查看状态
[root@master ~]# kubectl get ns power 
NAME    STATUS   AGE
power   Active   7s

#删除该namespace test
[root@master ~]# kubectl delete -f ns-power.yaml 
namespace "power" deleted

#验证是否删除
[root@master ~]# kubectl get ns power 
Error from server (NotFound): namespaces "power" not found

四、Pod

Pod概述

  • Pod是Kubernetes集群进行管理的最小单元,程序的运行和环境需要部署在容器中,而容器必须存在于Pod中
  • Pod可以视作为容器的封装,一个Pod可以存在一个或者多个容器

(1)、查看容器

  • 查看Pod容器
[root@master ~]# kubectl get pods --namespace kube-system -o wide
NAME                             READY   STATUS    RESTARTS   AGE    IP            NODE      NOMINATED NODE   READINESS GATES
coredns-bccdc95cf-hf8fx          1/1     Running   4          4d4h   10.244.0.29   master    <none>           <none>
coredns-bccdc95cf-sqpkz          1/1     Running   3          4d4h   10.244.0.30   master    <none>           <none>
etcd-master                      1/1     Running   2          4d4h   10.0.0.10     master    <none>           <none>
kube-apiserver-master            1/1     Running   2          4d4h   10.0.0.10     master    <none>           <none>
kube-controller-manager-master   1/1     Running   2          4d4h   10.0.0.10     master    <none>           <none>
kube-flannel-ds-8jpqb            1/1     Running   3          4d4h   10.0.0.10     master    <none>           <none>
kube-flannel-ds-qm56c            1/1     Running   0          4d4h   10.0.0.20     worker1   <none>           <none>
kube-flannel-ds-t7nts            1/1     Running   0          4d4h   10.0.0.30     worker2   <none>           <none>
kube-proxy-dnpxl                 1/1     Running   0          4d4h   10.0.0.20     worker1   <none>           <none>
kube-proxy-r7szb                 1/1     Running   2          4d4h   10.0.0.10     master    <none>           <none>
kube-proxy-stbzr                 1/1     Running   0          4d4h   10.0.0.30     worker2   <none>           <none>
kube-scheduler-master            1/1     Running   2          4d4h   10.0.0.10     master    <none>           <none>

(2)、创建Nginx Pod

  • 创建一个Nginx的pod
# 命令格式: kubectl run (pod控制器名称) [参数] 
# --image  指定Pod的镜像
# --port   指定端口
# --namespace  指定namespace
#创建一个Nginx的pod
[root@master ~]# kubectl run nginx --image=nginx:latest --port=80 --namespace dev
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/nginx created

#查看是否运行
[root@master ~]# kubectl get pod -n dev
NAME                     READY   STATUS    RESTARTS   AGE
nginx-5ff9d6cc77-xt68z   1/1     Running   0          2m22s
#后面追加参数“-o wide”查看更为详细的参数
[root@master ~]# kubectl get pod -n dev -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
nginx-5ff9d6cc77-xt68z   1/1     Running   0          3m23s   10.244.0.36   master   <none>           <none>

#查看Nginx pod的详细描述信息
[root@master ~]# kubectl describe pod nginx-5ff9d6cc77-xt68z -n dev
Name:           nginx-5ff9d6cc77-xt68z
Namespace:      dev
Priority:       0
Node:           master/10.0.0.10
Start Time:     Wed, 11 May 2022 00:14:04 +0800
Labels:         pod-template-hash=5ff9d6cc77
                run=nginx
Annotations:    <none>
Status:         Running
IP:             10.244.0.36
Controlled By:  ReplicaSet/nginx-5ff9d6cc77
Containers:
  nginx:
    Container ID:   docker://a7c46e132845d6e335f572a8010dd5ec44f82d1d46e113c246bcabc631cf3c86
    Image:          nginx:latest
    Image ID:       docker-pullable://nginx@sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Wed, 11 May 2022 00:14:20 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-mpqp8 (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  default-token-mpqp8:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-mpqp8
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age    From               Message
  ----    ------     ----   ----               -------
  Normal  Scheduled  9m33s  default-scheduler  Successfully assigned dev/nginx-5ff9d6cc77-xt68z to master
  Normal  Pulling    9m32s  kubelet, master    Pulling image "nginx:latest"
  Normal  Pulled     9m17s  kubelet, master    Successfully pulled image "nginx:latest"
  Normal  Created    9m17s  kubelet, master    Created container nginx
  Normal  Started    9m17s  kubelet, master    Started container nginx

(3)、查看Nginx Pod的ip和映射的端口,访问

  • 查看端口
[root@master ~]# kubectl get pods -n dev -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
nginx-5ff9d6cc77-xt68z   1/1     Running   0          13m   10.244.0.36   master   <none>           <none>
  • 验证
[root@master ~]# curl 10.244.0.36:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

(4)、删除指定Pod

  • Kubernetes管理pod是采用Pod控制器管理的,当前Pod是由Pod控制器创建的,控制器会监控Pod状况,一旦发现Pod死亡,会立即重建
  • 如果想要删除Pod,需要删除Pod控制器
#查看Pod此时的状态
[root@master ~]# kubectl get pod -n dev
NAME                     READY   STATUS    RESTARTS   AGE
nginx-5ff9d6cc77-xt68z   1/1     Running   0          22m

#查看Pod控制器
[root@master ~]# kubectl get deploy -n dev
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           23m

#删除控制器
[root@master ~]# kubectl delete deployment nginx -n dev
deployment.extensions "nginx" deleted

#验证是否删除
[root@master ~]# kubectl get deploy -n dev
No resources found.
[root@master ~]# kubectl get pod -n dev
No resources found.

(5)、yaml语言介绍

Yaml概述:

YAML是一个类似于XML、JSON的标记性语言,它强调以数据为中心,并不是以标识语言为重点.因而YAML本身的定义比较简单,号称一种人性化的数据格式语言.

Yaml语法:

①.大小写敏感

②.使用缩进表示层级关系

③.缩进不允许使用Tab,只允许使用空格(对于低版本的限制)

④.缩进的空格数不重要,只要相同层级的元素左对齐即可

⑤.'#'表示注释

  • yaml支持以下几种数据类型
数据类型
纯量:单个的、不可再分的值
对象:键值对的集合,又称为映射(mapping)/ 哈希(hash) / 字典(dictionary)
数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
# 纯量, 就是指的一个简单的值,字符串、布尔值、整数、浮点数、Null、时间、日期
# 1 布尔类型
c1: true (或者True)
# 2 整型
c2: 234
# 3 浮点型
c3: 3.14
# 4 null类型 
c4: ~  # 使用~表示null
# 5 日期类型
c5: 2018-02-17    # 日期必须使用ISO 8601格式,即yyyy-MM-dd
# 6 时间类型
c6: 2018-02-17T15:02:31+08:00  # 时间使用ISO 8601格式,时间和日期之间使用T连接,最后使用+代表时区
# 7 字符串类型
c7: heima     # 简单写法,直接写值 , 如果字符串中间有特殊字符,必须使用双引号或者单引号包裹 
c8: line1
    line2     # 字符串过多的情况可以拆成多行,每一行会被转化成一个空格
    
    # 对象
# 形式一(推荐):
heima:
  age: 15
  address: Beijing
# 形式二(了解):
heima: {age: 15,address: Beijing}

Tips:

1 书写yaml切记: 后面要加一个空格

2 如果需要将多段yaml配置放在一个文件中,中间要使用---分隔

3 下面是一个yaml转json的网站,可以通过它验证yaml是否书写正确

https://www.json2yaml.com/convert-yaml-to-json

(6)、使用yaml配置文件创建一一个Nginx Pod

  • 首先编写一个Nginx的yaml文件
[root@master ~]# vim pod-nginx.yaml

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: dev
spec:
  containers:
  - image: nginx:latest
    name: pod
    ports:
    - name: nginx-port
      containerPort: 80
      protocol: TCP
  • 创建
[root@master ~]# kubectl create -f pod-nginx.yaml 
pod/nginx created

#查看状态
[root@master ~]# kubectl get pod -n dev
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          44s
  • 删除Nginx Pod
[root@master ~]# kubectl delete -f pod-nginx.yaml 
pod "nginx" deleted

#查看状态
[root@master ~]# kubectl get pod -n dev
No resources found.

四、多种配置方式

  • (1)、命令式对象配置:

命令式对象配置就是使用命令配合配置文件一起来操作kubernetes资源

创建一个nginxpod.yaml:输入以下内容

[root@zabbix-server ~]# vim nginxpod.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: pods

---

apiVersion: v1
kind: Pod
metadata:
  name: nginxpod
  namespace: pods
spec:
  containers:
   - name: nginx-conntainers
     image: nginx:1.20.0

  • 执行create命令,创建一个资源
[root@zabbix-server ~]# kubectl create -f nginxpod.yaml 
namespace/dev created
pod/nginxpod created

[root@k8s-master ~]# kubectl get pod -n pods 
NAME       READY   STATUS    RESTARTS   AGE
nginxpod   1/1     Running   0          117s

#查看Nginx容器的详细数据
[root@k8s-master ~]# kubectl describe pod -n pods nginxpod 
Name:         nginxpod
Namespace:    pods
Priority:     0
Node:         computer/10.0.0.10
Start Time:   Wed, 10 Aug 2022 14:52:36 +0800
Labels:       <none>
Annotations:  <none>
Status:       Running
IP:           10.244.1.7
IPs:
  IP:  10.244.1.7
Containers:
  nginx-conntainers:
    Container ID:   docker://c4d1afe15ddcfeb7d795fac337e1f5e3d3cdf1f5af77528fe8096ada9b47f48a
    Image:          nginx:1.20.0
    Image ID:       docker-pullable://nginx@sha256:ea4560b87ff03479670d15df426f7d02e30cb6340dcd3004cdfc048d6a1d54b4
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Wed, 10 Aug 2022 14:53:24 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-jl2jr (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  kube-api-access-jl2jr:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  112s  default-scheduler  Successfully assigned pods/nginxpod to computer
  Normal  Pulling    111s  kubelet            Pulling image "nginx:1.20.0"
  Normal  Pulled     65s   kubelet            Successfully pulled image "nginx:1.20.0" in 46.413550509s
  Normal  Created    64s   kubelet            Created container nginx-conntainers
  Normal  Started    64s   kubelet            Started container nginx-conntainers

#查看IP地址
[root@k8s-master ~]# kubectl get pod -n pods -o wide
NAME       READY   STATUS    RESTARTS   AGE     IP           NODE       NOMINATED NODE   READINESS GATES
nginxpod   1/1     Running   0          5m18s   10.244.1.7   computer   <none>           <none>

[root@k8s-master ~]# curl 10.244.1.7
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and

  • (2)、声明式对象配置

声明式对象配置: 通过apply命令和配置文件去操作kubernetes资源,apply命令和create的区别就是,如果yaml文件里面的环境已有就是更新,没有就是创建.

#我们修改一下刚刚的nginxpod.yaml文件
[root@k8s-master ~]# cat nginxpod.yaml 
apiVersion: v1
kind: Namespace
metadata:
  name: pods

---

apiVersion: v1
kind: Pod
metadata:
  name: nginxpod
  namespace: pods
spec:
  containers:
   - name: nginx-conntainers
     image: nginx:1.21.0	==>修改为1.21.0
     
 #执行apply命令
[root@k8s-master ~]# kubectl apply -f nginxpod.yaml 
namespace/pods configured
pod/nginxpod configured

#重新查看详细信息
[root@k8s-master ~]# kubectl describe pod -n pods nginxpod 
Name:         nginxpod
Namespace:    pods
Priority:     0
Node:         computer/10.0.0.10
Start Time:   Wed, 10 Aug 2022 14:52:36 +0800
Labels:       <none>
Annotations:  <none>
Status:       Running
IP:           10.244.1.7
IPs:
  IP:  10.244.1.7
Containers:
  nginx-conntainers:
    Container ID:   docker://c4d1afe15ddcfeb7d795fac337e1f5e3d3cdf1f5af77528fe8096ada9b47f48a
    Image:          nginx:1.21.0
    Image ID:       docker-pullable://nginx@sha256:ea4560b87ff03479670d15df426f7d02e30cb6340dcd3004cdfc048d6a1d54b4
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Wed, 10 Aug 2022 14:53:24 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-jl2jr (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  kube-api-access-jl2jr:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  11m   default-scheduler  Successfully assigned pods/nginxpod to computer
  Normal  Pulling    11m   kubelet            Pulling image "nginx:1.20.0"
  Normal  Pulled     10m   kubelet            Successfully pulled image "nginx:1.20.0" in 46.413550509s
  Normal  Created    10m   kubelet            Created container nginx-conntainers
  Normal  Started    10m   kubelet            Started container nginx-conntainers
  Normal  Killing    33s   kubelet            Container nginx-conntainers definition changed, will be restarted
  Normal  Pulling    33s   kubelet            Pulling image "nginx:1.21.0"	==>发现image version已经更新

node节点上执行kubectl命令

#首先我们要把master主节点上的环境变量拷贝到node节点下
[root@k8s-master ~]# scp -r ~/.kube/ computer:~/

#或者设置一个环境变量也可以
创建更资源使用声明式对象配置: kubectl apply -f xxx.taml
删除资源使用命令式对象配置: kubectl delete -f xxx.yaml
查询资源使用命令式对象管理: kubectl get (describe) 资源名称

五、Pod

Pod

Pod 是k8s集群进行管理的最小单元,程序要运行在部署的容器当中,而容器必须存在于 Pod

中,Pod 可以认为是容器的封装,一个Pod中可以存在一个或者多个容器.k8s多少个节点就有对应的服务

k8s对于Pod的管理是通过Pod控制器,如果当pod控制器发现一个pod死亡,会立即重建一个pod,为pod提供高可用、冗余服务.

所以想要删除一个pod容器必须删除pod控制器.

容器功能
①.coredns:用于k8s的dns解析
②.etcd:负责存储k8s整个集群的状态
③.apiserver:负责消息的接收
④.controller-manager:负责进行提供服务
⑤.flannel:负责k8s集群中的网络
[root@xnode1 ~]# kubectl get pod -n kube-system
NAME                             READY   STATUS    RESTARTS   AGE
coredns-8686dcc4fd-f9pqv         1/1     Running   2          5h57m
coredns-8686dcc4fd-mtcmn         1/1     Running   5          5h57m
etcd-xnode1                      1/1     Running   2          5h56m
kube-apiserver-xnode1            1/1     Running   2          5h56m
kube-controller-manager-xnode1   1/1     Running   2          5h56m
kube-flannel-ds-amd64-67htn      1/1     Running   2          5h41m
kube-flannel-ds-amd64-frh8l      1/1     Running   2          5h45m
kube-proxy-ptlm8                 1/1     Running   2          82m
kube-proxy-rjgfs                 1/1     Running   0          82m
kube-scheduler-xnode1            1/1     Running   3          5h56m

#创建一个容器
[root@xnode1 ~]# kubectl create namespace dev
namespace/dev created
[root@xnode1 ~]# kubectl run nginx --image=nginx:1.17.1 --port=80 --namespace=dev
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/nginx created

#查看容器的详细信息
[root@xnode1 ~]# kubectl describe pod -n dev nginx-64959c9fb5-szlnj 
Name:               nginx-64959c9fb5-szlnj
Namespace:          dev
Priority:           0
PriorityClassName:  <none>
Node:               xnode2/10.0.0.40
Start Time:         Wed, 17 Aug 2022 05:04:40 -0400
Labels:             pod-template-hash=64959c9fb5
                    run=nginx
Annotations:        <none>
Status:             Running
IP:                 10.244.1.15
Controlled By:      ReplicaSet/nginx-64959c9fb5
Containers:
  nginx:
    Container ID:   docker://9d76ced9a4d34619d56ab1a5775432abf028d4cc19cc73115a36737021431d7c
    Image:          nginx:1.17.1
    Image ID:       docker-pullable://nginx@sha256:b4b9b3eee194703fc2fa8afa5b7510c77ae70cfba567af1376a573a967c03dbb
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Wed, 17 Aug 2022 05:04:42 -0400
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-wltjd (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  default-token-wltjd:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-wltjd
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  2m2s  default-scheduler  Successfully assigned dev/nginx-64959c9fb5-szlnj to xnode2
  Normal  Pulled     2m    kubelet, xnode2    Container image "nginx:1.17.1" already present on machine
  Normal  Created    2m    kubelet, xnode2    Created container nginx
  Normal  Started    2m    kubelet, xnode2    Started container nginx
  
#访问该Nginx pod:查询dev namespace下的Nginxpod容器IP地址
[root@xnode1 ~]# kubectl get pod -n dev nginx-64959c9fb5-szlnj -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
nginx-64959c9fb5-szlnj   1/1     Running   0          14m   10.244.1.15   xnode2   <none>           <none>

[root@xnode1 ~]# curl 10.244.1.15:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

查看pod控制器

删除pod:先将pod控制器删除,pod也就没了

[root@xnode1 ~]# kubectl get deployment -n dev 
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           20m

[root@xnode1 ~]# kubectl delete deployment nginx -n dev 
deployment.extensions "nginx" deleted
[root@xnode1 ~]# kubectl get pod -n dev 
No resources found.

六、Label

Label:

Label是k8s系统中的一个重要的概念,它的作用就是在资源商添加标识,对他们进行区分和选择.

Label 会在key/value键值对的形式附加到各种对象上,如 Pod 、Node 、Service

一个资源对象可以定义任意数量的 Label,同一个 Label也可以被添加到任意数量的资源对象上去

Label可以通过对象式配置时添加到yaml配置文件里面

分类标签
版本标签:version: xxx
环境标签:environment:xxx
架构标签:tier:xxx
  • (1)、label用于给某个资源对象定义标识而label selector用于查看和筛选拥有某些标签的资源对象
  • 基于等式的Label Selector

    name = slave: 选择所有包含Label中key="name"且value="slave"的对象

    env != production: 选择所有包括Label中的key="env"且value不等于"production"的对象

  • 基于集合的Label Selector

    name in (master, slave): 选择所有包含Label中的key="name"且value="master"或"slave"的对象

    name not in (frontend): 选择所有包含Label中的key="name"且value不等于"frontend"的对象

标签的选择条件可以使用多个,此时将多个Label Selector进行组合,使用逗号","进行分隔即可。例如:

name=slave,env!=production

name not in (frontend),env!=production

#查看资源标签
[root@xnode1 ~]# kubectl get pod -n dev 
NAME    READY   STATUS              RESTARTS   AGE
nginx   0/1     ContainerCreating   0          6s
[root@xnode1 ~]# kubectl get pod -n dev --show-labels
NAME    READY   STATUS              RESTARTS   AGE   LABELS
nginx   0/1     ContainerCreating   0          13s   <none>

#给Nginx这个资源打上标签
[root@xnode1 ~]# kubectl label pod nginx -n dev version=1.0
pod/nginx labeled

[root@xnode1 ~]# kubectl get pod -n dev --show-labels
NAME    READY   STATUS    RESTARTS   AGE   LABELS
nginx   1/1     Running   0          91s   version=1.0

#追加更新标签:
[root@xnode1 ~]# kubectl label pod nginx -n dev tier=back
pod/nginx labeled
[root@xnode1 ~]# kubectl get pod -n dev --show-labels
NAME    READY   STATUS    RESTARTS   AGE     LABELS
nginx   1/1     Running   0          3m12s   tier=back,version=1.0

#覆盖更新标签:
[root@xnode1 ~]# kubectl label pod nginx -n dev --overwrite version=2.0
pod/nginx labeled
[root@xnode1 ~]# kubectl get pod -n dev --show-labels
NAME    READY   STATUS    RESTARTS   AGE     LABELS
nginx   1/1     Running   0          4m16s   tier=back,version=2.0

#筛选标签
[root@xnode1 ~]# kubectl create -f nginx.yaml 
pod/nginx01 created
[root@xnode1 ~]# kubectl label pod nginx01 -n dev version=1.0
pod/nginx01 labeled
[root@xnode1 ~]# kubectl get pod -n dev nginx01 --show-labels
NAME      READY   STATUS    RESTARTS   AGE   LABELS
nginx01   1/1     Running   0          86s   version=1.0

#对着两个label的version进行筛选
[root@xnode1 ~]# kubectl get pods -n dev 
NAME      READY   STATUS    RESTARTS   AGE
nginx     1/1     Running   0          8m44s
nginx01   1/1     Running   0          2m11s
[root@xnode1 ~]# kubectl get pods -n dev --show-labels
NAME      READY   STATUS    RESTARTS   AGE     LABELS
nginx     1/1     Running   0          8m54s   tier=back,version=2.0
nginx01   1/1     Running   0          2m21s   version=1.0

#加上参数-l "筛选label名字"
[root@xnode1 ~]# kubectl get pod -l "version=1.0" -n dev --show-labels
NAME      READY   STATUS    RESTARTS   AGE     LABELS
nginx01   1/1     Running   0          3m21s   version=1.0

#删除标签
[root@xnode1 ~]# kubectl label pod nginx -n dev tier-
pod/nginx labeled

[root@xnode1 ~]# kubectl get pod -n dev 
NAME      READY   STATUS    RESTARTS   AGE
nginx     1/1     Running   0          11m
nginx01   1/1     Running   0          4m39s

[root@xnode1 ~]# kubectl get pod -n dev --show-labels
NAME      READY   STATUS    RESTARTS   AGE    LABELS
nginx     1/1     Running   0          11m    version=2.0
nginx01   1/1     Running   0          5m3s   version=1.0

对象配置方式设置label:

[root@xnode1 ~]# cat >>nginx.yaml<<EOF
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: dev
  labels:
    version: "3.0" 
    env: "test"
spec:
  containers:
  - image: nginx:latest
    name: pod
    ports:
    - name: nginx-port
      containerPort: 80
      protocol: TCP
EOF

[root@xnode1 ~]# kubectl create -f nginx.yaml 
pod/nginx02 created
[root@xnode1 ~]# kubectl get pods -n dev --show-labels 
NAME      READY   STATUS              RESTARTS   AGE     LABELS
nginx     1/1     Running             0          16m     version=2.0
nginx01   1/1     Running             0          9m58s   version=1.0
nginx02   0/1     ContainerCreating   0          22s     env=test,version=3.0

七、deployment

Deployment:

在kubernetes中,Pod是最少的控制单元,但是kubernetes很少直接控制Pod,一般pod是由Pod控制器管理,确保Pod处于预期的状态,当一个Pod出现故障时,会尝试重启或者进行自动修复或重建Pod

#使用命令创建一个Pod
[root@xnode1 ~]# kubectl run nginx --image=nginx:1.17.1 --port=80 --replicas=3 --namespace=dev 
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/nginx created

[root@xnode1 ~]# kubectl get pod -n dev 
NAME                     READY   STATUS    RESTARTS   AGE
nginx-64959c9fb5-9556z   1/1     Running   0          11s
nginx-64959c9fb5-pzdtj   1/1     Running   0          11s
nginx-64959c9fb5-s4n5j   1/1     Running   0          11s

#并查看这个Pod控制器下的Pod
[root@xnode1 ~]# kubectl get deployment,pods -n dev 
NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/nginx   3/3     3            3           34s

NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-64959c9fb5-9556z   1/1     Running   0          34s
pod/nginx-64959c9fb5-pzdtj   1/1     Running   0          34s
pod/nginx-64959c9fb5-s4n5j   1/1     Running   0          34s

#查看Pod控制器的详细信息
[root@xnode1 ~]# kubectl describe deployment nginx -n dev 
Name:                   nginx
Namespace:              dev
CreationTimestamp:      Wed, 17 Aug 2022 21:09:41 -0400
Labels:                 run=nginx
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               run=nginx
Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  run=nginx
  Containers:
   nginx:
    Image:        nginx:1.17.1
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   nginx-64959c9fb5 (3/3 replicas created)
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  2m51s  deployment-controller  Scaled up replica set nginx-64959c9fb5 to 3
  
[root@xnode1 ~]# kubectl get pods -n dev --show-labels 
NAME                     READY   STATUS    RESTARTS   AGE    LABELS
nginx-64959c9fb5-9556z   1/1     Running   0          4m1s   pod-template-hash=64959c9fb5,run=nginx
nginx-64959c9fb5-pzdtj   1/1     Running   0          4m1s   pod-template-hash=64959c9fb5,run=nginx
nginx-64959c9fb5-s4n5j   1/1     Running   0          4m1s   pod-template-hash=64959c9fb5,run=nginx

#删除deployment
[root@xnode1 ~]# kubectl delete deployment nginx -n dev 
deployment.extensions "nginx" deleted

使用配置文件删除deployment

[root@xnode1 ~]# cat >>deploy-nginx.yaml<<EOF
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:latest
        name: nginx
        ports:
        - containerPort: 80
          protocol: TCP
EOF

[root@xnode1 ~]# kubectl create -f deploy-nginx.yaml 
deployment.apps/nginx created
[root@xnode1 ~]# kubectl get deployment,pods -n dev 
NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/nginx   2/3     3            2           23s

NAME                         READY   STATUS              RESTARTS   AGE
pod/nginx-69578d4d9b-4jn8w   1/1     Running             0          23s
pod/nginx-69578d4d9b-7xx6g   0/1     ContainerCreating   0          23s
pod/nginx-69578d4d9b-n79rt   1/1     Running             0          23s

#尝试删除deployment
[root@xnode1 ~]# kubectl delete deployment -n dev nginx
deployment.extensions "nginx" deleted
[root@xnode1 ~]# 
[root@xnode1 ~]# kubectl get deployment,pods -n dev 
NAME                         READY   STATUS        RESTARTS   AGE
pod/nginx-69578d4d9b-4jn8w   0/1     Terminating   0          93s
pod/nginx-69578d4d9b-7xx6g   0/1     Terminating   0          93s
pod/nginx-69578d4d9b-n79rt   0/1     Terminating   0          93s

八、Service

Pod在创建的时候会分配一个Ip

  • 但是Pod的IP会随着的重建而产生变化

  • Pod的IP仅仅是集群内部的IP,外部无法访问

①.这个时候kubernetes设计了Services来解决这个问题,Services可以看做是同一组里面同类Pod 对外访问的一个IP,借助Service,应用可以方便的实现服务的发现和负载均衡.

②.只要不删除Service,那么这个ServiceIp是不变得

[root@xnode1 ~]# kubectl expose deployment nginx --name=svc-nginx1 --type=ClusterIP --port=80 --target-port=80 -n dev 
service/svc-nginx1 exposed

[root@xnode1 ~]# kubectl get service -n dev 
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
svc-nginx1   ClusterIP   10.100.168.159   <none>        80/TCP    28s

#访问以下ClusterIP
[root@xnode1 ~]# curl 10.100.168.159:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

上面创建的Service的Type类型为ClusterIP,这个IP地址只用集群内部可访问

如果需要创建外部也可以访问的Service,需要修改Type为NodePort

[root@xnode1 ~]# kubectl expose deployment nginx --name=svc-nginx2 --type=NodePort --port=80 --target-port=80 -n dev 
service/svc-nginx2 exposed

#查看验证
[root@xnode1 ~]# kubectl get svc -n dev 
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
svc-nginx1   ClusterIP   10.100.168.159   <none>        80/TCP         12m
svc-nginx2   NodePort    10.101.90.131    <none>        80:30413/TCP   24s	==>这个端口映射到master集群的端口
  • 我们在这里访问一下 30413 这个端口

在这里插入图片描述

#删除Service
[root@xnode1 ~]# kubectl delete svc svc-nginx1 -n dev 
service "svc-nginx1" deleted

[root@xnode1 ~]# kubectl get svc -n dev 
NAME         TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
svc-nginx2   NodePort   10.101.90.131   <none>        80:30413/TCP   6m18s

使用命令式配置对象的方式创建svc-nginx

[root@xnode1 ~]# cat <<EOF >svc-nginx.yaml
apiVersion: v1
kind: Service
metadata:
  name: svc-nginx
  namespace: dev
spec:
  clusterIP: 10.109.179.231 #固定svc的内网ip
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: nginx
  type: ClusterIP
EOF

[root@xnode1 ~]# kubectl create -f svc-nginx.yaml 
service/svc-nginx created
[root@xnode1 ~]# kubectl get svc -n dev 
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
svc-nginx    ClusterIP   10.109.179.231   <none>        80/TCP         13s
svc-nginx2   NodePort    10.101.90.131    <none>        80:30413/TCP   11m

#创建并删除
[root@xnode1 ~]# kubectl delete -f svc-nginx.yaml 
service "svc-nginx" deleted

[root@xnode1 ~]# kubectl get svc -n dev 
NAME         TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
svc-nginx2   NodePort   10.101.90.131   <none>        80:30413/TCP   12m

九、Pod详解

(1)、Pod概述

每个Pod中都可以包含一个或者多个容器,这些容器可以分为两类

  • 用户所在的容器,容器数量可多可少

  • Pause 容器,这是每个Pod都会有的一个 根容器 ,它的作用有以下两个

    ①.可以以它为依据,评估整个Pod的健康状态

    ②.可以在根容器上设置IP地址,其它的容器都根据此Pod IP来实现Pod的内部通信

    ③.Pod内部的通信,Pod之间的通讯采用虚拟的二层网络技术实现的,我们当前使用的的flannel

#查看Pod的1级属性
[root@xnode1 ~]# kubectl explain pod
KIND:     Pod
VERSION:  v1

DESCRIPTION:
     Pod is a collection of containers that can run on a host. This resource is
     created by clients and scheduled onto hosts.

FIELDS:
   apiVersion   <string>
     APIVersion defines the versioned schema of this representation of an
     object. Servers should convert recognized schemas to the latest internal
     value, and may reject unrecognized values. More info:
     https://git.k8s.io/community/contributors/devel/api-conventions.md#resources

   kind <string>
     Kind is a string value representing the REST resource this object
     represents. Servers may infer this from the endpoint the client submits
     requests to. Cannot be updated. In CamelCase. More info:
     https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds

   metadata     <Object>
     Standard object's metadata. More info:
     https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata

   spec <Object>
     Specification of the desired behavior of the pod. More info:
     https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status

   status       <Object>
     Most recently observed status of the pod. This data may not be up to date.
     Populated by the system. Read-only. More info:
     https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
     
#查看Pod的2级属性
[root@xnode1 ~]# kubectl explain pod.apiVersion
KIND:     Pod
VERSION:  v1

FIELD:    apiVersion <string>

DESCRIPTION:
     APIVersion defines the versioned schema of this representation of an
     object. Servers should convert recognized schemas to the latest internal
     value, and may reject unrecognized values. More info:
     https://git.k8s.io/community/contributors/devel/api-conventions.md#resources
     
#查看apiversion所有的版本
[root@xnode1 ~]# kubectl api-versions 
(2)、Pod配置
[root@xnode1 ~]# 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>      # 资源限制和资源请求的设置

基本配置:

创建Pod-base.yaml文件:

[root@xnode1 ~]# cat <<EOF >pod-base.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-base
  namespace: dev
  labels:
    user: heima
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  - name: busybox
    image: busybox:1.30
EOF

[root@xnode1 ~]# kubectl create -f pod-base.yaml 
pod/pod-base created

#查看验证
[root@xnode1 ~]# kubectl get pods -n dev 
NAME       READY   STATUS              RESTARTS   AGE
pod-base   0/2     ContainerCreating   0          22s
[root@xnode1 ~]# kubectl get pods -n dev 
NAME       READY   STATUS             RESTARTS   AGE
pod-base   1/2     CrashLoopBackOff   1          28s
[root@xnode1 ~]# kubectl get pods -n dev 
NAME       READY   STATUS    RESTARTS   AGE
pod-base   1/2     Running   2          45s

#查看这个容器的详细信息
[root@xnode1 ~]# kubectl describe pods -n dev pod-base 
Name:               pod-base
Namespace:          dev
Priority:           0
PriorityClassName:  <none>
Node:               xnode2/10.0.0.40
Start Time:         Wed, 17 Aug 2022 23:24:59 -0400
Labels:             user=heima
Annotations:        <none>
Status:             Running
IP:                 10.244.1.37
Containers:
  nginx:
    Container ID:   docker://17fbb7874027d0238562a5840a9f12fcf5537b492d52cfad71fe2f29835435ba
    Image:          nginx:1.17.1
    Image ID:       docker-pullable://nginx@sha256:b4b9b3eee194703fc2fa8afa5b7510c77ae70cfba567af1376a573a967c03dbb
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Wed, 17 Aug 2022 23:25:01 -0400
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-wltjd (ro)
  busybox:
    Container ID:   docker://41c5263c5d5c81ebe4c36b554f96774fe4c0f49d8b0cc82468f72ee50bba65c0
    Image:          busybox:1.30
    Image ID:       docker-pullable://busybox@sha256:4b6ad3a68d34da29bf7c8ccb5d355ba8b4babcad1f99798204e7abb43e54ee3d
    Port:           <none>
    Host Port:      <none>
    State:          Waiting
      Reason:       CrashLoopBackOff
    Last State:     Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Wed, 17 Aug 2022 23:26:02 -0400
      Finished:     Wed, 17 Aug 2022 23:26:02 -0400
    Ready:          False
    Restart Count:  3
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-wltjd (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             False 
  ContainersReady   False 
  PodScheduled      True 
Volumes:
  default-token-wltjd:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-wltjd
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type     Reason     Age                            From               Message
  ----     ------     ----                           ----               -------
  Normal   Scheduled  100s                           default-scheduler  Successfully assigned dev/pod-base to xnode2
  Normal   Pulled     <invalid>                      kubelet, xnode2    Container image "nginx:1.17.1" already present on machine
  Normal   Created    <invalid>                      kubelet, xnode2    Created container nginx
  Normal   Started    <invalid>                      kubelet, xnode2    Started container nginx
  Normal   Pulling    <invalid>                      kubelet, xnode2    Pulling image "busybox:1.30"
  Normal   Pulled     <invalid>                      kubelet, xnode2    Successfully pulled image "busybox:1.30"
  Normal   Created    <invalid> (x4 over <invalid>)  kubelet, xnode2    Created container busybox
  Normal   Started    <invalid> (x4 over <invalid>)  kubelet, xnode2    Started container busybox
  Normal   Pulled     <invalid> (x3 over <invalid>)  kubelet, xnode2    Container image "busybox:1.30" already present on machine
  Warning  BackOff    <invalid> (x6 over <invalid>)  kubelet, xnode2    Back-off restarting failed container

#我们可以这个容器被尝试重启4次,查看详情发现容器启动时报错
[root@xnode1 ~]# kubectl get pods -n dev 
NAME       READY   STATUS             RESTARTS   AGE
pod-base   1/2     CrashLoopBackOff   4          2m48s

(3)、镜像拉取策略

镜像拉取策略

imagePullPolicy,用于设置镜像拉取策略,kubernetes支持配置三种拉取策略:

  • Always: 总是从远程仓库拉取镜像(默认一直是远程下载)
  • IfNotPresent: 本地有镜像则使用本地的镜像,本地没有则从远程仓库拉取镜像(本地有惊险就用本地,没有则远程下载)
  • Never: 只使用本地镜像,从不去远程仓库拉取,本地没有就报错(一直使用本地镜像)
[root@xnode1 ~]# cat <<EOF >pod-imagepullpolicy.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-imagepullpolicy
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.2
    imagePullPolicy: Never # 用于设置镜像拉取策略
  - name: busybox
    image: busybox:1.30
EOF

[root@xnode1 ~]# kubectl create -f pod-imagepullpolicy.yaml 
pod/pod-imagepullpolicy created

[root@xnode1 ~]# kubectl get pods -n dev 
NAME                  READY   STATUS             RESTARTS   AGE
pod-imagepullpolicy   1/2     CrashLoopBackOff   1          6s

#查看详细信息
[root@xnode1 ~]# kubectl describe pod -n dev pod-imagepullpolicy 
... ...
Events:
  Type     Reason             Age                            From               Message
  ----     ------             ----                           ----               -------
  Normal   Scheduled          21s                            default-scheduler  Successfully assigned dev/pod-imagepullpolicy to xnode2
  Normal   Pulled             <invalid> (x3 over <invalid>)  kubelet, xnode2    Container image "busybox:1.30" already present on machine
  Normal   Created            <invalid> (x3 over <invalid>)  kubelet, xnode2    Created container busybox
  Normal   Started            <invalid> (x3 over <invalid>)  kubelet, xnode2    Started container busybox
  Warning  ErrImageNeverPull  <invalid> (x6 over <invalid>)  kubelet, xnode2    Container image "nginx:1.17.2" is not present with pull policy of Never
  Warning  Failed             <invalid> (x6 over <invalid>)  kubelet, xnode2    Error: ErrImageNeverPull
  Warning  BackOff            <invalid> (x3 over <invalid>)  kubelet, xnode2    Back-off restarting failed container

查看本地Pod拉取镜像策略

 [root@xnode1 ~]# kubectl explain pod.spec.containers
 
 ... ...
 imagePullPolicy      <string>
     Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always
     if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated.
     More info:
     https://kubernetes.io/docs/concepts/containers/images#updating-images

我们修改一下拉取镜像启动Pod的配置文件:

将原本空的镜像策略Never修改成IdNotPresent

[root@xnode1 ~]# cat <<EOF >pod-imagepullpolicy.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-imagepullpolicy
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.2
    imagePullPolicy: IfNotPresent # 用于设置镜像拉取策略
  - name: busybox
    image: busybox:1.30
EOF

#重新创建
[root@xnode1 ~]# kubectl create -f pod-imagepullpolicy.yaml 
pod/pod-imagepullpolicy created

#查看详细信息
[root@xnode1 ~]# kubectl describe pod -n dev pod-imagepullpolicy
Events:
  Type     Reason     Age                            From               Message
  ----     ------     ----                           ----               -------
  Normal   Scheduled  55s                            default-scheduler  Successfully assigned dev/pod-imagepullpolicy to xnode2
  Normal   Pulling    <invalid>                      kubelet, xnode2    Pulling image "nginx:1.17.2"
  Normal   Pulled     <invalid>                      kubelet, xnode2    Successfully pulled image "nginx:1.17.2"
  Normal   Created    <invalid>                      kubelet, xnode2    Created container nginx
  Normal   Started    <invalid>                      kubelet, xnode2    Started container nginx
  Normal   Pulled     <invalid> (x2 over <invalid>)  kubelet, xnode2    Container image "busybox:1.30" already present on machine
  Normal   Created    <invalid> (x2 over <invalid>)  kubelet, xnode2    Created container busybox
  Normal   Started    <invalid> (x2 over <invalid>)  kubelet, xnode2    Started container busybox
  Warning  BackOff    <invalid> (x2 over <invalid>)  kubelet, xnode2    Back-off restarting failed container


#查看docker images镜像
[root@xnode2 ~]# docker images | grep nginx
nginx                                                latest              605c77e624dd        7 months ago        141MB
nginx                                                1.20.0              7ab27dbbfbdf        15 months ago       133MB
nginx                                                1.17.2              4733136e5c3c        3 years ago         126MB
nginx                                                1.17.1              98ebf73aba75        3 years ago         109MB
(4)、启动命令:command

在前面启动Pod中,一直有一个问题没有解决,就是busybox容器没有成功运行,是什么原因导致这个容器故障呢?

busybox并不是一个程序,而是一个类似于工具类的集合,kubernetes集群启动管理后,它就会自动关闭,解决方案就是让其一直在允许,这里就用到了command配置

command 就是k8s Pod运行起来了初始化执行的一个命令

对下面yaml文件里的 command 进行解释:

  • “/bin/bash”,"-c"是一个shell命令解释器,表示执行sh命令
  • touch /tmp/hello.txt/:在/tmp/目录下创建一个hello的txt文件
  • while true;do /bin/echo $(date +%T) >> /tmp/hello.txt;sleep 3;done:每隔3秒向文件中写入当前时间.
[root@xnode1 ~]# cat <<EOF >pod-command.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-command
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  - 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;"]
EOF

#创建并查看验证
[root@xnode1 ~]# kubectl create -f pod-command.yaml 
pod/pod-command created
[root@xnode1 ~]# kubectl get pods -n dev 
NAME                  READY   STATUS             RESTARTS   AGE
pod-command           2/2     Running            0          7s
pod-imagepullpolicy   1/2     CrashLoopBackOff   17         21h

#进入pod中的busybox容器查看文件内容
[root@xnode1 ~]# kubectl exec pod-command -n dev -it -c busybox /bin/sh
/ # tail -f /tmp/hello.txt 
03:19:50
03:19:50
03:19:50
03:19:50
(5)、环境变量
  • 创建一个pod-env.yaml文件
[root@xnode1 ~]# cat <<EOF >pod-env.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-env
  namespace: dev
spec:
  containers:
  - name: busybox
    image: busybox:1.30
    command: ["/bin/sh","-c","while true;do /bin/echo $(date +%T);sleep 60; done;"]
    env: # 设置环境变量列表
    - name: "username"
      value: "admin"
    - name: "password"
      value: "123456"
EOF
  • 执行环境变量配置文件
[root@xnode1 ~]# kubectl create -f pod-env.yaml 
pod/pod-env created

[root@xnode1 ~]# kubectl get pod -n dev 
NAME                  READY   STATUS             RESTARTS   AGE
pod-command           2/2     Running            0          13m
pod-env               1/1     Running            0          5s
pod-imagepullpolicy   1/2     CrashLoopBackOff   19         21h

#进入容器,输出环境变量
[root@xnode1 ~]# kubectl exec -it pod-env -n dev -c busybox /bin/sh
/ # echo $username
admin
/ # echo $password
123456
(6)、Pod端口配置
[root@xnode1 ~]# kubectl explain pod.spec.containers.ports | grep -Ev '^$'
KIND:     Pod
VERSION:  v1
RESOURCE: ports <[]Object>
DESCRIPTION:
     List of ports to expose from the container. Exposing a port here gives the
     system additional information about the network connections a container
     uses, but is primarily informational. Not specifying a port here DOES NOT
     prevent that port from being exposed. Any port which is listening on the
     default "0.0.0.0" address inside a container will be accessible from the
     network. Cannot be updated.
     ContainerPort represents a network port in a single container.
FIELDS:
   containerPort        <integer> -required-	#容器要监听的端口(0<x<65536)
     Number of port to expose on the pod's IP address. This must be a valid port
     number, 0 < x < 65536.
   hostIP       <string>	#要将外部端口绑定到主机IP
     What host IP to bind the external port to.
   hostPort     <integer>	#容器要在主机上公开的端口,如果设置,主机上只能运行容器的一个副本
     Number of port to expose on the host. If specified, this must be a valid
     port number, 0 < x < 65536. If HostNetwork is specified, this must match
     ContainerPort. Most containers do not need this.
   name <string>	#端口名称,如果指定,必须保证name在pod中是唯一的
     If specified, this must be an IANA_SVC_NAME and unique within the pod. Each
     named port in a pod must have a unique name. Name for the port that can be
     referred to by services.
   protocol     <string>	#端口协议:必须是TCP UDP协议或SCTP.默认是TCP
     Protocol for port. Must be UDP, TCP, or SCTP. Defaults to "TCP".
  • 编写一个pod-ports.yaml配置文件
[root@xnode1 ~]# cat <<EOF >pod-ports.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-ports
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports: # 设置容器暴露的端口列表
    - name: nginx-port
      containerPort: 80
      protocol: TCP
EOF
  • 查看是否允许
[root@xnode1 ~]# kubectl create -f pod-ports.yaml 
pod/pod-ports created

[root@xnode1 ~]# kubectl get pods -n dev 
NAME                  READY   STATUS             RESTARTS   AGE
pod-command           2/2     Running            0          38m
pod-env               1/1     Running            0          25m
pod-imagepullpolicy   1/2     CrashLoopBackOff   24         22h
pod-ports             1/1     Running            0          29s

#查看pod-ports这个pod的yaml信息
[root@xnode1 ~]# kubectl get pods -n dev pod-ports -o yaml
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2022-08-18T07:58:14Z"
  name: pod-ports
  namespace: dev
  resourceVersion: "25418"
  selfLink: /api/v1/namespaces/dev/pods/pod-ports
  uid: 82f7f109-1ecb-11ed-a440-000c292ce9a5
spec:
  containers:
  - image: nginx:1.17.1
    imagePullPolicy: IfNotPresent
    name: nginx
    ports:
    - containerPort: 80		#映射的端口为80
      name: nginx-port
      protocol: TCP
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
    
#查看这个Pod的详细信息
[root@xnode1 ~]# kubectl describe pods -n dev pod-ports 
Name:               pod-ports
Namespace:          dev
Priority:           0
PriorityClassName:  <none>
Node:               xnode2/10.0.0.40
Start Time:         Thu, 18 Aug 2022 03:58:14 -0400
Labels:             <none>
Annotations:        <none>
Status:             Running
IP:                 10.244.1.47
Containers:
  nginx:
    Container ID:   docker://b06bde3d33fb758a932e5980e660f5fb2355bb4a7a4649becfa15bab4b92054a
    Image:          nginx:1.17.1
    Image ID:       docker-pullable://nginx@sha256:b4b9b3eee194703fc2fa8afa5b7510c77ae70cfba567af1376a573a967c03dbb
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Thu, 18 Aug 2022 03:58:15 -0400
    Ready:          True
    Restart Count:  0
    Environment:    <none>
(7)、Pod的资源配额

什么是 资源配额?

容器中的程序运行对外提供服务,肯定是要占用一定的资源,比如CPU和内存,如果不对某个容器的资源做出限制,那么它就可能吃掉大量的资源,导致其它容器无法运行.针对这种情况,kubernetes提供了对内存和CPU的资源进行配额的机制,这种机制主要是通过resources选项实现的,他有两个子选项.

  • limits: 用于限制运行时容器的最大占用资源,当容器占用资源超过 limits 时会被终止,并进行重启
  • requests: 用于设置容器需要的最小资源,如果环境资源不够,容器将无法启动
  • 编写一个测试案例yaml文件
[root@xnode1 ~]# cat <<EOF >pod-resources.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-resources
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    resources: # 资源配额
      limits:  # 限制资源(上限)
        cpu: "2" # CPU限制,单位是core数
        memory: "10Gi" # 内存限制
      requests: # 请求资源(下限)
        cpu: "1"  # CPU限制,单位是core数
        memory: "10Mi"  # 内存限制
EOF

[root@xnode1 ~]# kubectl create -f pod-resources.yaml 
pod/pod-resources created
  • 查看是否在运行
[root@xnode1 ~]# kubectl get pod -n dev 
NAME            READY   STATUS    RESTARTS   AGE
pod-command     2/2     Running   2          82m
pod-env         1/1     Running   1          70m
pod-ports       1/1     Running   1          45m
pod-resources   1/1     Running   0          7s
CPU、MEM说明
CPU: core数,可以做一个说明
Memory: 内存大小,可以使用Gi、Mi、G、M等形式
(8)、Pod的生命周期

Pod的生命周期包括以下的过程:

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

在这里插入图片描述

状态动作
挂起(Pending):apiserver已经创建了pod资源对象,但它尚未被调度完成或者仍处于下载镜像的过程中
运行中(Running):pod已经被调度至某节点,并且所有容器都已经被kubelet创建完成
成功(Succeeded):pod中的所有容器都已经成功终止并且不会被重启
失败(Failed):所有容器都已经终止,但至少有一个容器终止失败,即容器返回了非0值的退出状态
未知(Unknown):apiserver无法正常获取到pod对象的状态信息,通常由网络通信失败所导致
(9)、Pod的创建和终止
Pod的创建和终止
1、用户通过kubectl或其它api客户端提交需要创建的pod信息给apiServer
2、apiServer开始生成pod对象的信息,并将信息存入etcd,然后返回确认信息至客户端
3、apiServer开始反映etcd中的pod对象的变化,其它组件使用watch机制来跟踪检查apiServer上的变动
4、scheduler发现有新的pod对象要创建,开始为pod分配主机并将结果信息更新至apiServer
5、node节点上的kubectl发现有pod调度过来,尝试调用docker启动容器,并将结果回送至apiServer
6、apiServer将收到的pod状态信息存入etcd

在这里插入图片描述


Pod的终止过程
1、用户将APIServer发送删除pod对象的命令
2、apiServer中的pod对象信息会随着时间的推断而更新,在宽限期内(默认30s),Pod被视为dead
3、将Pod标记为terminationing状态
4、kubelet在监控到pod对象转为terminating状态的同时启动pod关闭过程
5、端点控制器监控到Pod对象的关闭行为时将其从所有匹配到此端点的service资源的端口列表中移除
6、如果当前pod对象定义了preStop钩子处理器,则在其标记为terminating后即会同步到方式启动执行
7、Pod对象中的容器进程收到停止信号
8、宽限期结束后,若Pod中还存在仍在运行的进程,那么Pod对象会收到立即终止的信号
9、kubelet请求apiServer将此Pod资源的宽限期设置为0从而完成删除操作,此时Pod对于用户已不可见
(10)、初始化容器

初始化容器在Pod主容器之前要运行的容器,主要就是做一些主容器的前置工作,它具有两大特征:

  • 初始化容器必须运行完成直至结束,若某初始化容器运行失败,那么kubernetes需要重启它直到成功完成
  • 初始化容器必须按照定义的顺序执行,当且仅当前一个成功之后,后面的一个才能运行

初始化容器最长看到的应用场景:

  • 提供主容器镜像中不具备的工具程序或自定义代码
  • 初始化容器要先于2应用容器串行启动并运行完成,因此可用于延后应用容器的启动直至依赖的条件得到满足
  • 例如:这里一个项目要求启动一个Nginx容器,但是启动Nginx的前置条件要先启动一个mysql容器,如果这个mysql容器没有启动那么这个Nginx容器就会一直处于初始化状态.
  • 创建pod-initcontainer.yaml
[root@xnode1 ~]# cat <<EOF > pod-initcontainer.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-initcontainer
  namespace: dev
spec:
  containers:
  - name: main-container
    image: nginx:1.17.1
    ports: 
    - name: nginx-port
      containerPort: 80
  initContainers:
  - name: test-mysql
    image: busybox:1.30
    command: ['sh', '-c', 'until ping 192.168.5.14 -c 1 ; do echo waiting for mysql...; sleep 2; done;']
  - name: test-redis
    image: busybox:1.30
    command: ['sh', '-c', 'until ping 192.168.5.15 -c 1 ; do echo waiting for reids...; sleep 2; done;']
EOF
  • 启动并查看
[root@xnode1 ~]# kubectl create -f pod-initcontainer.yaml 
pod/pod-initcontainer creat

[root@xnode1 ~]# kubectl get pods -n dev 
NAME                READY   STATUS     RESTARTS   AGE
pod-initcontainer   0/1     Init:0/2   0          28sed

#可以看到容器一直卡在初始化没有运行
[root@xnode1 ~]# kubectl describe pod -n dev pod-initcontainer
... ...
Events:
  Type    Reason     Age    From               Message
  ----    ------     ----   ----               -------
  Normal  Scheduled  3m55s  default-scheduler  Successfully assigned dev/pod-initcontainer to xnode2
  Normal  Pulled     3m53s  kubelet, xnode2    Container image "busybox:1.30" already present on machine
  Normal  Created    3m52s  kubelet, xnode2    Created container test-mysql
  Normal  Started    3m52s  kubelet, xnode2    Started container test-mysql
  
#动态监听pod
[root@xnode1 ~]# kubectl get pods -n dev -w
NAME                READY   STATUS     RESTARTS   AGE
pod-initcontainer   0/1     Init:0/2   0          112s

#新开一个终端为服务器新添加几个IP,观察pod的变化
[root@xnode1 ~]# ifconfig eno16777736:1 10.0.0.100 netmask 255.255.255.0 up
[root@xnode1 ~]# ifconfig eno16777736:1 10.0.0.200 netmask 255.255.255.0 up

#查看动态监听的pod:pod成功运行
[root@xnode1 ~]# kubectl get pod -n dev -w
NAME                READY   STATUS     RESTARTS   AGE
pod-initcontainer   0/1     Init:0/2   0          22s
pod-initcontainer   0/1     Init:1/2   0          2m27s
pod-initcontainer   0/1     Init:1/2   0          2m28s
pod-initcontainer   0/1     PodInitializing   0          2m40s
pod-initcontainer   1/1     Running           0          2m41s
(11)、钩子函数

钩子函数能够感知自身生命周期中的事件,并在相应的时刻到来之时运行用户程序指定的代码

kubernetes在主容器启动之后和之前提供了两个钩子函数:

  • post start:容器创建之后执行,如果失败了会重启容器
  • pre stop:容器终止之前执行,执行完成之后容器将成功终止,在其完成之前会阻塞删除容器的操作
  • Exec命令:在容器内执行一次命令
……
  lifecycle:
    postStart: 
      exec:
        command:
        - cat
        - /tmp/healthy
……
  • TCPSocket:在当前容器尝试访问指定的socket
……      
  lifecycle:
    postStart:
      tcpSocket:
        port: 8080
……
  • HTTPGet:在当前容器中向某url发起http请求
……
  lifecycle:
    postStart:
      httpGet:
        path: / #URI地址
        port: 80 #端口号
        host: 192.168.5.3 #主机地址
        scheme: HTTP #支持的协议,http或者https
……

以exec方式为例,演示钩子函数的使用,创建pod-hook-exec.yaml文件:

[root@xnode1 ~]# cat <<EOF > pod-hook-exec.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-hook-exec
  namespace: dev
spec:
  containers:
  - name: main-container
    image: nginx:1.17.1
    ports:
    - name: nginx-port
      containerPort: 80
    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"]
EOF
  • 创建Pod查看:
[root@xnode1 ~]# kubectl create -f pod-hook-exec.yaml 
pod/pod-hook-exec created

[root@xnode1 ~]# kubectl get pods -n dev pod-hook-exec -o wide
NAME            READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
pod-hook-exec   1/1     Running   0          49s   10.244.1.61   xnode2   <none>           <none>

#访问这个IP:80端口
[root@xnode1 ~]# curl 10.244.1.61:80
postStart...
(12)、容器探测

容器探测 用于检测容器中的应用实例是否正常工作,是保障业务可用性的一种传统机制.经过探测,实例的状态不符合预期,那么kubernetes就会把该问题实例"摘除",不承担业务流量.kubernetes提供了两种探针来实现容器探测.

  • liveness Probes: 存活性探针,用于检测应用实例当前是否处于正常运行状态,如果不是,k8s会重启容器

  • readiness probes: 就绪性探针,用于检测应用实例当前是否可以接收请求,如果不能,k8s不会转发流量

这两者之间不同的区别是,决定是否重启容器,readinessProbe决定是否将请求转发给容器.

上面的这两者探针均支持3种探测方式.

  • exec命令: 在容器内执行一次命令,如果命令执行的退出码为0,则认为程序正常,否则不正常.
……
  livenessProbe:
    exec:
      command:
      - cat
      - /tmp/healthy
……
  • TCPSocket: 将会尝试访问一个用户容器的端口,如果能够建立这条连接,则认为程序正常,否则不正常.
……      
  livenessProbe:
    tcpSocket:
      port: 8080
……
  • HTTPGet: 调用容器内Web应用的URL,如果返回的状态码在200和399之间,则认为程序正常,否则不正常
……
  livenessProbe:
    httpGet:
      path: / #URI地址
      port: 80 #端口号
      host: 127.0.0.1 #主机地址
      scheme: HTTP #支持的协议,http或者https
……

liveness probes 为例,做几个演示:

方式一: Exec

  • 创建一个pod-liveness-exec.yaml
[root@xnode1 ~]# cat <<EOF > pod-liveness-exec.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness-exec
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports: 
    - name: nginx-port
      containerPort: 80
    livenessProbe:
      exec:
        command: ["/bin/cat","/tmp/hello.txt"] # 执行一个查看文件的命令
EOF

#创建pod并查看状态:
[root@xnode1 ~]# kubectl create -f pod-liveness-exec.yaml 
pod/pod-liveness-exec created

[root@xnode1 ~]# kubectl get pods -n dev pod-liveness-exec 
NAME                READY   STATUS    RESTARTS   AGE
pod-liveness-exec   1/1     Running   0          23s

#查看状态:发现已经重启4次
[root@xnode1 ~]# kubectl get pods -n dev pod-liveness-exec 
NAME                READY   STATUS    RESTARTS   AGE
pod-liveness-exec   1/1     Running   4          2m5s

#查看这个pod的详细信息:发现这个Pod在执行livenessProbe探测,内容是使用command查看/tmp目录下的Hello文件,没有查找到这个文件,没有达到这个预期于是一直重启容器
[root@xnode1 ~]# kubectl describe pods -n dev pod-liveness-exec
... ...
Events:
  Type     Reason     Age               From               Message
  ----     ------     ----              ----               -------
  Normal   Scheduled  70s               default-scheduler  Successfully assigned dev/pod-liveness-exec to xnode2
  Normal   Pulled     9s (x3 over 69s)  kubelet, xnode2    Container image "nginx:1.17.1" already present on machine
  Normal   Created    9s (x3 over 68s)  kubelet, xnode2    Created container nginx
  Warning  Unhealthy  9s (x6 over 59s)  kubelet, xnode2    Liveness probe failed: /bin/cat: /tmp/hello.txt: No such file or directory
  Normal   Killing    9s (x2 over 39s)  kubelet, xnode2    Container nginx failed liveness probe, will be restarted
  Normal   Started    8s (x3 over 67s)  kubelet, xnode2    Started container nginx
  • 我们这里修改pod-liveness的yaml文件: command修改为查看/tmp目录下的配置文件
[root@xnode1 ~]# cat <<EOF > pod-liveness-exec.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness-exec
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports: 
    - name: nginx-port
      containerPort: 80
    livenessProbe:
      exec:
        command: ["/bin/ls","/tmp/"] # 执行一个查看文件的命令
EOF

#执行创建这个Pod并查看状态:发现容器没有重启,查看容器的详细信息都是一次性通过
[root@xnode1 ~]# kubectl create -f pod-liveness-exec.yaml 
pod/pod-liveness-exec created

[root@xnode1 ~]# kubectl get  pods -n dev pod-liveness-exec 
NAME                READY   STATUS    RESTARTS   AGE
pod-liveness-exec   1/1     Running   0          14s

[root@xnode1 ~]# kubectl describe pod -n dev pod-liveness-exec
... ...

Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  66s   default-scheduler  Successfully assigned dev/pod-liveness-exec to xnode2
  Normal  Pulled     65s   kubelet, xnode2    Container image "nginx:1.17.1" already present on machine
  Normal  Created    64s   kubelet, xnode2    Created container nginx
  Normal  Started    64s   kubelet, xnode2    Started container nginx

方式二: TCP Socket

#创建一个pod-liveness-tcpsocket.yaml
[root@xnode1 ~]# cat <<EOF > pod-liveness-tcpsocket.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness-tcpsocket
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports: 
    - name: nginx-port
      containerPort: 80
    livenessProbe:
      tcpSocket:
        port: 8080 # 尝试访问8080端口
EOF

#创建pod 查看pod状态:由于pod容器创建初执行的liveness容器探测要求访问8080端口,pod无法访问这个端口于是该容器执行重启
[root@xnode1 ~]# kubectl create -f pod-liveness-tcpsocket.yaml 
pod/pod-liveness-tcpsocket created

[root@xnode1 ~]# kubectl get pods -n dev pod-liveness-tcpsocket 
NAME                     READY   STATUS    RESTARTS   AGE
pod-liveness-tcpsocket   1/1     Running   1          35s

[root@xnode1 ~]# kubectl describe pod -n dev pod-liveness-tcpsocket 
... ...

Events:
  Type     Reason     Age                From               Message
  ----     ------     ----               ----               -------
  Normal   Scheduled  56s                default-scheduler  Successfully assigned dev/pod-liveness-tcpsocket to xnode2
  Normal   Pulled     28s (x2 over 55s)  kubelet, xnode2    Container image "nginx:1.17.1" already present on machine
  Normal   Killing    28s                kubelet, xnode2    Container nginx failed liveness probe, will be restarted
  Normal   Created    27s (x2 over 55s)  kubelet, xnode2    Created container nginx
  Normal   Started    27s (x2 over 55s)  kubelet, xnode2    Started container nginx
  Warning  Unhealthy  8s (x5 over 48s)   kubelet, xnode2    Liveness probe failed: dial tcp 10.244.1.64:8080: connect: connection refused

  • 我们这里修改一下pod-liveness-tcpsocket这个容器的配置文件 :
[root@xnode1 ~]# cat <<EOF > pod-liveness-tcpsocket.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness-tcpsocket
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports: 
    - name: nginx-port
      containerPort: 80
    livenessProbe:
      tcpSocket:
        port: 80 # 尝试访问80端口
EOF

#查看:发现既没有重启也没有报错
[root@xnode1 ~]# kubectl create -f pod-liveness-tcpsocket.yaml 
pod/pod-liveness-tcpsocket created
[root@xnode1 ~]# 
[root@xnode1 ~]# kubectl get pod -n dev pod-liveness-tcpsocket 
NAME                     READY   STATUS    RESTARTS   AGE
pod-liveness-tcpsocket   1/1     Running   0          9s

[root@xnode1 ~]# kubectl describe pods -n dev pod-liveness-tcpsocket
... ...

Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  38s   default-scheduler  Successfully assigned dev/pod-liveness-tcpsocket to xnode2
  Normal  Pulled     37s   kubelet, xnode2    Container image "nginx:1.17.1" already present on machine
  Normal  Created    37s   kubelet, xnode2    Created container nginx
  Normal  Started    37s   kubelet, xnode2    Started container nginx

方式三:httpGET

[root@xnode1 ~]# cat <<EOF > pod-liveness-httpget.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness-httpget
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports:
    - name: nginx-port
      containerPort: 80
    livenessProbe:
      httpGet:  # 其实就是访问http://127.0.0.1:80/hello  
        scheme: HTTP #支持的协议,http或者https
        port: 80 #端口号
        path: /hello #URI地址
EOF

#查看
[root@xnode1 ~]# kubectl create -f pod-liveness-httpget.yaml 
pod/pod-liveness-httpget created
[root@xnode1 ~]# kubectl get pods -n dev pod-liveness-httpget 
NAME                   READY   STATUS    RESTARTS   AGE
pod-liveness-httpget   1/1     Running   3          113s

#查看pod的详细信息:访问地址404 not found
[root@xnode1 ~]# kubectl describe pod -n dev pod-liveness-httpget
... ...

Events:
  Type     Reason     Age                  From               Message
  ----     ------     ----                 ----               -------
  Normal   Scheduled  103s                 default-scheduler  Successfully assigned dev/pod-liveness-httpget to xnode2
  Normal   Pulled     20s (x4 over 102s)   kubelet, xnode2    Container image "nginx:1.17.1" already present on machine
  Normal   Killing    20s (x3 over 80s)    kubelet, xnode2    Container nginx failed liveness probe, will be restarted
  Normal   Created    19s (x4 over 102s)   kubelet, xnode2    Created container nginx
  Normal   Started    19s (x4 over 101s)   kubelet, xnode2    Started container nginx
  Warning  Unhealthy  10s (x10 over 100s)  kubelet, xnode2    Liveness probe failed: HTTP probe failed with statuscode: 404
  • 我们这里修改一下pod-liveness-httpget这个容器的配置文件 :
[root@xnode1 ~]# cat <<EOF > pod-liveness-httpget.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness-httpget
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports:
    - name: nginx-port
      containerPort: 80
    livenessProbe:
      httpGet:  # 其实就是访问http://127.0.0.1:80/hello  
        scheme: HTTP #支持的协议,http或者https
        port: 80 #端口号
        path: / #URI地址
EOF

#再次验证查看:发现没有进行重启,describe查看详细信息也没有报错
[root@xnode1 ~]# kubectl get pods -n dev pod-liveness-httpget 
NAME                   READY   STATUS    RESTARTS   AGE
pod-liveness-httpget   1/1     Running   0          57s

[root@xnode1 ~]# kubectl get pods -n dev pod-liveness-httpget 
... ...

Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  27s   default-scheduler  Successfully assigned dev/pod-liveness-httpget to xnode2
  Normal  Pulled     26s   kubelet, xnode2    Container image "nginx:1.17.1" already present on machine
  Normal  Created    26s   kubelet, xnode2    Created container nginx
  Normal  Started    26s   kubelet, xnode2    Started container nginx

至此已经使用了liveness Probe演示了3种探测方式,但是查看liveness Probe的子属性,会发现除了这三种方式,还有一些其它的配置,这里进行一一解释.

[root@xnode1 ~]# kubectl explain pod.spec.containers.livenessProbe

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

一旦容器出现了问题,kubernetes就会对容器所在的Pod进行重启,其实这是有Po的重启策略决定的,pod的重启策略有3种,分别如下:

Always: 容器失效时,自动重启该容器,这也就是默认值

OnFailure: 容器终止运行且退出码不为0时重启

Never: 无论状态如何,都不重启该容器

重启策略适用于pod对象中的所有容器,首次需要重启的容器,将在其需要时立即进行重启,随后再次需要重启的操作将由kubelet延迟一段时间后进行,且反复的重启操作的延迟时长以此为10s、20s、40s、80s、160s和300s,300s是最大延迟时长。

  • 创建 Pod-restartpolicy.yaml
[root@xnode1 ~]# cat <<EOF > pod-restartpolicy.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-restartpolicy
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports:
    - name: nginx-port
      containerPort: 80
    livenessProbe:
      httpGet:
        scheme: HTTP
        port: 80
        path: /hello
  restartPolicy: Always # 设置重启策略为Always
  EOF
  
#查看状态:
[root@xnode1 ~]# kubectl create -f pod-restartpolicy.yaml 
pod/pod-restartpolicy created
[root@xnode1 ~]# kubectl get pods -n dev pod-restartpolicy -w
NAME                READY   STATUS    RESTARTS   AGE
pod-restartpolicy   1/1     Running   0          25s
pod-restartpolicy   1/1     Running   1          31s

#我们修改配置文件将重启策略修改成"Never",不管遇到什么状态永不重启
[root@xnode1 ~]# cat <<EOF > pod-restartpolicy.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-restartpolicy
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports:
    - name: nginx-port
      containerPort: 80
    livenessProbe:
      httpGet:
        scheme: HTTP
        port: 80
        path: /hello
  restartPolicy: Never # 设置重启策略为Never
  EOF
  
#再次启动并查看状态
[root@xnode1 ~]# kubectl create -f pod-restartpolicy.yaml 
pod/pod-restartpolicy created

[root@xnode1 ~]# kubectl get pods -n dev pod-restartpolicy -w
NAME                READY   STATUS    RESTARTS   AGE
pod-restartpolicy   1/1     Running   0          10s
pod-restartpolicy   0/1     Completed   0          28s

[root@xnode1 ~]# kubectl describe pods -n dev pod-restartpolicy
Events:
  Type     Reason     Age                 From               Message
  ----     ------     ----                ----               -------
  Normal   Scheduled  2m                  default-scheduler  Successfully assigned dev/pod-restartpolicy to xnode2
  Normal   Pulled     119s                kubelet, xnode2    Container image "nginx:1.17.1" already present on machine
  Normal   Created    119s                kubelet, xnode2    Created container nginx
  Normal   Started    119s                kubelet, xnode2    Started container nginx
  Warning  Unhealthy  93s (x3 over 113s)  kubelet, xnode2    Liveness probe failed: HTTP probe failed with statuscode: 404
  Normal   Killing    93s                 kubelet, xnode2    Stopping container nginx

十、Pod的调度

默认情况下,一个Pod在哪个节点上运行,是由Scheduler组件采用相应的算法算出来的,这个时候是不受人为干预,但是在实际使用中这并不能满足我们的需求,在很多情况下我们向控制某个Pod达到某些节点上,那么应该怎么做呢?这就要求了解kubernetes对Pod的调度规则,kubernetes提供了四大类调度方式:

  • 自动调度:运行在哪个节点上完全由Scheduler经过一系列的算法计算得出
  • 定向调度:NodeName、NodeSelector
  • 亲和性调度:NodeAffinity、PodAffinity、PodAntiAffinity
  • 污点(容忍)调度:Taints、Toleration

(1)、定向调度:

定向调度:

定向调度, 指的是利用在Pod上声明nodename或者nodeSelector,从此将Pod调度到期望值的node节点上,注意,这里的调度是强制的,这就意味着即使调度的目标node不在,也会向上面进行调度,只不过pod运行失败而已.

NodeName:

用于强制约束将Pod调度到指定的name的node节点上.这种方式,其实是直接跳过Scheduler的调度逻辑 ,直接将pod调度到指定名称的节点.

  • 实验一下创建一个pod-nodename.yaml文件
[root@xnode1 ~]# cat <<EOF > pod-nodename.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-nodename
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  nodeName: xnode2 # 指定调度到node2节点上
EOF

#创建Pod并查看Pod详细信息
[root@xnode1 ~]# kubectl create -f pod-nodename.yaml 
pod/pod-nodename created

[root@xnode1 ~]# kubectl get pods -n dev pod-nodename -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
pod-nodename   1/1     Running   0          20s   10.244.1.79   xnode2   <none>           <none>

(2)、NodeSelector

NodeSelector 用于将pod调度到添加了指定标签的node节点上,它是通过kubernetes的label-selector实现的,也就是说,在Pod创建之前,会由scheduler使用MatchSelector调度策略来进行label匹配,找出目标Node,然后将pod调度到目标节点,该匹配着是强制约束.

  • 我们这里用实验来验证一下:
#首先分别给xnode节点添加标签:
[root@xnode1 ~]# kubectl label nodes xnode1 nodeenv=pro
node/xnode1 labeled
[root@xnode1 ~]# kubectl label nodes xnode2 nodeenv=test
node/xnode2 labeled

#创建一个pod-nodeselector.yaml文件,文件中声明一个键值对进行目标打了标签的node进行筛选,node使用它创建一个Pod
[root@xnode1 ~]# cat <<EOF > pod-nodeselector.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeselector
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  nodeSelector: 
    nodeenv: pro # 指定调度到具有nodeenv=pro标签的节点上
EOF

#我们这里查看一下pod的状态:因为xnode1是master节点不会运行用户级别的普通pod,所以调度到xnode1上,xnode1拒绝了
[root@xnode1 ~]# kubectl get pod -n dev pod-nodeselector -o wide
NAME               READY   STATUS    RESTARTS   AGE    IP       NODE     NOMINATED NODE   READINESS GATES
pod-nodeselector   0/1     Pending   0          101s   <none>   <none>   <none>           <none>

[root@xnode1 ~]# kubectl describe pod -n dev pod-nodeselector
... ...

Events:
  Type     Reason            Age                From               Message
  ----     ------            ----               ----               -------
  Warning  FailedScheduling  50s (x2 over 50s)  default-scheduler  0/2 nodes are available: 1 node(s) didn't match node selector, 1 node(s) had taints that the pod didn't tolerate.

(3)、亲和性调度

上面讲了定向调度,使用起来很方便,但是也有问题,那就是如果没有满足条件的Node,那么Pod将不会运行,即使在集群中还有可用Node列表也不行,这样就限制了它的使用场景.

基于上面的这些问题kubernetes提出来一种亲和性调度(Affinity)作为解决方案,它在NodeSelector的基础上进行了扩展,可以通过配置的形式,实现优先选择满足node进行调度,如果没有,也可以调度到不满足条件的节点上,使扩展更加灵活.

Affinity分为三大类:

  • node Affinity(node亲和性) : 以node为目标,解决Pod可以调度到哪些node的问题
  • pod Affinity(pod亲和性) : 以pod为目标,解决pod可以和哪些已存在的pod部署在同一个拓扑域中的问题.
  • pod AntiAffinity(pod反亲和性): 以Pod为目标,决绝pod不能和哪些已存在pod部署在同一拓扑域中的问题.

使用场景说明:

  • 亲和性: 如果两个应用需要频繁的进行网络通信交互,这样就很有必要利用亲和性让两个应用尽可能的靠近,这样可以减少因网络通信而带来的性能损耗.
  • 反亲和性: 当应用采用多副本部署时,有必要采用反亲和性让各个应用实例打散分布在各个node上,这样可以提高服务的高可用性和扩展性
  • NodeAffinity: 首先来看一下NodeAffinity的可配置项:
pod.spec.affinity.nodeAffinity
  requiredDuringSchedulingIgnoredDuringExecution  Node节点必须满足指定的所有规则才可以,相当于硬限制
    nodeSelectorTerms  节点选择列表
      matchFields   按节点字段列出的节点选择器要求列表
      matchExpressions   按节点标签列出的节点选择器要求列表(推荐)
        key    键
        values 值
        operator 关系符 支持Exists, DoesNotExist, In, NotIn, Gt, Lt
  preferredDuringSchedulingIgnoredDuringExecution 优先调度到满足指定的规则的Node,相当于软限制 (倾向)
    preference   一个节点选择器项,与相应的权重相关联
      matchFields   按节点字段列出的节点选择器要求列表
      matchExpressions   按节点标签列出的节点选择器要求列表(推荐)
        key    键
        values 值
        operator 关系符 支持In, NotIn, Exists, DoesNotExist, Gt, Lt
	weight 倾向权重,在范围1-100。
关系符的使用说明:

- matchExpressions:
  - key: nodeenv              # 匹配存在标签的key为nodeenv的节点
    operator: Exists
  - key: nodeenv              # 匹配标签的key为nodeenv,且value是"xxx"或"yyy"的节点
    operator: In
    values: ["xxx","yyy"]
  - key: nodeenv              # 匹配标签的key为nodeenv,且value大于"xxx"的节点
    operator: Gt
    values: "xxx"
  • 接下来首先演示一下requiredDuringSchedulingIgnoredDuringExecution 硬限制,
#创建一个pod-nodeaffinity-required.yaml
[root@xnode1 ~]# cat <<EOF > pod-nodeaffinity-required.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeaffinity-required
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:  #亲和性设置
    nodeAffinity: #设置node亲和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
        nodeSelectorTerms:
        - matchExpressions: # 匹配env的值在["xxx","yyy"]中的标签
          - key: nodeenv
            operator: In
            values: ["xxx","yyy"]
EOF

#查看状态
[root@xnode1 ~]# kubectl create -f pod-nodeaffinity-required.yaml 
pod/pod-nodeaffinity-required created
[root@xnode1 ~]# 
[root@xnode1 ~]# kubectl get pods -n dev pod-nodeaffinity-required -o wide
NAME                        READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
pod-nodeaffinity-required   0/1     Pending   0          17s   <none>   <none>   <none>           <none>

#查看这个pod的详细信息:Waring提示目前两个节点都不能满足您的调度需求
[root@xnode1 ~]# kubectl describe pod -n dev pod-nodeaffinity-required
... ...

Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  49s   default-scheduler  0/2 nodes are available: 2 node(s) didn't match node selector.
  
#重新修改这个配置文件
[root@xnode1 ~]# cat <<EOF > pod-nodeaffinity-required.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeaffinity-required
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:  #亲和性设置
    nodeAffinity: #设置node亲和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
        nodeSelectorTerms:
        - matchExpressions: # 匹配env的值在["xxx","yyy"]中的标签
          - key: nodeenv
            operator: In
            values: ["test","yyy"]
EOF

#再次尝试
[root@xnode1 ~]# kubectl create -f pod-nodeaffinity-required.yaml 
pod/pod-nodeaffinity-required created

[root@xnode1 ~]# kubectl get pods -n dev -o wide
NAME                        READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
pod-nodeaffinity-required   1/1     Running   0          6s    10.244.1.80   xnode2   <none>           <none>
pod-nodename                1/1     Running   0          86m   10.244.1.79   xnode2   <none>           <none>
  • 我们来演示一下requiredDuringSchedulingIgnoredDuringExecution ,软限制
[root@xnode1 ~]# cat <<EOF > pod-nodeaffinity-preferred.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeaffinity-preferred
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:  #亲和性设置
    nodeAffinity: #设置node亲和性
      preferredDuringSchedulingIgnoredDuringExecution: # 软限制
      - weight: 1
        preference:
          matchExpressions: # 匹配env的值在["xxx","yyy"]中的标签(当前环境没有)
          - key: nodeenv
            operator: In
            values: ["xxx","yyy"]
EOF

[root@xnode1 ~]# kubectl get pods -n dev pod-nodeaffinity-preferred -o wide
NAME                         READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
pod-nodeaffinity-preferred   1/1     Running   0          31s   10.244.1.81   xnode2   <none>           <none>

#因为使用的调度方法为软限制,软限制的调度策略优先寻找匹配的values,如果找不到就调度到可用的node节点上
[root@xnode1 ~]# kubectl describe pod -n dev pod-nodeaffinity-preferred 
... ...

Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  56s   default-scheduler  Successfully assigned dev/pod-nodeaffinity-preferred to xnode2
  Normal  Pulled     55s   kubelet, xnode2    Container image "nginx:1.17.1" already present on machine
  Normal  Created    54s   kubelet, xnode2    Created container nginx
  Normal  Started    54s   kubelet, xnode2    Started container nginx

NodeAffinity注意事项:

NodeAffinity规则设置的注意事项:

①.如果同时定义了nodeSelector(指定node标签匹配)和nodeAffinity(指定node匹配),那么必须两个条件都得到满足,Pod才能运行在指定的Node上.

②.如果nodeAffinity(指定node匹配)指定了多个nodeSelectorTerms(指定node标签匹配),那么只需要其中一个能够匹配成功即可

③.如果一个nodeSelectorTerms中有多个matchExpressions,则一个节点必须满足所有的才能匹配成功

④.如果一个Pod所在的Node在Pod运行期间其标签发生了变化,不再符合该Pod的节点亲和性需求,则系统将忽略此变化

(4)、PodAffinity

PodAffinity 主要实现以运行的Pod为参照物,实现让新创建的Pod跟参照Pod在一个区域的功能.

我们查看一下PodAffinity的可配置选项:

pod.spec.affinity.podAffinity
 # requiredDuringSchedulingIgnoredDuringExecution  硬限制
    namespaces       指定参照pod的namespace
    topologyKey      指定调度作用域
    labelSelector    标签选择器
      matchExpressions  按节点标签列出的节点选择器要求列表(推荐)
        key    键
        values 值
        operator 关系符 支持In, NotIn, Exists, DoesNotExist.
      matchLabels    指多个matchExpressions映射的内容
 # preferredDuringSchedulingIgnoredDuringExecution 软限制
    podAffinityTerm  选项
      namespaces      
      topologyKey
      labelSelector
        matchExpressions  
          key    键
          values 值
          operator
        matchLabels 
    weight 倾向权重,在范围1-100

toplogKey用于指定调度时作用域,例如:

  • 如果指定kubernetes.io/hostname,那就是以Node节点为分区范围
  • 如果指定为beta.kubernetes.io/os,则以Node节点的操作系统类型来区分
  • 演示requiredDuringSchedulingIgnoredDuringExecution
  • (1)、首先 创建一个参照Pod,pod-podaffinity-target.yaml
[root@xnode1 ~]# cat <<EOF > pod-podaffinity-target.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-podaffinity-target
  namespace: dev
  labels:
    podenv: test #设置标签
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  nodeName: xnode2 # 将目标pod名确指定到xnode2上
EOF

#查看Pod的信息
[root@xnode1 ~]# kubectl get pods -n dev pod-podaffinity-target -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
pod-podaffinity-target   1/1     Running   0          40s   10.244.1.89   xnode2   <none>

[root@xnode1 ~]# kubectl get pods -n dev pod-podaffinity-target -o wide --show-labels
NAME                     READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES   LABELS
pod-podaffinity-target   1/1     Running   0          71s   10.244.1.89   xnode2   <none>           <none>            podenv=test<none>
  • (2)、创建pod-podaffinity-required.yaml,内容如下:
[root@xnode1 ~]# cat <<EOF > pod-podaffinity-required.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-podaffinity-required
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:  #亲和性设置
    podAffinity: #设置pod亲和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
      - labelSelector:
          matchExpressions: # 匹配env的值在["xxx","yyy"]中的标签
          - key: podenv
            operator: In
            values: ["xxx","yyy"]
        topologyKey: kubernetes.io/hostname
EOF

#启动pod
[root@xnode1 ~]# kubectl create -f pod-podaffinity-required.yaml 
pod/pod-podaffinity-required created

#查看容器状态发现启动失败:查看详情"两个节点不可用,一个节点与pod关联规则不匹配,一个节点不匹配pod关联,一个节点有污点"
[root@xnode1 ~]# kubectl get pods -n dev pod-podaffinity-required -o wide --show-labels
NAME                       READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES   LABELS
pod-podaffinity-required   0/1     Pending   0          60s   <none>   <none>   <none>           <none>            <none>

[root@xnode1 ~]# kubectl describe pod -n dev pod-podaffinity-required 

... ...
Events:
  Type     Reason            Age                 From               Message
  ----     ------            ----                ----               -------
  Warning  FailedScheduling  16s (x3 over 105s)  default-scheduler  0/2 nodes are available: 1 node(s) didn't match pod affinity rules, 1 node(s) didn't match pod affinity/anti-affinity, 1 node(s) had taints that the pod didn't tolerate.
  
#修改配置文件
[root@xnode1 ~]# cat <<EOF > pod-podaffinity-required.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-podaffinity-required
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:  #亲和性设置
    podAffinity: #设置pod亲和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
      - labelSelector:
          matchExpressions: # 匹配env的值在["test","yyy"]中的标签
          - key: podenv
            operator: In
            values: ["test","yyy"]
        topologyKey: kubernetes.io/hostname
EOF

#再次查看
[root@xnode1 ~]# kubectl get pods -n dev pod-podaffinity-required -o wide --show-labels
NAME                       READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES   LABELS
pod-podaffinity-required   1/1     Running   0          6s    10.244.1.90   xnode2   <none>           <none>            <none>

(5)、PodAntiAffinity

PodAntiAffinity 主要实现以运行的Pod为参照,让新创建的Pod跟参照Pod不再一个区域中的功能.

  • (1)、继续使用上面的案例
[root@k8s-master01 ~]# kubectl get pods -n dev -o wide --show-labels
NAME                     READY   STATUS    RESTARTS   AGE     IP            NODE    LABELS
pod-podaffinity-required 1/1     Running   0          3m29s   10.244.1.38   node1   <none>     
pod-podaffinity-target   1/1     Running   0          9m25s   10.244.1.37   node1   podenv=pro
  • (2)、创建pod-podantiaffinity-required.yaml,内容如下:
# 上面配置表达的意思是:新Pod必须要与拥有标签nodeenv=pro的pod不在同一Node上,运行测试一下。
apiVersion: v1
kind: Pod
metadata:
  name: pod-podantiaffinity-required
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:  #亲和性设置
    podAntiAffinity: #设置pod亲和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
      - labelSelector:
          matchExpressions: # 匹配podenv的值在["pro"]中的标签
          - key: podenv
            operator: In
            values: ["pro"]
        topologyKey: kubernetes.io/hostname
# 创建pod
[root@k8s-master01 ~]# kubectl create -f pod-podantiaffinity-required.yaml
pod/pod-podantiaffinity-required created

# 查看pod
# 发现调度到了node2上
[root@k8s-master01 ~]# kubectl get pods pod-podantiaffinity-required -n dev -o wide
NAME                           READY   STATUS    RESTARTS   AGE   IP            NODE   .. 
pod-podantiaffinity-required   1/1     Running   0          30s   10.244.1.96   node2  ..

(6)、调度污点

污点(Taints):

在前面的调度方式都是站在Pod的角度上,通过在Pod上添加属性,来确定Pod是否要调度到指定的Node上,其实我们也可以站在Node的角度上,通过在Node上添加 污点 属性,来决定是否允许Pod调度过来.

Node被设置上污点之后就和Pod之间存在了一种相斥的关系,进而拒绝Pod调度进来,甚至可以将已存在的Pod驱逐出去;污点的格式为:key=value:effect ,key和value是污点的标签,effect描述污点的作用,支持如下三个选项:

  • **PreferNoSchedule: ** kubernetes将尽量避免把Pod调度到具有该污点的Pod上,除非没有其它节点可以调度
  • NoSchedule: kubernetes将不会把Pod调度到具有该污点的Node上,但不会影响当前Node上已存在的Pod
  • NoExecute: kubernetes将不会把Pod调度到具有该污点的Node上,同时也会将Node上已存在的Pod驱离.

在这里插入图片描述

  • 设置污点、去处污点
# 设置污点
kubectl taint nodes xnode1 key=value:effect

# 去除污点
kubectl taint nodes xnode1 key:effect-

# 去除所有污点
kubectl taint nodes xnode1 key-
  • 接下来,演示下污点的效果:
  1. 准备节点node1(为了演示效果更加明显,暂时停止node2节点)
  2. 为node1节点设置一个污点: tag=heima:PreferNoSchedule;然后创建pod1( pod1 可以 )
  3. 修改为node1节点设置一个污点: tag=heima:NoSchedule;然后创建pod2( pod1 正常 pod2 失败 )
  4. 修改为node1节点设置一个污点: tag=heima:NoExecute;然后创建pod3 ( 3个pod都失败 )
#为xnode2和xnode3设置污点
[root@xnode1 ~]# kubectl taint nodes xnode2 tag=xnode2:NoSchedule
node/xnode2 tainted
[root@xnode1 ~]# kubectl describe node xnode2 | grep Taints:
Taints:             tag=xnode2:NoSchedule
[root@xnode1 ~]# kubectl taint nodes xnode3 tag=xnode3:PreferNoSchedule
node/xnode3 tainted
[root@xnode1 ~]# kubectl describe node xnode3 | grep Taints:
Taints:             tag=xnode3:PreferNoSchedule

#启动Pod
[root@xnode1 ~]# kubectl run taint1 --image=nginx:1.17.1 -n dev 
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/taint1 created

#查看Pod:xnode2设置为NoSchedule(新的不要来,旧的不动),xnode3设置为PreferNoSchedule(尽量别来)
#此时的Pod应运行在xnode3上
[root@xnode1 ~]# kubectl get pod -n dev -o wide
NAME                      READY   STATUS    RESTARTS   AGE     IP           NODE     NOMINATED NODE   READINESS GATES
taint1-56b4468b94-4bd2m   1/1     Running   0          2m11s   10.244.2.6   xnode3   <none>           <none>


#把xnode3设置成NoSchedule(新的不要来,旧的不动)
#把xnode2设置成PreferNoSchedule(尽量别来)
[root@xnode1 ~]# kubectl taint nodes xnode3 tag=xnode3:NoSchedule
node/xnode3 tainted
[root@xnode1 ~]# kubectl taint nodes xnode2 tag=xnode2:PreferNoSchedule
node/xnode2 tainted


#再次启动Pod
#可以看到xnode3的容器正在运行,新Pod不会调度到xnode3
[root@xnode1 ~]# kubectl get pod -n dev -o wide
NAME                      READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
taint1-56b4468b94-4bd2m   1/1     Running   0          10m     10.244.2.6    xnode3   <none>           <none>
taint2-88556f6-8r47g      1/1     Running   0          3m24s   10.244.1.11   xnode2   <none>           <none>

#将xnode3设置成NoExecute(新的不要来啊旧的赶紧走)
[root@xnode1 ~]# kubectl taint nodes xnode3 tag:NoSchedule-
node/xnode3 untainted
[root@xnode1 ~]# kubectl taint nodes xnode3 tag=xnode3:NoExecute
node/xnode3 tainted

#再次查看Pod:发现Pod taint1转移到xnode2
[root@xnode1 ~]# kubectl get pod -n dev -o wide
NAME                      READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
taint1-56b4468b94-62xmb   1/1     Running   0          13s     10.244.1.12   xnode2   <none>           <none>
taint2-88556f6-8r47g      1/1     Running   0          6m19s   10.244.1.11   xnode2   <none>           <none>

(7)、污点的容忍(Toleration)

容忍(Toleration):

在node上添加污点用于拒绝pod调度上来,但是如果就是想将一个pod调度到一个有污点的node上去,这时候应该怎么做呢?这个实施就要使用到容忍.

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

在这里插入图片描述

  • 在之前xnode3已经打上了NoExecute的污点,此时Pod是调度不上去的,关闭xnode2.
  • 这里可以通过给pod添加容忍,然后将其调度上去

创建 pod-toleration.yaml文件

cat <<EOF > pod-toleration.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-toleration
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  tolerations:      # 添加容忍
  - key: "tag"        # 要容忍的污点的key
    operator: "Equal" # 操作符
    value: "xnode3"    # 容忍的污点的value
    effect: "NoExecute"   # 添加容忍的规则,这里必须和标记的污点规则相同
EOF
#没有设置容忍直接启动Pod:新启动的Pod状态为Pending
[root@xnode1 ~]# kubectl run taint3 --image=nginx:1.17.1 -n dev 
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/taint3 created

[root@xnode1 ~]# kubectl get pods -n dev -o wide 
NAME                      READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
taint1-56b4468b94-62xmb   1/1     Running   0          29m   10.244.1.12   xnode2   <none>           <none>
taint2-88556f6-8r47g      1/1     Running   0          35m   10.244.1.11   xnode2   <none>           <none>
taint3-69b4df4bf4-gzf9l   0/1     Pending   0          12s   <none>        <none>   <none>           <none>

#使用设置了污点容忍的yaml文件创建一个Pod:运行状态正常
[root@xnode1 ~]# kubectl create -f pod-toleration.yaml 
pod/pod-toleration created

[root@xnode1 ~]# kubectl get pods -n dev pod-toleration -o wide
NAME             READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
pod-toleration   1/1     Running   0          53s   10.244.2.7   xnode3   <none>           <none>
  • 容忍的详细配置
kubectl explain pod.spec.tolerations
......
FIELDS:
   key       # 对应着要容忍的污点的键,空意味着匹配所有的键
   value     # 对应着要容忍的污点的值
   operator  # key-value的运算符,支持Equal和Exists(默认)
   effect    # 对应污点的effect,空意味着匹配所有影响
   tolerationSeconds   # 容忍时间, 当effect为NoExecute时生效,表示pod在Node上的停留时间

十一、Pod控制器

Pod控制器介绍:

在kubernetes中,按照Pod的创建方式可以分为两种

  • **自主式Pod:**kubernetes直接创建出来的Pod,这种Pod删除后就没有了,也不会重建
  • 控制器创建的Pod: 通过控制器创建的Pod,这种Pod删除了之后还会自动重建

Pod控制器是管理pod的中间层,使用Pod控制器之后,只需要告诉Pod控制器,想要多少个什么样的Pod就可以了,它会创建出满足条件的Pod并确保每一个Pod资源处于用户期望的目标状态。如果Pod资源在运行中出现故障,它会基于指定策略重新编排Pod。

  • 在kubernetes中,有很多类型的Pod控制器,每种都有自己的适合的场景,常见的有下面这些:
Pod控制器的类型作用
ReplicationController:比较原始的pod控制器,已经被废弃,由ReplicaSet替代
ReplicaSet:保证副本数量一直维持在期望值,并支持pod数量扩缩容,镜像版本升级
Deployment:通过控制ReplicaSet来控制Pod,并支持滚动升级、回退版本
Horizontal Pod Autoscaler:可以根据集群负载自动水平调整Pod的数量,实现削峰填谷
DaemonSet:在集群中的指定Node上运行且仅运行一个副本,一般用于守护进程类的任务
Job:它创建出来的pod只要完成任务就立即退出,不需要重启或重建,用于执行一次性任务
Cronjob:它创建的Pod负责周期性任务控制,不需要持续后台运行
StatefulSet:管理有状态应用

(1)、ReplicaSet(RS)

在这里插入图片描述

ReplicaSet的主要作用是 保证一定数量的Pod正常运行 ,它会持续监听这些Pod的运行状态,一旦Pod发生故障,就会重启或重建。同时它还支持对Pod数量的扩缩容和镜像版本的升降级。

  • ReplicaSet的资源清单文件:
apiVersion: apps/v1 # 版本号
kind: ReplicaSet # 类型       
metadata: # 元数据
  name: # rs名称 
  namespace: # 所属命名空间 
  labels: #标签
    controller: rs
spec: # 详情描述
  replicas: 3 # 副本数量
  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

在这里面的配置文件,需要重新了解的配置项就是spec下面几个选项:

  • replicas:指定副本的数量,其实就是当前rs创建出来的数量,默认为1
  • selector:选择器,它的作用是建立Pod控制器和Pod之间的关联关系, 采用的Label Selector机制在Pod模板上定义Label,在控制器上定义选择器,就可以表明当前控制器能管理哪些Pod了
  • template:模板,就是当前控制器创建Pod所使用的的模板,里面其实就是之前学过的Pod的定义.

创建一个 ReplicaSet:

创建 pc-replicaset.yaml文件,内容如下.

cat <<EOF  > pc.replicaset.yaml
apiVersion: apps/v1
kind: ReplicaSet   
metadata:
  name: pc-replicaset
  namespace: dev
spec:
  replicas: 3
  selector: 
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
EOF
#创建rs
[root@xnode1 ~]# kubectl create -f pc.replicaset.yaml 
replicaset.apps/pc-replicaset created

#查看刚刚创建的rs:
#DESIRED:期望副本数量
#CURRENT:当前副本数量
#READY:已经准备好提供服务的副本数量
[root@xnode1 ~]# kubectl get rs -n dev pc-replicaset -o wide
NAME            DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES         SELECTOR
pc-replicaset   3         3         3       62s   nginx        nginx:1.17.1   app=nginx-pod

#查看Pod
[root@xnode1 ~]# kubectl get pods -n dev -o wide | grep ^pc-replicaset
pc-replicaset-g5dgl       1/1     Running   0          5m21s   10.244.1.18   xnode2   <none>           <none>
pc-replicaset-srnmz       1/1     Running   0          5m21s   10.244.1.19   xnode2   <none>           <none>
pc-replicaset-vcjqt       1/1     Running   0          5m21s   10.244.1.17   xnode2   <none>           <none>

#修改rs配置文件
[root@xnode1 ~]# kubectl edit rs -n dev pc-replicaset 

     15 spec:
     16   replicas: 4	==>	数量从3修改成4
     17   selector:
     18     matchLabels:
     19       app: nginx-pod
     20   template:
     21     metadata:
     22       creationTimestamp: null
     23       labels:
     24         app: nginx-pod
     
#查看rs和pod
[root@xnode1 ~]# kubectl get rs -n dev pc-replicaset -o wide
NAME            DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES         SELECTOR
pc-replicaset   4         4         4       10m   nginx        nginx:1.17.1   app=nginx-pod

[root@xnode1 ~]# kubectl get pods -n dev -o wide | grep ^pc-replicaset
pc-replicaset-g5dgl       1/1     Running   0          10m     10.244.1.18   xnode2   <none>           <none>
pc-replicaset-jgjtd       1/1     Running   0          23s     10.244.1.20   xnode2   <none>           <none>
pc-replicaset-srnmz       1/1     Running   0          10m     10.244.1.19   xnode2   <none>           <none>
pc-replicaset-vcjqt       1/1     Running   0          10m     10.244.1.17   xnode2   <none>           <none>

#直接使用命令来实现
#使用`scale`命令实现扩缩容, 后面--replicas=n 直接指定目标数量即可
[root@xnode1 ~]# kubectl scale rs -n dev pc-replicaset --replicas=2
replicaset.extensions/pc-replicaset scaled

#再次查看rs和pod
[root@xnode1 ~]# kubectl get rs -n dev pc-replicaset -o wide
NAME            DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES         SELECTOR
pc-replicaset   2         2         2       14m   nginx        nginx:1.17.1   app=nginx-pod

[root@xnode1 ~]# kubectl get pods -n dev -o wide | grep ^pc-replicaset
pc-replicaset-srnmz       1/1     Running   0          15m     10.244.1.19   xnode2   <none>           <none>
pc-replicaset-vcjqt       1/1     Running   0          15m     10.244.1.17   xnode2   <none>           <none>
#给Pod进行版本的升降级:修改配置文件
[root@xnode1 ~]# kubectl edit rs -n dev pc-replicaset 

     27     spec:
     28       containers:
     29       - image: nginx:1.17.1		==>nginx:1.17.1修改成'nginx:1.17.2'
     30         imagePullPolicy: IfNotPresent
     31         name: nginx
     32         resources: {}
     33         terminationMessagePath: /dev/termination-log
     34         terminationMessagePolicy: File
     
#查看版本:发现版本以及变更
[root@xnode1 ~]# kubectl get rs -n dev pc-replicaset -o wide
NAME            DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES         SELECTOR
pc-replicaset   2         2         2       19m   nginx        nginx:1.17.2   app=nginx-pod

#使用命令对版本进行升降级:
[root@xnode1 ~]# kubectl set image rs pc-replicaset nginx=nginx:1.17.1 -n dev 
replicaset.extensions/pc-replicaset image updated

[root@xnode1 ~]# kubectl get rs -n dev pc-replicaset -o wide
NAME            DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES         SELECTOR
pc-replicaset   2         2         2       24m   nginx        nginx:1.17.1   app=nginx-pod
  • 删除ReplicaSet:
#使用kubectl delete命令会删除此RS以及其它管理的Pod
#在kubernetes删除rs前,会将rs的replicasclear调整为0,等待所有的Pod被删除后,在执行RS对象的删除
kubectl delete rs pc-replicaset -n dev

#如果希望仅仅删除rs对象,保留(Pod),可以使用Kubectl delete命令添加--cascade=false选项,这样不推荐
kubectl delete rs pc-replicaset -n dev --cascade=false

#也可以使用yaml直接删除
[root@xnode1 ~]# kubectl delete -f pc.replicaset.yaml 
replicaset.apps "pc-replicaset" deleted

(2)、Deployment (Deploy)

为了更好解决服务编排的问题,kubernetes在v:1.12.版本开始,引入了Deployment控制器,这个控制器并不是直接管理Pod,而是通过ReplicaSet来进行管理Pod

即:Deployment管理ReplicaSet,ReplicaSet管理Pod,所以Deployment比ReplicaSet功能更加强大.

在这里插入图片描述

Deployment 主要的功能有下面几个:

  • 支持ReplicaSet的所有功能
  • 支持发布的停止、继续
  • 支持滚动升级和回滚版本

Deployment的资源清单文件:

apiVersion: apps/v1 # 版本号
kind: Deployment # 类型       
metadata: # 元数据
  name: # rs名称 
  namespace: # 所属命名空间 
  labels: #标签
    controller: deploy
spec: # 详情描述
  replicas: 3 # 副本数量
  revisionHistoryLimit: 3 # 保留历史版本
  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
  • 创建Deployment:
cat <<EOF > pc-deployment.yaml
apiVersion: apps/v1
kind: Deployment      
metadata:
  name: pc-deployment
  namespace: dev
spec: 
  replicas: 3
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
EOF
#创建deployment
[root@xnode1 ~]# kubectl create -f pc-deployment.yaml 
deployment.apps/pc-deployment created

#查看:
#UP-TO-DATE 最新版本的pod的数量
#AVAILABLE 当前可用的pod的数量
[root@xnode1 ~]# kubectl get deployment -n dev -o wide | grep ^pc-deployment
pc-deployment   3/3     3            3           28s     nginx        nginx:1.17.1   app=nginx-pod

#查看rs:发现rs的名称是在原来的deployment的名字后面添加了一个10位数的随机串
[root@xnode1 ~]# kubectl get rs -n dev -o wide
NAME                       DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES         SELECTOR
pc-deployment-77d96bb58b   3         3         3       5m5s    nginx        nginx:1.17.1   app=nginx-pod,pod-template-hash=77d96bb58b

扩缩容:

  • 命令行
  • 编辑配置文件
#使用命令行进行扩缩容
[root@xnode1 ~]# kubectl scale deployment pc-deployment --replicas=5 -n dev 
deployment.extensions/pc-deployment scaled

[root@xnode1 ~]# kubectl get pod -n dev | grep ^pc-deployment
pc-deployment-77d96bb58b-8kf2l   1/1     Running   0          20m
pc-deployment-77d96bb58b-fkrbz   1/1     Running   0          20m
pc-deployment-77d96bb58b-gfw2x   1/1     Running   0          34s
pc-deployment-77d96bb58b-m84wl   1/1     Running   0          20m
pc-deployment-77d96bb58b-nbbbq   1/1     Running   0          34s

#使用修改配置文件的方式进行缩扩容
[root@xnode1 ~]# kubectl edit deployment pc-deployment -n dev

     17 spec:
     18   progressDeadlineSeconds: 600
     19   replicas: 3		==>修改为3
     20   revisionHistoryLimit: 10
     21   selector:
     22     matchLabels:
     23       app: nginx-pod

[root@xnode1 ~]# kubectl get pod -n dev 
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-77d96bb58b-8f862   1/1     Running   0          4s
pc-deployment-77d96bb58b-8kf2l   1/1     Running   0          31m
pc-deployment-77d96bb58b-bkfn9   1/1     Running   0          4s

镜像更新:

Deployment 支持两种镜像更新的策略:重建更新滚动更新(默认),可以通过strategy 选项进行配置.

strategy:指定新的Pod替换旧的Pod的策略, 支持两个属性:
  type:指定策略类型,支持两种策略
    Recreate:在创建出新的Pod之前会先杀掉所有已存在的Pod
    RollingUpdate:滚动更新,就是杀死一部分,就启动一部分,在更新过程中,存在两个版本Pod
  rollingUpdate:当type为RollingUpdate时生效,用于为RollingUpdate设置参数,支持两个属性:
    maxUnavailable:用来指定在升级过程中不可用Pod的最大数量,默认为25%。
    maxSurge: 用来指定在升级过程中可以超过期望的Pod的最大数量,默认为25%。
  • 重建更新
  1. 编辑 pc-deployment.yaml在spec节点下添加更新策略
spec:
  strategy: # 策略
    type: Recreate # 重建更新
  1. 创建 deploy进行验证
[root@xnode1 ~]# cat <<EOF > pc-deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pc-deployment
  namespace: dev
spec:
  strategy: # 策略
    type: Recreate # 重建更新
  replicas: 3
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
EOF

#应用更新策略
[root@xnode1 ~]# kubectl apply -f pc-deployment.yaml

#执行
[root@xnode1 ~]# kubectl set image deploy pc-deployment nginx=nginx:1.17.2 -n dev 
deployment.extensions/pc-deployment image updated

#查看更新状态
[root@xnode1 ~]# kubectl get pods -n dev -w
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-77d96bb58b-8f862   1/1     Running   0          4m36s
pc-deployment-77d96bb58b-8kf2l   1/1     Running   0          35m
pc-deployment-77d96bb58b-bkfn9   1/1     Running   0          4m36s
taint1-56b4468b94-tbt4z          1/1     Running   0          4d23h
taint2-88556f6-dhhgl             1/1     Running   0          4d23h
taint3-69b4df4bf4-gzf9l          1/1     Running   0          4d23h
^C[root@xnode1 ~]# 
[root@xnode1 ~]# kubectl get pods -n dev -w | grep ^pc-deployment
pc-deployment-77d96bb58b-8f862   1/1     Running   0          4m52s
pc-deployment-77d96bb58b-8kf2l   1/1     Running   0          36m
pc-deployment-77d96bb58b-bkfn9   1/1     Running   0          4m52s
pc-deployment-77d96bb58b-8f862   1/1     Terminating   0          5m42s
pc-deployment-77d96bb58b-bkfn9   1/1     Terminating   0          5m42s
pc-deployment-77d96bb58b-8kf2l   1/1     Terminating   0          36m
pc-deployment-77d96bb58b-8kf2l   0/1     Terminating   0          37m
pc-deployment-77d96bb58b-bkfn9   0/1     Terminating   0          5m46s
pc-deployment-77d96bb58b-8f862   0/1     Terminating   0          5m46s
pc-deployment-77d96bb58b-8kf2l   0/1     Terminating   0          37m
pc-deployment-77d96bb58b-8kf2l   0/1     Terminating   0          37m
pc-deployment-77d96bb58b-8f862   0/1     Terminating   0          5m53s
pc-deployment-77d96bb58b-8f862   0/1     Terminating   0          5m53s
pc-deployment-77d96bb58b-bkfn9   0/1     Terminating   0          5m53s
pc-deployment-77d96bb58b-bkfn9   0/1     Terminating   0          5m53s
pc-deployment-54fd46c697-zq2l4   0/1     Pending       0          0s
pc-deployment-54fd46c697-zq2l4   0/1     Pending       0          0s
pc-deployment-54fd46c697-kjftb   0/1     Pending       0          0s
pc-deployment-54fd46c697-fjxv6   0/1     Pending       0          0s
pc-deployment-54fd46c697-kjftb   0/1     Pending       0          0s
pc-deployment-54fd46c697-fjxv6   0/1     Pending       0          0s
pc-deployment-54fd46c697-zq2l4   0/1     ContainerCreating   0          0s
pc-deployment-54fd46c697-kjftb   0/1     ContainerCreating   0          1s
pc-deployment-54fd46c697-fjxv6   0/1     ContainerCreating   0          1s
pc-deployment-54fd46c697-zq2l4   1/1     Running             0          29s
pc-deployment-54fd46c697-kjftb   1/1     Running             0          35s
pc-deployment-54fd46c697-fjxv6   1/1     Running             0          51s
  • 滚动更新

01.编辑pc-deployment.yaml,在spec节点上添加更新策略

cat <<EOF > pc-deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pc-deployment
  namespace: dev
spec:
  strategy: # 策略
    type: RollingUpdate # 滚动更新策略
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
  replicas: 3
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
EOF

#应用更新策略
[root@xnode1 ~]# kubectl apply -f pc-deployment.yaml 
deployment.apps/pc-deployment configured
#启动更新
[root@xnode1 ~]# kubectl set image deploy pc-deployment nginx=nginx:1.17.3 -n dev 
deployment.extensions/pc-deployment image updated

#查看Pod状态
[root@xnode1 ~]# kubectl get pods -n dev -w | grep ^pc-deployment
pc-deployment-77d96bb58b-8w5rx   1/1     Running   0          60s
pc-deployment-77d96bb58b-kbp4h   1/1     Running   0          53s
pc-deployment-77d96bb58b-vvngp   1/1     Running   0          50s
pc-deployment-7975858c88-r55gc   0/1     Pending   0          0s
pc-deployment-7975858c88-r55gc   0/1     Pending   0          0s
pc-deployment-7975858c88-r55gc   0/1     ContainerCreating   0          0s
pc-deployment-7975858c88-r55gc   1/1     Running             0          10s
pc-deployment-77d96bb58b-vvngp   1/1     Terminating         0          97s
pc-deployment-7975858c88-bwht8   0/1     Pending             0          0s
pc-deployment-7975858c88-bwht8   0/1     Pending             0          0s
pc-deployment-7975858c88-bwht8   0/1     ContainerCreating   0          0s
pc-deployment-77d96bb58b-vvngp   0/1     Terminating         0          98s
pc-deployment-7975858c88-bwht8   1/1     Running             0          2s
pc-deployment-77d96bb58b-kbp4h   1/1     Terminating         0          102s
pc-deployment-7975858c88-rv5rp   0/1     Pending             0          0s
pc-deployment-77d96bb58b-vvngp   0/1     Terminating         0          99s
pc-deployment-7975858c88-rv5rp   0/1     Pending             0          0s
pc-deployment-77d96bb58b-vvngp   0/1     Terminating         0          99s
pc-deployment-7975858c88-rv5rp   0/1     ContainerCreating   0          1s
pc-deployment-77d96bb58b-kbp4h   0/1     Terminating         0          103s
pc-deployment-7975858c88-rv5rp   1/1     Running             0          2s
pc-deployment-77d96bb58b-8w5rx   1/1     Terminating         0          112s
pc-deployment-77d96bb58b-kbp4h   0/1     Terminating         0          105s
pc-deployment-77d96bb58b-kbp4h   0/1     Terminating         0          105s
pc-deployment-77d96bb58b-8w5rx   0/1     Terminating         0          112s
pc-deployment-77d96bb58b-8w5rx   0/1     Terminating         0          113s
pc-deployment-77d96bb58b-8w5rx   0/1     Terminating         0          114s

滚动更新的过程:

在这里插入图片描述

  • 镜像更新中rs的变化
#查看rs,发现原来的rs的依旧存在,只是Pod数量变为了0,而后又新产生了一个rs,pod数量为4
#这就是deployment能够进行版本回退的奥妙所在
[root@xnode1 ~]# kubectl get rs -n dev | grep ^pc-deployment
pc-deployment-54fd46c697   0         0         0       128m
pc-deployment-77d96bb58b   0         0         0       165m
pc-deployment-7975858c88   3         3         3       115m

版本回退:

deployment支持版本升级过程中的暂停,继续功能以及版本回退等诸多功能,下面具体来看.

kubectl rollout: 版本升级相关功能,支持下面的选项:

  • status 显示当前升级状态
  • history 显示升级历史记录
  • pause 暂停版本升级过程
  • resume 继续以及暂停的版本升级过程
  • restart 重启版本升级过程
  • undo 回滚到上一级版本(可以使用 --to-version回滚到指定版本)
#查看升级状态
[root@xnode1 ~]# kubectl rollout status deploy -n dev pc-deployment
deployment "pc-deployment" successfully rolled out

#显示升级历史记录
[root@xnode1 ~]# kubectl rollout history deploy -n dev pc-deployment
deployment.extensions/pc-deployment 
REVISION  CHANGE-CAUSE
1         kubectl create --filename=pc-deployment.yaml --record=true
2         kubectl create --filename=pc-deployment.yaml --record=true

#版本回退
#查看当前版本
[root@xnode1 ~]# kubectl get deployments -n dev -o wide
NAME            READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS   IMAGES         SELECTOR
pc-deployment   3/3     3            3           16m     nginx        nginx:1.17.2   app=nginx-pod

[root@xnode1 ~]# kubectl rollout undo deployment pc-deployment --to-revision=1 -n dev
deployment.extensions/pc-deployment rolled back

[root@xnode1 ~]# kubectl get deployments -n dev -o wide
NAME            READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS   IMAGES         SELECTOR
pc-deployment   3/3     3            3           19m     nginx        nginx:1.17.1   app=nginx-pod
[root@xnode1 ~]# kubectl get deployment,rs -n dev -o wide | grep pc-deployment

deployment.extensions/pc-deployment   3/3     3            3           22m     nginx        nginx:1.17.1   app=nginx-pod
replicaset.extensions/pc-deployment-54fd46c697   0         0         0       19m     nginx        nginx:1.17.2   app=nginx-pod,pod-template-hash=54fd46c697
replicaset.extensions/pc-deployment-77d96bb58b   3         3         3       22m     nginx        nginx:1.17.1   app=nginx-pod,pod-template-hash=77d96bb58b

#查看回退历史记录
[root@xnode1 ~]# kubectl rollout history deployment pc-deployment -n dev 
deployment.extensions/pc-deployment 
REVISION  CHANGE-CAUSE
2         kubectl create --filename=pc-deployment.yaml --record=true
3         kubectl create --filename=pc-deployment.yaml --record=true

金丝雀:

Deployment控制器支持控制更新过程中的控制,如“暂停(pause)”或“继续(resume)”更新操作。

比如有一批新的Pod资源创建完成后立即暂停更新过程,此时,仅存在一部分新版本的应用,主体部分还是旧的版本。然后,再筛选一小部分的用户请求路由到新版本的Pod应用,继续观察能否稳定地按期望的方式运行。确定没问题之后再继续完成余下的Pod资源滚动更新,否则立即回滚更新操作。这就是所谓的金丝雀发布。

#更新deployment,并配置暂停deployment
[root@xnode1 ~]# kubectl set image deploy pc-deployment nginx=nginx:1.17.4 -n dev && kubectl rollout pause deployment pc-deployment -n dev 
deployment.extensions/pc-deployment image updated
deployment.extensions/pc-deployment paused

#查看此时的deployment更新状态
[root@xnode1 ~]# kubectl rollout status deployment pc-deployment -n dev 
Waiting for deployment "pc-deployment" rollout to finish: 1 out of 3 new replicas have been updated...

#监控更新的过程,可以看到一部分的pod以及更新了一部分,但是没有按照预期的状态去删除一个旧的资源,因为我们上面在更新后面使用了pause暂停命令
[root@xnode1 ~]# kubectl get rs -n dev 
NAME                       DESIRED   CURRENT   READY   AGE
pc-deployment-54fd46c697   0         0         0       30m
pc-deployment-69ff4bbfcf   1         1         1       58s
pc-deployment-77d96bb58b   3         3         3       33m

#确认pod没问题了,继续更新
[root@xnode1 ~]# kubectl rollout resume deployment pc-deployment -n dev 
deployment.extensions/pc-deployment resumed

[root@xnode1 ~]# kubectl rollout status deployment pc-deployment -n dev 
Waiting for deployment "pc-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment spec update to be observed...
Waiting for deployment spec update to be observed...
Waiting for deployment "pc-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "pc-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "pc-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "pc-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "pc-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "pc-deployment" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "pc-deployment" rollout to finish: 1 old replicas are pending termination...
deployment "pc-deployment" successfully rolled out

(3)、Horizontal Pod Autoscaler(HPA)

通过前面的课程学习,我们以及可以实现通过手工kubectl scale 命令实现pod扩容或缩容,但是这并不符合kubernetes的定位目标-自动化.kubernetes期望的是通过监测pod的使用情况,实现pod数量的自动调整,于是就产生了Horizontal Pod Autoscaler(HPA)

HPA原理:

HPA可以获得每个Pod的利用率,然后HPA中定义的指标进行对比,同时计算出需要伸缩的具体值,最后实现Pod数量的调整,其实HPA与之前的Deployment一样,也属于一种kubernetes的资源对象,它通过追踪分析RC控制的所有目标Pod负载变化情况,来确定是否需要针对性的调整目标Pod的副本数,

在这里插入图片描述

1、安装metrics-server

  • metrics-server可以用来收集集群中的资源使用情况
#安装git
[root@xnode1 ~]# yum install git -y
[root@xnode1 ~]# git clone -b v0.3.6 https://github.com/kubernetes-incubator/metrics-server

#修改配置文件
[root@xnode1 ~]# vim /root/metrics-server/deploy/1.8+/metrics-server-deployment.yaml

 24     spec:
 25       hostNetwork: true		==>添加
 26       serviceAccountName: metrics-server
 27       volumes:
 28       # mount in tmp so we can safely use from-scratch images and/or read-only containers
 29       - name: tmp-dir
 30         emptyDir: {}
 31       containers:
 32       - name: metrics-server
 33         image: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server-amd64:v0.3.6	==>修改
 34         imagePullPolicy: Always
 35         args:			==>添加
 36         - --kubelet-insecure-tls		==>添加
 37         - --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP==>添加
 38         volumeMounts:
 39         - name: tmp-dir
 40           mountPath: /tmp
 
[root@xnode1 ~]# cd /root/metrics-server/deploy/1.8+/
[root@xnode1 1.8+]# kubectl apply -f ./
clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created
rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created
serviceaccount/metrics-server created
deployment.apps/metrics-server created
service/metrics-server created
clusterrole.rbac.authorization.k8s.io/system:metrics-server created
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created

#查看
[root@xnode1 1.8+]# kubectl get pods -n kube-system 
NAME                              READY   STATUS    RESTARTS   AGE
coredns-8686dcc4fd-f9pqv          1/1     Running   4          6d
coredns-8686dcc4fd-mtcmn          1/1     Running   7          6d
etcd-xnode1                       1/1     Running   4          6d
kube-apiserver-xnode1             1/1     Running   4          6d
kube-controller-manager-xnode1    1/1     Running   4          6d
kube-flannel-ds-amd64-67htn       1/1     Running   3          6d
kube-flannel-ds-amd64-frh8l       1/1     Running   4          6d
kube-proxy-mvgrq                  1/1     Running   2          5d18h
kube-proxy-ptlm8                  1/1     Running   4          5d20h
kube-proxy-rjgfs                  1/1     Running   2          5d20h
kube-scheduler-xnode1             1/1     Running   5          6d
metrics-server-55f688dd5f-wgjjc   1/1     Running   0          32s

#查看资源的使用情况
[root@xnode1 1.8+]# kubectl top node
NAME     CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
xnode1   166m         8%     1619Mi          42%       
xnode2   39m          3%     748Mi           40%       
xnode3   27m          2%     351Mi           18% 
[root@xnode1 1.8+]# kubectl top pod -n kube-system 
NAME                              CPU(cores)   MEMORY(bytes)   
coredns-8686dcc4fd-f9pqv          3m           15Mi            
coredns-8686dcc4fd-mtcmn          3m           17Mi            
etcd-xnode1                       20m          67Mi            
kube-apiserver-xnode1             28m          236Mi           
kube-controller-manager-xnode1    15m          42Mi            
kube-flannel-ds-amd64-67htn       2m           19Mi            
kube-flannel-ds-amd64-frh8l       3m           12Mi            
kube-proxy-mvgrq                  4m           17Mi            
kube-proxy-ptlm8                  1m           18Mi            
kube-proxy-rjgfs                  1m           20Mi            
kube-scheduler-xnode1             3m           16Mi            
metrics-server-55f688dd5f-wgjjc   1m           12Mi            

2、准备deployment和service

#创建deployment
[root@xnode1 ~]# kubectl run nginx --image=nginx:1.17.1 --requests=cpu=100m -n dev 
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/nginx created

[root@xnode1 ~]# kubectl get deployment,pod -n dev 
NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/nginx   1/1     1            1           60s

NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-84c556bc5c-f6xvm   1/1     Running   0          60s

#创建service
[root@xnode1 ~]# kubectl expose deployment nginx --type=NodePort --port=80 -n dev 
service/nginx exposed

3、部署HPA

#创建pc-hpa.yaml
cat <<EOF > pc-hpa.yaml
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: pc-hpa
  namespace: dev
spec:
  minReplicas: 1  #最小pod数量
  maxReplicas: 10 #最大pod数量
  targetCPUUtilizationPercentage: 3 # CPU使用率指标
  scaleTargetRef:   # 指定要控制的nginx信息
    apiVersion: apps/v1
    kind: Deployment
    name: nginx
EOF

#创建并查看
[root@xnode1 ~]# kubectl create -f pc-hpa.yaml 
horizontalpodautoscaler.autoscaling/pc-hpa created
[root@xnode1 ~]# kubectl get hpa -n dev 
NAME     REFERENCE          TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
pc-hpa   Deployment/nginx   0%/3%     1         10        1          29s

4、测试:

  • 使用测压工具对service地址10.0.0.30:32647进行测试
  • 通过控制台查看hpa和pod的变化
#hpa变化
[root@xnode1 ~]# kubectl get hpa -n dev -w
NAME   REFERENCE      TARGETS  MINPODS  MAXPODS  REPLICAS  AGE
pc-hpa  Deployment/nginx  0%/3%   1     10     1      4m11s
pc-hpa  Deployment/nginx  0%/3%   1     10     1      5m19s
pc-hpa  Deployment/nginx  22%/3%   1     10     1      6m50s
pc-hpa  Deployment/nginx  22%/3%   1     10     4      7m5s
pc-hpa  Deployment/nginx  22%/3%   1     10     8      7m21s
pc-hpa  Deployment/nginx  6%/3%   1     10     8      7m51s
pc-hpa  Deployment/nginx  0%/3%   1     10     8      9m6s
pc-hpa  Deployment/nginx  0%/3%   1     10     8      13m
pc-hpa  Deployment/nginx  0%/3%   1     10     1      14m

#deployment变化
[root@xnode1 ~]# kubectl get deployment -n dev -w
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           11m
nginx   1/4     1            1           13m
nginx   1/4     1            1           13m
nginx   1/4     1            1           13m
nginx   1/4     4            1           13m
nginx   1/8     4            1           14m
nginx   1/8     4            1           14m
nginx   1/8     4            1           14m
nginx   1/8     8            1           14m
nginx   2/8     8            2           14m
nginx   3/8     8            3           14m
nginx   4/8     8            4           14m
nginx   5/8     8            5           14m
nginx   6/8     8            6           14m
nginx   7/8     8            7           14m
nginx   8/8     8            8           15m
nginx   8/1     8            8           20m
nginx   8/1     8            8           20m
nginx   1/1     1            1           20m

#pod变化
[root@xnode1 ~]# kubectl get pods -n dev -w
NAME                     READY   STATUS    RESTARTS   AGE
nginx-7df9756ccc-bh8dr   1/1     Running   0          11m
nginx-7df9756ccc-cpgrv   0/1     Pending   0          0s
nginx-7df9756ccc-8zhwk   0/1     Pending   0          0s
nginx-7df9756ccc-rr9bn   0/1     Pending   0          0s
nginx-7df9756ccc-cpgrv   0/1     ContainerCreating   0          0s
nginx-7df9756ccc-8zhwk   0/1     ContainerCreating   0          0s
nginx-7df9756ccc-rr9bn   0/1     ContainerCreating   0          0s
nginx-7df9756ccc-m9gsj   0/1     Pending             0          0s
nginx-7df9756ccc-g56qb   0/1     Pending             0          0s
nginx-7df9756ccc-sl9c6   0/1     Pending             0          0s
nginx-7df9756ccc-fgst7   0/1     Pending             0          0s
nginx-7df9756ccc-g56qb   0/1     ContainerCreating   0          0s
nginx-7df9756ccc-m9gsj   0/1     ContainerCreating   0          0s
nginx-7df9756ccc-sl9c6   0/1     ContainerCreating   0          0s
nginx-7df9756ccc-fgst7   0/1     ContainerCreating   0          0s
nginx-7df9756ccc-8zhwk   1/1     Running             0          19s
nginx-7df9756ccc-rr9bn   1/1     Running             0          30s
nginx-7df9756ccc-m9gsj   1/1     Running             0          21s
nginx-7df9756ccc-cpgrv   1/1     Running             0          47s
nginx-7df9756ccc-sl9c6   1/1     Running             0          33s
nginx-7df9756ccc-g56qb   1/1     Running             0          48s
nginx-7df9756ccc-fgst7   1/1     Running             0          66s
nginx-7df9756ccc-fgst7   1/1     Terminating         0          6m50s
nginx-7df9756ccc-8zhwk   1/1     Terminating         0          7m5s
nginx-7df9756ccc-cpgrv   1/1     Terminating         0          7m5s
nginx-7df9756ccc-g56qb   1/1     Terminating         0          6m50s
nginx-7df9756ccc-rr9bn   1/1     Terminating         0          7m5s
nginx-7df9756ccc-m9gsj   1/1     Terminating         0          6m50s
nginx-7df9756ccc-sl9c6   1/1     Terminating         0          6m50s

(4)、DaemonSet(DS)

DaemonSet:

DaemonSet 类型的控制器可以保证集群中的每一台(或指定)节点上都运行一个副本,一般是用于日志收集、节点控制等场景。也就是说,如果一个pod提供的功能是节点级别的(每个节点都需要且只需要一个),那么这类pod就适合DaemonSet类型的控制器创建。

在这里插入图片描述

DaemonSet控制器的特点 :

  • 每当向集群中添加一个节点时,指定的pod副本也将添加到该节点上
  • 每当节点从集群中移除时,pod也就被垃圾回收了

1、查看一下DaemonSet的资源清单文件

apiVersion: apps/v1 # 版本号
kind: DaemonSet # 类型       
metadata: # 元数据
  name: # rs名称 
  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

2、创建pc-daemonset.yaml

cat <<EOF > pc-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet      
metadata:
  name: pc-daemonset
  namespace: dev
spec: 
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
EOF

3、查看

[root@xnode1 ~]# kubectl create -f pc-daemonset.yaml 
daemonset.apps/pc-daemonset created

[root@xnode1 ~]# kubectl get daemonset -n dev -o wide
NAME           DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE   CONTAINERS   IMAGES         SELECTOR
pc-daemonset   2         2         2       2            2           <none>          14s   nginx        nginx:1.17.1   app=nginx-pod

[root@xnode1 ~]# kubectl get pods -n dev -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
pc-daemonset-pcdt6       1/1     Running   0          37s     10.244.2.9    xnode3   <none>           <none>
pc-daemonset-zmdh8       1/1     Running   0          37s     10.244.1.61   xnode2   <none>           <none>

4、删除daemonset

[root@xnode1 ~]# kubectl delete -f pc-daemonset.yaml 
daemonset.apps "pc-daemonset" deleted

(5)、Job

Job:

Job主要用于负责 批量处理短暂的 一次性任务,Job的特点:

  • Job创建的Pod执行成功结束时,Job将记录成功结束的pod数量
  • 当成功结束的Pod达到指定的数量时,Job将完成执行

在这里插入图片描述

1、Job资源清单文件

apiVersion: batch/v1 # 版本号
kind: Job # 类型       
metadata: # 元数据
  name: # rs名称 
  namespace: # 所属命名空间 
  labels: #标签
    controller: job
spec: # 详情描述
  completions: 1 # 指定job需要成功运行Pods的次数。默认值: 1
  parallelism: 1 # 指定job在任一时刻应该并发运行Pods的数量。默认值: 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 2;done"]

重启策略说明:

如果指定为OnFailure,则job会在pod出现故障时重启容器,而不是创建pod,failed次数不变
如果指定为Never,则job会在pod出现故障时创建新的pod,并且故障pod不会消失,也不会重启,failed次数加1
如果指定为Always的话,就意味着一直重启,意味着job任务会重复去执行了,当然不对,所以不能设置为Always

2、创建pc-job.yaml

cat <<EOF > pc-job.yaml
apiVersion: batch/v1
kind: Job      
metadata:
  name: pc-job
  namespace: dev
spec:
  manualSelector: true
  selector:
    matchLabels:
      app: counter-pod
  template:
    metadata:
      labels:
        app: counter-pod
    spec:
      restartPolicy: Never
      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 3;done"]
EOF

3、创建并查看

#创建Job
[root@xnode1 ~]# kubectl create -f pc-job.yaml 
job.batch/pc-job created

#监控Job
[root@xnode1 ~]# kubectl get job -n dev -o wide -w
NAME     COMPLETIONS   DURATION   AGE   CONTAINERS   IMAGES         SELECTOR
pc-job   0/1                      0s    counter      busybox:1.30   app=counter-pod
pc-job   0/1           0s         0s    counter      busybox:1.30   app=counter-pod
pc-job   1/1           29s        29s   counter      busybox:1.30   app=counter-pod

#监控Pod
[root@xnode1 ~]# kubectl get pod -n dev -o wide -w
NAME           READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
pc-job-8j5kz   0/1     Pending   0          0s    <none>   <none>   <none>           <none>
pc-job-8j5kz   0/1     Pending   0          0s    <none>   xnode2   <none>           <none>
pc-job-8j5kz   0/1     ContainerCreating   0          0s    <none>   xnode2   <none>           <none>
pc-job-8j5kz   1/1     Running             0          2s    10.244.1.63   xnode2   <none>           <none>
pc-job-8j5kz   0/1     Completed           0          29s   10.244.1.63   xnode2   <none>           <none>
#修改pc-job.yaml
cat <<EOF > pc-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: pc-job
  namespace: dev
spec:
  manualSelector: true
  completions: 6 # 指定job需要成功运行Pods的次数。默认值: 1			==>添加
  parallelism: 3 # 指定job在任一时刻应该并发运行Pods的数量。默认值: 1	==>添加
  selector:
    matchLabels:
      app: counter-pod
  template:
    metadata:
      labels:
        app: counter-pod
    spec:
      restartPolicy: Never
      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 ;sleep 3;done"]
EOF

#再次观察Job和Pod
#发现Job每次运行3个Pod,总共执行了6个Pod
[root@xnode1 ~]# kubectl get job -n dev -o wide -w
NAME     COMPLETIONS   DURATION   AGE   CONTAINERS   IMAGES         SELECTOR
pc-job   0/6                      0s    counter      busybox:1.30   app=counter-pod
pc-job   0/6           0s         0s    counter      busybox:1.30   app=counter-pod
pc-job   1/6           31s        31s   counter      busybox:1.30   app=counter-pod
pc-job   2/6           32s        32s   counter      busybox:1.30   app=counter-pod
pc-job   3/6           32s        32s   counter      busybox:1.30   app=counter-pod
pc-job   4/6           60s        60s   counter      busybox:1.30   app=counter-pod
pc-job   5/6           62s        62s   counter      busybox:1.30   app=counter-pod
pc-job   6/6           62s        62s   counter      busybox:1.30   app=counter-pod

[root@xnode1 ~]# kubectl get pod -n dev -o wide -w
NAME           READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
pc-job-gxs4q   0/1     Pending   0          0s    <none>   <none>   <none>           <none>
pc-job-gxs4q   0/1     Pending   0          0s    <none>   xnode2   <none>           <none>
pc-job-cz7cw   0/1     Pending   0          0s    <none>   <none>   <none>           <none>
pc-job-9z6hk   0/1     Pending   0          0s    <none>   <none>   <none>           <none>
pc-job-cz7cw   0/1     Pending   0          0s    <none>   xnode2   <none>           <none>
pc-job-9z6hk   0/1     Pending   0          0s    <none>   xnode2   <none>           <none>
pc-job-gxs4q   0/1     ContainerCreating   0          0s    <none>   xnode2   <none>           <none>
pc-job-cz7cw   0/1     ContainerCreating   0          0s    <none>   xnode2   <none>           <none>
pc-job-9z6hk   0/1     ContainerCreating   0          0s    <none>   xnode2   <none>           <none>
pc-job-cz7cw   1/1     Running             0          5s    10.244.1.65   xnode2   <none>           <none>
pc-job-gxs4q   1/1     Running             0          5s    10.244.1.64   xnode2   <none>           <none>
pc-job-9z6hk   1/1     Running             0          5s    10.244.1.66   xnode2   <none>           <none>
pc-job-gxs4q   0/1     Completed           0          31s   10.244.1.64   xnode2   <none>           <none>
pc-job-5xp4q   0/1     Pending             0          0s    <none>        <none>   <none>           <none>
pc-job-5xp4q   0/1     Pending             0          0s    <none>        xnode2   <none>           <none>
pc-job-5xp4q   0/1     ContainerCreating   0          0s    <none>        xnode2   <none>           <none>
pc-job-9z6hk   0/1     Completed           0          32s   10.244.1.66   xnode2   <none>           <none>
pc-job-xqd8m   0/1     Pending             0          0s    <none>        <none>   <none>           <none>
pc-job-xqd8m   0/1     Pending             0          0s    <none>        xnode2   <none>           <none>
pc-job-xqd8m   0/1     ContainerCreating   0          0s    <none>        xnode2   <none>           <none>
pc-job-cz7cw   0/1     Completed           0          32s   10.244.1.65   xnode2   <none>           <none>
pc-job-v7msn   0/1     Pending             0          0s    <none>        <none>   <none>           <none>
pc-job-v7msn   0/1     Pending             0          0s    <none>        xnode2   <none>           <none>
pc-job-v7msn   0/1     ContainerCreating   0          0s    <none>        xnode2   <none>           <none>
pc-job-5xp4q   1/1     Running             0          2s    10.244.1.67   xnode2   <none>           <none>
pc-job-v7msn   1/1     Running             0          3s    10.244.1.69   xnode2   <none>           <none>
pc-job-xqd8m   1/1     Running             0          3s    10.244.1.68   xnode2   <none>           <none>
pc-job-5xp4q   0/1     Completed           0          29s   10.244.1.67   xnode2   <none>           <none>
pc-job-xqd8m   0/1     Completed           0          30s   10.244.1.68   xnode2   <none>           <none>
pc-job-v7msn   0/1     Completed           0          30s   10.244.1.69   xnode2   <none>           <none>

4、End 删除pc-job

[root@xnode1 ~]# kubectl delete -f pc-job.yaml 
job.batch "pc-job" deleted

(6)、CrontabJob(CJ)

CronJob控制器:

以Job控制器资源为管控对象,并借助它管理oid资源对象,Job控制器定义的作业任务在其控制器资源创建之后便会立即执行,但CronJob可以以类似于Linux操作系统的周期性任务作业计划的方式控制其运行时间点及重复运行的方式.也就是说,CronJob可以在特定的时间点(反复的)去运行job任务

在这里插入图片描述

1、CronJob资源清单文件:

apiVersion: batch/v1beta1 # 版本号
kind: CronJob # 类型       
metadata: # 元数据
  name: # rs名称 
  namespace: # 所属命名空间 
  labels: #标签
    controller: cronjob
spec: # 详情描述
  schedule: # cron格式的作业调度运行时间点,用于控制任务在什么时间执行
  concurrencyPolicy: # 并发执行策略,用于定义前一次作业运行尚未完成时是否以及如何运行后一次的作业
  failedJobHistoryLimit: # 为失败的任务执行保留的历史记录数,默认为1
  successfulJobHistoryLimit: # 为成功的任务执行保留的历史记录数,默认为3
  startingDeadlineSeconds: # 启动作业错误的超时时长
  jobTemplate: # job控制器模板,用于为cronjob控制器生成job对象;下面其实就是job的定义
    metadata:
    spec:
      completions: 1
      parallelism: 1
      activeDeadlineSeconds: 30
      backoffLimit: 6
      manualSelector: true
      selector:
        matchLabels:
          app: counter-pod
        matchExpressions: 规则
          - {key: app, operator: In, values: [counter-pod]}
      template:
        metadata:
          labels:
            app: counter-pod
        spec:
          restartPolicy: Never 
          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"]
需要重点解释的几个选项:
schedule: cron表达式,用于指定任务的执行时间
    */1    *      *    *     *
    <分钟> <小时> <日> <月份> <星期>

    分钟 值从 0 到 59.
    小时 值从 0 到 23.
    日 值从 1 到 31.
    月 值从 1 到 12.
    星期 值从 0 到 6, 0 代表星期日
    多个时间可以用逗号隔开; 范围可以用连字符给出;*可以作为通配符; /表示每...
concurrencyPolicy:
    Allow:   允许Jobs并发运行(默认)
    Forbid:  禁止并发运行,如果上一次运行尚未完成,则跳过下一次运行
    Replace: 替换,取消当前正在运行的作业并用新作业替换它

2、创建一个pc-cronjob.yaml

cat <<EOF > pc-cronjob.yaml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: pc-cronjob
  namespace: dev
  labels:
    controller: cronjob
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    metadata:
    spec:
      template:
        spec:
          restartPolicy: Never
          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 3;done"]
EOF

3、创建并查看

可以看到cronjob每隔30s就执行一次任务,pod也是30s就新建一次

#创建cronjob
[root@xnode1 ~]# kubectl create -f pc-cronjob.yaml 
cronjob.batch/pc-cronjob created

#查看cronjob
[root@xnode1 ~]# kubectl get cronjob -n dev -w
NAME         SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
pc-cronjob   */1 * * * *   False     0        <none>          0s
pc-cronjob   */1 * * * *   False     1        6s              42s
pc-cronjob   */1 * * * *   False     0        36s             72s
pc-cronjob   */1 * * * *   False     1        6s              102s
pc-cronjob   */1 * * * *   False     0        36s             2m12s

#查看job
[root@xnode1 ~]# kubectl get job -n dev -w 
NAME                    COMPLETIONS   DURATION   AGE
pc-cronjob-1661247480   0/1                      0s
pc-cronjob-1661247480   0/1           0s         0s
pc-cronjob-1661247480   1/1           30s        30s
pc-cronjob-1661247540   0/1                      0s
pc-cronjob-1661247540   0/1           0s         0s
pc-cronjob-1661247540   1/1           28s        28s

#查看pod
[root@xnode1 ~]# kubectl get pod -n dev -w
NAME                          READY   STATUS    RESTARTS   AGE
pc-cronjob-1661247480-lgtrk   1/1     Running   0          20s
pc-cronjob-1661247480-lgtrk   0/1     Completed   0          30s
pc-cronjob-1661247540-s5xkj   0/1     Pending     0          0s
pc-cronjob-1661247540-s5xkj   0/1     Pending     0          0s
pc-cronjob-1661247540-s5xkj   0/1     ContainerCreating   0          0s
pc-cronjob-1661247540-s5xkj   1/1     Running             0          2s
pc-cronjob-1661247540-s5xkj   0/1     Completed           0          28s

#删除cronjob
[root@xnode1 ~]# kubectl delete -f pc-cronjob.yaml 
cronjob.batch "pc-cronjob" deleted

十二、Service详解

Service介绍:

kubernetes中,pod是应用程序的载体,我们通过对pod的ip访问应用程序,但是pod的ip地址不是固定的,也就意味着不方便采用相同的pod得到ip对服务进行访问.

为了解决这个问题,kubernetes提供了Service资源,Service会对提供同一个服务的多个pod进行聚合,并且提供一个同一的入口地址.通过访问Services的入口地址就能访问到后面的Pod服务

在这里插入图片描述

Service在很多情况下只是一个概念,真正起作用的其实是 Kube-Proxy服务进程,每个Node节点上都运行着一个 Kube-Proxy服务进程,当创建Services的时候会通过 API-ServerEtcd写入创建的service的信息里,而 Kube-Proxy 会基于监听的机制发现这种Service的变动,然后 它会将最新的Service信息转换成对应的访问规则.

在这里插入图片描述

#10.244.0.29:8443是service提供的访问入口
#当访问这个入口的时候,可以发现后面有3个pod的服务在等待调用
# kube-proxy会基于rr(轮询)的策略,将请求分发到其中一个pod上去
# 这个规则会同时在集群内的所有节点上都生成,所以在任何一个节点上访问都可以。

[root@xnode1 ~]# ipvsadm -Ln | grep 10.244
  -> 10.244.0.29:8443             Masq    1      0          0         
  -> 10.244.0.29:8443             Masq    1      0          0         
  -> 10.244.0.29:8443             Masq    1      0          0         
  -> 10.244.0.29:8443             Masq    1      0          0         
  -> 10.244.0.29:8443             Masq    1      0          0         
  -> 10.244.0.29:8443             Masq    1      0          0         
  -> 10.244.0.29:8443             Masq    1      0          0         
  -> 10.244.0.29:8443             Masq    1      0          0         
  -> 10.244.0.27:53               Masq    1      0          0         
  -> 10.244.0.30:53               Masq    1      0          0         
  -> 10.244.0.27:9153             Masq    1      0          0         
  -> 10.244.0.30:9153             Masq    1      0          0         
  -> 10.244.0.29:8443             Masq    1      0          0         
  -> 10.244.0.28:8000             Masq    1      0          0         
TCP  10.244.0.0:32429 rr
  -> 10.244.0.29:8443             Masq    1      0          0         
TCP  10.244.0.0:32647 rr
TCP  10.244.0.1:32429 rr
  -> 10.244.0.29:8443             Masq    1      0          0         
TCP  10.244.0.1:32647 rr
  -> 10.244.0.29:8443             Masq    1      0          0         
  -> 10.244.0.27:53               Masq    1      0          0         
  -> 10.244.0.30:53               Masq    1      0          0   

(1)、Kube-Proxy的三种模式

Kube-Proxy目前支持三种模式:

在这个模式下Kube-Proxy会为每一个Service创建一个监听端口,发向Cluster Ip的请求被Iptables规则重定向到 Kube-proxy监听端口上, Kube-proxy根据 LB算法选择一个提供服务的Pod并和其建立连接,以将请求转发到Pod上.该模式下,Kube-proxy充当了一个四层负载均衡器的角色.由于 Kube-proxy运行在userspace中,在进行转发处理时会增加内核和用户之间的数据拷贝,虽然比较稳定,但是效率比较低.

在这里插入图片描述

iptables模式:

iptables模式下,kube-proxyservice后端的每个pod创建对应的iptables规则,直接向cluster IP的请求重定向到一个Pod IP.该模式下Kube-Proxy不承担四层负载均衡的角色,只负责创建iptables规则.该模式的优点是较 userspace模式效率更高,但不能提供灵活的LB策略,当后端Pod也不可用时也无法进行重试.

在这里插入图片描述

ipvs模式:

ipvs模式iptables类似, kube-proxy监控pod的变化并创建相应的 ipvs规则,ipvs

相对 iptables转发规则效率更高,除此之外,ipvs支持更多的 Lb算法.

在这里插入图片描述

(2)、开启Ipvs

开启ipvs:

①.修改kube-proxy配置文件

②.重启kube-proxy

[root@xnode1 ~]# kubectl edit cm kube-proxy -n kube-system

     32     ipvs:
     33       excludeCIDRs: null
     34       minSyncPeriod: 0s
     35       scheduler: ""
     36       syncPeriod: 30s
     37     kind: KubeProxyConfiguration
     38     metricsBindAddress: 127.0.0.1:10249
     39     mode: "ipvs"				==>添加ipvs
     40     nodePortAddresses: null
     41     oomScoreAdj: -999
     42     portRange: ""
     43     resourceContainer: /kube-proxy
     44     udpIdleTimeout: 250ms
     
[root@xnode1 ~]# kubectl get pod -n kube-system | grep kube-proxy | awk '{system("kubectl delete pod "$1" -n kube-system")}'
pod "kube-proxy-q7z99" deleted
pod "kube-proxy-vw9wf" deleted

测试ipvs:

①.由于已经通过了configmap修改了kube-proxy的配置,素有后期增加了节点会直接使用ipvs模式,我们这里查看一下日志

#查看一下kube-proxy容器的详细信息

[root@xnode1 ~]# kubectl describe pod -n kube-system kube-proxy
Name:               kube-proxy-ptlm8
Namespace:          kube-system
Priority:           2000001000
PriorityClassName:  system-node-critical
Node:               xnode1/10.0.0.30
Start Time:         Wed, 17 Aug 2022 03:45:04 -0400
Labels:             controller-revision-hash=5f46cbf776
                    k8s-app=kube-proxy
                    pod-template-generation=1
Annotations:        <none>
Status:             Running
IP:                 10.0.0.30
Controlled By:      DaemonSet/kube-proxy
Containers:
  kube-proxy:
    Container ID:  docker://b7fc4a3b55063900c62415803b30097342e29a2dadd26277c7aac238cb49de55
    Image:         registry.aliyuncs.com/google_containers/kube-proxy:v1.14.1
    Image ID:      docker-pullable://registry.aliyuncs.com/google_containers/kube-proxy@sha256:44af2833c6cbd9a7fc2e9d2f5244a39dfd2e31ad91bf9d4b7d810678db738ee9
    Port:          <none>
    Host Port:     <none>
    
#查看kube-proxy-ptlm8这个pod的日志信息
[root@xnode1 ~]# kubectl logs kube-proxy-ptlm8 -n kube-system 
I0817 07:45:05.902030       1 server_others.go:177] Using ipvs Proxier.		==>可以看到这里已经在使用ipvs
W0817 07:45:05.902743       1 proxier.go:381] IPVS scheduler not specified, use rr by default
I0817 07:45:05.902982       1 server.go:555] Version: v1.14.1
I0817 07:45:05.922512       1 conntrack.go:52] Setting nf_conntrack_max to 131072
I0817 07:45:05.923301       1 config.go:102] Starting endpoints config controller
I0817 07:45:05.923338       1 controller_utils.go:1027] Waiting for caches to sync for endpoints config controller
I0817 07:45:05.923354       1 config.go:202] Starting service config controller
I0817 07:45:05.923416       1 controller_utils.go:1027] Waiting for caches to sync for service config controller
I0817 07:45:06.023978       1 controller_utils.go:1034] Caches are synced for endpoints config controller
I0817 07:45:06.024736       1 controller_utils.go:1034] Caches are synced for service config controller

(3)、service类型

  • Service资源清单文件:
kind: Service  # 资源类型
apiVersion: v1  # 资源版本
metadata: # 元数据
  name: service # 资源名称
  namespace: dev # 命名空间
spec: # 描述
  selector: # 标签选择器,用于确定当前service代理哪些pod
    app: nginx
  type: # Service类型,指定service的访问方式
  clusterIP:  # 虚拟服务的ip地址
  sessionAffinity: # session亲和性,支持ClientIP、None两个选项
  ports: # 端口信息
    - protocol: TCP 
      port: 3017  # service端口
      targetPort: 5003 # pod端口
      nodePort: 31122 # 主机端口

**Cluster IP:**默认值,它是Kubernetes系统自动分配的虚拟Ip,只能在集群内部访问

**NodePort:**将Service通过指定的Node上的端口暴露给外部,通过此方法,就可以在集群外部访问服务

**LoadBalancer:**使用外接负载均衡器完成到服务的负载分发,注意此模式需要外部云环境支持

**ExternalName:**把集群外部的服务引入集群内部,直接使用

(4)、service的使用

实验环境准备:

在使用service之前,首先利用Deployment创建出3个Pod,注意要为pod设置,app=nginx-pod的标签

  • 创建deployment.yaml文件:
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment      
metadata:
  name: pc-deployment
  namespace: dev
spec: 
  replicas: 3
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        ports:
        - containerPort: 80
EOF
#创建pod
[root@xnode1 ~]# kubectl create -f deployment.yaml 
deployment.apps/pc-deployment created

#查看

[root@xnode1 ~]# kubectl get pod -n dev -o wide
NAME                           READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
pc-deployment-d46fb9b9-5znzj   1/1     Running   0          51s   10.244.2.10   xnode3   <none>           <none>
pc-deployment-d46fb9b9-bl89n   1/1     Running   0          51s   10.244.1.76   xnode2   <none>           <none>
pc-deployment-d46fb9b9-q5n7x   1/1     Running   0          51s   10.244.1.77   xnode2   <none>           <none>

#进入pod,修改nginx的访问页面
[root@xnode1 ~]# kubectl exec -it pc-deployment-d46fb9b9-5znzj -n dev /bin/sh
# echo "10.244.2.10" > /usr/share/nginx/html/index.html
# exit
[root@xnode1 ~]# kubectl exec -it pc-deployment-d46fb9b9-bl89n -n dev /bin/sh
# echo "10.244.1.76" > /usr/share/nginx/html/index.html
# exit
[root@xnode1 ~]# kubectl exec -it pc-deployment-d46fb9b9-q5n7x -n dev /bin/sh
# echo "10.244.1.77" > /usr/share/nginx/html/index.html
# exit

#访问测试
[root@xnode1 ~]# curl 10.244.2.10:80
10.244.2.10
[root@xnode1 ~]# curl 10.244.1.76:80
10.244.1.76
[root@xnode1 ~]# curl 10.244.1.77:80
10.244.1.77

(5)、ClusterIP类型的Services

  • 创建service-cluster.yaml文件
cat <<EOF > service-cluster.yaml
apiVersion: v1
kind: Service
metadata:
  name: service-clusterip
  namespace: dev
spec:
  selector:
    app: nginx-pod
  clusterIP: 10.97.97.97 # service的ip地址,如果不写,默认会生成一个
  type: ClusterIP
  ports:
  - port: 80  # Service端口       
    targetPort: 80 # pod端口
EOF
  • 创建ClusterIP:
#创建ClusterIP
[root@xnode1 ~]# kubectl create -f service-cluster.yaml 
service/service-clusterip created

#查看
[root@xnode1 ~]# kubectl get service -n dev -o wide
NAME                TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE    SELECTOR
nginx               NodePort    10.106.191.78   <none>        80:32647/TCP   2d5h   run=nginx
service-clusterip   ClusterIP   10.97.97.97     <none>        80/TCP         56s    app=nginx-pod

#查看clusterIP的详细信息
[root@xnode1 ~]# kubectl describe service -n dev service-clusterip 
Name:              service-clusterip
Namespace:         dev
Labels:            <none>
Annotations:       <none>
Selector:          app=nginx-pod
Type:              ClusterIP
IP:                10.97.97.97
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.1.78:80,10.244.1.79:80,10.244.2.11:80
Session Affinity:  None
Events:            <none>

#查看ipvs的映射规则
[root@xnode1 ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
  
TCP  10.97.97.97:80 rr
  -> 10.244.1.78:80               Masq    1      0          0         
  -> 10.244.1.79:80               Masq    1      0          0         
  -> 10.244.2.11:80               Masq    1      0          0         
  
#访问测试
[root@xnode1 ~]# curl 10.97.97.97:80
10.244.1.79
  • Endpoint:

Endpoint :

①.Endpoint是kubernetes中的一个资源对象,存储在etcd中,存储在ectd中,用来记录一个 service对应的所有pod的访问地址,它是根据 service配置文件中的selector描述产生的.

②.一个 service 由一组Pod组成,这些Pod通过 Endpoints暴露出来, Endpoint是实现实际服务的端点集合.换句话说,service和pod之间的联系是通过 Endpoint实现的

在这里插入图片描述

在这里插入图片描述

  • 负载分发策略:

对service的访问被分发到了后端的Pod上去,目前kubernetes提供了两种负载分发策略

  • 如果不定义,默认使用 kube-proxy的策略,比如说 轮询、随机
  • 基于客户端地址的回话保持模式,即来自同一个客户端发起的所有请求都会转发到固定的一个Pod上,此模式可以使在spec中添加sessionAffinity:ClientIP选项
#修改service-cluster.yaml文件
apiVersion: v1
kind: Service
metadata:
  name: service-clusterip	==>添加此行
  namespace: dev
spec:
  sessionAffinity: ClientIP
  selector:
    app: nginx-pod
  clusterIP: 10.97.97.97 # service的ip地址,如果不写,默认会生成一个
  type: ClusterIP
  ports:
  - port: 80  # Service端口       
    targetPort: 80 # pod端口
    
#删除之前创建的clusterip service服务
[root@xnode1 ~]# kubectl delete -f service-cluster.yaml 
service "service-clusterip" deleted

#启动新的服务
[root@xnode1 ~]# kubectl create -f service-cluster.yaml 
service/service-clusterip created

#查看ipvs的映射规则: 【persistent 代表持久】
[root@xnode1 ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn

TCP  10.97.97.97:80 rr persistent 10800
  -> 10.244.1.78:80               Masq    1      0          0         
  -> 10.244.1.79:80               Masq    1      0          0         
  -> 10.244.2.11:80               Masq    1      0          0   
  
#循环访问测试:发现这个时候的访问都是固定的一个Pod
[root@xnode1 ~]# while true;do curl 10.97.97.97; sleep 5; done;
10.244.2.11
10.244.2.11
10.244.2.11
10.244.2.11
10.244.2.11
10.244.2.11

#删除service
[root@xnode1 ~]# kubectl delete -f service-cluster.yaml 
service "service-clusterip" deleted

(6)、HeadLiness类型的Service

HeadLiness Service:

在某些场景中,开发人员可能不想使用Service提供的负载均衡功能,而希望自己来控制负载均衡策略,针对这种情况,kubernetes提供了HeadLiness Service,这类Service不会分配ClusterIP,如果想要访问service,只能通过service的域名进行查询.

  • 创建service-headliness.yaml
cat <<EOF > service-headliness.yaml
apiVersion: v1
kind: Service
metadata:
  name: service-headliness
  namespace: dev
spec:
  selector:
    app: nginx-pod
  clusterIP: None # 将clusterIP设置为None,即可创建headliness Service
  type: ClusterIP
  ports:
  - port: 80    
    targetPort: 80
EOF
  • 创建服务并查看
#创建service
[root@xnode1 ~]# kubectl create -f service-headliness.yaml 
service/service-headliness created

#获取service,发现CLUSTER-IP未分配
[root@xnode1 ~]# kubectl get svc -n dev service-headliness -o wide
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE   SELECTOR
service-headliness   ClusterIP   None         <none>        80/TCP    93s   app=nginx-pod

#查看service:service-headliness的详细信息
[root@xnode1 ~]# kubectl describe svc -n dev service-headliness 
Name:              service-headliness
Namespace:         dev
Labels:            <none>
Annotations:       <none>
Selector:          app=nginx-pod
Type:              ClusterIP
IP:                None
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.1.78:80,10.244.1.79:80,10.244.2.11:80
Session Affinity:  None
Events:            <none>

#查看pod[root@xnode1 ~]# kubectl get pod -n dev
NAME                           READY   STATUS    RESTARTS   AGE
pc-deployment-d46fb9b9-5znzj   1/1     Running   1          8h
pc-deployment-d46fb9b9-bl89n   1/1     Running   1          8h
pc-deployment-d46fb9b9-q5n7x   1/1     Running   1          8h

#进入一个pod查看域名解析情况
[root@xnode1 ~]# kubectl exec -it -n dev pc-deployment-d46fb9b9-5znzj /bin/sh
# grep ^search /etc/resolv.conf
search dev.svc.cluster.local svc.cluster.local cluster.local
# grep ^nameserver /etc/resolv.conf
nameserver 10.96.0.10

#dig 'pod:cat /etc/resolv.conf ^nameserver'、'service名字'、'命名空间'、'pod:cat /etc/resolv.conf ^search'
[root@xnode1 ~]# dig @10.96.0.10 serivce-headliness.dev.svc.cluster.local

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7 <<>> @10.96.0.10 serivce-headliness.dev.svc.cluster.local
; (1 server found)
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 62821
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;serivce-headliness.dev.svc.cluster.local. IN A

;; AUTHORITY SECTION:
cluster.local.          5       IN      SOA     ns.dns.cluster.local. hostmaster.cluster.local. 1661424260 7200 1800 86400 5

;; Query time: 16 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Thu Aug 25 06:52:36 EDT 2022
;; MSG SIZE  rcvd: 162

(7)、NodePort类型的Service

NodePort:

在之前的样例中,创建的service的IP地址只有集群内部才可以访问,如果希望service暴露给集群外部使用,那么就要使用到另外一种类型的service,称为NodePort类型.NodePort的工作原理其实就是 将service的端口映射到Node的一个端口上,然后就可以通过NodeIP:NodePort来访问Service了.

在这里插入图片描述

  • 创建一个service-nodeport.yaml文件
cat <<EOF > service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: service-nodeport
  namespace: dev
spec:
  selector:
    app: nginx-pod
  type: NodePort # service类型
  ports:
  - port: 80
    nodePort: 30002 # 指定绑定的node的端口(默认的取值范围是:30000-32767), 如果不指定,会默认分配
    targetPort: 80
EOF
  • 创建service:nodeport
#创建NodePort
[root@xnode1 ~]# kubectl create -f service-nodeport.yaml 
service/service-nodeport created

#查看service服务
[root@xnode1 ~]# kubectl get svc -n dev -o wide
NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE    SELECTOR
service-headliness   ClusterIP   None           <none>        80/TCP         38m    app=nginx-pod
service-nodeport     NodePort    10.97.55.214   <none>        80:30002/TCP   113s   app=nginx-pod

#通过电脑浏览器访问集群中的nodeip的30002端口访问pod
[root@xnode1 ~]# curl 10.0.0.30:30002
10.244.2.11

在这里插入图片描述

(8)、LoadBalancer类型的Service

LoadBalancer:

LoadBalancerNodePort很相似,目的都是向外部暴露一个端口,区别在于 LoadBalancer会在集群的外部再来做一个负载均衡设备,而这个设备需要外部环境支持的,外部服务发送到这个设备上的请求,会被设备负载之后转发到集群中.

在这里插入图片描述

(9)、ExternalName类型的Service

ExternalName:

ExternalName类型的 Service用于引入集群外部的服务,它通过 externalName属性指定外部一个服务的地址,然后再集群内部访问此service就可以访问到外部的服务了.

在这里插入图片描述

  • 创建一个service-externalname.yaml
cat <<EOF > service-external.yaml
apiVersion: v1
kind: Service
metadata:
  name: service-externalname
  namespace: dev
spec:
  type: ExternalName # service类型
  externalName: www.baidu.com  #改成ip地址也可以
EOF
  • 创建一个service:
[root@xnode1 ~]# kubectl create -f service-external.yaml 
service/service-externalname created

#查看svc
[root@xnode1 ~]# kubectl get svc -n dev -o wide
NAME                   TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE   SELECTOR
service-externalname   ExternalName   <none>         www.baidu.com   <none>         35s   <none>

#查看详细信息
[root@xnode1 ~]# kubectl describe svc -n dev service-externalname 
Name:              service-externalname
Namespace:         dev
Labels:            <none>
Annotations:       <none>
Selector:          <none>
Type:              ExternalName
IP:                
External Name:     www.baidu.com
Session Affinity:  None
Events:            <none>

#解析域名
[root@xnode1 ~]# dig @10.96.0.10 service-externalname.dev.svc.cluster.local

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7 <<>> @10.96.0.10 service-externalname.dev.svc.cluster.local
; (1 server found)
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50647
;; flags: qr aa rd; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;service-externalname.dev.svc.cluster.local. IN A

;; ANSWER SECTION:
service-externalname.dev.svc.cluster.local. 5 IN CNAME www.baidu.com.
www.baidu.com.          5       IN      CNAME   www.a.shifen.com.
www.a.shifen.com.       5       IN      A       220.181.38.149
www.a.shifen.com.       5       IN      A       220.181.38.150

;; Query time: 56 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Thu Aug 25 22:19:37 EDT 2022
;; MSG SIZE  rcvd: 247

(10)、Ingress介绍

在前面的提到了,service对集群之外暴露服务的主要两种方式: NodePortLoadBalancer,但是这两种方式都有一定的缺点:

  • NodePort方式的缺点是会占用很多的集群机器的端口,那么当集群服务变多的时候,这个缺点就会愈发明显.
  • LB 的方式的缺点是每个service需要一个LB,浪费,麻烦,并且需要kubernetes之外设备的支持

基于这种现状kubernetes提供了Ingress资源对象,Ingress只需要一个 NodePort或者一个 LB就可以满足暴露多个service的需求

工作流程:

在这里插入图片描述

Ingress:

Ingress相当于一个7层负载均衡器,是kubernetes对反向代理的一个抽象,它的工作原理类似于Nginx,可以理解成在 Ingress里面建立诸多的映射规则,Ingress Controller通过监听这些配置规则并转换成Nginx的反向代理配置,然后对外提供服务.

  • **Ingress:**kubernetes中的一个对象,作用是定义四请求如何转发到service的规则
  • **Ingress controller:**具体实现反向代理以及负载均衡的程序,对Ingress定义的规则进行解析,根据配置的规则来实现请求转发,实现的方式很多,比如Nginx,Contour,Haproxy… …

Ingress(以Nginx为例)的工作原理:

  • 用户编写Ingress规则,说明哪个域名对应的kubernetes集群中的哪个service
  • Ingress controller动态感知 Ingress服务规则的变化,然后生成一段对应的Nginx反向代理配置
  • Ingress controller将会生成的Nginx配置写入到一个运行着的Nginx服务中,并动态更新
  • 到了这里,真正意义上工作的就是一个Nginx了,内部配置了用户定义请求转发规则

在这里插入图片描述

(11)、Ingress的使用

  • 1.环境准备:
[root@xnode1 ~]# mkdir ingress-controller
[root@xnode1 ~]# wget -P ingress-controller/ https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
[root@xnode1 ~]# wget -P ingress-controller/ https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml

# 创建ingress-nginx
[root@xnode1 ingress-controller]# kubectl apply -f ./
namespace/ingress-nginx created
configmap/nginx-configuration created
configmap/tcp-services created
configmap/udp-services created
serviceaccount/nginx-ingress-serviceaccount created
clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created
role.rbac.authorization.k8s.io/nginx-ingress-role created
rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created
deployment.apps/nginx-ingress-controller created
limitrange/ingress-nginx created
service/ingress-nginx created

# 查看pod
[root@xnode1 ingress-controller]# kubectl get pod -n ingress-nginx
NAME                                        READY   STATUS    RESTARTS   AGE
nginx-ingress-controller-767bbbd54f-rn5n2   1/1     Running   0          97s

# 查看service
[root@xnode1 ingress-controller]# kubectl get svc -n ingress-nginx 
NAME            TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx   NodePort   10.110.182.175   <none>        80:32599/TCP,443:32410/TCP   26s
  • 2.准备service和pod

在这里插入图片描述

#创建tomcat-nginx. yaml
cat <<EOF > tomcat-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        ports:
        - containerPort: 80

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: tomcat-pod
  template:
    metadata:
      labels:
        app: tomcat-pod
    spec:
      containers:
      - name: tomcat
        image: tomcat:8.5-jre10-slim
        ports:
        - containerPort: 8080

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: dev
spec:
  selector:
    app: nginx-pod
  clusterIP: None
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 80

---

apiVersion: v1
kind: Service
metadata:
  name: tomcat-service
  namespace: dev
spec:
  selector:
    app: tomcat-pod
  clusterIP: None
  type: ClusterIP
  ports:
  - port: 8080
    targetPort: 8080
EOF

#创建
[root@xnode1 ~]# kubectl create -f tomcat-nginx.yaml 
deployment.apps/nginx-deployment created
deployment.apps/tomcat-deployment created
service/nginx-service created
service/tomcat-service created

#查看
[root@xnode1 ~]# kubectl get svc -n dev 
NAME             TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
nginx-service    ClusterIP   None         <none>        80/TCP     29s
tomcat-service   ClusterIP   None         <none>        8080/TCP   29s
  • 3.http的创建
#创建ingress-http.yaml
cat <<EOF > ingress-http.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-http
  namespace: dev
spec:
  rules:
  - host: nginx.itheima.com
    http:
      paths:
      - path: /
        backend:
          serviceName: nginx-service
          servicePort: 80
  - host: tomcat.itheima.com
    http:
      paths:
      - path: /
        backend:
          serviceName: tomcat-service
          servicePort: 8080
EOF
#创建
[root@xnode1 ~]# kubectl create -f ingress-http.yaml 
ingress.extensions/ingress-http created

#查看
[root@xnode1 ~]# kubectl get ingresses ingress-http -n dev 
NAME           HOSTS                                  ADDRESS   PORTS   AGE
ingress-http   nginx.itheima.com,tomcat.itheima.com             80      25s

#查看http服务的详情
[root@xnode1 ~]# kubectl describe ingresses ingress-http -n dev 
... ...

Rules:
  Host                Path  Backends
  ----                ----  --------
  nginx.itheima.com   
                      /   nginx-service:80 (10.244.1.91:80,10.244.1.92:80,10.244.2.14:80)
  tomcat.itheima.com  
                      /   tomcat-service:8080 (10.244.1.89:8080,10.244.1.90:8080,10.244.2.15:8080)
... ...

#修改Windows目录:C:\Windows\System32\drivers\etc下的hosts文件,添加域名映射
10.0.0.30 nginx.itheima.com
10.0.0.30 tomcat.itheima.com

使用主机访问http://nginx.itheima.com:31546/

在这里插入图片描述

访问 http://tomcat.itheima.com:31546/

在这里插入图片描述

  • 4.https代理:

  • 创建证书和秘钥

[root@xnode1 ~]# openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/C=CN/ST=BJ/L=BJ/O=nginx/CN=itheima.com"
Generating a 2048 bit RSA private key
............+++
..................+++
writing new private key to 'tls.key'
-----

[root@xnode1 ~]# kubectl create secret tls tls-secret --key tls.key --cert tls.crt
secret/tls-secret created
  • 创建ingress-https.yaml
cat <<EOF > ingress-https.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-https
  namespace: dev
spec:
  tls:
    - hosts:
      - nginx.itheima.com
      - tomcat.itheima.com
      secretName: tls-secret # 指定秘钥
  rules:
  - host: nginx.itheima.com
    http:
      paths:
      - path: /
        backend:
          serviceName: nginx-service
          servicePort: 80
  - host: tomcat.itheima.com
    http:
      paths:
      - path: /
        backend:
          serviceName: tomcat-service
          servicePort: 8080
EOF
#创建
[root@xnode1 ~]# kubectl create -f ingress-https.yaml 
ingress.extensions/ingress-https created

#查看
[root@xnode1 ~]# kubectl get ingresses ingress-https -n dev 
NAME            HOSTS                                  ADDRESS         PORTS     AGE
ingress-https   nginx.itheima.com,tomcat.itheima.com   10.102.125.70   80, 443   13s

#查看https的详细信息
[root@xnode1 ~]# kubectl describe ingresses ingress-https -n dev
...
TLS:
  tls-secret terminates nginx.itheima.com,tomcat.itheima.com
Rules:
  Host                Path  Backends
  ----                ----  --------
  nginx.itheima.com   
                      /   nginx-service:80 (10.244.1.91:80,10.244.1.92:80,10.244.2.14:80)
  tomcat.itheima.com  
                      /   tomcat-service:8080 (10.244.1.89:8080,10.244.1.90:8080,10.244.2.15:8080)
...

#通过浏览器访问 https://tomcat.itheima.com:31034/ https://nginx.itheima.com:31034/

十三、数据存储

在前面已经提到,容器的生命周期可能很短,会被频繁地创建和销毁。那么容器在销毁时,保存在容器中的数据也会被清除。这种结果对用户来说,在某些情况下是不乐意看到的。为了持久化保存容器的数据,kubernetes引入了Volume的概念。

Volume:

Volume是Pod中能够被多个容器访问的共享目录,它被定义在pod上,然后被一个Pod里的多个容器挂载到具体的文件目录下,kubernetes通过 Volume实现同一个pod中不同容器之间的数据共享以及数据化持久化存储, Volume的生命容器不与Pod中单个容器的生命周期相关,当容器终止或者重启时, Volume中的数据也不会丢失.

kubernetes的 Volume支持多种类型,常见的有下面几个:

  • 简单存储:EmptyDir、HostPath、NFS
  • 高级存储:PV、PVC
  • 配置存储:ConfigMap、Secret

(1)、EmptyDir

EmptyDir:

EmptyDir是在pod被分配到Node时创建的,它的初始内容为空,并且不误指定宿主机上对应的目录文件,因为kubernetes会自动分配一个目录,当pod销毁时, EmptyDir中的数据也会被永久删除, EmptyDir用途如下.

  • 临时空间,例如用于某些应用程序运行时所需的临时目录,且无需永久保留,作为容器之间共享目录进行的数据存储可以使用 EmptyDir
  • 一个容器需要从另一个容器中获取数据的目录(多容器共享目录)

在一个Pod中准备两个容器nginx和busybox,然后声明一个Volume分别挂在到两个容器的目录中,然后nginx容器负责向Volume中写日志,busybox中通过命令将日志内容读到控制台。

在这里插入图片描述

  • 创建一个volume-emptydir.yaml
cat <<EOF > volume-emptydir.yaml
apiVersion: v1
kind: Pod
metadata:
  name: volume-emptydir
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports:
    - containerPort: 80
    volumeMounts:  # 将logs-volume挂在到nginx容器中,对应的目录为 /var/log/nginx
    - name: logs-volume
      mountPath: /var/log/nginx
  - name: busybox
    image: busybox:1.30
    command: ["/bin/sh","-c","tail -f /logs/access.log"] # 初始命令,动态读取指定文件中内容
    volumeMounts:  # 将logs-volume 挂在到busybox容器中,对应的目录为 /logs
    - name: logs-volume
      mountPath: /logs
  volumes: # 声明volume, name为logs-volume,类型为emptyDir
  - name: logs-volume
    emptyDir: {}
EOF
#创建pod
[root@xnode1 ~]# kubectl create -f volume-emptydir.yaml 
pod/volume-emptydir created

#查看
[root@xnode1 ~]# kubectl get pods -n dev volume-emptydir -o wide
NAME              READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
volume-emptydir   2/2     Running   0          38s   10.244.2.18   xnode3   <none>           <none>

#通过podip访问nginx
[root@xnode1 ~]# curl 10.244.2.18:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body> 
</html>

#通过kubectl logs命令查看指定容器的标准输出
[root@xnode1 ~]# kubectl logs -f -n dev volume-emptydir -c busybox
10.244.0.0 - - [30/Aug/2022:16:30:33 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"

(2)、HostPath

HostPath:

HostPath就是将Node主机中一个实际目录挂在Pod中,以供容器使用,这样的设计就可以保证Pod销毁但是数据依旧可以存在于Node主机上

和前面讲过的 EmptyDir不同的是, EmptyDir中的数据不会持久化,它会随着Pod的结束而销毁.

在这里插入图片描述

  • 创建一个volume-hostpath.yaml文件
cat <<EOF > volume-hostpath.yaml
apiVersion: v1
kind: Pod
metadata:
  name: volume-hostpath
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports:
    - containerPort: 80
    volumeMounts:
    - name: logs-volume
      mountPath: /var/log/nginx
  - name: busybox
    image: busybox:1.30
    command: ["/bin/sh","-c","tail -f /logs/access.log"]
    volumeMounts:
    - name: logs-volume
      mountPath: /logs
  volumes:
  - name: logs-volume
    hostPath: 
      path: /root/logs
      type: DirectoryOrCreate  # 目录存在就使用,不存在就先创建后使用
EOF

关于 Type的说明:

  • DirectoryOrCreate:目录存在就使用,不存在就先创建后使用
  • **Directory:**目录必须存在
  • **FileOrCreate:**文件存在就使用,不存在就先创建后使用
  • **File:**文件必须存在
  • **Socket:**Unix套接字必须存在
  • **CharDevice:**字符设备必须存在
  • **BlockDevice:**块设备必须存在
#创建pod
[root@xnode1 ~]# kubectl create -f volume-hostpath.yaml 
pod/volume-hostpath created

#查看pod
[root@xnode1 ~]# kubectl get pods -n dev volume-hostpath -o wide
NAME              READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATES
volume-hostpath   2/2     Running   0          20s   10.244.1.101   xnode2   <none>           <none>

#访问nginx
[root@xnode1 ~]# curl 10.244.1.101:80
... ...

#查看xnode2节点的日志文件
[root@xnode2 ~]# cat /root/logs/access.log 
10.244.0.0 - - [30/Aug/2022:08:11:20 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"

(3)、NFS

NFS:

NFS是一个网络文件存储系统,可以搭建一台NFS服务器,然后将Pod中的存储直接连接到NFS系统上,这样的话,无论Pod在节点上怎么转移,只要Node和NFS的对接没有问题,数据就可以成功访问.

HostPath可以解决数据持久化的问题,但是一旦Node节点故障,Pod如果转移到了其它节点,又会出现问题,此时需要准备单独的网络存储系统,比如常用的NFSCIFS

在这里插入图片描述

a)、准备搭建NFS服务,这里选择在master主节点上部署nfs服务

#安装nfs服务
[root@xnode1 ~]# yum install nfs-utils.x86_64 -y

#创建一个共享目录
[root@xnode1 ~]# mkdir /root/data/nfs -pv

#将共享目录以读写权限暴露给10.0.0.0/24网段下的所有主机
[root@xnode1 ~]# echo "/root/data/nfs/ 10.0.0.0/24(rw,no_root_squash)" >> /etc/exports

[root@xnode1 ~]# tail -1 /etc/exports
/root/data/nfs/ 10.0.0.0/24(rw,no_root_squash)

#启动nfs服务
[root@xnode1 ~]# systemctl start nfs
[root@xnode1 ~]# systemctl enable nfs

b)、在xnode2、xnode3节点上安装nfs

#安装nfs服务,不要启动
yum install nfs-utils.x86_64 -y

c)、编写volume-nfs.yaml

cat <<EOF > volume-nfs.yaml
apiVersion: v1
kind: Pod
metadata:
  name: volume-nfs
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports:
    - containerPort: 80
    volumeMounts:
    - name: logs-volume
      mountPath: /var/log/nginx
  - name: busybox
    image: busybox:1.30
    command: ["/bin/sh","-c","tail -f /logs/access.log"] 
    volumeMounts:
    - name: logs-volume
      mountPath: /logs
  volumes:
  - name: logs-volume
    nfs:
      server: 10.0.0.30  #nfs服务器地址
      path: /root/data/nfs #共享文件路径
EOF

d)、运行Pod查看运行结果

#创建Pod
[root@xnode1 ~]# kubectl create -f volume-nfs.yaml 
pod/volume-nfs created

#查看Pod
[root@xnode1 ~]# kubectl get pod -n dev -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATES
volume-nfs   2/2     Running   0          12s   10.244.1.102   xnode2   <none>           <none>

#访问nginx服务
[root@xnode1 nfs]# curl 10.244.1.102:80
...

#查看nfs服务器共享目录及日志
[root@xnode1 ~]# cd /root/data/nfs/
[root@xnode1 nfs]# ls
access.log  error.log

[root@xnode1 nfs]# cat access.log 
10.244.0.0 - - [30/Aug/2022:08:53:57 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"

(4)、高级存储

前面以及学习了使用NFS提供的存储,此时就要求用户会搭建NFS系统,并且会在yaml配置nfs,由于kubernetes支持的存储系统有很多,要求客户全都掌握,显然不现实,为了能够方便用户的使用,kubernetes推出了PVPVC这两种资源对象。

PV:

**PV(Persistent Volume)**是持久卷的意思,是对底层共享存储的一种抽象,一般情况下 PV由kubernetes管理员进行创建和配置,它与底层具体的共享存储技术相关,并通过插件完成共享存储的对接

PVC(Persistent Volume Claim):是持久卷声明的意思,是用户对存储需求的一种声明,换句话说PVC其实就是用户向kubernetes系统发出的一种资源需求申请.

在这里插入图片描述

使用了 PVPVC之后,工作可以得到进一步的细分

  • 存储: 存储工程师维护
  • **PV:**kubernetes管理员负责维护
  • **PVC:**kubernetes用户维护

(5)、PV

PV是存储资源的抽象,下面是资源清单文件

apiVersion: v1  
kind: PersistentVolume
metadata:
  name: pv2
spec:
  nfs: # 存储类型,与底层真正存储对应
  capacity:  # 存储能力,目前只支持存储空间的设置
    storage: 2Gi
  accessModes:  # 访问模式
  storageClassName: # 存储类别
  persistentVolumeReclaimPolicy: # 回收策略

PV 的关键配置参数说明:

  • 存储类型

    底层实际存储的类型,kubernetes支持多种存储类型,每种存储类型的配置都有所差异

  • 存储能力(capacity)

目前只支持存储空间的设置( storage=1Gi ),不过未来可能会加入IOPS、吞吐量等指标的配置

  • 访问模式(accessModes)

    用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:

    • ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
    • ReadOnlyMany(ROX): 只读权限,可以被多个节点挂载
    • ReadWriteMany(RWX):读写权限,可以被多个节点挂载

    需要注意的是,底层不同的存储类型可能支持的访问模式不同

  • 回收策略(persistentVolumeReclaimPolicy)

    当PV不再被使用了之后,对其的处理方式。目前支持三种策略:

    • Retain (保留) 保留数据,需要管理员手工清理数据
    • Recycle(回收) 清除 PV 中的数据,效果相当于执行 rm -rf /thevolume/*
    • Delete (删除) 与 PV 相连的后端存储完成 volume 的删除操作,当然这常见于云服务商的存储服务

    需要注意的是,底层不同的存储类型可能支持的回收策略不同

  • 存储类别

    PV可以通过storageClassName参数指定一个存储类别

    • 具有特定类别的PV只能与请求了该类别的PVC进行绑定
    • 未设定类别的PV则只能与不请求任何类别的PVC进行绑定
  • 状态(status)

    一个 PV 的生命周期中,可能会处于4中不同的阶段:

    • Available(可用): 表示可用状态,还未被任何 PVC 绑定
    • Bound(已绑定): 表示 PV 已经被 PVC 绑定
    • Released(已释放): 表示 PVC 被删除,但是资源还未被集群重新声明
    • Failed(失败): 表示该 PV 的自动回收失败
  • 创建一个PV

使用NFS作为存储,来演示PV的使用,创建3个PV,对应的NFS中的3个暴露的路径)

a)、准备NFS环境

#创建目录
[root@xnode1 ~]# mkdir /root/data/{pv1,pv2,pv3} -pv

#暴露服务
[root@xnode1 ~]# cat <<EOF >> /etc/exports
/root/data/pv1     10.0.0.0/24(rw,no_root_squash)
/root/data/pv2     10.0.0.0/24(rw,no_root_squash)
/root/data/pv3     10.0.0.0/24(rw,no_root_squash)
EOF

#重启服务
[root@xnode1 ~]# systemctl restart nfs

b)、创建pv.yaml

cat <<EOF > pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name:  pv1
spec:
  capacity: 
    storage: 1Gi
  accessModes:
  - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /root/data/pv1
    server: 10.0.0.30

---

apiVersion: v1
kind: PersistentVolume
metadata:
  name:  pv2
spec:
  capacity: 
    storage: 2Gi
  accessModes:
  - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /root/data/pv2
    server: 10.0.0.30
    
---

apiVersion: v1
kind: PersistentVolume
metadata:
  name:  pv3
spec:
  capacity: 
    storage: 3Gi
  accessModes:
  - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /root/data/pv3
    server: 10.0.0.30
EOF
#创建pv
[root@xnode1 ~]# kubectl create -f pv.yaml 
persistentvolume/pv1 created
persistentvolume/pv2 created
persistentvolume/pv3 created

#查看pv
[root@xnode1 ~]# kubectl get pv -o wide
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv1    1Gi        RWX            Retain           Available                                   30s
pv2    2Gi        RWX            Retain           Available                                   30s
pv3    3Gi        RWX            Retain           Available                                   30s

(6)、PVC

PVC:

PVC是资源申请,用来声明对存储空间、访问模式、存储类别需求的信息,接下来我们查看一下清单文件.

#PVC清单文件

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc
  namespace: dev
spec:
  accessModes: # 访问模式
  selector: # 采用标签对PV选择
  storageClassName: # 存储类别
  resources: # 请求空间
    requests:
      storage: 5Gi

PVC关键访问参数:

**访问模式(accessModes)😗*用于描述用户对应存储资源的访问权限

选择条件(selector):通过 Label Selector,可使PVC对于系统中已存在的PV进行筛选

存储类别(storageClassName): ** PVC在定义时可以设定需要的后端存储的类型,只有设置了该class的PV**才能被系统选出

**资源请求(Resources)😗*描述对资源存储的请求

a)、实验

  • 1、创建pvc.yaml,申请pv
cat <<EOF > pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc1
  namespace: dev
spec:
  accessModes: 
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc2
  namespace: dev
spec:
  accessModes: 
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc3
  namespace: dev
spec:
  accessModes: 
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
EOF
#创建pvc
[root@xnode1 ~]# kubectl create -f pvc.yaml 
persistentvolumeclaim/pvc1 created
persistentvolumeclaim/pvc2 created
persistentvolumeclaim/pvc3 created

#查看pvc
[root@xnode1 ~]# kubectl get pvc -n dev -o wide
NAME   STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvc1   Bound    pv1      1Gi        RWX                           22s
pvc2   Bound    pv2      2Gi        RWX                           22s
pvc3   Bound    pv3      3Gi        RWX                           22s

#查看pv
[root@xnode1 ~]# kubectl get pv -n dev -o wide
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM      STORAGECLASS   REASON   AGE
pv1    1Gi        RWX            Retain           Bound    dev/pvc1                           47h
pv2    2Gi        RWX            Retain           Bound    dev/pvc2                           47h
pv3    3Gi        RWX            Retain           Bound    dev/pvc3                           47h

  • 2**、创建pods.yaml文件**
cat <<EOF > pods.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod1
  namespace: dev
spec:
  containers:
  - name: busybox
    image: busybox:1.30
    command: ["/bin/sh","-c","while true;do echo pod1 >> /root/out.txt; sleep 10; done;"]
    volumeMounts:
    - name: volume
      mountPath: /root/
  volumes:
    - name: volume
      persistentVolumeClaim:
        claimName: pvc1
        readOnly: false
---
apiVersion: v1
kind: Pod
metadata:
  name: pod2
  namespace: dev
spec:
  containers:
  - name: busybox
    image: busybox:1.30
    command: ["/bin/sh","-c","while true;do echo pod2 >> /root/out.txt; sleep 10; done;"]
    volumeMounts:
    - name: volume
      mountPath: /root/
  volumes:
    - name: volume
      persistentVolumeClaim:
        claimName: pvc2
        readOnly: false
EOF
#创建pod
[root@xnode1 ~]# kubectl create -f pods.yaml 
pod/pod1 created
pod/pod2 created

#查看pod
[root@xnode1 ~]# kubectl get pods -n dev -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
pod1   1/1     Running   0          54s   10.244.2.3   xnode3   <none>           <none>
pod2   1/1     Running   0          54s   10.244.2.2   xnode3   <none>           <none>

#查看pvc
[root@xnode1 ~]# kubectl get pvc -n dev -o wide
NAME   STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvc1   Bound    pv1      1Gi        RWX                           10m
pvc2   Bound    pv2      2Gi        RWX                           10m
pvc3   Bound    pv3      3Gi        RWX                           10m

#查看pv
[root@xnode1 ~]# kubectl get pv -n dev -o wide
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM      STORAGECLASS   REASON   AGE
pv1    1Gi        RWX            Retain           Bound    dev/pvc1                           10m
pv2    2Gi        RWX            Retain           Bound    dev/pvc2                           10m
pv3    3Gi        RWX            Retain           Bound    dev/pvc3                           10m

#查看nfs之中的文件存储
[root@xnode1 ~]# more /root/data/pv1/out.txt 
pod1
pod1
...

[root@xnode1 ~]# more /root/data/pv2/out.txt 
pod2
pod2
...

(7)、生命周期

PVPVC是对应的,PVPVC之间的相互作用遵循以下的生命周期:

  • 资源供应:管理员手动创建底层存储和PV
  • 资源绑定:用户创建PVC,kubernetes负责根据PVC的声明去寻找PV,并绑定在用户定义好PVC之后,系统将根据PVC对存储资源的请求在已存在的PV中选择一个满足条件的
  • 一旦找到,就将该PV与用户定义的PVC进行绑定,用户的应用就可以使用这个PVC
  • 如果找不到,PVC则会无限期处于Pending状态,直到等到系统管理员创建了一个符合其它要求的PV,PV一旦绑定到了某个PVC上,就会被这个PVC独占,不能再与其它的PVC进行绑定了.
  • 资源使用:用户可在pod中像volume一样使用PVC

    Pod使用Volume的定义,将PVC挂载到荣齐全内的某个路径进行使用.

  • 资源释放:用户删除PVC来释放PV

    当存储资源使用完毕后,用户可以删除PVC,与 该PVC绑定的PV将会被标记为"已释放",但还不能立刻与其它PVC进行绑定.通过之前PVC写入的数据还可能被留在存储设备上,只有在清除之后该PV才能再次使用.

  • 资源回收:kubernetes根据pv设置的回收策略进行资源的回收

    对于PV,管理员可以设定回收策略,用于设置与之绑定的PVC释放资源之后如何处理遗留数据的问题。只有PV的存储空间完成回收,才能供新的PVC绑定和使用

在这里插入图片描述

十四、配置存储

(1)、ConfigMap

ConfigMap:

ConfigMap是一种特殊的存储卷,它的作用主要是用来存储配置信息的.

创建 configmap.yaml,内容如下.

cat <<EOF > configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: configmap
  namespace: dev
data:
  info: |
    username:admin
    password:123456
EOF
  • 使用此配置文件创建configmap
#创建configmap
[root@xnode1 ~]# kubectl create -f configmap.yaml 
configmap/configmap created

#查看configmap的详情
[root@xnode1 ~]# kubectl describe configmaps -n dev configmap 
Name:         configmap
Namespace:    dev
Labels:       <none>
Annotations:  <none>

Data
====
info:
----
username:admin
password:123456

Events:  <none>
  • 创建一个pod-configmap.yaml,将上面创建的configmap挂载进去
cat <<EOF > pod-configmap.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-configmap
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    volumeMounts: # 将configmap挂载到目录
    - name: config
      mountPath: /configmap/config
  volumes: # 引用configmap
  - name: config
    configMap:
      name: configmap
EOF
#创建pod
[root@xnode1 ~]# kubectl create -f pod-configmap.yaml 
pod/pod-configmap created

#查看pod
[root@xnode1 ~]# kubectl get pods -n dev pod-configmap 
NAME            READY   STATUS    RESTARTS   AGE
pod-configmap   1/1     Running   0          32s

#进入容器
[root@xnode1 ~]# kubectl exec -it -n dev pod-configmap /bin/sh
# cat /configmap/config/info
username:admin
password:123456

#可以看到映射已经成功,每个configmap都映射成了一个目录
#key --->文件   value--->文件中的内容
#如果我们这个时候更新configmap中的内容,容器中的文件内容也会随之更新

[root@xnode1 ~]# kubectl edit configmaps configmap -n dev 

apiVersion: v1
data:
  info: |
    username:admin
    password:admin	--->修改
kind: ConfigMap

[root@xnode1 ~]# kubectl exec -it -n dev pod-configmap /bin/sh
# cat /configmap/config/info
username:admin
password:admin

(2)、Secret

kubernetes中还有一种和configmap很相似的配置存储工具,成为 Secret.它主要用来存储敏感信息,例如密码、秘钥、证书等。

  • 首先对base64数据进行编码
[root@xnode1 ~]# echo -n 'admin' | base64
YWRtaW4=
[root@xnode1 ~]# echo -n '123456' | base64
MTIzNDU2
  • 编写secret.yaml文件.并创建secret
cat <<EOF > secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: secret
  namespace: dev
type: Opaque
data:
  username: YWRtaW4=
  password: MTIzNDU2
EOF
#创建secret
[root@xnode1 ~]# kubectl create -f secret.yaml 
secret/secret created

#查看secret详情
[root@xnode1 ~]# kubectl describe secrets -n dev secret 
Name:         secret
Namespace:    dev
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password:  6 bytes
username:  5 bytes	-->可以看到这里的用户名和密码以及经过加密了
  • 创建一个pod-secret.yaml,将上面创建的secret挂载进去
cat <<EOF > pod-secret.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-secret
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    volumeMounts: # 将secret挂载到目录
    - name: config
      mountPath: /secret/config
  volumes:
  - name: config
    secret:
      secretName: secret
EOF
#创建pod
[root@xnode1 ~]# kubectl create -f pod-secret.yaml 
pod/pod-secret created

#查看pod
[root@xnode1 ~]# kubectl get pod -n dev pod-secret -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
pod-secret   1/1     Running   0          29s   10.244.2.5   xnode3   <none>           <none>

#进入容器.查看secret信息,发现已经自动解码了
[root@xnode1 ~]# kubectl exec -it -n dev pod-secret /bin/sh
# ls /secret/config/
password  username
# cat /secret/config/username
admin
# cat /secret/config/password
123456

#至此已经利用secret实现了信息的编码

十五、安全认证

(1)、访问控制概述

为了保证kubernetes内的集群和pod的安全性,kubernetes推出了访问安全认证对 客户端进行 认证和鉴权操作.

客户端:

  • **User Account:**一般是独立于kubernetes之外的其它服务管理的用户账号.
  • **Services Account:**kubernetes管理的账号,用于Pod中的服务进程在访问kubernetes时提供身份标识.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dclTYIsv-1662121676524)(/image-20200520102949189.png)]

  • 认证授权与准入控制:

APIServer是访问及管理资源对象的唯一入口.任何一个请求访问 APIServer,都要经过下面三个流程:

  • **Authentication(认证)😗*身份鉴别,只有正确的账号才通过认证
  • **Authorization(授权)😗*判断用户是否有访问权限对访问的资源执行特定的动作
  • **Admission Control(准入控制)😗*用于补充授权机制以及实现更加精准的访问控制功能

在这里插入图片描述

(2)、认证管理

kubernetes提供了三种客户端认证方式:

**HTTP Base认证:**通过用户名+密码的方式认证

  • 这种认证方式是把“用户名:密码”用BASE64算法进行编码后的字符串放在HTTP请求中的Header Authorization域里发送给服务端。服务端收到后进行解码,获取用户名及密码,然后进行用户身份认证的过程。

**HTTP Token认证:**通过一个Token来识别合法用户

  • 这种认证方式是用一个很长的难以被模仿的字符串–Token来表明客户身份的一种方式。每个Token对应一个用户名,当客户端发起API调用请求时,需要在HTTP Header里放入Token,API Server接到Token后会跟服务器中保存的token进行比对,然后进行用户身份认证的过程。

**HTTPS证书认证:**基于CA根证书签名的双向数字证书认证方式

  • HTTPS证书认证:基于CA根证书签名的双向数字证书认证方式

在这里插入图片描述

HTTPS认证大体分为3个过程:

  • **1.证书申请和下发:**HTTPS通信双方的服务器向CA机构申请证书,CA机构下发根证书、服务端证书及私钥给申请者
  • 2.客户端和服务端的双向认证:

a)、客户端向服务器端发起请求,服务端下发自己的证书给客户端,
客户端接收到证书后,通过私钥解密证书,在证书中获得服务端的公钥,
客户端利用服务器端的公钥认证证书中的信息,如果一致,则认可这个服务器
b)、 客户端发送自己的证书给服务器端,服务端接收到证书后,通过私钥解密证书,
在证书中获得客户端的公钥,并用该公钥认证证书信息,确认客户端是否合法

  • 3.服务器端和客户端进行通信:

服务器端和客户端协商好加密方案后,客户端会产生一个随机的秘钥并加密,然后发送到服务器端。服务器端接收这个秘钥后,双方接下来通信的所有内容都通过该随机秘钥加密

# 注意:
Kubernetes允许同时配置多种认证方式,只要其中任意一个方式认证通过即可

(3)、授权管理

授权在认证成功之后,通过认证就可以知道用户是谁,然后kubernetes会根据事先定义的授权策略来决定用户是否有权限访问,这个过程就称之为授权.

每个发送到ApiServer的请求都带上了用户和资源的信息:比如发送请求的用户、请求的路径、请求的动作等,授权就是根据这些信息和授权策略进行比较,如果符合策略,则认为授权通过,否则会返回错误。

API Server目前支持以下几种授权策略:

  • AlwaysDeny:表示拒绝所有请求,一般用于测试
  • AlwaysAllow:允许接收所有请求,相当于集群不需要授权流程(Kubernetes默认的策略)
  • ABAC:基于属性的访问控制,表示使用用户配置的授权规则对用户请求进行匹配和控制
  • Webhook:通过调用外部REST服务对用户进行授权
  • Node:是一种专用模式,用于对kubelet发出的请求进行访问控制
  • RBAC:基于角色的访问控制(kubeadm安装方式下的默认选项)

RBAC(Role-Based Access Control) 基于角色的访问控制,主要是在描述一件事情:给哪些对象授予了哪些权限

其中涉及到了下面几个概念:

  • 对象:User、Groups、ServiceAccount
  • 角色:代表着一组定义在资源上的可操作动作(权限)的集合
  • 绑定:将定义好的角色跟用户绑定在一起

在这里插入图片描述

RBAC引入了4个顶级资源对象:

  • **Role、ClusterRole:**角色,用于指定一组权限
  • **RoleBinding、ClusterRoleBinding:**角色绑定,用于将角色(权限)赋予给对象

**Role、ClusterRole:**一个角色就是一组权限的集合,这里的权限都是许可形式的(白名单)

# Role只能对命名空间内的资源进行授权,需要指定nameapce
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  namespace: dev
  name: authorization-role
rules:
- apiGroups: [""]  # 支持的API组列表,"" 空字符串,表示核心API群
  resources: ["pods"] # 支持的资源对象列表
  verbs: ["get", "watch", "list"] # 允许的对资源对象的操作方法列表
# ClusterRole可以对集群范围内资源、跨namespaces的范围资源、非资源类型进行授权
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
 name: authorization-clusterrole
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

需要详细说明的是,rules中的参数:

  • apiGroups: 支持的API组列表

    "","apps", "autoscaling", "batch"
    
  • resources:支持的资源对象列表

    "services", "endpoints", "pods","secrets","configmaps","crontabs","deployments","jobs",
    "nodes","rolebindings","clusterroles","daemonsets","replicasets","statefulsets",
    "horizontalpodautoscalers","replicationcontrollers","cronjobs"
    
  • verbs:对资源对象的操作方法列表

    "get", "list", "watch", "create", "update", "patch", "delete", "exec"
    

RoleBinding、ClusterRoleBinding

角色绑定用来把一个角色绑定到一个目标对象上,绑定目标可以是User、Group或者ServiceAccount。

# RoleBinding可以将同一namespace中的subject绑定到某个Role下,则此subject即具有该Role定义的权限
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: authorization-role-binding
  namespace: dev
subjects:
- kind: User
  name: heima
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: authorization-role
  apiGroup: rbac.authorization.k8s.io
# ClusterRoleBinding在整个集群级别和所有namespaces将特定的subject与ClusterRole绑定,授予权限
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
 name: authorization-clusterrole-binding
subjects:
- kind: User
  name: heima
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: authorization-clusterrole
  apiGroup: rbac.authorization.k8s.io

RoleBinding引用ClusterRole进行授权

RoleBinding可以引用 ClusterRole,对属于同一命名空间内 ClusterRole定义的资源主体进行授权.

一种很常用的做法就是,集群管理员为集群范围预定义好一组角色(ClusterRole),然后在多个命名空间中重复使用这些ClusterRole。这样可以大幅提高授权管理工作效率,也使得各个命名空间下的基础性授权规则与使用体验保持一致。
# 虽然authorization-clusterrole是一个集群角色,但是因为使用了RoleBinding
# 所以heima只能读取dev命名空间中的资源
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: authorization-role-binding-ns
  namespace: dev
subjects:
- kind: User
  name: heima
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: authorization-clusterrole
  apiGroup: rbac.authorization.k8s.io

实战:创建一个只能管理dev空间下的资源的账号

  • 1、创建账号
# 1)、创建证书
[root@xnode1 ~]# mkdir -p /etc/kubernetes/pki
[root@xnode1 ~]# cd /etc/kubernetes/pki/
[root@xnode1 pki]# (umask 077;openssl genrsa -out devman.key 2048)
Generating RSA private key, 2048 bit long modulus
.......................................+++
....................................................................................................+++
e is 65537 (0x10001)

# 2)、用apiserver的证书签署
# 签名申请,申请的用户是devman,组是devgroup
[root@xnode1 pki]# openssl req -new -key devman.key -out devman.csr -subj "/CN=devman/O=devgroup"

#签署证书
[root@xnode1 pki]# openssl x509 -req -in devman.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out devman.crt -days 3650
Signature ok
subject=/CN=devman/O=devgroup
Getting CA Private Key

# 3)、设置集群、用户、上下文信息
[root@xnode1 pki]# kubectl config set-cluster kubernetes --embed-certs=true --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://10.0.0.30:6443
Cluster "kubernetes" set.

[root@xnode1 pki]# kubectl config set-credentials devman --embed-certs=true --client-certificate=/etc/kubernetes/pki/devman.crt --client-key=/etc/kubernetes/pki/devman.key
User "devman" set.

[root@xnode1 pki]# kubectl config set-context devman@kubernetes --cluster=kubernetes --user=devman 
Context "devman@kubernetes" created.

# 将账户切换到devman
[root@xnode1 pki]# kubectl config use-context devman@kubernetes 
Switched to context "devman@kubernetes".

#查看dev下的pod,发现无相关的权限访问
[root@xnode1 pki]# kubectl get pods -n dev
Error from server (Forbidden): pods is forbidden: User "devman" cannot list resource "pods" in API group "" in the namespace "dev"

#切换回admin账户
[root@xnode1 pki]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".
  • 2、创建RoleRoleBinding,为 devman用户授权
cat <<EOF > dev-role.yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  namespace: dev
  name: dev-role
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
  
---

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: authorization-role-binding
  namespace: dev
subjects:
- kind: User
  name: devman
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: dev-role
  apiGroup: rbac.authorization.k8s.io
EOF
# 执行配置文件,赋予devman用户相应的角色和适当的权限
[root@xnode1 ~]# kubectl create -f dev-role.yaml 
role.rbac.authorization.k8s.io/dev-role created
rolebinding.rbac.authorization.k8s.io/authorization-role-binding created

# 切换账户,再次验证
[root@xnode1 ~]# kubectl config use-context devman@kubernetes
Switched to context "devman@kubernetes".

[root@xnode1 ~]# kubectl get pods -n dev -o wide
NAME            READY   STATUS    RESTARTS   AGE    IP           NODE     NOMINATED NODE   READINESS GATES
pod-configmap   1/1     Running   0          159m   10.244.2.4   xnode3   <none>           <none>
pod-secret      1/1     Running   0          135m   10.244.2.5   xnode3   <none>           <none>

# 切换回admin账户
[root@xnode1 ~]# kubectl config use-context kubernetes-admin@kubernetes 
Switched to context "kubernetes-admin@kubernetes".

(4)、准入控制

通过了前面的认证和授权之后,还需要经过准入控制处理通过之后,apiserver才会处理这个请求。

准入控制是一个可配置的控制器列表,可以通过在Api-Server上通过命令行设置选择执行哪些准入控制器:

--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,
                      DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds

只有当所有的准入控制器都检查通过之后,apiserver才执行该请求,否则返回拒绝。

当前可配置的Admission Control准入控制如下:

  • AlwaysAdmit:允许所有请求
  • AlwaysDeny:禁止所有请求,一般用于测试
  • AlwaysPullImages:在启动容器之前总去下载镜像
  • DenyExecOnPrivileged:它会拦截所有想在Privileged Container上执行命令的请求
  • ImagePolicyWebhook:这个插件将允许后端的一个Webhook程序来完成admission controller的功能。
  • Service Account:实现ServiceAccount实现了自动化
  • SecurityContextDeny:这个插件将使用SecurityContext的Pod中的定义全部失效
  • ResourceQuota:用于资源配额管理目的,观察所有请求,确保在namespace上的配额不会超标
  • LimitRanger:用于资源限制管理,作用于namespace上,确保对Pod进行资源限制
  • InitialResources:为未设置资源请求与限制的Pod,根据其镜像的历史资源的使用情况进行设置
  • NamespaceLifecycle:如果尝试在一个不存在的namespace中创建资源对象,则该创建请求将被拒绝。当删除一个namespace时,系统将会删除该namespace中所有对象。
  • DefaultStorageClass:为了实现共享存储的动态供应,为未指定StorageClass或PV的PVC尝试匹配默认的StorageClass,尽可能减少用户在申请PVC时所需了解的后端存储细节
  • DefaultTolerationSeconds:这个插件为那些没有设置forgiveness tolerations并具有notready:NoExecute和unreachable:NoExecute两种taints的Pod设置默认的“容忍”时间,为5min
  • PodSecurityPolicy:这个插件用于在创建或修改Pod时决定是否根据Pod的security context和可用的PodSecurityPolicy对Pod的安全策略进行控制
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值