kubernetes集群pod中的pause容器作用

文章目录

分析

我们搭建完集群了以后,可以使用最简单的方式创建一个pod,随意你建立什么pod,去访问相应node上执行docker ps 就会看到有一种pause容器,但是你可能从来没有启用

etrics-scraper_dashboard-metrics-scraper-7b59f7d4df-pqntv_kubernetes-dashboard_0516991e-e13a-4830-826f-6bb3a543b314_2
9a69b76f1410   lizhenliang/pause-amd64:3.0   "/pause"             2 hours ago   Up 2 hours             k8s_POD_dashboard-metrics-scraper-7b59f7d4df-pqntv_kubernetes-dashboard_0516991e-e13a-4830-826f-6bb3a543b314_2
1dab2142e86c   lizhenliang/pause-amd64:3.0   "/pause"             2 hours ago   Up 2 hours             k8s_POD_calico-node-9w6vz_kube-system_26c6db9f-a21a-46da-b22e-32b5c980db3c_2

在这里插入图片描述
那么它是啥呢?看看源码(C语言写的,简单看看吧)

知识普及
软中断信号(signal,又简称为信号)用来通知进程发生了异步事件。在软件层次上是对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是进程间通信机制中唯一的异步通信机制,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。进程之间可以互相通过系统调用kill发送软中断信号。内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件。信号机制除了基本通知功能外,还可以传递附加信息。

SIGHUP 1 A 终端挂起或者控制进程终止
SIGINT 2 A 键盘中断(如break键被按下)
SIGQUIT 3 C 键盘的退出键被按下
SIGILL 4 C 非法指令
SIGABRT 6 C 由abort(3)发出的退出指令
SIGFPE 8 C 浮点异常
SIGKILL 9 AEF Kill信号
SIGSEGV 11 C 无效的内存引用
SIGPIPE 13 A 管道破裂: 写一个没有读端口的管道
SIGALRM 14 A 由alarm(2)发出的信号
SIGTERM 15 A 终止信号
SIGUSR1 30,10,16 A 用户自定义信号1
SIGUSR2 31,12,17 A 用户自定义信号2
SIGCHLD 20,17,18 B 子进程结束信号
SIGCONT 19,18,25 进程继续(曾被停止的进程)
SIGSTOP 17,19,23 DEF 终止进程
SIGTSTP 18,20,24 D 控制终端(tty)上按下停止键
SIGTTIN 21,21,26 D 后台进程企图从控制终端读
SIGTTOU 22,22,27 D 后台进程企图从控制终端写

strcasecmp用忽略大小写比较字符串.,通过strncasecmp函数可以指定每个字符串用于比较的字符数,strcasecmp用来比较参数s1和s2字符串前n个字符,比较时会自动忽略大小写的差异。

fprintf 函数的功能是: Print formatted data to a stream格式化输出数据到流
strerr是作为程序运行过程中的错误显示出来的

#include <signal.h>                               #角度啊啥的函数库
#include <stdio.h>                                #C最基础的库
#include <stdlib.h>                                  
#include <string.h>                                
#include <sys/types.h>                            #系统类型的函数库       
#include <sys/wait.h>                             #系统进程wait控制函数库
#include <unistd.h>                             #从开始到现在都是调用库,会用到库里面的一些函数库
 
#define STRINGIFY(x) #x                         
#define VERSION_STRING(x) STRINGIFY(x) 
 
#ifndef VERSION 
#define VERSION HEAD                          
#endif                                          #到这里是重定义一些变量,不会C的可以理解为alias      
     
static void sigdown(int signo) {                 
  psignal(signo, "Shutting down, got signal");  #一个函数,意思让signal软中断信号停止
  exit(0); 
} 
 
static void sigreap(int signo) { 
  while (waitpid(-1, NULL, WNOHANG) > 0)    #循环waitpid函数获取相应的pid
    ; 
} 
 
