某不知名博客 某不知名博客
首页
  • 《vulcat文档》
  • Web安全

    • 《BurpSuite及官方实验室》
    • 《OSWE学习历程》
  • 云原生安全

    • 《Docker命令大全》
    • 《CKS考试学习指南》
    • 《旧-Kubernetes教程》
漏洞库
  • 《渗透工具大全》
  • 《云安全》
事件库
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Carsaid

安全界的小学生
首页
  • 《vulcat文档》
  • Web安全

    • 《BurpSuite及官方实验室》
    • 《OSWE学习历程》
  • 云原生安全

    • 《Docker命令大全》
    • 《CKS考试学习指南》
    • 《旧-Kubernetes教程》
漏洞库
  • 《渗透工具大全》
  • 《云安全》
事件库
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 前言

  • 学习建议

  • Docker命令大全
  • Kubernetes教程

    • Kubernetes(K8s)学习教程 - 前言
    • 第1章-Kubernetes集群部署
    • 第2章-便捷性设置以及集群插件的安装
    • 第3章-基础操作
    • 第4章-集群升级
    • 第5章-Pod
      • 1. 查看Pod
      • 2. 创建Pod
        • 2.1 通过命令行创建Pod
        • 2.2 通过yaml文件创建Pod
        • apiVersion参数
        • kind参数
        • metadata参数
        • spec参数
        • 2.2.5 应用yaml并创建Pod
        • 2.3 关于镜像下载策略
      • 3. 小练习
      • 4. 删除Pod
      • 5. 操作Pod
        • 5.1 查看Pod的日志信息
        • 5.2 在Pod中执行命令
        • 5.2.1 在已有的Pod中执行命令
        • 5.2.2 在创建Pod时执行命令
        • 5.3 Pod文件的拷贝
        • 5.3.1 从物理机到容器
        • 5.3.2 从容器到物理机
        • 5.4 查看Pod详细运行信息
        • 5.5 为Pod设置和删除标签
        • 5.5.1 为已有的Pod设置标签
        • 5.5.2 在创建Pod时设置标签
        • 5.5.3 删除已有的标签
      • 6. 初始化Pod
        • 6.1 初始化容器概念
        • 6.2 创建一个初始化容器
        • 6.3 遇到错误的初始化容器
      • 7. 静态Pod
        • 7.1 静态Pod概念
        • 7.2 创建一个静态Pod
        • 7.2.1 通过yaml文件创建静态Pod
        • 7.2.2 通过yaml文件删除静态Pod
        • 7.3 修改静态Pod存储路径
        • 7.3.1 通过kubelet服务文件修改
        • 7.3.2 通过k8s配置文件修改
      • 8. 小结
    • 第6章-Pod生命周期与资源限制
    • 第7章-Pod与节点
    • 第8章-控制器Deployment
    • 第9章-Deployment镜像变更和滚动更新
    • 第10章-其他控制器-以及标签表达式
    • 第11章-控制器与节点驱逐
    • 暂缓更新
    • 练习题

    • 常用命令及yaml配置

  • CKS教程

  • 云原生安全
  • Kubernetes教程
carsaid
2023-10-24
目录

第5章-Pod

原创

本博客原创文章,转载请注明出处

- name: 原创
  desc: 本博客原创文章,转载请注明出处
  bgColor: '#F0DFB1'
  textColor: '#1078E6'
1
2
3
4

# 第5章-Pod

本章要点
查看、创建、删除及操作 Pod
初始化 Pod
静态 Pod

# 11. 查看Pod

1. 查看当前有多少 Pod(默认只列出当前命名空间里的 Pod):

kubectl get pods
1

2. 列出指定命名空间里的 Pod:

kubectl get pods -n kube-system
1

3. 列出所有命名空间里的 Pod:

kubectl get pods -A

# 完整写法
kubectl get pods --all-namespaces
1
2
3
4

以上几个命令在之前的章节中已经使用过,下面介绍其它一些常用的标志符。

4. 列出 Pod 的同时显示这些 Pod 的基础信息:

kubectl get pods -o wide
1

从图中可以看到,在添加标志符-o wide后多出了几列信息。这些信息反馈了当前 Pod 运行在哪台主机上、运行在该主机上的哪个网段中等。

当你想知道一个 Pod 位于何处时,该标志符非常有用。

Not Found Image

5. 只列出 Pod 的名称:

kubectl get pods -o name
1

如果你只想获取 Pod 的名称,而不想看到其它的运行信息,则可以使用以上命令。

同时还可以通过管道符|以及命令wc -l来统计 Pod 的数量,这非常方便。

Not Found Image

6. 显示 Pod 的标签信息:

kubectl get pods --show-labels
1

从图中可以看到,这些 Pod 都具有不同的标签,不同的标签通过逗号来分隔。通过识别这些标签,你可以快速判断出某个 Pod 的作用、位置等信息,例如标签tier=control-plane表明这个 Pod 是运行在 master 节点上的。

Not Found Image

7. 列出含有特定标签的 Pod:

kubectl get pods -l <键>=<值>

# 多个标签之间通过逗号 , 分隔
kubectl get pods -l <键>=<值>,<键2>=<值2>
1
2
3
4

看,标签的作用这不就来了吗?

Not Found Image

8. 列出 Pod 的工作负载(该命令在第 2 章中已经介绍过):

kubectl top pods
1

