1. K8s DNS

官网地址:https://github.com/coredns/coredns
https://coredns.io/
https://coredns.io/plugins

1.1 简介

DNS组件历史版本有skydns、kube-dns和coredns三个,k8s 1.3版本之前使用skydns,之后的版本到1.17及之间的版本使用kube-dns,
1.18开始目前主要使用coredns,DNS组件用于解析k8s集群中service name所对应得到IP地址。

主要就是负责dns域名解析、服务发现(CoreDNS是一个DNS服务器,它是用Go编写的 )。
注意:CoreDNS几乎所有的功能,都是由插件提供的,如配置文件中的forward插件、health插件等等。

1.2 运行coredns

[root@k8s-harbor01 ~]# kubectl get po,svc -A |grep dns
kube-system   pod/coredns-5879bb4b8c-g8z8b                     1/1     Running   0             14d
kube-system   pod/coredns-5879bb4b8c-ph4h4                     1/1     Running   0             12d
kube-system   service/kube-dns             ClusterIP   10.100.0.2       <none>        53/UDP,53/TCP,9153/TCP       14d # 这里由于历史原因,svc的名称最好还是写kube-dns

1.3 配置文件详解

apiVersion: v1
data:
  Corefile: |
    .:53 { # 所有域名(.),都通过53端口号链接到dns服务进行域名解析
        errors # errors插件,主要作用是:查询处理过程中遇到的任何错误都将打印到标准输出中。
        health { # 健康检查插件(存活态)。当coredns启动并运行时,它会返回一个200 OK的HTTP状态码到/health接口,通过localhost:8080/health可以获取。
            lameduck 5s # 延迟关闭服务的时间(延迟关闭模式),当前为5s(进程收到关闭信号后会等5s),5s内/health接口任然会返回200 OK。
			# 注意:假设我们在多个配置块中都使用了lameduck功能,那么时间会叠加。
			# health插件主要是用于livenessProbe,主要关注服务是不是存活(服务yaml的健康检查配置中有体现)。
        }
        ready # 健康检查插件(就绪态)。当所有能够发出ready信号的插件都发出ready信号时,HTTP端点将返回200 OK,通过localhost:8181/ready可以获取。
		# 如果有插件没有ready,则返回一个未就绪插件列表和503状态码。
		# ready插件不受lameduck配置的影响
		# ready插件主要用于readinessProbe,主要关注服务能否正常提供服务(服务yaml的健康检查配置中有体现)。
        kubernetes cluster.local in-addr.arpa ip6.arpa {
		# kubernetes插件:实现了K8s基于dns的服务发现规范。每个服务器块(当成nginx的server部分)只能使用此插件一次。
		# cluster.local:域名后缀,所有该后缀结尾的域名,都会通过kubernetes插件像内部k8s集群发起查询。
		# in-addr.arpa:IPv4反向查询域名后缀。
		# ip6.arpa:IPv6反向查询域名后缀。
		# 服务发现:在Kubernetes中,每个Service对象都会被分配一个唯一的DNS名称。这个DNS名称采用以下格式:<service-name>.<namespace>.svc.cluster.local。
		# 这个名称将被解析为Service的一个或多个后端Pod的IP地址。
		# 当一个应用程序通过Service名称进行通信时,DNS解析将返回相应的后端Pod的IP地址,从而实现服务发现。
            pods insecure # 在处理 K8s Pod 的 DNS 请求时允许不进行安全性检查。
            fallthrough in-addr.arpa ip6.arpa # fallthrough:把dns请求向下传递到其他插件链。一般后面会跟指定的后缀,以此来把指定后缀域名向下传递给其他插件处理,而不是在当前插件中停止处理。
            ttl 30 # dns记录缓存时间,默认5s,最小 TTL 为 0 秒(不缓存),最大值上限为 3600 秒。
        }
        prometheus :9153 # 监控插件,coredns所有的指标都会被该插件收集
        #forward . /etc/resolv.conf {
        forward . 223.6.6.6 { # forward转发插件:将所有dns请求(.),都转发到223.6.6.6进行处理
            max_concurrent 1000 # 最大并发连接数:1000
        }
        cache 600 # dns缓存。cache针对所有域名,ttl是单个域名。
        loop # 防止dns查询死循环的插件。
        reload # 重载插件:允许自动重新加载已更改的Corefile。 编辑 ConfigMap 配置后,请等待两分钟,以使更改生效。如果文件修改有误,会自动应用旧的配置。
        loadbalance # 负载均衡:默认策略为轮询
    }
        myserver.online {
          forward . 172.16.16.16:53 # myserver.online结尾的域名,转发到172.16.16.16:53 
        }

在这里插入图片描述

1.4 解析演示

# 创建两个pod
[root@k8s-harbor01 ~]# kubectl run net-test0 --image=centos:7.9.2009 sleep 360000
pod/net-test0 created

[root@k8s-harbor01 ~]# kubectl run net-test1 --image=centos:7.9.2009 sleep 360000
pod/net-test1 created

# 互ping一下
[root@k8s-harbor01 ~]# kubectl get po -o wide
NAME        READY   STATUS    RESTARTS   AGE     IP               NODE         NOMINATED NODE   READINESS GATES
net-test0   1/1     Running   0          2m57s   10.200.135.133   k8s-node03   <none>           <none>
net-test1   1/1     Running   0          27h     10.200.135.132   k8s-node03   <none>           <none>
[root@k8s-harbor01 ~]# kubectl exec -it net-test0 -- /bin/bash
[root@net-test0 /]# ping 10.200.135.132
PING 10.200.135.133 (10.200.135.133) 56(84) bytes of data.
64 bytes from 10.200.135.133: icmp_seq=1 ttl=64 time=0.071 ms
^C
--- 10.200.135.133 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.071/0.071/0.071/0.000 ms
[root@net-test0 /]# exit
exit
[root@k8s-harbor01 ~]# kubectl exec -it net-test1 -- /bin/bash
[root@net-test1 /]# ping 10.200.135.133
PING 10.200.135.133 (10.200.135.133) 56(84) bytes of data.
64 bytes from 10.200.135.133: icmp_seq=1 ttl=63 time=0.174 ms
64 bytes from 10.200.135.133: icmp_seq=2 ttl=63 time=0.091 ms
^C
--- 10.200.135.133 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1019ms
rtt min/avg/max/mdev = 0.091/0.132/0.174/0.043 ms

# 解析内部域名
[root@net-test1 /]# yum -y install bind-utils
[root@net-test1 /]# nslookup kubernetes
Server:         10.100.0.2
Address:        10.100.0.2#53

Name:   kubernetes.default.svc.cluster.local
Address: 10.100.0.1

1.5 coredns是如何进行内部域名解析的

SVC调用后端dnsPod默认规则为:rr

