赞
踩
环境:centos7.9 docker-ce-20.10.9 kubernetes-version v1.22.6
在kubernetes的世界中,k8s并不直接处理容器,而是使用多个容器共存的理念,这组容器就叫做pod。
pod是k8s中可以创建和管理的最小单元,是资源对象模型中由用户创建或部署的最小资源对象模型,其他的资源对象都是用来支撑pod对象功能的,比如,pod控制器就是用来管理pod对象的,service或者imgress资源对象是用来暴露pod引用对象的,persistentvolume资源
是用来为pod提供存储等等,简而言之,k8s不会直接处理容器,而是pod,pod才是k8s中可以创建和管理的最小单元,也是基本单元。
1、每个pod就像一个独立的逻辑机器,k8s会为每个pod分配一个集群内部唯一的IP地址,所以每个pod都拥有自己的IP地址、主机名、进程等;
2、一个pod可以包含1个或多个容器,1个容器一般被设计成只运行1个进程,1个pod只可能运行在单个节点上,即不可能1个pod跨节点运行,pod的生命周期是短暂,也就是pod可能随时被消亡(如节点异常,pod异常等情况);
2、每一个pod都有一个特殊的被称为"根容器"的pause容器,也称info容器,pause容器对应的镜像属于k8s平台的一部分,除了pause容器,每个pod还包含一个或多个跑业务相关组件的容器;
3、一个pod中的容器共享network命名空间;
4、一个pod里的多个容器共享pod IP,这就意味着1个pod里面的多个容器的进程所占用的端口不能相同,否则在这个pod里面就会产生端口冲突;既然每个pod都有自己的IP和端口空间,那么对不同的两个pod来说就不可能存在端口冲突;
5、应该将应用程序组织到多个pod中,而每个pod只包含紧密相关的组件或进程;
6、pod是k8s中扩容、缩容的基本单位,也就是说k8s中扩容缩容是针对pod而言而非容器。
pod实现共享网络实现机制:首先pod会创建pause容器,把其他业务容器加入pause容器,
从而让所以业务容器都在同一个命名空间中,这样可是实现网络共享。
pod共享存储实现机制: 引入数据卷volume,使用数据卷进行持久化存储。
一个容器一般被设计运行一个进程,除非进程本身产生子进程,,由于不能将多个进程聚集在同一个单独的容器中,所以需要一种更高级的结构将容器绑定在一起,并将它们作为一个单元进行管理,这就是pod的背后原理。
#注意:kubectl run 在旧版本中创建的是deployment,但在本书的版本中创建的是pod
[root@master ~]# kubectl run nginx --image=nginx:1.7.9 --labels="app=nginx" #创建一个pod,并设置标签为app=httpd
pod/nginx created
[root@master ~]# kubectl get pods -n default #查看pod,已经是运行状态
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 43s
[root@master ~]# kubectl get pod nginx -n default -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 75s 10.244.1.28 node1 <none> <none>
[root@master ~]#
[root@master ~]# kubectl describe pod nginx #使用kubectl describe命令来查看我们刚才创建的pod的详细信息 Name: nginx #pod的名称为nginx Namespace: default #pod的所属命名空间 Priority: 0 #这个参数是优先级,暂时不用管 Node: node1/192.168.118.132 #pod所在节点 Start Time: Mon, 14 Feb 2022 22:40:55 +0800 #pod启动时间 Labels: app=nginx #标签 Annotations: <none> Status: Running #状态 IP: 10.244.1.28 #pod的IP,前面我们介绍pod的时候说过,pod就像一个逻辑机器,有着自己的IP IPs: IP: 10.244.1.28 Containers: #容器部分,一个pod可以跑多个容器 nginx: # Container ID: docker://042179fde4baa7138ac0213bbfb99dd5f02bf915cd91d0ae38982b2bdd30cb9a #容器ID Image: nginx:1.7.9 #镜像 Image ID: docker-pullable://nginx@sha256:e3456c851a152494c3e4ff5fcc26f240206a94affb40e0714846c451 #镜像ID Port: <none> Host Port: <none> State: Running #容器状态 Started: Mon, 14 Feb 2022 22:40:56 +0800 #容器启动时间 Ready: True #是否准备就绪 Restart Count: 0 #重启次数 Environment: <none> Mounts: #容器挂载点 /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-n5gcr (ro) Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: kube-api-access-n5gcr: Type: Projected (a volume that contains injected data from multiple sources) TokenExpirationSeconds: 3607 ConfigMapName: kube-root-ca.crt ConfigMapOptional: <nil> DownwardAPI: true QoS Class: BestEffort Node-Selectors: <none> Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s node.kubernetes.io/unreachable:NoExecute op=Exists for 300s Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 38m default-scheduler Successfully assigned default/nginx to node1 Normal Pulled 38m kubelet Container image "nginx:1.7.9" already present on machine Normal Created 38m kubelet Created container nginx Normal Started 38m kubelet Started container nginx [root@master ~]#
[root@master ~]# kubectl get pod nginx -o yaml apiVersion: v1 kind: Pod metadata: creationTimestamp: "2022-02-14T14:40:55Z" labels: app: nginx name: nginx namespace: default resourceVersion: "488083" uid: dff1bcac-b229-4a5d-803d-d003a4311437 spec: containers: - image: nginx:1.7.9 imagePullPolicy: IfNotPresent name: nginx resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File volumeMounts: - mountPath: /var/run/secrets/kubernetes.io/serviceaccount name: kube-api-access-n5gcr readOnly: true dnsPolicy: ClusterFirst enableServiceLinks: true nodeName: node1 preemptionPolicy: PreemptLowerPriority priority: 0 restartPolicy: Always schedulerName: default-scheduler securityContext: {} serviceAccount: default serviceAccountName: default terminationGracePeriodSeconds: 30 tolerations: - effect: NoExecute key: node.kubernetes.io/not-ready operator: Exists tolerationSeconds: 300 - effect: NoExecute key: node.kubernetes.io/unreachable operator: Exists tolerationSeconds: 300 volumes: - name: kube-api-access-n5gcr projected: defaultMode: 420 sources: - serviceAccountToken: expirationSeconds: 3607 path: token - configMap: items: - key: ca.crt path: ca.crt name: kube-root-ca.crt - downwardAPI: items: - fieldRef: apiVersion: v1 fieldPath: metadata.namespace path: namespace status: conditions: - lastProbeTime: null lastTransitionTime: "2022-02-14T14:40:55Z" status: "True" type: Initialized - lastProbeTime: null lastTransitionTime: "2022-02-14T14:40:57Z" status: "True" type: Ready - lastProbeTime: null lastTransitionTime: "2022-02-14T14:40:57Z" status: "True" type: ContainersReady - lastProbeTime: null lastTransitionTime: "2022-02-14T14:40:55Z" status: "True" type: PodScheduled containerStatuses: - containerID: docker://042179fde4baa7138ac0213bbfb99dd5f02bf915cd91d0ae38982b2bdd30cb9a image: nginx:1.7.9 imageID: docker-pullable://nginx@sha256:e3456c851a152494c3e4ff5fcc26f240206abac0c9d794affb40e0714846c451 lastState: {} name: nginx ready: true restartCount: 0 started: true state: running: startedAt: "2022-02-14T14:40:56Z" hostIP: 192.168.118.132 phase: Running podIP: 10.244.1.28 podIPs: - ip: 10.244.1.28 qosClass: BestEffort startTime: "2022-02-14T14:40:55Z" [root@master ~]#
以上我们创建了一个名为nginx的pod,但是这个pod还不能被外部客户端连接访问,我们还需要做一步,就是对外暴露pod,让外部客户端能访问k8s集群的pod服务,如下所示:
# --port=8088 表示指定集群内部访问端口,--target-port=80表示pod里面容器的应用程序端口 # 节点端口,即客户外部访问端口是自动生成的 [root@master ~]# kubectl expose pod nginx -n default --port=8088 --target-port=80 --type=NodePort --name=nginx service/nginx exposed [root@master ~]# kubectl get pod,svc -n default NAME READY STATUS RESTARTS AGE pod/nginx 1/1 Running 0 2m34s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 11d service/nginx NodePort 10.103.207.241 <none> 8088:30295/TCP 14s #8088为集群内部访问端口,30295为外部访问端口 [root@master ~]# curl http://10.103.207.241:8088 #使用集群内部IP+内部端口8088访问,能成功访问 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> 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> [root@master ~]#
在浏览器访问,任意一个节点的IP+30295端口都能访问到nginx,如下图所示:
如果需要修改外部访问端口或者需要修改一下刚才定义的service,这时我们可以使用kubectl edit 编辑刚才创建的service,如下:
[root@master ~]# kubectl edit service nginx #编辑我们刚才创建的名为nginx的服务 # Please edit the object below. Lines beginning with a '#' will be ignored, # and an empty file will abort the edit. If an error occurs while saving this file will be # reopened with the relevant failures. # apiVersion: v1 kind: Service metadata: creationTimestamp: "2022-02-14T14:43:15Z" labels: app: nginx name: nginx namespace: default resourceVersion: "488275" uid: e935f0c2-3f8b-48a0-b592-eae3332e40b1 spec: clusterIP: 10.103.207.241 clusterIPs: - 10.103.207.241 externalTrafficPolicy: Cluster internalTrafficPolicy: Cluster ipFamilies: - IPv4 ipFamilyPolicy: SingleStack ports: - nodePort: 30005 #修改一下对外暴露的端口为30005,注意:端口是有范围了,不能随便定义 port: 8088 protocol: TCP targetPort: 80 selector: app: nginx sessionAffinity: None type: NodePort status: loadBalancer: {} ~ "/tmp/kubectl-edit-3488312699.yaml" 34L, 785C written service/nginx edited #修改完成之后保存退出,k8s会立即自动应用你做的修改 [root@master ~]# kubectl get pod,svc -n default #查看service,发现外部端口已经改成了30005,浏览器就能使用这个端口来访问了 NAME READY STATUS RESTARTS AGE pod/nginx 1/1 Running 0 26m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 11d service/nginx NodePort 10.103.207.241 <none> 8088:30005/TCP 23m [root@master ~]#
以上我们创建了一个跑nginx服务的pod,也使用service对外暴露了pod,这样外部客户就能访问k8s集群里pod的容器里nginx服务了,但是以上我们创建的pod是不受任何控制的,换句话说就是pod出现异常挂掉了就挂掉了,k8s不会帮你重启pod;在实际的生产环境中,我们并不是直接创建pod,而是创建pod控制器,所谓pod控制器,就是用来管理pod,其具有上线部署、副本设定、滚动升级、回滚等诸多功能。关于pod控制的讲解,我们不在本篇论述。
创建pod,我们一般是通过定义资源清单yaml文件来创建的,下面通过讲解一个完整的pod定义来加深对pod的定义。
[root@master ~]# vim pod-nginx.yaml #创建一个pod资源清单 apiVersion: v1 #资源的api版本 kind: Pod #资源类型 metadata: #定义元数据 name: nginx-pod #pod的名称,必须是小写字母,不能有大写字母 namespase: default #所属命名空间 labels: #标签,可以有多个标签 app: dev annotations: #注解 - name: string spec: containers: #定义容器,可以有多个容器 - name: nginx-container #容器名称 image: nginx:1.18.0 #镜像 imagePullPolicy: [Always|Never|IfNotPresent]#镜像拉取策略,always表示总是从远程拉取,Never 从不拉取,IfNotPresent本地不存在才拉取 command: [string] #容器启动时执行的命令 args: [string] #容器启动时执行的命令参数 workingDir: string volumeMounts: #存储卷的挂载点 - name: string mountPath: string readOnly: boolean ports: #容器的端口 - name: string containerPort: int hostPort: int protocol: string env: #环境变量 - name: string value: string resources: #资源限额 limits: cpu: string memory: string requests: cpu: string memory: string livenessProde: #存活谭政 exec: command: [string] httpGet: path: string port: number host: string scheme: string httpHeaders: - name: string value: string tcpSocket: port: number initialDelaySeconds: 0 timeoutSeconds: 0 periodSeconds: 0 successThreshold: 0 failureThreshold: 0 securityContext: privileged: false restartPolicy: [Always | Never | OnFaulure] nodeSelector: object imagePullSecrets: - name: string hostNetwork: false volumes: #定义存储卷 - name: string emptyDir: {} hostPath: path: string secret: secretName: string items: - key: string path: string configMap: name: string items: - key: string path: string
可以用过在创建pod时使用command字段来指定容器的启动参数,如下:
#创建一个pod,容器运行busybox程序,启动容器就死循环往/tmp/hello.txt写入数据 [root@master ~]# cat pod-busybox.yaml apiVersion: v1 kind: Pod metadata: name: pod-command labels: env: dev namespace: default spec: containers: - image: busybox name: busybox-container command: ["/bin/sh","-c","touch /tmp/hello.txt;while true;do /bin/echo $(date +%T) >> /tmp/hello.txt;sleep 3;done;"] [root@master ~]#kubec apply -f pod-busybox.yaml pod/pod-command created [root@master ~]# kubectl get pod pod-command NAME READY STATUS RESTARTS AGE pod-command 1/1 Running 0 19s [root@master ~]# [root@master ~]# kubectl exec -it pod-command -c busybox-container -- tail -f /tmp/hello.txt 06:47:02 06:47:05
command #容器的启动命令列表,如果不指定,则使用打包时的启动命令
args #容器的启动命令需要的参数列表
特别说明:
通过上面发现command已经可以完成启动命令和传递参数的功能,为什么这里还有提供一个args选项用于传递参数呢?
这其实是跟docker优点关系,kubernetes中的command、args其实是实现覆盖dockerfile中的ENTRYPOINT的功能。
1、如果command和args均没有写,那么使用Dockerfile的配置;
2、如果command写了但args没写,那么Dockerfile默认的配置会被忽略,执行输入的command;
3、如果command没写但args写了,那么Dockerfile中的ENTRYPOINT的会被执行,使用当前args的参数;
4、如果command和args都写了,那么Dockerfile会被忽略,执行输入的command和args。
[root@master ~]# kubectl explain pod.spec.containers.ports
[root@master ~]# vim pod-busybox.yaml #定义容器的端口时主要有5个参数,每个参数的含义如下讲解所示:
........
ports: #设置容器暴露的端口列表,一个容器可以暴露多个端口
- containerPort: 80 #容器的端口(0<x<65536),就是应用程序的端口
hostIP: #将容器公开的端口绑定到指定的主机ip(一般不设置)
hostPort: #容器要在主机上公开的端口(一般不设置)如果设置,主机上只能运行容器的一个副本,因为,如果使用pod控制器创建了2个pod副本,
#那么指定了在主机上公开的端口,两个pod就都会在主机上公开端口,这样就会存在端口冲突问题,所以,该参数一般不会设置。
name: http #端口的名字,如果指定,则该名字必须在pod中是唯一的,为端口指定一个名字,主要是为了方便service与之关联
protocol: tcp #端口的协议,必须是 UDP,TCP,或者SCTP,默认tcp协议
......
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。