Kubernetes Pod对象和初始化容器(InitContainer)以及变量详解;

文章目录

  • 前言
  • 一、Pod介绍、存在意义,设计模式
    • 1.Pod的基本概念
    • 2.Pod存在的意义
    • 3.Pod资源共享实现机制
  • 二、环境变量
    • 1.将容器信息注入为环境变量 【内置变量】
    • 2.将容器资源信息注入为环境变量【内置变量】
    • 3.自定义变量
  • 三、Init Container
    • 1.init container概念
    • 2.应用场景
    • 3.init container用法(一)
    • 4.init container用法(二)


前言

提示:这里可以添加本文要记录的大概内容:


提示:以下是本篇文章正文内容,下面案例可供参考

一、Pod介绍、存在意义,设计模式

1.Pod的基本概念

Pod是一个逻辑抽象的概念,Kubernetes创建和管理的最小单元(容器的集合),一个Pod由一个容器或多个容器组成;

Pod特点:

  • 一个Pod可以理解为是一个应用的实例,提供服务;
  • Pod中容器始终部署在一个Node上;
  • Pod中容器共享网络、存储资源

Kubernetes Pod对象和初始化容器(InitContainer)以及变量详解;_第1张图片
如上图:这个豌豆就如同是一个Pod,里面的豌豆仁就相当于Pod里面的容器(可以有两个也可以有多个),它们之间共享网络、存储资源,就类似于这些豌豆仁共享外面的这一个豌豆荚来汲取外界营养一样;一个pod的只运行在一个节点上,不管pod里面有多少个容器都只在一个物理机上运行,就类似于一个豌豆只能在一个藤上一样(这个藤代表的就是物理节点)

2.Pod存在的意义

Pod主要用法(为什么要引入pod的概念):

  • 运行单个容器:最常见的用法,一个pod里面运行一个容器,可以将Pod看做是一个容器的抽象封装;
  • 运行多个容器:属于边车模式(Sidecar),通过在Pod中定义专门的容器来执行主业务容器需要的辅助工作,这样的好处是将辅助功能同主业务容器解耦,实现独立发布和能力重用;
    例如:
      - 日志收集
      - 应用监控

Kubernetes Pod对象和初始化容器(InitContainer)以及变量详解;_第2张图片
边车容器类似于生活中的三轮摩托,通过在原有的摩托车基础上增加一个边车模式来进行扩展现有的服务和功能;

3.Pod资源共享实现机制

 上面说到了pod中可以运行多容器(边车容器),例如启动一个辅助容器来进行日志采集或者对主业务容器进行监控,那么pod中的容器资源共享是怎么实现的,需要解决什么问题:

共享网络(如何通过本地回环地址连接对方):
Kubernetes Pod对象和初始化容器(InitContainer)以及变量详解;_第3张图片
 Pod会将业务(应用)容器网络加入到“负责Pod网络的容器(infra容器)实现网络共享”;
 其实Pod始终就一个IP,它不会为每个容器都分配不同的IP,这个IP就绑定在Infra容器上,那么同一组Pod内的其它容器也想使用这个网络的话只需要加入到这个共享里就行,这样一来不管是在容器1还是在容器2看到的IP都是一模一样的,这同一组Pod中的多个容器就相当于在一台机器上起了两个进程一样,这样两个进程就可以通过127.0.0.1看到对方;在pod中假如容器1监听的端口是80,那么正常情况下容器2是肯定是看不到的容器1上面的80 因为网络也是隔离的,这时如果两个容器共享了网络共享网络协议栈的话,那么容器2就可以看到容器1了 从而实现网络共享


示例一:
创建一个名叫pod1的pod,里面包含两个容器,一个是web(主容器nginx) 一个是test(测试容器busybox)

[root@k8s-master ~]# kubectl run pod1 --image=nginx -o yaml --dry-run=client > pod.yaml
[root@k8s-master ~]# vim pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: pod1
  name: pod1
