容器最初是一个 Linux 内核进程隔离结构,其中包含 2007 年的 cgroups[4] 和 2002 年的 namespaces[5](命名空间)。当 LXC[6] 在 2008 年可用时,容器变得越来越重要,而 Google 开发了自己的内部“在容器中运行所有机制”系统,称为 Borg[7]。快进到 2013 年,Docker 正式发布,并完全面向大众。当时,Mesos[8] 是编排容器的主要工具,但并未得到广泛采用。Kubernetes 于 2015 年发布,并迅速成为事实上的容器编排标准。
为了尝试了解 Kubernetes 的受欢迎程度,请考虑一些问题。开发人员最后一次可以在何时达成部署生产应用程序的方式?您知道有多少开发人员开箱即用地运行工具?如今有多少云运营工程师不了解应用程序如何工作?我们将在本文中探讨答案。
以数据(YAML)为基础的的架构
来自 Puppet[9] 和 Chef[10] 的世界,Kubernetes 的重大转变之一就是从以代码为基础的基础架构过渡到以数据为基础的基础架构(特别是 YAML)。Kubernetes 中的所有资源,包括 Pod,配置,部署,卷等,都可以简单地在 YAML 文件中表示。
- apiVersion: v1
- kind: Pod
- metadata:
- name: site
- labels:
- app: web
- spec:
- containers:
- - name: front-end
- image: nginx
- ports:
- - containerPort: 80
这种表示形式使 DevOps 或站点可靠性工程师可以更轻松地完全表达其工作负载,而无需使用 Python,Ruby 或 Javascript 等编程语言编写代码。
以数据为基础的架构的其他好处包括:
- GitOps 或 Git Operations 版本控制。使用这种方法,您可以将所有 Kubernetes YAML 文件保留在 git 存储库下,这使您可以准确地知道何时进行更改,由谁进行更改以及究竟进行了哪些更改。这样可以避免整个组织需要成员去寻找可能模棱两可的内容,从而提高了整个组织的透明度并提高了效率。同时,通过合并请求,可以更轻松地自动更改 Kubernetes 资源。
- 可扩展性。将资源定义为 YAML,使集群运营商可以非常轻松地更改 Kubernetes 资源中的一个或两个数字来更改缩放行为。Kubernetes 具有水平 Pod 自动缩放器,可帮助您确定特定部署必须能够处理的最小和最大数量的 Pod,才能处理低流量和高流量时间。例如,如果您运行的部署可能由于流量突然增加而可能需要更多容量,则可以将 maxReplicas 从 10 更改为 20:
- apiVersion: autoscaling/v2beta2
- kind: HorizontalPodAutoscaler
- metadata:
- name: myapp
- namespace: default
- spec:
- scaleTargetRef:
- apiVersion: apps/v1
- kind: Deployment
- name: myapp-deployment
- minReplicas: 1
- maxReplicas: 20
- metrics:
- - type: Resource
- resource:
- name: cpu
- target:
- type: Utilization
- averageUtilization: 50
- 安全和控制。YAML 是验证在 Kubernetes 中部署什么以及如何部署的好方法。例如,有关安全性的主要问题之一是您的工作负载是否以非 root 用户身份运行。我们可以使用 conftest[11](一种 YAML /JSON 验证器)之类的工具以及Open Policy Agent[12](一种策略验证器)来检查您的工作负载的 SecurityContext[13] 是否允许容器作为 root 运行。为此,用户可以使用一个简单的开放策略代理重新注册策略,如下所示:
- package main
- deny[msg] {
- input.kind = "Deployment"
- not input.spec.template.spec.securityContext.runAsNonRoot = true
- msg = "Containers must not run as root"
- }
- 云提供商集成。科技行业的主要趋势之一是在公有云提供商中运行工作负载。借助云提供商组件,Kubernetes 允许每个群集与其运行的云提供商进行集成。例如,如果用户正在 AWS 的 Kubernetes 中运行某个应用程序,并且希望通过服务访问该应用程序,则云提供商将帮助自动创建 LoadBalancer 服务,该服务将自动设置 Amazon Elastic Load Balancer 来将流量转发给应用程序 pods。
可扩展性
Kubernetes 具有很好的可扩展性,开发人员对此非常满意。内置一些资源,例如 Pod,Deployment,StatefulSet,Secrets,ConfigMap 等。同时用户和开发人员可以通过“自定义资源定义[14]”添加更多资源。例如,如果我们想定义 CronTab 资源,则可以使用以下方法来做到这一点:
- apiVersion: apiextensions.k8s.io/v1
- kind: CustomResourceDefinition
- metadata:
- name: crontabs.my.org
- spec:
- group: my.org
- versions:
- - name: v1
- served: true
- storage: true
- Schema:
- openAPIV3Schema:
- type: object
- properties:
- spec:
- type: object
- properties:
- cronSpec:
- type: string
- pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$'
- replicas:
- type: integer
- minimum: 1
- maximum: 10
- scope: Namespaced
- names:
- plural: crontabs
- singular: crontab
- kind: CronTab
- shortNames:
- - ct
我们可以稍后使用以下内容创建 CronTab 资源:
- apiVersion: "my.org/v1"
- kind: CronTab
- metadata:
- name: my-cron-object
- spec:
- cronSpec: "* * * * */5"
- image: my-cron-image
- replicas: 5
Kubernetes 可扩展性的另一种形式是开发人员编写自己的 Operators[15] 的能力,Operator 是在 Kubernetes 集群中运行的,遵循 control loop pattern[16] 的特定进程。操作员允许用户通过与 Kubernetes API 进行对话来自动管理 CRD(自定义资源定义)。
该社区有几种工具,允许开发人员创建自己的 Operators。这些工具之一是 Operator Framework[17] 及其 Operator SDK[18]。SDK 为开发人员提供了一个框架,使他们可以快速开始创建 operator。例如,您可以从命令行[19]输入以下命令开始:
- $ operator-sdk new my-operator --repo github.com/myuser/my-operator
它将为您的 operator 创建整个样板,包括 YAML 文件和 Go 代码:
- .
- |____cmd
- | |____manager
- | | |____main.go
- |____go.mod
- |____deploy
- | |____role.yaml
- | |____role_binding.yaml
- | |____service_account.yaml
- | |____operator.yaml
- |____tools.go
- |____go.sum
- |____.gitignore
- |____version
- | |____version.go
- |____build
- | |____bin
- | | |____user_setup
- | | |____entrypoint
- | |____Dockerfile
- |____pkg
- | |____apis
- | | |____apis.go
- | |____controller
- | | |____controller.go
然后,您可以添加 API 和类似的控制器:
- $ operator-sdk add api --api-version=myapp.com/v1alpha1 --kind=MyAppService
- $ operator-sdk add controller --api-version=myapp.com/v1alpha1 --kind=MyAppService
最后构建并将 operator 推送到您的容器注册表:
- $ operator-sdk build your.container.registry/youruser/myapp-operator
如果开发人员需要更多控制权,则可以修改 Go 文件中的样板代码。例如,要修改控制器的详细信息,他们可以对 controller.go 文件进行更改。
另一个项目 KUDO[20] 允许您仅使用声明性 YAML 文件来创建运算符。例如,Apache Kafka 的运算符将定义为以下内容[21],它允许用户使用以下命令在 Kubernetes 上安装 Kafka 集群:
- $ kubectl kudo install zookeeper
- $ kubectl kudo install kafka
然后还使用另一个命令对其进行调整:
- $ kubectl kudo install kafka --instance=my-kafka-name \
- -p ZOOKEEPER_URI=zk-zookeeper-0.zk-hs:2181 \
- -p ZOOKEEPER_PATH=/my-path -p BROKER_CPUS=3000m \
- -p BROKER_COUNT=5 -p BROKER_MEM=4096m \
- -p DISK_SIZE=40Gi -p MIN_INSYNC_REPLICAS=3 \
- -p NUM_NETWORK_THREADS=10 -p NUM_IO_THREADS=20
革新
在过去的几年中,Kubernetes 每三四个月发布一次主要版本,这意味着每年都有三到四个主要版本。推出的新功能的数量并未减慢,最新版本[22]的 30 多种新增功能和更改证明了这一点。此外,Kubernetes 项目 GitHub 活动表明[23],即使在这些困难时期,贡献也没有放缓的迹象。
这些新功能使集群运营商在运行各种不同的工作负载时具有更大的灵活性。软件工程师还喜欢拥有更多控件,以将其应用程序直接部署到生产环境中。
社区
Kubernetes 受欢迎的另一个重要方面是其强大的社区。首先,Kubernetes 在 2015 年发布 1.0 版本时捐赠给了一个与供应商无关的家庭:Cloud Native Computing Foundation[24]。
随着项目的推进,针对 Kubernetes 中的不同区域还有各种各样的社区 SIG[25](特殊兴趣小组)。他们不断添加新功能,并使其对用户更加友好。
Cloud Native Foundation 还组织了 CloudNativeCon/KubeCon,截至撰写本文时,CloudNativeCon/KubeCon 是世界上比较大的开源活动。该活动通常每年举行三届,吸引了数千名希望改善 Kubernetes 及其生态系统以及利用每三个月发布的新功能的技术人员和专业人士。
此外,Cloud Native Foundation 拥有一个技术监督委员会[26],与 SIGs[27] 一起,研究基金会在云原生生态系统中的新项目和现有项目[28]。大多数项目都有助于增强 Kubernetes 的价值主张。
最后,我相信,如果没有社区的有意识的努力来互相包容并欢迎任何新来者,Kubernetes 就不会取得成功。
未来
开发人员未来面临的主要挑战之一是如何将更多的精力放在代码的细节上,而不是代码运行所在的基础结构上。为此,无服务器[29]正在成为应对这一挑战的领先架构范例之一。已经有非常高级的框架,例如 Knative[30] 和 OpenFaas[31],它们使用 Kubernetes 从开发人员那里提取基础架构。
我们在本文中对 Kubernetes 进行了简要介绍,但这只是冰山一角。用户可以利用更多资源,功能和配置。我们将持续看到可增强或发展 Kubernetes 的新开源项目和技术,正如我们所提到的,贡献和社区无处不在。