EKSでWeave Fluxを使ってGitOpsしてみる
おはようございます、もきゅりんです。
最近は故あって、空いた時間をひたすら Amazon EKS Workshop に費やしております。
非常にコンテンツがボリューミーで中身が濃いです。
そのコンテンツの中から、GITOPS WITH WEAVE FLUXをやってみた、というものです。多少の行間を埋めるように心掛けました。
元々は、こちらのブログの内容かと思います。
Deploying GitOps with Weave Flux and Amazon EKS
今回やることの趣旨を簡単に述べると、Gitのみをソースとして、EKSにContinuous Delivery(以下CD。継続的なデリバリ)する、という内容です。
よく似たツールに Argo CD があります。
弊社記事でも紹介されています。
Argo CDと同様、Pull型の同期です。
用語
EKS Workshopでは章が進むにつれて順次、用語や概念、ツールが増えていきます。したがって、途中から参入した場合に、よくわからない単語がいきなり出てくることもあると思いますので、今回出てくる用語を簡単に説明しておきます。なお、AWSの基本的な用語は既知であるとします。
GitOps
Weaveworks が提唱するCDの手法。開発者にとって、馴染み深いGitのみを信頼できるソースとして利用してクラスターにデプロイするので、容易であるという考え方に基づく。
Helm
Helm とは、Chartと呼ばれる、複数のKubernetes(以下、k8s)リソース一式(下記のManifest)を管理・共有できるツールです。HelmとChartを用いて、k8sクラスタにアプリケーションを構築します。誤解を恐れず述べれば、アプリケーションの持ち運びや管理を容易にできるツール、というイメージ。
Manifest
k8sで利用するリソース設定ファイル。yml, yaml, json形式どちらでも利用できますが、自分はこれまでjsonで書かれたものを見たことありません。AWSで使われるCloudFormationのテンプレートと同じようなもの。
Custom Resource Definition
k8sには、DeploymentやPodといったリソースが元々ありますが、自身でそのようなリソースを定義して機能を拡張することができます。Workshopにも CUSTOM RESOURCE DEFINITION チャプターがあります。
概略図
今回実行するCI/CDの図です。
上下のGitHubで、それぞれアプリケーションのリポジトリと、Manifestファイルのリポジトリとが分かれて管理されています。
またECRに対しての矢印に注目すると、Weave Fluxの方からPullしているのが分かります。
環境の準備について
基本的には、GETTING STARTEDに沿って進めています。
Cloud9(EC2/t2.micro/Amazon Linux2)で作業します。
INSTALL KUBERNETES TOOLSでは、version1.13.7のkubectlのインストールですが、自分はv1.14.8でインストールしました。(Serverのバージョンに合わせた) *1
LAUNCH USING EKSCTLの通りに進めます。
Helmからhelm CLIのインストールまで対応します。
これでようやく準備が整いました。
CodePipelineで使うS3バケットおよび各種IAM Roleを作成する
自身のアカウントIDを用いた名前のS3バケットを作成します。 CodePipelineのIAMロール、CodeBuidのIAMロールのポリシー定義を取得して、AWS CLIを使って、それぞれロールに設定してあげます。
# Use your account number below ACCOUNT_ID=$(aws sts get-caller-identity | jq -r '.Account') aws s3 mb s3://eksworkshop-${ACCOUNT_ID}-codepipeline-artifacts cd ~/environment wget https://eksworkshop.com/weave_flux/iam.files/cpAssumeRolePolicyDocument.json aws iam create-role --role-name eksworkshop-CodePipelineServiceRole --assume-role-policy-document file://cpAssumeRolePolicyDocument.json wget https://eksworkshop.com/weave_flux/iam.files/cpPolicyDocument.json aws iam put-role-policy --role-name eksworkshop-CodePipelineServiceRole --policy-name codepipeline-access --policy-document file://cpPolicyDocument.json wget https://eksworkshop.com/weave_flux/iam.files/cbAssumeRolePolicyDocument.json aws iam create-role --role-name eksworkshop-CodeBuildServiceRole --assume-role-policy-document file://cbAssumeRolePolicyDocument.json wget https://eksworkshop.com/weave_flux/iam.files/cbPolicyDocument.json aws iam put-role-policy --role-name eksworkshop-CodeBuildServiceRole --policy-name codebuild-access --policy-document file://cbPolicyDocument.json
GitHubで2つのリポジトリの準備とaccess tokenを発行する
Dockerイメージにbuildされるアプリケーションのリポジトリと、Manifestを管理するリポジトリをそれぞれ作成します。今回はCloud9上で対応するため、Publicリポジトリで進めています。
また、CodePipelineがBuildするために、リポジトリにアクセスするためのaccess tokenを発行します。GitHub右上のアイコンからSettings > Developer settings > Personal access tokensです。
判別できる名前を付けて下図の通りに発行します。
Helmを使ってWeave FluxをEKSにデプロイする
Get started with Flux using Helmの通り進めます。
Flux Custom Resource Definitionをインストールします。
kubectl apply -f https://raw.githubusercontent.com/fluxcd/flux/helm-0.10.1/deploy-helm/flux-helm-release-crd.yaml
Tiller *2がインストールされているか確認します。
helm ls
Error: could not find tiller
が表示された場合は、INSTALL HELM CLIに戻りましょう。
Fluxをインストールします。
YOURUSER
とk8s-config
は、それぞれGitHubの使用名とリポジトリ名で置き換えて下さい。
helm repo add fluxcd https://charts.fluxcd.io helm upgrade -i flux \ --set helmOperator.create=true \ --set helmOperator.createCRD=false \ --set [email protected]:YOURUSER/k8s-config \ --namespace flux \ fluxcd/flux
名前空間fluxのpodを確認します。
$ kubectl get pods -n flux NAME READY STATUS RESTARTS AGE flux-5c678b8944-gg756 1/1 Running 0 95s flux-helm-operator-6877b9f564-j2dmp 1/1 Running 0 95s flux-memcached-88db78d9d-h57rc 1/1 Running 0 95s
fluxctl をインストールして、sshキーを発行します。それをManifest用に作成したGitHubリポジトリのデプロイキーとして登録します。
sudo wget -O /usr/local/bin/fluxctl https://github.com/fluxcd/flux/releases/download/1.14.1/fluxctl_linux_amd64 sudo chmod 755 /usr/local/bin/fluxctl fluxctl version
fluxctlは、デフォルトで名前空間"default"にポートフォワーディングします。--k8s-fwd-ns
を付けることで指定した名前空間に設定することができます。
fluxctl identity --k8s-fwd-ns flux ssh-rsa XXXXZ3NzaY1yc2EXXXXDXQXZXXXZXQYwXHtlWwXLipgktMbGuLQco9wqyYt0g5g5pO+28kdeakqn0uWYr7O9z0vb7K7eViS4R8agX/LPizGpFYLG0tDazwNWFyLM4RnvXQYRhiVEYFPZuIYHKoao8FiyYoZ588GLRGXDw3hkyfK17r1kxXqDdXWJ5HerrnLHe1UtXXLPljen2xFeijbxfPmHXM8/Oq3lm5aMNJ36vhOtqUgvnXiFUbn9Ua16pj1eouZeh2LNPGPzTTtYw5XDh/Mpswojoi5UGwn4RxDYGveN9K4TVpUJ4dbSYV4MoYE+IEy7TGIJVz0Z5SyeayYIWXnEOo+1JPbL5YDjd2S7GZKYkhjWWm2L
Keyの箇所に貼り付けます。
こうすることで、更新されたGitHubリポジトリにアクセスすることが可能となり、FluxはGitHubの構成とk8sクラスターにデプロイされた構成とを同期します。
CFnテンプレートでCodePipelineを構築する
記載された通りに項目を埋めてスタックを作成します。ECR、CodeBuildProject、CodePipelineを作成します。
アプリケーション用のGitHubにgit pushする
まずはgit cloneします。YOURUSER
はGitHubユーザ名です。
git clone https://github.com/YOURUSER/eks-example.git cd eks-example
nginxのファイルとDockerfileを取得してpushします。 ビルドの進捗が見えるように、CodePipelineの画面を開いておきましょう。
echo "# eks-example" > README.md mkdir src wget -O src/hello.conf https://eksworkshop.com/weave_flux/app.files/hello.conf wget -O src/index.html https://eksworkshop.com/weave_flux/app.files/index.html wget https://raw.githubusercontent.com/aws-samples/eks-workshop/master/content/weave_flux/app.files/Dockerfile tree . ├── Dockerfile ├── README.md └── src ├── hello.conf └── index.html git add . git commit -am "Initial commit" git push
ECRにもちゃんとDockerイメージが格納されています。
Manifestを使ってデプロイする
つぎに、Manifest用のリポジトリをgit cloneします。
cd .. git clone https://github.com/YOURUSER/k8s-config.git cd k8s-config mkdir namespaces workloads
そしたらManifestファイルを作成していきます。イメージ名はECRに作成されたもので更新してください。
なお、latest
タグを付けておかないとデフォルトではlatestになりません。
cat << EOF > namespaces/eks-example.yaml apiVersion: v1 kind: Namespace metadata: labels: name: eks-example name: eks-example EOF cat << EOF > workloads/eks-example-dep.yaml --- apiVersion: apps/v1 kind: Deployment metadata: name: eks-example namespace: eks-example labels: app: eks-example annotations: # Container Image Automated Updates flux.weave.works/automated: "true" # do not apply this manifest on the cluster #flux.weave.works/ignore: "true" spec: replicas: 1 selector: matchLabels: app: eks-example template: metadata: labels: app: eks-example spec: containers: - name: eks-example image: YOURACCOUNT.dkr.ecr.us-east-1.amazonaws.com/eks-example:YOURTAG imagePullPolicy: IfNotPresent ports: - containerPort: 80 name: http protocol: TCP livenessProbe: httpGet: path: / port: http readinessProbe: httpGet: path: / port: http EOF cat << EOF > workloads/eks-example-svc.yaml apiVersion: v1 kind: Service metadata: name: eks-example namespace: eks-example labels: app: eks-example spec: type: LoadBalancer ports: - port: 80 targetPort: http protocol: TCP name: http selector: app: eks-example EOF tree . ├── namespaces │ └── eks-example.yaml ├── README.md └── workloads ├── eks-example-dep.yaml └── eks-example-svc.yaml
flux.weave.works/automated
は、コンテナイメージを自動で更新するかどうかを設定します。flux.weave.works/ignore
はdeploymentをしないように設定できるようです。
デフォルトの設定では、5分間ごとにGitHubの構成を自動Pullします。
git pushします。
git add . git commit -am "eks-example-deployment" git push
fluxのpodのログから確認します。
kubectl get pods -n flux kubectl logs flux-5c678b8944-gg756 -n flux kubectl describe service eks-example -n eks-example
エンドポイントにアクセスすると、こんな感じのが表示されます。
次に、index.htmlを更新してみます。
cd ../eks-example vi src/index.html # Change the <title> AND <h> to Demo Flux with GitOps git commit -am "v2 Updating home page" git push
自動で更新されます。 *3
Helmでデプロイする
今度ではHelmで対応します。 *4
mkdir namespaces releases
Manifestファイルを作成します。
cat << EOF > namespaces/nginx.yaml apiVersion: v1 kind: Namespace metadata: labels: name: nginx name: nginx EOF cat << EOF > releases/nginx.yaml --- apiVersion: flux.weave.works/v1beta1 kind: HelmRelease metadata: name: mywebserver namespace: nginx annotations: flux.weave.works/automated: "true" flux.weave.works/tag.nginx: semver:~1.16 flux.weave.works/locked: 'true' flux.weave.works/locked_msg: '"Halt updates for now"' spec: releaseName: mywebserver chart: repository: https://charts.bitnami.com/bitnami/ name: nginx version: 3.3.2 values: usePassword: true image: registry: docker.io repository: bitnami/nginx tag: 1.16.0-debian-9-r46 service: type: LoadBalancer port: 80 nodePorts: http: "" externalTrafficPolicy: Cluster ingress: enabled: false livenessProbe: httpGet: path: / port: http initialDelaySeconds: 30 timeoutSeconds: 5 failureThreshold: 6 readinessProbe: httpGet: path: / port: http initialDelaySeconds: 5 timeoutSeconds: 3 periodSeconds: 5 metrics: enabled: false EOF tree ├── namespaces │ └── nginx.yaml ├── README.md └── releases └── nginx.yaml
タグやLockなどのCRDが付記されているのが分かります。
そしたらpushします。
git add . git commit -am "Adding nginx helm release" git push
確認します
kubectl get pods -n flux kubectl logs flux-5c678b8944-gg756 -n flux helm ls kubectl get all -n nginx
エンドポイントにアクセスするといつものやつが出ます。
以上です。
なお、検証後は、くれぐれも後片付けに留意して下さいまし!
最後に
GitOps、確かに分かりやすいです。
思った以上にかなり楽にCI/CDできました。
どなたかのお役に立てば幸いです。