Pod 的共享上下文包括一组 Linux 名字空间、控制组(cgroup)和可能一些其他的隔离方面, 即用来隔离容器的技术。 在 Pod 的上下文中,每个独立的应用可能会进一步实施隔离。Pod 类似于共享名字空间并共享文件系统卷的一组容器。
pod的基本操作
先新建一个nginx.yaml
# nginx.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx-container
image: nginx
根据yaml文件创建pod
kubectl apply -f nginx.yaml
查看pod资源
kubectl get pod
进入pod
#kubectl exec -it pod名 -c 容器名 -- bash 如果pod内只有一个容器,-c可省略
#kubectl exec -it pods/nginx-pod -c nginx-container -- bash
kubectl exec -it pods/nginx-pod -- bash
暴露pod端口
#将pod里的80端口映射到本机上
#kubectl port-forward pod名 宿主机端口:pod端口
kubectl port-forward nginx-pod 4000:80
查看pod日志
#kubectl logs pod名 -c 容器名 如果pod内只有一个容器,-c可省略
#kubectl logs -f pod名 -c 容器名 查看实时日志
#kubectl logs nginx-pod -c nginx-container
kubectl logs nginx-pod
删除pod
#kubectl delete pod pod名
kubectl delete pod nginx-pod
#或者根据创建pod的yaml文件来删除
kubectl delete -f nginx.yaml
查看pod的详细信息,kubectl describe pods pod名 ,可以查看k8s调度pod的一些详细信息,以及pod创建失败的排查
kubectl describe pods nginx-pod
pod的基本配置
- 设置容器启动命令
通过yaml配置文件里的command参数即可设置
apiVersion: v1
kind: Pod
metadata:
name: busybox-pod
spec:
containers:
- name: busybox-container
image: busybox
command: ['sh','-c','while true; do echo 原神 启动; sleep 1; done']
pod运行后,查看日志发现终端一直输出原神 启动
- pod的环境变量
apiVersion: v1
kind: Pod
metadata:
name: busybox-pod
spec:
containers:
- name: busybox-container1
image: busybox
command: ['sh','-c','while true; do echo $os; sleep 1; done']
env:
- name: os
value: "原神 启动"
- pod标签
apiVersion: v1
kind: Pod
metadata:
name: busybox-pod
labels:
app: busybox-pod
spec:
containers:
- name: busybox-container1
image: busybox
command: ['sh','-c','while true; do echo $os; sleep 1; done']
env:
- name: os
value: "原神 启动"
- 多容器
apiVersion: v1
kind: Pod
metadata:
name: multiple
spec:
containers:
- name: nginx
image: nginx
- name: curl
image: curlimages/curl
command: ['sh','-c','while true; do curl 127.0.0.1:80; sleep 1; done']
pod生命周期
- 初始化容器
初始化容器必须运行完成直至结束,若某初始化容器运行失败,那么kubernetes需要重启它直到成功完成,初始化容器必须按照定义的顺序执行,当且仅当前一个成功之后,后面的一个才能运行,只有所有初始化容器执行完成,主容器才会被执行
apiVersion: v1
kind: Pod
metadata:
name: busybox-pod
spec:
initContainers:
- name: init1
image: busybox
command: [ 'sh','-c','date && echo 1 && sleep 1' ]
- name: init2
image: busybox
command: [ 'sh','-c','date && echo 2 && sleep 1' ]
- name: init3
image: busybox
command: [ 'sh','-c','date && echo 3 && sleep 1' ]
containers:
- name: main-container
image: busybox
command: [ 'sh','-c','date && echo 启动成功哦 && sleep 3600' ]
- 生命周期钩子函数
kubernetes在主容器的启动之后和停止之前提供了两个钩子函数,post start:容器创建之后执行,如果失败了会重启容器
pre stop :容器终止之前执行,执行完成之后容器将成功终止,在其完成之前会阻塞删除容器的操作
apiVersion: v1
kind: Pod
metadata:
name: busybox-pod
spec:
containers:
- name: main-container
image: busybox
command: [ 'sh','-c','echo $(date) > /root/main && sleep 3600' ]
lifecycle:
postStart: # 在容器启动的时候执行一个命令,与主容器同时启动
exec:
command: [ 'sh','-c','echo $(date) > /root/postStart']
preStop: # 在容器停止之前停止之前的操作
exec:
command: [ "sh","-c","echo $(date) > /root/preStop && sleep 60" ]
postStart和main容器命令同一时间执行,在执行销毁pod的命令后,root目录下生成立preStop文件,并在60秒后容器会彻底销毁
- 容器探针
不承担业务流量。kubernetes提供了两种探针来实现容器探测,分别是:liveness probes:存活性探针,用于检测应用实例当前是否处于正常运行状态,如果不是,k8s会重启容器,readiness probes:就绪性探针,用于检测应用实例当前是否可以接收请求,如果不能,k8s不会转发流量
livenessProbe 决定是否重启容器,readinessProbe 决定是否将请求转发给容器
上面两种探针目前均支持三种探测方式:
- Exec命令:在容器内执行一次命令,如果命令执行的退出码为0,则认为程序正常,否则不正常
- TCPSocket:将会尝试访问一个用户容器的端口,如果能够建立这条连接,则认为程序正常,否则不正常
- HTTPGet:调用容器内Web应用的URL,如果返回的状态码在200和399之间,则认为程序正常,否则不正常
exec的示例
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: main-container
image: nginx
livenessProbe:
exec:
command: [ "sh","-c","exit 1" ] #退出码为1,表示本次探测失败
initialDelaySeconds: 1 # 容器启动后等待多少秒执行第一次探测
timeoutSeconds: 1 # 探测超时时间。默认1秒,最小1秒
periodSeconds: 3 # 执行探测的频率。默认是10秒,最小1秒
failureThreshold: 3 # 连续探测失败多少次才被认定为失败。默认是3。最小值是1
successThreshold: 1 # 连续探测成功多少次才被认定为成功。默认是1
容器会一直重启
tcpSocket的示例
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: main-container
image: nginx
livenessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 1 # 容器启动后等待多少秒执行第一次探测
timeoutSeconds: 1 # 探测超时时间。默认1秒,最小1秒
periodSeconds: 3 # 执行探测的频率。默认是10秒,最小1秒
failureThreshold: 3 # 连续探测失败多少次才被认定为失败。默认是3。最小值是1
successThreshold: 1 # 连续探测成功多少次才被认定为成功。默认是1
httpGet的示例
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: main-container
image: nginx
livenessProbe:
httpGet:
path: / #URI地址
port: 80 #端口号
scheme: HTTP #支持的协议,http或者https
initialDelaySeconds: 1 # 容器启动后等待多少秒执行第一次探测
timeoutSeconds: 1 # 探测超时时间。默认1秒,最小1秒
periodSeconds: 3 # 执行探测的频率。默认是10秒,最小1秒
failureThreshold: 3 # 连续探测失败多少次才被认定为失败。默认是3。最小值是1
successThreshold: 1 # 连续探测成功多少次才被认定为成功。默认是1
上面都是livenessProbe的示例,下面来几个readinessProbe的示例,readinessProbe检测失败不会重启,判定pod未就绪,就不会将请求分发给它
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx-demo
name: nginx-demo
spec:
type: NodePort
selector:
app: nginx-pod
ports:
- port: 80 #service端口
nodePort: 30000 #指定绑定的node的端口(默认的取值范围是:30000-32767), 如果不指定,会默认分配
targetPort: 80 #代理的目标端口
---
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: nginx-pod
spec:
containers:
- name: main-container
image: nginx
readinessProbe:
httpGet:
path: /666 #URI地址
port: 80 #端口号
scheme: HTTP #支持的协议,http或者https
initialDelaySeconds: 1 # 容器启动后等待多少秒执行第一次探测
timeoutSeconds: 1 # 探测超时时间。默认1秒,最小1秒
periodSeconds: 3 # 执行探测的频率。默认是10秒,最小1秒
failureThreshold: 3 # 连续探测失败多少次才被认定为失败。默认是3。最小值是1
successThreshold: 1 # 连续探测成功多少次才被认定为成功。默认是1
为了直观的看见流量的控制,所以新建一个service服务
有上面的输出可知,在readinessProbe检测pods失败后,查看nginx-demo的endpoints并没有显示pods的ip,并且通过service访问nginx-pod失败,在进入容器创建了readinessProbe可以访问的路径后,查看endpoints显示了pod的ip,并且通过service可以访问到pod的服务了
PS:其实可以通过kubectl port-forward 来代理pod,访问pod服务,无论readinessProbe检测成功与失败,pod功能是正常的,但是service不会将流量转发过来
pod的基本存储
- EmptyDir
EmptyDir就是Host(主机)上的一个空目录。EmptyDir是在Pod被分配到Node时创建的,它的初始内容为空,并且无须指定宿主机上对应的目录文件,因为kubernetes会自动分配一个目录,当Pod销毁时, EmptyDir中的数据也会被永久删除。 EmptyDir用途如下:临时空间,例如用于某些应用程序运行时所需的临时目录,最常用的就是一些程序缓存,且无须永久保留。或者一个容器需要从另一个容器中获取数据的目录(多容器共享目录)
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: busybox-write
image: busybox
command: ['sh','-c','while true; do echo $(date) 原神 启动 >> /root/1.log; sleep 1; done'] # 初始命令,向1.log目录下不断的最佳内容
volumeMounts: # 将logs-volume挂在到nginx容器中,对应的目录为 /var/log/nginx
- name: logs
mountPath: /root/
- name: busybox-read
image: busybox
command: ["sh","-c","tail -f /logs/1.log"] # 读取挂载目录下的文件内容
volumeMounts: # 将logs 挂在到busybox容器中,对应的目录为 /logs
- name: logs
mountPath: /logs
volumes: # 声明volume, name为logs-volume,类型为emptyDir
- name: logs
emptyDir: {}
查看busybox-read的日志
- HostPath
EmptyDir中数据不会被持久化,它会随着Pod的结束而销毁,如果想简单的将数据持久化到主机中,可以选择HostPath。HostPath就是将Node主机中一个实际目录挂在到Pod中,以供容器使用,这样的设计就可以保证Pod销毁了,但是数据依据可以存在于Node主机上
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: busybox-write
image: busybox
command: ['sh','-c','while true; do echo $(date) 原神 启动 >> /root/1.log; sleep 1; done'] # 初始命令,向1.log目录下不断的最佳内容
volumeMounts: # 将logs-volume挂在到nginx容器中,对应的目录为 /var/log/nginx
- name: logs
mountPath: /root/
volumes: # 声明volume, name为logs-volume,类型为emptyDir
- name: logs
hostPath:
path: /root/logs # 日志存储在主机这个目录下
查看宿主机目录上文件,但是其实该方法并不实用,因为pod会在node之间不断构建与销毁,虽然有方法可以指定pod调度到某个节点,但该方法并不合理
- NFS
NFS是一个网络文件存储系统,可以搭建一台NFS服务器,然后将Pod中的存储直接连接到NFS系统上,这样的话,无论Pod在节点上怎么转移,只要Node跟NFS的对接没问题,数据就可以成功访问
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: busybox-write
image: busybox
command: ['sh','-c','while true; do echo $(date) 原神 启动 >> /root/1.log; sleep 1; done'] # 初始命令,向1.log目录下不断的最佳内容
volumeMounts: # 将logs-volume挂在到nginx容器中,对应的目录为 /var/log/nginx
- name: logs
mountPath: /root/
volumes: # 声明volume, name为logs-volume,类型为emptyDir
- name: logs
nfs:
server: 10.206.16.2 #nfs服务器的ip
path: /root/nfs/ #nfs挂载目录,目录必须存在,否则pod创建会失败
ConfigMap
Configmap 是 k8s 中的资源对象,用于保存非机密性的配置的,它的主要作用是用来存储配置信息的,以便k8s的其他资源使用,Configmap创建后数据以 key/value 键值对的形式保存在k8s的etcd数据库内
创建ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: test-configmap
data:
userinfo: | #多行字符串可以使用|保留换行符,一般存放配置文件
username:菠菜
password:admin123
os: 原神启动
查看当前命名空间下的ConfigMap
kubectl get configmaps
查看某个ConfigMap的详细信息
kubectl get configmaps
使用ConfigMap,ConfigMap的使用方法分以下两种
- 作为容器内的变量环境
将某个ConfigMap里的某个键作为环境变量
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: busybox
image: busybox
command: ['sh','-c','echo $key1']
env:
- name: key1 # 容器中的环境变量参数
valueFrom: # 设置环境变量值的源,无法为空
configMapKeyRef: # 选择configmap中的键
name: test-configmap # 指定已经存在的ConfigMap名称
key: os
将某个ConfigMap里的所有键作为环境变量
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: busybox
image: busybox
command: ['sh','-c','while true; do echo $os; sleep 1; done']
envFrom:
- configMapRef: # 将ConfigMap里所有键值作为环境变量导入容器
name: test-configmap # 指定已经存在的ConfigMap名称
- 以volumes的方式挂载为容器内部,ConfigMap里的key作为文件名,value作为文件内容
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: busybox
image: busybox
command: ['sh','-c','sleep 3600']
volumeMounts: # 将configmap挂载到目录
- name: configmap
mountPath: /root/config
volumes: # 引用configmap
- name: configmap
configMap:
name: test-configmap
test-configmap里的键值会以文件形式挂载/root/config目下
PS:修改ConfigMap是可以热加载的,即更新configmap的内容, 容器中的值也会动态更新,但更新的时间好像不太稳定,有的时候5s有的时候可能10几秒。还有就是貌似只有volumes的方式挂载形式使用的ConfigMap才可以热加载,环境变量貌似无法热加载
结语
写这些,仅记录自己学习使用k8s的过程。如果有什么错误的地方,还请大家批评指正。最后,希望小伙伴们都能有所收获。