FluxでGitOpsフローを構築してリリースした話

# どういう話
先日リリースされたサービスで、自分がインフラとそれに付随するデプロイフローを構築したので、その備忘録。

あと、k8s周りを調べるとハンズオンが結構多かった印象だったので、実際にリリースまでしたものをアウトプットしたかった。

# 前提
Fargateを利用していますが、Fargate特有の話はあまりないです。
アプリケーションコードはGitHub, インフラコードはCodeCommitで管理しています。

※インフラコードをCodeCommitで管理している理由は、コード上に時々必要になる12桁のAWSIDは秘匿情報と考えており、
これを(privateとはいえ)GitHub上のリポジトリで管理するのは得策ではないと考えたためです。
CodeCommit上であれば、そもそもCodeCommitにアクセスするのにAWSの認証が必要なので安全であると考えています。
Fargateでは当時kubernetes-external-secretsなどを使うことができなかったための苦肉の策です。

## 出てくるもの

[Flux](https://github.com/fluxcd/flux) GitOpsフローを構築するのに使っています(メインの話)
[FluxCloud](https://github.com/justinbarrick/fluxcloud) FluxからのイベントをキャッチしSlackに通知するためにつかってます
[CircleCI](https://circleci.com/) CIとして使ってます
## GitOpsって何？
WeaveWorksが提唱するデプロイフローです。

[Guide To GitOps](https://www.weave.works/technologies/gitops/)
[コマンドラインツールを用いずにCI/CDを行うGitOpsとは？
](https://thinkit.co.jp/article/14164)

超絶簡単に言うと、"全ての変更はGit上のコードとして履歴が管理される"フローです。

# デプロイフロー
メインの話です。
GitOpsを提唱しているWeaveWorksが開発しているFluxを用いたフローを構築しました。

### アプリケーションコードの場合
![85833815-4a3e5880-b7cd-11ea-9e42-056fea792991.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475927/7ee90d21-9731-bd9f-f054-7ce2ce9954bf.png)

1. githubにアプリケーションコードをcommitする
2. CicleCIがECRにイメージをpush
3. イメージのpushを検知したfluxがCodeCommit上のmanifestファイルを更新してcommit
4. 更新されたmanifestファイルを元にfluxがk8sクラスターを更新する

### インフラ(k8s)コードの場合
![85834239-fed87a00-b7cd-11ea-8444-b523fd8dc758.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475927/576a967d-8f1d-e2fb-ecf1-cd40ee662f4f.png)

1. CodeCommitにcommitする
2. commitをfluxが検知し、manifestファイルを元にk8sクラスターを更新する

## Flux設定
Fluxのdeployment.ymlは最初から色々なものが書かれていますが、触ったところは大きく2つです。

1. gitリポジトリとECR設定

```deployment.yml
args:
- --git-url=ssh://********************@git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/*********
- --git-branch=master
- --git-path=k8s/production
- --git-label=flux
- --git-user=flux
- --git-email=flux@example.com
- --registry-ecr-region=ap-northeast-1
- --registry-ecr-exclude-id=[]
```

2. fluxcloud設定

```deployment.yml
args:
- --connect=ws://fluxcloud
```

## デプロイ方法
### staging
developブランチにpushされると自動でstaging環境にデプロイされます。

```.circleci/config.yml
register_staging_image:
  jobs:
    - aws-ecr/build-and-push-image:
        executor:
          name: aws-ecr/default
          use-docker-layer-caching: true
        account-url: ECR_URL
        create-repo: false
        dockerfile: .dockerenv/Dockerfile.production
        path: .
        region: AWS_DEFAULT_REGION
        repo: STG_REPO_NAME
        tag: "${CIRCLE_SHA1}"
        filters:
          branches:
            only: develop
```
### production
github上でmasterブランチに対してリリースタグを打つとproduction環境にデプロイされます。

リリースバージョンは1.0.0や1.0.0.0.1など、数字とピリオドの組み合わせのみにしてあります。

```.circleci/config.yml
register_production_image:
  jobs:
    - aws-ecr/build-and-push-image:
        executor:
          name: aws-ecr/default
          use-docker-layer-caching: true
        account-url: ECR_URL
        create-repo: false
        dockerfile: .dockerenv/Dockerfile.production
        path: .
        region: AWS_DEFAULT_REGION
        repo: PRD_REPO_NAME
        tag: "${CIRCLE_TAG}"
        filters:
          branches:
            ignore: /.*/
          tags:
            only: /[0-9]+(\.[0-9]+)+/
```

## ロールバック
FluxがcodeCommit上の変更を検知してk8sクラスターを更新してくれるので、
codeCommit上で目当てのバージョンまでrevertするか、イメージタグを変更してcommitすると変更できます。
## デプロイ通知
FluxCloudを用いてwebhookを通じてSlackにデプロイ通知を送信しています。

```deployment.yml
        - name: SLACK_URL
          value: "https://hooks.slack.com/services/******/**********/**************"
        - name: SLACK_CHANNEL
          value: "channel"
        - name: SLACK_USERNAME
          value: "Production Deployment"
        - name: SLACK_ICON_EMOJI
          value: ":kyaru-chan:"
        - name: GITHUB_URL
          value: "https://ap-northeast-1.console.aws.amazon.com/codesuite/codecommit/repositories/**********"

```

# 総括
少し前まではcapistranoなどを使って手作業でデプロイしていたので、相当楽で便利になりました。
このフローを最初に作ってしまえばエンジニアは開発に集中できるし、デザイナーやコーダーといった方のコミットでも自動でstagingにデプロイされるので、ある意味エンジニアを開放しているのかもしれないです。

アプリケーション周りも頑張ったのでそっちも書くかもしれません