Kubernetes之(八)Pod的生命周期

释放双眼,带上耳机,听听看~!

目录

  • Kubernetes之(八)Pod的生命周期

  • 理解Pod

  • Pod内如何管理多个容器
    * Pod的使用
    * 其他替代选择
    * Pod的持久性
    * Pod的终止
    * Init容器
    * Pause容器

    • Pod的生命周期
  • Pod的phase
    * Pod的状态
    * 容器探针
    * 存活性探测 livenessProbe
    * 就绪性探测 readnessProbe
    * livenessProbe和readinessProbe使用场景
    * lifecycle

Kubernetes之(八)Pod的生命周期

理解Pod

Pod是kubernetes中你可以创建和部署的最⼩也是最简的单位。 ⼀个Pod代表着集群中运⾏的⼀个进程。
Pod中封装着应⽤的容器(有的情况下是好⼏个容器) , 存储、 独⽴的⽹络IP, 管理容器如何运⾏的策略选项。 Pod代
表着部署的⼀个单位: kubernetes中应⽤的⼀个实例, 可能由⼀个或者多个容器组合在⼀起共享资源。
在Kubrenetes集群中Pod有如下两种使⽤⽅式:

  • ⼀个Pod中运⾏⼀个容器。 “每个Pod中⼀个容器”的模式是最常⻅的⽤法; 在这种使⽤⽅式中, 你可以把Pod想象成是单个容器的封装, kuberentes管理的是Pod⽽不是直接管理容器。
  • 在⼀个Pod中同时运⾏多个容器。 ⼀个Pod中也可以同时封装⼏个需要紧密耦合互相协作的容器, 它们之间共享资源。 这些在同⼀个Pod中的容器可以互相协作成为⼀个service单位——⼀个容器共享⽂件, 另⼀个“sidecar”容器来更新这些⽂件。 Pod将这些容器的存储资源作为⼀个实体来管理。

每个Pod都是应⽤的⼀个实例。 如果你想平⾏扩展应⽤的话(运⾏多个实例) , 你应该运⾏多个Pod, 每个Pod都是⼀个应⽤实例。 在Kubernetes中, 这通常被称为replication。

Pod内如何管理多个容器

Pod中可以同时运行多个进程(作为容器运行)协同工作。同一个Pod中的容器会自动的分配到同一个 node 上。同一个Pod中的容器共享资源、网络环境和依赖,它们总是被同时调度。
注意在一个Pod中同时运行多个容器是一种比较高级的用法。只有当你的容器需要紧密配合协作的时候才考虑用这种模式。例如,你有一个容器作为web服务器运行,需要用到共享的volume,有另一个“sidecar”容器来从远端获取资源更新这些文件,如下图所示:
(图片来源于网络)
Pod中可以共享两种资源:网络和存储。

  • 网络

每个Pod都会被分配一个唯一的IP地址。Pod中的所有容器共享网络空间,包括IP地址和端口。Pod内部的容器可以使用localhost互相通信。Pod中的容器与外界通信时,必须分配共享网络资源(例如使用宿主机的端口映射)。

  • 存储

可以Pod指定多个共享的Volume。Pod中的所有容器都可以访问共享的volume。Volume也可以用来持久化Pod中的存储资源,以防容器重启后文件丢失。

Pod的使用

Pod也可以⽤于垂直应⽤栈(例如LAMP) , 这样使⽤的主要动机是为了⽀持共同调度和协调管理应⽤程序, 例如:

  • 内容管理系统、 ⽂件和数据加载器、 本地换群管理器等。
  • ⽇志和检查点备份、 压缩、 旋转、 快照等。
  • 数据变更观察者、 ⽇志和监控适配器、 活动发布者等。
  • 代理、 桥接和适配器等。
  • 控制器、 管理器、 配置器、 更新器等。

通常单个pod中不会同时运⾏⼀个应⽤的多个实例。

其他替代选择

