YAZONG 我的开源

Kubernetes(十)服务调度与编排(10.5/6)深入Pod - pod相关的点点滴滴(上/下)

  , , ,
0 评论0 浏览

什么是POD?

K8S为什么要设计POD?

直接用容器不是更简单吗?

场景:多个服务、多个应用,要同时运行在一台机器上,但是每个容器只能运行一个服务,容器是单进程模型的,如果一个容器跑多个服务,那么肯定是违背了docker的运行原则的,后患无穷。

那么多个容器是如何调度在同一个机器上的呢?

(1)比如一个节点,内存还2.5GB,三个服务等待调度,分别占用1GB内存,如果一个个容器去调度的话,那么调度前两个是没问题的,最后一个是不够的。那么在调度层面,如果直接使用容器的话,肯定会有问题的。

因为POD是K8S中最小的调度单位,是原子单位,它的调度是按照整个POD的资源需求来做的,那么这个问题就解开了,当然了,POD并不是只是因为这个需求而设计的。

毕竟,这个问题可以通过另类手法绕过去,所以这样单单设计一个POD的代价太大。

(2)POD对K8S的另一个更重要的作用,POD是一个逻辑的概念,在物理机器上并不是真实存在的一个POD,没有POD的一个边界,真正处理的还是一个容器的隔离。

像,namespace,group,具体来说,POD的本质就是共享了同一个network namespace/共享网络,共享了同一个volume/共享存储,比如docker run 使用--net指定一个网络,--volume 指定一个存储,这样也可以让一个容器共享另一个容器的网络和存储,但是这样的潜在问题,这样是对容器的启动顺序有要求的,这样多个容器就不是一个对等的关系了,处理一起非常复杂。

(3)这时可以轮到POD出场了,POD用到了中间容器/pause容器,pause容器并不需要在显示中配置声明,每个POD都会有,POD启动的第一个就是pause容器,在配置文件中定义的容器都是通过joinnetworknamespace的方式跟pause容器关联在一起的。

pause容器是否会影响性能?pause是暂停,永远不做,不会占用计算机资源,并且其镜像只有100KB-200KB,不会占用很大内存。

=======================这里从实践上看下POD的特点。

POD对网络的设计

[root@node-1 deep-in-kubernetes]# mkdir 7-pod
[root@node-1 deep-in-kubernetes]# cd 7-pod

此yaml配置文件有俩容器。

类型是POD,更简单一些,相当于deployment中的template模板部分。这里未使用deployment来管理。

[root@node-1 7-pod]# cat pod-network.yaml  
apiVersion: v1
kind: Pod
metadata:
  name: pod-network
spec:
  containers:
  - name: web
    image: hub.mooc.com/kubernetes/web:v1
    ports:
    - containerPort: 8080
  - name: dubbo
    env:
    - name: DUBBO_PORT
      value: "20881"
    image: hub.mooc.com/kubernetes/dubbo:v1
    ports:
    - containerPort: 20881
      hostPort: 20881
      protocol: TCP
[root@node-1 7-pod]# kubectl create -f pod-network.yaml 
pod/pod-network created
[root@node-1 7-pod]# kubectl get pods -o wide
NAME          READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATES
pod-network   2/2     Running   0          43s   10.200.247.1   node-2   <none>           <none>

image.png

#进入dubbo容器,可以看到所有POD的端口
[root@node-2 ~]# crictl exec -it 5036dc8de1bca sh

#查看网络监听状况
/ # netstat -lntup

image.png

#查看当前的容器是DUBBO

/ # ps -ef

image.png

/ # wget localhost:8080

#能访问通,说明在dubbo容器中是可以访问到tomcat容器服务的

#说明容器之间是共享网络的,是可以通过localhost去通讯。

image.png

/ # cat index.html 
Apache Tomcat/8.0.51
/ # ifconfig
#看下IP地址

image.png

#看下网络设备

/ # ip add

image.png

#去到另一个tomcat容器中,可以看到自己的端口和dubbo的端口
[root@node-2 ~]# crictl exec -it b34fb88dcaef2 sh
/usr/local/tomcat # netstat -lntup

image.png

#看下自己的IP,发现跟前面容器的IP是一样的。
#共享POD的唯一的IP地址
/usr/local/tomcat # ifconfig

image.png

#网络设备跟前面的容器的网络设备也是一样的,共享了网络设备

image.png

#删除服务
[root@node-1 7-pod]# kubectl delete -f pod-network.yaml 
pod "pod-network" deleted
[root@node-1 ~]# kubectl get pods -o wide
No resources found in dev namespace.
#因为POD跟deployment不太一样,如果修改POD的字段的话,有很多字段是不可以修改的,所以说在操作POD时,要先删除,后创建。

POD对volume存储的设计

[root@node-1 deep-in-kubernetes]# mkdir 7-pod
[root@node-1 deep-in-kubernetes]# cd 7-pod   

