软件开发架构师

如何搭建可用于生产环境的Kubernetes基础设施?

架构 65 2019-12-24 13:17


 
作者 | Joe Duffy
译者 | 平川
策划 | 田晓旭
11 月 14 日,我们发布了 Pulumi Crosswalk for Kubernetes,其中包括开源工具、库和使用手册,帮助开发人员和操作人员一起将 Kubernetes 引入他们的组织。这其中囊括了过去一年,我们与组织合作从零开始为他们的基础设施和应用程序工作负载引入 Kubernetes 的经验教训。我们希望通过以开源的方式发布这些内容,帮助企业在 Kubernetes 项目中获得成功。
1 如何将基础设施即代码用于 Kubernetes

一年多前,我们启动了使用 Pulumi 的开源基础设施即代码工具来管理 Kubernetes 资源的支持。除了 Helm 、Charts 的整个生态系统之外,你可以在自己选择的语言中使用所有受支持版本的全部 Kubernetes 对象模型——包括 JavaScript、TypeScript 和 Python。这为新发布的 Kubernetes 版本提供了 100% 的 API 资源兼容和当日支持。

通过利用通用语言,你可以获得丰富的功能,如 for 循环、函数和类、共享和重用最佳实践的能力(消除复制和粘贴),以及使用你喜欢的工具(包括编辑器、测试框架和静态分析工具)。

这对于我们中任何一个与“YAML 或 JSON 之墙”作斗争的人来说都是令人兴奋的——但这还不是全部。

统一的基础设施即代码方法提供了健壮的交付工作流,不仅支持跨 Kubernetes 资源管理配置,还支持跨任何集群的底层公有或私有云基础设施,包括 AWS、Azure、Google Cloud、vSphere 等。

当时,我们没有意识到这种统一的方法会有多么强大。例如,正确地配置一个 Amazon EKS 集群不仅需要在 AWS 上编排部署,还需要来回使用 Kubernetes 资源。我们设计了 Pulumi,让你可以使用一个一致的平台和工作流来完成这项工作,从而取代了通常需要集成多个工具的“大量 Bash”。

这是一个令人兴奋的开始,我们有许多终端用户和组织,他们很快就找上门来,在我们的帮助下采用 Kubernetes。

2 为什么在生产环境中使用 Kubernetes 很困难

下面是我们面临的以及我们努力帮助解决的挑战:

  • Kubernetes 基础设施不是一座孤岛。尽管 AWS、Azure 和 GCP 提供了托管的 Kubernetes 服务,但是大多数拥有成熟基础设施的组织发现很难配置和管理集群基础设施。这通常是因为要投入生产应用,就需要将集群连接到许多周围的基础设施——包括 IAM、网络、加密服务、私有 Docker 注册中心等等。特定于 kubernets 的工具只能帮助解决部分问题并且会创建筒仓。

  • 赋能整个组织非常困难。 大多数采用 Kubernetes 的组织都试图协调“房子的两边”——开发人员和运营人员。基础设施运营团队负责管理集群和底层基础设施,而开发人员则尝试向集群交付应用程序和服务(通常还使用其他公共云服务,如对象存储)。尽管 Kubernetes 的体系结构非常适合这一点,但是团队很难在基础设施和应用程序交付方面标准化工具、工作流和实践。

  • 第二阶段比第一阶段更难。 许多团队决定在 Kubernetes 上“全力以赴”,结果却发现,保护、扩展和实施 Kubernetes 比他们想象的要复杂得多。你可以执行零停机升级吗?如何在区域之间执行故障转移?将新的容器镜像从 dev 提升到 staging,再提升到数十个生产集群的速度有多快?

更复杂的是,这些挑战会因为你的目标云环境而有所不同。尽管 Kubernetes 帮助你标准化了容器计算层,以及扩展负载均衡服务,但是它并没有抽象出云之间的所有基础设施功能,比如 IAM、容器注册中心和数据服务。

在过去的一年中,我们与许多客户有过这样的直接接触。我们致力于为客户开发三个特定领域的全套解决方案:

  • 基础设施操作手册

  • 使 Kubernetes 更便于开发人员使用

  • 现大规模交付和可观测性洞察

接下来让我们逐条说明。

3 开发集群基础设施操作手册

