Kubernetes 101,第一部分,基础知识
很久以来,我一直想坐下来写一些关于Kubernetes 的文章。现在是时候了。
简而言之,Kubernetes是一个用于自动化和管理容器化应用程序的开源系统。Kubernetes的核心就是容器。
❗如果你不太了解容器是什么,请先阅读我的Docker 101 系列,然后再回来阅读本系列。这样你就能更好地理解 Kubernetes。
免责声明:让我们看看这个“K8s 东西”试图解决的问题。
📦容器管理
假设我们有一个由以下部分组成的复杂系统:
- 用 Ruby 编写的 Backoffice
- 运行 PostgreSQL 的各种数据库
- 用Java编写的报表系统
- 用 Erlang 编写的聊天应用程序
- 用 NodeJS 编写的 Frontoffice
好吧,这个架构相当异构,但它满足了本文的目的。此外,我们在容器中运行所有内容:
假设我们必须确保“前台”应用的最大可用性和可扩展性,因为最终用户会使用它。此时,系统至少需要运行两个前台容器:
此外,还有另一项功能要求,即聊天应用程序不能长时间停机,并且万一发生故障,我们应该确保它能够重新启动,并具有自我修复能力:
现在想象一下我们有几十个甚至几百个容器的架构:
容器管理并不容易,这就是 Kubernetes 的用武之地。
📜 一点历史
在内部运行复杂工作负载 15 年后,谷歌决定公开其之前的容器管理工具“Borg”。
2014年,他们发布了这个工具,并将其命名为“Kubernetes”。该工具开源后,很快就得到了社区的广泛认可。
Kubernetes 是用Golang编写的,最初它只支持 Docker 容器,但后来也支持其他容器运行时,例如containerd 和 CRI-O。
☁️ 云原生计算基金会
2015 年,Linux 基金会创建了一个基础分支,旨在支持在云计算中运行和管理容器的开源项目。
随后,云原生计算基金会(CNCF)成立。
不到一年后, Kubernetes作为第一个 CNCF 毕业项目推出。
目前截至 2023 年,许多公司和大公司都在其基础设施上运行 Kubernetes,例如亚马逊、谷歌、微软、RedHat、VMWare 等等。
Kubernetes 架构
以下是 Kubernetes 架构的简要介绍:
在上面的场景中,我们有一个由“4 台机器”(或现在更常见的虚拟机)组成的 k8s 集群,它们是:
- 1 台称为“控制平面”的机器,集群在其中创建,并负责接受集群上的新机器(或节点)
- 另外 3 台机器称为节点,其中将包含集群管理的所有容器。
👍 经验法则
所有正在运行的容器建立我们所说的集群状态。
在 Kubernetes 中,我们通过向 Kubernetes API 发出 HTTP 请求来声明集群的期望状态,Kubernetes 将“努力”实现期望状态。
然而,为了声明状态而发送简单的 HTTP 请求可能有些繁琐,容易出错,而且很繁琐。不如在命令行中使用 CLI来完成身份验证和发送 HTTP 请求这些繁琐的工作?
认识kubectl。
👤 在集群中创建对象
Kubernetes 将集群中的所有内容视为对象,其中对象可以具有不同的类型(种类)。
$ kubectl run nginx --image=nginx
pod/nginx created
下图描述了这种交互,其中我们使用kubectl
CLI 向控制平面 API 发出请求:
但是你可能会好奇,Pod 是什么? Pod 是我们可以交互的最小对象单元。
Pod 可能像容器,但是Pod 可以包含多个容器。
🔎 架构流程
现在让我们深入研究创建对象的流程,了解集群如何执行pod 调度和状态更新。
这应该是一个简短的架构流程,以便我们可以更好地理解 k8s 架构。
👉 控制平面调度器
控制平面调度程序查找下一个可用节点并将对象/pod调度到该节点。
👉 节点 Kubelet
每个节点都包含一个名为Kubelet的组件,它接受来自 Scheduler 的对象,并使用安装在节点上的容器运行时(可以是 Docker、containerd 等)在节点中创建对象。
👉 etcd
在控制平面中,有一个名为etcd的组件,它是一个分布式键值存储,在分布式系统和机器集群中运行良好。它非常适合 Kubernetes。
K8s 使用 etcd 来持久化并保持当前状态。
✋ Kubernetes 中的一些网络知识
假设集群中有两个 NGINX pod,一个服务器和一个客户端:
$ kubectl run server --image=nginx
pod/server created
$ kubectl run client --image=nginx
pod/client created
假设我们想要访问server
,我们如何访问端口 80 中的这样的 pod?
在容器化应用中,默认情况下,容器是隔离的,不共享主机网络。Pod也是如此。
我们只能在Podlocalhost:80
内部请求server
。那么如何在正在运行的 Pod 中执行命令呢?
$ kubectl exec server -- curl localhost
<html>
...
它可以工作,但只能在 pod 内发出请求。
那么从客户端请求服务器 怎么样?可以吗?可以,因为每个 Pod在集群中都会收到一个内部 IP 。
$ kubectl describe pod server | grep IP
IP: 172.17.0.6
client
现在,我们可以使用服务器内部 IP向服务器发出请求:
$ kubectl exec client -- curl 172.17.0.6
<html>
...
但是,如果我们执行部署,即将旧server
Pod 更改为较新的 Pod,则无法保证新 Pod 将获得相同的先前 IP。
我们需要某种Pod 发现机制,在 Kubernetes 中声明一个特殊的对象,为指定的 Pod 命名。这样,在集群内部,我们就可以通过 Pod 的名称而不是内部 IP 来访问它们了。
这种特殊的对象被称为服务。
👉 控制器管理器
控制平面还使用一个名为Controller Manager 的组件。它负责接收对服务等特殊对象的请求,并通过服务发现将其公开。
我们所要做的就是发布kubectl expose
,然后控制平面就会完成这项工作。
$ kubectl expose pod server --port=80 --target-port=80
service/server exposed
然后我们就可以通过 pod 的名称来访问server
它,而不是通过它的内部 IP:
$ kubectl exec client -- curl server
<html>
...
让我们看看架构流程中发生了什么。首先,命令发出了Service 对象kubectl expose
的创建:
然后,控制器管理器通过服务发现公开 Pod:
之后,控制器管理器会路由到kube-proxy
节点中正在运行的组件,该组件将为相应的 Pod创建 Service 对象。该过程结束时,状态将持久化到 中etcd
。
👉 云控制器
控制平面中存在的另一个控制器是云控制器,负责接收创建对象的请求并在需要时与底层云提供商进行交互。
例如,当我们创建类型的服务对象时LoadBalancer
,云控制器 将在底层提供商(AWS、GCP、Azure 等)中创建一个 LB
💯 最终概述
了解了kubernetes架构之后,我们用一张图来总结一下主要的架构流程:
这篇文章是对 Kubernetes 的介绍以及其主要架构的概述。
我们还了解了一些构建块对象,例如Pod 和服务。
在即将发布的文章中,我们将看到有关 Kubernetes工作负载、配置和网络的更详细的视图。
敬请关注!
文章来源:https://dev.to/leandronsp/kubernetes-101-part-i-the-fundamentals-23a1