# coredns的cm中有这么一段配置
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa { # 就是在解析cluster.local这域名的时候,找的是kubernetes,那么这个kubernetes是谁呢?看下面
            pods insecure
            fallthrough in-addr.arpa ip6.arpa
            ttl 30

[root@k8s-harbor01 yaml]#  kubectl get po,svc -A |grep kubernetes # 就是这个,因为coredns是不能直接连接etcd的,所以它只能通过集群内部的kubernetes,也就是apiserver的svc,来获取etcd中的svc数据
default       service/kubernetes           ClusterIP   10.100.0.1       <none>        443/TCP                      14d
[root@k8s-harbor01 yaml]# kubectl get ep
NAME         ENDPOINTS                                                  AGE
kubernetes   10.31.200.101:6443,10.31.200.102:6443,10.31.200.103:6443   14d

# 对应权限可以查看yaml
rules:
- apiGroups:
  - ""
  resources:
  - endpoints
  - services
  - pods
  - namespaces
  verbs:
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - get
- apiGroups:
  - discovery.k8s.io
  resources:
  - endpointslices
  verbs:
  - list
  - watch

1.6 pod是如何获取到coredns的地址的

pod的创建,是由kubelet调用CRI(容器运行时)实现的,在pod创建的同时还会额外创建一个pause容器,来初始化pod中的网络名称空间,当pod为边车模式的时候,pod中的所有容器都共享该网络。
那pod如何获取到coredns地址的呢?
通过查看kubelet的配置文件可以看到,coredns的地址,是提前指定给了kubelet的(或者加启动参数–cluster-dns指定)
[root@k8s-node01 ~]# grep DNS -A 1 /var/lib/kubelet/config.yaml
clusterDNS:
- 10.100.0.2
上面的dns地址,会写入pause容器中,然后调用一些函数,生成所需配置,看下面。

1.7 pod resolv.conf文件是如何生成的

首先,kubelet从apiserver watch到创建pod的请求后, 调用 SyncPod 来创建 pod, pod 里容器的 dns 的配置是在 pause 里的.createPodSandbox 方法用来创建 pod, 其内部会生成 pause 所需的配置, 然后调用 cri 来传递配置并创建 pause 容器。
生成配置会调用generatePodSandboxConfig 方法用来生成 pod 配置, 其中有我们关注的 dns 配置项。
然后调用GetPodDNS 用来获取创建容器所需的 dnsConfig 配置, 其内部根据 pod 的 dnsPolicy 获取不同的 dns 配置。

1.8 pod的dns获取策略

1.8.1 策略类型

(1)Default: Pod 使用宿主机的 DNS 配置 ;
(2)ClusterFirst: K8s 的默认设置, 先在 K8s 集群配置的 coreDNS 中查询,查不到的再去继承自主机的上游 nameserver 中查询 ;
(3)ClusterFirstWithHostNet: 对于网络配置为 hostNetwork 的 Pod 而言,其 DNS 配置规则与 ClusterFirst 一致 ;
(4)None: 忽略 K8s 环境的 DNS 配置, 只认 Pod 里的 dnsConfig 配置项.

查看pod的dns策略

[root@k8s-harbor01 ~]# kubectl get po details-v1-58c888794b-pmv7g -oyaml |grep dnsPolicy
  dnsPolicy: ClusterFirst # 这就是默认的dns策略

1.8.2 策略配置方式

1.8.2.1 Default

使用宿主机 dns 配置

apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: dns-example
spec:
  containers:
    - name: test
      image: nginx
   dnsPolicy: Default
1.8.2.2 ClusterFirst

使用 k8s 的 coredns servers 配置

apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: dns-example
spec:
  containers:
    - name: test
      image: nginx
  dnsPolicy: ClusterFirst
1.8.2.3 ClusterFirstWithHostNet

使用 k8s 的 coredns server 配置, 但使用主机协议栈

apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: dns-example
spec:
  containers:
    - name: test
      image: nginx

   hostNetwork: true
   dnsPolicy: ClusterFirstWithHostNet

1.8.2.4 None

不使用 k8s 和主机的 dns 配置, 而是使用 dnsConfig 配置段

apiVersion: v1
kind: Pod
metadata:
  namespace: default
  name: dns-example
spec:
  containers:
    - name: test
      image: nginx
  dnsPolicy: "None"
  dnsConfig:
    nameservers:
      - 1.2.3.4
    searches:
      - ns1.svc.cluster-domain.example
    options:
      - name: ndots
        value: "2"
      - name: edns0

1.9 coredns使用注意事项

主要是内存cpu这块

如果集群内,coredns需要解析大量的内部域名,这个时候就需要关注一下coredns的资源使用情况了,万一资源不足了,可能会出现域名解析慢或者无法解析的情况。如果加了资源还是慢,可以尝试扩容副本(一般生产3个就够了)。
并且我亲身经历过,由于云上cordns配置不足,导致的后端服务调用链路缓慢导致的p0,故障,所以它的配置给够,监控告警做好。

resources:
  limits:
    memory: 256Mi
    cpu: 200m
  requests:  # 如果内存够多,可以配置1G或者512M,CPU给1C到2C,因为coredns主要还是比较消耗cpu,内存到还好(官方给的内存算法:容器内存=pod总数/1000+54)
    cpu: 100m
    memory: 70Mi

1.10 CoreDNS和Kube-DNS的差异

1.10.1 实现方式不同

在 kube-dns 中,一个 Pod 中使用多个 容器:kubedns、dnsmasq、和 sidecar。
kubedns 容器监视 Kubernetes API 并根据 Kubernetes DNS 规范 提供 DNS 记录,
dnsmasq 提供缓存和存根域支持,
sidecar 提供指标和健康检查。

在 CoreDNS 中,所有这些功能都是在一个容器中完成的,该容器运行用 Go 编写的进程。
所启用的不同插件可复制(并增强)在 kube-dns 中存在的功能。

1.10.2 配置文件

在 kube-dns 中,可以 修改 ConfigMap 来更改服务发现的行为。
用户可以添加诸如为存根域提供服务、修改上游名称服务器以及启用联盟之类的功能。

在 CoreDNS 中,可以类似地修改 CoreDNS Corefile 的 ConfigMap,以更改服务发现的工作方式。
这种 Corefile 配置提供了比 kube-dns 中更多的选项,因为它是 CoreDNS 用于配置所有功能的主要配置文件,即使与 Kubernetes 不相关的功能也可以操作。

1.10.3 错误修复和增强

在 CoreDNS 中解决了 kube-dn 的多个未解决问题,无论是默认配置还是某些自定义配置。
如:kube-dns 无法以非 root 用户身份运行,虽然通过non-default 镜像解决了此问题,但是这在corends中默认就支持。

1.10.4 监控数据指标

在 kube-dns 中,您将分别获得 dnsmasq 和 kubedns(skydns)的度量值。
在 CoreDNS 中,存在一组完全不同的指标,因为它们在同一个进程中。

2. k8s资源对象

通过以下命令,可以查看k8s集中支持的所有资源对象

[root@k8s-harbor01 ~]# kubectl api-resources
NAME(资源名称)      SHORTNAMES(资源简写)   APIVERSION(支持的API版本)   NAMESPACED(是否为ns级别)   KIND(资源类型)
bindings                                       v1                                     true         Binding
componentstatuses                 cs           v1                                     false        ComponentStatus
configmaps                        cm           v1                                     true         ConfigMap
endpoints                         ep           v1                                     true         Endpoints
events                            ev           v1                                     true         Event
limitranges                       limits       v1                                     true         LimitRange
namespaces                        ns           v1                                     false        Namespace
nodes                             no           v1                                     false        Node
persistentvolumeclaims            pvc          v1                                     true         PersistentVolumeClaim
persistentvolumes                 pv           v1                                     false        PersistentVolume
pods                              po           v1                                     true         Pod
…………省略部分内容

2.1 基本理论

2.1.1 K8s的设计理念—分层架构

在这里插入图片描述

2.1.2 K8s API设计原则

在这里插入图片描述

2.1.3 K8s内置资源对象简介

在这里插入图片描述

2.1.4 K8s常用命令简介

在这里插入图片描述

2.1.4.1 命令演示:scale 动态扩缩容
[root@k8s-harbor01 ~]# kubectl get deploy -A
NAMESPACE     NAME                        READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   calico-kube-controllers     1/1     1            1           14d
kube-system   coredns                     2/2     2            2           14d
myserver      myserver-nginx-deployment   1/1     1            1           5d # 这里把1副本的deploy扩容成2副本

[root@k8s-harbor01 ~]# kubectl scale deploy -n myserver myserver-nginx-deployment --replicas=2
deployment.apps/myserver-nginx-deployment scaled

[root@k8s-harbor01 ~]# kubectl get deploy -A|grep myserver
myserver      myserver-nginx-deployment   2/2     2            2           5d

2.1.5 K8s中的几个重要概念

在这里插入图片描述

2.1.6 yaml文件及必需字段

在这里插入图片描述

2.2 pod

在这里插入图片描述

2.3 Job与cronjob

2.3.1 Job与cronjob的区别

Job:单次执行的任务
cronjob:周期性执行的任务

2.3.2 演示

2.3.2.1 创建一个job
[root@k8s-harbor01 job]# cat test-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: job-mysql-init
spec:
  template:
    spec:
      containers:
      - name: job-mysql-init-container
        image: 10.31.200.104/myserver/centos:7.9.2009
        command: ["/bin/sh"] # 容器起来后,执行的命令
        args: ["-c", "echo data init job at `date +%Y-%m-%d_%H-%M-%S` >> /cache/data.log"] # command的参数,这里是echo一行字符串到指定文件中
        volumeMounts:
        - mountPath: /cache
          name: cache-volume
        - mountPath: /etc/localtime
          name: localtime
      volumes:
      - name: cache-volume
        hostPath:
          path: /tmp/jobdata # 这里把容器的/cache目录,挂载到宿主机的/tmp/jobdata
      - name: localtime
        hostPath:
          path: /etc/localtime
      restartPolicy: Never

[root@k8s-harbor01 job]# kubectl apply -f test-job.yaml 
job.batch/job-mysql-init created

[root@k8s-harbor01 job]# kubectl get job
NAME             COMPLETIONS   DURATION   AGE
job-mysql-init   1/1           5s         9s
[root@k8s-harbor01 job]# kubectl get po -o wide # 这个pod只会执行一次,执行完毕就退出了,状态显示Completed
NAME                   READY   STATUS      RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
job-mysql-init-cm7tl   0/1     Completed   0          70s   10.200.85.197    k8s-node01   <none>           <none>


[root@k8s-harbor01 job]# ssh k8s-node01
[root@k8s-node01 ~]# cat /tmp/jobdata/data.log   # 这就是job pod创建的文件
data init job at 2023-05-09_22-59-53
2.3.2.2 创建一个cronjob

cronjob在运行完毕后,状态变为Completed,默认保留3份历史,当一个pod运行完毕,下一次运行又会重新拉起一个新的pod,再删除存在时间最久的旧的pod

[root@k8s-harbor01 job]# cat test-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cronjob-mysql-databackup
spec:
  schedule: "* * * * *" # 这里,就跟我们linux定时任务是一样的。这里一定要保证宿主机的时间是准确的,不然会出问题。
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: cronjob-mysql-databackup-pod
            image: 10.31.200.104/myserver/centos:7.9.2009
            #imagePullPolicy: IfNotPresent
            command: ["/bin/sh"]
            args: ["-c", "echo mysql databackup cronjob at `date +%Y-%m-%d_%H-%M-%S` >> /cache/data.log"]
            volumeMounts: 
            - mountPath: /cache
              name: cache-volume
          volumes:
          - name: cache-volume
            hostPath: # 工作中用cronjob生成文件的话,一定不要存储到宿主机,用nfs都行,因为pod不一定每次都调度到同一台机器。
              path: /tmp/cronjobdata
          restartPolicy: OnFailure

[root@k8s-harbor01 job]# kubectl apply -f test-cronjob.yaml
cronjob.batch/cronjob-mysql-databackup created

[root@k8s-harbor01 job]# kubectl get cj
NAME                       SCHEDULE    SUSPEND   ACTIVE   LAST SCHEDULE   AGE
cronjob-mysql-databackup   * * * * *   False     0        9s              4m18s
[root@k8s-harbor01 job]# kubectl get po -A |grep cronjob-mysql-databackup # 每次运行完毕后,状态就更新为Completed。等下一次执行的时候,会创建一个新的pod,再删除之前的旧的pod
default       cronjob-mysql-databackup-28063282-689bs      0/1     Completed   0               2m16s
default       cronjob-mysql-databackup-28063283-skp4j      0/1     Completed   0               76s
default       cronjob-mysql-databackup-28063284-5fvqv      0/1     Completed   0               16s


[root@k8s-harbor01 job]# ssh k8s-node01
[root@k8s-node01 ~]# cat /tmp/cronjobdata/data.log  # 这就是cornjob生成文件
mysql databackup cronjob at 2023-05-11_09-20-01
mysql databackup cronjob at 2023-05-11_09-21-01
mysql databackup cronjob at 2023-05-11_09-22-01
mysql databackup cronjob at 2023-05-11_09-23-01
mysql databackup cronjob at 2023-05-11_09-24-01
mysql databackup cronjob at 2023-05-11_09-25-01

2.4 RC/RS 副本控制器

2.4.1 Replication Controller(rc)

2.4.1.1 简介

副本控制器,第一代pod副本控制器,现在基本已经不用它了,被RS替代了。
为啥不用了,因为它只能实现pod副本管理(只保证pod是按照指定数量运行的,其他不管),并且有很多功能不支持,比如滚动更新(只有3个资源支持:deployments、daemonsets、statefulsets)、蓝绿部署等。
缩容:删除运行时间最短的pod。

2.4.1.2 演示
[root@k8s-harbor01 yaml]# cat rc.yaml
apiVersion: v1  
kind: ReplicationController  
metadata:  
  name: ng-rc
spec:  
  replicas: 2
  selector:  
    app: ng-rc-80  # rc就是通过关联标签来管理pod的
  template:   
    metadata:  
      labels:  
        app: ng-rc-80
    spec:  
      containers:  
      - name: ng-rc-80 
        image: nginx  
        ports:  
        - containerPort: 80 


[root@k8s-harbor01 yaml]# kubectl apply -f rc.yaml
replicationcontroller/ng-rc created
[root@k8s-harbor01 yaml]# kubectl get po |grep ng-rc
ng-rc-5jj4v                               1/1     Running     0          48s
ng-rc-pt48w                               1/1     Running     0          48s

# 就算删除一个pod,rc控制器也会立马再创建一个新的
[root@k8s-harbor01 yaml]# kubectl delete po ng-rc-pt48w
pod "ng-rc-pt48w" deleted
[root@k8s-harbor01 yaml]# kubectl get po |grep ng-rc
ng-rc-5jj4v                               1/1     Running             0          14m
ng-rc-mz827                               0/1     ContainerCreating   0          2s

# 那么如何删除呢?删除rc控制器,这样pod就不会被无限拉起了
[root@k8s-harbor01 yaml]# kubectl get rc 
NAME    DESIRED   CURRENT   READY   AGE
ng-rc   2         2         2       15m
[root@k8s-harbor01 yaml]# kubectl delete rc ng-rc
replicationcontroller "ng-rc" deleted
[root@k8s-harbor01 yaml]# kubectl get po |grep ng-rc
[root@k8s-harbor01 yaml]# 

2.4.2 ReplicaSet(rs)

https://kubernetes.io/zh/docs/concepts/workloads/controllers/replicaset/

2.4.2.1 简介

副本控制器,和rc的区别是,对选择器的支持(selector 还支持in notin) #第二代pod副本控制

2.4.2.2 演示
[root@k8s-harbor01 deployment]# cat rs.yaml
apiVersion: apps/v1 
kind: ReplicaSet
metadata:
  name: frontend
spec:
  replicas: 2
  selector:
    #matchLabels: # 标签选择支持的写法一
    #  app: ng-rs-80 # 严格匹配
    matchExpressions: # 标签选择支持的写法二
      - {key: app, operator: In, values: [ng-rs-80,ng-rs-81]} # 正则模糊匹配。指定一个key为app,value是ng-rs-80或ng-rs-81的,这种方式比较少用,更常用的还是上面的严格匹配。
  template:
    metadata:
      labels:
        app: ng-rs-80
    spec:  
      containers:  
      - name: ng-rs-80 
        image: 10.31.200.104/myserver/nginx:latest 
        ports:  
        - containerPort: 80

[root@k8s-harbor01 deployment]# kubectl apply -f rs.yaml
[root@k8s-harbor01 deployment]# kubectl get rs,po|grep fron
replicaset.apps/frontend   2         2         2       31s
pod/frontend-fcnbc                            1/1     Running     0             31s
pod/frontend-kq7m4                            1/1     Running     0             31s

2.5 Deployment控制器(deploy)

官网地址:https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/deployment/

2.5.1 简介

比rs更高一级的控制器(也是工作中常用的控制器),除了有rs的功能之外,还有很多高级功能,,比如说最重要的:滚动升级、回滚等 #第三代pod控制器
deploy并不是直接管理控制pod副本的,当我们创建一个deploy的时候,它会先创建一个rs,由rs再去创建管理pod。
当我们对pod做版本迭代的时候,deploy也是会创建一个新的rs,由rs再来创建管理pod,新的rs创建并成功运行后,旧的rs就会回收一个旧的pod,直到新的pod全部起来为止,旧的rs副本数就变成了0。

2.5.2 演示

2.5.2.1 创建deploy
[root@k8s-harbor01 deployment]# cat deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    #app: ng-deploy-80 #rc # 标签选择支持的方式1
    matchLabels: #rs or deployment # 标签选择支持的方式2
      app: ng-deploy-80
    
    # matchExpressions: # 标签选择支持的方式3
      # - {key: app, operator: In, values: [ng-deploy-80,ng-rs-81]}
  template:
    metadata:
      labels:
        app: ng-deploy-80 # 这个标签要和上面selector一样
    spec:
      containers:
      - name: ng-deploy-80
        image: nginx
        ports:
        - containerPort: 80


[root@k8s-harbor01 deployment]# kubectl apply -f deploy.yaml
deployment.apps/nginx-deployment created
[root@k8s-harbor01 deployment]# kubectl get deploy,rs,po |grep nginx
deployment.apps/nginx-deployment   2/2     2            2           27s
replicaset.apps/nginx-deployment-68657ff5c6   2         2         2       27s
pod/nginx-deployment-68657ff5c6-bt72j         1/1     Running     0             27s
pod/nginx-deployment-68657ff5c6-fj78n         1/1     Running     0             27s

在这里插入图片描述

2.5.2.2 更新deploy
# 语法
kubectl set image 控制器类型 控制器名称 容器名称(containers.name)=镜像

[root@k8s-harbor01 yaml]# kubectl set image deploy nginx-deployment ng-deploy-80=10.31.200.104/myserver/nginx:latest
deployment.apps/nginx-deployment image updated
[root@k8s-harbor01 yaml]# kubectl get deploy,rs,po |grep nginx
deployment.apps/nginx-deployment   2/2     2            2           14m
replicaset.apps/nginx-deployment-68657ff5c6   0         0         0       14m
replicaset.apps/nginx-deployment-8579958888   2         2         2       8s
replicaset.apps/nginx-deployment-dd7d85df7    0         0         0       59s
pod/nginx-deployment-8579958888-pqtfn         1/1     Running     0             6s
pod/nginx-deployment-8579958888-tm4qg         1/1     Running     0             8s

在这里插入图片描述
https://www.qikqiak.com/post/k8s-deployment-strategies/

2.5.2.3 查看deploy的更新信息
root@k8s-harbor01 yaml]# kubectl rollout history deploy nginx-deployment  # 从下面的输入可以看到,该deploy更新了3次,从rs也能看出来有3个
deployment.apps/nginx-deployment 
REVISION  CHANGE-CAUSE
1         <none>
2         <none>
3         <none>
2.5.2.4 回滚deploy
# 有2种方式,第一种方式是直接更新deploy的镜像,edit替换或者修改yaml后apply。
# 第二种是通过rs的历史版本进行回滚

# 查看历史版本号
[root@k8s-harbor01 yaml]# kubectl rollout history deploy nginx-deployment 
deployment.apps/nginx-deployment 
REVISION  CHANGE-CAUSE
3         <none>
4         <none>
5         <none>
6         <none>

[root@k8s-harbor01 yaml]# kubectl exec -it pod/nginx-deployment-599889b4-c2vjn -- nginx -v
nginx version: nginx/1.18.0

# 回滚到版本5
[root@k8s-harbor01 yaml]# kubectl rollout undo deploy nginx-deployment  --to-revision=5

[root@k8s-harbor01 yaml]# kubectl get deploy,rs,po |grep nginx
deployment.apps/nginx-deployment   2/2     2            2           27m
replicaset.apps/nginx-deployment-68657ff5c6   2         2         2       27m
replicaset.apps/nginx-deployment-8579958888   0         0         0       13m
replicaset.apps/nginx-deployment-dd7d85df7    0         0         0       14m
pod/nginx-deployment-68657ff5c6-w42lq         1/1     Running     0             19s
pod/nginx-deployment-68657ff5c6-ckmsq         1/1     Running     0             36s

[root@k8s-harbor01 yaml]# kubectl exec -it pod/nginx-deployment-68657ff5c6-ckmsq -- nginx -v
nginx version: nginx/1.21.5

# 还有一个办法,就是通过注解来回滚
## 查看历史更新版本
[root@k8s-harbor01 deployment]# kubectl rollout history deploy nginx-deployment
deployment.apps/nginx-deployment 
REVISION  CHANGE-CAUSE # 这里发现change-cause为空,其实这个是需要们手动添加注解的
1         <none>
2         <none>

## 模拟更新deploy
[root@k8s-harbor01 deployment]# kubectl set image deploy nginx-deployment ng-deploy-80=nginx
deployment.apps/nginx-deployment image updated
[root@k8s-harbor01 deployment]# kubectl rollout history deploy nginx-deployment
deployment.apps/nginx-deployment 
REVISION  CHANGE-CAUSE
2         <none>
3         <none> # 3是空的