[root@node-1 7-pod]# cat pod-volume.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-volume
spec:
  containers:
  - name: web
    image: hub.mooc.com/kubernetes/web:v1
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: shared-volume
	#把这个目录挂载到这个容器的"shared-web"下面
	#这个例子没那么贴切,WEB和DUBBO没必要放在一个POD里,也没必要共享目录。
	#在真实的业务场景中比较常见的多种机的POD,一个是主机,一个是辅助
	#比如业务容器和日志容器可以共享一个日志目录,业务容器负责写日志,采集容器负责把日志发送到kafka或ES中保存起来。
      mountPath: /shared-web
  - name: dubbo
    env:
    - name: DUBBO_PORT
      value: "20881"
    image: hub.mooc.com/kubernetes/dubbo:v1
    ports:
    - containerPort: 20881
      hostPort: 20881
      protocol: TCP
    volumeMounts:
    - name: shared-volume
	#注意这个名字必须保持一致
	#把这个目录挂载到这个容器的"shared-dubbo"下面
      mountPath: /shared-dubbo
#前面只有俩空格,说明volumes是放置在POD层面	  
#一旦POD设置了volumes,所有POD的容器是都可以共同使用的
  volumes:
  - name: shared-volume
  #主机的目录
    hostPath:
      path: /shared-volume-data
[root@node-1 7-pod]# kubectl create -f pod-volume.yaml
pod/pod-volume created

[root@node-1 7-pod]# kubectl get pods -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP              NODE     NOMINATED NODE   READINESS GATES
pod-volume   2/2     Running   0          3s    10.200.247.59   node-2   <none>           <none>

[root@node-2 ~]# crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                       ATTEMPT             POD ID
7cd4b707e2633       72c4c898918b5       14 seconds ago      Running             dubbo                      0                   411b25c95bdcf
8cc0e3dd64f45       0d9200b59e63a       14 seconds ago      Running             web                        0                   411b25c95bdcf
#进入DUBBO镜像,在挂载目录做测试文件
#当重新创建”pod-volume.yaml”时,下述目录中的文件依然存在。

[root@node-2 ~]# crictl exec -it 7cd4b707e2633 sh
/ # cd shared-dubbo/
/shared-dubbo # ls
/shared-dubbo # touch abc
/shared-dubbo # ls
abc
#去到另外一个容器,看文件是否是共享的

[root@node-2 ~]# crictl exec -it 8cc0e3dd64f45 sh
/usr/local/tomcat # cd /shared-web/
/shared-web # ls
abc
#这里不要删除服务,在下一节”POD的hosts文件”需要使用。
#因为POD跟deployment不太一样,如果修改POD的字段的话,有很多字段是不可以修改的,所以说在操作POD时,要先删除,后创建。

POD的hosts文件

#基于上一节”POD对volume存储的设计”中的pod-volume.yaml服务。
[root@node-2 ~]# crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                       ATTEMPT             POD ID
7cd4b707e2633       72c4c898918b5       14 seconds ago      Running             dubbo                      0                   411b25c95bdcf
8cc0e3dd64f45       0d9200b59e63a       14 seconds ago      Running             web                        0                   411b25c95bdcf
#查看dubbo的hosts
[root@node-2 ~]# crictl exec -it 7cd4b707e2633 cat /etc/hosts   
# Kubernetes-managed hosts file.
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
10.200.247.62   pod-volume
#查看tomcat的hosts
[root@node-2 ~]# crictl exec -it 8cc0e3dd64f45 cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
10.200.247.62   pod-volume

#发现上述两个容器的hosts文件是一样的,但是跟当前主机的hosts内容是不一样的。

[root@node-2 ~]# cat /etc/hosts
127.0.0.1   localhost
172.16.1.21 node-1
172.16.1.22 node-2
172.16.1.23 node-3

172.16.1.100 kxsw-1

10.0.0.22 harbor-1
10.0.0.23 harbor-2

10.0.0.21   hub.mooc.com
10.0.0.22   tomcat.mooc.com
10.0.0.22   api.mooc.com
10.0.0.22   springboot.mooc.com
10.0.0.22   web.mooc.com
10.0.0.22   k8s-web.mooc.com
10.0.0.22   web-dev.mooc.com
10.0.0.22   web-recreate.mooc.com
10.0.0.22   web-rollingupdate.mooc.com
10.0.0.22   web-bluegreen.mooc.com

为啥容器的hosts文件是一样的,但是跟当前主机的hosts内容是不一样的呢?

说明hosts文件是POD负责创建的,hosts文件是POD管理的,而不是容器自己管理的。

当自己要自定义hosts文件时,不能直接去修改POD管理的hosts文件,因为POD的设计要时刻保持所有POD下的hosts文件永远是一致的,所以就不能在容器中直接去修改hosts文件。

#这里先删除上一节”POD对volume存储的设计”中的pod-volume.yaml服务。
[root@node-1 7-pod]# kubectl delete -f pod-volume.yaml 
pod "pod-volume" deleted
[root@node-1 7-pod]# kubectl get pods -o wide
No resources found in dev namespace.
#因为POD跟deployment不太一样,如果修改POD的字段的话,有很多字段是不可以修改的,所以说在操作POD时,要先删除,后创建。

#通过yaml文件对hosts文件修改

[root@node-1 7-pod]# cat pod-volume2.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-volume
spec:
#指定一个worker节点的IP,把hostname绑定在这个IP地址上,可以绑定多个hostname。
  hostAliases:
  - ip: "10.0.0.22"
    hostnames:
    - "web.mooc.com"
  containers:
  - name: web
    image: hub.mooc.com/kubernetes/web:v1
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: shared-volume
      mountPath: /shared-web
  - name: dubbo
    env:
    - name: DUBBO_PORT
      value: "20881"
    image: hub.mooc.com/kubernetes/dubbo:v1
    ports:
    - containerPort: 20881
      hostPort: 20881
      protocol: TCP
    volumeMounts:
    - name: shared-volume
      mountPath: /shared-dubbo
  volumes:
  - name: shared-volume
    hostPath:
      path: /shared-volume-data
[root@node-1 7-pod]# kubectl create -f pod-volume2.yaml 
pod/pod-volume created
[root@node-1 7-pod]# kubectl get pods -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP              NODE     NOMINATED NODE   READINESS GATES
pod-volume   2/2     Running   0          11s   10.200.247.60   node-2   <none>           <none>
[root@node-2 ~]# crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                       ATTEMPT             POD ID
e674dca93dd84       72c4c898918b5       22 seconds ago      Running             dubbo                      0                   bbb2f8108b8c6
8d127586bd041       0d9200b59e63a       22 seconds ago      Running             web                        0                   bbb2f8108b8c6
#核实加入的host配置
[root@node-2 ~]# crictl exec -it e674dca93dd84 cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
10.200.247.60   pod-volume

# Entries added by HostAliases.
10.0.0.22       web.mooc.com
[root@node-2 ~]# crictl exec -it 8d127586bd041 cat /etc/hosts           
# Kubernetes-managed hosts file.
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
10.200.247.60   pod-volume

# Entries added by HostAliases.
10.0.0.22       web.mooc.com
#删除服务
[root@node-1 7-pod]# kubectl delete -f pod-volume2.yaml 
pod "pod-volume" deleted
[root@node-1 ~]# kubectl get pods -o wide
No resources found in dev namespace.
#因为POD跟deployment不太一样,如果修改POD的字段的话,有很多字段是不可以修改的,所以说在操作POD时,要先删除,后创建。

POD对namespace(network)的管理

除了网络部分是在POD级别管理以外,所有的Linux的namespace的东西都属于POD级别管理。

下述网络和进程等这些东西的定义都是在POD级别的。

说明,以后要在这些方面做些调整和变化的时候,一定小心,不要在容器层面去做,直接在容器层面去做是错误的。

[root@node-1 7-pod]# cat pod-volume3.yaml  
apiVersion: v1
kind: Pod
metadata:
  name: pod-volume
spec:
#是否使用宿主机的网路
  hostNetwork: true
#是否使用宿主机的PID的namespace
  hostPID: true
#指定一个worker节点的IP,把hostname绑定在这个IP地址上,可以绑定多个hostname。
  hostAliases:
  - ip: "10.0.0.22"
    hostnames:
    - "web.mooc.com"
  containers:
  - name: web
    image: hub.mooc.com/kubernetes/web:v1
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: shared-volume
      mountPath: /shared-web
  - name: dubbo
    env:
    - name: DUBBO_PORT
      value: "20881"
    image: hub.mooc.com/kubernetes/dubbo:v1
    ports:
    - containerPort: 20881
      hostPort: 20881
      protocol: TCP
    volumeMounts:
    - name: shared-volume
      mountPath: /shared-dubbo
  volumes:
  - name: shared-volume
    hostPath:
      path: /shared-volume-data
[root@node-1 7-pod]# kubectl create -f pod-volume3.yaml 
pod/pod-volume created
[root@node-1 7-pod]# kubectl get pods -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
pod-volume   2/2     Running   0          4s    172.16.1.22   node-2   <none>           <none>
[root@node-2 ~]# crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                       ATTEMPT             POD ID
0b687b1a216e3       72c4c898918b5       18 seconds ago      Running             dubbo                      0                   a933d4e68de5c
f4fb29c1427bc       0d9200b59e63a       19 seconds ago      Running             web                        0                   a933d4e68de5c

[root@node-2 ~]# crictl exec -it 0b687b1a216e3 sh

#发现了很多端口,说明使用了宿主机的network namespace。
/ # netstat -lntup