9. 以 JSON 或 yaml 的格式输出 Pod 的详细运行信息:

kubectl get pods -o json
kubectl get pods -o yaml

# 数据量可能过大, 建议配合输出重定向来使用
kubectl get pods -o json > result.json
1
2
3
4
5

这里我添加了-A和-o json标志符,以 JSON 格式输出所有命名空间里的 Pod 的运行信息。由于数据量过大,所以我将其保存到了外部文件当中。

以下动图演示了这条命令:

Not Found Image

从图中可以看到,仅仅 14 个 Pod 的运行信息就有将近五千行之多。

# 22. 创建Pod

之前查看的那些 Pod 都是集群自带的,你一定很想创建一个属于你自己的 Pod 吧?

Pod 和容器一样,也需要依靠镜像来创建,所以我们先下载几个镜像:

# 由于网络原因, 下载可能会很慢, 需要耐心等待
ctr -n k8s.io i pull docker.io/library/nginx:latest
ctr -n k8s.io i pull docker.io/library/nginx:1.9
ctr -n k8s.io i pull docker.io/library/busybox:latest
ctr -n k8s.io i pull docker.io/library/alpine:latest
1
2
3
4
5

官方的提醒

在生产环境中部署容器时,应避免使用:latest标记,因为很难跟踪正在运行的镜像版本,也很难正确回滚。

前面说过,ctr 是安装 containerd 时自带的一款命令行工具,可用于管理容器镜像。同时 ctr 具有命名空间概念,与 kubernetes 有关的镜像都需要放在k8s.io命名空间当中。

Not Found Image

完成全部下载之后,你应该已经拥有了四个来自 docker.io 存储库的镜像。

ctr -n k8s.io i ls | grep library
1
Not Found Image

# 2.12.1 通过命令行创建Pod

我们先来看看创建 Pod 的命令语法:

# 语法
kubectl run <名称> --image <镜像>
kubectl run <名称> --image <镜像> --image-pull-policy=<镜像下载策略>
1
2
3

你可能会注意到--image-pull-policy标志符,它指定了创建 Pod 时的镜像下载策略,共有三种策略:

  • IfNotPresent:如果本地没有才去下载镜像。如果本地存在相应的镜像,则使用本地镜像来创建 Pod;如果本地没有镜像,则尝试下载该镜像,然后再创建 Pod
  • Always:总是下载镜像。不管本地有没有镜像,都会去下载镜像,然后用所下载的镜像来创建 Pod
  • Never:从不下载镜像。只当本地存在镜像的时候,才创建 Pod

笔记

一些选项必须通过等于号=来指定,不能使用空格。

默认的下载策略一般为Always,我们刚刚已经下载过镜像了,所以这里手动指定策略为IfNotPresent,以免二次下载镜像。

创建一个名为 “pod1” 的 Pod,同时指定镜像下载策略为 “IfNotPresent”:

# 嫌命令太长的话可以通过 Tab 键自动补全, 该功能在第 2 章中已经设置过了
kubectl run pod1 --image nginx --image-pull-policy=IfNotPresent
1
2

等待一会后,你就可以看到一个新鲜出炉的 Pod,它被调度到了 worker02 节点上运行。

Not Found Image

我们来创建第二个 Pod,这次的操作不太一样:

# 创建命名空间 ns1
kubectl create ns ns1

# 创建 Pod 并将其命名空间指定为 ns1
kubectl run pod2 --image nginx --image-pull-policy=IfNotPresent -n ns1
1
2
3
4
5

创建 pod2 之后我们查看一下,你会发现还是只有 pod1 的信息,那 pod2 呢?创建失败了吗?

Not Found Image

我们刚刚位于命名空间default当中,而kubectl get pods命令默认只会列出当前命名空间中的 Pod,自然看不到命名空间ns1中的 Pod 啦。

这次我们为命令加上-n ns1:

kubectl get pods -n ns1
1

这次顺利看到了 pod2。

Not Found Image

笔记

如果没有指定-n选项,那么你当前所处的命名空间是哪个,创建的 Pod 就会在哪个命名空间中运行。

# 2.22.2 通过yaml文件创建Pod

kubernetes 通过 yaml(.yaml)文件来定义和创建各种集群资源。在第 2 章中我们配置并优化了 vim 编辑器,这将有助于你编写 yaml 文件。

学习更多

菜鸟教程-yaml入门 (opens new window)

我们先创建一个目录,把相关的 yaml 文件都放在该目录中。

mkdir pod-yaml
cd pod-yaml
1
2
Not Found Image

然后,你可以通过以下命令快速生成一个用于创建 Pod 的 yaml 文件:

  • --dry-run=client:试运行,在本地模拟创建一个 Pod,并不会真的创建
  • -o yaml:以 yaml 格式导出该 Pod 的所有配置项
kubectl run <名称> --image <镜像> --dry-run=client -o yaml > pod.yaml

vim pod.yaml
1
2
3

导出文件后,你可通过 vim 来打开该文件。

Not Found Image

打开文件之后,你将看到以下内容:

Not Found Image
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: pod-y
  name: pod-y
spec:
  containers:
  - image: nginx
    name: pod-y
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 2.2.1apiVersion参数

该参数用于指定 Pod 的 API 版本,一般是固定的v1。

apiVersion: v1
1

你还记得kubectl api-versions命令吗?它列出了 k8s 里所有可用的 apiVersion 参数值。

