K8S 之 Pod

摘要

Pod 介绍

  • Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。

  • Pod(就像在豌豆荚中)是一组(一个或多个) 容器,这些容器共享存储、网络、以及怎样运行这些容器的规约。

  • Pod 中的内容总是并置(colocated)的并且一同调度,在共享的上下文中运行。

  • Kubernetes 集群中的 Pod 主要有两种用法:

    • 运行单个容器的 Pod: "每个 Pod 一个容器"模型是最常见的 Kubernetes 用例,在这种情况下,可以将 Pod 看作单个容器的包装器,并且 Kubernetes 直接管理 Pod,而不是容器。
    • 运行多个协同工作的容器的 Pod: Pod 可以封装由紧密耦合且需要共享资源的多个并置容器组成的应用,这些位于同一位置的容器构成一个内聚单元。

Pod 管理

Pod 创建

  • run 创建

1
2
3
4
5
kubectl run nginx --image=nginx
# 输出 yaml
kubectl run nginx --image=nginx --dry-run=client -o yaml > pod.yaml
# 通过 yaml 文件创建
kubectl apply -f pod.yaml

pod.yaml 文件说明

  • 因为 Pod 不支持扩缩容,所以日常使用时一般不会直接创建 Pod,而是创建 Deployment, DaemonSet等这些工作负载资源,这些后面会介绍到。

  • 但我们这里还是要重点介绍一下 Pod 的 yaml 文件格式,因为它是后面所有资源创建的基础。

  • 一个最基础的 Pod 配置如下:

1
2
3
4
5
6
7
8
apiVersion: v1                   # 必填。指定使用的 API 版本,Pod 是核心资源,使用 v1
kind: Pod # 必填。资源类型:Pod
metadata: # 必填。元数据,包含 Pod 的名称、命名空间、标签、注解等信息
name: nginx # 必填。Pod 的名称,命名空间中唯一
spec: # 必填。资源的特性描述(规约),定义Pod具体行为的部分
containers: # 必填。容器列表
- image: nginx # 必填。容器使用的镜像
name: nginx # 必填。容器名称,在同一个 Pod 内必须唯一
  • Pod是用来配置容器的,我们在学习docker时知道,容器有非常多的配置项,比如端口、网络、存储等,而 pod 的配置项更丰富。

  • 一个Pod的配置主要包含两大部分:metadataspec,每一项中包含的配置项非常多,这里只对常用的配置项进行说明,若要查看每个配置项的说明可以通过如下命令获取:

1
2
3
4
5
6
# pod开头,配置项以 . 连接,例如:
kubectl explain pod.metadata
kubectl explain pod.metadata.labels
kubectl explain pod.spec
kubectl explain pod.spec.containers
kubectl explain pod.spec.containers.ports

metadata

  • metadata 是 Pod 的元数据,比如 Pod 的名称、命名空间、标签、注解等。

1
2
3
4
5
6
7
8
metadata:                 # 元数据部分
name: myapp-pod # Pod 的名称
namespace: default # Pod 所在的命名空间,默认是 default
labels: # 标签,用于选择器、管理、分组
app: myapp
tier: frontend
annotations: # 注解,用于添加非结构化元信息
description: "A sample pod for demonstration"

spec

  • spec 描述了 Pod 的配置信息,包括 Pod 的容器、存储、网络、资源限制、调度策略等

spec.containers
  • containers 描述了 Pod 中容器的配置信息,包括镜像、启动命令、环境变量、资源限制、卷挂载等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
