AWS Controllers for Kubernetes(ACK) ことはじめ vol.2 ~ 実践編 ~

※ 本記事は、2022/1/10 現在で著者が検証として諸々触ってみた内容をまとめたものです。ACK は現在デベロッパープレビューな OSS です。後述しますが未実装な機能や改善の余地があり、その実装も今後変更される可能性がに大いにございます。

長くなってしまったので、3 編に分けております。この記事は Vol.2 です。ACK をご存知でない方やこれから試してみたい方はまず環境を整える必要があるので、vol.1 からご覧になることを推奨します。

目次

ACK で S3 バケットを触ってみる

さて前回の記事で準備が整ったので、色々試していきます。まずは S3 で試します。

以下のようなシンプルなマニフェストを書きました。S3 のマニフェスト Yaml のパラメータは API リファレンスを参照ください。また、各サービスコントローラーの Github にもサンプルとなる Yaml があります。S3 だとこちら

apiVersion: s3.services.k8s.aws/v1alpha1
kind: Bucket
metadata:
  name: ack-s3-bucket-hama
spec:
  name: ack-s3-bucket-hama

さて、早速できた マニフェストでデプロイしてみましょう!

$ kubectl apply -f s3-bucket.yaml
--output--
bucket.s3.services.k8s.aws/ack-s3-bucket-hama created

デプロイできました。早速リソースができているか確認すると、Kubernetes 上にリソースができており、また S3 バケット実体もできています。

$ kubectl get bucket
--output--
NAME                 AGE
ack-s3-bucket-hama   43s

$ aws s3api list-buckets | jq '.Buckets[] | select(.Name | test("^ack-s3-bucket-hama"))'
--output--
{
  "Name": "ack-s3-bucket-hama",
  "CreationDate": "2022-01-09T07:37:28+00:00"
}

今度はこのマニフェストを編集します。バージョニングを有効化しました。

apiVersion: s3.services.k8s.aws/v1alpha1
kind: Bucket
metadata:
  name: ack-s3-bucket-hama
spec:
  name: ack-s3-bucket-hama
  versioning:
    status: Enabled

このマニフェストを再度 Apply します。

$ kubectl apply -f s3-bucket.yaml
--output--
bucket.s3.services.k8s.aws/ack-s3-bucket-hama configured

configured で更新されました。そして、先ほど作成したバケットでバージョニングが有効化されていることが確認できました。

$ aws s3api list-buckets | jq '.Buckets[] | select(.Name | test("^ack-s3-bucket-hama"))'
--output--
{
  "Name": "ack-s3-bucket-hama",
  "CreationDate": "2022-01-09T07:37:28+00:00"
}

$ aws s3api get-bucket-versioning --bucket ack-s3-bucket-hama
--output--
{
    "Status": "Enabled"
}

最後に Kubernetes 上でリソースを削除してみます。

$ kubectl delete -f s3-bucket.yaml
--output--
bucket.s3.services.k8s.aws "ack-s3-bucket-hama" deleted

deleted になり、kubernetes 上からも AWS 上のバケットの実体としても削除されたことが確認できました。

$ kubectl get bucket
--output--
No resources found in default namespace.

$ aws s3api list-buckets | jq '.Buckets[] | select(.Name | test("^ack-s3-bucket-hama"))'
--output--
no response

一通り操作しましたが、実際裏でどんなことが起きているのか?また触っているとうまくいかないこともあるでしょう。デバッグとしてサービスコントローラーの log を見てみます。

create/update/delete の各イベントや、update の際に宣言したリソースの状態が変わった時の差分がログとして表示されており、カスタムコントローラーでどんなことをしているか非常にわかりやすいです。

$ kubectl logs ack-s3-controller-s3-chart-86986fb68f-j8lpp -n $ACK_K8S_NAMESPACE
---
...
1.6419669211030383e+09  INFO    ackrt   created new resource    {"account": "xxxxxxxxxxxx", "role": "", "region": "us-west-2", "kind": "Bucket", "namespace": "default", "name": "ack-s3-bucket-hama", "is_adopted": false, "generation": 1}
1.641973046783967e+09   INFO    ackrt   desired resource state has changed      {"account": "xxxxxxxxxxxx", "role": "", "region": "us-west-2", "kind": "Bucket", "namespace": "default", "name": "ack-s3-bucket-hama", "is_adopted": false, "generation": 2, "diff": [{"Path":{"Parts":["Spec","ACL"]},"A":null,"B":"private|bucket-owner-read|bucket-owner-full-control"},{"Path":{"Parts":["Spec","Versioning","Status"]},"A":"Enabled","B":null},{"Path":{"Parts":["Spec","Website","ErrorDocument"]},"A":{"key":"error.html"},"B":null},{"Path":{"Parts":["Spec","Website","IndexDocument"]},"A":{"suffix":"index.html"},"B":null}]}
1.641973047537799e+09   INFO    ackrt   updated resource        {"account": "xxxxxxxxxxxx", "role": "", "region": "us-west-2", "kind": "Bucket", "namespace": "default", "name": "ack-s3-bucket-hama", "is_adopted": false, "generation": 2}
1.6419966414173994e+09  INFO    ackrt   deleted resource        {"account": "xxxxxxxxxxxx", "role": "", "region": "us-west-2", "kind": "Bucket", "namespace": "default", "name": "ack-s3-bucket-hama", "generation": 3}