image.png

#发现了很多进程,也就是说当前使用了宿主机的进程空间。
/ # ps -ef

image.png

#删除服务
[root@node-1 7-pod]# kubectl delete -f pod-volume3.yaml 
pod "pod-volume" deleted
[root@node-1 ~]# kubectl get pods -o wide
No resources found in dev namespace.
#因为POD跟deployment不太一样,如果修改POD的字段的话,有很多字段是不可以修改的,所以说在操作POD时,要先删除,后创建。

容器级别参数:lifecycle生命周期

定义生命周期的管理:

(1)在容器启动之后,可以执行一个命令。

(2)注意一下,这个启动之后,postStart是什么意思,当容器执行了EntryPoint命令,进行启动的时候,也会同时的执行exec的command,这俩是一个并行的过程,并没有等待的关系,是同时的进行的,所以这里一定不要把容器完全启动后再做的事放在这里,这样肯定会有问题的。

(3)postStart相对应的,叫preStop,叫停止之前要做的事情。

(4)preStop跟postStart区别,proStop是串行的,意思是容器停止之前会执行这条脚本,并且等待这个脚本执行完成之后才会给容器发送停止sigterm信号。

如果这个脚本执行时间比较长,那么会等待这个脚本执行完再进行停止容器。

如果这个脚本执行时间非常长,那么也不会一直等待,有个超时,一旦超时,那么就自动跳过。

(5)preStop一般用来做容器的优雅退出。

[root@node-1 7-pod]# cat pod-volume4.yaml  
apiVersion: v1
kind: Pod
metadata:
  name: pod-volume
spec:
  hostNetwork: true
  hostPID: true
  hostAliases:
  - ip: "10.0.0.22"
    hostnames:
    - "web.mooc.com"
  containers:
  - name: web
    image: hub.mooc.com/kubernetes/web:v1
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: shared-volume
      mountPath: /shared-web
    lifecycle:
      postStart:
        exec:
          command: ["/bin/sh", "-c", "echo web starting ... >> /var/log/messages"]
      preStop:
        exec:
#当执行kubectl delete时,可能preStop这个脚本是执行非常快的,一旦执行完了,就立刻把容器停掉了,以至于屏幕缓冲区可能还没刷新,容器就给杀掉了。
#为了测试,加个缓冲时间,模拟命令的执行时长。
#preStop一般用来做容器的优雅退出。
          command: ["/bin/sh", "-c", "echo web stopping ... >> /var/log/messages && sleep 3"]
  - name: dubbo
    env:
    - name: DUBBO_PORT
      value: "20881"
    image: hub.mooc.com/kubernetes/dubbo:v1
    ports:
    - containerPort: 20881
      hostPort: 20881
      protocol: TCP
    volumeMounts:
    - name: shared-volume
      mountPath: /shared-dubbo
  volumes:
  - name: shared-volume
    hostPath:
      path: /shared-volume-data
[root@node-1 7-pod]# kubectl create -f pod-volume4.yaml 
pod/pod-volume created
[root@node-1 7-pod]# kubectl get pods -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
pod-volume   2/2     Running   0          4s    172.16.1.22   node-2   <none>           <none>
[root@node-2 ~]# crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                       ATTEMPT             POD ID
0d4de49663614       72c4c898918b5       14 seconds ago      Running             dubbo                      0                   9903529f34c5a
78a3be052e9f8       0d9200b59e63a       14 seconds ago      Running             web                        0                   9903529f34c5a
#进入tomcat的容器。
[root@node-2 ~]# crictl exec -it 78a3be052e9f8 sh
/usr/local/tomcat # tail -f /var/log/messages 
web starting ...
web stopping ...
FATA[0039] execing command in container: command terminated with exit code 137 


#执行delete删除服务操作
[root@node-1 7-pod]# kubectl delete -f pod-volume4.yaml     
pod "pod-volume" deleted

#镜像中的日志输出stop并退出容器
[root@node-2 ~]# crictl exec -it 78a3be052e9f8 sh
/usr/local/tomcat # tail -f /var/log/messages 
web starting ...
web stopping ...
FATA[0039] execing command in container: command terminated with exit code 137 

#另外,因为POD跟deployment不太一样,如果修改POD的字段的话,有很多字段是不可以修改的,所以说在操作POD时,要先删除,后创建。
[root@node-1 7-pod]# kubectl get pods -o wide         
No resources found in dev namespace.

POD的生命周期(状态)

(1)POD最开始处于pending未被调度状态,有几种原因还没有被调度的POD,比如内存不足,匹配不到满足的节点,拉取不到镜像等,都会导致POD长时间处于pending状态。

(2)如果pending过了,那么就证明POD找到了合适的机器了,此时,POD处于containerCreating创建容器的状态,初始化的状态,这个状态的时间不会持续很久。

(3)如果containerCreating过了,那么容器就会进入Running运行中状态。

