この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
おはようございます、もきゅりんです。
最近は故あって、空いた時間をひたすら 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 git.url=git@github.com: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できました。
どなたかのお役に立てば幸いです。