また、Kubernetes を通して作った S3 バケットを AWS から直接編集・削除をしてみましたが、変更した設定はそのままでマニフェストの宣言状態に収束されず、削除したバケットも再作成されませんでした。ログ上も無反応だったので、ACK のコントローラーからリソース作成・変更・削除操作時以外の状態監視は現状されていないようでした。

訂正。こちらの Issue に記載の通り、実装としてはあるけど頻繁なチェックはリソースへの負担も大きく現状は8h間隔でのチェックみたいです。

後述しますが、Crossplane の方はこの辺対応しており、個人的には Kubernetes っぽく宣言状態を保つような動きをしてほしいなと思っていますので、ACK でも今後に期待です。 の方がチェック感覚が短いというところで、どっちがいいのかは微妙なところですね。

ACK で EKS クラスターを触ってみる

さて、今度は EKS クラスターを EKS で管理します。Kubernetes のクラスター自体も Kubernetes で管理したい瞬間ないですか?

2021/09/29 に AWS Dev Day で ACK の話をした時はまだ EKS Controller は IN PROGRESS だったんですが、11月に晴れて Preview としてリリースされましたので、早速触ってみました。

インストールまではACK 導入手順 の通りなのですが、(2021/01/10 現在) 一部動かないところがあり、補足を入れます。

EKS では FullAccess Policy がないため、インラインポリシーかセルフ管理のポリシーを書くことになるのですが、recommended-inline-policy には以下のように書いてあります。そして、このままだと主に IAM 周りの権限が足りません。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "eks:*"
            ],
            "Resource": "*"
        }
    ]
}

特に EKS というサービスが Kubernetes のクラスターや関連リソースを操作するために、「EKS サービスに IAM ロールを渡す」アクセス権限をサービスコントローラーが持っている必要があります。つまり iam:PassRole が必要です。取り急ぎ、以下のようなポリシーにすることで動作しました。ちょっとした検証しかできていないので、実際はもっと権限が必要な気はします。ちゃんと Issue 書いて、pull request しますかね。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "iam:GetRole",
                "iam:ListAttachedRolePolicies",
                "ec2:DescribeSubnets",
                "eks:*"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "iam:PassRole",
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "iam:PassedToService": "eks.amazonaws.com"
                }
            }
        }
    ]
}

これで準備ができたので、早速 EKS クラスターを作ります。クラスター・ノードグループ・アドオン(vpc-cni, coredns, kube-proxy) のマニフェスト Yaml を書きました。EKS のマニフェスト Yaml のパラメータは API リファレンスを参照ください。サンプル Yaml はこちらです。

apiVersion: eks.services.k8s.aws/v1alpha1
kind: Cluster
metadata:
  name: ack-hama-cluster
spec:
  name: ack-hama-cluster
  version: "1.21"
  roleARN: "$CLUSTER_ROLE"
  resourcesVPCConfig:
    endpointPublicAccess: true
    subnetIDs:
      - "$SUBNET_1"
      - "$SUBNET_2"
      - "$SUBNET_3"
  logging: 
    clusterLogging:
    - enabled: true
      types:
      - api
      - audit
      - authenticator
      - scheduler
---
apiVersion: eks.services.k8s.aws/v1alpha1
kind: Nodegroup
metadata:
  name: ack-hama-ng
spec:
  name: ack-hama-ng
  clusterName: ack-hama-cluster
  instanceTypes: 
    - "m5.large"
  subnets:
    - "$SUBNET_1"
    - "$SUBNET_2"
    - "$SUBNET_3"
  nodeRole: "$NODEGROUP_ROLE"
  scalingConfig:
    minSize: 3
    maxSize: 3
    desiredSize: 3
---
apiVersion: eks.services.k8s.aws/v1alpha1
kind: Addon
metadata:
  name: ack-hama-vpc-cni