spec:
  containers:
  - image: nginx #主容器
    name: web
  - image: busybox #辅助容器
    name: test
    command: ['/bin/sh','-c','sleep 24h']
[root@k8s-master ~]# kubectl apply -f pod.yaml 
pod/pod1 created
[root@k8s-master ~]# kubectl get pod -o wide 
NAME   READY   STATUS    RESTARTS   AGE   IP             NODE        NOMINATED NODE   READINESS GATES
pod1   2/2     Running   0          20h   10.244.36.65   k8s-node1   <none>           <none>

进入test容器后我们查看一下现有的进程(辅助容器是没有任何进程的)

[root@k8s-master ~]# kubectl exec -it pod/pod1 -c test sh  #-c 在pod中有多个容器的话,可以使用-c 容器名 指定进入某个容器
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # ps -ef  
PID   USER     TIME  COMMAND
    1 root      0:00 sleep 24h
    7 root      0:00 sh
   30 root      0:00 sh
   40 root      0:00 ps -ef

接下来我们查看下辅助容器监听的端口,会发现有一个80的监听,但是通过ps查看进程的时候却没有发现有进程;

/ # netstat -anptl 
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      -
tcp        0      0 :::80                   :::*                    LISTEN      -

然后这时我们访问下这个80端口 可以发现是主容器nginx的页面内容

/ # wget 127.0.0.1:80 #因为没有curl所以这里直接使用wget了
Connecting to 127.0.0.1:80 (127.0.0.1:80)
saving to 'index.html'
index.html           100% |*************************************************************************************************************************|   615  0:00:00 ETA
'index.html' saved
/ # cat index.html 
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
/ # 

到这里我们就会发现这个辅助容器里是没有nginx这个进程的,但是他可以访问到web容器里的nginx,所以也就证明了同一组pod中的容器是共享网络协议栈的,直接通过本地回环地址即可访问到对方;

接下来我们去这个web容器修改下nginx的index.html页面再次验证这个辅助容器test是否访问的就是 web主容器nginx;
修改web主容器nginx的index.html页面

[root@k8s-master ~]# kubectl exec -it pod/pod1 -c web  sh 
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
# echo "hello fandaoshuai-nginx" > /usr/share/nginx/html/index.html
# exit 

切换到test辅助容器再次访问本地监听的80端口

[root@k8s-master ~]# kubectl exec -it pod/pod1 -c test sh 
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # wget 127.0.0.1:80
Connecting to 127.0.0.1:80 (127.0.0.1:80)
saving to 'index.html'
index.html           100% |*************************************************************************************************************************|    24  0:00:00 ETA
'index.html' saved
/ # cat index.html 
hello fandaoshuai-nginx

这也就验证了通过127.0.0.1能访问到nginx容器里面的80,同一个pod中多个容器是共享的;

实例二:
还有一种验证方法,通过Infra container去验证,infra container其实是背后的容器,通过kubectl工具是看不到的,查看方法为

先查看这个pod1被分配到哪个节点上了

[root@k8s-master ~]# kubectl get pod -o wide 
NAME   READY   STATUS    RESTARTS   AGE   IP             NODE        NOMINATED NODE   READINESS GATES
pod1   2/2     Running   0          22h   10.244.36.65   k8s-node1   <none>           <none>

可以看到被分配到了node1节点上,然后我们再到node1节点上去查看有没有这个容器

[root@k8s-node1 ~]# docker ps | grep pod1
be6926eee3c5   busybox                                              "/bin/sh -c 'sleep 2…"   22 hours ago   Up 22 hours             k8s_test_pod1_default_eb03ef25-d675-498e-a42d-1e06cc439686_0
5f869b6d515d   nginx                                                "/docker-entrypoint.…"   22 hours ago   Up 22 hours             k8s_web_pod1_default_eb03ef25-d675-498e-a42d-1e06cc439686_0
7cb508fdaba6   registry.aliyuncs.com/google_containers/pause:3.2    "/pause"                 22 hours ago   Up 22 hours             k8s_POD_pod1_default_eb03ef25-d675-498e-a42d-1e06cc439686_0