## 添加注解
[root@k8s-harbor01 deployment]# kubectl annotate deployment nginx-deployment kubernetes.io/change-cause="image updated to nginx:latest"
deployment.apps/nginx-deployment annotated
[root@k8s-harbor01 deployment]# kubectl rollout history deploy nginx-deployment
deployment.apps/nginx-deployment 
REVISION  CHANGE-CAUSE
2         <none>
3         image updated to nginx:latest # 这就能看到了(但是这种方法真的鸡肋)

2.5.3 Deployment部署策略

新的pod如何替换旧的pod

spec:
  replicas: 3
  strategy: # 这个参数描述了如何用新的pod替换现有的pod。
2.5.3.1 rollingUpdate

滚动更新,deployment的默认更新策略

# 查看deploy的默认更新策略
[root@k8s-harbor01 deployment]# kubectl get deploy -o yaml nginx-deployment|grep maxSurge -C 2
  strategy: # 更新策略
    rollingUpdate: # 滚动更新
      maxSurge: 25% # 除了当前正在运行中的pod,我更新的时候还可以额外创建的pod,比如已有3副本,那么按照百分比就是我可以额外创建1个,一共是4个
      maxUnavailable: 25% # 这个跟上面的意思差不多,是说我额外创建pod后,有25%可以是不可用的(比如set image时,镜像地址写错了,拉不到镜像报错)。
    type: RollingUpdate # 部署类型,默认是RollingUpdate


# 除了上面按照百分比进行滚动更新,还可以直接设置数字
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 2
      maxUnavailable: 1

通过这个图也能直接看出来
在这里插入图片描述

2.5.3.2 recreate

先杀死所有已经存在的pod,再创建新的pod
这个生产环境严禁使用

spec:
  replicas: 3
  strategy:
    type: Recreate
2.5.3.3 扩展:蓝绿部署

蓝/绿发布是版本2 与版本1 一起发布,然后流量切换到版本2,也称为红/黑部署。
蓝/绿发布与滚动更新不同,版本2(绿) 与版本1(蓝)一起部署,在测试新版本满足要求后,然后更新 Kubernetes 中扮演负载均衡器角色的 Service 对象,通过替换 label selector 中的版本标签来将流量发送到新版本,如下图所示:

在这里插入图片描述

2.5.3.4 扩展:金丝雀(Canary)部署

金丝雀部署是让部分用户访问到新版本应用,在 Kubernetes 中,可以使用两个具有相同 Pod 标签的 Deployment 来实现金丝雀部署。新版本的副本和旧版本的一起发布。在一段时间后如果没有检测到错误,则可以扩展新版本的副本数量并删除旧版本的应用。

如果需要按照具体的百分比来进行金丝雀发布,需要尽可能的启动多的 Pod 副本,这样计算流量百分比的时候才方便,比如,如果你想将 1% 的流量发送到版本 B,那么我们就需要有一个运行版本 B 的 Pod 和 99 个运行版本 A 的 Pod,当然如果你对具体的控制策略不在意的话也就无所谓了,如果你需要更精确的控制策略,建议使用服务网格(如 Istio),它们可以更好地控制流量。

在这里插入图片描述

2.5.3.5 扩展:A/B测试(A/B testing)

最适合部分用户的功能测试

A/B 测试实际上是一种基于统计信息而非部署策略来制定业务决策的技术,与业务结合非常紧密。但是它们也是相关的,也可以使用金丝雀发布来实现。

除了基于权重在版本之间进行流量控制之外,A/B 测试还可以基于一些其他参数(比如 Cookie、User Agent、地区等等)来精确定位给定的用户群,该技术广泛用于测试一些功能特性的效果,然后按照效果来进行确定。

我们经常可以在今日头条的客户端中就会发现有大量的 A/B 测试,同一个地区的用户看到的客户端有很大不同。

要使用这些细粒度的控制,仍然还是建议使用 Istio,可以根据权重或 HTTP 头等来动态请求路由控制流量转发。

总结AB测试:
如果你的公司需要在特定的用户群体中进行新功能的测试,例如,移动端用户请求路由到版本 A,桌面端用户请求路由到版本 B,那么你就看使用A/B 测试,通过使用 Kubernetes 服务网关的配置,可以根据某些请求参数来确定用户应路由的服务。

在这里插入图片描述

2.5 Service(svc)

官方文档:https://v1-26.docs.kubernetes.io/zh-cn/docs/concepts/services-networking/service/#service-in-k8s

2.5.1 简介

由于pod重建之后ip就变了,因此 pod之间使用pod的IP直接访问会 出现无法访问的问题,而service则解耦了服务和应用,service的实现方式就是通过label标签动态匹配后端endpoint。

kube-proxy监听着k8s-apiserver, 一旦service资源发生变化(调k8s-api修改service信息),kube- proxy就会生成对应的ipvs\iptables规则,这样就保证service的最新状态。

kube-proxy有三种调度模型:
(1)userspace:k8s1.1之前
(2)iptables:1.2-k8s1.11之前
(3)ipvs:k8s 1.11之后,如果没有开启ipvs,则自动降级为iptables

2.5.2 svc类型介绍

(1)ClusterIP:默认类型,用于内部服务基于service name的访问,仅在k8s内部可用。
(2)NodePort:用于kubernetes集群以外的服务主动访问运行在kubernetes集群内部的服务(通过在宿主机生成一个端口,来让外部能够通过该端口访问集群内部的pod)。
(3)LoadBalancer:用于公有云环境的服务暴露,一般是公有云负载均衡把请求转给nodeport,再由nodeport把请求转给clusterIP,clusterIP再把请求转给pod。
(4)ExternalName:用于将k8s集群外部的服务映射至k8s集群内部访问,从而让集群内部的pod能够通过固定的service name访问集群外部的服务,有时候也用于将不同namespace之间的pod通过ExternalName进行访问。
(5)Headless Services(无头服务):有时不需要或不想要负载均衡,以及单独的 Service IP。 遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP)的值为 “None” 来创建 Headless Service。
对于无头 Services 并不会分配 Cluster IP,kube-proxy 不会处理它们, 而且平台也不会为它们进行负载均衡和路由。 DNS 如何实现自动配置,依赖于 Service 是否定义了标签选择器。

2.5.3 演示

先创建一个演示服务

[root@k8s-harbor01 deployment]# cat deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels: #rs or deployment
      app: ng-deploy-svc-test
  template:
    metadata:
      labels:
        app: ng-deploy-svc-test
    spec:
      containers:
      - name: ng-deploy-80
        image: nginx
        ports:
        - containerPort: 8

[root@k8s-harbor01 deployment]# kubectl apply -f deploy.yaml
deployment.apps/nginx-deployment created

[root@k8s-harbor01 deployment]# kubectl get po  |grep nginx-depl
nginx-deployment-588b464fc5-f22p5         1/1     Running     0             45s
nginx-deployment-588b464fc5-h27r6         1/1     Running     0             45s
[root@k8s-harbor01 deployment]# 
2.5.3.1 无svc

创建的pod没有service时,我们可以在集群内部直接访问pod ip。
但是pod ip会随着pod的更新而变化,所以这种方式不推荐使用。

[root@k8s-master01 ~]# kubectl get po -o wide |grep nginx-depl
nginx-deployment-588b464fc5-f22p5         1/1     Running     0             3m12s   10.200.58.211    k8s-node02   <none>           <none>
nginx-deployment-588b464fc5-h27r6         1/1     Running     0             3m12s   10.200.85.204    k8s-node01   <none>           <none>
[root@k8s-master01 ~]# curl -I 10.200.58.211
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Sun, 14 May 2023 08:46:03 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 28 Dec 2021 15:28:38 GMT
Connection: keep-alive
ETag: "61cb2d26-267"
Accept-Ranges: bytes
2.5.3.2 ClusterIP类型的svc

集群内部访问

[root@k8s-master01 yaml]# cat nginx-deploy-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: ng-deploy
spec:
  ports:
  - name: http 
    port: 80 # svc的端口,可以和targetPort不同
    targetPort: 80 # 目的容器端口
    protocol: TCP # svc使用的协议
  type: ClusterIP # svc的类型
  #clusterIP: 10.100.21.199 # 指定clusterip,但是一般不会这么做
  selector:
    app: ng-deploy-svc-test # 这里写pod的标签


[root@k8s-master01 yaml]# kubectl get svc |grep ng-deploy
ng-deploy    ClusterIP   10.100.251.44   <none>        80/TCP    29s

[root@k8s-master01 yaml]# kubectl describe svc ng-deploy
Name:              ng-deploy
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=ng-deploy-svc-test
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.100.251.44
IPs:               10.100.251.44
Port:              http  80/TCP
TargetPort:        80/TCP
Endpoints:         10.200.58.211:80,10.200.85.204:80 # 只有svc标签选择器和pod标签匹配上了,pod才能注册到svc的Endpoint中,我们才能访问到
Session Affinity:  None
Events:            <none>

[root@k8s-master01 yaml]# curl -I 10.100.251.44
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Sun, 14 May 2023 08:54:54 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 28 Dec 2021 15:28:38 GMT
Connection: keep-alive
ETag: "61cb2d26-267"
Accept-Ranges: bytes
2.5.3.3 NodePort类型的svc

集群外部访问

[root@k8s-master01 yaml]# cat nginx-deploy-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: ng-deploy-nodeport
spec:
  ports:
  - name: http
    port: 81
    targetPort: 80
    nodePort: 30012 # 这个端口可以不指定,不指定的话会随机分配一个端口
    protocol: TCP
  type: NodePort
  selector:
    app: ng-deploy-svc-test

[root@k8s-master01 yaml]# kubectl apply -f nginx-deploy-nodeport.yaml
service/ng-deploy-nodeport created
[root@k8s-master01 yaml]# kubectl get svc |grep ng-deploy
ng-deploy            ClusterIP   10.100.251.44   <none>        80/TCP         7m6s
ng-deploy-nodeport   NodePort    10.100.51.123   <none>        81:30012/TCP   4s

[root@k8s-master01 yaml]# curl -I 10.31.200.102:30012
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Sun, 14 May 2023 09:00:16 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 28 Dec 2021 15:28:38 GMT
Connection: keep-alive
ETag: "61cb2d26-267"
Accept-Ranges: bytes
2.5.3.4 LoadBalancer类型的svc

这里由于我没有云上环境,就大概描述下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.5.3.5 ExternalName类型的svc
root@master1 Ingress-case-20230611-backup]# cat 0.2.externalName.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-external-test-name
spec:
  type: ExternalName  #service类型
  externalName: www.magedu.com   #外部域名

[root@master1 Ingress-case-20230611-backup]# kubectl apply -f 0.2.externalName.yaml
service/my-external-test-name created
[root@master1 Ingress-case-20230611-backup]# kubectl get svc
NAME                    TYPE           CLUSTER-IP   EXTERNAL-IP      PORT(S)   AGE
kubernetes              ClusterIP      10.200.0.1   <none>           443/TCP   3d23h
my-external-test-name   ExternalName   <none>       www.magedu.com   <none>    3s

[root@master1 Ingress-case-20230611-backup]# kubectl get po
NAME               READY   STATUS    RESTARTS   AGE
centos-net-test1   1/1     Running   0          44h
[root@master1 Ingress-case-20230611-backup]# kubectl exec -it centos-net-test1 -- /bin/bash
[root@centos-net-test1 /]# yum -y install bind-utils

[root@centos-net-test1 /]# nslookup my-external-test-name 
Server:         10.200.0.10
Address:        10.200.0.10#53

my-external-test-name.default.svc.cluster.local canonical name = www.magedu.com. # 通过域名解析可以发现,my-external-test-name就是做了一个caname记录,再解析到了百度的域名
Name:   www.magedu.com
Address: 114.116.196.150

2.5.3.6 手动绑定svc和endpoint

这种方式用的不多,相当于也是一种引入集群外部服务到内部的方式
在这里插入图片描述

2.6 Volume-存储卷

2.6.1 简介

官网地址:https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/

Volume将容器中的指定目录数据和容器解耦,并将数据存储到指定的位置,不同的存储卷功能不一样,如果是基于网络存储的存储卷可实现容器间的数据共享和持久化。
卷还分为动态和静态,静态存储卷需要在使用前手动创建PV和PVC,然后绑定至pod使用。

2.6.2 常用的几种卷

官网:https://kubernetes.io/zh/docs/concepts/storage/volumes/
kubectl explain deployment.spec.template.spec.volumes

(1)Secret:是一种包含少量敏感信息(例如密码、令牌或密钥)的对象。
(2)configmap: 配置文件。
(3)emptyDir:本地临时卷(pod在哪个主机,数据就临时持久化到哪个主机,一旦pod删除,临时卷也会被删除)。
(4)hostPath:本地存储卷(跟上面一样,但是pod被删除后,数据不会被删除。)。
(5)nfs等:网络存储卷。

2.6.3 emptyDir

官方文档:https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/#emptydir

2.6.3.1 简介

当Pod被分配给节点时,首先创建emptyDir卷,并且只要该Pod在该节点上运行,该卷就会存在。
正如卷的名字所述,它最初是空的,Pod中的容器可以读取和写入emptyDir 卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上。
当出于任何原因从节点中删除Pod时,emptyDir中的数据将被永久删。

在这里插入图片描述

2.6.3.2 演示
# emptydir参数
[root@k8s-harbor01 valume]# kubectl explain deployment.spec.template.spec.volumes.emptyDir
KIND:     Deployment
VERSION:  apps/v1

RESOURCE: emptyDir <Object>

DESCRIPTION:
     emptyDir represents a temporary directory that shares a pod's lifetime.
     More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir

     Represents an empty directory for a pod. Empty directory volumes support
     ownership management and SELinux relabeling.

FIELDS:
   medium       <string> # 设置这个参数,可以让数据存储到宿主机磁盘,还是宿主机内存中
     medium represents what type of storage medium should back this directory.
     The default is "" which means to use the node's default medium. Must be an
     empty string (default) or Memory. More info:
     https://kubernetes.io/docs/concepts/storage/volumes#emptydir
 
   sizeLimit    <string> # 设置临时卷的大小
     sizeLimit is the total amount of local storage required for this EmptyDir
     volume. The size limit is also applicable for memory medium. The maximum
     usage on memory medium EmptyDir would be the minimum value between the
     SizeLimit specified here and the sum of memory limits of all containers in
     a pod. The default is nil which means that the limit is undefined. More
     info: http://kubernetes.io/docs/user-guide/volumes#emptydir

