GitOpsのCI環境を構築する

# 内容

会社の業務でk8sを使用したGitOps([参考リンク](https://www.1915keke.com/entry/2018/12/15/034843))を実現する為にCI/CDのCI側の実装をcircleciで行ったのでその内容を残します

※ 本記事はAmazon ECR・EKSの使用を想定しておりGKE等の他のクラウドを使ったk8s運用には少し外れる内容になることご了承ください。

## 対象者

- これから会社にk8sを導入しciの選定をしている方
- コンテナ自体初めてでcircleciからpushをするのも初めてな方(ECS運用にも使える部分はあります)

## ECRへのpush

先ずはECRへのpushを先に実装します

circleciにはorbという便利なものがありECRもそれに対応しているのでそれを使用します。
https://circleci.com/orbs/registry/orb/circleci/aws-ecr

今回ですが2つのjobを用意しました
詳細に関しては別の記事にも参考になるものがございますのでそちらをご参照ください
こちらがとてもわかりやすいです
https://qiita.com/nyasba/items/517c0d6b15600bf774b5

```yaml
workflows:
  build_and_push_image_dev:
    jobs:
      - aws-ecr/build-and-push-image:
          account-url: AWS_ECR_ACCOUNT_URL
          aws-access-key-id: AWS_ACCESS_KEY_ID
          aws-secret-access-key: AWS_SECRET_ACCESS_KEY
          region: AWS_DEFAULT_REGION
          repo: '${DEV_ECR_REPO}'
          tag: '${CIRCLE_SHA1}'
          path: .
          filters:
            branches:
              only: 
                - master
            
  build_and_push_image_prod:
    jobs:
      - aws-ecr/build-and-push-image:
          account-url: AWS_ECR_ACCOUNT_URL
          aws-access-key-id: AWS_ACCESS_KEY_ID
          aws-secret-access-key: AWS_SECRET_ACCESS_KEY
          region: AWS_DEFAULT_REGION
          repo: '${PROD_ECR_REPO}'
          tag: '${CIRCLE_TAG}'
          path: ./poc/
          filters:
            tags:
              only:
                - /^v[0-9](\.[0-9]){2}$/
            branches:
              ignore: /.*/
```

```
 build_and_push_image_dev:
```

こちらですがmaster branchにpush(merge)された際にjobが走ることを想定しています。


```
build_and_push_image_prod:
```

こちらはGithubにバージョンtagをつけた際に発火するjobです、production環境にリリースする際にはこちらのjobでdocker image tagにgit version tagをつけてECRにpushしています。

ECRへのpushはここまでです。

## image tagの更新

ここからはk8sのmanifestのdocker image tagの更新をします

kustomizeを使用してmanifestファイルの管理をしています
https://qiita.com/ryodocx/items/008fdaf5c68678656749

`k8s/overlays/dev/bases/kustomization.yaml`という構造になっていて
`kustomization.yaml`のファイルはこのようになっています

```yaml
~省略~

images:
  - name: nginx
    newTag: 1.15.2
  - name: XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/backend-admin
    newName: 767177527229.dkr.ecr.ap-northeast-1.amazonaws.com/backend-admin
    newTag: latest
  - name: XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/frontend-admin
    newName: 767177527229.dkr.ecr.ap-northeast-1.amazonaws.com/frontend-admin
    newTag: latest
```

今回は`backend-admin`というところの`newTag`を更新していきます

circleciで実装していきます

```yaml
jobs:
  create-pull-request:
    docker:
      - image: circleci/python:3.7.4-stretch
    environment:
      PR_TEMPLATE: ./github/PULL_REQUEST_TEMPLATE.md
    steps:
      - checkout
      - run:
          name: install hub
          command: |
            curl -sSLf https://github.com/github/hub/releases/download/v2.8.3/hub-linux-amd64-2.8.3.tgz | \
            tar zxf - --strip-components=1 -C /tmp/ && \
            sudo mv /tmp/bin/hub /usr/local/bin/hub
            hub --version
      - run:
          name: install yq
          command: |
            sudo pip install --upgrade pip
            sudo pip install yq
      - run:
          name: git clone commit push create pull request
          command: |
            git config --global user.name ${GITHUB_NAME}
            git config --global user.email ${GITHUB_EMAIL}
            git clone https://${GITHUB_NAME}:${GITHUB_TOKEN}@github.com/username/appname.git
            cd appname
            git init
            git checkout -b feature-backend-admin-${CIRCLE_SHA1}
            yq -y -i '.images |= map(select(.name=="XXXXXXXXXXXX.dkr.ecr.リージョン.amazonaws.com/backend-admin").newTag |= "'$CIRCLE_SHA1'")' k8s/overlays/dev/bases/kustomization.yaml
            git add .
            git commit -m "feature-backend-admin-${CIRCLE_SHA1}"
            git push --set-upstream origin feature-backend-admin-${CIRCLE_SHA1}
            hub pull-request -F $PR_TEMPLATE -m "[image update] backend-admin ${CIRCLE_SHA1}"

```

先に全ての実装を載せました。

やっていることを説明します

```yaml
- run:
    name: install hub
    command: |
      curl -sSLf https://github.com/github/hub/releases/download/v2.8.3/hub-linux-amd64-2.8.3.tgz | \
     tar zxf - --strip-components=1 -C /tmp/ && \
     sudo mv /tmp/bin/hub /usr/local/bin/hub
```

こちらは最後のPRを出すための[hub](https://dev.classmethod.jp/tool/git/hub/)というツールをinstallしています

```yaml
- run:
   name: install yq
   command: |
     sudo pip install --upgrade pip
     sudo pip install yq
```

こちらはmanifestのyamlをいじる為に[yq](https://dev.classmethod.jp/tool/yq/)というツールのinstallをしています

```yaml
- run:
    name: git clone commit push create pull request
    command: |
    git config --global user.name ${GITHUB_NAME}
    git config --global user.email ${GITHUB_EMAIL}
    git clone https://${GITHUB_NAME}:${GITHUB_TOKEN}@github.com/username/appname.git
    cd appname
    git init
    git checkout -b feature-backend-admin-${CIRCLE_SHA1}
    yq -y -i '.images |= map(select(.name=="XXXXXXXXXXXX.dkr.ecr.リージョン.amazonaws.com/backend-admin").newTag |= "'$CIRCLE_SHA1'")' k8s/overlays/dev/bases/kustomization.yaml
    git add .
    git commit -m "feature-backend-admin-${CIRCLE_SHA1}"
    git push --set-upstream origin feature-backend-admin-${CIRCLE_SHA1}
    hub pull-request -F $PR_TEMPLATE -m "[image update] backend-admin ${CIRCLE_SHA1}"
```

こちらですがコマンドのままなのですがgit cloneでmanifestのリポジトリをcloneしてそこからbranchを切り、manifestのimage tagの更新を

```sh
yq -y -i '.images |= map(select(.name=="XXXXXXXXXXXX.dkr.ecr.リージョン.amazonaws.com/backend-admin").newTag |= "'$CIRCLE_SHA1'")' k8s/overlays/dev/bases/kustomization.yaml
```

で行っています
参考 https://qiita.com/mafuyuk/items/d6b62c25691a4ca29aba

最後に最初にinstallしたhubでPull Requestを送るとGitHub側にPull Requestが上がります。

branch名や`${${CIRCLE_SHA1}}`の部分は好きなものにしていただいて構いません。

異常がcircleciでのGitOpsにおけるCIの部分の実装でした。


この実装にテストを加えることにより、GitHubからPushするだけで自動でテスト、Docker imageのpush manifest側にdocker imageの更新のPull Requestが送れるのでスムーズな運用が可能になります。
k8sを運用しようと検討したり運用方法に戸惑っている開発者の方もいらっしゃると思いますので参考になれば幸いです。

次はCD側の実装について記事を書こうと思います


## 参考にした記事、サイト
https://circleci.com/orbs/registry/orb/circleci/aws-ecr
https://qiita.com/nyasba/items/517c0d6b15600bf774b5
https://qiita.com/ryodocx/items/008fdaf5c68678656749
https://dev.classmethod.jp/tool/git/hub/
https://dev.classmethod.jp/tool/yq/
https://qiita.com/mafuyuk/items/d6b62c25691a4ca29aba