我们可以看到现在关于pod1的有三个容器,一个是web(nginx) 一个是test(busybox)容器,还有一个是pause容器,这个pause容器就是infra容器,它是pod起的一个容器然后主要来维护网络命名空间(简单来说就是负责管理pod网络的容器) 其它容器都可以加入到这个容器中来,实现网络的互连互通,不管在k8s里创建什么样的pod都会,始终每创建一个pod都会创建一个这样的pod;
Kubernetes Pod对象和初始化容器(InitContainer)以及变量详解;_第4张图片
上面这张图里都是负责pod网络的infra容器,所以不管是上面样的pod都会有一个infra容器来伴随着;

共享存储(如何实现容器之间的文件共享):
Kubernetes Pod对象和初始化容器(InitContainer)以及变量详解;_第5张图片
容器通过数据卷共享数据,将多个容器都挂在到volume里实现类似共享存储的功能,这样容器就都能读取到对方的文件和操作;

实例:
定义一个数据卷(volumes)logs,并使主容器和辅助容器都挂载(volumeMounts)这同一个数据卷;

[root@k8s-master ~]# vim pod2.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: pod2
  name: pod2
spec:
  containers:
  - image: nginx #主容器
    name: web
    volumeMounts:
    - name: logs
      mountPath: /usr/share/nginx/html
  - image: busybox #辅助容器
    name: test
    command: ['/bin/sh','-c','sleep 24h']
    volumeMounts: #数据卷挂载
    - name: logs #指定挂载的数据卷名称
      mountPath: /data #数据卷挂载到容器中的路径
  volumes:  #定义数据卷
  - name: logs  #数据卷名称
    emptyDir: {}  #数据卷类型

[root@k8s-master ~]# kubectl apply -f pod2.yaml 
pod/pod2 created
[root@k8s-master ~]# kubectl get pod 
NAME                    READY   STATUS    RESTARTS   AGE
pod2                    2/2     Running   0          3m26s

此时在主容器web的挂载数据卷的目录里(上面为/usr/share/nginx/html)创建一个文件,那么在辅助容器test里是可以看到这个文件的,因为他们已经实现了共享;同理,在辅助容器test里创建的文件,在主容器web里是一样可以看到的。

验证1:
去主容器web的挂载数据卷的目录(共享目录)上创建一个a.txt文件
[root@k8s-master ~]# kubectl exec -it pods/pod2 -c web sh 
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
# cd /usr/share/nginx/html
# echo "123" > a.txt
# cat a.txt
123

此时去辅助容器test的挂载数据卷的目录(共享目录)上看是否能查看到此文件
[root@k8s-master ~]# kubectl exec -it pods/pod2 -c test sh 
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # ls /data/
a.txt
/ # cat /data/a.txt 
123
发现是可以看到这个a.txt文件的,
证明多容器之间的挂载同一个数据卷就可以实现数据共享,解决文件之间的交互;
验证2:
在辅助容器test的挂载数据卷的目录(共享目录)上创建一个b.html文件
[root@k8s-master ~]# kubectl exec -it pods/pod2 -c test sh 
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # touch /data/b.html
/ # ls /data/
a.txt   b.html

此时去主容器web的挂载数据卷的目录(共享目录)上看是否能查看到此文件
[root@k8s-master ~]# kubectl exec -it pods/pod2 -c web sh 
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
# cd /usr/share/nginx/html
# ls 
a.txt  b.html
发现是可以看到这个b.html文件的,
证明多容器之间的挂载同一个数据卷就可以实现数据共享,解决文件之间的交互;

二、环境变量

创建Pod时,可以为其下的容器设置环境变量;

应用场景:

  • 容器内应用程序希望获取Pod信息;
  • 容器内应用程序希望通过用户定义的变量改变默认行为;

变量值的几种定义行为:

  • 自定义变量值;
  • 变量值从Pod属性获取;
  • 变量值从Secert、ConfigMap获取;