int main(int argc, char **argv) {                       #主函数终于来了***************
  int i; 
  for (i = 1; i < argc; ++i) {                      #循环判断
    if (!strcasecmp(argv[i], "-v")) {   #比较字符串组 argv[i]版本是否与需求版本一致
      printf("pause.c %s\n", VERSION_STRING(VERSION)); #不是这输出pause版本
      return 0; 
    } 
  } 
 
  if (getpid() != 1)                  #判断获取的pid号是否为1
    /* Not an error because pause sees use outside of infra containers. */ 
    fprintf(stderr, "Warning: pause should be the first process\n");  #将错误信息打印,并打印提示信息
 
  if (sigaction(SIGINT, &(struct sigaction){.sa_handler = sigdown}, NULL) < 0)  #A 键盘中断(如break键被按下)
    return 1;                    
  if (sigaction(SIGTERM, &(struct sigaction){.sa_handler = sigdown}, NULL) < 0)  # A  终止信号
    return 2; 
  if (sigaction(SIGCHLD, &(struct sigaction){.sa_handler = sigreap, 
                                             .sa_flags = SA_NOCLDSTOP}, 
                NULL) < 0) #  B 子进程结束信号
    return 3; 
 
  for (;;)   #死循环
    pause();    #等待
  fprintf(stderr, "Error: infinite loop terminated\n"); #将错误信息打印,并打印提示信息
  return 42; 
} 

由以上我们差不多读懂了,这个玩意很傲娇啊,抢到了pid为1后执行一个等待函数,就死循环等待了。
那么它为啥要抢pid等于1的init进程呢?
先了解一下init进程

描述init进程,它是内核启动的第一个用户级进程。init有许多很重要的任务,比如像启动getty(用于用户登录)、实现运行级别、以及处理孤立进程。

x86和x86-64是Linux作业系统的常用指令集架构。
BIOS/UEFI针对实际的硬件平台执行硬件初始化任务。
由启动程式载入initrd/initramfs,并由启动程式载入Linux核心。
内核将配置系统功能,譬如配置硬件,称为start_kernel(),这会执行大部分系统配置(中断、内存管理、设备和驱动程式初始化等)。然后它分别启动内存管理进程、init进程等在用户空间执行的进程。
Init有特定的运行级别(System V)或目标(Systemd),每个运行级别或目标都是由特定的一组服务(守护进程)组成。
一个典型的桌面环境从X显示管理器开始初始化,X显示管理器显示登入画面,成功登入后由X显示管理器启动桌面环境(如GNOME、KDE)。
关机时,init会结束所有用户空间处理程序。init随后终止,内核自行关闭。

Init是Linux的根进程。进程号为1,它是所有进程的父进程

我们知道pod内的所有容器共用一个namespace(名字空间),就意味着,他们之间pid号是公用的,根据init的意思,给其他容器的pid造了一个爹(一切进程的父进程)出来。它活着还好,init没了,pod就嘎了。
那么这个爹有啥用呢?
站在进程角度,它可以回收僵尸进程。哦哦哦,可以回收僵尸进程啊,真棒(听懂了耶)
算了吧,那我们还是一块说说什么是僵尸进程吧。
书上说:

僵尸进程是已停止运行但是进程表条目依然存在的进程,父进程尚未通过wait系统调用进行检索。僵尸进程无法通过kill命令清除。只能通过父进程wait进行索检。
系统有过多僵尸进程将会占用大量操作系统进程表资源
如果父进程在子进程完成前退出,OS将子进程分配给init进程,init进程就“收养”子进程并成为其父进程。

简单的说,就是pod的其他容器意外退出时候产生的僵尸子进程会被pause容器进行收养,并且wait系统函数回收减少进程表占用
好的第一个功能占用pid 1说完了,那么循环执行pause()暂停函数几个意思?
一个意思,作为pod共享namespace的基础,pod内其他所有容器都是用它的名字空间

namespace即“命名空间”,也称“名称空间” 。是许多编程语言使用的一种代码组织的形式,通过命名空间来分类,区别不同的代码功能,避免不同的代码片段(通常由不同的人协同工作或调用已有的代码片段)同时使用时由于不同代码间变量名相同而造成冲突。

这么说又蒙了,docker这种容器不是有分割名字空间能力吗?要它干啥?
几个问题

你重启docker后,IP变了吗?
重启docker以后你的容器hostname改变还存在吗?
你要运行三个软件作为一个pod,难道运行在一个docker里面吗?以达到在同一名字空间下的目的
那要是一百个软件呢?那还是容器吗?还能体现容器的优越性吗?

我们说的单pod单ip段,单pod单namespace就是靠它来的
它利用暂停的容器,一直占用着属于它pod的namespace,防止应用容器的死亡,导致整个pod资源被释放,给我的感觉就是像火种,不论部落里有啥变化,火种不灭,生生不息。

总结

一共有俩作用
pod的其他容器意外退出时候产生的僵尸子进程会被pause容器进行收养,并且wait系统函数回收减少进程表占用
作为pod共享namespace的基础,pod内其他所有容器都是用它的名字空间

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

(~ ̄▽ ̄)~凤凰涅槃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值