GitOps化を通じた「AWS Controllers for Kubernetes」の実用性検証
こんにちは、NRIデジタルの島です。
コンテナベースのアプリケーションを構築、運用していく場合、多くの場合コンテナを継続的に運用・管理していくコンテナオーケストレーションツールが必要になってきます。AWSにおけるコンテナオーケストレーションサービスには「Elastic Container Service(ECS)」や「Elastic Kubernetes Service(以下EKS)」などがありますが、AWS上でKubernetes(以下k8s)の恩恵を受けられることから、今後EKSを選択する利用者は増えていくのではないかと思っております。
k8sの恩恵は多々ありますが、その一つに「CustomResourceDefinitions(以下CRD)」 があります。CRDを使用すると、k8s環境への柔軟なリソース追加や機能拡張が可能になります。
CRD
Extend the Kubernetes API with CustomResourceDefinitions
EKSを使用してアプリケーションを構築する場合、アプリケーションの要件がそのコンテナサービス内のみで満たせることは少なく、各AWSサービスと連携するユースケースがほとんどかと思います。その際、「アプリケーション構築は開発チーム、連携するAWSサービスの構築はインフラチーム」というようにチームを跨って管理が分断されてしまうことや、「アプリケーションの設定はk8sのマニフェスト、連携するAWSサービスは手動」というようにリソース管理手段が分断されてしまうことも多いと思います。これらはアプリケーション開発のアジリティを損なう要因になりかねません。
本記事で紹介する「AWS Controllers for Kubernetes」はk8sのCRDを利用して、使用するAWSサービスをコンテナ内リソースと同等に扱うことが出来るツールであり、上記の分断管理の課題を解決できるソリューションとなっています。
AWS Controllers for Kubernetes
概要
AWS Controllers for Kubernetes(以下ACK)は、k8sのCRD機能における「カスタムリソース」や「カスタムコントローラ」の仕組みを利用して、k8sから利用する各種AWSサービスの作成やライフサイクル管理を実行できるようにAWSが開発したツール(AWSサービス用のカスタムリソース/コントローラ)となります。
※カスタムリソース/コントローラについては以下をご参照ください
カスタムリソース
ACKを利用すると、それらのAWSリソースを個別に管理することなく、k8sクラスタ内で一元管理できるようになります。
ACKの実態はk8sクラスタのデータプレーン上で稼働するPodとなります。Podとして稼働している各AWSサービスのコントローラ(下図例では「ack-s3-controller」)がk8sのコントロールプレーン上のAPI Server(下図「kube-apiserver」)と常時会話をし、実際のAWSサービスの状態を、applyされているリソース定義情報に整えます(※1)。
ACK公式ページより
※1
このようにリソースをあるべき状態に整えるk8sの機能を「Reconciliation Loop」といい、各コントローラによって実現されています。
コントローラー
ACKのメリット
ACKもCDKやTerraform等と同様にリソースをコード化してデプロイするいわゆる「Infrastructure as Code(IaC)」の一種と捉えることができますが、筆者が考えるACKのメリットは以下となります。
- マニフェストファイルを定義さえすれば、AWSサービスを作成・変更可能
- マニフェストを作成するので、インフラ設計のマスタにすることができる
- APIを直接コールする為、デプロイが高速
- k8sの「Reconciliation Loop」機能により、適切な状態を維持できる
- k8sと連携可能なツールを利用でき、ACKと組み合わせて利用できる
- k8sで利用しているツールをそのまま利用可能(e.g. kubectl apply・・・)
アプリケーションで利用するAWSサービスの構築をインフラチームに依頼するような開発スキームの場合、構築までのリードタイムが開発のボトルネックになる可能性があります。
ACKを利用すると、開発者自身が、利用するAWSサービスまで構築できるようになる為、開発業務がスムーズになります。
SSOT(Single Source of Truth 唯一の信頼できる情報)を実現できます。
CDKやTerraformはCloudFormationをラップしているツールの為デプロイが遅いですが、ACKはCloudFormationを介さず、コントローラから各AWSサービスのAPIを直接コールする為、数秒で反映できます。
各AWSサービスを手動で設定変更(誤削除や手動設定ミス)してしまった場合もマニフェストを正として自動リカバリが可能となります。
k8sのエコシステム上の様々な製品と連携できる為、Argo CDやFlux等を利用したGitOpsなどが実現可能となります。
CDKやTerraformのように、それを実装、実行する為の独自のツール等のインストールが不要で、kubectlなどk8s標準ツールがあれば利用できます。
※上記メリットのいくつかはCDKやTerraformでも同様ですが、yamlマニフェストレベルでより容易に管理できる(複雑なコード記述は不要)ことがポイントになると思っています
ACK検証(サマリ)
このACKついて、先日いくつかのサービスが一般利用可能になったとアナウンスがありました。
ACKコントローラーが一般提供を開始
早速、実際にEKS上にACKとArgo CDをインストールし、各種リソースのデプロイを試してみました。次項よりその検証内容を共有させていただきますが、検証を通しての筆者の感想、気になった事項を先に共有したいと思います。
まず全体的な使用感ですが、アプリケーションが利用する各AWSサービスを、アプリケーションと同レベル(手順等含め)で扱えることが体感できました。これは、開発者自身がTry and ErrorでAWSサービスも含めて変更、テストを迅速に繰り返し実施できるということになり、これは開発のアジリティ向上における大きなメリットになると感じました。また、前述した通り、ACKはCloudFormationを介さず、APIを直コールします。検証を通して、作成時も変更時も削除時も、適用後ほんの数秒で反映されておりました。これはCDKやTerraformにはない大きなメリットかと思います。
一方、使用するにあたり気になるポイントについてもお伝えしておきます。使用是非のご判断のご参考になれば幸いです。
- 対応済みサービスが少ない
- API仕様が理解しにくい
- 「Reconciliation Loop」の間隔が長い
一般利用可能となったとはいえ、執筆時点ではGA済みのサービスはまだまだ少ない状態です。
※公式ドキュメントにおいて各サービスの対応状況が確認できます
Services
また、仮にGAしているサービスでも、一部の機能だけに留まっているケース(例えばAPI Gatewayが対応しているのは「HTTP API及びWebsocket API」であり、「REST API」に対応しておりません)もある為、サービスだけでなく、サービス内の利用予定機能が対応しているかどうかも確認が必要です。
マニフェスト作成する為にはその定義方法を知らなければなりません。基本的には公式ページのAPIリファレンスを参照することになります。
API Reference
しかしながら、各項目の説明もデータ型のみだったり、サンプルが少なかったりと、執筆時点ではまだ十分に充実した内容にはなっていない印象です。
e.g. API Gateway Integration
ACKは「CloudFormation」の仕様をベースに作成されているようで、基本的には定義方法もほぼ同様となっています。上記APIリファレンスを見てもわからない場合は、CloudFormationのドキュメントを参照すると良いと思います。もしそれでもうまくいかない場合は、ACKのGitHubページのソースコードやサンプルをご確認いただければと思います。
aws-controllers-k8s
前述のメリット説明で、ACKを使用することで「k8sのReconciliation Loopの恩恵を享受できる」と述べました。しかしながら実際に試してみたところ、そのループ間隔が非常に長いようで、迅速な状態チェックはされてないようでした。確認したところ、以下Issueにもある通り、Reconciliation 自体は実装に含まれているものの、頻繁なリソースの確認は CPU 負荷が高い為、執筆時点では 8 時間の間隔のようです。
[Reconcillation issue in s3 controller #1288] Reconcillation issue in s3 controller · Issue #1288 · aws-controllers-k8s/community ''' We have common logic in all of the ACK controllers that when the resource reaches its desired state, it will pause reconciliation for a while. It would be CPU intensive to continuously check for drift at a relatively short interval, so we leave that to the K8s API server default requeue time, which I think is 8 hours.
ここは今後の改善に期待したいところですが、執筆時点ではこのような仕様になっていることをご認識いただければと思います。
では、次項より検証内容を共有させていただきますので、興味ある方は是非ご参照ください。
ACK検証
システム構成
本検証で構築するシステム構成は以下の通りです。
※EKSはデータプレーンにEC2を使用しています
本検証では「外部からのデータを受け付け、非同期に処理を行う」ようなユースケースを想定しました。
簡単な処理の流れは以下の通りです。
- クライアントからAPI Gateway経由でJSONを受信し、Application Load Ballancer(以下ALB)経由でPod(REST API)へ転送する ※API Gateway→ALB→Podの通信はPrivate
- JSONを受信したPod(REST API)はそのJSONをS3バケットへ書き込む(S3 Put Object)
- S3のPutイベントによりLambda関数が起動される(S3 Put Event)
- Lambda関数より該当のJSONを取得する(S3 Get Object)
- 取得したJSONをDynamoDBへ書き込む(DynamoDB Put Item)
※非同期処理であれば「Amazon Simple Queue Service(SQS)」利用にしたいところでしたが、執筆時点ではACK未対応だった為、ACKに対応している「S3」及び「S3 Event」で代用しております
また、前述した通りEKSはk8sに準拠している為、k8sエコシステムの製品を容易に導入可能です。今回はArgo CDを導入し、ACKのカスタムリソースや各種マニフェストをデプロイしていきました。
Argo CD
前提条件
以降の流れを実施するには以下の事前準備が必要です。
- EKSクラスタが構築されていること
- EKSクラスタ用のOIDCプロバイダが作成されていること
クラスターの IAM OIDC プロバイダーを作成するには – Amazon EKS - AWS Load Balancer Controllerがデプロイされていること
AWS Load Balancer Controller アドオンのインストール – Amazon EKS
Welcome – AWS Load Balancer Controller
※ 手動でALBを作成する場合は不要 - EKSクラスタを操作する端末にHelm(3系以上)がインストールされていること
ACKコントローラ
- ACKコントローラのインストール
- コントローラのアクセス制御
インストールは以下公式ページの手順で簡単にインストール可能です。(Helmによるインストール)
Install an ACK Controller
インストール後、正常にPodが起動しました。
# helm list >helm list -n ack-system NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION ack-apigatewayv2-controller ack-system 1 2022-06-07 08:06:54.536616213 +0000 UTC deployed apigatewayv2-chart-v0.1.0 v0.1.0 ack-dynamodb-controller ack-system 1 2022-06-07 08:08:18.47455996 +0000 UTC deployed dynamodb-chart-v0.1.0 v0.1.0 ack-ecr-controller ack-system 1 2022-06-07 08:05:08.285228847 +0000 UTC deployed ecr-chart-v0.1.0 v0.1.0 ack-iam-controller ack-system 1 2022-06-07 08:05:36.612184657 +0000 UTC deployed iam-chart-v0.0.15 v0.0.15 ack-lambda-controller ack-system 1 2022-06-07 08:05:58.013244891 +0000 UTC deployed lambda-chart-v0.0.16 v0.0.16 ack-s3-controller ack-system 1 2022-06-07 08:03:17.493889296 +0000 UTC deployed s3-chart-v0.0.20 v0.0.20 # get pod >kubectl get po -n ack-system NAME READY STATUS RESTARTS AGE ack-apigatewayv2-controller-apigatewayv2-chart-5d7df474c6-t4brg 1/1 Running 0 99s ack-dynamodb-controller-dynamodb-chart-5fd44ffbf6-97s4w 1/1 Running 0 15s ack-ecr-controller-ecr-chart-6f4d6f66f4-thstm 1/1 Running 0 3m25s ack-iam-controller-iam-chart-68db864587-mxpjv 1/1 Running 0 2m57s ack-lambda-controller-lambda-chart-579cd85ddb-jwhm9 1/1 Running 0 2m36s ack-s3-controller-s3-chart-665f6c5679-l9wf4 1/1 Running 0 5m17s
各コントローラに対してAWSリソースを操作できる権限を「IAM Roles for Service Accounts (IRSA) 」で与えます。
※WorkerNodeのIAMロールへの直接的な権限付与は過剰な権限付与になる可能性がある為、「IAM Roles for Service Accounts (IRSA) 」で Pod レベルのアクセスコントロールを付与することが推奨されています
以下公式ページの手順を全コントローラに対して実施しました。
IAM roles for service accounts – Amazon EKS
以下例のように各コントローラに対して、IAMロールやWeb ID Tokenが設定されていれば正常です。
# DynamoDBコントローラ 例 kubectl describe po ack-dynamodb-controller-dynamodb-chart-55f7d79bf5-xd9gw -n ack-system | grep "^\s*AWS_" AWS_REGION: ap-northeast-1 AWS_ENDPOINT_URL: AWS_ROLE_ARN: arn:aws:iam::XXXXXXXXXXXX:role/ack-dynamodb-controller-role AWS_WEB_IDENTITY_TOKEN_FILE: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
Argo CD
ACKやその他のマニフェストをベースにGitOpsする為に、Gitリポジトリの準備とArgo CDのインストール、設定をします。
※Argo CDも構成図の通り、Podとして稼働します
- Gitリポジトリの準備
- Argo CDのインストール
今回はBitBucketにてリポジトリを作成し、マニフェストを格納するディレクトリを準備します。
ACKやその他のマニフェストをベースにGitOpsする為にArgo CDをインストールします。
インストールは以下公式ページの手順でインストール、設定しました。
Getting Started – Argo CD – Declarative GitOps CD for Kubernetes
今回はCLIで対象クラスタを追加し、その後はGUI画面から対象クラスタ、①のリポジトリ、マニフェスト対象ディレクトリを指定してアプリケーションを作成しました。
なお、Argo CDのGUI画面へのアクセスについてhttpでアクセスしたい場合は、以下のようにinstall.yamlを修正する必要があります。(「argocd-server」のContainerに「− − insecure」を追加)
# install.yaml ---略--- containers: - command: - argocd-server - --insecure ←※追加 env: - name: ARGOCD_SERVER_INSECURE ---略---
アプリケーション
アプリケーション(Podとして稼働させるREST APIとLambda関数(実行IAMロールを含む))をデプロイしていきます。今回両アプリケーションはDockerコンテナとして稼働させる為、Dockerイメージを格納する「ECRリポジトリ」とAPI GatewayがPod(REST API)へ連携する為の「ALB」もあわせて作成します。
- ECRリポジトリの作成
- イメージのPush
- PodとALBのデプロイ
- Lambda関数のデプロイ
ACKを使用して、アプリケーションのイメージを格納するECRリポジトリを作成します。
※API用とLambda用2つのリポジトリを作成
以下のマニフェストを作成し、BitBucketのリポジトリへPushします。
################################# # Repository ################################# apiVersion: ecr.services.k8s.aws/v1alpha1 kind: Repository metadata: name: ecrr-coe-val-stg0-api namespace: coe-system spec: imageScanningConfiguration: scanOnPush: true name: coe-api-repo --- apiVersion: ecr.services.k8s.aws/v1alpha1 kind: Repository metadata: name: ecrr-coe-val-stg0-function namespace: coe-system spec: imageScanningConfiguration: scanOnPush: true name: coe-function-repo
Argo CDのGUIでマニフェストが認識されます。
同期します。
↓
EKS上にECR Repositoryのリソースがデプロイされ、ACK ECRコントローラにより実際のリポジトリが作成されます。
>kubectl get repository -n coe-system NAME AGE ecrr-coe-val-stg0-api 17s ecrr-coe-val-stg0-function 17s
作成したアプリケーションのイメージを①で作成したリポジトリにPushします。
# ECRへログイン >aws ecr get-login-password --region ap-northeast-1 | sudo docker login --username AWS --password-stdin https://XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com Login Succeeded # APIアプリケーションのイメージ >sudo docker push XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/coe-api-repo:0.0.1 The push refers to repository [XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/coe-api-repo] 727be6559cfd: Pushed b6bbb8e20db6: Pushed 0f1b6278031e: Pushed d14c97a375c7: Pushed d51348c0e837: Pushed b4886229869b: Pushed 426e0bc3b80d: Pushed e6b57a4b7e93: Pushed c4c461dc990d: Pushed 0.0.1: digest: sha256:cd8532d86473fba75ef5c59840c5a07117bdcce39b6e23e3a0c664da5f08eaf6 size: 2208 # Lambda関数のイメージ >sudo docker push XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/coe-function-repo:0.0.1 The push refers to repository [XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/coe-function-repo] 87899ff4e869: Pushed 20716ea1d5b7: Pushed b5a0b85cd06a: Pushed a17ea8ccee27: Pushed e44da8829878: Pushed 929f92908dc5: Pushed 365acf1eba74: Pushed 79672c89d4a0: Pushed 0.0.1: digest: sha256:b1c41deb3c90a5b75e557041b04cf96d0e201c18273b52a9a920bbbbcc2bb1f7 size: 2004
API用PodとALBをデプロイします。
以下のマニフェストを作成し、BitBucketのリポジトリへPush後、Argo CDよりデプロイします。
※ALBはIngressリソースとして作成します。
また、後続で作成するAPIGatewayとPrivate統合としたい為「Internal」で作成します。
################################# # Deployment ################################# apiVersion: apps/v1 kind: Deployment metadata: name: coe-rest-api namespace: coe-system spec: replicas: 2 selector: matchLabels: app: coe-rest-api progressDeadlineSeconds: 600 strategy: type: RollingUpdate rollingUpdate: maxSurge: 50% maxUnavailable: 50% template: metadata: name: coe-rest-api labels: app: coe-rest-api spec: containers: - name: coe-rest-api image: XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/coe-api-repo:0.0.1 ←ECRリポジトリへPushしたイメージ imagePullPolicy: IfNotPresent ports: - containerPort: 18081 resources: limits: cpu: "250m" memory: "512Mi" readinessProbe: httpGet: path: /actuator/health/readiness port: 18081 initialDelaySeconds: 10 periodSeconds: 5 timeoutSeconds: 1 successThreshold: 1 failureThreshold: 5 livenessProbe: httpGet: path: /actuator/health/liveness port: 18081 - ./ initialDelaySeconds: 10 periodSeconds: 5 timeoutSeconds: 1 successThreshold: 1 failureThreshold: 5 affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: ["coe-rest-api"] topologyKey: failure-domain.beta.kubernetes.io/zone - weight: 1 podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: ["coe-rest-api"] topologyKey: kubernetes.io/hostname --- ################################# # Service ################################# apiVersion: v1 kind: Service metadata: name: coe-rest-api-svc namespace: coe-system labels: app: coe-rest-api-svc spec: ports: - name: http port: 18081 targetPort: 18081 protocol: TCP selector: app: coe-rest-api --- ################################ # Ingress ################################# apiVersion: networking.k8s.io/v1 kind: Ingress metadata: namespace: coe-system name: coe-rest-api-ing annotations: alb.ingress.kubernetes.io/scheme: internal alb.ingress.kubernetes.io/target-type: ip alb.ingress.kubernetes.io/subnets: 'subnet-XXXXXXXXXXXXXXXXX,subnet-XXXXXXXXXXXXXXXXX' alb.ingress.kubernetes.io/security-groups: 'sg-XXXXXXXXXXXXXXXXX,sg-XXXXXXXXXXXXXXXXX' alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}]' alb.ingress.kubernetes.io/healthcheck-path: '/actuator/health/readiness' alb.ingress.kubernetes.io/success-codes: '200-399' spec: ingressClassName: alb rules: - http: paths: - path: / pathType: Prefix backend: service: name: coe-rest-api-svc port: number: 18081
Argo CDで同期。
↓
正常に各リソースがデプロイされました。
>kubectl get po,svc,ing -n coe-system NAME READY STATUS RESTARTS AGE pod/coe-rest-api-86886fcc5c-pnrk5 1/1 Running 0 74s pod/coe-rest-api-86886fcc5c-vm48l 1/1 Running 0 74s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/coe-rest-api-svc ClusterIP 172.20.229.49 <none> 18081/TCP 74s NAME CLASS HOSTS ADDRESS PORTS AGE ingress.networking.k8s.io/coe-rest-api-ing alb * internal-k8s-coesyste-coeresta-7aca3ea431-721558692.ap-northeast-1.elb.amazonaws.com 80 74s
ACKを使用して、DynamoDBにデータを書き込むLambdaをデプロイします。
以下のマニフェストを作成し、BitBucketのリポジトリへPush後、Argo CDよりデプロイします。
※Lambdaの実行ロールもACKで作成します
################################# # Role ################################# apiVersion: iam.services.k8s.aws/v1alpha1 kind: Role metadata: name: irl-coe-val-stg0-lambda namespace: coe-system spec: assumeRolePolicyDocument: > { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" ] }, "Action": [ "sts:AssumeRole" ] } ] } description: "role for coe lambda function.." name: coe-function-role policies: - arn:aws:iam::aws:policy/AWSLambda_FullAccess - arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess - arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess - arn:aws:iam::aws:policy/CloudWatchLogsFullAccess --- ################################# # Function ################################# apiVersion: lambda.services.k8s.aws/v1alpha1 kind: Function metadata: name: lmdf-coe-val-stg0-dkr namespace: coe-system spec: name: coe-function packageType: Image code: imageURI: XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/coe-function-repo:0.0.1 ←ECRリポジトリへPushしたイメージ role: arn:aws:iam::XXXXXXXXXXXX:role/coe-function-role ←上記Role名 memorySize: 512 timeout: 15
Argo CDで同期。
↓
以下の通り、正常にLambda関数がデプロイされました。
Lambda実行ロール
Lambda関数
※注意
今回のユースケースでは、S3イベントによりLambda関数をキックできるようにLambda設定にリソースベースポリシーの適用が必要ですが、ACKのLambdaはまだ「Preview」の為、「Lambda::Permission」リソースが使用できません。その為、今回は以下の通り手動で設定しました。
その他AWSサービス
前項までに未デプロイのAWSサービス(S3/DynamoDB/API Gateway)をACKを使用してデプロイしていきます。
手順は前項のECR等と同様の為、適用したマニフェストと作成された実リソースのみ掲載します。
S3
マニフェスト
※S3イベントでLambdaをキックするユースケースの為「notification」の設定が必要
# s3-bucket.yaml ################################# # Bucket ################################# apiVersion: s3.services.k8s.aws/v1alpha1 kind: Bucket metadata: name: s3-coe-val-stg0-bucket namespace: coe-system spec: name: coe-items-bucket notification: lambdaFunctionConfigurations: - events: - s3:ObjectCreated:Put lambdaFunctionARN: arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:coe-function ←前項で作成したLambda関数名
S3バケット
DynamoDB
マニフェスト
※ハッシュキーのみの単純なテーブルです
################################# # Table ################################# apiVersion: dynamodb.services.k8s.aws/v1alpha1 kind: Table metadata: name: ddbt-coe-val-stg0 namespace: coe-system spec: attributeDefinitions: - attributeName: id attributeType: S billingMode: PAY_PER_REQUEST keySchema: - attributeName: id keyType: HASH tableName: coe-ddbt-table
DynamoDB テーブル
API Gateway
API GatewayはALBを経由してPod(REST API)とPrivate統合で連携します。
Understanding VPC links in Amazon API Gateway private integrations
※上記ブログより引用
マニフェスト
※上記の通りPrivate統合としたい為「VPC Link」も作成しています
################################# # API ################################# apiVersion: apigatewayv2.services.k8s.aws/v1alpha1 kind: API metadata: name: agw-coe-val-stg0-api namespace: coe-system spec: name: agw-coe-api protocolType: HTTP --- ################################# # Integration ################################# apiVersion: apigatewayv2.services.k8s.aws/v1alpha1 kind: Integration metadata: name: itg-coe-val-stg0-api namespace: coe-system spec: apiRef: from: name: agw-coe-val-stg0-api connectionType: VPC_LINK connectionRef: from: name: vpcl-coe-val-stg0-api integrationType: HTTP_PROXY integrationURI: arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXXXXXX:listener/app/k8s-coesyste-coeresta-7aca3ea431/f436e085bb226b51/755ccd3f2fceb1ce ←リスナーARN(※1) integrationMethod: POST payloadFormatVersion: "1.0" --- ################################# # VPCLink ################################# apiVersion: apigatewayv2.services.k8s.aws/v1alpha1 kind: VPCLink metadata: name: vpcl-coe-val-stg0-api namespace: coe-system spec: name: vpcl-coe-api securityGroupIDs: - sg-XXXXXXXXXXXXXXXXX subnetIDs: - subnet-XXXXXXXXXXXXXXXXX - subnet-XXXXXXXXXXXXXXXXX --- ################################# # Route ################################# apiVersion: apigatewayv2.services.k8s.aws/v1alpha1 kind: Route metadata: name: rte-coe-val-stg0-api namespace: coe-system spec: apiRef: from: name: agw-coe-val-stg0-api routeKey: POST /api/v1/items targetRef: from: name: itg-coe-val-stg0-api --- ################################# # Stage ################################# apiVersion: apigatewayv2.services.k8s.aws/v1alpha1 kind: Stage metadata: name: stg-coe-val-stg0-api namespace: coe-system spec: apiRef: from: name: agw-coe-val-stg0-api stageName: $default autoDeploy: true description: "auto deployed stage for agw-coe-val-stg0-api"
※1
VPC Link経由の通信となる為、上記マニフェストのIntegrationリソース「integrationURI」は前項で作成したALBのリスナーARNを指定します。
※注意
執筆時点では、ACKは「REST_APIタイプ」をサポートしておりません。作成しようとすると以下の通りのエラーとなりますのでご注意ください。
ERROR controller.api Reconciler error {"reconciler group": "apigatewayv2.services.k8s.aws", "reconciler kind": "API", "name": "agw-coe-val-stg0-api", "namespace": "coe-system", "error": "BadRequestException: Invalid protocol specified. Must be one of ["HTTP, WEBSOCKET]"}
今回は「HTTP_API」タイプを使用しています。
API
VPC Link
ルート/統合
ステージ
以上で構築完了です。
全てデプロイ完了すると、Argo CD上では全てのリソースが「Synced」となります。
アプリケーションの実行
構築したアプリケーションが正常に動作するかを確認します。
以下の通りの特定の端末からCurlでリクエストしてみます。
curl -v -X POST -H "Content-Type: application/json" -d "{\"item1\":\"001\",\"item2\":\"002\",\"item3\":\"003\",\"item4\":\"004\",\"item5\":\"005\"}" https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/api/v1/items
作成したS3バケットにリクエストしたJSONが想定通り保存されました。
また、作成したDynamoDBのテーブルにJSONデータが正常に登録されました。
以上の通り、AWSリソースを個別で作成することなく、アプリケーションの実行に必要なリソースをマニフェストのみで作成することができました。Argo CD等のGitOpsツールを使用することで状態の可視化も簡単に行えました。
さいごに
昨今、日々刻々と変化するビジネス要求に対応する為に、アプリケーションに対する変更要求は短期間で発生し続けます。その要求に迅速に対応していく為には、アプリケーションレイヤのみでなく、インフラレイヤも同時に迅速かつ臨機応変に対応していかなければなりません。
EKSを採用しているシステムにおいて、ACKはCDKやTerraformにはない迅速性、リコンサイルによる整合性担保などを備えており開発アジリティ向上に向けた優れたツールだと思います。
まだまだ開発途上で課題も多いですが、今後のアップデートを期待しながら、採用検討を進めていきたいと思います。
以上