せっかく RAML で API ドキュメントを作ってもローカルでしか閲覧できないのは悲しいよねって話

## はじめに

API ドキュメントの管理を Excel や Word などから [Raml](https://raml.org/) のような API ドキュメンテーションツールに切り替えるチームも増えていると思います。しかし作成した API ドキュメントはプロジェクトを `git clone` してローカルで閲覧する、というようなちょっと残念な方法をとっているチームもあるような気がします。

そこで本記事では、作成した API ドキュメントを AWS にサクッと数分でホスティングする方法をまとめました。本記事では API ドキュメントを対象としますが、ホスティング対象は静的コンテンツであれば何でも構いません。

## 注意

本記事では Route 53 のような **無料利用枠のない** サービスを使うため、静的コンテンツを公開したままにしておくと一月あたり 100 円程度ですが課金されます ( [Amazon Route 53 料金表](https://aws.amazon.com/jp/route53/pricing/) ) 。

もし課金されたくない場合は本記事の内容を実施後、下記の流れで作成した AWS リソースを必ず削除してください。

1. S3 バケットにアップロードしたコンテンツを削除する
2. コマンド `terraform destroy` を実行する
3. Route 53 ホストゾーンを削除する

## システム構成図

本記事で構築するシステム構成は以下の通りです。今回は Raml で作成した API ドキュメントをデプロイします。対象プロジェクトは [fizzbuzz](https://github.com/mizuhara/fizzbuzz) とします。

![system-configuration.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28856/d20d252a-263e-acfe-e037-8ff337029790.png)

上記構成図で概要が分からないサービスがある場合は本記事後半の「使用サービスの一言メモ」にサービスの概要を記載したので、そちらを参考にしてください。

## 前提

- デプロイ対象のコンテンツ ( 今回は API ドキュメント ) が作成済みであること

- AWS への登録と IAM ユーザの作成が完了していること

  - IAM ユーザには **S3, CloudFront, ACM, Route 53 へのフルアクセス権限** を付与しておく

- terraform がインストール済みであること

  - 本記事で使用するバージョンは `v0.12.29` です
  - Mac ユーザの方は `brew install terraform` でインストールできます
  - インストール後は [Terraform の credential 情報をリポジトリ外で管理する](https://qiita.com/akashixi/items/889f43562d16fd2f9367#%E3%82%84%E3%82%8A%E6%96%B9) あたりを参考にして credentials 情報の設定をしてください

## システム構築

### 独自ドメインを取得する

1. [freenom](https://www.freenom.com/ja/index.html?lang=ja) にアクセスする
2. 右上にある **サインイン** からログインする ( 初回利用時は登録が必要 )
3. 画面上部の **Services** から **Register a New Domain** を選択する
4. 検索ボックスに取得したいドメイン名を入力して **Check Availability** を押下する
5. 取得したいドメインの **Get it Now!** を選択後に画面上部の **Checkout** を押下する
6. 内容を確認して **I have read and agree to the Terms & Conditions** にチェックを入れ、**Complete Order** を押下する

以上で独自ドメインの取得は完了です。

### ネームサーバを変更する

まずは Route 53 ホストゾーンを作成する。

1. AWS マネジメントコンソールから Route 53 のページを開く
2. **ホストゾーンを作成する** ボタンを押下して、**ドメイン名** に先ほど登録したドメイン名を入力後 **作成** ボタンを押下する
3. 表示された **NS レコード** をメモする

続いてネームサーバの変更作業を実施する。

1. [freenom](https://www.freenom.com/ja/index.html?lang=ja) にアクセスする
2. 画面上部の **Services** から **My Domains** を選択する
3. 対象ドメインの **Manage Domain** を押下する
4. 管理画面が開いたら **Management Tools** から **Nameservers** を選択する
5. **Use custom nameservers (enter below)** を選択して先ほどメモした NS レコード 4 つを入力、**Change Nameservers** ボタンを押下する

以上でネームサーバの変更作業は完了です。

### ACM, S3, CloudFront を作成する

私が用意した ACM, S3, CloudFront を作成する terraform ファイルを clone します。

```terminal
$ git clone https://github.com/mizuhara/terraform.git
$ cd terraform/https-static-site
```

続いて clone したファイル内の `<your-domain>` を先ほど取得したドメイン名に置き換えます。例えば取得したドメインが `api-doc.tk` であれば以下のコマンドを実行すれば置き換わります。

```terminal
$ grep -l '<your-domain>' ./* | xargs sed -i.bak -e 's/<your-domain>/api-doc.tk/g'
```

続いて `variables.tf` の 10 行目 `<your-bucket-name>` を好きな S3 バケット名に置き換えてください。

ここまで来たら下記コマンドを実行して完了です。

```terminal
$ terraform init
$ terraform apply
```

もし実行前に実行後の状態を知りたい場合は `init` の後に下記コマンドを実行してください。terraform ファイルのエラー有無も知ることができます。

```terminal
$ terraform plan
```

`apply` コマンド実行が完了したら CloudFront ディストリビューション ID が出力されるのでメモしておいてください。S3 バケットへのファイルアップロードが完了した後 https://www.api-doc.tk/ にアクセスできれば Web サイトの公開は完了です ( `api-doc.tk` の箇所は適宜読み替えてください ) 。

### GitHub Actions を設定する

さて、API ドキュメントを更新する度に手動で S3 バケットに最新のドキュメントをアップロードするのは面倒ですよね？ということで、もう一手間かけて API ドキュメントを自動アップロードできるようにしましょう。

1. GitHub リポジトリを開く
2. Secrets に下記情報を設定する

    | key                   | value                                             |
    | --------------------- | ------------------------------------------------- |
    | AWS_ACCESS_KEY_ID     | 事前準備で用意した IAM ユーザの access key id     |
    | AWS_SECRET_ACCESS_KEY | 事前準備で用意した IAM ユーザの secret access key |
    | S3_UPLOAD_BUCKET      | `variables.tf` に指定した S3 バケット名           |
    | DISTRIBUTION          | `terraform apply` コマンドの実行後にメモした ID   |

3. **Actions** を押下する
4. **set up a workflow yourself** のリンクを押下する
5. yaml ファイルを入力する画面が開かれるので下記内容をコピペして画面右にある **Start commit** ボタンを押下する

    ```main.yml
    name: deploy to s3
    on: [push]
    jobs:
    build:
     runs-on: ubuntu-latest
     timeout-minutes: 5

     steps:
       - name: checkout
         uses: actions/checkout@v2

       - name: setup jdk
         uses: actions/setup-java@v1
         with:
           java-version: 1.8

       - name: build with gradle
         run: ./gradlew build

       - 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: us-east-1

       - name: upload file to s3
         env:
           S3_UPLOAD_BUCKET: ${{ secrets.S3_UPLOAD_BUCKET }}
         run: |
           aws s3 cp ./doc/index.html s3://$S3_UPLOAD_BUCKET/ --quiet

       - name: invalidate cloudfront cache
         uses: chetan/invalidate-cloudfront-action@master
         env:
           DISTRIBUTION: ${{ secrets.DISTRIBUTION }}
           PATHS: '/*'
           AWS_REGION: 'us-east-1'
           AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
           AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
    ```

6. コミットメッセージを入力してコミットする

以上で GitHub に push すると `gradle build` が実行され、成功すると S3 バケットに API ドキュメントをアップロードして CloudFront のキャッシュをクリアします。

## 使用サービスの一言メモ

### Amazon Certificate Manager ( ACM )

ACM は AWS 自身が認証局となって SSL 証明書を発行するサービスです。発行した証明書の有効期限は 13 ヶ月で、自動更新することも可能です。

2020 年 7 月時点で ACM を利用可能なサービスは ALB や CloudFront などの一部サービスに限定されますが、無料で利用できます。

### Route 53

Route 53 は AWS が提供する DNS サービスです。DNS は権威 DNS とキャッシュ DNS に大別されますが、Route 53 は前者なので、必要に応じてキャッシュ DNS を別途用意する必要があります。

### Simple Storage Service ( S3 )

S3 は非常に優れた耐久性を持つ容量無制限のオブジェクトストレージサービスです。

### CloudFront

CloudFront は AWS が提供する Contents Delivery Network ( CDN ) サービスです。

通常であればキャッシュした HTML や CSS などの静的コンテンツをオリジンサーバの代わりに配信することで、オリジンサーバの負荷軽減やユーザへのレスポンス速度を向上させる目的で利用しますが、今回は https 接続するために利用します。

### Terraform

Terraform は [HashiCorp](https://www.hashicorp.com/) が手がけるインフラストラクチャ定義ツールです。クラウド上のリソースを定義ファイルの状態になるように生成・操作してくれます。

今回作成した Terraform の解説は tf ファイルに記載したコメントを参照してください。

### GitHub Actions

GitHub Actions は GitHub のイベントをトリガに任意の Docker コンテナの実行を連係させることで、ユーザが自由にワークフローを定義できるサービスです。

## まとめ

本記事では AWS に https 対応した静的サイトをサクッと公開する方法を説明しました。弊社では現在オンプレから AWS への移行を進めつつあり、アプリケーションエンジニアでもインフラ環境を ( ある程度は ) 触れる必要があるなぁと実感しています。

これを機に AWS を触れるようになりましょう。

## 参考資料

- [S3/CloudFront/Route53/ACM 構成の静的サイトを Terraform で構築 & CircleCI で自動デプロイ](https://tech.lucheholdings.com/entry/2018/09/25/220855)
- [無料ドメイン(.tk)と Route53 を利用して 0 円で HTTPS 環境を設定してみた](https://dev.classmethod.jp/articles/mesoko-r53-cdn/)