(另外)下述两种状态,只有普通job和cronJob类型的POD会达到这两种状态。

如果成功运行,就会处于Successed成功状态。

如果失败,就会处于Failed失败状态。

(4)如果POD运行结束了,那么正常退出,容器的退出值是0,就是successed,如果是非0,那么就是failed。

(5)如果是长期运行的应用,并且服务配置了健康检查,通过了健康检查的POD就会处于ready状态。

(6)如果未通过健康检查的POD就会处于CrashLoopBackOff状态(crash循环不长,POD处于一个等待状态),当出现的次数越多,那么等待的时间就越久。如果出现这个CrashLoopBackOff状态,那么服务就是一直处于启动失败状态。

(7)异常Unknown未知状态,一般是API-SERVER未收到这个POD信息的汇报,一般是,kubelet与API-SERVER之间的通信是有问题的。

POD的ProjectedVolume

POD中非常重要,很常见的功能:ProjectedVolume投射数据卷。

这里加了Projected,肯定跟之前说的volume不是一回事,并不是挂载宿主机的目录的,也不会用来容器之间共享存储的,是比较轻量级的volume,是由API-SERVER投射到POD中的。

比如API-SERVER知道POD需要一个文件,就在POD启动的时候,就把文件扔给了POD,那么在程序启动的时候,就会读到这个文件。

K8S根据这个场景,预先定义好了三种使用方式:

Secret

ConfigMap

DownwardAPI(不是DownloadAPI!)

这三种方式,使用了ProjectedVolume。

方式1:Secret

Secret存放秘钥,加密的数据。存在ETCD中,比如用户名密码之类的。

K8S也有很多在使用Secret。

POD原生Secret(serviceAccount)

#启动一个springboot-web:v1测试POD

[root@node-1 configs]# pwd
/root/mooc-k8s-demo/configs
[root@node-1 configs]# kubectl apply -f springboot-web.yaml 
deployment.apps/springboot-web-demo created
service/springboot-web-demo created
[root@node-1 configs]# kubectl get pods -o wide
NAME                                   READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATES
springboot-web-demo-7564d56d5f-pr9zm   1/1     Running   0          54s   10.200.247.3   node-2   <none>           <none>

#查看POD的描述文件内容

[root@node-1 configs]# kubectl get pods springboot-web-demo-7564d56d5f-pr9zm -o yaml

image.png

image.png

#这里看下Secret在serviceAccount中是如何使用的。

#K8S会把serviceAccount自动的加入到每一个POD中。

#查看POD原生的Secret

#查询下现在的secret
[root@node-1 7-pod]# kubectl get secret
NAME                  TYPE                                  DATA   AGE
default-token-rd2zj   kubernetes.io/service-account-token   3      5d11h

[root@node-1 7-pod]# kubectl get secret default-token-rd2zj -o yaml

image.png

[root@node-2 ~]# crictl ps
CONTAINER           IMAGE               CREATED              STATE               NAME                       ATTEMPT             POD ID
6fe80909e74df       e5e494a7ee468       About a minute ago   Running             springboot-web-demo        0                   7d963e1c91ff4

(

BASE64的生成方式非常简单.-n是让imooc后无回车

比如echo -n imooc|base64

)

#进入POD镜像查看BASE64解密后的内容

[root@node-2 ~]# crictl exec -it 6fe80909e74df sh
/ # cd /var/run/secrets/kubernetes.io/serviceaccount
/run/secrets/kubernetes.io/serviceaccount # ls -l

image.png

#这里文件中的内容就是BASE64解密后的内容
/run/secrets/kubernetes.io/serviceaccount # cat ca.crt 

image.png

/run/secrets/kubernetes.io/serviceaccount # cat namespace 
dev/run/secrets/kubernetes.io/serviceaccount
dev/run/secrets/kubernetes.io/serviceaccount # cat token

image.png

#删除服务
[root@node-1 configs]# kubectl delete -f springboot-web.yaml    
deployment.apps "springboot-web-demo" deleted
service "springboot-web-demo" deleted
创建自定义Secret

#看了K8S对Secret的使用,可以创建自己的Secret。

[root@node-1 7-pod]# cat secret.yaml 
apiVersion: v1
kind: Secret
metadata:
#数据库密码
  name: dbpass
#不透明、浑浊的。一般用的secret类型都是这个Opaque。
#除非用K8S中内置的类型,比如serviceAccount中的secret中的token。
type: Opaque
data:
  username: aW1vb2M=
  #经过BASE64加密后的用户名和密码
  passwd:  aW1vb2MxMjM=