1.将容器信息注入为环境变量 【内置变量】

将容器的信息注入为环境变量【内置变量的值都来自于获取pod的自身属性并注入到容器中】
Kubernetes Pod对象和初始化容器(InitContainer)以及变量详解;_第6张图片

apiVersion: v1
kind: Pod
metadata:
  name: "pod1"
  namespace: default
  labels:
    app: "pod1"
spec:
  containers:
  - name: pod1
    image: "nginx:latest"
    #k8s内置变量的值都来自于获取pod的自身属性并注入到容器中(可以通过kubectl get pod名称 [-n 命名空间] -o yaml 来查看)
    env:
      #获取pod所在的节点名称
      - name: MY_NODE_NAME
        valueFrom:
          fieldRef:
            fieldPath: spec.nodeName
      #获取pod名称
      - name: MY_POD_NAME
        valueFrom:
          fieldRef:
            fieldPath: metadata.name
      #获取pod所在的命名空间
      - name: MY_POD_NAMESPACE
        valueFrom:
          fieldRef:
            fieldPath: metadata.namespace
      #获取pod的IP
      - name: MY_POD_IP
        valueFrom:
          fieldRef:
            fieldPath: status.podIP
      #获取pod的ServiceAccountName
      - name: MY_POD_SERVICE_ACCOUNT
        valueFrom:
          fieldRef:
            fieldPath: spec.serviceAccountName

然后启动pod进入容器使用env命令查看pod的变量

[root@k8s-master ~]# kubectl apply -f pod1.yaml 
[root@k8s-master ~]# kubectl exec -it pod/pod1 bash 
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
#查看k8s内置的pod变量
root@pod1:/# env | grep MY_
MY_NODE_NAME=k8s-node1
MY_POD_NAMESPACE=default
MY_POD_IP=10.244.36.97
MY_POD_SERVICE_ACCOUNT=default
MY_POD_NAME=pod1

2.将容器资源信息注入为环境变量【内置变量】

将容器资源信息注入为环境变量【内置变量的值都来自于获取pod的自身属性并注入到容器中】

apiVersion: v1
kind: Pod
metadata:
  name: "pod3"
  namespace: default
  labels:
    app: "pod3"
spec:
  containers:
  - name: pod3
    image: "nginx:latest"
    #资源限制
    #资源限制
    resources:
      requests:
        memory: "32Mi"
        cpu: "125m"
      limits:
        memory: "64Mi"
        cpu: "250m"
    env:
      - name: MY_CPU_REQUEST
        valueFrom:
          resourceFieldRef:
            containerName: pod3
            resource: requests.cpu
      - name: MY_CPU_LIMIT
        valueFrom:
          resourceFieldRef:
            containerName: pod3
            resource: limits.cpu
      - name: MY_MEM_REQUEST
        valueFrom:
          resourceFieldRef:
            containerName: pod3
            resource: requests.memory
      - name: MY_MEM_LIMIT
        valueFrom:
          resourceFieldRef:
            containerName: pod3
            resource: limits.memory

然后启动pod进入容器使用env命令查看pod的资源变量

[root@k8s-master ~]# kubectl exec -it pod/pod3 bash 
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@pod3:/# env |grep MY_
MY_MEM_REQUEST=33554432
MY_CPU_REQUEST=1
MY_CPU_LIMIT=1
MY_MEM_LIMIT=67108864

3.自定义变量

apiVersion: v1
kind: Pod
metadata:
  name: "pod2"
  namespace: default
  labels:
    app: "pod2"
spec:
  containers:
  - name: pod2
    image: "nginx:latest"
    env:
      - name: ABC #自定义变量的名称
        value: "123456" #自定义变量的值
      - name: CDE 
        value: "789jqk"

然后启动pod进入容器使用env命令查看pod的自定义变量

[root@k8s-master ~]# kubectl exec -it pod/pod2 bash 
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@pod2:/# env | grep ABC
ABC=123456
root@pod2:/# echo $ABC
123456
root@pod2:/# env | grep DEF
DEF=789jqk
root@pod2:/# echo $DEF
789jqk