# yaml
[root@k8s-harbor01 valume]# cat emptyDir.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels: #rs or deployment
      app: ng-deploy-80
  template:
    metadata:
      labels:
        app: ng-deploy-80
    spec:
      containers:
      - name: ng-deploy-80
        image: 10.31.200.104/myserver/nginx:latest
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /cache
          name: cache-volume
      volumes:
      - name: cache-volume
        emptyDir: {}


# 创建
[root@k8s-harbor01 valume]# kubectl apply -f emptyDir.yaml 
deployment.apps/nginx-deployment created

# 查看
[root@k8s-harbor01 valume]# kubectl get po |grep nginx-deploy
nginx-deployment-6898958d59-gftsx         1/1     Running     0            14s

# 查看pod的临时目录
[root@k8s-harbor01 valume]# kubectl get po -o wide |grep nginx-deploy
nginx-deployment-6898958d59-gftsx         1/1     Running     0            3m3s    10.200.85.223    k8s-node01   <none>           <none>
[root@k8s-harbor01 valume]# ssh k8s-node01
Last login: Tue May 16 16:47:54 2023 from k8s-harbor01
[root@k8s-node01 ~]# find / -name cache-volume
/var/lib/kubelet/pods/76c47036-3c31-47a5-879b-1193b090818f/volumes/kubernetes.io~empty-dir/cache-volume
/var/lib/kubelet/pods/76c47036-3c31-47a5-879b-1193b090818f/plugins/kubernetes.io~empty-dir/cache-volume
[root@k8s-node01 ~]# ll /var/lib/kubelet/pods/76c47036-3c31-47a5-879b-1193b090818f/
总用量 4
drwxr-x--- 3 root root  26 518 13:41 containers
-rw-r--r-- 1 root root 231 518 13:41 etc-hosts
drwxr-x--- 3 root root  37 518 13:41 plugins
drwxr-x--- 4 root root  68 518 13:41 volumes

# 为什么volume会生成在kubelet目录下,因为是kubelet去调用宿主机内核来完成volume的挂载的。

# 在容器中生成一些数据,看是否会持久化到宿主机
[root@k8s-harbor01 valume]# kubectl exec -it nginx-deployment-6898958d59-gftsx -- /bin/bash
root@nginx-deployment-6898958d59-gftsx:/cache# echo 'emptydir-volumelslslslsls!' > emptydir.log
root@nginx-deployment-6898958d59-gftsx:/cache# cat emptydir.log
emptydir-volumelslslslsls!

# 宿主机查看数据
[root@k8s-harbor01 valume]# !ss
ssh k8s-node01
[root@k8s-node01 ~]# cat /var/lib/kubelet/pods/76c47036-3c31-47a5-879b-1193b090818f/volumes/kubernetes.io~empty-dir/cache-volume/emptydir.log 
emptydir-volumelslslslsls!

# 删除pod
[root@k8s-harbor01 valume]# kubectl delete po nginx-deployment-6898958d59-gftsx
pod "nginx-deployment-6898958d59-gftsx" deleted

# 查看数据
[root@k8s-harbor01 valume]# !ss
ssh k8s-node01
Last login: Thu May 18 13:52:05 2023 from k8s-harbor01
[root@k8s-node01 ~]# !cat
cat /var/lib/kubelet/pods/76c47036-3c31-47a5-879b-1193b090818f/volumes/kubernetes.io~empty-dir/cache-volume/emptydir.log 
cat: /var/lib/kubelet/pods/76c47036-3c31-47a5-879b-1193b090818f/volumes/kubernetes.io~empty-dir/cache-volume/emptydir.log: 没有那个文件或目录

2.6.4 hostPath

官方文档:https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/#hostpath

2.6.4.1 简介

hostPath卷将主机节点上的文件系统中的文件或目录挂载到集群中,pod删除的时候,卷不会被删除(把宿主机文件挂载到容器中)。

在这里插入图片描述

2.6.4.2 演示
# 准备yaml
[root@k8s-harbor01 valume]# cat hostPath.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ng-deploy-80
  template:
    metadata:
      labels:
        app: ng-deploy-80
    spec:
      containers:
      - name: ng-deploy-80
        image: nginx 
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /cache
          name: cache-volume
      volumes:
      - name: cache-volume
        hostPath:
          path: /data/kubernetes # 宿主机上如果没有这路径,会由kubelet创建

# 删除之前的emptyDir
[root@k8s-harbor01 valume]# kubectl delete -f emptyDir.yaml 
deployment.apps "nginx-deployment" deleted

# 创建hostPath类型的deploy
[root@k8s-harbor01 valume]# kubectl apply -f hostPath.yaml 
deployment.apps/nginx-deployment created
[root@k8s-harbor01 valume]# kubectl get po -o wide |grep nginx-deploy
nginx-deployment-b8587d7c-9k2v6           1/1     Running             0            61s    10.200.58.241    k8s-node02   <none>           <none>

# 进入pod创建文件
[root@k8s-harbor01 valume]# kubectl exec -it nginx-deployment-b8587d7c-9k2v6 -- /bin/bash
root@nginx-deployment-b8587d7c-9k2v6:/# cd cache/
root@nginx-deployment-b8587d7c-9k2v6:/cache# ls
root@nginx-deployment-b8587d7c-9k2v6:/cache# echo 'hostPath test !!!!' > hostPath.log
root@nginx-deployment-b8587d7c-9k2v6:/cache# cat hostPath.log
hostPath test !!!!
root@nginx-deployment-b8587d7c-9k2v6:/cache# exit
exit

# 宿主机查看持久化情况
[root@k8s-harbor01 valume]# ssh k8s-node02
Last login: Tue Apr 25 10:25:31 2023 from k8s-harbor01
[root@k8s-node02 ~]# cat /data/kubernetes/hostPath.log 
hostPath test !!!!

# 删除pod
[root@k8s-harbor01 valume]# kubectl delete po nginx-deployment-b8587d7c-9k2v6
pod "nginx-deployment-b8587d7c-9k2v6" deleted

# 再次查看宿主机上的数据
[root@k8s-harbor01 valume]# !ss
ssh k8s-node02
Last login: Thu May 18 14:12:20 2023 from k8s-harbor01
[root@k8s-node02 ~]# !cat
cat /data/kubernetes/hostPath.log 
hostPath test !!!!  # 文件还是在的
2.6.4.3 其他可选的参数

在这里插入图片描述

2.6.5 NFS网络共享存储

2.6.5.1 简介

nfs卷允许将现有的NFS(网络文件系统)挂载到容器中,且不像emptyDir会丢失数据。
当删除Pod时,nfs 卷的内容被保留,卷仅仅是被卸载,这意味着NFS卷可以预先上传好数据待pod启动后即可直接使用。
并且网络存储可以在多pod之间共享同一份数据,即NFS可以被多个pod同时挂载和读写。

在这里插入图片描述

2.6.5.2 安装nfs

我这里安装在harbor上

[root@k8s-harbor01 ~]# yum -y install nfs-utils rpcbind
2.6.5.3 创建共享目录并进行相关权限配置
[root@k8s-harbor01 ~]# mkdir /data/k8s-data
[root@k8s-harbor01 ~]# cat /etc/exports
/data/k8s-data *(rw,no_root_squash)

[root@k8s-harbor01 ~]# systemctl start rpcbind.service
[root@k8s-harbor01 ~]# systemctl enable rpcbind.service
[root@k8s-harbor01 ~]# systemctl start nfs
[root@k8s-harbor01 ~]# systemctl enable nfs

[root@k8s-harbor01 ~]# showmount -e 10.31.200.104
Export list for 10.31.200.104:
/data/k8s-data *

# 测试挂载
[root@k8s-harbor01 ~]# mount -t nfs 10.31.200.104:/data/k8s-data /mnt
[root@k8s-harbor01 ~]# df -h|grep mnt
10.31.200.104:/data/k8s-data   50G   15G   36G   29% /mnt
2.6.5.4 编辑yaml并使用nfs存储

一个pod中,还可以存在多个不同类型的卷

[root@k8s-harbor01 valume]# cat nfs.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ng-deploy-80
  template:
    metadata:
      labels:
        app: ng-deploy-80
    spec:
      containers:
      - name: ng-deploy-80
        image: nginx 
        ports:
        - containerPort: 80
        volumeMounts: # 容器的挂载配置
        - mountPath: /usr/share/nginx/html/mysite # 挂载容器的这个目录。不存在的目录会自动创建
          name: my-nfs-volume
      volumes:  # 这里
      - name: my-nfs-volume
        nfs: # 使用nfs类型的存储
          server: 10.31.200.104 # nfs的IP地址
          path: /data/k8s-data # nfs共享的目录。容器的数据就会存储到宿主机的这里

---
apiVersion: v1
kind: Service
metadata:
  name: ng-deploy-80
spec:
  ports:
  - name: http
    port: 81
    targetPort: 80
    nodePort: 30016
    protocol: TCP
  type: NodePort
  selector:
    app: ng-deploy-80

[root@k8s-harbor01 valume]# kubectl apply -f nfs.yaml
deployment.apps/nginx-deployment configured
service/ng-deploy-80 created

[root@k8s-harbor01 valume]# kubectl get po
NAME                                READY   STATUS        RESTARTS   AGE
nginx-deployment-5bf9747df-kmbhm    1/1     Running       0          66s
2.6.5.5 上传一张图片到nfs共享目录下
[root@k8s-harbor01 k8s-data]# ls
kong.png
[root@k8s-harbor01 k8s-data]# chmod 644 kong.png 
[root@k8s-harbor01 k8s-data]# ll
总用量 4
-rw-r--r-- 1 root root 1812 518 09:45 kong.png
2.6.5.6 访问测试

在这里插入图片描述

2.7 PV/PVC

2.7.1 简介

不同存储卷支持的访问
模式:
https://v1-22.docs.kubernetes.io/zh/docs/concepts/storage/persistent-volumes/

PV:PersistentVolume(用来实现csi,主要负责和后端存储对接)
PVC:PersistentVolumeClaim(主要负责和pod进行绑定)
用于实现pod和storage的解耦,这样我们修改storage的时候不需要修改pod。
与NFS的区别,可以在PV和PVC层面实现实现对存储服务器的空间分配、存储的访问权限管理等。
kubernetes 从1.0版本开始支持PersistentVolume和PersistentVolumeClaim。

2.7.1.1 pv

是集群中已经由kubernetes管理员配置的一个网络存储,是集群中的存储资源(集群级别的),即不隶属于任何namespace。

PV的数据最终存储在硬件存储,pod不能直接挂载PV,PV需要绑定给PVC并最终由pod挂载PVC使用。
PV其支持NFS、Ceph、商业存储或云提供商的特定的存储等,可以自定义PV的类型是块还是文件存储、存储空间大小、访问模式等。

PV的生命周期独立于Pod,即当使用PV的Pod被删除时可以对PV中的数据没有影响。

2.7.1.2 pvc

是pod对存储的请求, pod挂载PVC并将数据存储在PVC,而PVC需要绑定到PV才能使用,另外PVC在创建的时候要指定namespace,即pod要和PVC运行在同一个namespace。
可以对PVC设置特定的空间大小和访问模式,使用PVC的pod在删除时也可以对PVC中的数据没有影响。

2.7.2 pvc和存储的关系

比如启动一个pod,它并不是直接挂载存储,而是挂载到pvc上,但是pvc是一个逻辑的存储对象,它是不负责存储数据的,那么存储数据由谁负责呢?
那就是pv,由pv来和存储对接,如nfs、nas、ceph等。
我们需要先在存储上创建好所需的目录,然后创建pv和存储对接,再创建pvc,最后pod才能顺利挂载pvc。
但上面说的是静态存储,后面会讲动态存储,pv和pvc就不用自己手动创建了。

在这里插入图片描述

2.7.3 PV/PVC总结

PV是对底层网络存储的抽象,即将网络存储定义为一种存储资源,将一个整体的存储资源拆分成多份后给不同的业务使用。
PVC是对PV资源的申请调用,pod是通过PVC将数据保存至PV,PV再把数据保存至真正的硬件存储。

在这里插入图片描述

2.7.4 PersistentVolume参数介绍

(1)Capacity: #当前PV空间大小,不能大于后端存储的可用空间。kubectl explain PersistentVolume.spec.capacity

(2)accessModes :访问模式。#kubectl explain PersistentVolume.spec.accessModes
ReadWriteOnce – PV只能被单个节点以读写权限挂载,RWO
ReadOnlyMany – PV以可以被多个节点挂载,但是权限是只读的,ROX
ReadWriteMany – PV可以被多个节点是读写方式挂载使用,RWX
ReadWriteOncePod - PV可以被单个pod以读写方式挂载。该模式只支持CSI卷并且k8s集群版本需要在1.22以上。

应用场景:
ReadWriteOnce:RWO,用于有状态服务使用,如mysql主从、Redis Cluster等。
ReadOnlyMany:ROX,用于多个pod需要读同一份数据,如nginx读取静态文件等。
ReadWriteMany:RWX,用于多个pod需要读写同一份数据的场景,如java微服务。

一般用的最多的就是前三种模式。

(3)persistentVolumeReclaimPolicy #删除机制。即删除存储卷的时候,已经创建好的存储卷有以下删除操作:
Retain – 手动创建pv时的默认策略,删除PV后保持原装,最后需要管理员手动删除。
Recycle – 空间回收。当用户不再使用其存储卷时,他们可以从 API 中将 PVC 对象删除, 从而允许该资源被回收再利用。仅支持NFS和hostPath。目前已经被废弃。
Delete – 动态创建pv的默认策略,会自动删除后端存储中的数据。

(4)volumeMode #卷类型,kubectl explain PersistentVolume.spec.volumeMode。定义存储卷使用的卷模式是文件系统(Filesystem)还是块设备(Block),默认为文件系统(Filesystem)。
什么时候用块设备?什么时候用文件系统?
如nginx和java服务挂载,凡是设计到一个卷被多个pod挂载的,都是文件系统。
如有状态服务,一个卷只被单个pod挂载,一般都是用块设备,但是也可以是文件系统。

一个卷被单个pod挂载,那么它的类型可以是块设备或者文件系统。
一个卷被多个pod挂载,那么它的类型一定是文件系统。

(5)mountOptions #附加的挂载选项列表,实现更精细的权限控制。
ro #等

2.7.4.1 不同的后端存储类型所支持的PV访问模式

官方文档:https://kubernetes.io/zh/docs/concepts/storage/persistent-volumes/
在这里插入图片描述

2.7.5 PersistentVolumeClaim参数介绍