#Secret创建完成,相当于把配置写到了ETCD中,但还是需要POD来用的。
[root@node-1 7-pod]# kubectl create -f secret.yaml 
secret/dbpass created
[root@node-1 7-pod]# kubectl get all
No resources found in dev namespace.
[root@node-1 7-pod]# cat pod-secret.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-secret
spec:
  containers:
  - name: springboot-web
    image: hub.mooc.com/kubernetes/springboot-web:v1
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: db-secret
      mountPath: /db-secret
      readOnly: true
  volumes:
  - name: db-secret
    projected:
      sources:
      - secret:
          name: dbpass
[root@node-1 7-pod]# kubectl create -f pod-secret.yaml 
pod/pod-secret created
[root@node-1 7-pod]# kubectl get pods -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATES
pod-secret   1/1     Running   0          11s   10.200.247.2   node-2   <none>           <none>
[root@node-2 ~]# crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                       ATTEMPT             POD ID
449339eb56b0b       e5e494a7ee468       27 seconds ago      Running             springboot-web             0                   f3666f5f7fdc4
#找到secret.yaml中配置的用户名密码
[root@node-2 ~]# crictl exec -it 449339eb56b0b sh
/ # cd /db-secret
/db-secret # ls -l
total 0
lrwxrwxrwx    1 root     root            13 Nov 21 19:09 passwd -> ..data/passwd
lrwxrwxrwx    1 root     root            15 Nov 21 19:09 username -> ..data/username
#有了下述的用户名和密码,就可以通过这个目录下的内容去访问数据库了。
/db-secret # cat passwd 
imooc123
/db-secret # cat username 
imooc

#如果用户名或者密码错了咋整。这里把密码修改成和用户名一样。可以通过secret.yaml动态修改容器里的内容。

[root@node-1 7-pod]# cat secret.yaml 
apiVersion: v1
kind: Secret
metadata:
#数据库密码
  name: dbpass
#不透明、浑浊的。一般用的secret类型都是这个Opaque。
#除非用K8S中内置的类型,比如serviceAccount中的secret中的token。
type: Opaque
data:
  username: aW1vb2M=
  #经过BASE64加密后的用户名和密码
  passwd:  aW1vb2M=

[root@node-1 7-pod]# kubectl apply -f secret2.yaml 
secret/dbpass configured

#再次核实一下,可能会有一段时间的延迟。
[root@node-2 ~]# crictl exec -it 449339eb56b0b sh
/ # cd /db-secret
/db-secret # cat username
imooc
/db-secret # cat passwd
imooc
#加”-n”不会有回车
/db-secret # cat -n passwd 
     1  imooc
#删除服务
[root@node-1 7-pod]# kubectl delete -f pod-secret.yaml    
pod "pod-secret" deleted
[root@node-1 ~]# kubectl get pods -o wide
No resources found in dev namespace.
#因为POD跟deployment不太一样,如果修改POD的字段的话,有很多字段是不可以修改的,所以说在操作POD时,要先删除,后创建。

方式2:ConfigMap

方式2-1:创建自定义的configmap-文件的创建功能
#把这个配置文件放到K8S中,最好的方式就是使用ConfigMap。

[root@node-1 7-pod]# cat game.properties 
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30

#以文件的创建功能(Secret也可以)来创建自定义的configmap:给创建的configmap起个名字web-game,指定文件game.properties,从这个game.properties配置文件创建一个configmap(configmap可以简写成cm)。

[root@node-1 7-pod]# kubectl create configmap web-game --from-file game.properties 
configmap/web-game created

#获取configmap中叫web-game名字的配置描述

#除了用配置文件,也可使用yaml文件的方式,把下面的整个内容复制了,直接通过”kubectl create-f XX.yaml”创建yaml文件也可以。.


[root@node-1 7-pod]# kubectl get cm web-game -o yaml
apiVersion: v1
data:
  game.properties: |
    enemies=aliens
    lives=3
    enemies.cheat=true
    enemies.cheat.level=noGoodRotten
    secret.code.passphrase=UUDDLRLRBABAS
    secret.code.allowed=true
    secret.code.lives=30
kind: ConfigMap
metadata:
  creationTimestamp: "2022-11-21T19:25:28Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        .: {}
        f:game.properties: {}
    manager: kubectl-create
    operation: Update
    time: "2022-11-21T19:25:28Z"
  name: web-game
  namespace: dev
  resourceVersion: "974922"
  uid: 491a2252-c23c-4f84-89dd-36791948f8b6

#配置文件创建好了之后,如何在POD中去使用?

[root@node-1 7-pod]# cat pod-game.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-game
spec:
  containers:
  - name: web
    image: hub.mooc.com/kubernetes/springboot-web:v1
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: game
	#容器里也定义了一个同名的game
      mountPath: /etc/config/game
      readOnly: true
  volumes:
  - name: game
    configMap:
	#用了刚才定义好的web-game
      name: web-game




