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编写的 )。

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 coredns是如何进行内部域名解析的

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

# coredns的cm中有这么一段配置readykubernetes cluster.local in-addr.arpa ip6.arpa { # 就是在解析cluster.local这域名的时候,找的是kubernetes,那么这个kubernetes是谁呢?看下面pods insecurefallthrough in-addr.arpa ip6.arpattl 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- namespacesverbs:- list- watch
- apiGroups:- ""resources:- nodesverbs:- get
- apiGroups:- discovery.k8s.ioresources:- endpointslicesverbs:- list- watch

1.4 coredns使用注意事项

主要是内存cpu这块

# 如果集群内,coredns需要解析大量的内部域名,这个时候就需要关注一下coredns的资源使用情况了,万一资源不足了,可能会出现域名解析慢或者无法解析的情况。如果加了资源还是慢,可以尝试扩容副本(一般生产3个就够了)resources:limits:memory: 256Micpu: 200mrequests:  # 如果内存够多,可以配置1G或者512M,CPU给1C到2C,因为coredns主要还是比较消耗cpu,内存到还好(官方给的内存算法:容器内存=pod总数/1000+54)cpu: 100mmemory: 70Mi

1.5 配置文件详解

1.6 解析演示

# 创建两个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#53Name:   kubernetes.default.svc.cluster.local
Address: 10.100.0.1

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-containerimage: 10.31.200.104/myserver/centos:7.9.2009command: ["/bin/sh"] # 容器起来后,执行的命令args: ["-c", "echo data init job at `date +%Y-%m-%d_%H-%M-%S` >> /cache/data.log"] # command的参数,这里是echo一行字符串到指定文件中volumeMounts:- mountPath: /cachename: cache-volume- mountPath: /etc/localtimename: localtimevolumes:- name: cache-volumehostPath:path: /tmp/jobdata # 这里把容器的/cache目录,挂载到宿主机的/tmp/jobdata- name: localtimehostPath:path: /etc/localtimerestartPolicy: 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-podimage: 10.31.200.104/myserver/centos:7.9.2009#imagePullPolicy: IfNotPresentcommand: ["/bin/sh"]args: ["-c", "echo mysql databackup cronjob at `date +%Y-%m-%d_%H-%M-%S` >> /cache/data.log"]volumeMounts: - mountPath: /cachename: cache-volumevolumes:- name: cache-volumehostPath: # 工作中用cronjob生成文件的话,一定不要存储到宿主机,用nfs都行,因为pod不一定每次都调度到同一台机器。path: /tmp/cronjobdatarestartPolicy: 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: 2selector:  app: ng-rc-80  # rc就是通过关联标签来管理pod的template:   metadata:  labels:  app: ng-rc-80spec:  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: 2selector:#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-80spec:  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: 2selector:#app: ng-deploy-80 #rc # 标签选择支持的方式1matchLabels: #rs or deployment # 标签选择支持的方式2app: 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-80image: nginxports:- 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


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: 3strategy: # 这个参数描述了如何用新的pod替换现有的pod。

2.5.3.1 rollingUpdate

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

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

通过这个图也能直接看出来

2.5.3.2 recreate

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