为什么不直接在⼀个容器中运⾏多个应⽤程序呢?
1、透明,让Pod中的容器对基础设施可⻅, 以便基础设施能够为这些容器提供服务, 例如进程管理和资源监控。 这可以为⽤户带来极⼤的便利。
2、解耦软件依赖。 每个容器都可以进⾏版本管理, 独⽴的编译和发布。 未来kubernetes甚⾄可能⽀持单个容器的在线升级。
3、使⽤⽅便。 ⽤户不必运⾏⾃⼰的进程管理器, 还要担⼼错误信号传播等。
4、效率。 因为由基础架构提供更多的职责, 所以容器可以变得更加轻量级。

Pod的持久性

Pod在设计⽀持就不是作为持久化实体的。 在调度失败、 节点故障、 缺少资源或者节点维护的状态下都会死掉会被驱逐。
通常, ⽤户不需要⼿动直接创建Pod, ⽽是应该使⽤controller(例如Deployments) , 即使是在创建单个Pod的情况下。 Controller可以提供集群级别的⾃愈功能、 复制和升级管理。
Pod原语有利于:

  • 调度程序和控制器可插拔性
  • 支持pod级操作,无需通过控尸气API代理他们
  • 将pod生命周期与控制器生命周期分离
  • 控制器与服务的分离,端点控制器只是监视pod
  • 将集群集功能与kubelet及共鞥的清晰组合
  • 高可用性应用程序,他们可以在终止前及在删除前更换pod

Pod的终止

因为Pod作为在集群的节点上运⾏的进程, 所以在不再需要的时候能够优雅的终⽌掉是⼗分必要的(⽐起使⽤发送KILL信号这种暴⼒的⽅式) 。 ⽤户需要能够放松删除请求, 并且知道它们何时会被终⽌, 是否被正确的删除。 ⽤户想终⽌程序时发送删除pod的请求, 在pod可以被强制删除前会有⼀个宽限期, 会发送⼀个TERM请求到每个容器的主进程。 ⼀旦超时, 将向主进程发送KILL信号并从API server中删除。 如果kubelet或者container manager在等待进程终⽌的过程中重启, 在重启后仍然会重试完整的宽限期。
示例流程如下:

  1. 用户发送删除pod的命令,默认宽限期30秒
  2. 、在Pod超过该宽限期后API server就会更新Pod的状态为dead
  3. 在客户端命令行上显示的Pod的状态为为terminating;
  4. 跟上一部同时,当kubelet发现pod被标记为terminating时,开始停止pod进程:
  • 如果在pod中定义了preStop hook,在停止pod前会被调用。如果宽限期后 preStop hook仍然在运行,第二部会增加2秒宽限期;
  • 向Pod中的进程发送TERM信号
  1. 跟第三部同时,该Pod将从该service的端点列表中删除,不再是replication controller中的一部分,关闭的慢的pod将继续处理load balancer转发的流量
  2. 过了宽限期后,将向Pod中易安存在的进程发SIGKILL信号杀掉进程。
  3. kubelet会在APIserver中完成Pod的删除,通过将优雅周期设置为0(立即删除)Pod在API中小时,并且客户端也不可见。

删除宽限期默认是30秒。 kubectl delete 命令⽀持 —grace-period=
选项, 允许⽤户设置⾃⼰的宽限期。 如果设置为0将强制删除pod。 在kubectl>=1.5版本的命令中, 你必须同时使⽤ –force 和 –grace-period=0 来强制删除pod。

Init容器

Pod能够具有多个容器,应用运行在容器里面,但是它也可能有一个或多个咸鱼应用容器启动的Init容器。
Init容器与普通容器很像,除了一下亮点:

  • Init容器总是u以女性到成功完成为止。
  • 每个Init容器都必要在下一个Init容器启动之前完成。

如果 Pod 的 Init 容器失败, Kubernetes 会不断地重启该 Pod, 直到 Init 容器成功为⽌。 然⽽, 如果 Pod 对应的restartPolicy 为 Never, 它不会重新启动。

Pause容器

Pause容器,又叫Infra容器。我们检查node节点的时候会发现每个node上都运行了很多的pause容器,例如如下。


