简介

适用于 Kubernetes 的 AWS 控制器 (ACK)允许通过您在 Kubernetes 中部署其他资源所使用的相同流程来创建 AWS 资源。 ACK 使用 Kubernetes 控制器模型与 AWS API 进行交互。部署特定服务的 ACK 服务控制器后,您可以利用 Kubernetes 自定义资源定义 (CRD) 在 YAML 清单中声明特定 AWS 资源。然后,您将它们发送到 Kubernetes API 服务器,并在您的 AWS 账户中预置指定的 AWS 资源。

当我最初听到有关适用于 Kubernetes 的 AWS 控制器的消息时,我立即被之前的一些挑战所震惊,在这些挑战中,将 AWS 资源直接绑定到其他 Kubernetes 部署将非常有帮助。我认为使用 ACK 的关键是理解何时使用它们是有意义的。大多数组织都有使用 CloudFormation 或 Terraform 等工具配置云基础架构的成熟流程。通过引入一种新的资源配置方式,您引入了一个额外的地方,您现在需要在命名/标记/安全配置方面管理标准,验证控制器的权限遵循最小权限等。

用例

在我看来,使用 ACK 来部署资源的原因只有几个,而您可能希望避免使用 ACK 的情况会更长。显然,这完全取决于您的组织和用例。

什么时候使用ACK

  • 管理与 Kubernetes 资源生命周期相关的 AWS 资源 - 在许多用例中,您可能希望在 Kubernetes 部署的同时维护资源,或在 Helm Chart 中指定它们。例如,第 1 天对我有帮助的一个用例是能够在 Kubernetes 中的部署旁边创建 SQS 队列,这些部署设置为根据新 SQS 队列的长度进行扩展。

什么时候不使用ACK

  • AWS 资源将主要在 Kubernetes 之外使用——这不能替代 CloudFormation 或 Terraform 等基础设施即代码解决方案。

  • 需要保留数据 - 这是一个灰色区域,因为您绝对可以使用 ACK 创建数据存储,并且可能有很好的案例。但是,重要的是要了解在 Kubernetes 中简单地删除 AWS 资源对象会导致 AWS 资源及其所有相关数据的删除。

  • ACK 控制器未公开所需参数 - 如果控制器未公开您需要在资源上设置的特定参数,则应使用另一种方法创建资源以避免重复工作。例如,如果您需要关闭 S3 Public Access,它不是可用参数,因此 ACK 不是一个好的选择。

  • 您想要一种向开发人员公开资源部署的方法,并且他们已经了解 Kubernetes - 仅仅因为开发人员熟悉 Kubernetes 资源的工作方式,如果资源不直接与 Kubernetes 部署相关联,那么管理这些资源就没有意义带有 ACK 的资源。开发人员学习 CloudFormation 或 Terraform 或使用 AWS Service Catalog 之类的工具向他们公开资源创建更有意义。

选择部署模型

ACK 调用这些installScope并且选项是clusternamespace。每个选项都有一些优点和缺点。

  • 集群:

  • 优点:只需要运行集群中每个控制器的一个副本,因此减少了管理这些组件所需的工作量。

  • 缺点:每个控制器使用的 IAM 凭证的权限需要广泛,以适应需要在集群中的任何位置创建资源的所有可能方式。

  • 命名空间:

  • 优点:可以通过控制器配置和控制器创建资源时使用的 IAM 权限获得更细粒度。

  • 缺点:需要管理所有命名空间中的每个控制器,这会增加操作开销(例如,需要跨所有命名空间而不是仅在一个地方运行升级)。

我非常喜欢多租户集群中的“共享服务”模型,并且可能会在此处使用cluster选项。我认为,只要您在集群中进行适当的治理,您就可以一次集中管理所有组件,并使它们可供集群中的所有用户使用。有关治理方法的更多信息,请参阅本文的最后一部分。

开始使用 ACK 的 S3 控制器

