
EKSでWeave Fluxを使ってGitOpsしてみる
この記事は公開されてから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できました。
どなたかのお役に立てば幸いです。