1
2
3
4
5
6
7
1[root@node02 ~]# docker ps |grep pause
2db1f4da98626        registry.aliyuncs.com/google_containers/pause:3.1   "/pause"                 24 hours ago        Up 24 hours                             k8s_POD_myapp-9b4987d5-djdr9_default_995067e0-5124-11e9-80a7-000c295ec349_0
3e344da31cee8        registry.aliyuncs.com/google_containers/pause:3.1   "/pause"                 24 hours ago        Up 24 hours                             k8s_POD_client-f5cdb799f-pklmc_default_25f4bf9b-5121-11e9-80a7-000c295ec349_0
4de5e811fa5fa        registry.aliyuncs.com/google_containers/pause:3.1   "/pause"                 28 hours ago        Up 28 hours                             k8s_POD_nginx-deploy-84cbfc56b6-tcssz_default_10003a4a-5104-11e9-80a7-000c295ec349_0
53f7d179b79b9        registry.aliyuncs.com/google_containers/pause:3.1   "/pause"                 30 hours ago        Up 30 hours                             k8s_POD_kube-flannel-ds-amd64-gwbql_kube-system_0f2de1c5-506c-11e9-80a7-000c295ec349_1
6cc07e6411d32        registry.aliyuncs.com/google_containers/pause:3.1   "/pause"                 30 hours ago        Up 30 hours                             k8s_POD_kube-proxy-cz2rf_kube-system_1f58e488-5068-11e9-80a7-000c295ec349_1
7

kubernetes中的pause容器主要为每个业务容器提供以下功能:

  • 在pod中担任Linux命名空间共享的基础;
  • 启用pid命名空间,开启init进程。

pause容器的作⽤可以从这个例⼦中看出, ⾸先⻅下
图:
(图片来源于网络)
我们⾸先在节点上运⾏⼀个pause容器。


1
2
3
4
5
6
7
1[root@node02 ~]# docker run --name pause -d -p 8880:80 xiaobai20201/pause:3.1
2Unable to find image 'xiaobai20201/pause:3.1' locally
33.1: Pulling from xiaobai20201/pause
4Digest: sha256:59eec8837a4d942cc19a52b8c09ea75121acc38114a2c68b98983ce9356b8610
5Status: Downloaded newer image for xiaobai20201/pause:3.1
6d4078dc99bec81167c8d288c2b44485d407780913eee88458986d5bb3750c509
7

然后再运⾏⼀个nginx容器, nginx将为 localhost:2368 创建⼀个代理。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1[root@node02 ~]# vim nginx.conf
2error_log stderr;
3events { worker_connections 1024; }
4http {
5        access_log /dev/stdout combined;
6        server {
7                listen 80 default_server;
8                server_name example.com www.example.com;
9                location / {
10                        proxy_pass http://127.0.0.1:2368;
11                }
12        }
13}
14[root@node02 ~]#  docker run -d --name nginx -v `pwd`/nginx.conf:/etc/nginx/nginx.conf --net=container:pause --ipc=container:pause --pid=container:pause nginx
15
16

然后为ghost创建一个容器应用,这是一款博客软件。


1
2
1[root@node02 ~]# docker run -d --name ghost --net=container:pause --ipc=container:pause --pid=container:pause ghost
2

现在访问http://10.0.0.12:8880/ 就可以看到ghost博客的界面了

解析
pause容器将内部的80端⼝映射到宿主机的8880端⼝, pause容器在宿主机上设置好了⽹络namespace后, nginx容器加⼊到该⽹络namespace中, 我们看到nginx容器启动的时候指定了 –net=container:pause , ghost容器同样加⼊到了该⽹络namespace中, 这样三个容器就共享了⽹络, 互相之间就可以使⽤ localhost 直接通信, –ipc=contianer:pause –pid=container:pause 就是三个容器处于同⼀个namespace中, init进程为 pause , 这时我们进⼊到ghost容器中查看进程情况。

Pod的生命周期

Pod的phase

Pod的status信息保存在PodStatus中定义,有一个phase字段
Pod的相位(phase)是Pod在其生命周期中的简单宏观概述,该阶段并不是对容器或Pod的总和汇总,也不是为了作为综合状态机。
Pod香味的数量和含义是严格指定的。除了文档中列举的状态外,不应该再假定Pod有其他phase值。
下面是phase可能的值:

  • 挂起 Pending:Pod已经被Kubernetes系统接受,但是有一个或多个容器镜像尚未创建,等待时间包括调度Pod的时间和通过网络下载镜像的时间。
  • 运行中 Running:该Pod已经绑定到一个节点上,Pod中所有的容器都已经被创建,至少有一个容器正在运行或者处于启动或者重启状态。
  • 成功 Succeeded:Pod中的所有容器都被成功终止,并且不会在重启。
  • 失败 Failed:Pod中的所有容器已经终止,并且至少有一个容器是因为失败终止,也就是说,容器以非0状态退出或者被系统终止。
  • 位置 Unknown:因为某些议无法获取Pod的状态,哦那个厂是因为与Pod所在的节点通信失败。