# 2.2.2kind参数

该参数用于指定当前 yaml 文件所创建的 k8s 资源类型。参数值采用驼峰命名法,英文首字母需要大写,否则会创建失败。

kind: Pod
1

资源类型和 apiVersion 的值是对应的,不同的资源都有不同的 apiVersion 来搭配,例如 Pod 资源必须对应 v1 版本。

# 2.2.3metadata参数

该参数用于指定当前资源的元数据信息。

metadata:
  creationTimestamp: null
  labels:
    run: pod-y
  name: pod-y
1
2
3
4
5

metadata.creationTimestamp是一个时间戳,表示创建此资源时的服务器时间。它以 RFC3339 形式表示,并采用 UTC。它可以指定为 null(空)。

metadata.labels是一个对象,用于定义资源的多个标签,定义标签的格式为<key>: <value>。这就是之前通过命令kubectl get pods --show-labels所看到的那些标签。

metadata.name用于定义资源的名称。

# 2.2.4spec参数

该参数定义了 Pod 中的容器以及各种策略。

spec:
  containers:
  - image: nginx
    name: pod-y
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
1
2
3
4
5
6
7

spec.containers是一个数组 + 对象的复合结构,用于定义单个 Pod 中的多个容器。每个对象的第一个参数都需要以符号-开头,表示这是一个新容器的开始。

spec.containers.image定义容器所使用的镜像。

spec.containers.name定义容器名称,该名称与metadata.name是不同的。一个是 Pod 名称,一个是 Pod 中某个容器的名称。

spec.containers.resources定义容器资源限制,这将在后面的内容中介绍。

spec.dnsPolicy定义 DNS 策略。

spec.restartPolicy定义 Pod 重启策略,在这里为 Always(遇到故障之后,总是重启)。

# 2.2.52.2.5 应用yaml并创建Pod

在创建 Pod 之前先打开文件,在原有的条目下方添加镜像下载策略:

imagePullPolicy: IfNotPresent
1

此外,你也可以在执行命令的时候添加--image-pull-policy选项,这样镜像下载策略会一同被导出至 yaml 文件当中。

Not Found Image

运行以下命令,从一个文件中创建 Pod:

kubectl apply -f <文件名>
1

成功创建了一个名为 pod-y 的 Pod。

Not Found Image

# 2.32.3 关于镜像下载策略

在命令行中创建 Pod 时,可以通过标志符--image-pull-policy来指定镜像下载策略。通过 yaml 文件创建 Pod 时,可以通过参数spec.containers.imagePullPolicy来指定镜像下载策略。

通过前面的介绍,得知镜像下载策略有三个值:IfNotPresent、Always 和 Never。默认的策略一般为 Always,为什么要说一般呢?网上有很多文章都说 Always 是默认的下载策略,但这并不完全正确。

在官方文档 (opens new window)中详细记录了有关于 “默认镜像下载策略” 的信息。当满足某个特定条件时,你的 k8s 会自动设置一个合适的下载策略。

笔记

当你省略imagePullPolicy字段的情况下,如果:

  • 没有为容器镜像指定标签,自动设置为Always
  • 容器镜像的标签为:latest,自动设置为Always
  • 为容器镜像指定了摘要,自动设置为IfNotPresent
  • 为容器镜像指定了非:latest的标签,自动设置为IfNotPresent

两种 Always 的情况,两种 IfNotPresent 的情况。相信你现在对默认的镜像下载策略有了一个初步了解。

更加详细的信息可参阅官方文档 (opens new window)。

# 33. 小练习

我们来做个小练习:

  • 通过 yaml 文件创建一个名为 pod-abc 的 Pod
  • 镜像为 nginx
  • 镜像下载策略为 IfNotPresent
  • 命名空间为 ns1
  • 添加两个标签:abc=xyz 和 hello=world
kubectl run pod-abc --image nginx --image-pull-policy=IfNotPresent -n ns1 -l abc=xyz,hello=world --dry-run=client -o yaml > abc.yaml
1

运行命令之后,将会获得以下文件内容:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    abc: xyz
    hello: world
  name: pod-abc
  namespace: ns1
spec:
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: pod-abc
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

然后,运行以下命令创建该 Pod:

kubectl apply -f abc.yaml
1

在命名空间 ns1 中可以看到刚刚创建的 pod-abc,还有之前创建的 pod2。

pod-abc 具有两个标签,都是我们手动指定的。我们之前没有为 pod2 打过标签,但 pod2 却有一个标签run=pod2。这说明,如果你没有为 Pod 指定标签,则 kubernetes 会自动为其加上一个格式为run=<名称>的默认标签。

Not Found Image

# 44. 删除Pod

从开始到现在,我们一共创建了四个 Pod:pod1、pod2、pod-y 和 pod-abc。其中 pod1 和 pod2 都是通过命令行创建的,而 pod-y 和 pod-abc 都是通过 yaml 文件的方式创建的。

Not Found Image

删除命令的语法:

kubectl delete pods <名称>

# 强制删除
kubectl delete pods <名称> --force
1
2
3
4

1. 删除 pod1:

kubectl delete pods pod1
1

一次简单的删除。此外,你还可以通过添加--force来强制删除某个 Pod,以加快删除速度。

Not Found Image

2. 同时删除命名空间 ns1 中的两个 Pod:

# 多个 Pod 之间通过空格来分隔
kubectl delete pods -n ns1 pod-2 pod-abc
1
2

我当前位于default命名空间中,如果想要删除 pod-2 和 pod-abc,则必须使用-n指定命名空间。

可以看到,第一次我没有指定命名空间,所以删除失败了,因为当前命名空间中没有这两个 Pod。

Not Found Image

现在只剩下 pod-y 了,这个 Pod 是通过 yaml 文件pod.yaml创建的。那么问题来了,我们能否基于 yaml 文件来删除某个 Pod 呢?当然可以!

Not Found Image

3. 通过 yaml 文件删除某个资源:

kubectl delete -f <文件名>
1

但是 yaml 文件中的kind和metadata参数不能有太大的偏差,否则 k8s 可能找不到对应的资源。

Not Found Image

4. 删除具有某个特定标签的多个 Pod:

之前的 Pod 都删光了,再创建四个 Pod,分别打上不同的标签:

kubectl run pod1 --image nginx --image-pull-policy=IfNotPresent -l abc=123
kubectl run pod2 --image nginx --image-pull-policy=IfNotPresent -l xyz=123
kubectl run pod3 --image nginx --image-pull-policy=IfNotPresent -l xyz=456
kubectl run pod4 --image nginx --image-pull-policy=IfNotPresent -l xyz=456
1
2
3
4

创建成功。

Not Found Image

然后运行以下命令,删除具有标签xyz=456的所有 Pod:

kubectl delete pods -l xyz=456
1

感受到标签的便捷性了吧。

Not Found Image

# 55. 操作Pod

现在我们来对 Pod 进行一些具体的操作。不过在那之前,我们先生成一个 Pod 的 yaml 文件:

kubectl run ac-pod --image nginx --image-pull-policy=IfNotPresent --dry-run=client -o yaml > ac-pod.yaml
1

文件内容如下:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: ac-pod
  name: ac-pod
spec:
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: ac-pod
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

前面提到过,一个 Pod 里可以有多个容器,怎么实现呢?

我们编辑这个文件的spec.containers参数,在原有的基础上往 Pod 里再添加一个容器:

...
spec:
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: ac1
    resources: {}
  - name: ac2
    image: nginx
    imagePullPolicy: IfNotPresent
    resources: {}
...
1
2
3
4
5
6
7
8
9
10
11
12

前面介绍过spec.containers参数,它是一个数组 + 对象的复合结构,每个符号-都表示一个新容器的开始。

这里有两个-说明有两个容器,第一个容器以参数image开始,第二个容器以参数name开始。参数没有书写顺序要求,只要保持在符号-之内即可。

此外,如果同一个 Pod 中有多个容器,则这些容器的名称不能重复,否则会冲突,导致 Pod 创建失败。所以我这里将两个容器的name分别设置为了ac1和ac2。

完整的 yaml 文件内容如下:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: ac-pod
  name: ac-pod
spec:
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: ac1
    resources: {}
  - name: ac2
    image: nginx
    imagePullPolicy: IfNotPresent
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

通过以上 yaml 文件创建 Pod:

kubectl apply -f ac-pod.yaml
1

创建成功,这个 Pod 在READY一栏中显示了2/2,表示这个 Pod 里有两个容器,且容器运行正常。

Not Found Image

如果显示1/2,表示 Pod 里有两个容器,但是只有一个容器运行正常。

你可能会看到 Pod 状态一直处于 “Error”(错误)之中,别担心,这是演示目的之一。

Not Found Image

# 5.15.1 查看Pod的日志信息

通过以下命令可以查看 Pod 中某个容器的日志信息(命令行输出信息):

kubectl logs <Pod名称>
1

查看成功,这是容器内部的一些初始化信息。

同时在最上方有一行提示 “默认容器为 ac1,共有 ac1, ac2”。这说明,如果单个 Pod 中有多个容器,则logs命令默认只会查看第一个容器中的命令行输出。

Not Found Image

如果想要查看其它容器中的命令行输出,则需要指定-c选项:

# 查看Pod中指定容器的命令行输出
kubectl logs <Pod名称> -c <容器名称>

kubectl logs ac-pod -c ac2
1
2
3
4

通过-c指定容器名称为 ac2,成功看到了容器 ac2 中的命令行输出。其中包含大量的错误信息,提示 “绑定地址的 80 端口失败”。

在 docker 中,每个容器可能都有一个独立的 IP 地址。但是在 k8s 中,每个 Pod 拥有一个独立的 IP 地址,而 Pod 中的多个容器则会共用同一个 Pod 的 IP 地址。

由于单个 Pod 中的多个容器会共用一个 IP 地址,而我们创建的两个容器又都是nginx镜像,该镜像默认监听的端口为80。两个容器都想使用这个 IP 的 80 端口,这造成了冲突,导致最终只有一个容器可以正常运行。

Not Found Image

# 5.25.2 在Pod中执行命令

# 5.2.15.2.1 在已有的Pod中执行命令

与 docker 类似,我们可以通过exec命令在 Pod 的某个容器中执行命令。

kubectl exec <Pod名称> -- <命令>

# 在指定容器中执行命令
kubectl exec <Pod名称> -c <容器名称> -- <命令>
1
2
3
4

就像这样:

# 在 ac-pod 中的 ac1 容器里执行 ls -l 命令
kubectl exec ac-pod -c ac1 -- ls -l
1
2

你可能会很疑惑,为什么 k8s 要用--来分隔要执行的命令?我也很疑惑,但这是固定语法。

Not Found Image

笔记

符号--的两边必须有空格。

那么,命令kubectl exec能否像 docker 那样,获取一个容器的 shell 终端呢?

当然!和 docker 一样,我们可以通过-it参数以及bash命令来获取一个容器的 shell 交互终端。

  • -i:获取容器的标准输入
  • -t:获取一个伪终端
kubectl exec -it ac-pod -c ac1 -- bash
1

获取 ac1 容器的终端之后,你就可以在 ac1 中尽情地执行命令。最后,你可以通过命令exit或者快捷键Ctrl+D来退出容器终端。

此外,如果不指定-c选项,则默认会获得第一个容器的 shell 终端,这和logs命令是一样的。

Not Found Image

# 5.2.25.2.2 在创建Pod时执行命令

虽然通过kubectl exec命令可以在现有的某个 Pod 中执行命令,但如果我想在创建 Pod 时执行命令呢?

和 exec 命令一样,我们可以在创建 Pod 时加上--符号,后面跟上想要执行的命令:

kubectl run e-pod --image nginx --image-pull-policy=IfNotPresent -- echo "Hello k8s"
1

然后通过 logs 命令查看 Pod 命令行输出,可以看到所打印的字符 “Hello k8s”。

此外,该 Pod 的运行状态为Completed(完成),你可能会感到疑惑,为什么这个 Pod 的运行状态会是 Completed 呢?这个问题将会在下一章节中进行解答。

Not Found Image

在模拟创建 Pod 的时候,你同样可以执行命令,并将命令一同导出至 yaml 文件中:

kubectl run e-pod2 --image nginx --image-pull-policy=IfNotPresent --dry-run=client -o yaml -- sh -c echo "Hello k8s" > hello.yaml
1

打开hello.yaml文件之后,你将看到以下内容:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: e-pod2
  name: e-pod2
spec:
  containers:
  - args:
    - sh
    - -c
    - echo
    - Hello k8s
    image: nginx
    imagePullPolicy: IfNotPresent
    name: e-pod2
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

可以看到,参数spec.containers.args定义了一个容器在启动时将要执行的命令。

args看起来可能有点突兀,其实它可以使用command参数来代替:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: e-pod2
  name: e-pod2
spec:
  containers:
  - command: ['sh', '-c', 'echo "Hello k8s"']
    image: nginx
    imagePullPolicy: IfNotPresent
    name: e-pod2
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

换成command之后看得是不是更直观了点?完整的命令为sh -c echo "Hello k8s",意思是通过脚本解释器 sh 来执行 echo 命令打印一个字符串。

然后创建该 Pod:

kubectl apply -f hello.yaml
1

查看命令行输出,可以看到由 echo 打印出来的字符。

Not Found Image

# 5.35.3 Pod文件的拷贝

我们先通过exec命令在容器 ac1 中创建一个目录:

kubectl exec ac-pod -c ac1 -- mkdir /opt/test
1
Not Found Image

# 5.3.15.3.1 从物理机到容器

语法:

kubectl cp <物理机文件路径> <Pod名称>:<文件路径>

# 指定容器, 不指定的话默认拷贝至第一个容器
kubectl cp <物理机文件路径> <Pod名称>:<文件路径> -c <容器名称>
1
2
3
4

尝试将物理机上的/etc/hosts文件拷贝到 ac-pod 里的容器 ac1 的/opt/test目录当中:

kubectl cp /etc/hosts ac-pod:/opt/test

# 查看
kubectl exec ac-pod -c ac1 -- ls /opt/test
kubectl exec ac-pod -c ac1 -- cat /opt/test/hosts
1
2
3
4
5

拷贝成功,在容器 ac1 的对应目录中可以看到来自物理机的 hosts 文件。

Not Found Image

你也可以将物理机上的一个目录拷贝至容器中。

Not Found Image

# 5.3.25.3.2 从容器到物理机

只需要将物理机和 Pod 的位置调换一下即可:

kubectl cp <Pod名称>:<文件路径> <物理机文件路径>

# 指定从哪个容器中拷贝
kubectl cp <Pod名称>:<文件路径> <物理机文件路径> -c <容器名称>
1
2
3
4

将容器 ac1 中的/etc/passwd文件拷贝至物理机的当前目录下:

kubectl cp ac-pod:/etc/passwd ./passwd
1

成功。

Not Found Image

值得一提的是,从容器中拷贝文件 到 物理机中时,你必须在物理机的路径中指定文件名。如果不指定物理机上的文件名,则拷贝会失败:

# 失败, 必须在物理机路径中指定文件名
kubectl cp -c ac1 ac-pod:/etc/passwd ./

# 成功
kubectl cp -c ac1 ac-pod:/etc/passwd ./abc
1
2
3
4
5
Not Found Image

但如果你拷贝的是一个文件夹,可以不指定目录名。

Not Found Image

笔记

使用kubectl cp命令从容器里拷贝文件至物理机时,必须在物理机路径中指定文件名。

# 5.45.4 查看Pod详细运行信息

通过该命令可以列出某个 Pod 的详细运行信息:

kubectl describe pods <Pod名称>
1

可以看到这个 Pod 的名称、所处的命名空间、运行在哪个节点上。