(1)accessModes:# PVC 访问模式,一般情况下,pv和pvc的访问模式是一样的。#kubectl explain PersistentVolumeClaim.spec.volumeMode
ReadWriteOnce – PVC只能被单个节点以读写权限挂载,RWO
ReadOnlyMany – PVC以可以被多个节点挂载但是权限是只读的,ROX
ReadWriteMany – PVC可以被多个节点是读写方式挂载使用,RWX

(2)resources: #定义PVC创建存储卷的空间大小

(3)selector: #标签选择器,选择要绑定的PV
matchLabels #匹配标签名称(精确匹配)
matchExpressions #基于正则表达式匹配(模糊匹配)

(4)volumeName #要绑定的PV名,就是指定该pvc要和哪个pv绑定到一起。

(5)volumeMode #卷类型
定义PVC使用的文件系统是块设备还是文件系统,默认为文件系统

2.7.6 Volume-存储卷类型

2.7.6.1 静态存储卷

static:静态存储卷 ,需要在使用前手动创建PV、然后创建PVC并绑定到PV, 然后挂载至pod使用,适用于PV和PVC相对比较固定的业务场景。

2.7.6.2 动态存储卷

dynamin:动态存储卷,先创建一个存储类storageclass,后期pod在使用PVC的时候可以通过存储类动态创建PVC,适用于有状态服务集群如MySQL一主多从、 zookeeper集群等。

在这里插入图片描述

2.7.7 Volume-静态存储卷示例

2.7.7.1 后端存储创建所需目录
[root@k8s-harbor01 ~]# mkdir /data/k8s-data/myserver/myappdata -p
[root@k8s-harbor01 ~]# vim /etc/exports
[root@k8s-harbor01 ~]# cat /etc/exports
/data/k8s-data *(rw,no_root_squash)
/data/k8s-data/myserver/myappdata *(rw,no_root_squash) # 这一条其实不用写,因为/data/k8s-data下的目录都能被挂载
[root@k8s-harbor01 ~]# systemctl restart nfs-server && systemctl enable nfs-server
2.7.7.2 创建PV
# 创建pv
[root@k8s-harbor01 volume]# cat pv.yaml
apiVersion: v1
kind: PersistentVolume # 资源类型
metadata: # 资源类型元数据
  name: myserver-myapp-static-pv # pv名称
spec:
  capacity: # 容量
    storage: 10Gi # 分配的可用存储空间为10G
  accessModes: # 访问模式
    - ReadWriteOnce # PV只能被单个节点以读写权限挂载,RWO
  nfs: # pv类型
    path: /data/k8s-data/myserver/myappdata # 挂载路径
    server: 10.31.200.104 # nfs地址

[root@k8s-harbor01 volume]# kubectl apply -f pv.yaml 
persistentvolume/myserver-myapp-static-pv created
[root@k8s-harbor01 volume]# kubectl get pv
NAME                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
myserver-myapp-static-pv   10Gi       RWO            Retain           Available                                   4s
2.7.7.3 创建PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myserver-myapp-static-pvc
  namespace: myserver
spec:
  volumeName: myserver-myapp-static-pv # 这里一定要写对pv的名称,不然绑定不上。
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi # 这里的容量不能比pv上分配的容量大,不然创建后无法和pv进行绑定。

[root@k8s-harbor01 volume]# kubectl get pvc -n myserver # 创建后注意查看STATUS这列,只有状态为Bound才表示和pv绑定成功,并且还要看VOLUME这里,看看绑定的pv对不对。
NAME                        STATUS   VOLUME                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
myserver-myapp-static-pvc   Bound    myserver-myapp-static-pv   10Gi       RWO                           11s
2.7.7.4 创建web服务
[root@k8s-harbor01 volume]# cat deploy-volume.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    app: myserver-myapp 
  name: myserver-myapp-deployment-name
  namespace: myserver
spec:
  replicas: 1 
  selector:
    matchLabels:
      app: myserver-myapp-frontend
  template:
    metadata:
      labels:
        app: myserver-myapp-frontend
    spec:
      containers:
        - name: myserver-myapp-container
          image: nginx:1.20.0 
          #imagePullPolicy: Always
          volumeMounts:
          - mountPath: "/usr/share/nginx/html/statics"
            name: statics-datadir #容器挂载的卷的名称
      volumes: # pod提供的卷
        - name: statics-datadir # pvc的名称
          persistentVolumeClaim: #类型为pvc
            claimName: myserver-myapp-static-pvc  # pvc的名称

---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: myserver-myapp-service
  name: myserver-myapp-service-name
  namespace: myserver
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30080
  selector:
    app: myserver-myapp-frontend

[root@k8s-harbor01 volume]# kubectl apply -f deploy-volume.yaml
deployment.apps/myserver-myapp-deployment-name created
service/myserver-myapp-service-name created
[root@k8s-harbor01 volume]# kubectl get po -n myserver|grep myapp-deploy
myserver-myapp-deployment-name-b7cfb8476-qqvp4   1/1     Running   0          29s
[root@k8s-harbor01 volume]# kubectl exec -it -n myserver myserver-myapp-deployment-name-b7cfb8476-qqvp4 -- /bin/bash
root@myserver-myapp-deployment-name-b7cfb8476-qqvp4:/# df -h
Filesystem                                       Size  Used Avail Use% Mounted on
overlay                                           50G  5.3G   45G  11% /
tmpfs                                             64M     0   64M   0% /dev
tmpfs                                            2.0G     0  2.0G   0% /sys/fs/cgroup
shm                                               64M     0   64M   0% /dev/shm
/dev/sda2                                         50G  5.3G   45G  11% /etc/hosts
tmpfs                                            3.6G   12K  3.6G   1% /run/secrets/kubernetes.io/serviceaccount
10.31.200.104:/data/k8s-data/myserver/myappdata   50G   15G   36G  29% /usr/share/nginx/html/statics # 这就是容器通过pvc挂载的nfs存储
tmpfs                                            2.0G     0  2.0G   0% /proc/acpi
tmpfs                                            2.0G     0  2.0G   0% /proc/scsi
tmpfs                                            2.0G     0  2.0G   0% /sys/firmware

[root@k8s-harbor01 volume]# curl  10.31.200.101:30080
<!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>
2.7.7.5 生成测试数据
[root@k8s-harbor01 volume]# kubectl exec -it -n myserver myserver-myapp-deployment-name-b7cfb8476-qqvp4 -- /bin/bash
root@myserver-myapp-deployment-name-b7cfb8476-qqvp4:/# cd /usr/share/nginx/html/statics/
root@myserver-myapp-deployment-name-b7cfb8476-qqvp4:/usr/share/nginx/html/statics# echo 'pv/pvc test' > index.html
root@myserver-myapp-deployment-name-b7cfb8476-qqvp4:/usr/share/nginx/html/statics# cat index.html
pv/pvc test
2.7.7.6 验证存储数据
[root@k8s-harbor01 volume]# cat /data/k8s-data/myserver/myappdata/index.html 
pv/pvc tes
2.7.7.7 访问测试数据
[root@k8s-harbor01 volume]# curl  10.31.200.101:30080/statics/index.html
pv/pvc test
2.7.7.8 删除pv/pvc
# 删除的时候一定不要直接删除目录,按照我们创建时的相反步骤进行
kubectl delete -f deploy-volume.yaml 
kubectl delete -f pvc.yaml 
kubectl delete -f pv.yaml 

2.7.8 Volume-动态存储卷示例

官方文档:https://v1-26.docs.kubernetes.io/zh-cn/docs/concepts/storage/storage-classes/
自动实现我们操作静态存储的步骤

2.7.8.1 创建账户并授权
[root@k8s-harbor01 volume]# cat rbac.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: nfs # 创建一个名为nfs的ns
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner # 账号名称,同时也是nfs提供者
  namespace: nfs
---
kind: ClusterRole # 集群角色
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["nodes"] # 操作对象
    verbs: ["get", "list", "watch"] # 操作权限
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding # 角色绑定
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner # 绑定账号,账号和角色相绑定,就拥有了角色配置的权限
    # replace with namespace where provisioner is deployed
    namespace: nfs
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner # 绑定角色
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: nfs
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: nfs
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: nfs
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io


[root@k8s-harbor01 volume]# kubectl apply -f rbac.yaml
namespace/nfs created
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
2.7.8.2 创建存储类
[root@k8s-harbor01 volume]# cat sc.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
  #annotaions: #默认存储类配置。创建完毕后name旁边会多一个(default)
    #storageclass.kubernetes.io/is-default-class: "true"
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # 提供者。这个等下需要额外创建。因为nfs在k8s动态存储中,没有内置制备器。
reclaimPolicy: Retain #PV的删除策略,默认为delete,删除PV后立即删除NFS server的数据
mountOptions: # 挂载选项,不同类型的后端存储都有不同的挂载选项,并不是通用的。
  #- vers=4.1 #containerd有部分参数异常
  #- noresvport #告知NFS客户端在重新建立网络连接时,使用新的传输控制协议源端口(nfs宕机后,重新建立挂载关系)
  - noatime #访问文件时不更新文件inode中的时间戳,高并发环境可提高性能
parameters:
  #mountOptions: "vers=4.1,noresvport,noatime"
  archiveOnDelete: "true"  #删除pod时保留pod数据,默认为false时为不保留数据

[root@k8s-harbor01 volume]# kubectl apply -f sc.yaml
storageclass.storage.k8s.io/managed-nfs-storage created
[root@k8s-harbor01 volume]# kubectl get sc
NAME                  PROVISIONER                                   RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
managed-nfs-storage   k8s-sigs.io/nfs-subdir-external-provisioner   Retain          Immediate           false                  14s

# 这个时候sc虽然创建好了,但是它并不能直接去操作nfs,而是会去找提供者(provisioner: k8s-sigs.io/nfs-subdir-external-provisioner)来进行相关操作。
2.7.8.3 创建提供者(nfs制备器)

官方文档:https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner/tree/master/deploy

[root@k8s-harbor01 volume]# cat nfs-provisioner.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: nfs
spec:
  replicas: 1
  strategy: #部署策略
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          #image: k8s.gcr.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2 
          image: registry.cn-qingdao.aliyuncs.com/zhangshijie/nfs-subdir-external-provisioner:v4.0.2 
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes # 这个配置不用改
          env:
            - name: PROVISIONER_NAME
              value: k8s-sigs.io/nfs-subdir-external-provisioner # 这个名称,必须和sc里面的提供者是一样的。
            - name: NFS_SERVER
              value: 10.31.200.104
            - name: NFS_PATH
              value: /data/volumes
      volumes:
        - name: nfs-client-root
          nfs:
            server: 10.31.200.104
            path: /data/volumes # 需要在nfs服务端创建该目录.提供者会连接到nfs的这个目录下,创建子目录来分配pv

# nfs服务端创建存储目录
[root@k8s-harbor01 volume]# mkdir /data/volumes
[root@k8s-harbor01 volume]# tail -1 /etc/exports
/data/volumes *(rw,no_root_squash)
[root@k8s-harbor01 volume]# systemctl restart nfs-server

[root@k8s-harbor01 volume]# kubectl apply -f nfs-provisioner.yaml 
deployment.apps/nfs-client-provisioner created
[root@k8s-harbor01 volume]# kubectl get po -A |grep nfs
nfs           nfs-client-provisioner-757b8bc9c-cp99s       1/1     Running   0             38s
2.7.8.4 创建pvc
[root@k8s-harbor01 volume]# cat pvc.yaml
# Test PVC
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: myserver-myapp-dynamic-pvc
  namespace: myserver
spec:
  storageClassName: managed-nfs-storage #调用的storageclass 名称。如果是默认存储类,可以不加名称这里的配置。但是随之而来也会有很多问题,那就是后期所有创建的pvpvc都会到这来。
  accessModes:
    - ReadWriteMany #访问权限
  resources:
    requests:
      storage: 500Mi #空间大小

# 数据目录创建过程就是pvc调用storageClass(nfs提供者),storageClass调用nfs来建好目录。

[root@k8s-harbor01 volume]# kubectl apply -f pvc.yaml
persistentvolumeclaim/myserver-myapp-dynamic-pvc created

[root@k8s-harbor01 volume]# kubectl get pvc -n myserver
NAME                         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
myserver-myapp-dynamic-pvc   Bound    pvc-aa016cd8-b84c-4759-8030-7ffdf5d1b43a   500Mi      RWX            managed-nfs-storage   19s
2.7.8.5 验证pv是否被自动创建
[root@k8s-harbor01 volume]# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                 STORAGECLASS          REASON   AGE
pvc-aa016cd8-b84c-4759-8030-7ffdf5d1b43a   500Mi      RWX            Retain           Bound    myserver/myserver-myapp-dynamic-pvc   managed-nfs-storage            71s


[root@k8s-harbor01 volume]# kubectl get pv -o yaml pvc-aa016cd8-b84c-4759-8030-7ffdf5d1b43a
apiVersion: v1
kind: PersistentVolume
metadata:
  annotations:
    pv.kubernetes.io/provisioned-by: k8s-sigs.io/nfs-subdir-external-provisioner # 就是他创建的pv
  creationTimestamp: "2023-05-21T09:13:48Z"
  finalizers:
  - kubernetes.io/pv-protection
  name: pvc-aa016cd8-b84c-4759-8030-7ffdf5d1b43a
  resourceVersion: "5566205"
  uid: c51ecca9-414c-4eb0-a728-40029a69ee2d
spec:
  accessModes:
  - ReadWriteMany
  capacity:
    storage: 500Mi
  claimRef:
    apiVersion: v1
    kind: PersistentVolumeClaim
    name: myserver-myapp-dynamic-pvc
    namespace: myserver
    resourceVersion: "5566201"
    uid: aa016cd8-b84c-4759-8030-7ffdf5d1b43a
  mountOptions:
  - noatime
  nfs:
    path: /data/volumes/myserver-myserver-myapp-dynamic-pvc-pvc-aa016cd8-b84c-4759-8030-7ffdf5d1b43a # nfs上的挂载路径
    server: 10.31.200.104
  persistentVolumeReclaimPolicy: Retain
  storageClassName: managed-nfs-storage
  volumeMode: Filesystem
status:
  phase: Bound


[root@k8s-harbor01 volume]# ll /data/volumes/myserver-myserver-myapp-dynamic-pvc-pvc-aa016cd8-b84c-4759-8030-7ffdf5d1b43a
总用量 0
2.7.8.6 创建web服务
[root@k8s-harbor01 volume]# cat deploy-volume.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
  labels:
    app: myserver-myapp 
  name: myserver-myapp-deployment-name
  namespace: myserver