我最初开始遵循 ACK 文档](https://aws-controllers-k8s.github.io/community/user-docs/install/#helm-recommended)中的安装说明,特别是使用 Helm 图表。查看 ECR中的[S3 控制器 Helm Chart,最新版本为v0.0.2

export HELM_EXPERIMENTAL_OCI=1
export SERVICE=s3
export RELEASE_VERSION=v0.0.2
export CHART_EXPORT_PATH=/tmp/chart
export CHART_REPO=public.ecr.aws/aws-controllers-k8s/$SERVICE-chart
export CHART_REF=$CHART_REPO:$RELEASE_VERSION
export ACK_K8S_NAMESPACE=ack-system

mkdir -p $CHART_EXPORT_PATH

helm chart pull $CHART_REF
helm chart export $CHART_REF --destination $CHART_EXPORT_PATH

kubectl create namespace $ACK_K8S_NAMESPACE

helm install --namespace $ACK_K8S_NAMESPACE ack-$SERVICE-controller \
    $CHART_EXPORT_PATH/ack-$SERVICE-controller

进入全屏模式 退出全屏模式

这总体上有效,但是当我开始部署测试 S3 存储桶时,文档](https://aws-controllers-k8s.github.io/community/reference/S3/v1alpha1/Bucket/#spec)中列出的许多Specs[都生成错误并且无法正常工作。例如,我的存储桶清单如下。v0.0.2tagging没有任何支持,因此这将创建一个没有标签的存储桶并引发not implemented错误。

apiVersion: s3.services.k8s.aws/v1alpha1
kind: Bucket
metadata:
  name: test-s3-matt-bucket
spec:
  tagging:
    tagSet:
      - key: CostCenter
        value: Development
  name: test-s3-matt-bucket

进入全屏模式 退出全屏模式

在尝试了解发生了什么之后,我意识到 ECR 中可用的 Helm Chart 和 Docker 映像都已过时。查看 s3-controller 存储库,正在积极进行更改,但没有发布表明v0.0.2版本与哪个提交相关联。

作为下一步,我决定构建一个更新的 Docker 映像并使用存储库中的最新 Helm 图表来部署控制器。这最终比我预期的要困难一些。 ACK 解决方案的设计非常模块化。这种设计的优点是向 ACK 添加新服务非常容易。最大的缺点是,作为项目的新手,弄清楚所有东西如何组合在一起有点令人困惑。

在阅读了更多文档并查看了aws-controllers-k8s组织中的所有不同存储库后,我发现了code-generator存储库,其中包含适当的脚本,可以根据服务存储库上的最新提交为服务生成新的 Docker 映像。

要构建新的 S3 映像:

  • 运行以下命令克隆code-generator存储库并运行s3的构建脚本:
git clone https://github.com/aws-controllers-k8s/code-generator.git
cd code-generator/scripts/
./build-controller-image.sh s3

进入全屏模式 退出全屏模式

  • 标记新生成的图像并将其推送到我自己的 ECR 存储库。
docker tag <image-tag> public.ecr.aws/<repository>/s3-ack:<tag>
docker push public.ecr.aws/<repository>/s3-ack:<tag>

进入全屏模式 退出全屏模式

  • 运行以下命令克隆s3-controller存储库:
git clone https://github.com/aws-controllers-k8s/s3-controller.git
cd s3-controller/helm/

进入全屏模式 退出全屏模式

  • 假设您之前已经部署了 Helm 图表,您将需要使用与以前相同的名称升级图表,而不是指向本地克隆的副本。下面的示例升级安装在命名空间ack-system中的名为ack-s3-controller的 Helm 图表,并从当前目录 (.) 获取 Helm 图表。它还将image.repositoryimage.tag值设置为步骤 #2 中 ECR 中的新位置。
helm upgrade ack-s3-controller .  --namespace ack-system \
     --set image.repository=public.ecr.aws/<repository>/s3-ack,image.tag=<tag>

进入全屏模式 退出全屏模式

从那里,您现在应该能够利用文档中提供的最新功能创建一个新的 S3 存储桶。根据我的经验,一旦我部署了新版本并使用了上面列出的 S3 存储桶 YAML 文件,就会部署一个带有预期标签的新 S3 存储桶。

建议

ACK 项目对其发布和版本控制过程进行了非常深入的审查这里。它非常彻底,并遵循您对这种性质的解决方案所期望的许多标准。文档中非常清楚的项目之一是每个控制器都有自己的发布和维护周期。考虑到需要的不同服务控制器的数量,这也是有道理的。

说了这么多,我的建议是:

  • 遵循所有控制器的标准化发布流程。一些控制器在 GitHub 中定义了与 Docker 图像和 Helm 图表匹配的版本,有些则没有(正如我们在 S3 中看到的那样)。

  • 如果正在更新 Docs 网站上的服务控制器文档,请确保有一个实际发布的 Docker 映像和可用的 Helm 图表,以允许使用 Docs 引用的内容。

  • 在文档网站的集中位置记录发布版本。这个页面将是列出最新发布版本的好地方。

我认为将一些简单的发布过程附加到处理上述内容的每个控制器存储库中并不是一个巨大的要求。我完全意识到这些仍处于 alpha 阶段,可能还没有为“稳定”标签做好准备,但我认为这个简单的更改大大降低了进入门槛,并将允许社区中的其他人试用这些控制器.

通过 ACK 与 Gatekeeper 管理资源创建

您可能希望在使用 ACK 时使用指定的防护机制创建 AWS 资源。您可以这样做的一种方法是尝试自定义附加到控制器的 IAM 策略,以限制资源的创建,除非它们满足某些条件。这很好用,但不同的资源提供不同的条件,这意味着您可能会或可能无法根据您想要的参数来限制创建。此外,从 AWS 返回的拒绝访问的错误消息不会传递给最终用户,使他们对 IAM 限制引起的问题视而不见。

在 Kubernetes 的世界里,Gatekeeper可以在我们使用 ACK 时填补这个空白。因为要使用 ACK 部署的 AWS 资源在提交到 Kubernetes API 时被转换为标准 JSON 格式,所以我们可以在 rego 中编写策略,然后使用 Gatekeeper 强制执行这些策略。

我将为已经存在的其他帖子留下完整的 Gatekeeper 教程,但将在下面发布示例 Gatekeeper 模板和约束。

关守模板和约束示例 - S3 标准

template.yaml- 这定义了约束模板。您可以看到我们正在检查 S3 存储桶名称是否以特定字符串开头并且存在特定标签。

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: bucketdefaultrequirements
  annotations:
    description: Requires S3 buckets created by ACK match standards.
spec:
  crd:
    spec:
      names:
        kind: bucketDefaultRequirements
      validation:
        # Schema for the `parameters` field
        openAPIV3Schema:
          type: object
          properties:
            bucketStartsWith:
              type: string
            requiredTagKey:
              type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package bucketdefaultrequirements

        violation[{"msg": msg}] {
          namingConventionStartsWith := input.parameters.bucketStartsWith

          value := input.review.object.spec.name

          # Check if the Bucket Name follows our naming convention
          not startswith(value, namingConventionStartsWith)

          # Construct an error message to return to the user.
          msg := sprintf("Bucket name does not follow proper format; found `%v`; needs to start with `%v`.", [value, namingConventionStartsWith])
        }

        violation[{"msg": msg}] {
          requiredTagKey := input.parameters.requiredTagKey
          value := input.review.object.spec.tagging.tagSet
          not contains(value, requiredTagKey)
          msg := sprintf("%v tag is missing.", [requiredTagKey])
        }

        contains(tagKeys, elem) {
          tagKeys[_]["key"] = elem
        }

进入全屏模式 退出全屏模式

constraint.yaml- 这定义了使用上面创建的模板的实际约束。我们可以创建一个新的约束以在整个集群中使用(如下所示),或者我们可以为此规则创建特定的命名空间范围约束。

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: bucketDefaultRequirements
metadata:
  name: s3-buckets-must-meet-base-requirements
spec:
  match:
    kinds:
      - apiGroups: ["s3.services.k8s.aws"]
        kinds: ["Bucket"]
  parameters:
    bucketStartsWith: "matt-s3-"
    requiredTagKey: "CostCenter"

进入全屏模式 退出全屏模式

当上述约束失败并且我尝试创建一个名为test-s3-matt-bucket且没有 CostCenter 标签的 S3 存储桶时,我会收到 Kubernetes API 返回的以下友好消息:

error when creating "bucket.yaml": admission webhook "validation.gatekeeper.sh" denied the request: 
[s3-buckets-must-meet-base-requirements] CostCenter tag is missing.
[s3-buckets-must-meet-base-requirements] Bucket name does not follow proper format; found `test-s3-matt-bucket`; needs to start with `matt-s3-`.

进入全屏模式 退出全屏模式

总结

我希望这在某种程度上有所帮助! ACK 是在将 AWS 资源与许多开发人员已经非常熟悉的 Kubernetes 部署生命周期集成方面向前迈出的一大步。现在还处于早期阶段,就像 AWS 带来的一切一样,我很肯定客户的痴迷将继续推动 ACK 项目在 Kubernetes 中部署 AWS 资源时实现完全的 API 对等。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