spec:replicas: 3strategy: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: 2selector:matchLabels: #rs or deploymentapp: ng-deploy-svc-testtemplate:metadata:labels:app: ng-deploy-svc-testspec:containers:- name: ng-deploy-80image: nginxports:- 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: httpport: 81targetPort: 80nodePort: 30012 # 这个端口可以不指定,不指定的话会随机分配一个端口protocol: TCPtype: NodePortselector: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.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/v1RESOURCE: emptyDir <Object>DESCRIPTION:emptyDir represents a temporary directory that shares a pod's lifetime.More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydirRepresents an empty directory for a pod. Empty directory volumes supportownership 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 anempty string (default) or Memory. More info:https://kubernetes.io/docs/concepts/storage/volumes#emptydirsizeLimit    <string> # 设置临时卷的大小sizeLimit is the total amount of local storage required for this EmptyDirvolume. The size limit is also applicable for memory medium. The maximumusage on memory medium EmptyDir would be the minimum value between theSizeLimit specified here and the sum of memory limits of all containers ina pod. The default is nil which means that the limit is undefined. Moreinfo: 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: 1selector:matchLabels: #rs or deploymentapp: ng-deploy-80template:metadata:labels:app: ng-deploy-80spec:containers:- name: ng-deploy-80image: 10.31.200.104/myserver/nginx:latestports:- containerPort: 80volumeMounts:- mountPath: /cachename: cache-volumevolumes:- name: cache-volumeemptyDir: {}# 创建
[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 5月  18 13:41 containers
-rw-r--r-- 1 root root 231 5月  18 13:41 etc-hosts
drwxr-x--- 3 root root  37 5月  18 13:41 plugins
drwxr-x--- 4 root root  68 5月  18 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: 1selector:matchLabels:app: ng-deploy-80template:metadata:labels:app: ng-deploy-80spec:containers:- name: ng-deploy-80image: nginx ports:- containerPort: 80volumeMounts:- mountPath: /cachename: cache-volumevolumes:- name: cache-volumehostPath: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: 1selector:matchLabels:app: ng-deploy-80template:metadata:labels:app: ng-deploy-80spec:containers:- name: ng-deploy-80image: nginx ports:- containerPort: 80volumeMounts: # 容器的挂载配置- mountPath: /usr/share/nginx/html/mysite # 挂载容器的这个目录。不存在的目录会自动创建name: my-nfs-volumevolumes:  # 这里- name: my-nfs-volumenfs: # 使用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: httpport: 81targetPort: 80nodePort: 30016protocol: TCPtype: NodePortselector: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 5月  18 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参数介绍

# kubectl explain PersistentVo(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后保持原装,最后需要管理员手动删除。
Recycle – 空间回收,及删除存储卷上的所有数据(包括目录和隐藏文件),目前仅支持NFS和hostPath。
Delete – 自动删除存储卷。(4)volumeMode #卷类型,kubectl explain PersistentVolume.spec.volumeMode。定义存储卷使用的文件系统是块设备还是文件系统,默认为文件系统。
什么时候用块设备?什么时候用文件系统?
如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 # 分配的可用存储空间为10GaccessModes: # 访问模式- ReadWriteOnce # PV只能被单个节点以读写权限挂载,RWOnfs: # 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-pvcnamespace: myserver
spec:volumeName: myserver-myapp-static-pv # 这里一定要写对pv的名称,不然绑定不上。accessModes:- ReadWriteOnceresources: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-namenamespace: myserver
spec:replicas: 1 selector:matchLabels:app: myserver-myapp-frontendtemplate:metadata:labels:app: myserver-myapp-frontendspec:containers:- name: myserver-myapp-containerimage: nginx:1.20.0 #imagePullPolicy: AlwaysvolumeMounts:- mountPath: "/usr/share/nginx/html/statics"name: statics-datadir #容器挂载的卷的名称volumes: # pod提供的卷- name: statics-datadir # pvc的名称persistentVolumeClaim: #类型为pvcclaimName: myserver-myapp-static-pvc  # pvc的名称---
kind: Service
apiVersion: v1
metadata:labels:app: myserver-myapp-servicename: myserver-myapp-service-namenamespace: myserver
spec:type: NodePortports:- name: httpport: 80targetPort: 80nodePort: 30080selector: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 pv.yaml
kubectl delete -f pvc.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: ServiceAccountname: nfs-client-provisioner # 绑定账号,账号和角色相绑定,就拥有了角色配置的权限# replace with namespace where provisioner is deployednamespace: nfs
roleRef:kind: ClusterRolename: 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 deployednamespace: 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 deployednamespace: nfs
subjects:- kind: ServiceAccountname: nfs-client-provisioner# replace with namespace where provisioner is deployednamespace: nfs
roleRef:kind: Rolename: leader-locking-nfs-client-provisionerapiGroup: 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-provisionerlabels:app: nfs-client-provisioner# replace with namespace where provisioner is deployednamespace: nfs
spec:replicas: 1strategy: #部署策略type: Recreateselector:matchLabels:app: nfs-client-provisionertemplate:metadata:labels:app: nfs-client-provisionerspec:serviceAccountName: nfs-client-provisionercontainers:- 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-rootmountPath: /persistentvolumes # 这个配置不用改env:- name: PROVISIONER_NAMEvalue: k8s-sigs.io/nfs-subdir-external-provisioner # 这个名称,必须和sc里面的提供者是一样的。- name: NFS_SERVERvalue: 10.31.200.104- name: NFS_PATHvalue: /data/volumesvolumes:- name: nfs-client-rootnfs:server: 10.31.200.104path: /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-pvcnamespace: 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 # 就是他创建的pvcreationTimestamp: "2023-05-21T09:13:48Z"finalizers:- kubernetes.io/pv-protectionname: pvc-aa016cd8-b84c-4759-8030-7ffdf5d1b43aresourceVersion: "5566205"uid: c51ecca9-414c-4eb0-a728-40029a69ee2d
spec:accessModes:- ReadWriteManycapacity:storage: 500MiclaimRef:apiVersion: v1kind: PersistentVolumeClaimname: myserver-myapp-dynamic-pvcnamespace: myserverresourceVersion: "5566201"uid: aa016cd8-b84c-4759-8030-7ffdf5d1b43amountOptions:- noatimenfs:path: /data/volumes/myserver-myserver-myapp-dynamic-pvc-pvc-aa016cd8-b84c-4759-8030-7ffdf5d1b43a # nfs上的挂载路径server: 10.31.200.104persistentVolumeReclaimPolicy: RetainstorageClassName: managed-nfs-storagevolumeMode: 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-namenamespace: myserver
spec:replicas: 1 selector:matchLabels:app: myserver-myapp-frontendtemplate:metadata:labels:app: myserver-myapp-frontendspec:containers:- name: myserver-myapp-containerimage: nginx:1.20.0 #imagePullPolicy: AlwaysvolumeMounts:- mountPath: "/usr/share/nginx/html/statics"name: statics-datadirvolumes:- name: statics-datadirpersistentVolumeClaim:claimName: myserver-myapp-dynamic-pvc ---
kind: Service
apiVersion: v1
metadata:labels:app: myserver-myapp-servicename: myserver-myapp-service-namenamespace: myserver
spec:type: NodePortports:- name: httpport: 80targetPort: 80nodePort: 30080selector: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.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: # 数据。这个下面可以配置多个cmdefault: | # 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: 1selector:matchLabels:app: ng-deploy-80template:metadata:labels:app: ng-deploy-80spec:containers:- name: ng-deploy-80image: nginx:1.20.0ports:- containerPort: 80volumeMounts:- mountPath: /data/nginx/htmlname: nginx-static-dir- name: nginx-configmountPath:  /etc/nginx/conf.d # 这个挂载点不存在的话,会自动创建volumes:- name: nginx-static-dir # 第一个卷hostPath: # 使用的类型为hostpathpath: /data/nginx/linux39- name: nginx-configconfigMap: # 这里就是挂载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: httpport: 81targetPort: 80nodePort: 30019protocol: TCPtype: NodePortselector: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: # 数据。这个下面可以配置多个cmdefault: | # default为名称,这个是可以自定义的。|管道符是隔离开下面的配置server {  # 从这里开始就是nginx具体的配置信息listen       81; #修改cm中nginx的端口为81server_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/htmlmountPath:  /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: 1selector:matchLabels:app: ng-env-deploy-80template:metadata:labels:app: ng-env-deploy-80spec:containers:- name: ng-env-deploy-80image: nginx env: # 通过env配置,在下面指定环境变量- name: MY_USERNAME # 容器中的变量名valueFrom: # 值的来源configMapKeyRef: # 来源与cm中的keyname: nginx-env-config # 来源cm的名称key: username # 来源cm的key,对应的值就是user1- name: MY_PASSWORDvalueFrom:configMapKeyRef:name: nginx-env-configkey: 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: 1selector:matchLabels:app: ng-deploy-80template:metadata:labels:app: ng-deploy-80spec:containers:- name: ng-deploy-80image: nginx:1.20.0ports:- containerPort: 80volumeMounts:- mountPath: /data/nginx/mysitename: nginx-mysite-statics- name: nginx-myserver-staticsmountPath: /data/nginx/myserver- name: nginx-mysite-configmountPath: /etc/nginx/conf.d/mysite- name: nginx-myserver-configmountPath: /etc/nginx/conf.d/myservervolumes:- name: nginx-mysite-configconfigMap:name: nginx-configitems:- key: mysitepath: mysite.conf- name: nginx-myserver-configconfigMap:name: nginx-configitems:- key: myserverpath: myserver.conf- name: nginx-myserver-staticsnfs:server: 10.31.200.104path: /data/k8s-data/myserver- name: nginx-mysite-staticsnfs:server: 10.31.200.104path: /data/k8s-data/mysite# nfs机器上创建所需目录
[root@k8s-harbor01 k8s-data]# ll
drwxr-xr-x 3 root root   23 5月  21 15:26 myserver
drwxr-xr-x 2 root root    6 5月  23 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-cmroot@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-datanamespace: myserver
type: Opaque # Secret类型
data: # data数据类型的一定要加密,不然会报错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-datanamespace: myserverresourceVersion: "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-deploymentnamespace: myserver
spec:replicas: 1selector:matchLabels:app: myserver-myapp-app1template:metadata:labels:app: myserver-myapp-app1spec:containers:- name: myserver-myapp-app1image: tomcat:7.0.94-alpineports:- containerPort: 8080volumeMounts:- mountPath: /data/myserver/authname: myserver-auth-secret volumes:- name: myserver-auth-secretsecret:secretName: mysecret-data #挂载指定的secret,挂载后会将base64解密为明文---
apiVersion: v1
kind: Service
metadata:name: myserver-myapp-app1namespace: myserver
spec:ports:- name: httpport: 8080targetPort: 8080nodePort: 30018protocol: TCPtype: NodePortselector: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中
123456bash-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-stringdatanamespace: 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 5月  25 13:19 ca.key
-rw-r--r-- 1 root root 1789 5月  25 13:19 ca.crt
-rw-r--r-- 1 root root 3272 5月  25 13:21 server.key
-rw-r--r-- 1 root root 1590 5月  25 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 5月  25 13:19 ca.key
-rw-r--r-- 1 root root 1789 5月  25 13:19 ca.crt
-rw-r--r-- 1 root root 3272 5月  25 13:21 server.key
-rw-r--r-- 1 root root 1590 5月  25 13:21 server.csr
-rw-r--r-- 1 root root 1667 5月  25 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-keynamespace: myserverresourceVersion: "6326671"uid: 2bc973a1-da49-4a8b-8f24-b84929d0ca38
type: kubernetes.io/tls

2.9.5.3 创建nginx并挂载该secret

apiVersion: v1
kind: ConfigMap
metadata:name: nginx-confignamespace: 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下的keyssl_certificate_key /etc/nginx/conf.d/certs/tls.key; # 这里的tls.key是上面secret中data下的keylocation / {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-deploymentnamespace: myserver
spec:replicas: 1selector:matchLabels:app: myserver-myapp-frontendtemplate:metadata:labels:app: myserver-myapp-frontendspec:containers:- name: myserver-myapp-frontendimage: nginx:1.20.2-alpine ports:- containerPort: 80volumeMounts:- name: nginx-configmountPath:  /etc/nginx/conf.d/myserver- name: myserver-tls-keymountPath:  /etc/nginx/conf.d/certs # 把secret挂载到容器的这个目录下volumes:- name: nginx-configconfigMap:name: nginx-configitems:- key: defaultpath: mysite.conf- name: myserver-tls-keysecret: # 卷类型secretName: myserver-tls-key # tls secret---
apiVersion: v1
kind: Service
metadata:name: myserver-myapp-frontendnamespace: myserver
spec:type: NodePortports:- name: httpport: 80targetPort: 80nodePort: 30018protocol: TCP- name: httsport: 443targetPort: 443nodePort: 30019protocol: TCPselector: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-keynamespace: myserverresourceVersion: "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-deploymentnamespace: myserver
spec:replicas: 1selector:matchLabels:app: myserver-myapp-frontendtemplate:metadata:labels:app: myserver-myapp-frontendspec:containers:- name: myserver-myapp-frontendimage: 10.31.200.104/myserver/nginx # 下载这个镜像的时候,就会使用下面的secret来进行验证(就算你node主机配置了仓库认证,下载镜像的时候也会优先使用这个配置)ports:- containerPort: 80imagePullSecrets: # 使用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/dockerconfigjsonData
====
.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: 1selector:matchLabels:app: myserver-myapp-frontendtemplate:metadata:labels:app: myserver-myapp-frontendspec:containers:- name: myserver-myapp-frontendimage: 10.31.200.104/myserver/nginx:latestports:- containerPort: 80imagePullSecrets: # 使用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-stsnamespace: myserver
spec:replicas: 3serviceName: "myserver-sts-service"selector:matchLabels:app: myserver-sts-frontendtemplate:metadata:labels:app: myserver-sts-frontendspec:containers:- name: myserver-sts-frontendimage: nginx:1.20.2-alpine ports:- containerPort: 80---
apiVersion: v1
kind: Service
metadata:name: myserver-sts-servicenamespace: myserver
spec:clusterIP: None # 这里注意,搭配sts的svc没有指定IP地址,也就是一个无头的svc,所以请求svc的时候,请求是直接轮训到的后端pod的ports:- name: httpport: 80selector: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-myappnamespace: myserver
spec:selector:matchLabels:app: myserver-myapp-frontendtemplate:metadata:labels:app: myserver-myapp-frontendspec: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的keyoperator: Exists # operator表示容忍关系, Exists表示只要有一个容忍度匹配即可effect: NoSchedule # effect表示容忍类型,NoSchedule表示节点不应该被调度到这个容忍度匹配的 Pod 上(意思是就算你有NoSchedule,我也可以调度)hostNetwork: truehostPID: truecontainers:- name: myserver-myapp-frontendimage: nginx:1.20.2-alpine ports:- containerPort: 80---
apiVersion: v1
kind: Service
metadata:name: myserver-myapp-frontendnamespace: myserver
spec:ports:- name: httpport: 80targetPort: 80nodePort: 30018protocol: TCPtype: NodePortselector: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>

CoreDNS与k8s资源对象详解-Day03相关推荐

  1. jQuery的deferred对象详解

    阮一峰大神的关于jQuery的deferred对象详解 http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_ ...

  2. 【ES6】Promise对象详解

    [ES6]Promise对象详解 一.Promise对象的含义 二.Promise对象的用法 三.Promise对象的几个应用[重点] 1.时间延迟函数 2.图片异步加载 查看更多ES6教学文章: 参 ...

  3. javascript BOM对象详解

    javascript BOM对象详解 目标:本章节将分为9点详细介绍有关BOM对象的知识点 1.什么是BOM 2.BOM的构成 3.顶级对象window 4.window对象常见事件(页面加载事件和体 ...

  4. Javascript中的Document对象详解

    Document对象详解 document 文挡对象 - JavaScript脚本语言描述           -------------------------------------------- ...

  5. 转载 雨松mono Unity获取游戏对象详解(来自我的长微博)

    Unity获取游戏对象详解(来自我的长微博) 转载 自 雨松mono 本文固定链接: http://www.xuanyusong.com/archives/2768 转载请注明: 雨松MOMO 201 ...

  6. html内置时间对象,JavaScript中的常用事件,以及内置对象详解

    原标题:JavaScript中的常用事件,以及内置对象详解 今天是刘小爱自学Java的第81天. 感谢你的观看,谢谢你. 话不多说,开始今天的学习: 学前端有一个非常权威的组织,也就是w3c,其有个专 ...

  7. JS----window对象详解

    一.说明 他是JS中最大的对象,它描述的是一个浏览器窗口,一般要引用他的属性和方法时,不需要用"Window.XXX"这种形式,而是直接使用"XXX".一个框架 ...

  8. Helm 3 完整教程(五):Helm 内置对象详解

    推荐阅读 Helm3(K8S 资源对象管理工具)视频教程:https://edu.csdn.net/course/detail/32506 Helm3(K8S 资源对象管理工具)博客专栏:https: ...

  9. JavaScript高级编程--对象详解

    对象详解 Object.prototype.hasOwnProperty() 返回布尔 (原型对象的方法) 表示是否是对象自身的属性.所有实例对象都可以访问 这个方法会查找一个对象是否有某个属性,但是 ...

最新文章

  1. freeswitch呼叫流程分析
  2. ehchache验证缓存过期的api_Ehcache缓存时间设置
  3. 周杰伦178首歌被网易云侵权 单曲仅获赔4500元
  4. Linux kernel进行编译时提示No rule to make target `menconfig'
  5. html制作摩天轮,LED幻彩摩天轮的制作方法
  6. SMARTS决策引擎技术白皮书
  7. 五年高考三年模拟暗部软件库_BIM软件-关于Lumion的这些,你真的了解了吗?
  8. 技术文化和惨淡命运 —— 怀念中国雅虎----转载
  9. PcShare2007 暗桩
  10. imindmap思维导图免费下载
  11. 百善孝为先,万恶淫为首
  12. win10下sticky notes(便笺)数据存放地址、数据备份及恢复
  13. SiT2020:抗冲击抗振动宽温振荡器,1-110MHz之间频率,SOT23-5封装
  14. 体重预测[线性回归]
  15. 银行存管java 对接_Jay su-华正商务旅行社-4年中级java工程师-猿急送
  16. 如何用淘宝引流卖产品?如何利用淘宝问答功能引流到微信?
  17. 记一篇迟到的2019年年终总结
  18. 网易数据治理工具产品实践
  19. TCL加码半导体,能走好显示面板国产化最后一段路吗?
  20. opencv双目标定常见问题总结

热门文章

  1. 请用美丽欢呼-------Day38
  2. Nginx的简单使用
  3. office wps之间的乱码
  4. 移动端开发_手机快速登录
  5. vue 父子组件传值小白教程
  6. JavaWeb入门-JQuery
  7. Win10家庭版笔记本电脑开热点时显示“我们无法设置移动热点”
  8. office2013 VOl下载地址
  9. 汇编语言从安装到使用dosbox
  10. git配置与查看当前配置