spec:
  replicas: 1 
  selector:
    matchLabels:
      app: myserver-myapp-frontend
  template:
    metadata:
      labels:
        app: myserver-myapp-frontend
    spec:
      containers:
        - name: myserver-myapp-container
          image: nginx:1.20.0 
          #imagePullPolicy: Always
          volumeMounts:
          - mountPath: "/usr/share/nginx/html/statics"
            name: statics-datadir
      volumes:
        - name: statics-datadir
          persistentVolumeClaim:
            claimName: myserver-myapp-dynamic-pvc 

---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: myserver-myapp-service
  name: myserver-myapp-service-name
  namespace: myserver
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30080
  selector:
    app: myserver-myapp-frontend

[root@k8s-harbor01 volume]# kubectl apply -f deploy-volume.yaml
deployment.apps/myserver-myapp-deployment-name created
service/myserver-myapp-service-name created
[root@k8s-harbor01 volume]# kubectl get po -n myserver
NAME                                              READY   STATUS    RESTARTS   AGE
myserver-myapp-deployment-name-65ff65446f-9fnvx   1/1     Running   0          6s

[root@k8s-harbor01 volume]# kubectl exec -it -n myserver myserver-myapp-deployment-name-65ff65446f-9fnvx -- /bin/bash
root@myserver-myapp-deployment-name-65ff65446f-9fnvx:/# df -h
Filesystem                                                                                                Size  Used Avail Use% Mounted on
overlay                                                                                                    50G  5.4G   45G  11% /
tmpfs                                                                                                      64M     0   64M   0% /dev
tmpfs                                                                                                     2.0G     0  2.0G   0% /sys/fs/cgroup
shm                                                                                                        64M     0   64M   0% /dev/shm
/dev/sda2                                                                                                  50G  5.4G   45G  11% /etc/hosts
tmpfs                                                                                                     3.6G   12K  3.6G   1% /run/secrets/kubernetes.io/serviceaccount
10.31.200.104:/data/volumes/myserver-myserver-myapp-dynamic-pvc-pvc-aa016cd8-b84c-4759-8030-7ffdf5d1b43a   50G   15G   36G  29% /usr/share/nginx/html/statics # 容器中挂载的pvc
tmpfs                                                                                                     2.0G     0  2.0G   0% /proc/acpi
tmpfs                                                                                                     2.0G     0  2.0G   0% /proc/scsi
tmpfs                                                                                                     2.0G     0  2.0G   0% /sys/firmware
2.7.8.7 清理方式

也是按照创建的相反顺序

[root@k8s-harbor01 volume]# kubectl delete -f deploy-volume.yaml 
deployment.apps "myserver-myapp-deployment-name" deleted
service "myserver-myapp-service-name" deleted
[root@k8s-harbor01 volume]# kubectl delete -f pvc.yaml 
persistentvolumeclaim "myserver-myapp-dynamic-pvc" deleted
[root@k8s-harbor01 volume]# kubectl delete -f nfs-provisioner.yaml 
deployment.apps "nfs-client-provisioner" deleted
[root@k8s-harbor01 volume]# kubectl delete -f sc.yaml  # 一般情况下,删除到这里就行了
storageclass.storage.k8s.io "managed-nfs-storage" deleted
[root@k8s-harbor01 volume]# kubectl delete -f rbac.yaml 
namespace "nfs" deleted
serviceaccount "nfs-client-provisioner" deleted
clusterrole.rbac.authorization.k8s.io "nfs-client-provisioner-runner" deleted
clusterrolebinding.rbac.authorization.k8s.io "run-nfs-client-provisioner" deleted
role.rbac.authorization.k8s.io "leader-locking-nfs-client-provisioner" deleted
rolebinding.rbac.authorization.k8s.io "leader-locking-nfs-client-provisioner" deleted

2.7.9 volume和PV/PVC区别

(1)Volume:是Pod中使用的一段存储空间,可以是容器内的文件系统,也可以是主机上的一个目录或文件,当Pod从节点迁移到其他节点时,Volume的内容不会丢失。

(2)PersistentVolume(PV):是Kubernetes集群中的一段网络存储空间,可以是集群中的NFS、iSCSI、GCE Persistent Disk等存储设备。PV是由管理员管理并提供给用户使用的,支持多个Pod共享同一个PV,当Pod需要使用PV时,可以通过PVC来请求。

(3)PersistentVolumeClaim(PVC):是Pod对PV的一种声明,用来请求一定的存储空间并指定存储类别、访问模式等属性,当Pod需要使用PV时,需要先创建PVC,PVC会在PV池中选择合适的PV,并将其绑定为Pod的Volume。

因此,Volume是Pod中使用的一段存储空间,而PV/PVC则是Kubernetes集群中的一种动态的存储管理机制。而且PV/PVC可以实现存储资源的动态分配和管理,增强了Kubernetes集群的存储扩展性和灵活性。

2.7.10 pv/pvc流程详解

https://mp.weixin.qq.com/s/miCxuSbDwxJYTfBMzfUFvA

2.8 Configmap

cm热加载:https://github.com/jimmidyson/configmap-reload

2.8.1 简介

Configmap配置信息和镜像解耦, 实现方式为将配置信息放到configmap对象中,然后在pod的中作为Volume挂载到pod中,从而实现导入配置的目的。
需要注意的的是,cm是和pod在同一名称空间下的。

2.8.2 使用场景

(1)通过Configmap给pod定义全局环境变量。(这种方式用的不多,更多情况下是直接在deploy的yaml中,通过参数的方式传递的)
(2)通过Configmap给pod传递命令行参数,如mysql -u -p中的账户名密码可以通过Configmap传递。
(3)通过Configmap给pod中的容器服务提供配置文件,配置文件以挂载到容器的形式使用。

2.8.3 使用注意事项

(1)Configmap需要在pod使用它之前创建。
(2)pod只能使用位于同一个namespace的Configmap,即Configmap不能跨namespace使用。
(3)通常用于非安全加密的配置场景。
(4)Configmap通常是小于1MB的配置。

2.8.4 使用cm挂载nginx配置到pod中

2.8.4.1 创建cm
[root@k8s-harbor01 configmap]# cat nginx-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config # cm的名称,一般都是先创建好cm,再创建pod
data: # 数据。这个下面可以配置多个cm
 default: | # default为名称,这个是可以自定义的。|管道符是隔离开下面的配置
    server {  # 从这里开始就是nginx具体的配置信息
       listen       80;
       server_name  www.mysite.com;
       index        index.html index.php index.htm;

       location / {
           root /data/nginx/html;
           if (!-e $request_filename) {
               rewrite ^/(.*) /index.html last;
           }
       }
    }


[root@k8s-harbor01 configmap]# kubectl apply -f nginx-cm.yaml
configmap/nginx-config created
[root@k8s-harbor01 configmap]# kubectl get cm
NAME               DATA   AGE
nginx-config       1      4s
2.8.4.2 创建deploy
[root@k8s-harbor01 configmap]# cat nginx-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ng-deploy-80
  template:
    metadata:
      labels:
        app: ng-deploy-80
    spec:
      containers:
      - name: ng-deploy-80
        image: nginx:1.20.0
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /data/nginx/html
          name: nginx-static-dir
        - name: nginx-config
          mountPath:  /etc/nginx/conf.d # 这个挂载点不存在的话,会自动创建
      volumes:
      - name: nginx-static-dir # 第一个卷
        hostPath: # 使用的类型为hostpath
          path: /data/nginx/linux39
      - name: nginx-config
        configMap: # 这里就是挂载cm的配置了
          name: nginx-config # 这个名称要和cm的名称一样
          items: #配置项。如cm中的default
             - key: default #这个key,就是上面cm的名称
               path: mysite.conf # 上面cm中default下面的配置最终会挂载到这个文件中,这个文件是不存在的(不能存在,存在会报错)。那么这个文件放到哪个目录中呢?在上面,volumeMounts.name=nginx-config,会放到/etc/nginx/conf.d下,就等于是/etc/nginx/conf.d/mysite.conf


[root@k8s-harbor01 configmap]# kubectl apply -f nginx-deploy.yaml
deployment.apps/nginx-deployment created
[root@k8s-harbor01 configmap]# kubectl get po
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-65f49fcddd-kjvld   1/1     Running   0          36s
2.8.4.3 创建svc
[root@k8s-harbor01 configmap]# cat nginx-deploy-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: ng-deploy-80
spec:
  ports:
  - name: http
    port: 81
    targetPort: 80
    nodePort: 30019
    protocol: TCP
  type: NodePort
  selector:
    app: ng-deploy-80


[root@k8s-harbor01 configmap]# kubectl apply -f nginx-deploy-nodeport.yaml 
service/ng-deploy-80 created
[root@k8s-harbor01 configmap]# kubectl get svc
NAME           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
ng-deploy-80   NodePort    10.100.237.103   <none>        81:30019/TCP   3s
2.8.4.4 验证cm是否生效

验证conf.d下有没有mysite.conf

[root@k8s-harbor01 configmap]# kubectl exec -it nginx-deployment-65f49fcddd-kjvld -- /bin/bash             
root@nginx-deployment-65f49fcddd-kjvld:/# cat /etc/nginx/conf.d/mysite.conf  # 有这个文件就表示cm已经挂进来了
server {  # 从这里开始就是nginx具体的配置信息
   listen       80;
   server_name  www.mysite.com;
   index        index.html index.php index.htm;

   location / {
       root /data/nginx/html;
       if (!-e $request_filename) {
           rewrite ^/(.*) /index.html last;
       }
   }
}
2.8.4.5 修改cm配置

不建议直接edit cm,推荐通过修改yaml,然后apply应用,避免通过edit,后期apply yaml配置又还原了。

[root@k8s-harbor01 configmap]# cat nginx-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config # cm的名称,一般都是先创建好cm,再创建pod
data: # 数据。这个下面可以配置多个cm
 default: | # default为名称,这个是可以自定义的。|管道符是隔离开下面的配置
    server {  # 从这里开始就是nginx具体的配置信息
       listen       81; #修改cm中nginx的端口为81
       server_name  www.mysite.com;
       index        index.html index.php index.htm;

       location / {
           root /data/nginx/html;
           if (!-e $request_filename) {
               rewrite ^/(.*) /index.html last;
           }
       }
    }

[root@k8s-harbor01 configmap]# kubectl apply -f nginx-cm.yaml  # 这里如果想要配置生效,就需要重启pod
configmap/nginx-config configured

[root@k8s-harbor01 configmap]# vim nginx-deploy.yaml 
[root@k8s-harbor01 configmap]# grep '/data/nginx' nginx-deploy.yaml
        - mountPath: /data/nginx/html
          mountPath:  /data/nginx/conf.d # 修改一下配置文件挂载点,这个路径不存在会自动创建
          path: /data/nginx/linux39

[root@k8s-harbor01 configmap]# kubectl apply -f nginx-deploy.yaml
deployment.apps/nginx-deployment configured
2.8.4.6 验证cm是否生效
[root@k8s-harbor01 configmap]# kubectl exec -it nginx-deployment-5d88fdd89d-ckh4n -- /bin/bash
root@nginx-deployment-5d88fdd89d-ckh4n:/# cat /data/nginx/conf.d/mysite.conf 
server {  # 从这里开始就是nginx具体的配置信息
   listen       81;
   server_name  www.mysite.com;
   index        index.html index.php index.htm;

   location / {
       root /data/nginx/html;
       if (!-e $request_filename) {
           rewrite ^/(.*) /index.html last;
       }
   }
}

2.8.5 使用cm挂载变量到pod中

2.8.5.1 创建cm
[root@k8s-harbor01 configmap]# cat cm-env.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-env-config
data:
  username: "user1" #username 为key,"user1"为value。
  password: "12345678" # 关系同上

[root@k8s-harbor01 configmap]# kubectl apply -f cm-env.yaml
configmap/nginx-config created
[root@k8s-harbor01 configmap]# kubectl get cm|grep nginx-env-config
nginx-env-config   2      11s
2.8.5.2 创建deploy
[root@k8s-harbor01 configmap]# cat nginx-env-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-env-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ng-env-deploy-80
  template:
    metadata:
      labels:
        app: ng-env-deploy-80
    spec:
      containers:
      - name: ng-env-deploy-80
        image: nginx 
        env: # 通过env配置,在下面指定环境变量
        - name: MY_USERNAME # 容器中的变量名
          valueFrom: # 值的来源
            configMapKeyRef: # 来源与cm中的key
              name: nginx-env-config # 来源cm的名称
              key: username # 来源cm的key,对应的值就是user1
        - name: MY_PASSWORD
          valueFrom:
            configMapKeyRef:
              name: nginx-env-config
              key: password # 也是同上
        ###### 上面这种方式比较麻烦,更简单的则是下面这种方式,直接声明
        - name: "password" # 变量名
          value: "123456" # 变量值
        ports:
        - containerPort: 80

[root@k8s-harbor01 configmap]# kubectl apply -f nginx-env-deploy.yaml
deployment.apps/nginx-env-deployment created
2.8.5.3 检查cm是否生效
[root@k8s-harbor01 configmap]# kubectl exec -it nginx-env-deployment-759dff4758-b9pb8 -- /bin/bash
root@nginx-env-deployment-759dff4758-b9pb8:/# env|grep MY_USERNAME
MY_USERNAME=user1
root@nginx-env-deployment-759dff4758-b9pb8:/# env|grep MY_PASSWORD
MY_PASSWORD=12345678
root@nginx-env-deployment-759dff4758-b9pb8:/# env|grep password
password=123456

2.8.6 使用cm实现多网站配置

2.8.6.1 创建cm
[root@k8s-harbor01 configmap]# cat nginx-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  mysite: | # 一般工作中,这个名称都是和业务相关联的,这样才能顾名思义
    server {
       listen       80;
       server_name  www.mysite.com;
       index        index.html index.php index.htm;

       location / {
           root /data/nginx/mysite;
           if (!-e $request_filename) {
               rewrite ^/(.*) /index.html last;
           }
       }
    }
  myserver: | # 一般工作中,这个名称都是和业务相关联的,这样才能顾名思义
    server {
       listen       80;
       server_name  www.myserver.com;
       index        index.html index.php index.htm;

       location / {
           root /data/nginx/myserver;
           if (!-e $request_filename) {
               rewrite ^/(.*) /index.html last;
           }
       }
    }

