Kubernetes

kubernetes如何运行和管理container?

该系列是我正在学习和实践的一系列教程。内容源于《Learn Kubernetes in a Month of Lunches》作者是ELTON STONEMAN,非常不错的一本书。

问题:既然docker里有了容器,为什么kubernetes还要在container之上再封装一个抽象层,并且叫pod?

a 动手创建pod,并查看pod的信息
#创建pod:kubectl run hello-kiamol --image=kiamol/ch02-hello-kiamol --restart=Never
#hello-kiamol是这个pod的名字,后面指定这个pod里运行的container的镜像,--resstart=Nerver,表示只创建这个pod,不创建其它相关的resources。
[root@master-node ~]# kubectl run hello-kiamol --image=kiamol/ch02-hello-kiamol --restart=Never
pod/hello-kiamol created
[root@master-node ~]#
#查看所有pod:kubectl get pods
#The Ready column lists the number of containers in the Pod and the number that are currently ready. This pod has a single container.
[root@master-node ~]# kubectl get pods
NAME           READY   STATUS   RESTARTS   AGE
hello-kiamol   1/1     Running   0         47s
[root@master-node ~]#
#查看pod的详细信息:查看单独的pod,它的IP,它所运行在的弄的,它的container信息等;
[root@master-node ~]# kubectl describe pod hello-kiamol
Name:         hello-kiamol
Namespace:   default
Priority:     0
Node:         node-2/172.16.11.161
Start Time:   Fri, 07 Jan 2022 17:27:49 +0800
Labels:       run=hello-kiamol
Annotations: <none>
Status:       Running
IP:           10.244.2.2
IPs:
IP:  10.244.2.2
Containers:
....
Events:
Type   Reason     Age   From               Message
 ----    ------     ----   ----               -------
Normal Scheduled 5m25s default-scheduler Successfully assigned default/hello-kiamol to node-2
Normal Pulling   5m24s kubelet           Pulling image "kiamol/ch02-hello-kiamol"
Normal Pulled     5m21s kubelet           Successfully pulled image "kiamol/ch02-hello-kiamol" in 3.726178887s
Normal Created   5m21s kubelet           Created container hello-kiamol
Normal Started   5m20s kubelet           Started container hello-kiamol
[root@master-node ~]#
#从上,可以看到名为hello-kiamol的pod,它的IP是10.244.2.2,它运行在kubernetes的节点2上,node-2/172.16.11.161,等等其它详细信息。

需要注意的是:kubernetes自身不去运行和管理container,它依赖CRI,即container Runtime interface去执行容器。通常是Docker或者是其它的容器运行环境。这就是为什么kubernetes搞出1个pod的概念,kubernetes会管理pod,而把container交给CRI。That’s why the Pod is an abstraction: it’s the resource that Kubernetes manages, whereas the container is managed by something outside of Kubernetes.

b 查看定制化输出数据列的pod
#kubectl get pod hello-kiamol --output custom-columns=NAME:metadata.name,NODE_IP:status.hostIP,POD_IP:status.podIP
[root@master-node ~]# kubectl get pod hello-kiamol --output custom-columns=NAME:metadata.name,NODE_IP:status.hostIP,POD_IP:status.podIP
NAME           NODE_IP         POD_IP
hello-kiamol   172.16.11.161   10.244.2.2
[root@master-node ~]#

可以看到名为hello-kiamol的pod运行在172.16.11.161节点上,pod的IP是10.244.2.2。

c 查看运行在pod中的container id
#kubectl get pod hello-kiamol -o jsonpath='{.status.containerStatuses[0].containerID}'
[root@master-node ~]# kubectl get pod hello-kiamol -o jsonpath='{.status.containerStatuses[0].containerID}'
docker://8b7704f62e36bc4745c9921e4744a8403951a8f09ea8136150f4a9c778e1766f
[root@master-node ~]#

