S3バケットにJSONファイルをアップロードするCI・CDを作ってみた

AWSのS3バケットにJSONファイルをアップロードするCI・CDを作ってみました。GitHubリポジトリのJSONファイルを更新すると、CircleCIによってS3バケットのJSONファイルが更新されます。
2020.01.06

スマホアプリで全ユーザに「お知らせ」を表示しようと思い、JSONデータを公開する仕組みを作ってみました。

API(API Gateway + Lambda)を作っても良かったのですが、簡単に済ませるため、S3バケットにJSONファイルを格納して公開することで簡略化しました。 (「クラウド側の仕組みとCI/CDの仕組み」を作ってみたかった)

目次

概要

GitHubリポジトリのJSONファイルを更新すると、CircleCIによってS3バケットのJSONファイルが更新されます。簡略化のためCloudFrontは未使用です。

CI/CDの概要図

JSONファイルの仕様

次のJSONファイルをS3バケットに格納します。なお、「お知らせ」の更新頻度は月数回を想定しているため、頻繁なJSONデータ取得はさせない予定です。(この仕組はクライアント側ですが、Periodパラメータを利用する想定)

information.json

{
    "Message": "お知らせ:xxxxx",
    "DeadlineTimestamp": 1578636000,
    "Period": 86400
}
  • Message
    • 表示するお知らせの本文
  • DeadlineTimestamp
    • お知らせの有効期限(Unixtime)
    • これ以降はお知らせを表示しない
  • Period
    • データ再取得の期間(Unixtime)
    • 前回取得してからこの期間が経過すると、再取得する

リポジトリとブランチ運用

masterブランチにPushされたら、CircleCIによって開発環境にデプロイします。そのあと、CircleCIのApprove機能で本番環境にデプロイします。

種類 名前の例 環境
ブランチ master 開発環境 → 本番環境

CI/CDを構築する

下記を作成していきます。

  • Python仮想環境を作成
  • Makefileを作成
  • S3バケットを作成
  • IAMユーザとIAMロールを作成(CircleCI用)
  • IAMロールのARNを取得
  • IAMユーザのアクセスキーを取得
  • 単体テスト用のファイルを作成
  • AssumeRole用のスクリプトを作成
  • CircleCIの設定ファイルを作成
  • CircleCIの設定

なお、IAMユーザやIAMロールの詳細は下記をご覧ください。

Python仮想環境を作成

次のコマンドでPythonの仮想環境を作成します。

$ pipenv install --python 3.7.2

続いて、次のコマンドで必要なライブラリをPython仮想環境に導入します。

$ pipenv install awscli
$ pipenv install pytest

Makefileを作成

次のMakefileを作成します。

S3バケット & IAMユーザ & IAMロールを作成

次のCloudFormationテンプレートをprepare.yamlとして作成します。sts:ExternalIdには任意の値を設定します。これはCircelCIの環境変数に設定します。

続いてデプロイします。

$ ENV=dev make prepare
$ ENV=prod make prepare

IAMロールのARNを取得

次のコマンドを実行し、作成したIAMロールのARNを取得します。これはAssumeRoleするために必要なのでメモしておき、CircelCIの環境変数に設定します。

$ ENV=dev make describe-prepare
$ ENV=prod make describe-prepare

IAMユーザのアクセスキーを取得

IAMユーザのアクセスキーを取得します。これはCircleCIの環境変数に設定するためメモしておきます。

$ ENV=dev make create-access-key
$ ENV=prod make create-access-key

単体テスト用のファイルを作成

次のPythonコードをtest_checker.pyとして作成します。

確認する内容は下記です。

  • JSONファイルとして正しいか?
  • 必要なKeyがあるか?
  • Valueの型が期待通りか?

AssumeRole用のスクリプトを作成

AssumeRole用に次のスクリプトをassume_role.shとして作成します。

次に実行権限を付与しておきます。

$ chmod 755 assume_role.sh

JSONファイルを作成

次のJSONファイルをinformation.jsonとして作成します。

CircleCIの設定ファイルを作成

.circleciディレクトリを作成し、その中にconfig.ymlを作成します。

$ mkdir .circleci
$ touch .circleci/config.yml

続いて、config.ymlファイルの中身を記述します。

CircleCIの設定

リポジトリのPush

まずはGitHubにリポジトリをPushしておきます。

$ git push origin master

CircleCIにログイン

CircleCIにログインします。

プロジェクト作成

「ADD PROJECT」を選択し、さきほどGitHubにPushしたリポジトリを選択します。

Add Projectをする

続いて、「Start building」を選択します。

Start buildingを選択する

初めてのジョブが走りますが、環境変数が未設定なので失敗します。

環境変数が未設定なので失敗する

環境変数を設定

プロジェクト一覧の設定マークを押し、設定画面に移ります。

設定画面に移動する

Environment Variablesを選択します。

Environment Variablesを選択する

次の環境変数を追加します。

Name Value
AWS_ACCESS_KEY_ID_DEV 取得したAccessKeyId(開発用)
AWS_ACCESS_KEY_ID_PROD 取得したAccessKeyId(本番用)
AWS_SECRET_ACCESS_KEY_DEV 取得したSecretAccessKey(開発用)
AWS_SECRET_ACCESS_KEY_PROD 取得したSecretAccessKey(本番用)
AWS_DEPLOY_IAM_ROLE_ARN_DEV 取得したIAMロールのARN(開発用)
AWS_DEPLOY_IAM_ROLE_ARN_PROD 取得したIAMロールのARN(本番用)
AWS_DEPLOY_IAM_ROLE_EXTERNAL_ID_DEV sts:ExternalIdで設定した値(開発用)
AWS_DEPLOY_IAM_ROLE_EXTERNAL_ID_PROD sts:ExternalIdで設定した値(本番用)
AWS_DEFAULT_REGION ap-northeast-1
AWS_DEFAULT_OUTPUT json

動作確認

開発環境

さきほど失敗したWorkflowsの「Rerun」を選択し、そこの「Rerun from failed」を選択します。

Rerun from failedを選択する

しばらくするとデプロイが成功しました!

デプロイが成功する

次のコマンドでJSON取得できます。

$ curl app-information-dev.s3.amazonaws.com/information.json
{
    "Message": "テストメッセージ",
    "DeadlineTimestamp": 1578636000,
    "Period": 86400
}

本番環境

この状態で「Approve Job」のApproveを選択し、続いて本番環境にデプロイを進めます。

Approveを選択する

Approveする

しばらく待つと、デプロイが成功しました!

本番環境へのデプロイが成功する

次のコマンドでJSON取得できます。

$ curl app-information-prod.s3.amazonaws.com/information.json
{
    "Message": "テストメッセージ",
    "DeadlineTimestamp": 1578636000,
    "Period": 86400
}

さいごに

思っていたよりも簡単にできました。API化は必要になったら考えたいです。

参考