Pod的状态

Pod 有一个 PodStatus 对象,其中包含一个 PodCondition 数组。 PodCondition 数组的每个元素都有一个 type 字段和一个 status 字段。type 字段是字符串,可能的值有 PodScheduled、Ready、Initialized 和 Unschedulable。status 字段是一个字符串,可能的值有 True、False 和 Unknown。

容器探针

在pod生命周期中可以做的一些事情。主容器启动前可以完成初始化容器,初始化容器可以有多个,他们是串行执行的,执行完成后就推出了,在主程序刚刚启动的时候可以指定一个post start 主程序启动开始后执行一些操作,在主程序结束前可以指定一个 pre stop 表示主程序结束前执行的一些操作。在程序启动后可以做两类检测 liveness probe(存活性探测) 和 readness probe(就绪性探测)

探针是由 kubelet 对容器执⾏的定期诊断。 要执⾏诊断, kubelet 调⽤由容器实现的 Handler。 有三种类型的处理程序:

  • ExecAction: 在容器内执⾏指定命令。 如果命令退出时返回码为 0 则认为诊断成功。
  • TCPSocketAction: 对指定端⼝上的容器的 IP 地址进⾏ TCP 检查。 如果端⼝打开, 则诊断被认为是成功的
  • HTTPGetAction: 对指定的端⼝和路径上的容器的 IP 地址执⾏ HTTP Get 请求。 如果响应的状态码⼤于等于200且⼩于 400, 则诊断被认为是成功的。

Kubelet 可以选择是否执行在容器上运行的两种探针执行和做出反应:

  • **livenessProbe:**指示容器是否正在运行。如果存活探测失败,则 kubelet 会杀死容器,并且容器将受到其 重启策略 的影响。如果容器不提供存活探针,则默认状态为 Success。
  • **readinessProbe:**指示容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与 Pod 匹配的所有 Service 的端点中删除该 Pod 的 IP 地址。初始延迟之前的就绪状态默认为 Failure。如果容器不提供就绪探针,则默认状态为 Success。

存活性探测 livenessProbe

解析


1
2
3
4
5
6
7
8
9
10
11
12
13
1
2[root@master ~]# kubectl explain pods.spec.containers.livenessProbe.
3KIND:     Pod
4VERSION:  v1
5   exec <Object> #命令式探针
6   failureThreshold     <integer> #探测失败次数,超过该次数才算失败,默认是3
7   periodSeconds        <integer> #探测间隔时间,默认10s
8   successThreshold     <integer> #探测成功的最少次数,默认是1,即探测成功1次就算是成功
9   tcpSocket    <Object> #检测端口的探测
10   initialDelaySeconds  #初始化延迟探测,第一次探测的时候,因为主程序未必启动完成
11   timeoutSeconds       <integer> # 探测超时的秒数 默认1s
12   httpGet <Object> #http请求探测
13

exec探针举例


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
28
29
30
31
32
1[root@master manifests]# vim liveness-exec.yaml
2apiVersion: v1
3kind: Pod
4metadata:
5  name: liveness-exec-pod
6  namespace: default
7spec:
8  containers:
9  - name: liveness-exec-container
10    image: busybox
11    imagePullPolicy: IfNotPresent
12    command: ["/bin/sh","-c","touch /tmp/healthy;sleep 30;rm -f /tmp/healthy;sleep 600"]
13    livenessProbe:
14      exec:
15        command: ["test","-e","/tmp/healthy"]
16      initialDelaySecond: 1
17      periodSecond: 3
18#运行并查看pod
19[root@master manifests]# kubectl apply -f liveness-exec.yaml
20pod/liveness-exec-pod created
21[root@master manifests]# kubectl get pods -w
22NAME                            READY   STATUS    RESTARTS   AGE
23client-f5cdb799f-pklmc          1/1     Running   0          25h
24liveness-exec-pod               1/1     Running   0          5s
25myapp-9b4987d5-47sjj            1/1     Running   0          25h
26myapp-9b4987d5-684q9            1/1     Running   0          25h
27myapp-9b4987d5-djdr9            1/1     Running   0          25h
28nginx-deploy-84cbfc56b6-tcssz   1/1     Running   0          29h
29pod-demo                        2/2     Running   4          4h33m
30liveness-exec-pod   1/1   Running   1     87s
31#重启次数变成1
32