说明:JSONPath is an alternative output format that supports complex queries. This query fetches the ID of the first container in the Pod. There is only one in this case, but there could be many, and the first index is zero.

这个container信息,可以从它所运行的node上看到相关信息,比如到172.16.11.161机器:

[root@node-2 ~]# hostname -i
172.16.11.161
[root@node-2 ~]# ll /var/lib/docker/containers/8b7704f62e36bc4745c9921e4744a8403951a8f09ea8136150f4a9c778e1766f/
总用量 12
drwx------ 2 root root    6 1月   7 17:27 checkpoints
-rw-r--r-- 1 root root 4745 1月   7 17:27 config.v2.json
-rw-r--r-- 1 root root 1723 1月   7 17:27 hostconfig.json
drwxr-xr-x 4 root root   39 1月   7 17:27 secrets
[root@node-2 ~]# docker ps|grep 8b77
8b7704f62e36       docker.io/kiamol/ch02-hello-kiamol@sha256:b89be17a3a64294c4e76c1d43b5e2bfa81a256f9dc6d61e8e153feafe9690b99   "/docker-entrypoin..."   18 hours ago       Up 18 hours                             k8s_hello-kiamol_hello-kiamol_default_25a3f3ba-55e3-42b9-bd8c-f9e8e5c4b17d_0
[root@node-2 ~]#

注意:Kubernetes does not run containers—the container ID in the Pod is a reference to another system that runs containers.

当创建pod时,有master来指定该pod运行在哪个node上,然后运行在pod中的container交给pod所在node的CRI去处理container的管理和维护。

d 手工杀死这个container

https://kubernetes.io/docs/tutorials/hello-minikube/

环境是单节点,master和node在同一个节点上,可以验证该场景:

#到node-2节点上,即运行这个container容器的节点上执行:
[root@node-2 ~]# hostname -i
172.16.11.161
[root@node-2 ~]# docker container ls -q --filter label=io.kubernetes.container.name=hello-kiamol
8b7704f62e36
[root@node-2 ~]#
#然后到,主节点上,执行,
[root@master-node ~]# kubectl get pods
NAME           READY   STATUS     RESTARTS   AGE
hello-kiamol   0/1     Completed   0         20h
[root@master-node ~]#
#此时,看到该pod里的container已经被杀死,pod没有能力重新拉起该container。如果,master和worker node在同一个机器上,则可以看到,如果手工杀死container之后,pod会自动重新拉起container。

#####利用minikube平台来执行:https://kubernetes.io/docs/tutorials/hello-minikube/
$ kubectl run hello-kiamol --image=kiamol/ch02-hello-kiamol --restart=Never
pod/hello-kiamol created
$ kubectl get pods
NAME           READY   STATUS   RESTARTS   AGE
hello-kiamol   1/1     Running   0         8m16s
$ kubectl get pod hello-kiamol --output custom-columns=NAME:metadata.name,NODE_IP:status.hostIP,POD_IP:status.podIP
NAME           NODE_IP       POD_IP
hello-kiamol   172.17.0.14   172.18.0.6
$ docker container ls -q --filter label=io.kubernetes.container.name=hello-kiamol
0cf31030afc6
$ docker container rm -f $(docker container ls -q --filter label=io.kubernetes.container.name=hello-kiamol)
0cf31030afc6
$ docker container ls -q --filter label=io.kubernetes.container.name=hello-kiamol
b35a3a95f212
$
##此时,我们可以看到,手工杀死container之后,pod会自动拉起一个新的container起来。从container的新id可以看出来。
#也就是说,kubernetes立即响应,发现pod的desired state是至少1个container,current它是zero container,于是,k8s赶紧修复这个pod,并使之返回到一个正确的状态。

It’s the abstraction from containers to Pods that lets Kubernetes repair issues like this. A failed container is a temporary fault; the Pod still exists, and the Pod can be brought back up to spec with a new container. This is just one level of self-healing that Kubernetes provides, with further abstractions on top of Pods giving your apps even more resilience.