spec:
  name: vpc-cni
  addonVersion: v1.10.1-eksbuild.1
  clusterName: ack-hama-cluster
---
apiVersion: eks.services.k8s.aws/v1alpha1
kind: Addon
metadata:
  name: ack-hama-coredns
spec:
  name: coredns
  addonVersion: v1.8.4-eksbuild.1
  clusterName: ack-hama-cluster
---
apiVersion: eks.services.k8s.aws/v1alpha1
kind: Addon
metadata:
  name: ack-hama-kube-proxy
spec:
  name: kube-proxy
  addonVersion: v1.21.2-eksbuild.2
  clusterName: ack-hama-cluster

早速できたマニフェストでデプロイしてみます。

$ kubectl apply -f eks.yaml
--output--
cluster.eks.services.k8s.aws/ack-hama-cluster created
nodegroup.eks.services.k8s.aws/ack-hama-ng created
addon.eks.services.k8s.aws/ack-hama-vpc-cni created
addon.eks.services.k8s.aws/ack-hama-coredns created
addon.eks.services.k8s.aws/ack-hama-kube-proxy created

はい、できました。

$ aws eks describe-cluster --name ack-hama-cluster
--output--
{
    "cluster": {
        "name": "ack-hama-cluster",
        "arn": "arn:aws:eks:us-west-2:xxxxxxxxxxxx:cluster/ack-hama-cluster",
        "createdAt": "2022-01-09T16:13:32.036000+00:00",
        "version": "1.21",
        ~ snip ~

$ aws eks list-nodegroups --cluster-name ack-hama-cluster
--output--
{
    "nodegroups": [
        "ack-hama-ng"
    ]
}

$ aws eks list-addons --cluster-name ack-hama-cluster
--output--
{
    "addons": [
        "coredns",
        "kube-proxy",
        "vpc-cni"
    ]
}

この後、S3 の時と同様にマニフェストを編集して Apply してみましたがうまく反映されず、「あれ?」と思って log を見てみると、“not implemented” error が出ていました (2022/01/10 確認)。おそらく現状は未実装で明示的に 501 エラーを返すようになっているのかと思います。そのうち解消されるでしょう。プレビューですし仕方ない。

ちなみに削除は問題なく動作しました。

$ kubectl logs ack-eks-controller-eks-chart-cb5bcd9bd-md697 -n $ACK_K8S_NAMESPACE
---
2022-01-10T14:23:26.476Z        INFO    ackrt   desired resource state has changed      {"account": "xxxxxxxxxxxx", "role": "", "region": "us-west-2", "kind": "Cluster", "namespace": "default", "name": "ack-hama-cluster", "is_adopted": false, "generation": 5, "diff": [{"Path":{"Parts":["Spec","Logging","ClusterLogging"]},"A":[{"enabled":true,"types":["api","audit","authenticator","scheduler"]}],"B":[{"enabled":true,"types":["api","audit","authenticator"]},{"enabled":false,"types":["controllerManager","scheduler"]}]},{"Path":{"Parts":["Spec","ResourcesVPCConfig","EndpointPrivateAccess"]},"A":true,"B":false},{"Path":{"Parts":["Spec","Tags"]},"A":null,"B":{}}]}
2022-01-05T14:23:26.487Z        ERROR   controller-runtime.controller   Reconciler error        {"controller": "cluster", "request": "default/ack-hama-cluster", "error": "not implemented"}

2022-01-10T14:26:55.878Z        INFO    ackrt   desired resource state has changed      {"account": "xxxxxxxxxxxx", "role": "", "region": "us-west-2", "kind": "Nodegroup", "namespace": "default", "name": "ack-hama-ng", "is_adopted": false, "generation": 3, "diff": [{"Path":{"Parts":["Spec","InstanceTypes"]},"A":["m5.xlarge"],"B":["m5.large"]},{"Path":{"Parts":["Spec","Labels"]},"A":null,"B":{}},{"Path":{"Parts":["Spec","ScalingConfig","DesiredSize"]},"A":2,"B":3},{"Path":{"Parts":["Spec","ScalingConfig","MaxSize"]},"A":2,"B":3},{"Path":{"Parts":["Spec","ScalingConfig","MinSize"]},"A":2,"B":3},{"Path":{"Parts":["Spec","Tags"]},"A":null,"B":{}}]}
2022-01-10T14:26:55.890Z        ERROR   controller-runtime.controller   Reconciler error        {"controller": "nodegroup", "request": "default/ack-hama-ng", "error": "not implemented"}

つづく!

もう少し続くのじゃ。


関連リンク: