pod详解
pod详解
-
在生产环境中,使用的是pod的更加高级的对象,不建议直接使用pod
-
应该使用的是pod的高级对象
1、pod和命名空间
-
pod是k8s中最小的,最基本的部署和调度单元
-
一个pod里面封装了一个或者多个容器,相当于是一个进程
-
一个pod多个容器,共享网络命名空间(共享ip和端口空间)
-
pod单独创建的话,是一个临时性的,删除就没有了,如果是控制器的话,删除pod,系统会再次创建一个pod
-
-
默认创建的pod都是在default空间下的
-
不同命名空间下的pod是隔离的,但是还是可以通过服务发现(svc)进行通信(服务名.命名空间.svc.cluster.local)
创建一个pod,里面运行nginx,httpd 2个容器,看是否能运行
[root@master01 ~]# cat web1.yml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: web
name: web
spec:
containers:
- image: httpd
name: h1 # h1容器
- image: nginx
name: n1 # n1容器
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
# 发现pod是error的状态
[root@master01 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
web 1/2 Error 1 (5s ago) 11s
# 查看日志
# 发现n1容器无法监听80端口,所以失败了
# -c 是选择一个容器进行查看(有多个容器的情况)
[root@master01 ~]# kubectl logs web -c n1
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2026/03/25 10:09:24 [emerg] 1#1: bind() to 0.0.0.0:80 failed (98: Address already in use)
-
为什么会失败了?
-
一个pod里面的多个容器都是共享这个网络命名空间的
-
共享同一个pod的ip地址,可以进入2个容器,查看ip地址都是一样的
-
同一个网络端口,不能绑定相同的端口
-
-
可以这样理解
-
每一个pod都相当于是一个主机
-
在里面运行多个容器,会占用这个主机的端口,不能使用相同
-
-
default/pod1 和 default/pod2 2个pod是互不干扰的,2个都是独立的虚拟空间(抽象)

2、pod的创建过程

-
用户提交创建pod请求
-
api-server处理用户请求,先存储pod数据到etcd中,写入成功,api-server将成功的信息返回给客户端
-
scheduler通过watch机制监听到有新的pod后,会对多个主机进行打分,选择一个节点调度到上面去
-
scheduler将成功的调度到节点的信息写回到api-server,api-server将其写入到etcd中进行永久存储
-
kubelet接管pod创建,调用容器运行时创建,运行在目标节点上的kubelet监听pod资源变化
-
创建成功后kubelet返回信息给api-server,然后存入到etcd中
-
就是这样反复的一个写入过程
3、pod的创建的方式2种
1、命令行创建
# kubectl run pod_name image=
[root@master01 ~]# kubectl run pod1 --image=nginx
pod/pod1 created
[root@master01 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
pod1 1/1 Running 0 3s
# 会自动的注入一个标签
[root@master01 ~]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
pod1 1/1 Running 0 13s run=pod1
2、yaml文件创建
# 将配置信息输出到一个yaml文件里面
# --dry-run=client 不会向api server 发送请求,只是在客户端验证并输出结果,通常是生成配置模板
# 然后再次基础上面修改配置文件(不然一个一个手敲,太麻烦了)
[root@master01 ~]# kubectl run pod2 --image=nginx --image-pull-policy IfNotPresent --dry-run=client -o yaml > pod2.yml
[root@master01 ~]# cat pod2.yml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: pod2
name: pod2
spec:
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: pod2
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
-
apply命令,非常好用,如果后续修改了yml文件,也可以使用apply,
-
但是如果修改了一些pod的名字这些的话,使用apply就会报错,就需要删除,然后使用apply创建即可
4、yaml中的pod
[root@master01 ~]# cat pod2.yml
apiVersion: v1 # 版本
kind: Pod # 类型
metadata: # pod元数据
creationTimestamp: null
labels: # 标签
run: pod2
name: pod2 # pod的名字
spec: # 描述信息
containers: # pod包含的容器
- image: nginx # 第一个容器使用的镜像,多个容器使用-
imagePullPolicy: IfNotPresent # 镜像拉取策略
name: pod2 # 容器的名字
resources: {}
dnsPolicy: ClusterFirst # dns策略
restartPolicy: Always # pod重启策略
status: {}
5、镜像的拉取策略
-
Always 每次都会联网,从网上下载最新的镜像,不管本地有没有镜像,每次找的都是latest
-
Never 从来不联网,在本地寻找镜像
-
IfNotPresent 先从本地进行拉取,如果没有的话,就联网去网上寻找
6、pod的基本操作
1、端口映射
-
我们创建一个web容器,集群之间可以访问到内容,但是在集群外面就访问不到了
-
因此的话我们就需要映射端口
1、hostPort
- 直接映射到宿主机上面,hostPort
[root@master01 ~]# cat pod2.yml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: pod2
name: pod2
spec:
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: pod2
ports:
- containerPort: 80 # 容器监听的端口
hostPort: 8080 # 直接映射到被调度的节点上的8080端口
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
-
客户端访问 节点ip+映射到节点的端口,换了一个节点的话,访问就换节点的ip
-
上面这种很少用,不推荐使用,如果再次运行了一个pod,使用的也是hostPort的话,也是8080端口,那么就出现了端口占用,无法调度了
2、NodePort
-
后面会有这个NodePort这种方式(最常见的),后面讲svc的时候,会详细说明的
-
这个的话,就是任意节点的ip+映射的端口都能访问到
-
映射到宿主机上面端口,所有节点都在监听,同意了入口
-
高可用,某个节点宕机了,其他节点也可提供服务
-
3、hostnetwork
-
直接使用宿主机的ip地址,调度在哪一个节点上,就是哪一个ip
-
kube-system空间下,pod就是这样的
[root@master01 ~]# cat pod2.yml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: pod2
name: pod2
spec:
hostNetwork: true
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: pod2
resources: {}
# 发现ip为节点的ip
[root@master01 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod2 1/1 Running 0 4s 192.168.50.22 node <none> <none>
2、环境变量
- 为pod注入环境变量
[root@master01 ~]# cat m1.yml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: m1
name: m1
spec:
containers:
- image: mysql
name: m1
ports:
- containerPort: 3306
hostPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD # root密码
value: "123"
- name: MYSQL_DATABASE # 创建一个数据库
value: "qwe"
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
# 直接登录数据库
[root@master01 ~]# mysql -u root -p123 -h 192.168.50.22 -P3306
3、配置dns
-
dnsPolicy字段
-
default,继承 Pod 运行节点的 DNS 配置,也就是这个宿主机的dns
-
ClusterFirst: 优先使用集群 DNS(也就是coredns),失败则使用宿主机 DNS(默认)
-
none: 忽略集群 DNS,使用自定义 DNS 配置
-
clusterfirstwithhostnet 如果一个容器使用的ip是宿主机的ip,默认策略使用集群的dns
-
# 创建出来的pod默认使用的dns是ClusterFirst,也就是使用集群的dns
[root@master01 ~]# kubectl run b1 --image=busybox -- sleep 3600
pod/b1 created
/ # cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
1、default策略
[root@master01 ~]# cat b2.yml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: b2
name: b2
spec:
containers:
- image: busybox
name: b2
resources: {}
command: ["sleep","3600"] # 数组的形式,"" 包含一个命令
dnsPolicy: Default # pod的dns策略
# 使用的是节点的dns
/ # cat /etc/resolv.conf
nameserver 119.29.29.29
2、ClusterFirstWithHostNet
- 使用宿主机的网络,dns策略就是集群的dns
[root@master01 ~]# cat b2.yml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: b2
name: b2
spec:
hostNetwork: true # 使用宿主机网络
containers:
- image: busybox
name: b2
resources: {}
command: ["sleep","3600"]
dnsPolicy: ClusterFirstWithHostNet # dns策略
restartPolicy: Always
# 使用的是集群的dns
/ # cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
3、None(自定义dns)
[root@master01 ~]# cat b2.yml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: b2
name: b2
spec:
containers:
- image: busybox
name: b2
resources: {}
command: ["sleep","3600"]
dnsPolicy: None # 自定义dns
dnsConfig: # 自定义dns配置
nameservers:
- 114.114.114.114
restartPolicy: Always
/ # cat /etc/resolv.conf
nameserver 114.114.114.114
4、重启策略
-
restartPolicy
-
Always: 容器退出后,总是重启
-
OnFailure: 容器异常退出时,重启,job,cronjob这些
-
Never:从不重启
-
5、pod的持久化存储
-
就是创建了一个pod后,写入数据后,删除后里面的数据就没了,下次创建pod的时候,里面就没有数据了
-
有了持久化目录后,再次创建容器指定这个目录,里面就有数据了
-
后面会详细讲解持久化存储的
[root@master01 test]# cat b1.yml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: b1
name: b1
spec:
volumes:
- name: timefile # 注意挂载的名字需要一样,这样才能对应起来
hostPath:
path: /etc/localtime
containers:
- image: busybox
name: b1
resources: {}
command: ["sleep","3600"]
volumeMounts:
- name: timefile # 将节点上面的/etc/localtime挂载到容器里面
readOnly: true
mountPath: /etc/localtime
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
-
但是了上面的持久化存储有一种缺陷,就是这个pod被删除的话,再次调度到其他节点上面,就没有这个文件,就需要自己创建出来
-
hostPath 适用的场景是每个节点都有这个文件
7、pod健康检查
- 检查的是容器的状态,因此的话就是在containers字段里面
1、探针参数和方式
-
三个探针基本上都是共用参数的
-
是有kubelet发起的
initialDelaySeconds # 容器启动后,延迟多少秒才开始探测, 这个作用就是为了先让容器启动一段时间,然后开始探测 默认值为0
periodSeconds # 每隔多少秒后执行一次探测, 默认值为 10s
timeoutSeconds # 每次探测的超时时间 就是执行一次探测后,没有反应的超时时间 默认值为 1s
successThreshold # 连续成功多少次,标记为成功, 默认值为 1
failureThreshold # 连续失败多少次,标记为失败 默认值为 3次
- 探测的方式有三种
- httpget 发送其http Get 请求
- tcpSocket 尝试建立tcp连接,成功则健康
- exec 在容器内部执行命令,退出码为0成功,这个很少用的
2、Startup Probe
-
判断容器内的应用是否已启动成功
-
就是容器启动的阶段
-
失败的话,重启容器,重启就相当于是杀掉这个容器
-
这个优先级是最高的,执行期间会暂停禁用liveness和readiness探针
-
应用启动慢的应用,适合这java应用,初始化时长的服务,避免因为启动慢被其他探针误杀
-
startupprobe 1.16出来的,启动阶段探测,探测失败,探测退出,成功则这个阶段结束
3、Liveness Probe(存活探针)
- 判断容器是否存活,失败的话,重启容器,重启就相当于是杀掉容器
4、readinessProbe(就绪探针)
-
判断容器是否就绪,能否接收外部的请求
-
失败的话,则不能对外提供访问
5、探针案例
- 一般在生产中三个探针都是结合使用的
[root@master01 test]# cat n1.yml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: n1
name: n1
spec:
restartPolicy: Always
containers:
- image: nginx
name: n1
ports:
- containerPort: 80 # 容器监听的端口
startupProbe: # 启动探针,判断容器是否启动了
periodSeconds: 5 # 每隔5秒开始探测
timeoutSeconds: 1 # 超时时间为1s
successThreshold: 1 # 成功1次就标记成功
failureThreshold: 6 # 练习失败6次标记失败,过30s才算失败
tcpSocket: # tcp连接的方式
port: 80 # 与80进行连接
readinessProbe: # 就绪探针,判断容器是否能够接收流量
periodSeconds: 2
timeoutSeconds: 1
successThreshold: 1
failureThreshold: 3 # 连续失败3次,标记为失败
httpGet: # 发送请求探测
path: / # curl localhost:80/ 进行探测
port: 80
livenessProbe: # 存活探针
periodSeconds: 2
timeoutSeconds: 1
successThreshold: 1
failureThreshold: 3
httpGet: # 也是发送http请求探测
path: /
port: 80
[root@master01 test]# kubectl get pod
NAME READY STATUS RESTARTS AGE
n1 1/1 Running 0 10m
- 启动探针失败的案例
# 修改监听的端口为8080
startupProbe: # 在运行启动探针的时候,其他探针都暂停,这个优先级是最高的
periodSeconds: 5
timeoutSeconds: 1
successThreshold: 1
failureThreshold: 6
tcpSocket:
port: 8080 # 8080端口
# 查看pod详细信息,发现无法监听8080端口,启动探针失败了
Warning Unhealthy 1s (x4 over 16s) kubelet Startup probe failed: dial tcp 10.246.73.153:8080: connect: connection refused
# pod重启了,相当于是被kill了
[root@master01 ~]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
n1 0/1 Running 0 7s
n1 0/1 Running 1 (4s ago) 39s
- 就绪探针失败
# 修改为8080端口
readinessProbe:
periodSeconds: 2
timeoutSeconds: 1
successThreshold: 1
failureThreshold: 3
httpGet:
path: /
port: 8080
# 一直无法就绪,无法对外提供服务
[root@master01 test]# kubectl get pod
NAME READY STATUS RESTARTS AGE
n1 0/1 Running 0 41s
# 查看pod详细信息,发现这个就绪探测失败了
Warning Unhealthy 1s (x4 over 3s) kubelet Readiness probe failed: Get "http://10.246.73.154:8080/": dial tcp 10.246.73.154:8080: connect: connection refused
- 存活探针失败案例
livenessProbe:
periodSeconds: 2
timeoutSeconds: 1
successThreshold: 1
failureThreshold: 3
httpGet:
path: /
port: 8080
# 可以发现pod启动了,也是就绪的,但是了隔一段时间就会重启,这个就是存活探针
[root@master01 ~]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
n1 1/1 Running 0 7s
n1 0/1 Running 1 (3s ago) 13s
n1 0/1 Running 1 (5s ago) 15s
n1 1/1 Running 1 (6s ago) 16s
n1 0/1 Running 2 (3s ago) 23s
n1 0/1 Running 2 (5s ago) 25s
n1 1/1 Running 2 (5s ago) 25s
# 查看pod详细信息
Warning Unhealthy 101s (x9 over 2m5s) kubelet Liveness probe failed: Get "http://10.246.73.155:8080/": dial tcp 10.246.73.155:8080: connect: connection refused
8、静态pod,就是一个配置文件
- 在一个目录下面的文件,会自动的创建
# 静态pod目录,将yml文件拷贝过去,会自动的创建pod
[root@master01 manifests]# ls
etcd.yaml kube-controller-manager.yaml
kube-apiserver.yaml kube-scheduler.yaml
[root@master01 manifests]# pwd
/etc/kubernetes/manifests
# 拷贝到哪一个节点上面去,就会运行在这个节点上面,不走调度器
[root@master01 manifests]# cp /root/test/n1.yml .
[root@master01 manifests]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
n1-master01 0/1 ContainerCreating 0 98s <none> master01 <none> <none>
9、pod状态
-
pending 等待中, 镜像正在拉取
-
running 运行中
-
succeeded 成功,所有容器都已经终止了,且不会重启,正常退出
-
failed 失败,pod所有容器都终止了,且至少有一个非0状态退出
-
unknown 未知 pod状态无法被kubelet获取,通常是节点失联
-
Completed 常见于 Job 或 initContainer,表示容器正常结束(类似于 Succeeded)
-
CrashLoopBackOff 容器反复启动后崩溃,kubelet 在退避等待重启
10、初始化容器
-
initcontainers 有自己的生命周期,为主容器准备数据的,先于主容器执行
-
启动容器是有顺序的,启动前做什么,启动后做什么,删除容器之前做什么
-
yml文件里面的,就已经从上而下的执行就已经定义了
-
实验
-
一个pod里面的多个容器,存储是不共享的,临时存储
-
准备一个临时目录
-
初始化容器将网页数据写好
-
主容器挂载即可
-
[root@master01 test]# cat n2.yml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: n2
name: n2
spec:
volumes:
- name: webdir # pod的临时存储目录
emptyDir: {}
initContainers:
- name: initcontiner
image: busybox
imagePullPolicy: IfNotPresent
volumeMounts:
- name: webdir
mountPath: /etc/html/ # 挂载到这个目录
command:
- /bin/sh
- -c
- echo "welcome nginx" >> /etc/html/index.html # 任务就是写入这个文件即可,写入了一个文件
containers:
- image: nginx
name: n2
resources: {}
ports:
- containerPort: 80
volumeMounts:
- name: webdir
mountPath: /usr/share/nginx/html/ # 挂载到网页目录下面
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
# 访问
[root@master01 test]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
n2 1/1 Running 0 3m3s 10.246.73.159 node <none> <none>
[root@master01 test]# curl 10.246.73.159
welcome nginx
11、资源配额
-
设置pod中的容器资源配额,cpu,内存
-
requests 是启动容器最少需要的
-
limits 限制容器,最多的限制
[root@master01 test]# cat b1.yml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: b1
name: b1
spec:
volumes:
- name: timefile
hostPath:
path: /etc/localtime
containers:
- image: busybox
name: b1
resources: {}
command: ["sleep","3600"]
volumeMounts:
- name: timefile
readOnly: true
mountPath: /etc/localtime
resources:
requests:
cpu: "100m" # 0.1个cpu核心
memory: "12Mi" # 12mb内存
limits:
cpu: "200m"
memory: "24Mi"
dnsPolicy: ClusterFirst
restartPolicy: Always
13、pod和控制器的区别
-
为什么不用pod呢?缺点
-
pod删除后,就彻底没有了,没有自愈的能力
-
没有滚动更新,更新的话,需要手动更新
-
没有扩缩容的能力
-
-
控制器
-
通过标签管理多个副本数量
-
有自愈的能力,pod被删除后,会自动的在创建pod出来
-
弹性伸缩
-
-
一般在生产中用的是控制器

浙公网安备 33010602011771号