对于docker container ls -q –filter label=io.kubernetes.container.name=hello-kiamol命令的解释:由于kubernetes把pod的name的label打到container上了,所以,我们可以用pod的name作为过滤标签,去获取container的id信息。

e 如何通过node来访问pod

截止到现在,这个pod里的container是一个web应用,我们还不能直接去访问它。但是,我们可以通过kubernetes设置pod的流量转发,进而可以访问这个pod里运行的文本应用。

#重新运行pod
[root@master-node ~]# kubectl delete pod --all
pod "hello-kiamol" deleted
[root@master-node ~]# kubectl run hello-kiamol --image=kiamol/ch02-hello-kiamol --restart=Never
pod/hello-kiamol created
[root@master-node ~]# kubectl get pods
NAME           READY   STATUS   RESTARTS   AGE
hello-kiamol   1/1     Running   0         7s
[root@master-node ~]#
#设置转发
[root@master-node ~]# kubectl port-forward pod/hello-kiamol 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80

#然后,新开1个session,来访问运行在本机上8080端口的服务,其实相当于是访问名为hello-kiamol这个pod里的80端口的服务。此时,可以看到,hello-kiamol依然是运行在172.16.11.161节点上,但是这个pod的IP是10.244.2.3。
[root@master-node ~]# kubectl get pod hello-kiamol --output custom-columns=NAME:metadata.name,NODE_IP:status.hostIP,POD_IP:status.podIP
NAME           NODE_IP         POD_IP
hello-kiamol   172.16.11.161   10.244.2.3
[root@master-node ~]# curl localhost:8080
<html>
<body>
  <h1>
    Hello from Chapter 2!
  </h1>
  <h2>
    This is
    <a
       href="https://www.manning.com/books/learn-kubernetes-in-a-month-of-lunches"
      >Learn Kubernetes in a Month of Lunches</a
    >.
  </h2>
  <h3>By <a href="https://blog.sixeyed.com">Elton Stoneman</a>.</h3>
</body>
</html>
[root@master-node ~]#

说明:kubectl port-forward pod/hello-kiamol 8080:80这条命令指的是,kubernetes把对本机的8080端口的请求,转发到名为hello-kiamol的pod的80端口。Port forwarding is a feature of kubectl. It starts listening for traffic on your local machine and sends it to the Pod running in the cluster.

f 小结

截止到现在:

  • 我们已经手工创建了1个pod:kubectl run hello-kiamol –image=kiamol/ch02-hello-kiamol –restart=Never
  • 查看所有pod信息:kubectl get pods
  • 查看指定pod的详细信息:kubectl describe pod hello-kiamol
  • 定制化查看pod IP和其运行的node的IP:kubectl get pod hello-kiamol –output custom-columns=NAME:metadata.name,NODE_IP:status.hostIP,POD_IP:status.podIP
  • 定制化查看运行在pod中的container id:kubectl get pod hello-kiamol -o jsonpath='{.status.containerStatuses[0].containerID}’
  • 通过pod name这个label作为过滤条件,去获取运行在该pod里的container的id:docker container ls -q –filter label=io.kubernetes.container.name=hello-kiamol
  • 验证了,通过手工杀死运行在pod里的container时,kubernetes会自动把我们的pod重新拉回到正常状态(重启pod中的那个container):docker container rm -f $(docker container ls -q –filter label=io.kubernetes.container.name=hello-kiamol)
  • 通过设置端口转发,将访问node上的请求,转发到运行在pod里的container上:kubectl port-forward pod/hello-kiamol 8080:80
  • 在kubernetes里,我们不需要也不应该直接去创建和管理pod;
  • pod是对container的上层封装,这种封装是有其意义的,比如,如果杀掉该pod中的container,那么kubernetes会接管并重启运行在这个pod中的container;

留言