0%

k8s教程01-Pod

1. 基础

⼀旦应⽤程序运⾏起来,Kubernetes就会不断地确认应⽤程序的部署状态始终与你提供的描述相匹配。例如,如果你指出你需要运⾏五个web服务器实例,那么Kubernetes总是保持正好运⾏五个实例。如果实例之⼀停⽌了正常⼯作,⽐如当进程崩溃或停⽌响应时,Kubernetes将⾃动重启它。

iShot_2024-01-16_15.27.06

1.1 pod

你或许在想,是否有⼀个列表显⽰所有正在运⾏的容器,可以通过类似于kuberctl get containers的命令获取。这并不是Kubernetes的⼯作,它不直接处理单个容器。相反,它使⽤多个共存容器的理念。这组容器就叫作pod。

每个pod都有⾃⼰的IP,并包含⼀个或多个容器,每个容器都运⾏⼀个应⽤进程。pod分布在不同的⼯作节点上。

image-20240117192744204

⼀个pod的所有容器都运⾏在同⼀个节点上;⼀个pod绝不跨越两个节点。

image-20240117195217153

1.2 创建过程

当运⾏ kubectl 命令时,它通过向Kubernetes API服务器发送⼀个 REST HTTP请求,在集群中创建⼀个新的ReplicationController对象。

ReplicationController创建了⼀个新的pod,调度器将其调度到⼀个⼯作节点上。Kubelet看到pod被调度到节点上,就告知Docker从镜像中⼼中拉取指定的镜像,因为本地没有该镜像。下载镜像后,Docker创建并运⾏容器。

1.3 pod访问

每个pod都有⾃⼰的IP地址,但是这个地址是集群内部的,不能从集群外部访问。要让pod能够从 外 部 访 问 , 需 要 通 过 服 务 对 象 公 开 它 , 要 创 建 ⼀ 个 特 殊 的LoadBalancer 类型的服务。

通过创建LoadBalancer 类型的服务,将创建⼀个外部的负载均衡,可以通过负载均衡的公共IP访问pod。

每个pod都像⼀个独⽴的机器,具有⾃⼰的IP地址和主机名。尽管应⽤程序运⾏在⼯作节点的操作系统中,但对应⽤程序来说,它似乎是在⼀个独⽴的机器上运⾏,⽽这台机器本⾝就是应⽤程序的专⽤机器。

1.4 RC、pod和服务

通过运⾏kubectl run 命令,创建了⼀个ReplicationController,它⽤于创建pod实例。为了使该pod能够从集群外部访问,需要让Kubernetes将该ReplicationController管理的所有pod由⼀个服务对外暴露。

image-20240117193845670

  • ReplicationController

它确保始终存在⼀个运⾏中的pod实例。通常,ReplicationController⽤于复制pod(即创建pod的多个副本)并让它们保持运⾏。⽰例中没有指定需要多少pod副本,所以ReplicationController创建了⼀个副本。如果你的pod因为任何原因消失了,那么ReplicationController将创建⼀个新的pod来替换消失的 pod。

  • 服务

pod的存在是短暂的,⼀个pod可能会在任何时候消失。服务就是解决不断变化的pod IP地址的问题,以及在⼀个固定的IP和端⼜对上对外暴露多个pod。

当⼀个服务被创建时,它会得到⼀个静态的IP,在服务的⽣命周期中这个IP不会发⽣改变。客户端应该通过固定IP地址连接到服务,⽽不是直接连接pod。

服务作为负载均衡挡在多个pod前⾯。当只有⼀个pod时,服务为单个pod提供⼀个静态地址。⽆论服务后⾯是单个pod还是⼀组pod,这些pod在集群内创建、消失,这意味着它们的IP地址会发⽣变化,但服务的地址总是相同的。

1.5 问题

  • 关于为何需要pod这种容器?为何不直接使⽤容器?

由于每⼀个容器都⾮常像⼀台独⽴的机器,此时你可能认为在单个容器中运⾏多个进程是合乎逻辑的,然⽽在实践中这种做法并不合理。

容器被设计为每个容器只运⾏⼀个进程(除⾮进程本⾝产⽣⼦进程)。如果在单个容器中运⾏多个不相关的进程,那么保持所有进程运⾏、管理它们的⽇志等将会是我们的责任。

  • 为何多个容器⽐单个容器中包含多个进程要好?