还可以看到 Pod 中的容器信息,例如容器 ac1 的容器编号、镜像编号、容器运行状态等。

Not Found Image

# 5.55.5 为Pod设置和删除标签

在列出 Pod 的同时,我们可以添加--show-labels选项以显示这些 Pod 的标签,那么如何为 Pod 设置标签呢?

# 5.5.15.5.1 为已有的Pod设置标签

语法:

kubectl label pods <Pod名称> <键>=<值>

# 多个标签之间使用空格分隔
kubectl label pods <Pod名称> <键1>=<值1> <键2>=<值2> ...

# 通过 减号- 来删除标签
kubectl label pods <Pod名称> <键>-
1
2
3
4
5
6
7

为这个 Pod 设置标签status=error(状态=错误),表示该 Pod 运行错误:

kubectl label pods ac-pod status=error
1

标签设置成功。

Not Found Image

同时设置多个标签:

kubectl label pods ac-pod abc=123 xyz=456
1

设置成功。

Not Found Image

注意,在生产环境中为集群资源设置标签时,标签应该具有意义,避免设置无意义标签。像此处的标签abc=123和xyz=456就是一个反面示例。

# 5.5.25.5.2 在创建Pod时设置标签

语法:

kubectl run <Pod名称> --labels <键>=<值>

# 多个标签之间使用逗号分隔
kubectl run <Pod名称> --labels <键1>=<值1>,<键2>=<值2>
1
2
3
4

创建 Pod 时通过--labels选项来为其设置标签。需要注意的是,在一个选项中设置多个标签时,你应该通过逗号,来分隔这些标签,这与kubectl label pods命令(通过空格分隔)不太一样。

Not Found Image

使用 yaml 文件创建 Pod 时,你也可以通过metadata.labels参数来为 Pod 设置标签。

metadata:
  name: <Pod名称>
  labels:
    <标签1>: <值1>
    <标签2>: <值2>
    ...
1
2
3
4
5
6

# 5.5.35.5.3 删除已有的标签

很简单,同一个命令,只需要在对应的标签 “键” 后面添加减号-即可:

kubectl label pods <Pod名称> <键>-

# 例如
kubectl label pods ac-pod abc-
1
2
3
4
Not Found Image

如果你想同时删除多个标签,则用空格分隔:

kubectl label pods ac-pod xyz- run-
1
Not Found Image

# 66. 初始化Pod

初始化 Pod 也可以叫作 Pod 中的初始化容器。

# 6.16.1 初始化容器概念

举个例子:

  • 现在有一辆车,这辆车想过河到对岸去,但是没有桥
  • 然后来了一个施工队,这个施工队在车辆过河之前,先帮忙把桥修好,然后这辆车才能过河
  • 如果在施工期间发生了任何闪失,导致修桥计划终止,那这辆车就过不了河了

然后,你可以这样理解初始化容器:

  • 某个 Pod 里有一个容器,这个容器想执行某些操作,但是运行环境不满足条件
  • 然后有一个初始化容器,在后续的容器启动之前,初始化容器先把环境配置好,之后的容器就可以正常启动和运行了
  • 如果在初始化期间发生了任何致命错误,导致初始化容器终止,那后续的容器就都不会启动了

简单来讲,初始化容器会先进行一些准备工作,为后续容器的正常运行奠定基础。

# 6.26.2 创建一个初始化容器

假设现在有一个需求,如果某个节点想要运行容器,则该节点的内核参数vm.swappiness必须为40,否则容器会运行失败。

通过以下命令可以查询一台主机上的vm.swappiness内核参数值:

cat /proc/sys/vm/swappiness
1

可以看到,节点 worker01 和 worker02 的内核参数vm.swappiness都为30,不满足运行条件。虽然我们可以手动修改这个参数,但这很繁琐。

worker01:

Not Found Image

worker02:

Not Found Image

能否在容器运行之前,先自动把当前主机的内核参数vm.swappiness调整为预期的值?这时候就可以用到初始化容器。

先通过以下命令生成一个 Pod 的 yaml 文件:

kubectl run i-pod --image nginx --image-pull-policy=IfNotPresent --dry-run=client -o yaml > init.yaml
1

然后我们打开这个文件,将其修改为以下内容:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: i-pod
  name: i-pod
spec:
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: c
    resources: {}
  initContainers:
  - image: alpine
    imagePullPolicy: IfNotPresent
    name: init-c
    command: ["/bin/sh", "-c", "/sbin/sysctl -w vm.swappiness=40"]
    securityContext:
      privileged: true
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

这个 Pod 中包含两个容器,一个是位于spec.containers参数下的普通容器c1,另一个是位于spec.initContainers参数下的初始化容器init-c。容器镜像分别为 nginx 和 alpine。

在初始化容器init-c启动的时候,通过参数command执行命令/sbin/sysctl -w vm.swappiness=40,这条命令可以修改 Pod 所处物理机上的内核参数vm.swappiness为 40。

此外,由于安全策略的存在,容器不允许修改物理机的内核参数。所以这里还添加了securityContext选项,并通过privileged: true赋予了初始化容器特权权限,使其拥有足够的权限来修改物理机的内核参数。

创建初始化 Pod:

kubectl apply -f init.yaml
1

查看 Pod 状态,此时容器的准备状态为READY: 0/1,说明容器尚未启动。而运行状态为STATUS: Init:0/1,说明有一个初始化容器已经启动,正处于初始化运行状态。