#这个pod-game.yaml是把配置文件直接塞到了容器里面
[root@node-1 7-pod]# kubectl create -f pod-game.yaml 
pod/pod-game created
[root@node-1 7-pod]# kubectl get pods -o wide
NAME       READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATES
pod-game   1/1     Running   0          15s   10.200.247.4   node-2   <none>           <none>
[root@node-2 ~]# crictl ps
CONTAINER           IMAGE               CREATED              STATE               NAME                       ATTEMPT             POD ID
e442c49578aed       e5e494a7ee468       About a minute ago   Running             web                        0                   9d26f44e0731f

[root@node-2 ~]# crictl exec -it e442c49578aed sh
/ # cd /etc/config/game
/etc/config/game # ls -l
total 0
lrwxrwxrwx    1 root     root            22 Nov 21 19:33 game.properties -> ..data/game.properties
#程序可以访问这个配置文件拿到属性值了
#但是不可以把原程序ROOT/config下的log4j等配置文件通过ConfigMap的形式注入进去。因为下述game是一个目录,而不是一个文件。
#如果要映射到现有的目录的话,它也会把这个目录直接覆盖掉了,并不会替换这个目录下的某一个文件,用的是mount进去的所有文件。
/etc/config/game # cat game.properties 
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
修改configmap并监听变化
[root@node-2 ~]# crictl exec -it e442c49578aed sh
/ # cd /etc/config/game
#每隔五秒去看下这个配置的变化
/etc/config/game # watch -n 5 cat game.properties
[root@node-1 7-pod]# kubectl edit cm web-game
#修改enemies.cheat=true为enemies.cheat=false

image.png

#每隔五秒去看下这个配置的变化
/etc/config/game # watch -n 5 cat game.properties 
enemies=aliens
lives=3
enemies.cheat=false
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
#删除服务
[root@node-1 7-pod]# kubectl delete -f pod-game.yaml
pod "pod-game" deleted
[root@node-1 ~]# kubectl get pods -o wide
No resources found in dev namespace.
#因为POD跟deployment不太一样,如果修改POD的字段的话,有很多字段是不可以修改的,所以说在操作POD时,要先删除,后创建。
方式2-2: 创建自定义的configmap- yaml配置文件
[root@node-1 7-pod]# cat configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: configs
data:
  JAVA_OPTS: -Xms1024m
  LOG_LEVEL: DEBUG

[root@node-1 7-pod]# kubectl create -f configmap.yaml 
configmap/configs created
[root@node-1 7-pod]# kubectl get all
No resources found in dev namespace.

#第一种:通过环境变量的方式去使用

[root@node-1 7-pod]# cat pod-env.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-env
spec:
  containers:
  - name: web
    image: hub.mooc.com/kubernetes/springboot-web:v1
    ports:
- containerPort: 8080
#首先要有个环境变量
    env:
      - name: LOG_LEVEL_CONFIG
        valueFrom:
		#值从configMap的哪儿来
          configMapKeyRef:
		#configMap的名字是configs
            name: configs
		#具体的值是configs下的LOG_LEVEL
            key: LOG_LEVEL
[root@node-1 7-pod]# kubectl create -f pod-env.yaml 
pod/pod-env created
[root@node-1 7-pod]# kubectl get pods -o wide
NAME      READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATES
pod-env   1/1     Running   0          9s    10.200.247.6   node-2   <none>           <none>
[root@node-2 ~]# crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                       ATTEMPT             POD ID
20575ad199d38       e5e494a7ee468       19 seconds ago      Running             web                        0                   ddb2bd63fe00d

[root@node-2 ~]# crictl exec -it 20575ad199d38 sh
#发现已经被设置到了当前环境变量中去,程序就可以通过环境变量访问到这个值了

image.png

#删除服务
[root@node-1 7-pod]# kubectl delete -f pod-env.yaml
pod "pod-env" deleted
[root@node-1 ~]# kubectl get pods -o wide
No resources found in dev namespace.
#因为POD跟deployment不太一样,如果修改POD的字段的话,有很多字段是不可以修改的,所以说在操作POD时,要先删除,后创建。

第二种:通过参数的形式传进去

[root@node-1 7-pod]# cat pod-cmd.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-cmd
spec:
  containers:
  - name: web
    image: hub.mooc.com/kubernetes/springboot-web:v1
	#本质上是环境变量的使用方案,环境变量可以放到command的命令中去。
    command: ["/bin/sh", "-c", "java -jar /springboot-web.jar -DJAVA_OPTS=$(JAVA_OPTS)"]
    ports:
    - containerPort: 8080
#首先要有个环境变量
    env:
      - name: JAVA_OPTS
        valueFrom:
		#值从configMap的哪儿来
          configMapKeyRef:
		  #configMap的名字是configs
            name: configs
			#具体的值是configs下的JAVA_OPTS
			#可以把这个环境变量放到上述command的启动命令中去
            key: JAVA_OPTS