spec:                      #必选,Pod中容器的详细定义
containers: #必选,Pod中容器列表
- name: string #必选,容器名称
image: string #必选,容器的镜像名称
imagePullPolicy: [ Always|Never|IfNotPresent ] #获取镜像的策略,当镜像标签为 latest 时默认值为 Always,否则为 IfNotPresent
command: [string] #容器的启动命令列表,如不指定,使用打包时使用的启动命令
args: [string] #容器的启动命令参数列表
workingDir: string #容器的工作目录,如果为指定,则默认为镜像中的配置
volumeMounts: #挂载到容器内部的存储卷配置
- name: string #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
mountPath: string #存储卷在容器内mount的绝对路径,应少于512字符
readOnly: boolean #是否为只读模式
ports: #需要暴露的端口库号列表
- name: string #端口的名称
containerPort: 80 #容器需要监听的端口号
hostPort: int #容器所在主机需要监听的端口号,默认与Container相同
protocol: string #端口协议,支持TCP和UDP,默认TCP
env: #容器运行前需设置的环境变量列表
- name: string #环境变量名称
value: string #环境变量的值
resources: #资源限制和请求的设置
limits: #资源限制的设置(上限)
cpu: string #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
memory: string #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
requests: #资源请求的设置(下限)
cpu: string #Cpu请求,容器启动的初始可用数量
memory: string #内存请求,容器启动的初始可用数量
  • 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
spec:                         # Pod 的具体规范
containers: # Pod 中的容器数组,可以有多个容器
- name: myapp-container # 容器名称
image: nginx:1.25 # 使用的镜像
ports: # 容器开放的端口
- containerPort: 80 # 容器内部端口,只是声明性的字段,不具有决定作用
env: # 环境变量配置
- name: ENVIRONMENT
value: production
resources: # 资源限制和请求
limits:
memory: "512Mi" # 最大内存限制
cpu: "1" # 最大 CPU 核心数,这里是 1 核
# cpu: 1000m # 1000m = 1 核
requests:
memory: "256Mi" # 初始分配内存
cpu: "0.5" # 初始分配 CPU, 这里0.5 表示 0.5 核
# cpu: 500m # 500 毫核,也就是 0.5 核
volumeMounts: # 挂载到容器的卷
- name: app-storage # 卷名称,需要和 volumes 中定义的卷名称一致
mountPath: /usr/share/nginx/html # 挂载到容器的目录
spec.containers.command | args
  • 容器启动时执行的命令

  • 默认情况下,容器启动时,会从镜像中获取命令并执行,如果这里配置了命令,则容器启动时,会执行这里的命令,而不是镜像中的命令

1
2
3
4
5
spec:
containers:
- name: busybox-container
image: busybox:1.36
command: ["/bin/sh", "-c", "while true; do echo hello; sleep 10;done"]
  • 或者

1
2
3
4
5
6
spec:
containers:
- name: busybox-container
image: busybox:1.36
command: ["/bin/sh","-c"]
args: ["while true; do echo hello; sleep 10;done"]
  • 或者

1
2
3
4
5
6
7
8
9
10
11
spec:
containers:
- name: busybox-container
image: busybox:1.36
command: ["/bin/bash", "-c"]
args:
- | # 使用 | 符号,表示多行输入
while true; do
echo "hello world"
sleep 5
done
spec.restartPolicy
  • 指在系统发生故障或意外停机时,系统或应用程序如何处理和恢复的策略

    • Always:总是重启
    • OnFailure:失败时重启
    • Never:不重启
1
2
3
4
5
spec:
containers:
- name: my-nginx
image: nginx
restartPolicy: OnFailure #失败时重启

spec.terminationGracePeriodSeconds

  • Pod 删除时,系统给 Pod 留的时间,用于完成清理工作

  • 宽限期为避免服务突然中断,造成事物不一致的问题,当容器运行完自己的任务后,会等待一段时间,然后优雅的退出

  • 默认值为 30s,单位为秒

1
2
3
4
5
spec:
containers:
- name: my-nginx
image: nginx
terminationGracePeriodSeconds: 60

spec.volumes

  • Kubernetes 中的卷(volumes)是为了在容器之间共享数据,或将数据从容器持久化到外部存储。

emptyDir(最简单,Pod 生命周期内有效)
  • emptyDir 卷是一个没有名字的临时目录,Pod 创建时创建,Pod 删除时删除。