[root@k8s-harbor01 configmap]# kubectl apply -f nginx-cm.yaml
configmap/nginx-config created
2.8.6.2 创建deploy
[root@k8s-harbor01 configmap]# cat nginx-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ng-deploy-80
  template:
    metadata:
      labels:
        app: ng-deploy-80
    spec:
      containers:
      - name: ng-deploy-80
        image: nginx:1.20.0
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /data/nginx/mysite
          name: nginx-mysite-statics
        - name: nginx-myserver-statics
          mountPath: /data/nginx/myserver
        - name: nginx-mysite-config
          mountPath: /etc/nginx/conf.d/mysite
        - name: nginx-myserver-config
          mountPath: /etc/nginx/conf.d/myserver
      volumes:
      - name: nginx-mysite-config
        configMap:
          name: nginx-config
          items:
            - key: mysite
              path: mysite.conf
      - name: nginx-myserver-config
        configMap:
          name: nginx-config
          items:
            - key: myserver
              path: myserver.conf
      - name: nginx-myserver-statics
        nfs:
          server: 10.31.200.104
          path: /data/k8s-data/myserver
      - name: nginx-mysite-statics
        nfs:
          server: 10.31.200.104
          path: /data/k8s-data/mysite

# nfs机器上创建所需目录
[root@k8s-harbor01 k8s-data]# ll
drwxr-xr-x 3 root root   23 521 15:26 myserver
drwxr-xr-x 2 root root    6 523 17:00 mysite
[root@k8s-harbor01 k8s-data]# cat /etc/exports
/data/k8s-data *(rw,no_root_squash)

[root@k8s-harbor01 configmap]# kubectl apply -f nginx-deploy.yaml
deployment.apps/nginx-deployment created
[root@k8s-harbor01 k8s-data]# kubectl get po
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-7878fc9f8f-qjrcx   1/1     Running   0          55
2.8.6.3 配置验证
[root@k8s-harbor01 myserver]# echo myserver-cm > index.html
[root@k8s-harbor01 myserver]# pwd
/data/k8s-data/myserver
[root@k8s-harbor01 myserver]# cd ../mysite/
[root@k8s-harbor01 mysite]# echo mysite-cm > index.html
[root@k8s-harbor01 mysite]# pwd
/data/k8s-data/mysite


[root@k8s-harbor01 mysite]# kubectl exec -it nginx-deployment-7878fc9f8f-qjrcx -- /bin/bash
root@nginx-deployment-7878fc9f8f-qjrcx:/# df -h
Filesystem                             Size  Used Avail Use% Mounted on
overlay                                 50G  5.1G   45G  11% /
tmpfs                                   64M     0   64M   0% /dev
tmpfs                                  2.0G     0  2.0G   0% /sys/fs/cgroup
/dev/sda2                               50G  5.1G   45G  11% /etc/hosts
shm                                     64M     0   64M   0% /dev/shm
10.31.200.104:/data/k8s-data/mysite     50G   15G   36G  30% /data/nginx/mysite
10.31.200.104:/data/k8s-data/myserver   50G   15G   36G  30% /data/nginx/myserver
tmpfs                                  3.6G   12K  3.6G   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs                                  2.0G     0  2.0G   0% /proc/acpi
tmpfs                                  2.0G     0  2.0G   0% /proc/scsi
tmpfs                                  2.0G     0  2.0G   0% /sys/firmware
root@nginx-deployment-7878fc9f8f-qjrcx:/# cat /data/nginx/mysite/index.html 
mysite-cm
root@nginx-deployment-7878fc9f8f-qjrcx:/# cat /data/nginx/myserver/index.html 
myserver-cm

root@nginx-deployment-7878fc9f8f-qjrcx:/# cat /etc/nginx/conf.d/myserver/myserver.conf 
server {
   listen       80;
   server_name  www.myserver.com;
   index        index.html index.php index.htm;

   location / {
       root /data/nginx/myserver;
       if (!-e $request_filename) {
           rewrite ^/(.*) /index.html last;
       }
   }
}
root@nginx-deployment-7878fc9f8f-qjrcx:/# cat /etc/nginx/conf.d/mysite/mysite.conf    
server {
   listen       80;
   server_name  www.mysite.com;
   index        index.html index.php index.htm;

   location / {
       root /data/nginx/mysite;
       if (!-e $request_filename) {
           rewrite ^/(.*) /index.html last;
       }
   }
}

2.9 Secret

2.9.1 简介

Secret的功能类似于ConfigMap给pod提供额外的配置信息,但是Secret是一种包含少量敏感信息例如密码、令牌或密钥的对象。

Secret的名称必须是合法的DNS子域名(只能包含字母、数字和连字符(减号),不能包含其他字符)。

每个Secret的大小最多为1MiB,主要是为了避免用户创建非常大的Secret进而导致API服务器和kubelet内存耗尽。
不过创建很多小的Secret也可能耗尽内存,可以使用资源配额来约束每个名字空间中Secret的个数。

在通过yaml文件创建secret时,可以设置data或stringData字段,data和stringData字段都是可选的,data字段中所有键值都必须是base64编码的字符串。
如果不希望执行这种base64字符串的转换操作,也可以选择设置stringData字段,其中可以使用任何非加密的字符串作为其取值。

Pod可以用三种方式的任意一种来使用Secret:
(1)作为挂载到一个或多个容器上的卷中的文件(crt文件、key文件)。
(2)作为容器的环境变量。
(3)由kubelet在为Pod拉取镜像时使用(与镜像仓库的认证)。

2.9.2 Secret的创建和请求流程

在这里插入图片描述

2.9.3 Secret类型

Kubernetes默认支持多种不同类型的secret,用于一不同的使用场景,不同类型的secret的配置参数也不一样。
在这里插入图片描述

2.9.4 Secret-Opaque类型

2.9.4.1 加密形式Opaque-data数据类型
## base64加密内容(必须加密)
[root@k8s-harbor01 yaml]# mkdir secret
[root@k8s-harbor01 yaml]# cd secret
[root@k8s-harbor01 secret]# echo admin | base64
YWRtaW4K
[root@k8s-harbor01 secret]# echo 123456 | base64
MTIzNDU2Cg==

## 创建secret
[root@k8s-harbor01 secret]# cat 1-secret-Opaque-data.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mysecret-data
  namespace: myserver
type: Opaque # Secret类型
data: # data数据类型的一定要先用base64加密,不然会报错
  user: YWRtaW4K # key和value都可以自定义
  password: MTIzNDU2Cg==

[root@k8s-harbor01 secret]# kubectl apply -f 1-secret-Opaque-data.yaml
secret/mysecret-data created
[root@k8s-harbor01 secret]# kubectl get secret -A
NAMESPACE     NAME                  TYPE     DATA   AGE
kube-system   calico-etcd-secrets   Opaque   3      30d
myserver      mysecret-data         Opaque   2      3s  # 这就是刚才新建的secret

[root@k8s-harbor01 secret]# kubectl get secret -n myserver mysecret-data -oyaml
apiVersion: v1
data:
  password: MTIzNDU2Cg==
  user: YWRtaW4K
kind: Secret
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","data":{"password":"MTIzNDU2Cg==","user":"YWRtaW4K"},"kind":"Secret","metadata":{"annotations":{},"name":"mysecret-data","namespace":"myserver"},"type":"Opaque"}
  creationTimestamp: "2023-05-25T02:22:16Z"
  name: mysecret-data
  namespace: myserver
  resourceVersion: "6296073"
  uid: 5438b70b-25e6-4512-a228-042d26bc1dde
type: Opaque
[root@k8s-harbor01 secret]# echo MTIzNDU2Cg==|base64 -d # 我们base64加密的数据, 存到etcd的时候依然是加密的,直到在容器中挂载的时候,才会变成明文
123456


## pod挂载secret
[root@k8s-harbor01 secret]# cat 3-secret-Opaque-mount.yaml
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-myapp-app1-deployment
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myserver-myapp-app1
  template:
    metadata:
      labels:
        app: myserver-myapp-app1
    spec:
      containers:
      - name: myserver-myapp-app1
        image: tomcat:7.0.94-alpine
        ports:
        - containerPort: 8080
        volumeMounts:
        - mountPath: /data/myserver/auth
          name: myserver-auth-secret 
      volumes:
      - name: myserver-auth-secret
        secret:
          secretName: mysecret-data #挂载指定的secret,挂载后会将base64解密为明文

---
apiVersion: v1
kind: Service
metadata:
  name: myserver-myapp-app1
  namespace: myserver
spec:
  ports:
  - name: http
    port: 8080
    targetPort: 8080
    nodePort: 30018
    protocol: TCP
  type: NodePort
  selector:
    app: myserver-myapp-app1

[root@k8s-harbor01 secret]# kubectl apply -f 3-secret-Opaque-mount.yaml
deployment.apps/myserver-myapp-app1-deployment created
service/myserver-myapp-app1 created
[root@k8s-harbor01 secret]# kubectl get po -n myserver
NAME                                              READY   STATUS    RESTARTS   AGE
myserver-myapp-app1-deployment-6f68468b89-fg4k5   1/1     Running   0          2m24s

# 验证
[root@k8s-harbor01 secret]# kubectl exec -it -n myserver myserver-myapp-app1-deployment-6f68468b89-fg4k5 -- /bin/bash
bash-4.4# cat /data/myserver/auth/user  # 可以看到,在pod中,实际上是吧secret的key当成文件挂载到了pod中
admin
bash-4.4# cat /data/myserver/auth/password   # 可以看到,在pod中,实际上是吧secret的key当成文件挂载到了pod中
123456

bash-4.4# cd -
/data/myserver/auth
bash-4.4# ls
password  user
bash-4.4# ls -la
total 0
drwxrwxrwt    3 root     root           120 May 25 03:29 .
drwxr-xr-x    3 root     root            18 May 25 03:30 ..
drwxr-xr-x    2 root     root            80 May 25 03:29 ..2023_05_25_03_29_24.3852920187
lrwxrwxrwx    1 root     root            32 May 25 03:29 ..data -> ..2023_05_25_03_29_24.3852920187
lrwxrwxrwx    1 root     root            15 May 25 03:29 password -> ..data/password
lrwxrwxrwx    1 root     root            11 May 25 03:29 user -> ..data/user

# 同时,pod对应的宿主机上也会存在secret文件
[root@k8s-node01 ~]# find / -name user -type f
/var/lib/kubelet/pods/70e8f360-9710-4479-822b-283efcc0853c/volumes/kubernetes.io~secret/myserver-auth-secret/..2023_05_25_03_29_24.3852920187/user
[root@k8s-node01 ~]# find / -name password -type f
/var/lib/kubelet/pods/70e8f360-9710-4479-822b-283efcc0853c/volumes/kubernetes.io~secret/myserver-auth-secret/..2023_05_25_03_29_24.3852920187/password
2.9.4.2 明文形式Opaque-stringData数据类型

存储在etcd中的数据也是明文的

## 创建yaml
[root@k8s-harbor01 secret]# cat 2-secret-Opaque-stringData.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mysecret-stringdata
  namespace: myserver
type: Opaque # secret类型
stringData: # 数据类型
  user: 'admin'
  password: '123456'

## 创建
[root@k8s-harbor01 secret]# kubectl apply -f 2-secret-Opaque-stringData.yaml
secret/mysecret-stringdata created
[root@k8s-harbor01 secret]# kubectl get secret -n myserver
NAME                  TYPE     DATA   AGE
mysecret-data         Opaque   2      17m
mysecret-stringdata   Opaque   2      9s  # 新建的stringdata数据类型的secret

2.9.5 Secret-kubernetes.io/tls类型-为nginx提供证书

2.9.5.1 自签证书
[root@k8s-harbor01 secret]# mkdir certs
[root@k8s-harbor01 secret]# cd certs
[root@k8s-harbor01 certs]# openssl req -x509 -sha256 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 3560 -nodes -subj '/CN=www.ca.com' # 自签CA根证书
Generating a 4096 bit RSA private key
............................................++
......++
writing new private key to 'ca.key'
-----
[root@k8s-harbor01 certs]# ls
ca.crt  ca.key

[root@k8s-harbor01 certs]# openssl req -new -newkey rsa:4096 -keyout server.key -out server.csr -nodes -subj '/CN=www.mysite.com' # 生成一个RSA密对和一个证书签名请求 (CSR)。后续可以将其提交给证书颁发机构 (CA) 以获取一个由CA签名的域名证书(server.key就是域名的私钥证书,公钥证书需要把csr文件交给ca签名,来签发域名公钥证书)
Generating a 4096 bit RSA private key
.......................................................................................................................................................................++
.....++
writing new private key to 'server.key'
-----
[root@k8s-harbor01 certs]# ll -rt
总用量 16
-rw-r--r-- 1 root root 3268 525 13:19 ca.key
-rw-r--r-- 1 root root 1789 525 13:19 ca.crt
-rw-r--r-- 1 root root 3272 525 13:21 server.key
-rw-r--r-- 1 root root 1590 525 13:21 server.csr


[root@k8s-harbor01 certs]# openssl x509 -req -sha256 -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt # 签发域名公钥证书
Signature ok
subject=/CN=www.mysite.com
Getting CA Private Key
[root@k8s-harbor01 certs]# ll -rt
总用量 20
-rw-r--r-- 1 root root 3268 525 13:19 ca.key
-rw-r--r-- 1 root root 1789 525 13:19 ca.crt
-rw-r--r-- 1 root root 3272 525 13:21 server.key
-rw-r--r-- 1 root root 1590 525 13:21 server.csr
-rw-r--r-- 1 root root 1667 525 13:22 server.crt
2.9.5.2 创建tls类型的secret
[root@k8s-harbor01 certs]# kubectl create secret tls myserver-tls-key --cert=./server.crt --key=./server.key -n myserver  # 因为公钥和私钥的内容都比较长,所以一般都是用证书来创建secret
secret/myserver-tls-key created
[root@k8s-harbor01 certs]# kubectl get secret -n myserver
NAME                  TYPE                DATA   AGE
mysecret-data         Opaque              2      3h44m
mysecret-stringdata   Opaque              2      3h26m
myserver-tls-key      kubernetes.io/tls   2      7s

[root@k8s-harbor01 certs]# kubectl get secret -o yaml -n myserver myserver-tls-key
apiVersion: v1
data:
  tls.crt: LS0tLS1CRxxx # 省略部分内容。这个key可以自定义,但是需要记住,会在下面创建deploy中引用
  tls.key: LS0tLS1Cxxx # 省略部分内容。这个key可以自定义,但是需要记住,会在下面创建deploy中引用
