Code for Japanに飛び込んで、GitHub ActionsでElastic BeanstalkへのCI/CDを構築した流れ

# 背景

コロナで外出しづらくなったこともあり、以前から興味のあったCode for Japanに参加しました。

今回のプロジェクトは、Ruby on Railsでした。私は、Ruby初心者なので、コンテナやAWSまわりの足回りを固めるために活動してます。

私が、プロジェクトの参加からCI/CD構築までの流れを紹介します。興味がある方の参考になると嬉しいです。

# 3文まとめ

- Code for Japanに参加するのは簡単
- 当然だけど、AWSを触るのはNDAが必要
- GitHub ActionsでCI/CDを構築するは簡単

# Code for Japan プロジェクト参加のきっかけ

[東京都のコロナ対策サイト](https://github.com/tokyo-metropolitan-gov/covid19)で気になって、ROM専でSlackにいました。

[Slack コミュニティ - Code for Japan](https://www.code4japan.org/activity/community)から、気軽に参加できます。

たまたま、slack上でメンバーの募集を見かけ、市民の政治参加に興味があり参加しますと声を掛けました。
Ruby初心者でしたが、心よく受け入れて頂きました。笑

# 参加したDIY City プロジェクト(市民参加型合意形成プラットフォーム)

>地域で暮らす人たちや、その地域を愛する人たちが主役になり、自分たちでどんなまちにしたいのか、そのためにどんなことが必要なのかを考え、手を動かし、自分たちでつくっていく都市です。できるだけ多様な人がまちづくりに関わり、「要望する」のではなく「つくる」側として参画します。
>
>[DIY 都市を作ろう｜Hal Seki｜note](https://note.com/hal_sk/n/nb18550eae279)

上記のような構想をもとに、市区町村と協力してサービスを提供するプロジェクトです。市民が積極的に参加することで、より良い町づくりを目指します。

日本では、加古川市で2020/11から本稼働しています。

[加古川市 市民参加型合意形成プラットフォーム](https://kakogawa.diycities.jp/)

## OSS decidim

上記のサイトは、[Decidim (Free Open-Source participatory democracy for cities and organizations)](https://decidim.org/)をベースに構築されています。Ruby on railsで構築されており、これにパッチ修正をあてて稼働しています。翻訳など本家に取り込んでも問題ないものは、本家を修正しています。

このOSSで数年前から、[バルセロナ](https://www.decidim.barcelona/)や[ヘルシンキ](https://omastadi.hel.fi/?locale=en)などいくつかの複数の都市で運用されています。都市ごとに、カスタマイズされており、どれも個性的で興味深いです。

バルセロナでは、うまく軌道にのり、下記のような成果が出ているようです。

>2016年から2019年の3年間で、すでに市民の70％が登録しており、9000以上の市民からの新たな政策提案が集まっている
>
>[「シティOS」で市民に還元。バルセロナが本当にスマートな理由](https://forbesjapan.com/articles/detail/36262/3/1/1)

# NDA締結

今回、CI/CD構築のため、AWSを触るので、NDA締結が必要でした。
一般的な内容で、クラウドサインで締結しました。

※私が勤めている弁護士ドットコムのサービスを使ってくれていました。

# CI/CD概要

![GitHub Actions aws eb deploy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525723/6b02141e-870e-3341-d647-27948c3338a1.png)


既にソースコードをGitHubで管理していたので、GitHub上で完結するGitHub Actionsを採用しました。

ユーザーがGitHubにコードをcommit pushすると、GitHub ActionsでイメージをBuildして、ECRにpush。その後、AWS ECRを使用してElastic Beanstalkにデプロイする非常にシンプルなパイプラインです。

## AWS ECR作成

ECRは、Cloud Formationで作成しました。

```yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: Create ECR

Resources:
  TestEcrPoc:
    Type: AWS::ECR::Repository
    Properties:
      RepositoryName: hoge
      ImageScanningConfiguration:
        scanOnPush: "true"
      ImageTagMutability: "MUTABLE"
      LifecyclePolicy:
        LifecyclePolicyText: |
          {
            "rules": [
              {
                "rulePriority": 1,
                "description": "Delete image without tag after 7 days",
                "selection": {
                  "tagStatus": "untagged",
                  "countType": "sinceImagePushed",
                  "countUnit": "days",
                  "countNumber": 7
                },
                "action": {
                  "type": "expire"
                }
              }
            ]
          }
```

### イメージスキャン

[イメージスキャン - Amazon ECR](https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/image-scanning.html)を有効化しています。Pushするたびに、スキャンされます。


イメージスキャンは、オープンソースの[Clair](https://github.com/quay/clair)プロジェクトからCommon Vulnerabilities and Exposures(CVE)データベースを使用してスキャンし、GUI上から結果を確認できる機能です。

### ライフサイクルポリシー

タグなしのイメージだけ、7日経過後に削除するライフサイクルポリシーを設定しています。
ライフサイクルポリシーだけJSONで記述する必要があります。yamlの中なので、補完が効かず書きづらいですが、仕方がありません。

## AWS IAMユーザーの作成

Elastic Beanstalkのアクセス権だけでなく、上記で作成したECRへのReadWriteアクセスも必要です。

## GitHub Actionsで使うSecretsの設定

GitHubでは、レポジトリごとにSecretsが設定できます。

それを使用して、下記のキーで、上記で作成したIAMのアクセス情報とECRのレポジトリ名を保存します。
レポジトリ名は場合によっては、Secretsでなくてもいいと思います。

```
AWS_ACCESS_KEY_ID: *********************
AWS_SECRET_ACCESS_KEY: *********************
AWS_ECR_REPO_NAME: hoge
```

## AWS ECRへのイメージのpush

```.github/workflows/deploy.yml
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1

      - name: Build, tag, and push image to Amazon ECR
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: ${{ secrets.AWS_ECR_REPO_NAME }}
          IMAGE_TAG: staging
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
```

### AWS ECRへのログイン & Push

公式で、下記のActionが提供されているので、非常に簡単にpushできます。

[aws-actions/amazon-ecr-login: Logs into Amazon ECR with the local Docker client.](https://github.com/aws-actions/amazon-ecr-login)


## Dockerrun.aws.jsonの作成

```/deployments/Dockerrun.aws.json
{
    "AWSEBDockerrunVersion": "1",
    "Logging": "/app/log",
    "Image": {
        "Name": "{RepositoryName}",
        "Update": "true"
    },
    "Ports": [
        {
            "ContainerPort": "3000"
        }
    ]
}
```

`${RepositoryName}`はデプロイ時に、タグ付きのレポジトリ名にリプレイスします。

あえて`deployments`ディレクトリを掘って、その下に置いています。同じ階層にDockerfileがあると、そちらが優先されてしまうためです。また、デプロイ時にDockerrun.aws.jsonだけをzipすることで転送量を減らすのが狙いです。

Loggingセクションに コンテナ内のディレクトリを指定することで、ebの管理下にあるLogディレクトリにログを出力できます。
またGUI上のコンソールからLogの閲覧も可能になります。

## AWS Elastic Beanstalkへのデプロイ


```.github/workflows/deploy.yml
      - uses: actions/setup-python@master
        with:
          python-version: "3.7"

      - name: Install awsebcli
        run: pip install -U awsebcli

      - name: Deploy to Elastic Beanstalk
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: ${{ secrets.AWS_ECR_REPO_NAME }}
          IMAGE_TAG: staging
          EB_ENVIRONMENT_NAME: staging
        run: |
          cd deployments
          sed -i -e "s|{RepositoryName}|$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG|g" Dockerrun.aws.json
          eb deploy ${EB_ENVIRONMENT_NAME}
```

今回は、極力公式のActionだけにしたかったので、有志の[Beanstalk Deploy · Actions · GitHub Marketplace](https://github.com/marketplace/actions/beanstalk-deploy)を使用しませんでした。要件次第では、使った方が楽だと思います。

eb コマンドを使用しているので、python環境の構築後にコマンドのインストールを行っています。

# まとめ

GitHub Actionsを使用することで、比較的簡単にパイプラインが構築できました。

デジタル庁の民間登用やCode for Japanの東京都コロナ対策サイト、COCOAなどを契機に、一般市民がテクノロジーを活用して、行政サービスの問題や社会課題を解決するCivitechはこれから盛り上がっていくと思います。

コードの全体は、[codeforjapan/decidim-cfj: Code for Japan Decidim](https://github.com/codeforjapan/decidim-cfj)にあります。

ぜひあなたのコントリビュートをお待ちしております。

# 参考

- [GitHub ActionでDockerコンテナをビルドしてAmazon ECRに保存する | Developers.IO](https://dev.classmethod.jp/articles/github-action-ecr-push/)
- [ElasticBeanstalk x Docker のベストプラクティスっぽいものまとめ - Qiita](https://qiita.com/rosylilly/items/8129ab876698d4f0b216)