1
2
3
4
5
6
7
8
9
10
spec:
containers:
- name: app
image: nginx
volumeMounts:
- mountPath: /usr/share/nginx/html
name: html-volume
volumes:
- name: html-volume
emptyDir: {} # 表示一个空目录,在 Pod 生命周期内有效
hostPath(挂载宿主机路径)
  • 用于测试或非常了解宿主机结构的场景。生产不推荐。

1
2
3
4
5
6
spec:
volumes:
- name: mydata
hostPath:
path: /tmp/data # 宿主机路径
type: DirectoryOrCreate # 如果目录不存在就创建
configMap(挂载配置文件)
1
2
3
4
5
spec:
volumes:
- name: config
configMap:
name: my-configmap # 需提前创建 ConfigMap,这个后面会介绍
使用 PVC(挂载持久化存储)
1
2
3
4
5
spec:
volumes:
- name: persistent-storage
persistentVolumeClaim:
claimName: mypvc # PVC 名称,需要提前创建,这个后面会介绍

spec.tolerations: Pod容忍策略

  • tolerations 是 Kubernetes Pod 中用来“容忍”某些 Node 节点的污点(Taints) 的字段。它允许 Pod 被调度到带有相应 Taint 的节点上。

  • 默认情况下,Pod 会因为 Node 节点的 Taint 而不被调度。

  • 比如一个 Node 有 NoSchedule 类型的 taint,而 Pod 没有设置对应的 toleration,该 Pod 就不会被调度到这个 Node 上。

  • 示例: 容忍 key=value:NoSchedule 的 Taint

  • 假设某节点打了如下污点(Taint):

1
2
3
4
5
6
7
8
9
10
11
12
13
kubectl taint nodes node1 key=value:NoSchedule
# NoSchedule 不调度到该节点,除非容忍策略显式允许
# PreferNoSchedule 尽量不调度到该节点,但非强制,即可能会被调度
# NoExecute 不仅不调度到该节点,还会把现有 Pod 驱逐出去,除非设置容忍时间

# key=value 是用来 区分不同类型的污点的。比如:
# 你可能给 node1 设置 env=prod:NoSchedule
# 给 node2 设置 gpu=true:NoSchedule
# 给 node3 设置 arch=arm64:NoSchedule

# 这些都属于不同的“原因”或“标签”,这样你可以:
# 用不同的 toleration 来容忍不同的 taint;
# 精准控制某些 Pod 只能被调度到符合条件的节点。
  • 容忍该 Taint

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: v1
kind: Pod
metadata:
name: tolerate-example
spec:
containers:
- name: busybox
image: busybox
command: ["sleep", "3600"]
tolerations: # 定义容忍策略
- operator: "Equal" # 匹配方式,必选(Equal:精确匹配 key 和 value。Exists:只匹配 key 是否存在,不关心 value 是什么)
key: "key" # 设置键值对的key,为空代表任意键值对
value: "value" # 设置values的值,
effect: "NoSchedule" # 设置容忍的标签,为空代表所有污点标签
tolerationSeconds: 60 # 容忍时间,这里Pod 最多可停留 60 秒,之后仍会被驱逐,不设置表示永久容忍

spec.nodeName | nodeSelector :Pod调度策略

  • 在k8s中,调度是将Pod分配到合适的节点并运行的过程,kube-scheduler是默认调度器,是集群的核心组件。

  • 调度器通过k8s的监测(Watch)机制来发现集群中尚未被调度到节点上的Pod,调度器依据调度原则将Pod分配到一个合适的节点上运行。

  • 调度器给一个pod做调度包含两个步骤: 过滤 和 打分

    • 过滤:首先要筛选出满足Pod所有的资源请求的节点,这里包含计算资源、内存、存储、网络、端口号等等,如果没有节点能满足Pod的需求,Pod将一直停留在Pending状态,直到调度器能够找到合适的节点运行它
    • 打分:调度器将节点按照打分规则进行打分,然后按照分数进行排序,将分数最高的节点作为Pod的运行节点。如果存在多个得分最高的节点,调度器会从中随机选取一个。
  • Pod 支持两种调度策略:nodeNamenodeSelector