Not Found Image

等待一段时间后,容器运行状态变为Running,说明初始化成功,普通容器正常启动并运行了。

该 Pod 运行在 worker02 节点上。

Not Found Image

先看下节点 worker01 上的内核参数,还是 30 没有变化。

Not Found Image

再看下 worker02 节点,由于刚刚的 Pod 在 worker02 上运行,所以初始化容器将主机上的内核参数vm.swappiness修改为了 40。

Not Found Image

初始化容器成功配置了运行环境。

# 6.36.3 遇到错误的初始化容器

前面的例子提到过,如果在初始化期间发生了任何致命错误,导致初始化容器终止,那后续的容器就都不会启动了。我们来验证一下这个说法。

还是使用 6.2 中的 yaml 文件,但是我故意把/sbin/sysctl写错成了/sbin/sysctyyl:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: i-pod2
  name: i-pod2
spec:
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: c
    resources: {}
  initContainers:
  - image: alpine
    imagePullPolicy: IfNotPresent
    name: init-c
    command: ["/bin/sh", "-c", "/sbin/sysctyyl -w vm.swappiness=40"]
    securityContext:
      privileged: true
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

将以上内容保存至文件init2.yaml中,然后创建 Pod:

# 保存
cat <<EOF > init2.yaml
...文件内容
EOF

# 创建Pod
kubectl apply -f init2.yaml
1
2
3
4
5
6
7
Not Found Image

然后可以看到 Pod 的运行状态为Init:Error,说明初始化容器遇到错误。同时由于spec.restartPolicy参数设置为了Always,所以该 Pod 会不断尝试重启,直到不再产生错误为止,但这种重启是徒劳的。

这验证了之前的说法,桥都没修好,车怎么过?

Not Found Image

前面提到过,一个 Pod 可以有多个容器,在spec.containers条目下添加参数即可。

那可不可以有多个初始化容器呢?当然可以,书写参数的语法和普通容器一样,只不过添加参数的位置变成了spec.initContainers而已:

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: i-pod3
  name: i-pod3
spec:
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: c
  initContainers:
  - image: alpine
    imagePullPolicy: IfNotPresent
    name: init-c1
    command: ["/bin/sh", "-c", "echo 123"]
  - image: alpine
    imagePullPolicy: IfNotPresent
    name: init-c2
    command: ["/bin/sh", "-c", "echo 456456"]
  - image: alpine
    imagePullPolicy: IfNotPresent
    name: init-c3
    command: ["/bin/sh", "-c", "echo 789789789"]
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
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

如果存在多个初始化容器,它们会如何运行?

例如,以上 Pod 拥有init-c1、init-c2和init-c3共三个初始化容器,这三个初始化容器会按定义的顺序依次执行,当这三个初始化容器都完成运行之后,普通容器c才会正常启动。

如果某一个初始化容器出现错误,则整个 Pod 都不会运行。例如,当init-c1完成运行之后,如果init-c2遇到了致命错误,则后续的初始化容器init-c3和普通容器c都将不会启动,普通容器不运行,则 Pod 也同样不会运行。

# 77. 静态Pod

# 7.17.1 静态Pod概念

在 master 节点的/etc/kubernetes/manifests/目录下,总是会看到以下几个 yaml 文件:

Not Found Image

这些 yaml 文件的名称是不是很眼熟?在命名空间kube-system中,也能看到四个同名的 Pod,它们是用于运行 master 节点的核心 Pod。

只有当这些 Pod 运行了,master 和其余的 node 节点才能运行和建立联系。当节点与节点之间都联系起来时,就形成了一个集群。换句话说,这四个 Pod 是用于启动集群的核心。

但是现在遇到了一个问题:

  • 如果想运行 Pod,则需要依靠集群内的 master 节点来创建和调度 Pod
  • 如果想启动 master 节点,又必须先运行这些核心 Pod

核心 Pod 没运行,那 master 就无法运行,集群也无法运行。集群没启动,怎么创建和调度 Pod 呢?

Not Found Image

这时候就需要静态 Pod 了,这是一种不需要 master 节点即可自主运行的 Pod。

一般情况下,需要依靠 master 节点来创建和调度 Pod。这类 Pod 可以称其为动态 Pod(依赖 master 创建)。

而有些 Pod 则不需要依赖 master 节点,当 k8s 的主服务kubelet启动时,这些 Pod 也会跟随服务自动创建和运行。这类 Pod 可以称其为静态 Pod(不依赖 master,启动 k8s 时自动创建)。

什么?你问我kubelet是啥?请回去看 “第 1 章的 2.1 节”。

# 7.27.2 创建一个静态Pod

# 7.2.17.2.1 通过yaml文件创建静态Pod

静态 Pod 纯粹依靠 yaml 文件来创建,无法通过kubectl run命令来创建。

但你依然可以通过该命令来导出一个 yaml 文件模板:

kubectl run static-pod --image nginx --image-pull-policy=IfNotPresent --dry-run=client -o yaml > static-pod.yaml

cp static-pod.yaml /etc/kubernetes/manifests/
1
2
3

通过以上命令生成一个 Pod 的 yaml 文件,然后将其拷贝到默认的静态 Pod 目录/etc/kubernetes/manifests/中。