[root@node-1 7-pod]# kubectl create -f pod-cmd.yaml
pod/pod-cmd created
[root@node-1 7-pod]# kubectl get pods -o wide    
NAME      READY   STATUS    RESTARTS   AGE   IP              NODE     NOMINATED NODE   READINESS GATES
pod-cmd   1/1     Running   0          10s   10.200.247.11   node-2   <none>           <none>
[root@node-2 ~]# crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                       ATTEMPT             POD ID
51e0c3cfad222       e5e494a7ee468       18 seconds ago      Running             web                        0                   044905fd09aa4
[root@node-2 ~]# crictl exec -it 51e0c3cfad222 sh
/ # ps -ef
PID   USER     TIME  COMMAND
#发现已经被设置到了当前环境变量中去,程序就可以通过环境变量访问到这个值了
    1 root      0:07 java -jar /springboot-web.jar -DJAVA_OPTS=-Xms1024m
#删除服务
[root@node-1 7-pod]# kubectl delete -f pod-cmd.yaml       
pod "pod-cmd" deleted
[root@node-1 ~]# kubectl get pods -o wide
No resources found in dev namespace.
#因为POD跟deployment不太一样,如果修改POD的字段的话,有很多字段是不可以修改的,所以说在操作POD时,要先删除,后创建。

方式3:DownwardAPI

跟之前的Secret和ConfigMap不一样。

DownwardAPI(不是DownloadAPI!)是让在程序中可以取到POD本身对象的信息。

[root@node-1 7-pod]# cat pod-downwardapi.yaml
#看看downwardapi的更多用法。
apiVersion: v1
kind: Pod
metadata:
  name: pod-downwardapi
  labels:
    app: downwardapi
    type: webapp
spec:
  containers:
  - name: web
    image: hub.mooc.com/kubernetes/springboot-web:v1
    ports:
    - containerPort: 8080
    volumeMounts:
      - name: podinfo
#podinfo被容器挂载到了/etc/podinfo目录中
        mountPath: /etc/podinfo	
  volumes:
#这里是volumes的一些定义,取到了这些值,名字叫做podinf。
    - name: podinfo
      projected:
	  #来源
        sources:
		#来源下面的downwardAPI
        - downwardAPI:
            items:
              - path: "labels"
                fieldRef:
				#labels来源是metadata下的labels
                  fieldPath: metadata.labels
              - path: "name"
                fieldRef:
				#name来源是metadata下的name
                  fieldPath: metadata.name
              - path: "namespace"
                fieldRef:
				#namespace来源是metadata下的namespace
                  fieldPath: metadata.namespace 
			#除了metadata还有计算资源下的内容	  
              - path: "mem-request"
                resourceFieldRef:
				#比如CPU的请求是多少,可以配置具体的container下的resource
                  containerName: web
                  resource: limits.memory
[root@node-1 7-pod]# kubectl create -f pod-downwardapi.yaml  
pod/pod-downwardapi created
[root@node-1 7-pod]# kubectl get pods -o wide    
NAME              READY   STATUS    RESTARTS   AGE   IP               NODE     NOMINATED NODE   READINESS GATES
pod-downwardapi   1/1     Running   0          10s   10.200.139.104   node-3   <none>           <none>
[root@node-3 harbor]# crictl ps  
CONTAINER           IMAGE               CREATED             STATE               NAME                   ATTEMPT             POD ID
35329d96614d2       e5e494a7ee468       16 seconds ago      Running             web                    0                   ac073d3b1c7ca
[root@node-3 harbor]# crictl exec -it 35329d96614d2 sh
/ # cd /etc/podinfo
/etc/podinfo # ls -l
total 0
lrwxrwxrwx    1 root     root            13 Nov 21 20:11 labels -> ..data/labels
lrwxrwxrwx    1 root     root            18 Nov 21 20:11 mem-request -> ..data/mem-request
lrwxrwxrwx    1 root     root            11 Nov 21 20:11 name -> ..data/name
lrwxrwxrwx    1 root     root            16 Nov 21 20:11 namespace -> ..data/namespace
/etc/podinfo # cat labels 
app="downwardapi"
type="webapp"
/etc/podinfo # cat mem-request
#没配置限制内存,这里取到的就是本虚拟机的所有内存6.6GB。
6470250496
/etc/podinfo # cat name
pod-downwardapi
/etc/podinfo # cat namespace 
dev/etc/podinfo
#删除服务
[root@node-1 7-pod]# kubectl delete -f pod-downwardapi.yaml      
pod "pod-downwardapi" deleted
[root@node-1 ~]# kubectl get pods -o wide
No resources found in dev namespace.
#因为POD跟deployment不太一样,如果修改POD的字段的话,有很多字段是不可以修改的,所以说在操作POD时,要先删除,后创建。

标题:Kubernetes(十)服务调度与编排(10.5/6)深入Pod - pod相关的点点滴滴(上/下)
作者:yazong
地址:https://blog.llyweb.com/articles/2022/11/22/1669067467701.html