超安価&超簡単にウェブサイト運用しよう。CircleCIで、GitHubプッシュ→自動でビルド→S3に自動デプロイ

# はじめに
S3の静的ウェブサイトホスティング機能をご存じでしょうか。
https://aws.amazon.com/jp/s3-hosting/

AWSのストレージサービスであるS3に
HTMLやCSS、JSなどの
ソースファイルをアップロードし、
S3のホスティング機能を有効にするだけで、
非常に安価に、大容量、優れた耐久性のウェブサイトを公開できるという機能です。
　
　

AWSの管理画面から手動でソースファイルをアップロードすれば、
すぐにでもこの静的ウェブサイトホスティングを利用することができます。
https://qiita.com/suuungwoo/items/2e49c3008a04e48581ed
https://qiita.com/dogwood008/items/a92abae789f4b0466f38
　
　

今回は、このS3静的ウェブサイトホスティング機能をさらに便利に利用するために、
CircleCIを利用して

GitHubにソースプッシュ
↓
ソースビルド
↓
S3にデプロイ

という自動の処理を作ります。
　
　

今回は**静的**ウェブサイトが対象となります。
静的ウェブサイトとは、
HTMLやCSS、JSなどクライアントサイドだけで動かすことができるウェブサイトのことで、
PHPやJavaなどサーバサイドのプログラムが入っているウェブサイトの場合は対象外となります。


# 全体構成
今回構築する仕組みの全体像はこのようになります。

