什么是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>
#进入dubbo容器,可以看到所有POD的端口
[root@node-2 ~]# crictl exec -it 5036dc8de1bca sh
#查看网络监听状况
/ # netstat -lntup
#查看当前的容器是DUBBO
/ # ps -ef
/ # wget localhost:8080
#能访问通,说明在dubbo容器中是可以访问到tomcat容器服务的
#说明容器之间是共享网络的,是可以通过localhost去通讯。
/ # cat index.html
Apache Tomcat/8.0.51
/ # ifconfig
#看下IP地址
#看下网络设备
/ # ip add
#去到另一个tomcat容器中,可以看到自己的端口和dubbo的端口
[root@node-2 ~]# crictl exec -it b34fb88dcaef2 sh
/usr/local/tomcat # netstat -lntup
#看下自己的IP,发现跟前面容器的IP是一样的。
#共享POD的唯一的IP地址
/usr/local/tomcat # ifconfig
#网络设备跟前面的容器的网络设备也是一样的,共享了网络设备
#删除服务
[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
#发现了很多进程,也就是说当前使用了宿主机的进程空间。
/ # ps -ef
#删除服务
[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
#这里看下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
[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
#这里文件中的内容就是BASE64解密后的内容
/run/secrets/kubernetes.io/serviceaccount # cat ca.crt
/run/secrets/kubernetes.io/serviceaccount # cat namespace
dev/run/secrets/kubernetes.io/serviceaccount
dev/run/secrets/kubernetes.io/serviceaccount # cat token
#删除服务
[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
#每隔五秒去看下这个配置的变化
/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
#发现已经被设置到了当前环境变量中去,程序就可以通过环境变量访问到这个值了
#删除服务
[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