この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
「Flux でCloudFormationをデプロイ! CloudFormationでもPull型のGitOpsが始まる!?」
Fluxを使用して、CloudFormationをデプロイできるようになりました。
以下のアップデートの紹介ブログです。
Introducing the AWS CloudFormation Template Sync Controller for Flux
Fluxとは
Gitリポジトリで宣言された状態とKubernetesクラスタの状態を同期するツールです。
類似のツールとしては、Argo CDなどがあげられます。
CDに使われるツールでGitリポジトリ上のコードが変更されたら、自動的にクラスターにデプロイすることができます。
「GitHub ActionsやAWSのCodeシリーズなどのCI/CDツールと何が違うの?」と思う方もいるかもしれません。
FluxやArgo CDなどはGitOpsツール(Pull型)と言われます。(Github Actions等はCIOps(Push型))
リポジトリへのPushをトリガーにするわけではなく、FluxがKubernetesクラスター上でGitリポジトリの変更をポーリング(Pull)して変更があったら反映(デプロイ)するためです。
CIOpsとGitOpsについては、以下の記事の説明が分かりやすいです。
CIOpsとGitOpsの話 - inductor's blog
何が嬉しい?
CloudFormationをFluxで管理できることで、以下のようなメリットがあります。
- 正しい設定にリソースを保ちやすい
- KubernetesとCloudFormationのCDを1つのツールで行える
- CD用の権限をAWS外部に渡す必要がない
正しい設定にリソースを保ちやすい
Push型のCIOpsでは、CloudFormationが実行されるのはトリガー時(特定ブランチへのPush等)だけです。
もし手動でAWSリソースが変更された場合、次のPushまではAWSリソースとコードの状態が一致しません。
しかし、Pull型のGitOpsは定期的にGitリポジトリをPollingします。
Gitリポジトリの状態を正として、リソースに差分があればGitリポジトリで定義されている状態に変更します。
リソースを正しい設定状態に保ちやすいのがメリットだと思います。
KubernetesとCloudFormationのCDを1つのツールで行える
既にFluxを使用していてかつ、CloudFormationも使っている場合、CloudFormation用にCDの仕組みを作らなくても、FluxにCDを統一できるメリットもあります。
CD用の権限をAWS外部に渡す必要がない
Pull型のGitOpsのメリットとして、認証情報を外部に渡す必要がないというのも挙げられます。
Github ActionsやCircle CI等でCloudFormationのデプロイを行う場合は、AWS外部に認証情報を渡す必要がありました。
EKSに権限を渡せばいいので、AWS外部に認証情報を渡す必要がありません。 (Codeシリーズだったら、AWS外部に渡さないでCloudFormationデプロイは可能ですが。)
やってみる
前提条件
以下をローカルPC上で使用できるようにしておく必要があります。
構成図
FluxのCloudFormation Controllerを使用して、CloudFormation Stackを作成してみます。
CloudFormationでは、Parameter Storeを作成します。
フォルダ構成
最終的なフォルダ構成を紹介します。
CodeCommitを2つ使用します。(手順中のサンプルリソース作成用CloudFormationでデプロイします)
リポジトリ名 | 概要 |
---|---|
my-flux-configuration | Fluxマニフェストファイル保存用 |
my-cloudformation-templates | CloudFormationテンプレートファイル保存用 |
# my-flux-configuration リポジトリ
$ tree my-flux-configuration/
my-flux-configuration
├── cfn-controller-source.yaml # cfn controllerのGitリポジトリ設定
├── cfn-controller.yaml # cfn controllerデプロイ
├── cfn-stack.yaml # cfn stackデプロイ
├── cfn-templates-repo.yaml # my-cloudformation-templatesのGitリポジトリ設定
└── flux-system
├── gotk-components.yaml
├── gotk-sync.yaml
└── kustomization.yaml
# my-cloudformation-templates リポジトリ
$ tree my-cloudformation-templates/
my-cloudformation-templates
└── template.yaml # デプロイするCloudFormationテンプレート
eksctlでクラスター作成
$ eksctl create cluster \
--name flux-cfn-sample \
--region ap-northeast-1 \
--node-type t3.small \
--nodes 2
FluxのCloudFormationコントローラーがリソースを操作できるように権限を付与します。
本来なら必要な権限に絞るべきですが、検証のためPowerUserAccessを与えます。
$ eksctl utils associate-iam-oidc-provider --cluster flux-cfn-sample --approve
$ eksctl create iamserviceaccount \
--cluster flux-cfn-sample \
--namespace flux-system \
--name cfn-controller \
--role-only \
--role-name "AWSCloudFormationControllerFluxIRSARole" \
--attach-policy-arn arn:aws:iam::aws:policy/PowerUserAccess \
--approve
Fluxの設定ファイル保存用のCodeCommit等の準備
Fluxの設定ファイルやCloudFormationテンプレート等を置くCodeCommitやS3バケットを用意します。
サンプルのCloudFormationを使用して、必要なリソースを作成します。
Fluxのインストール
作成したクラスターでFluxを実行可能か確認します。
問題なければ以下のような出力があります。
$ flux check --pre
► checking prerequisites
✔ Kubernetes 1.25.3 >=1.20.6-0
✔ prerequisites checks passed
リポジトリはサンプルCloudFormationで作成されるCodeCommitを使用します。
flux-git
というIAMユーザーが作成されているため、CodeCommit認証情報を生成してflux bootstrap
を行います。
flux bootstrap git \
--url=https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/my-flux-configuration \
--branch=main \
--username=<my-username> \
--password=<my-password> \
--token-auth=true
bootstrapを実施したことで、EKSにはFluxのインストールおよび、CodeCommitにFluxを使用するために必要なファイルがpushされました。
CloudFormationコントローラリポジトリをFluxに登録する
CloudFormationコントローラーをFluxで使用できるようにするために、リポジトリをFluxに登録します。
任意のディレクトリにFluxのCodeCommitリポジトリをCloneします。
git clone codecommit::ap-northeast-1://my-flux-configuration
以下のファイルを作成して、CodeCommitにPushします。
cfn-controller-source.yaml
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: GitRepository
metadata:
name: aws-cloudformation-controller-for-flux
namespace: flux-system
spec:
interval: 1h
timeout: 60s
ref:
branch: main
url: https://github.com/awslabs/aws-cloudformation-controller-for-flux
git add .
git commit -m "add: cfn controller repo"
git push origin HEAD
Pushまでできたら、以下のコマンドを実行してFluxがリポジトリに正常に接続できることを確認します。
$ flux reconcile source git flux-system
$ flux reconcile source git aws-cloudformation-controller-for-flux
Fluxを使用してCloudFormationコントローラーをデプロイする
CloudFormationコントローラーをデプロイします。
以下のファイルを用意して、CodeCommitにPushします。
cfn-controller.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: aws-cloudformation-controller-for-flux
namespace: flux-system
spec:
interval: 5m
path: ./config/default
prune: true
wait: true
timeout: 5m
sourceRef:
kind: GitRepository
name: aws-cloudformation-controller-for-flux
patches:
- patch: |
apiVersion: v1
kind: ServiceAccount
metadata:
name: cfn-controller
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/AWSCloudFormationControllerFluxIRSARole # AWSアカウントIDを書き換える
target:
kind: ServiceAccount
name: cfn-controller
- patch: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: cfn-controller
spec:
template:
spec:
containers:
- name: manager
env:
- name: AWS_REGION
value: "ap-northeast-1"
- name: TEMPLATE_BUCKET
value: "<バケット名>" # サンプルCFnで作成したバケット名
target:
kind: Deployment
name: cfn-controller
git add .
git commit -m "add: cfn controller"
git push origin HEAD
以下のコマンドでデプロイを確認します。
$ flux reconcile source git flux-system
$ flux reconcile kustomization aws-cloudformation-controller-for-flux
$ kubectl rollout status deployment/cfn-controller -n flux-system
$ kubectl logs deployment/cfn-controller -n flux-system
CloudFormationコントローラーのFlux通知の有効化
CloudFormationコントローラーはサードパーティーコントローラーのため、以下の設定を追加して通知を有効化します。
flux-system/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- gotk-components.yaml
- gotk-sync.yaml
patches:
- patch: |
- op: add
path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/eventSources/items/properties/kind/enum/-
value: CloudFormationStack
- op: add
path: /spec/versions/1/schema/openAPIV3Schema/properties/spec/properties/eventSources/items/properties/kind/enum/-
value: CloudFormationStack
target:
kind: CustomResourceDefinition
name: alerts.notification.toolkit.fluxcd.io
- patch: |
- op: add
path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/resources/items/properties/kind/enum/-
value: CloudFormationStack
- op: add
path: /spec/versions/1/schema/openAPIV3Schema/properties/spec/properties/resources/items/properties/kind/enum/-
value: CloudFormationStack
target:
kind: CustomResourceDefinition
name: receivers.notification.toolkit.fluxcd.io
- patch: |
- op: add
path: /rules/-
value:
apiGroups: [ 'cloudformation.contrib.fluxcd.io' ]
resources: [ '*' ]
verbs: [ '*' ]
target:
kind: ClusterRole
name: crd-controller-flux-system
CloudFormationテンプレートリポジトリにテンプレートファイルをPush
CloudFormationテンプレートファイル用のリポジトリにテンプレートファイルをPushします。
このテンプレートファイルがFluxによって、デプロイされます。
$ git clone codecommit::ap-northeast-1://my-cloudformation-templates
$ cd my-cloudformation-templates
$ touch template.yaml
template.yaml
Resources:
SampleResource:
Type: AWS::SSM::Parameter
Properties:
Type: String
Value: "Hello World"
$ git add .
$ git commit -m "add: temaplte file"
$ git push origin HEAD
CloudFormation用のCodeCommitリポジトリと接続
FluxがCloudFormation用のCodeCommitリポジトリの内容を見れるように設定を行います。
bootstrap時に使用したCodeCommitの認証情報をSecretに登録します。
$ CODECOMMIT_USERNAME="<CodeCommitユーザー名>"
$ CODECOMMIT_PASSWORD="<CodeCommitパスワード>"
$ flux create secret git cfn-template-repo-auth \
--url=https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/my-cloudformation-templates \
--username=$CODECOMMIT_USERNAME \
--password=$CODECOMMIT_PASSWORD
fluxの設定リポジトリに移動して、以下のファイルを作成します。
$ cd my-flux-configuration
$ touch cfn-templates-repo.yaml cfn-stack.yaml
cfn-templates-repo.yaml
はCloudFormation用のCodeCommitリポジトリを登録します。
cfn-templates-repo.yaml
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: GitRepository
metadata:
name: my-cfn-templates-repo
namespace: flux-system
spec:
url: https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/my-cloudformation-templates
interval: 5m
ref:
branch: main
secretRef:
name: cfn-template-repo-auth
cfn-stack.yaml
では、デプロイするCloudFormation Stackの設定を行います。
このファイルで、同期の間隔やStack名などを定義します。
cfn-stack.yaml
apiVersion: cloudformation.contrib.fluxcd.io/v1alpha1
kind: CloudFormationStack
metadata:
name: my-cfn-stack
namespace: flux-system
spec:
stackName: my-cfn-stack-deployed-by-flux
templatePath: ./template.yaml
sourceRef:
kind: GitRepository
name: my-cfn-templates-repo
interval: 1h
retryInterval: 5m
destroyStackOnDeletion: true
ファイルの用意ができたら、リポジトリにPushします。
$ git add .
$ git commit -m "add: cfn stack file"
$ git push origin HEAD
動作確認: CloudFormation Stackデプロイ確認
先ほどのファイルのPushができたら、自動的にCloudFormation Stackが作成されます。
まずは、kubectl
コマンドで確認してみます。
デプロイが成功していれば、以下のような出力を確認できます。
$ kubectl describe cfnstack my-cfn-stack --namespace flux-system
Name: my-cfn-stack
Namespace: flux-system
Labels: kustomize.toolkit.fluxcd.io/name=flux-system
kustomize.toolkit.fluxcd.io/namespace=flux-system
Annotations: <none>
API Version: cloudformation.contrib.fluxcd.io/v1alpha1
Kind: CloudFormationStack
Metadata:
Creation Timestamp: 2023-05-10T08:43:54Z
Finalizers:
finalizers.cloudformation.contrib.fluxcd.io
Generation: 1
Managed Fields:
API Version: cloudformation.contrib.fluxcd.io/v1alpha1
Fields Type: FieldsV1
# 省略
マネジメントコンソールからも確認してみましょう。
Flux CDで定義したスタックmy-cfn-stack-deployed-by-flux
が確認できます。
CloudFormationを変更して、CodeCommitにPushで自動的にデプロイされるか確認します。
Parameter StoreのValueをHello World
からHello Flux CloudFormation Controller
に変更しました。
commitして、CodeCommitにPushしました。
$ git diff
diff --git a/template.yaml b/template.yaml
index 51b5e79..752a177 100644
--- a/template.yaml
+++ b/template.yaml
@@ -3,4 +3,4 @@ Resources:
Type: AWS::SSM::Parameter
Properties:
Type: String
- Value: "Hello World"
+ Value: "Hello Flux Cloudformation Controller"
少し待つと変更した値にパラメータストアの値が変わっていることを確認できました。
クリーンアップ
EKSクラスターを削除します。
$ eksctl delete cluster --name=flux-cfn-sample
まとめ
Terraform用のControllerはあったみたいですが、CloudFormationもきましたね。
How to GitOps Your Terraform | Flux
EKSの運用が必要になるので少し敷居は高いと思いますが、CloudFormationでもGitOpsが可能になるのは激アツだと思いました。
以上、AWS事業本部の佐藤(@chari7311)でした。