![Untitled Diagram (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297693/49319546-0966-e79b-5c38-6890fc14ee80.png)
　
　
　
③ソースをビルド
は具体的には
`npm intall` を実行してパッケージをインストール、
gulpやwebpackなどを使ってソースコンパイルやモジュールバンドル
などを行います。

ただし、gulpやwebpackなどのソースビルド処理自体は
事前に作ってある前提で、
CircleCIが行うのはビルドコマンドの実行のみです。


# 設定の進め方
今回の構築する仕組みでは、
AWS、CircleCI、GitHub
という３つのサービスを利用します。

その各サービスごとに、
このような手順で進めていきます。

* AWSの設定
 * CircleCI用のIAM作成
 * S3バケット作成
 * S3バケットポリシー作成
 * S3ホスティング設定有効化
* CircleCIの設定
 * CircleCIにアカウント登録
 * プロジェクト作成
 * IAM情報登録
* GitHubの設定
 * CircleCI用configファイル作成
 * config.ymlをmasterにプッシュ




また前提条件として、
AWSアカウントとGitHubアカウントを用意した状態で
次からの作業に進んでください。


# AWSの設定
それではAWSの設定を進めていきます。

※
AWSのコンソール画面は日々変更されていきます。
下記に記載した画面やボタン、設定方法は古くなっている可能性があるので注意してください

## CircleCI用のIAM作成
まず、CircleCIからS3を操作するために必要な
IAMを作ります。

AWSコンソールのIAMのページから
左メニューの「ユーザー」、
上部の「ユーザーを追加」と進みます。

ユーザー名は「CircleCiS3User」などとして、
アクセスの種類は「プログラムによるアクセス」を選択します。

![iam.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297693/188e83a9-6575-6a3f-9627-49b5d6ac4420.png)



次のアクセス許可の設定では
「既存のポリシーを直接アタッチ」を選択し、
「ポリシーの作成」をクリックします。

表示されたポリシー作成画面で、
下記の通りJSONを入力してポリシーを作成してください。

```json:IAMポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:ListBucket",
                "s3:DeleteObject"
            ],
            "Resource": "*"
        }
    ]
}
```

そのままステップを進めてIAMユーザ作成を完了します。

IAM作成完了ページに表示される、
AWS_ACCESS_KEY_ID
と
AWS_SECRET_ACCESS_KEY
を必ずメモに取っておきましょう。

後ほどのCircleCI側の設定で必要になります。
※IAM作成完了画面を１度閉じるとキー情報は再表示できません


## S3バケット作成
次に、静的ウェブサイトとして運用する
S3バケットを作成します。

AWSコンソールのS3ページから、
「バケットを作成する」で進みます。

バケット名は好きな名前を付け、
他は基本的にデフォルトのまま進んでいいですが、
「ブロックパブリックアクセス」の設定では
チェックを外すようにしてください。
（チェックを付けているとウェブサイトの公開設定ができない）

最後に「バケットを作成」ボタンをクリックして
バケット作成を完了してください。


## S3バケットポリシー作成
次に、CircleCIからS3へのアクセスができるように
バケットポリシーを設定します。

バケット一覧から先ほど作成したバケットをクリックし、
「アクセス権限」のタブをクリック
→バケットポリシー
と進みます。


表示されたバケットポリシーエディターに、
下記のようなjsonを記述してください。


```json:バケットポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowAqRead",
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::【自分のバケット名】/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": "【アクセスを許可したいIPアドレス】"
                }
            }
        },
        {
            "Sid": "forCircleCi",
            "Effect": "Allow",
            "Principal": {
                "AWS": "【CircleCI用のIAMのarn】"
            },
            "Action": [
                "s3:PutObject",
                "s3:ListBucket",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::【自分のバケット名】",
                "arn:aws:s3:::【自分のバケット名】/*"
            ]
        }
    ]
}
```

【】で囲んだ箇所は、
自分の環境に合わせて編集してください。

【CircleCI用のIAMのarn】は、
先ほどのステップで作成したIAMユーザです。
AWSコンソールのIAMユーザのページからarnを確認できます。

僕はウェブサイトへのアクセス可能IPを制限したかったため
【アクセスを許可したいIPアドレス】
を記述しましたが、
全世界公開で問題ない場合は`Condition`を記述する必要がありません。


jsonを記述したら保存ボタンをクリックして
バケットポリシーの設定を完了してください。


## S3ホスティング設定有効化
次に、このS3バケットを静的ウェブサイトホスティングする
設定を有効化します。

バケット一覧ページでバケット名をクリックし、
「プロパティ」のタブ
→「Static website hosting」
へと進みます。

表示された設定フォームで
「このバケットを使用してウェブサイトをホストする」
を選択します。

![s3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297693/103cb71e-b3bd-730e-169b-2002f326cee8.png)


さらに表示されたフォームの
「インデックスドキュメント」に「index.html」と入力し
「保存」ボタンをクリックします。
※インデックスドキュメントは自分のウェブサイトに合わせて変更してください



これでホスティング設定完了です。

今の「Static website hosting」のフォーム上部にある
「エンドポイント」に記述されているURLが、
自分のウェブサイトのURLになります。


試しに適当な内容を記述したindex.htmlファイルを用意し、
手動でバケットにアップロードして
先ほどのURLにアクセスしてみたら、ちゃんと表示されるはずです。


自動ビルドや自動デプロイの必要がない場合は
ここまでやった設定だけで、
あとは手動アップロードをすればウェブサイトを運用することができます。


これでAWSの設定はすべて完了です。


# CircleCIの設定
次に、CircleCIの設定を進めます。

## CircleCIにアカウント登録
まずはCircleCIにアカウント登録する必要があります。

https://circleci.com/
CircleCIのトップページ右上にある「Sign Up」をクリック。

そして「Sign Up with GitHub」をクリックして
GitHubアカウントと連携させてください。

## プロジェクト作成
次に、GitHubリポジトリと連携させて
CircleCIのプロジェクトを作成します。

CircleCIのダッシュボードの左メニューにある
「ADD PROJECTS」をクリックすると、
自分のGitHubのリポジトリが一覧で表示されていると思います。


今回連携したいリポジトリの右端に表示されている
「Set Up Project」ボタンをクリックします。

進んだページで「Start building」ボタンをクリックしたら
CircleCIのプロジェクト作成完了です。


## IAM情報登録
次に、
AWS側作業の最初に作成したCircleCI用IAMの情報を
CircleCIプロジェクトに登録します。

ADD PROJECTSのページから
作成したプロジェクトをクリックし、
右上の歯車マークからProject settingページにいきます。

設定ページの左メニューにある
「Environment Variables」に進みます。

![circle.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297693/fdd671e1-b4ec-870a-535a-0eec08ea2af7.png)



「Add Variable」ボタンから、
AWS_ACCESS_KEY_ID
と
AWS_SECRET_ACCESS_KEY
を登録してください。
※AWS設定の最初にやったIAMの作成完了画面でとっておいた情報です

![ci.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297693/5ac66814-23df-384c-ec71-ad905aba542b.png)



これで、CircleCIの設定はすべて完了です。


# GitHubの設定
次にGitHubの設定をします。

設定といっても、
GitHubリポジトリ自体の設定などはする必要はありません。

CircleCI用の設定ファイルをリポジトリのソースファイルに追加して
プッシュするだけです。

## CircleCI用configファイル作成
今回連携したいGitHubリポジトリの
ルートディレクトリに
`.circleci/`ディレクトリを作成し、
その配下に
`config.yml`というファイルを作成します。

ファイルの内容は下記のようにします。

```.circleci/config.yml
version: 2
jobs:
  build:
    docker:
      - image: circleci/node:latest
    working_directory: ~/repo
    steps:
      - checkout
      - run: yarn install   # npmパッケージインストール
      - run: yarn run prod  # ソースビルド実行
      - persist_to_workspace:
          root: .
          paths: [ '*' ]
  deploy:
    working_directory: ~/repo
    environment:
      - AWS_S3_BUCKET_NAME: 【自分のS3バケット名】
    docker:
      - image: innovatorjapan/awscli:latest
    steps:
      - attach_workspace:
          at: .
      - run: aws s3 sync . s3://${AWS_S3_BUCKET_NAME}/ --exact-timestamps --delete --exclude=".git/*" --exclude=".circleci/*" --exclude="node_modules/*"  # ここのexcludeオプションは自分の環境に合わせる

workflows:
  version: 2
  build-deploy:
    jobs:
      - build
      - deploy:
          requires:
            - build
          filters:
            branches:
              only: master

```

これがCircleCIの設定ファイルです。
【自分のS3バケット名】の部分は自分の環境に合わせて変更してください。

CircleCIを扱うためにはこのファイルの記述方法、
様々なオプションを理解する必要がありますが、
今回詳細な解説は省きます。

この記事で実践した後、
もう少し詳しく学ぶといいと思います。
https://circleci.com/docs/ja/2.0/configuration-reference/
https://circleci.com/docs/ja/2.0/sample-config/

今回はCircleCiの設定ファイルで
buildとdeployの２つのジョブを定義しています。

buildジョブでは、
まず`yarn install`コマンドでnpmパッケージをインストールしています。
（yarnとはnpmの進化版ツールのようなもので、`npm install`と同じ意味だと思って大丈夫です）

そのあと、
`yarn run prod`コマンドでビルドを行っています。
このコマンドは僕のプロジェクトで設定していたwebpackの実行コマンドです。
ここは各々のプロジェクトに合わせて
gulpやgrunt、webpackなどビルドツールの実行コマンドを設定してください。

次に、deployジョブ。
このジョブでは、
AWS-CLIを利用して
ビルド済みのソースコードをS3バケットにアップロードしています。

> --exclude=".git/*" --exclude=".circleci/*" --exclude="node_modules/*"

このexcludeオプションで指定したファイル、ディレクトリはS3にアップロードされません。
自分の環境に合わせてアップロード不要なファイルはexcludeするようにしましょう。
（アップロード処理時間が短くなります）


また、設定ファイルの最後にある
workflowsのfilterのところで
masterブランチの場合のみこの処理が走るように設定しています。
ブランチを変更したい場合はこの部分を変更してください。


## config.ymlをmasterにプッシュ
最後に、
作成した`.circleci/config.yml`を
GitHubリポジトリのmasterブランチにプッシュします。

もうすでにCircleCIとGitHubの連携設定は完了していますので、
このプッシュの瞬間、
CircleCIが動いて
先ほど定義したジョブが実行され、
最終的にS3バケットにビルド済みソースがデプロイされます。


# 処理結果確認
GitHubにプッシュしたら、
CircleCIの左メニューにある
「WORKFLOWS」を見てみましょう。

ジョブが実行されているのが見れるはずです。

実行中は「RUNNING」、
成功すると「SUCCEEDED」、
失敗すると「FAILED」
と表示されます。
もし「FAILED」になった場合は、
そのジョブをクリックすればエラーメッセージなどを見れるので、
原因を確認してみましょう。


また、S3のバケットの画面も開いてみましょう。
ビルド済みの状態のソースコードが
バケットに配置されていると思います。


そして最後に、
「S3ホスティング設定有効化」の工程で確認した
ウェブサイトのURLにアクセスしてみましょう。

ウェブサイトが表示されていると思います。


もしうまくできていない場合は、
これまでの作業のどれかしらが正しくできていないと思いますので
見直してみてください。


# おわりに
今回は最低限の簡単な設定で
GitHub、S3、CircleCIの作業を進めました。

ここから拡張するポイントとしては、
・S3のホスティングサイトに独自ドメインを設定する
・CloudFrontを導入する
・CircleCIでユニットテストを実行する
・CircleCIでGitHubのプルリクエスト制限をかける
・CircleCIでSlack通知を行う
などなどたくさんあります。

興味のある方はこれらを調べて
より便利な仕組みを構築するといいと思います。