提示:这里可以添加本文要记录的大概内容:
提示:以下是本篇文章正文内容,下面案例可供参考
Pod是一个逻辑抽象的概念,Kubernetes创建和管理的最小单元(容器的集合),一个Pod由一个容器或多个容器组成;
Pod特点:
如上图:这个豌豆就如同是一个Pod,里面的豌豆仁就相当于Pod里面的容器(可以有两个也可以有多个),它们之间共享网络、存储资源,就类似于这些豌豆仁共享外面的这一个豌豆荚来汲取外界营养一样;一个pod的只运行在一个节点上,不管pod里面有多少个容器都只在一个物理机上运行,就类似于一个豌豆只能在一个藤上一样(这个藤代表的就是物理节点)
Pod主要用法(为什么要引入pod的概念):
边车容器类似于生活中的三轮摩托,通过在原有的摩托车基础上增加一个边车模式来进行扩展现有的服务和功能;
上面说到了pod中可以运行多容器(边车容器),例如启动一个辅助容器来进行日志采集或者对主业务容器进行监控,那么pod中的容器资源共享是怎么实现的,需要解决什么问题:
共享网络(如何通过本地回环地址连接对方):
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;
上面这张图里都是负责pod网络的infra容器,所以不管是上面样的pod都会有一个infra容器来伴随着;
共享存储(如何实现容器之间的文件共享):
容器通过数据卷共享数据,将多个容器都挂在到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的自身属性并注入到容器中】
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
将容器资源信息
注入为环境变量【内置变量的值都来自于获取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
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模式)都是为了主容器实现节藕,动态的帮助主容器添加一些功能,方便后期的管理和维护;
示例:部署一个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 命名空间]
来查看初始化容器的日志
(2).pod启动后,可以curl一下pod的index.html,我这里代码的index.html是在nginx/html/dist目录下,所以在访问的时候应该是url/dist/index.html
浏览器访问效果如下,大家可以通过service的NodePort暴露端口来访问
如果没有代码仓库的话可以找个网站然后使用wget下载它的web页面;
例如官网的例子:
https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/configure-pod-initialization/
运行并访问结果如下
注:因此,Pod中会有这几种类型的容器:
Infrastructure Container
:基础容器
用途:负责维护整个Pod网络空间;
InitContainers
:初始化容器
用途:先于业务容器开始执行(主要做一些业务容器的初始化工作,例如启动主容器之前的一些前置、依赖工作
),再执行业务容器;
Containers
:业务容器
用途:并行启动,无论container下有多少个容器,都是并行启动的,例 边车容器也是在Container下定义的,它属于container的一种工作模式
,并不是一个独立类型的容器;