kind: Secret
metadata:
  creationTimestamp: "2023-05-25T06:06:32Z"
  name: myserver-tls-key
  namespace: myserver
  resourceVersion: "6326671"
  uid: 2bc973a1-da49-4a8b-8f24-b84929d0ca38
type: kubernetes.io/tls
2.9.5.3 创建nginx并挂载该secret
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
  namespace: myserver
data:
 default: |
    server {
       listen       80;
       server_name  www.mysite.com;
       listen 443 ssl;
       ssl_certificate /etc/nginx/conf.d/certs/tls.crt; # 这里的tls.crt是上面secret中data下的key
       ssl_certificate_key /etc/nginx/conf.d/certs/tls.key; # 这里的tls.key是上面secret中data下的key

       location / {
           root /usr/share/nginx/html; 
           index index.html;
           if ($scheme = http ){  #未加条件判断,会导致死循环
              rewrite / https://www.mysite.com permanent;
           }  

           if (!-e $request_filename) {
               rewrite ^/(.*) /index.html last;
           }
       }
    }

---
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-myapp-frontend-deployment
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myserver-myapp-frontend
  template:
    metadata:
      labels:
        app: myserver-myapp-frontend
    spec:
      containers:
      - name: myserver-myapp-frontend
        image: nginx:1.20.2-alpine 
        ports:
          - containerPort: 80
        volumeMounts:
          - name: nginx-config
            mountPath:  /etc/nginx/conf.d/myserver
          - name: myserver-tls-key
            mountPath:  /etc/nginx/conf.d/certs # 把secret挂载到容器的这个目录下
      volumes:
      - name: nginx-config
        configMap:
          name: nginx-config
          items:
             - key: default
               path: mysite.conf
      - name: myserver-tls-key
        secret: # 卷类型
          secretName: myserver-tls-key # tls secret


---
apiVersion: v1
kind: Service
metadata:
  name: myserver-myapp-frontend
  namespace: myserver
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30018
    protocol: TCP
  - name: htts
    port: 443
    targetPort: 443
    nodePort: 30019
    protocol: TCP
  selector:
    app: myserver-myapp-frontend

[root@k8s-harbor01 certs]# kubectl apply -f 4-secret-tls.yaml
2.9.5.4 配置检查
[root@k8s-harbor01 certs]# kubectl exec -it -n myserver myserver-myapp-frontend-deployment-5cf6b65d59-x6hlc -- sh
/ # ls -l /etc/nginx/conf.d/certs/
total 0
lrwxrwxrwx    1 root     root            14 May 25 06:38 tls.crt -> ..data/tls.crt
lrwxrwxrwx    1 root     root            14 May 25 06:38 tls.key -> ..data/tls.key

2.9.6 Secret-kubernetes.io/dockerconfigjson类型

存储docker registry的认证信息,在下载镜像的时候使用,这样每一个node节点就可以不登录也可以下载私有级别的镜像了。

2.9.6.1 通过docker认证文件创建
# 当我们docker login层工登录镜像仓库的时候,服务器上也会缓存一份文件,可以基于这个文件来创建
[root@k8s-harbor01 .docker]# pwd
/root/.docker
[root@k8s-harbor01 .docker]# cat config.json 
{
        "auths": {
                "10.31.200.104": {
                        "auth": "YWRtaW46MTIzNDU2"
                }
        }
}[root@k8s-harbor01 .docker]# echo YWRtaW46MTIzNDU2|base64 -d
admin:123456[root@k8s-harbor0

# 创建secret
kubectl create secret generic \ # generic: 从本地文件、目录或文字值创建
dockerhub-image-pull-key \ # dockerhub-image-pull-key为secret名称
--from-file=.dockerconfigjson=/root/.docker/config.json \ # 基于config.json创建
--type=kubernetes.io/dockerconfigjson \ # secret类型
-n myserver # 这里有一点需要注意,这个dockerconfigjson类型的secret是名称空间级别的,也就是我这个只能给myserver使用,如果其他ns想用,那么害的继续在对应ns下创建一遍。
secret/dockerhub-image-pull-key created
[root@k8s-harbor01 .docker]# kubectl get secret -n myserver|grep image
dockerhub-image-pull-key   kubernetes.io/dockerconfigjson   1      11s
[root@k8s-harbor01 .docker]# kubectl get secret -n myserver -oyaml dockerhub-image-pull-key
apiVersion: v1
data:
  .dockerconfigjson: ewoJImF1dGhzIjogewoJCSIxMC4zMS4yMDAuMTA0IjogewoJCQkiYXV0aCI6ICJZV1J0YVc0Nk1USXpORFUyIgoJCX0KCX0KfQ== # 这值也是base64加密过的
kind: Secret
metadata:
  creationTimestamp: "2023-05-25T08:04:58Z"
  name: dockerhub-image-pull-key
  namespace: myserver
  resourceVersion: "6342840"
  uid: e0822088-be62-4f4f-8dc0-1d953ec2b897
type: kubernetes.io/dockerconfigjson

## 创建pod挂载该secret
[root@k8s-harbor01 secret]# cat 5-secret-imagePull.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-myapp-frontend-deployment
  namespace: myserver
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myserver-myapp-frontend
  template:
    metadata:
      labels:
        app: myserver-myapp-frontend
    spec:
      containers:
      - name: myserver-myapp-frontend
        image: 10.31.200.104/myserver/nginx # 下载这个镜像的时候,就会使用下面的secret来进行验证(就算你node主机配置了仓库认证,下载镜像的时候也会优先使用这个配置)
        ports:
          - containerPort: 80
      imagePullSecrets: # 使用dockerconfigjson类型的secret
        - name: dockerhub-image-pull-key # secret名称

[root@k8s-harbor01 secret]# kubectl apply -f 5-secret-imagePull.yaml
deployment.apps/myserver-myapp-frontend-deployment configured

# 检查配置
[root@k8s-harbor01 secret]# kubectl get po -n myserver
NAME                                                  READY   STATUS    RESTARTS   AGE
myserver-myapp-app1-deployment-6f68468b89-fg4k5       1/1     Running   0          4h53m
myserver-myapp-frontend-deployment-86b4f46769-llpch   1/1     Running   0          3s
2.9.6.2 直接命令行创建
[root@k8s-harbor01 secret]# kubectl create secret docker-registry \ # 创建一个给Docker registry使用的Secret
dockerhub-image-pull-key \ # secret的名称
--docker-server=10.31.200.104 \ # 仓库地址
--docker-username=admin \ # 用户
--docker-password=123456 # 密码

[root@k8s-harbor01 secret]# kubectl get secret
NAME                       TYPE                             DATA   AGE
dockerhub-image-pull-key   kubernetes.io/dockerconfigjson   1      81s
root@k8s-harbor01 secret]# kubectl get secret
NAME                       TYPE                             DATA   AGE
dockerhub-image-pull-key   kubernetes.io/dockerconfigjson   1      81s
[root@k8s-harbor01 secret]# kubectl describe secret dockerhub-image-pull-key
Name:         dockerhub-image-pull-key
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  kubernetes.io/dockerconfigjson

Data
====
.dockerconfigjson:  94 bytes

# 创建pod
[root@k8s-harbor01 secret]# cat 5-secret-imagePull.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myserver-myapp-frontend-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myserver-myapp-frontend
  template:
    metadata:
      labels:
        app: myserver-myapp-frontend
    spec:
      containers:
      - name: myserver-myapp-frontend
        image: 10.31.200.104/myserver/nginx:latest
        ports:
          - containerPort: 80
      imagePullSecrets: # 使用dockerconfigjson类型的secret
        - name: dockerhub-image-pull-key # secret名称

[root@k8s-harbor01 secret]# kubectl apply -f 5-secret-imagePull.yaml
deployment.apps/myserver-myapp-frontend-deployment created
[root@k8s-harbor01 secret]# kubectl get po 
NAME                                                 READY   STATUS    RESTARTS   AGE
myserver-myapp-frontend-deployment-d9bfc6555-598x7   1/1     Running   0          9s

# 把secret改成错误的,看看pod能不能拉镜像
[root@k8s-harbor01 secret]# kubectl delete -f 5-secret-imagePull.yaml 
deployment.apps "myserver-myapp-frontend-deployment" deleted
[root@k8s-harbor01 secret]# kubectl delete secret dockerhub-image-pull-key
secret "dockerhub-image-pull-key" deleted

[root@k8s-harbor01 secret]# kubectl create secret docker-registry \
> dockerhub-image-pull-key \
> --docker-server=10.31.200.104 \
> --docker-username=admin \
> --docker-password=1234
secret/dockerhub-image-pull-key created
[root@k8s-harbor01 secret]# kubectl apply -f 5-secret-imagePull.yaml 
deployment.apps/myserver-myapp-frontend-deployment created
[root@k8s-harbor01 secret]# kubectl get po
NAME                                                 READY   STATUS         RESTARTS   AGE
myserver-myapp-frontend-deployment-d9bfc6555-8cs92   0/1     ErrImagePull   0          9s # 可以看到这里拉镜像报错了
nginx-deployment-7878fc9f8f-qjrcx                    1/1     Running        0          2d

在这里插入图片描述

2.9.5 Secret挂载流程

[root@k8s-etcd01 ~]# etcdctl get / --keys-only --prefix |grep mysecret
/registry/secrets/myserver/mysecret-data
/registry/secrets/myserver/mysecret-stringdata

在这里插入图片描述

2.10 Statefulset

官网地址:https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/statefulset/

2.10.1 简介

(1)Statefulset为了解决有状态服务的集群部署、集群之间的数据同步问题(MySQL主从等)。
(2)Statefulset所管理的Pod拥有唯一且固定的Pod名称。
(3)Statefulset按照顺序对pod进行启停、伸缩和回收(创建:从前到后。删除:从后到前)。
(4)Headless Services(无头服务,请求的解析直接解析到pod IP),一种特殊的svc,没有svcip。

2.10.2 部署sts

2.10.2.1 准备yaml
[root@k8s-harbor01 sts]# cat 1-Statefulset.yaml
---
apiVersion: apps/v1
kind: StatefulSet 
metadata:
  name: myserver-sts
  namespace: myserver
spec:
  replicas: 3
  serviceName: "myserver-sts-service"
  selector:
    matchLabels:
      app: myserver-sts-frontend
  template:
    metadata:
      labels:
        app: myserver-sts-frontend
    spec:
      containers:
      - name: myserver-sts-frontend
        image: nginx:1.20.2-alpine 
        ports:
          - containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: myserver-sts-service
  namespace: myserver
spec:
  clusterIP: None # 这里注意,搭配sts的svc没有指定IP地址,也就是一个无头的svc,所以请求svc的时候,请求是直接轮训到的后端pod的
  ports:
  - name: http
    port: 80
  selector:
    app: myserver-sts-frontend

[root@k8s-harbor01 sts]# kubectl apply -f 1-Statefulset.yaml
statefulset.apps/myserver-sts created
service/myserver-sts-service created

# pod命名规律:sts名称-0..n
[root@k8s-harbor01 sts]# kubectl get all -n myserver|grep sts # 看创建时间,可以看出pod都是顺序创建的
pod/myserver-sts-0                                    1/1     Running   0          4m31s
pod/myserver-sts-1                                    1/1     Running   0          4m8s
pod/myserver-sts-2                                    1/1     Running   0          3m46s
service/myserver-sts-service   ClusterIP   None             <none>        80/TCP                       4m32s
statefulset.apps/myserver-sts   3/3     4m32s

2.11 DaemonSet

官方文档:https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/daemonset/

2.11.1 简介

DaemonSet确保全部(或者某些)节点上都运行一个Pod的副本。
当有节点加入集群时,也会为他们新增一个Pod 。
当有节点从集群移除时,这些Pod也会被回收。
删除DaemonSet将会删除它创建的所有Pod。

2.11.2 应用场景

(1)在每个节点上运行集群守护进程
(2)在每个节点上运行日志收集守护进程
(3)在每个节点上运行监控守护进程

2.11.3 创建daemonset

[root@k8s-harbor01 yaml]# mkdir ds
[root@k8s-harbor01 yaml]# cd ds
[root@k8s-harbor01 ds]# cat daemonset.yaml
---
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: DaemonSet 
metadata:
  name: myserver-myapp
  namespace: myserver
spec:
  selector:
    matchLabels:
      app: myserver-myapp-frontend
  template:
    metadata:
      labels:
        app: myserver-myapp-frontend
    spec:
      tolerations: # 这下面配置了一个污点容忍,让deamonset启动的pod也能在master节点运行(我的master是配置了禁止调度的)
      # this toleration is to have the daemonset runnable on master nodes
      # remove it if your masters can't run pods
      - key: node-role.kubernetes.io/master # tolerations的key
        operator: Exists # operator表示容忍关系, Exists表示只要有一个容忍度匹配即可
        effect: NoSchedule # effect表示容忍类型,NoSchedule表示节点不应该被调度到这个容忍度匹配的 Pod 上(意思是就算你有NoSchedule,我也可以调度)
      hostNetwork: true
      hostPID: true
      containers:
      - name: myserver-myapp-frontend
        image: nginx:1.20.2-alpine 
        ports:
          - containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: myserver-myapp-frontend
  namespace: myserver
spec:
  ports:
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30018
    protocol: TCP
  type: NodePort
  selector:
    app: myserver-myapp-frontend


[root@k8s-harbor01 ds]# kubectl apply -f daemonset.yaml  
daemonset.apps/myserver-myapp unchanged
service/myserver-myapp-frontend created
[root@k8s-harbor01 ds]# kubectl get po -A -owide|grep myserver-myapp # 这里可以看到pod在每个节点都运行了
myserver      myserver-myapp-4vl79                              1/1     Running   0             57s     10.31.200.101    k8s-master01   <none>           <none>
myserver      myserver-myapp-app1-deployment-6f68468b89-fg4k5   1/1     Running   0             29h     10.200.85.245    k8s-node01     <none>           <none>
myserver      myserver-myapp-bv59h                              1/1     Running   0             57s     10.31.200.111    k8s-node02     <none>           <none>
myserver      myserver-myapp-k2kbl                              1/1     Running   0             57s     10.31.200.112    k8s-node03     <none>           <none>
myserver      myserver-myapp-ljfvk                              1/1     Running   0             57s     10.31.200.103    k8s-master03   <none>           <none>
myserver      myserver-myapp-mcmjq                              1/1     Running   0             57s     10.31.200.102    k8s-master02   <none>           <none>
myserver      myserver-myapp-rgg9m                              1/1     Running   0             57s     10.31.200.110    k8s-node01     <none>           <none>

文章引用:https://xiaorui.cc/archives/7350

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