上面的资源清单中定义了一个Pod对象,基于busybox镜像启动一个运行“touch /tmp/healthy;sleep 30;rm -f /tmp/healthy;sleep 600”命令的容器,此命令在容器启动时创建/tmp/healthy文件,并于60秒之后将其删除。存活性探针运行“test -e /tmp/healthy”命令检查/tmp/healthy文件的存在性,若文件存在则返回状态码0,表示成功通过测试。

httpGet探测举例


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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
1[root@master manifests]# vim liveness-httpget.yaml
2apiVersion: v1
3kind: Pod
4metadata:
5  name: liveness-httpget-pod
6  namespace: default
7spec:
8  containers:
9  - name: liveness-httpget-container
10    image: ikubernetes/myapp:v1
11    imagePullPolicy: IfNotPresent
12    ports:
13    - name: http
14      containerPort: 80
15    livenessProbe:
16      httpGet:
17        port: http
18        path: /index.html
19
20#创建Pod并查看
21[root@master manifests]# kubectl create -f liveness-httpget.yaml
22pod/liveness-httpget-pod created
23[root@master manifests]# kubectl get pods
24NAME                            READY   STATUS    RESTARTS   AGE
25client-f5cdb799f-pklmc          1/1     Running   0          26h
26liveness-exec-pod               1/1     Running   8          20m
27liveness-httpget-pod            1/1     Running   0          8s
28myapp-9b4987d5-47sjj            1/1     Running   0          25h
29myapp-9b4987d5-684q9            1/1     Running   0          25h
30myapp-9b4987d5-djdr9            1/1     Running   1          25h
31nginx-deploy-84cbfc56b6-tcssz   1/1     Running   0          29h
32pod-demo                        2/2     Running   4          4h53m
33
34#手动进入容器删除index.html文件,再监控pod状态
35[root@master manifests]# kubectl exec -it  liveness-httpget-pod -- /bin/sh
36/ # rm -f /usr/share/nginx/html/index.html
37#查看pod
38^C[root@master manifests]# kubectl get pods -w
39NAME                            READY   STATUS             RESTARTS   AGE
40client-f5cdb799f-pklmc          1/1     Running            0          26h
41liveness-exec-pod               0/1     CrashLoopBackOff   9          24m
42liveness-httpget-pod            1/1     Running            1          3m41s
43myapp-9b4987d5-47sjj            1/1     Running            0          25h
44myapp-9b4987d5-684q9            1/1     Running            0          25h
45myapp-9b4987d5-djdr9            1/1     Running            1          25h
46nginx-deploy-84cbfc56b6-tcssz   1/1     Running            0          29h
47pod-demo                        2/2     Running            4          4h57m
48#发现liveness-httpget-pod已经重启了一次
49
50

TCP探测举例


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1apiVersion: v1
2kind: Pod
3metadata:
4  labels:
5    test: liveness-tcp
6  name: liveness-tcp
7spec:
8  containers:
9  - name: liveness-tcp-demo
10    image: nginx:1.12-alpine
11    ports:
12    - name: http
13      containerPort: 80
14    livenessProbe:
15      tcpSocket:
16        port: http
17

就绪性探测 readnessProbe


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1[root@master manifests]# vim readness-httpget.yaml
2apiVersion: v1
3kind: Pod
4metadata:
5  name: readiness-httpget-pod
6  namespace: default
7spec:
8  containers:
9  - name: readiness-httpget-container
10    image: ikubernetes/myapp:v1
11    imagePullPolicy: IfNotPresent
12    ports:
13    - name: http
14      containerPort: 80
15    readinessProbe:
16      httpGet:
17        port: http
18        path: /index.html
19      initialDelaySecond: 1
20      periodSeconds: 3
21