大多数实践者只能自己去寻找 Kubernetes 基础设施中最困难的问题的解决方案。在帮助数十个客户使用 AWS EKS、Azure AKS、谷歌 Cloud GKE 和 Kubernetes 内部基础设施进行生产之后,我们决定将最佳实践开发成一套操作手册。这有助于组织避免重复劳动,以及减少安全、可靠性和可维护性方面的潜在缺陷。

这些操作手册涵盖了许多领域,比如包括下面这样的主题:

  • 控制平面。每个 Kubernetes 集群都有一个由控制器、状态管理和其他集中服务组成的控制平面。每个提供商都提供了创建、部署和管理控制平面的独有方法。

  • 工作节点。每个集群还需要工作节点来实际运行计算。根据你的计算、存储和安全需求,这些节点(通常使用多个节点池)的配置和管理有很大的不同。正确处理这一问题对于在成本和性能之间取得良好的平衡至关重要。

  • 身份标识。所有这些还需要与团队的安全策略集成,包括身份和访问管理(IAM)以及基于角色的访问控制(RBAC)。如果你在 AWS 上,你无疑想要连接到 AWS IAM;如果你在 Azure 中,你想利用现有的 ActiveDirectory 设置;如果你在 GCP 中,你会想要使用 GCP IAM;如果你使用的是自定义配置,那就更复杂了。这是在组织内部署 Kubernetes 的一个重要部分。

  • 集群服务。每个集群都需要部署到集群中的集群范围内的服务,包括性能和监视服务(AWS CloudWatch、Azure 日志分析和监视、Datadog、Prometheus 等)、服务网格、容器注册中心、CRD 和操作人员。

  • 应用程序交付。应用程序需要进行容器化、打包并部署到私有容器注册中心,然后部署到集群,通常是连续不断的。

  • 应用程序服务。除了应用程序本身之外,云原生应用程序通常还需要额外的服务。这包括进入控制器、DNS 和证书管理服务等。升级集群。最后,同样重要的是,集群升级是整个操作的重要组成部分。Kubernetes 发展很快,所以经常需要升级,但是要自信地部署升级并不总是很容易,特别是当你要考虑零停机和持久化工作负载时。

这种层次结构如下图所示:

我们相信,任何希望在任何公有云中甚或是本地创建可生产使用的基础设施的人,都将受益于这份资料。它也是开源的,所以我们希望在未来几周内与社区合作来改进和完善它。

4 开发人员如何使用 Kubernetes

除了必须翻过 YAML 这堵墙之外,还需要重复进行大量惯用的 Kubernetes 配置。事实上,它常常让人感觉手工编写 Kubernetes YAML 类似于用汇编语言编写软件,而不是用高级语言。

Pulumi 公开了全部的 Kubernetes API,这意味着你可以使用现代语言实践来驯服这些低级的混乱。但是,在 Crosswalk 中提供的新的库结构通过消除常见的样板模式将这一问题提升到了另一个层次。

例如,YAML 这堵墙:

apiVersion: v1
kind: ConfigMap
data:
  config: very important data
metadata:
  name: app-config
---
apiVersion: v1
kind: Secret
data:
  app-password: JikkMz9mK2hIRDo3
  database-password: Y29uZmlnLmRhdGFiYXNlUGFzc3dvcmQ=
metadata:
  name: app-secrets
type: Opaque
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - env:
            - name: APP_CONFIG_PATH
              value: /app/config
            - name: APP_USER
              value: config.user
            - name: APP_PASSWORD
              valueFrom:
                secretKeyRef:
                  key: app-password
                  name: app-secrets
            - name: APP_DATABASE_PASSWORD
              valueFrom:
                secretKeyRef:
                  key: database-password
                  name: app-secrets
          image: nginx
          imagePullPolicy: Always
          name: nginx
          ports:
            - containerPort: 80
              name: http
          volumeMounts:
            - mountPath: /app/config
              name: app-config-rsg88x4g
      restartPolicy: Always
      volumes:
        - configMap:
            name: app-config
          name: app-config
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  ports:
    - name: http
      port: 80
      targetPort: 80
  selector:
    app: nginx
  type: LoadBalancer
 

提炼出它的精髓,少了许多繁琐和重复:

// 定义应用程序配置和秘密
const configs = new kx.ConfigMap("app-config", {
    data: { "config": "very important data" }
});
const secrets = new kx.Secret("app-secrets", {
    stringData: {
        "app-password": new kx.RandomPassword("app-password"),
        "database-password": config.databasePassword
    }
});
// 定义应用程序 Pod.
const appConfigPath = "/app/config";
const appPod = new kx.PodBuilder({
    containers: [{
        image: "app:1.0.0",
        env: {
            "APP_CONFIG_PATH": appConfigPath,
            "APP_USER": config.user,
            "APP_PASSWORD": secrets.asEnvValue("app-password"),
            "APP_DATABASE_PASSWORD": secrets.asEnvValue("database-password"),
        },
        volumeMounts: [
            configs.mount(appConfigPath)
        ],
    }],
});
// 使用之前的 Pod 定义创建一个 Kubernetes 部署
const deployment = new kx.Deployment("nginx", {
    spec: appPod.asDeploymentSpec({ replicas: 3 }),
});
// 使用 Kubernetes Service 通过负载均衡器暴露部署
const service = deployment.createService({
    type: kx.types.ServiceType.LoadBalancer,
});



这些库扩展被设计为与现有的 Kubernetes 配置共存,这样你就可以逐渐减少复杂性,而结果仍然是熟悉且完整统一的。除了以这些方式使 Kubernetes 配置更容易访问之外,我们还看到了应用程序配置的其他好处,这包括:

  • 数据服务。 对于我们许多人来说,在 Kubernetes 中管理持续的工作负载是不值得的。虽然可以管理污染、移除和迁移的复杂过程,但我们的许多客户都依赖于托管的数据存储产品——比如 Amazon S3、RDS、Azure Cosmos DB 或谷歌的 Cloud BigTable——以及 Kubernetes 无状态计算。使用托管服务带来了扩展、备份和管理等固有的优点,而且不会很麻烦。Pulumi 允许你混合使用 Kubernetes 和公有云基础设施即代码。

  • 容器注册。 大多数最终用户需要使用私有容器注册中心来承载应用程序镜像。此外,我们大多数人都希望使用云提供商的原生产品,比如 Amazon 弹性容器注册中心、Azure 容器注册中心或谷歌容器注册中心,因为它集成了 IAM。使用 Pulumi,与支持应用程序基础设施相比,你不需要单独的容器部署管道。

  • 无服务器。 如果你想要使用最好且最经济的无服务器功能,那么你可能想要使用 AWS Lambda、Azure 函数或谷歌云函数。我们看到终端用户一直在使用无服务器扩展增强基于容器的应用程序。

  • 架构即代码。 由于 Pulumi 将真正的语言用于基础设施即代码,最终用户能够将复杂性抽象并封装成可重用的形式,例如函数和类。这甚至可以帮助你在 Kx 解决的基本 Kubernetes 配置挑战之外,将云原生架构中重复出现的模式编成代码。

除此之外,我们一直在努力开发一种新的试验性“观看模式”功能,与上述功能相结合,以一种全新的方式将所有 Kubernetes 内容展示给你。我们很高兴下周能在 KubeCon 的展位上展示这个!

5 如何实现大规模交付?

在掌握了基础设施和应用程序编写的挑战之后,困难就转移到第二阶段及后续的工作中。在这个阶段,组织需要弄清楚如何持续地向不断增加的环境交付变更。

自从去年我们首次发布以来,我们已经添加了许多不同的 CI/CD 集成,包括对 GitLab、Codefresh、Azure DevOps、Octopus Deploy、GitHub Action 等等的支持。这使全球范围的交付成为可能。事实上,我们的一个客户不断地部署横跨开发和基础设施运营团队的 80 个不同的环境。

最后,我们很高兴能够在这个预览版中发布一项新技术、一个新的查询命令和 Kubernetes 查询库,它利用 Pulumi 对象模型来请求关于集群及其应用程序的操作查询。这包括“在我的集群中运行了多少个不同版本的 MySQL?”,“哪些 Pod 通过负载平衡服务暴露在了互联网上?”等等。

例如,这个查询显示了集群中不同版本的 MySQL:

import * as kq from "@pulumi/query-kubernetes";
// 找出集群中运行的所有不同版本的 MySQL
const mySqlVersions = kq
    .list("v1", "Pod")
    .flatMap(pod => pod.spec.containers)
    .map(container => container.image)
    .filter(imageName => imageName.includes("mysql"))
    .distinct();
mySqlVersions.forEach(console.log);
 

CQL 还支持实时流查询,CLI 将实时显示查询结果。

原文链接:

https://www.pulumi.com/blog/crosswalk-kubernetes/

点个在看少个 bug


文章评论