spec.nodeName
  • 指定 Pod 运行在指定名称的节点上

1
2
3
4
5
spec:
nodeName: node-1 # 基于节点名进行调度
containers:
- name: apache
image: myos:httpd

affinity: # 亲和性规则,更细粒度地控制调度
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd

spec.nodeSelector
  • 节点选择器,基于节点的标签进行调度

1
2
3
4
5
6
spec:
nodeSelector: # 基于节点标签进行调度
kubernetes.io/hostname: node-2 # 标签
containers:
- name: apache
image: myos:httpd
  • 为节点设置标签

1
2
3
4
5
6
7
8
9
10
11
# 所有资源都可以设置标签,语法为: kubectl label <资源> <资源名称> <标签key>=<标签value>
kubectl label nodes node-2 kubernetes.io/hostname=node-2

# 删除标签,语法为: kubectl label <资源> <资源名称> <标签key>-
# 这里注意,删除标签就是在标签key后加上 - 符号
kubectl label nodes node-2 kubernetes.io/hostname-

# 查看资源标签:kubectl get <资源> --show-labels
kubectl get nodes --show-labels
# 查看指定节点的标签
kubectl get nodes node-2 --show-labels

spec.resources

  • Pod资源配额可以限制命名空间或项目中Pod使用的CPU、内存、存储等资源用量

  • CPU资源的约束和请求以豪核(m)为单位。在k8s中1m是最小的调度单元,CPU的一个核心可以看作1000m

如果你有2颗cpu,且每CPU为4核心,那么你的CPU资源总量就是8000

1
2
3
4
5
6
7
8
9
10
11
12
13
spec:                     # Pod 的具体规范
containers: # Pod 中的容器数组,可以有多个容器
- name: myapp-container # 容器名称
image: nginx:1.25 # 使用的镜像
resources: # 资源限制和请求
limits:
memory: "512Mi" # 最大内存限制
cpu: "1" # 最大 CPU 核心数,这里是 1 核
# cpu: 1000m # 1000m = 1 核
requests:
memory: "256Mi" # 初始分配内存
cpu: "0.5" # 初始分配 CPU, 这里0.5 表示 0.5 核
# cpu: 500m # 500 毫核,也就是 0.5 核
  • 如果有大量的容器需要设置资源配额,为每个Pod设置资源配额策略不方便且不好管理

  • 可以以名称空间为单位(namespace),限制其资源的使用与创建,在该名称空间中创建的容器都会受到规则的限制。

LimitRange
  • 对单个Pod内存、CPU进行配额

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: v1
kind: LimitRange
metadata:
name: mem-cpu-limit-range # LimitRange 的名称
namespace: demo # 生效的命名空间
spec:
limits:
- type: Container # 表示限制的是每个容器(也可设置为 Pod)
default: # 容器未指定 resources.limits 时使用的默认值
cpu: 500m # 默认限制 CPU 为 0.5 核
memory: 512Mi # 默认限制内存为 512 MiB
defaultRequest: # 容器未指定 resources.requests 时使用的默认请求值,初始值
cpu: 100m # 默认请求 CPU 为 0.1 核
memory: 128Mi # 默认请求内存为 128 MiB
max: # 容器可设置的最大限制值,即 容器中指定的 resources.limits 的最大允许值
cpu: "1" # 最大可使用 CPU 为 1 核
memory: 1Gi # 最大可使用内存为 1 GiB
min: # 容器可设置的最小请求值,,即 容器中指定的 resources.requests 的最小允许值
cpu: 50m # 最小请求 CPU 为 0.05 核
memory: 64Mi # 最小请求内存为 64 MiB
ResourceQuota
  • 限制整个 namespace 的资源总量

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources # ResourceQuota 的名称
namespace: demo # 生效的命名空间
spec:
hard: # 定义各类资源的总配额上限
pods: "10" # 该命名空间最多允许创建 10 个 Pod
requests.cpu: "2" # 所有 Pod 的 requests.cpu 总和最多为 2 核
requests.memory: 4Gi # 所有 Pod 的 requests.memory 总和最多为 4 GiB
limits.cpu: "4" # 所有 Pod 的 limits.cpu 总和最多为 4 核
limits.memory: 8Gi # 所有 Pod 的 limits.memory 总和最多为 8 GiB