三、Init Container

1.init container概念

用于初始化工作,执行完就结束,不是持续运行的,可以理解为一次性任务。

  • 支持大部分应用容器配置,但不支持健康检查(因为不是持续运行的);
  • 优先于应用容器执行;

2.应用场景

  • 环境检查:例如确保应用容器依赖的服务启动后再启动应用容器;
  • 初始化配置:例如给应用容器准备配置文件 或者下载其它依赖、代码等;
    Kubernetes Pod对象和初始化容器(InitContainer)以及变量详解;_第7张图片
    辅助容器(边车模式)和初始化容器(init container模式)都是为了主容器实现节藕,动态的帮助主容器添加一些功能,方便后期的管理和维护;

3.init container用法(一)

示例:部署一个web网站,网站程序没有打到镜像中,而是希望从代码仓库中动态拉取放到应用容器中;
yam如下:
k8s init container测试前端项目 这个链接是我在yaml中git clone的前端项目,大家要是没有自己前端项目可以使用我这个来实验,或直接使用下面k8s官方提供的的wget方式练习;

apiVersion: v1
kind: Pod
metadata:
  name: "pod7"
  namespace: default
  labels:
    app: "pod7"
spec:
  initContainers:
  - name: init-git
    image: "nginx:1.24.0"
    #更新软件包以及下载git并clone代码
    command: ["/bin/sh"]
    args: ["-c", "apt-get update; apt-get install git -y; git clone https://github.com/fandaoshuai777/k8s-init-container.git /opt"]
    volumeMounts:
    - name: workdir
      mountPath: /opt
  containers:
  - name: pod7
    image: "nginx:latest"
    volumeMounts:
    - name: workdir
      mountPath: /usr/share/nginx/html
  volumes:
  - name: workdir
    emptyDir: {}

(1).运行此yaml并kubectl get pod [-n 命名空间] -w 实时查看pod状态

[root@k8s-master ~]# kubectl get pod  -w 
NAME                   READY   STATUS        RESTARTS   AGE
pod7                   0/1     Init:0/1      0          8s
pod7                   0/1     Init:0/1      0          19s
pod7                   0/1     PodInitializing   0          15m

pod7                   1/1     Running           0          15m
可以看到是先运行的初始化容器Init

另外可以使用 kubectl logs -f pod名 -c 初始化的容器名 [-n 命名空间] 来查看初始化容器的日志
Kubernetes Pod对象和初始化容器(InitContainer)以及变量详解;_第8张图片

(2).pod启动后,可以curl一下pod的index.html,我这里代码的index.html是在nginx/html/dist目录下,所以在访问的时候应该是url/dist/index.html
在这里插入图片描述
浏览器访问效果如下,大家可以通过service的NodePort暴露端口来访问
Kubernetes Pod对象和初始化容器(InitContainer)以及变量详解;_第9张图片

4.init container用法(二)

如果没有代码仓库的话可以找个网站然后使用wget下载它的web页面;
例如官网的例子:
https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/configure-pod-initialization/
Kubernetes Pod对象和初始化容器(InitContainer)以及变量详解;_第10张图片
运行并访问结果如下
Kubernetes Pod对象和初始化容器(InitContainer)以及变量详解;_第11张图片
注:因此,Pod中会有这几种类型的容器:

  • Infrastructure Container:基础容器
    用途:负责维护整个Pod网络空间;

  • InitContainers:初始化容器
    用途:先于业务容器开始执行(主要做一些业务容器的初始化工作,例如启动主容器之前的一些前置、依赖工作),再执行业务容器;

  • Containers:业务容器
    用途:并行启动,无论container下有多少个容器,都是并行启动的,例 边车容器也是在Container下定义的,它属于container的一种工作模式,并不是一个独立类型的容器;


你可能感兴趣的:(Kubernetes学习分享;,kubernetes,容器,docker)