Pod 是 Kubernetes 应用程序的基本执行单元,即它是 Kubernetes 对象模型中创建或部署的最小和最简单的单元。Pod 表示在 集群 上运行的进程。
Pod 封装了应用程序容器(或者在某些情况下封装多个容器)、存储资源、唯一网络 IP 以及控制容器应该如何运行的选项。
Kubernetes 集群中的 Pod 可被用于以下两个主要用途:
运行单个容器的 Pod。"每个 Pod 一个容器"模型是最常见的 Kubernetes 用例;在这种情况下,可以将 Pod 看作单个容器的包装器,并且 Kubernetes 直接管理 Pod,而不是容器。
运行多个协同工作的容器的 Pod。 Pod 可能封装由多个紧密耦合且需要共享资源的共处容器组成的应用程序。 这些位于同一位置的容器可能形成单个内聚的服务单元 —— 一个容器将文件从共享卷提供给公众,而另一个单独的“挂斗”(sidecar)容器则刷新或更新这些文件。 Pod 将这些容器和存储资源打包为一个可管理的实体。
Pod 为其组成容器提供了两种共享资源:网络 和 存储。
网络
每个 Pod 分配一个唯一的 IP 地址。 Pod 中的每个容器共享网络命名空间,包括 IP 地址和网络端口。 Pod 内的容器 可以使用 localhost 互相通信。 当 Pod 中的容器与 Pod 之外 的实体通信时,它们必须协调如何使用共享的网络资源(例如端口)。
存储
一个 Pod 可以指定一组共享存储卷 。 Pod 中的所有容器都可以访问共享卷,允许这些容器共享数据。 卷还允许 Pod 中的持久数据保留下来,以防其中的容器需要重新启动。
在k8s的每个结点上都有这样一个镜像:
[root@server4 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
reg.caoaoyuan.org/library/pause 3.2 80d28bedfe5d 4 months ago 683kB
//这是k8s为pod准备的跟镜像,每个pod通过它来启动,它为pod准备了启动的环境(网路,卷)。
pod在运行容器之前,会先运行一个或多个init初始化容器,他们一次进行,他们运行完,应用容器才会进行启动。
初始化容器结束后,普通的容器(main container)开始运行,普通容器的启动和停止通过探针来检测,探针有存活探针和就绪探针,不指定的话默认为成功,liveness探针用来进行存活检测,看容器是否正常的运行着。readness用来检测容器服务是否就绪.
[root@server2 manifest]# kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-5fd54d7f56-k5jb9 1/1 Running 3 7d8h
coredns-5fd54d7f56-xb5m4 1/1 Running 4 7d19h
etcd-server2 1/1 Running 7 7d23h
存活探针检测成功才会时running的状态,就绪检测通过才会时ready的状态,用户才可以访问,才可以有流量进来。
更多详情参考:https://kubernetes.io/zh/docs/concepts/workloads/pods/init-containers/
[root@server2 manifest]# vim init.yml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
initContainers:
- name: init-myservice
image: busybox:latest
command: ['sh', '-c', "until nslookup myservice.default.svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
- name: init-mydb
image: busybox:latest
command: ['sh', '-c', "until nslookup mydb.default.svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
containers:
- name: myapp-container
image: busybox:latest
~
“until nslookup myservice.default.svc.cluster.local; do echo waiting for myservice; sleep 2; done”]
的意思是,执行nslookup指令解析myservice.default.svc.cluster.local
这个地址,如果解析成功则继续,不成功则一直处于初始化状态,循环do里面的内容。
[root@server2 manifest]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
myapp-pod 0/2 Init:0/1 0 5s
//正在进行初始化容器,但是卡在这里了,一直在进行init
Init Containers:
init-myservice:
Container ID: docker://3b83c7896675f49dab5b8c103e52b5f5e4b62bf6ce6d3659267267ebddc0978e
Image: busyboxplus
Image ID: docker-pullable://busyboxplus@sha256:9d1c242c1fd588a1b8ec4461d33a9ba08071f0cc5bb2d50d4ca49e430014ab06
Port: <none>
Host Port: <none>
Command:
sh
-c
until nslookup myservice.default.svc.cluster.local; do echo waiting for myservice; sleep 2; done
State: Running //一直在运行
Started: Fri, 26 Jun 2020 18:56:21 +0800
Ready: False
但是当前这个容器时无法运行的,因为没有创建myservice这个服务,不能完成解析。
注意要关闭外网,不然会通过主机的dns解析出去。
为两个初始化容器创建服务:
[root@server2 manifest]# vim service.yml
kind: Service
apiVersion: v1
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
---
kind: Service
apiVersion: v1
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
[root@server2 manifest]# kubectl apply -f service.yml
service/myservice created
service/mydb created
[root@server2 manifest]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8d
mydb ClusterIP 10.100.111.80 <none> 80/TCP 7s
myservice ClusterIP 10.107.87.62 <none> 80/TCP 7s
[root@server2 manifest]# kubectl get pod -w //再次查看
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:1/2 0 9s
myapp-pod 0/1 PodInitializing 0 13s //pod初始化
myapp-pod 1/1 Running 0 52s //就运行了
此时我们在关闭service,这个容器也不会在受影响了,因为init时运行在容器之前的,运行完就结束了。不会在对后面的容器产生影响了。
进入到应用容器的运行后,接下来我们就可以去布置探针了。用来检测服务和运行状态了。
startupProbe
存在时就会忽略
上面的存活探针
和就绪探针
,所以我们只对存活探针和就绪探针进行实验.
[root@server2 manifest]# vim init.yml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
initContainers:
- name: init-myservice
image: busyboxplus
command: ['sh', '-c', "until nslookup myservice.default.svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
containers:
- name: myapp-container
image: myapp:v1
imagePullPolicy: IfNotPresent
livenessProbe: //存活探针
tcpSocket:
port: 80 //检测80端口,打开则正常运行
initialDelaySeconds: 1 //容器开启后延迟1秒
periodSeconds: 2 //每2秒检测一次
timeoutSeconds: 1 //超时
[root@server2 manifest]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 443/TCP 8d
myservice ClusterIP 10.99.245.243 80/TCP 15h //我们的svc开启着
[root@server2 manifest]# kubectl apply -f init.yml
pod/myapp-pod created
[root@server2 manifest]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 PodInitializing 0 4s
myapp-pod 1/1 Running 0 4s
[root@server2 manifest]# kubectl exec -it myapp-pod -- sh
/ # nginx -s stop //进入同期内部,关闭nginx服务
2020/06/27 02:51:21 [notice] 12#12: signal process started
/ # command terminated with exit code 137
[root@server2 manifest]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 1 3m42s //自动重启了。
[root@server2 manifest]# kubectl describe pod myapp-pod
Liveness: tcp-socket :80 delay=1s timeout=1s period=2s #success=1 #failure=3 //成功检测一次,失败检测三次
存活探针和容器的生命周期保持一直,会不断的进行容器的存活检测,当检测到端口关闭的时候,会让kubelet 去重启这个容器,但是前提时重启策略不是Never。
此时我们的service无法识别pod的ip地址,只是做了一个解析,我们应该:
kind: Service
apiVersion: v1
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
selector: //加上选择器,选择我们的pod的标签加入到service的服务中
app: myapp //service就是作一个端口的暴露
[root@server2 manifest]# kubectl apply -f service.yml
service/myservice created
[root@server2 manifest]# kubectl describe svc myservice
Name: myservice
Namespace: default
Labels: <none>
Annotations: Selector: app=myapp
Type: ClusterIP
IP: 10.100.34.244
Port: <unset> 80/TCP
TargetPort: 9376/TCP
Endpoints: 10.244.1.60:9376 //pod的资源就到了service上了,这是在就绪探针完成的状态下,
Session Affinity: None
Events: <none>
[root@server2 manifest]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp-pod 1/1 Running 1 22m 10.244.1.60 server3 <none> <none>
上面我们只加了存活探针,就绪探针不加的话是默认成功,所以我们才能看到pod的ip加到svc上,可以访问。下面我们加上就绪探针进行检测。
[root@server2 manifest]# vim init.yml
...
livenessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 1
periodSeconds: 2
timeoutSeconds: 1
readinessProbe: //把就绪探针加进去
httpGet:
path: /hostname.html //让它检测这个页面
port: 80 //和80端口
initialDelaySeconds: 1
periodSeconds: 2
timeoutSeconds: 1
[root@server2 manifest]# kubectl apply -f init.yml
pod/myapp-pod created
[root@server2 manifest]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 2m9s
//当前的ready状态是正常的,因为检测的两个东西都正常
[root@server2 manifest]# kubectl exec -it myapp-pod -- sh //做一些更改
/ # vi /etc/nginx/conf.d/default.conf
#location = /hostname.html {
# alias /etc/hostname; //注释掉着两行
#}
/ # nginx -s reload
2020/06/27 03:23:53 [notice] 23#23: signal process started
/ # ps ax
PID USER TIME COMMAND
1 root 0:00 nginx: master process nginx -g daemon off;
14 root 0:00 sh
24 nginx 0:00 nginx: worker process
25 root 0:00 ps ax
/ # [root@server2 manifest]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Running 0 6m50s //容器运行,但是没准备好
//就绪状态就关闭了,因为就绪探针生效,它找不到 path: /hostname.html 这个路径了。
[root@server2 manifest]# kubectl describe svc myservice
Name: myservice
Namespace: default
Labels:
Annotations: Selector: app=myapp
Type: ClusterIP
IP: 10.100.34.244
Port: 80/TCP
TargetPort: 9376/TCP
Endpoints: //就不会把pod的地址接入到这里了。
[root@server2 manifest]# kubectl exec -it myapp-pod -- sh
/ # vi /etc/nginx/conf.d/default.conf //我们在进入容器打开哪几个参数
/ # nginx -s reload
2020/06/27 04:03:16 [notice] 32#32: signal process started
/ # [root@server2 manifest]# kubectl describe svc myservice
Name: myservice
Namespace: default
Labels:
Annotations: Selector: app=myapp
Type: ClusterIP
IP: 10.100.34.244
Port: 80/TCP
TargetPort: 9376/TCP
Endpoints: 10.244.1.61:9376 //加近来了
Session Affinity: None
Events:
[root@server2 manifest]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 46m
[root@server2 manifest]# kubectl run demo --image=busyboxplus -it --restart=Never
cuelIf you don't see a command prompt, try pressing enter.
/ # curl 10.102.77.37
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
// 然后通过svc的ip地址就可以访问容器了,svc通过标签把容器的接入近来。
我们在多加一个pod:
[root@server2 manifest]# vim pod2.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-example
spec:
replicas: 2 //有两个副本
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp //设置标签相同。
spec:
containers:
- name: nginx
image: myapp:v2 //使用v2镜像
[root@server2 manifest]# kubectl apply -f pod2.yml
kubec deployment.apps/deployment-example created
[root@server2 manifest]# kubectl get pod
NAME READY STATUS RESTARTS AGE
demo 0/1 Completed 0 10m
deployment-example-5c9fb4c54c-4f9dj 1/1 Running 0 5s
deployment-example-5c9fb4c54c-pnfzb 1/1 Running 0 5s
myapp-pod 1/1 Running 0 64m
[root@server2 manifest]# kubectl describe svc myservice
Name: myservice
Namespace: default
Labels: <none>
Annotations: Selector: app=myapp
Type: ClusterIP
IP: 10.102.77.37
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.1.61:80,10.244.2.36:80,10.244.2.37:80 //把新开的两个容器页加进去了
Session Affinity: None
Events: <none>
这样我们就可以做负载均衡了。
[root@server2 manifest]# kubectl run demo --image=busyboxplus -it --restart=Never
If you don't see a command prompt, try pressing enter.
/ # curl 10.102.77.37
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
/ # curl 10.102.77.37
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
/ # curl 10.102.77.37
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
/ # curl 10.102.77.37
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
/ # curl 10.102.77.37
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
/ # curl 10.102.77.37
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
/ # curl 10.102.77.37
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>