可以看到,在拷贝 yaml 文件之前只有i-pod这一个 Pod,在拷贝之后,立马生成了一个新的名为static-pod-<主机名>的 Pod。

Not Found Image

这正是由我们的 yaml 创建出来的一个静态 Pod,它的名称后面总会加上一个-<主机名>作为标识。

# 7.2.27.2.2 通过yaml文件删除静态Pod

静态 Pod 是无法通过命令kubectl delete pods来删除的,我们可以做个实验。

删除刚刚创建的静态 Pod:

kubectl delete pods static-pod-www.k10.com
1

从图中可以看到,运行命令后提示成功删除了该 Pod。随后发现 Pod 的状态为 “Pending”,在该状态停留一会之后,Pod 的状态又变回了 “Running” 继续运行。

Not Found Image

刚刚的 Pod 确实已经被删除了,但是由于 yaml 文件还存在,在删除之后的短时间内,这个 yaml 文件又被解析并创建了一个新的、一模一样的 Pod。

既然无法通过命令删除静态 Pod,那就直接找准源头,删除它的 yaml 文件:

rm -rf /etc/kubernetes/manifests/static-pod.yaml
1

删除源文件后,由该文件创建出来的静态 Pod 也会自动停止并删除。

Not Found Image

# 7.37.3 修改静态Pod存储路径

存放静态 Pod 的默认路径为/etc/kubernetes/manifests/,有两种方式可以修改存放路径。

# 7.3.17.3.1 通过kubelet服务文件修改

我拿 master 节点来做以下操作。

  1. 查看kubelet服务状态,找到服务文件的存储目录:
systemctl status kubelet
1
Not Found Image
  1. 在目录下找到kubelet的服务文件10-kubeadm.conf,然后打开它:
ls -l /usr/lib/systemd/system/kubelet.service.d/

vim /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf
1
2
3
Not Found Image
  1. 打开文件后,找到以下配置选项:
# 任意一个Environment
Environment="..."
1
2
Not Found Image
  1. 在该选项的最后边添加参数,修改静态 Pod 存储路径:
--pod-manifest-path=<目录>

# 例如
--pod-manifest-path=/opt/change-service
1
2
3
4
Not Found Image
  1. 创建对应的存储目录,然后重启kubelet服务:
mkdir /opt/change-service

systemctl daemon-reload
systemctl restart kubelet
1
2
3
4

重启成功后就完成了路径的修改。

Not Found Image

然后你会发现,集群失灵了?服务kubelet的运行状态是正常的,但无论运行什么命令都毫无作用。

是配置错了吗?

Not Found Image

其实配置没错,反而非常对。

前面说过,集群的运行依靠 master 节点,master 节点的运行依靠默认路径/etc/kubernetes/manifests/下的核心静态 Pod。

由于刚刚修改了静态 Pod 的默认路径,导致 master 的核心组件无法启动,集群自然也无法运行。

你可以将 master 所需的静态 Pod yaml 文件拷贝到新的路径下,从而解决这个问题。但一般情况下,我们都不会去修改 master 节点上的默认静态 Pod 存储目录。

# 7.3.27.3.2 通过k8s配置文件修改

既然 master 节点上有静态 Pod,那 worker 上面有没有静态 Pod 呢?——有,而且可以随意修改存储路径。

  1. 切换至 worker01 节点,打开同样的kubelet服务文件:
ls -l /usr/lib/systemd/system/kubelet.service.d/

vim /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf
1
2
3
Not Found Image
  1. 打开文件后,即可看到 k8s 配置文件的存储位置。
--config=/var/lib/kubelet/config.yaml
1
Not Found Image
  1. 打开配置文件后,在文件最底部可以看到静态 Pod 的默认存储路径:
staticPodPath: /etc/kubernetes/manifests
1
Not Found Image
  1. 你可以通过#将原来的条目注释,防止原配置丢失。然后另起一行用于修改静态 Pod 存储路径:
Not Found Image
  1. 一样的创建存储目录,一样的重启kubelet服务:
mkdir /opt/change-conf

systemctl daemon-reload
systemctl restart kubelet
1
2
3
4

重启服务之后,在目录opt/change-conf下放置一个简单的 yaml 文件用于测试:

apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: test
1
2
3
4
5
6
7
8
9
Not Found Image

然后回到 master 节点上进行查看,发现 worker01 节点成功创建了一个名为test-www.k11.com的静态 Pod。

Not Found Image

# 88. 小结

本章对 Pod 做了一个初步的了解,通过本章的学习,你应该掌握以下技能:

  • 使用kubectl get和kubectl top命令以及一系列参数查看 Pod
  • 通过命令行或 yaml 文件的方式创建 Pod
  • 通过命令行或 yaml 文件的方式删除单个/多个 Pod
  • 通过logs、exec、cp、describe和label等子命令操作 Pod
  • 创建初始化 Pod
  • 修改静态 Pod 存储路径,通过 yaml 创建静态 Pod

如果你已经掌握了以上内容,就试着去完成一些练习(练习题-3)吧!

编辑 (opens new window)
第4章-集群升级
第6章-Pod生命周期与资源限制

← 第4章-集群升级 第6章-Pod生命周期与资源限制→

最近更新
01
API测试笔记
04-30
02
msfvenom
03-29
03
Metasploit
03-29
更多文章>
Theme by Vdoing | Copyright © 2023-2024 Carsaid | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式