spec.priorityClassName

  • Pod 的优先级,优先级就是为了保证重要的Pod被优先调度并运行

  • 优先级策略:

    • 非抢占优先:指的是在调度阶段优先进行调度分配,一旦容器调度完成就不可以抢占,资源不足时,只能等待
    • 抢占优先:强制调度一个Pod,如果资源不足无法被调度,调度程序会抢占(删除)较低优先级的Pod的资 源,来保证高优先级Pod的运行
  • 创建优先级

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
kind: PriorityClass
apiVersion: scheduling.k8s.io/v1
metadata:
name: high-non # 优先级名称
preemptionPolicy: Never # 策略:非抢占,PreemptLowerPriority:抢占(删除)较低优先级的Pod的资源,保证高优先级Pod的运行
value: 1000 # 优先级,可以设置小于10亿的整数值,值越大,优先级越高,默认优先级0

---
kind: Pod
apiVersion: v1
metadata:
name: nginx
spec:
nodeSelector:
kubernetes.io/hostname: node01 # 指定匹配具有当前标签的节点
priorityClassName: high-non # 优先级名称
containers:
- name: my-nginx
image: nginx

spec.affinity

  • 节点亲和性,用于控制 Pod 调度到具有特定标签的节点上,是 nodeSelector 的增强版本

类型 功能 示例用途
Node Affinity 控制调度到有指定标签的节点 SSD、高内存节点
Pod Affinity 调度到和某些 Pod 一起的节点 微服务协同部署
Pod Anti-Affinity 避免和某些 Pod 一起的节点 高可用副本分散部署
节点亲和性(Node Affinity)
  • Pod 只能调度到具有标签 disktype=ssd 的节点上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: v1
kind: Pod
metadata:
name: node-affinity-pod
spec:
containers:
- name: nginx
image: nginx
affinity: # 亲和性配置
nodeAffinity: # 节点亲和性
requiredDuringSchedulingIgnoredDuringExecution: # 在调度期间必须满足,运行中忽略变化(即调度后标签变了不会驱逐 Pod)。
nodeSelectorTerms: # 节点选择器
- matchExpressions: # 匹配表达式,支持复杂逻辑,比如 In、NotIn、Exists、DoesNotExist、Gt、Lt。
- key: disktype # 键
operator: In # 操作符
values: # 值
- ssd
Pod 亲和性(Pod Affinity)
  • Pod 会被调度到 与标签为 app=web 的 Pod 所在同一节点(或拓扑层)上。

通常用于需要紧密协作的服务部署在一起(如同一机器内通信)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: v1
kind: Pod
metadata:
name: pod-affinity-pod
spec:
containers:
- name: app
image: busybox
command: ["sleep", "3600"]
affinity:
podAffinity: # pod 亲和性
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector: # 标签选择器
matchExpressions: # 标签选择条件
- key: app # 键
operator: In # 操作符
values: # 值
- web
topologyKey: "kubernetes.io/hostname" # 拓扑键,表示“同一主机”
Pod 反亲和性(Pod Anti-Affinity)
  • 表示不能和 app=web 的 Pod 在同一节点上

常用于高可用部署,避免多个副本部署在同一个节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: v1
kind: Pod
metadata:
name: pod-anti-affinity-pod
spec:
containers:
- name: app
image: busybox
command: ["sleep", "3600"]
affinity:
podAntiAffinity: # Pod 反亲和性
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web
topologyKey: "kubernetes.io/hostname"