由于不能将多个进程聚集在⼀个单独的容器中,我们需要另⼀种更⾼级的结构来将容器绑定在⼀起,并将它们作为⼀个单元进⾏管理,这就是pod背后的根本原理。

在包含容器的pod下,我们可以同时运⾏⼀些密切相关的进程,并为它们提供(⼏乎)相同的环境,此时这些进程就好像全部运⾏于单个容器中⼀样,同时又保持着⼀定的隔离。这样⼀来,我们便能全⾯地利⽤容器所提供的特性,同时对这些进程来说它们就像运⾏在⼀起⼀样,实现两全其美。

  • 同⼀pod中容器之间的部分隔离

Kubernetes通过配置Docker来让⼀个pod内的所有容器共享相同的Linux命名空间,⽽不是每个容器都有⾃⼰的⼀组命名空间。

由于⼀个pod中的所有容器都在相同的network和UTS命名空间下运⾏(在这⾥我们讨论的是Linux命名空间),所以它们都共享相同的主机名和⽹络接口。同样地,这些容器也都在相同的IPC命名空间下运⾏,因此能够通过IPC进⾏通信。

这⾥需强调的⼀点是,由于⼀个pod中的容器运⾏于相同的 Network命名空间中,因此它们共享相同的IP地址和端口空间。这意味着在同⼀pod中的容器运⾏的多个进程需要注意不能绑定到相同的端口号,否则会导致端口冲突,但这只涉及同⼀pod中的容器。

此外,⼀个pod中的所有容器也都具有相同的loopback⽹络接口,因此容器可以通过localhost与同⼀pod中的其他容器进⾏通信。

2. 设计

2.1 pod之间访问

Kubernetes集群中的所有pod都在同⼀个共享⽹络地址空间中,这意味着每个pod都可以通过其他pod的IP地址来实现相互访问。换句话说,这也表⽰它们之间没有NAT(⽹络地址转换)⽹关。

pod之间的通信其实是⾮常简单的。不论是将两个pod安排在单⼀的还是不同的⼯作节点上,同时不管实际节点间的⽹络拓扑结构如何,这些pod内的容器都能够像在⽆NAT的平坦⽹络中⼀样相互通信,就像局域⽹(LAN)上的计算机⼀样。

2.2 将多层应⽤分散到多个pod中

虽然我们可以在单个pod中同时运⾏前端服务器和数据库这两个容器,但这种⽅式并不值得推荐。前⾯我们已经讨论过,同⼀pod的所有容器总是运⾏在⼀起,但对于Web服务器和数据库来说,它们真的需要在同⼀台计算机上运⾏吗?答案显然是否定的,它们不应该被放到同⼀个pod中。那假如你⾮要把它们放在⼀起,有错吗?某种程度上来说,是的。

pod也是扩缩容的基本单位,对于Kubernetes来说,它不能横向扩缩单个容器,只能扩缩整个pod。这意味着如果你的pod由⼀个前端和⼀个后端容器组成,那么当你扩⼤pod的实例数量时,⽐如扩⼤为两个,最终会得到两个前端容器和两个后端容器。

将多个容器添加到单个pod的主要原因是应⽤可能由⼀个主进程和⼀个或多个辅助进程组成。例如sidecar容器的其他例⼦包括⽇志轮转器和收集器、数据处理器、通信适配器等。

image-20240117204009601

2.3 将本地⽹络端⼜转发到pod中的端口

如果想要在不通过service的情况下与某个特定的pod进⾏通信(出于调试或其他原因),Kubernetes将允许我们配置端⼜转发到该pod。可以通过kubectl port-forward命令完成上述操作。例如以下命令会将机器的本地端⼜8888转发到我们的kubia-manual pod的端⼜8080:

1
kubectl port-forward kubia-manual 8888:8080

在另⼀个终端中,通过运⾏在localhost:8888上的kubectl portforward代理,可以使⽤curl 命令向pod发送⼀个HTTP请求:

1
curl localhost:8888

image-20240117205145410

给作者打赏,可以加首页微信,咨询作者相关问题!