此时pod运行正常,进入容器删除首页文件后观察pod状态


1
2
3
4
5
6
7
8
9
10
11
12
13
1[root@master manifests]# kubectl exec -it readiness-httpget-pod -- /bin/sh
2/ # rm -f /usr/share/nginx/html/index.html
3
4[root@master manifests]# kubectl get pods -w
5NAME                            READY   STATUS    RESTARTS   AGE
6client-f5cdb799f-pklmc          1/1     Running   0          26h
7myapp-9b4987d5-47sjj            1/1     Running   0          26h
8myapp-9b4987d5-684q9            1/1     Running   0          26h
9myapp-9b4987d5-djdr9            1/1     Running   1          26h
10nginx-deploy-84cbfc56b6-tcssz   1/1     Running   0          30h
11pod-demo                        2/2     Running   5          5h27m
12readiness-httpget-pod           0/1     Running   0          115s
13

重写写入index.html文件后继续观察pod


1
2
3
4
5
6
7
8
9
10
11
1/ # echo ad >/usr/share/nginx/html/index.html
2^C[root@master manifests]# kubectl get pods -w
3NAME                            READY   STATUS    RESTARTS   AGE
4client-f5cdb799f-pklmc          1/1     Running   0          26h
5myapp-9b4987d5-47sjj            1/1     Running   0          26h
6myapp-9b4987d5-684q9            1/1     Running   0          26h
7myapp-9b4987d5-djdr9            1/1     Running   1          26h
8nginx-deploy-84cbfc56b6-tcssz   1/1     Running   0          30h
9pod-demo                        2/2     Running   5          5h29m
10readiness-httpget-pod           1/1     Running   0          3m54s
11

livenessProbe和readinessProbe使用场景

如果容器中的进程能够在遇到问题或不健康的情况下自行崩溃,则不一定需要存活探针; kubelet 将根据 Pod 的restartPolicy 自动执行正确的操作。

如果希望容器在探测失败时被杀死并重新启动,那么请指定一个存活探针,并指定restartPolicy 为 Always 或 OnFailure。

如果要仅在探测成功时才开始向 Pod 发送流量,请指定就绪探针。在这种情况下,就绪探针可能与存活探针相同,但是 spec 中的就绪探针的存在意味着 Pod 将在没有接收到任何流量的情况下启动,并且只有在探针探测成功后才开始接收流量。

如果您希望容器能够自行维护,您可以指定一个就绪探针,该探针检查与存活探针不同的端点。

请注意,如果您只想在 Pod 被删除时能够排除请求,则不一定需要使用就绪探针;在删除 Pod 时,Pod 会自动将自身置于未完成状态,无论就绪探针是否存在。当等待 Pod 中的容器停止时,Pod 仍处于未完成状态。

lifecycle

定义容器启动后和终止前立即执行的动作
解析


1
2
3
4
5
6
7
8
9
10
11
1[root@master ~]# kubectl explain pods.spec.containers.lifecycle.
2postStart    <Object> #启动后
3- exec
4- httpGet
5- tcpSocket
6
7preStop      <Object> #终止前
8- exec
9- httpGet
10- tcpSocket
11

postStart举例


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1[root@master manifests]# vim poststart-pod.yaml
2apiVersion: v1
3kind: Pod
4metadata:
5  name: poststart-pod
6  namespace: default
7spec:
8  containers:
9  - name: busybox-httpd
10    image: busybox
11    imagePullPolicy: IfNotPresent
12    lifecycle:
13      postStart:
14        exec:
15          command: ["mkdir","-p","/tmp/share"]
16    command: ["/bin/sh","-c","sleep 3600"]
17#进入容器查看是否有/tmp/share目录
18[root@master manifests]# kubectl exec -it poststart-pod  -- /bin/sh
19/ # ls -l /tmp
20total 0
21drwxr-xr-x    2 root     root             6 Mar 29 09:19 share
22

给TA打赏
共{{data.count}}人
人已打赏
安全运维

故障复盘的简洁框架-黄金三问

2021-9-30 19:18:23

安全运维

OpenSSH-8.7p1离线升级修复安全漏洞

2021-10-23 10:13:25

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索