查看 Pod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 查看 Pod,默认显示 default 命名空间下的 Pod
kubectl get pods
# 查看 kube-system 命名空间下的 Pod
kubectl get pods -n kube-system
# 查看所有命名空间下的 Pod
kubectl get pods -A
# -o wide: 显示 Pod 的详细信息,此时会看到 pod 的 IP 地址、节点名称等信息
kubectl get pods -o wide
# 显示 Pod 的详细信息,输出为 json/yaml 格式
kubectl get pods -o json/yaml
# 显示 Pod 的标签
kubectl get pod --show-labels
# 按 Pod 的标签进程查询
kubectl get pod -l <label_name>=<label_value>
# 持续查看 Pod 的状态,当 pod 状态发生改变时,会实时显示
kubectl get pods -w
## 状态类型
- Pending: Pod 尚未就绪
- ContainerCreating: Pod 正在创建容器
- Running: Pod 正在运行
- Error: Pod 运行错误
- Terminating: Pod 正在删除
- Completed: Pod 执行完成
- Failed: Pod中的所有容器至少有一个容器退出是非0状态
- Unkown: 无法正常获取Pod对象的状态信息

查看 Pod 详情

  • 当 pod 运行错误时,可以通过该命令查看 pod 的详情,找到错误原因

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
kubectl describe pod <pod-name>
kubectl describe pod <pod-name> -n <namespace-name>

## 排查原因时主要观察最后的 Events,从上到下就是 Pod 的运行过程
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
# 被调度器分配到 k8s-worker2 节点
Normal Scheduled 4s default-scheduler Successfully assigned default/nginx to k8s-worker2
# 开始拉取镜像
Normal Pulling <invalid> kubelet Pulling image "nginx"
# 镜像拉取成功
Normal Pulled <invalid> kubelet Successfully pulled image "nginx" in 2.067s (2.067s including waiting). Image size: 72225394 bytes.
# 开始创建容器
Normal Created <invalid> kubelet Created container: nginx
# 容器启动成功
Normal Started <invalid> kubelet Started container nginx

进入容器

1
2
# kubectl exec -it <pod-name> -n <namespace-name> -- <command>
kubectl exec -it nginx -- /bin/bash

删除 Pod

1
2
kubectl delete pod <pod-name>
kubectl delete pod <pod-name> -n <namespace-name>

查看 Pod 日志

1
2
3
kubectl logs <pod-name>
kubectl logs pod/<pod-name>
kubectl logs pod/<pod-name> -n <namespace-name>

访问 Pod

  • 我们刚刚创建了一个nginx的pod,该如何访问呢?

1
2
3
4
5
6
7
# 获取pod的ip
$ k get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 12m 10.244.126.8 k8s-worker2 <none> <none>

# 在任意节点上访问,nginx 默认端口是80
$ curl 10.244.126.8
  • 暂时我们还不能通过节点的 IP 访问 Pod,因为 Pod 运行在容器网络中,等我后面讲解 deployment 和 service 之后,会介绍如何通过 service 访问

一个 Pod 运行多个容器

  • yaml 文件

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Pod
metadata:
name: multi-pod
spec:
containers:
- name: nginx
image: nginx
- name: tomcat
image: tomcat
  • 运行 pod

1
kubectl apply -f multi_pod.yaml
  • 查看运行结果

1
2
3
4
# 这里看到,READY 里有两个,表示两个容器都运行成功
$ kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
multi-pod 2/2 Running 0 118s 10.244.194.81 k8s-worker1 <none> <none>
  • 访问nginx和tomcat

1
2
3
4
# 访问nginx,ngxin默认端口是80
curl http://10.244.194.81
# 访问tomcat,tomcat默认端口是8080,因为tomcat的webapp是空的,所以看到404就说明正常
curl http://10.244.194.81:8080
  • 进入容器执行命令

1
2
3
4
5
6
7
# 进入nginx容器,-c 指定容器名称
kubectl exec -it multi-pod -c nginx -- /bin/bash
## 进入nginx容器后访问tomcat可以正常访问,说明同一个pod中的容器共享网络和存储
curl http://localhost:8080

# 进入tomcat容器
kubectl exec -it multi-pod -c tomcat -- /bin/bash