MkDocsでハンズオンサイトを作ってAmplifyでホストする

最近MkDocsでハンズオンを書くことが多かったので、備忘録を兼ねて手順を整理しておく。

## やりたいこと
MkDocsでハンズオンサイトを作り、GitHubとAmplify CICDを連動させつつAmplifyでホストする。

## 前提条件
ローカル端末（自分の場合はMac）に以下をインストール済みであること。

- Amplify CLI
    - [公式](https://docs.amplify.aws/cli/start/install/)参照
    - しばらく触ってない場合は、`amplify ugprade`を実施しておく
- AWS CLI （プロファイル設定済み）
    - [公式](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-cliv2.html)参照
    - しばらく触ってない場合は、`brew upgrade aws-cli`を実施しておく
- MkDocsおよび関連リソース
    - python3 -m pip install --upgrade pip
    - python3 -m pip install mkdocs
    - python3 -m pip install mkdocs-material
    - python3 -m pip install pygments
    - python3 -m pip install pymdown-extensions
    - python3 -m pip install fontawesome_markdown

## ステップバイステップ

### 1. GitHubのプライベートレポジトリを準備
このレポジトリにソースを配置する。CodeCommitでも可。
MkDocsは/mkdocs/site配下にアーティファクトを生成するので、最終的にはここの内容をAmplifyにデプロイすることになる（amplify.ymlでパス指定する）。

他には、ローカルでビルドしてsite配下のアーティファクトだけをルート直下に置くレポ構造を取る方法もある。この場合はamplify.ymlは不要だが、ビルドに際して最新のモジュールが使われなくなるので、ローカルにインストールされた`mkdocs`や`mkdocs-material`のバージョンに注意する必要がある。自分の場合、アイコンのサイズがゆがんで表示される問題があり、mkdocs-material-8.1.10にする必要があったのだが、ローカルのテストでのみうまく行かず15分くらい悩んだ（mkdocs-material-8.1.5になってた）。

ということで、ここでは前者を採用。

### 2. レポジトリをクローン

レポジトリをクローンし、mkdocsディレクトリを作っておく。

```bash
> git clone https://github.com/itsuki3/mkdocs-sample.git
Cloning into 'mkdocs-sample'...
warning: You appear to have cloned an empty repository.
> cd mkdocs-sample
> mkdir mkdocs
```

### 3. Amplifyを初期化
Amplifyプロジェクトを初期化する。
プロジェクトルートで`amplify init`を実行する。

```bash
> pwd
/Users/（略）/mkdocs-sample
> amplify init
Note: It is recommended to run this command from the root of your app directory
? Enter a name for the project mkdocssample
The following configuration will be applied:

Project information
| Name: mkdocssample
| Environment: dev
| Default editor: Visual Studio Code
| App type: javascript
| Javascript framework: none
| Source Directory Path: src
| Distribution Directory Path: dist
| Build Command: npm run-script build
| Start Command: npm run-script start

? Initialize the project with the above configuration? Yes
Using default provider  awscloudformation
? Select the authentication method you want to use: AWS profile

...（中略）...
Your project has been successfully initialized and connected to the cloud!
...（略）...
```

これでAmplifyのガラができる。

```bash
> ls .
amplify	mkdocs	src
```
![management-console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609876/25a16eb6-84e1-6640-2f4b-aec64355e3e9.png)

### 4. MkDocsを初期化

mkdocsフォルダに移動し、MkDocsを初期化しておく。

```bash
> cd mkdocs
> mkdocs new .
INFO     -  Writing config file: ./mkdocs.yml
INFO     -  Writing initial docs: ./docs/index.md

mkdocs.ymlで諸々の設定を行う。
サイトの実体はdocs配下に作成していく。
現時点では両方ともほぼ空の状態。
```

### 5. AmplifyホスティングおよびCICDをセットアップ

AmplifyでWebサイトホスティングを設定し、GitHubレポジトリとAmplifyを接続する。
いったんプロジェクトルートに戻っておくこと。

```bash
> cd ..
> pwd
/Users/（略）/mkdocs-sample
```

レポジトリとAmplifyを接続することで、ブランチへのプッシュに連動してCICDを動かすことができるようになる。
開発・本番を分離して多少本格的にやるなら、`main`ブランチをdev環境、`prod`![configure.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609876/4991c3c6-df28-4d9e-abf3-a613b38f72cf.png)
ブランチをprod環境...というふうに複数の環境と連動させることもできる。例えば以下のようなフローが考えられる。

- メンバーは`feature/xxx`ブランチでローカル開発し、プッシュする。
- `feature/xxx`ブランチから`main`へのプルリク承認とマージをトリガーとして、dev環境がビルド・デプロイされる。
- `main`から`prod`へのプルリク承認とマージをトリガーとしてprod環境がビルド・デプロイされる。

ここでは簡略化して、以下を構成する。Amplifyと接続するブランチは`main`のみ、Amplifyの環境も一つ（dev）のみとなる。

- `feature/xxx`ブランチでローカル開発し、プッシュする。
- `feature/xxx`ブランチから`main`へのプルリク承認とマージをトリガーとして、dev環境がビルド・デプロイされる。

接続前にプロジェクトルート（mkdocs-sample）に`amplify.yml`を置いておくことで、CICD設定を自動的に読み取ってくれるので、このタイミングで作成しておく。
 
```yaml:amplify.yml
version: 1
frontend:
  phases:
    preBuild:
      commands:
        - python3 -m pip install --upgrade pip
        - python3 -m pip install mkdocs
        - python3 -m pip install mkdocs-material
        - python3 -m pip install pygments
        - python3 -m pip install pymdown-extensions
        - python3 -m pip install fontawesome_markdown
    build:
      commands:
        - cd mkdocs
        - mkdocs build
  artifacts:
    baseDirectory: mkdocs/site
    files:
      - '**/*'
  cache:
    paths: []
```

ここまでの内容一式をコミットして、レポジトリのmainにプッシュしておく。

```bash

> git add .
> git commit -m "Initial commit"
...（中略）...
> git push
You are pushing to the remote origin at https://github.com/itsuki3/mkdocs-sample.git
...（中略）...
To https://github.com/itsuki3/mkdocs-sample.git
 * [new branch]      main -> main
```

ここまでできたら、Webホスティングの構成とレポジトリ接続を一気に進める。

```bash
> amplify add hosting
? Select the plugin module to execute Hosting with Amplify Console (Managed hosting with custom doma
ins, Continuous deployment)
? Choose a type Continuous deployment (Git-based deployments)
? Continuous deployment is configured in the Amplify Console. Please hit enter once you connect your
 repository
```
途中でレポジトリ接続のためにマネジメントコンソール（Amplify Console）に飛ばされるので、GitHubを選択して`main`ブランチをデフォルトのdev環境と接続する。
![connect.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609876/0ec8b6b7-e096-c45e-73f0-b3d63ed9f319.png)
そのままレポジトリとブランチを接続する。
![branch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609876/720ce0d9-48b3-7493-ddde-0d22a1c6cd8a.png)
Environment、IAMロールを選択する。
なお、`Amplify.yml`が正しく作成されていれば、ここで読み取ってくれる（見つからない場合は、プロジェクトルートに置いてあるかを確認すること）。
![configure.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609876/62fa40ea-e215-ed2a-b4d1-5a6c36b8931f.png)
あとは、保存すればパイプラインが構成され、ついでに起動するが、この時点ではビルド・デプロイすべきものもないので無視して手元のターミナルに戻る。

```bash
...（略）...
? Continuous deployment is configured in the Amplify Console. Please hit enter once you connect your
 repository
Amplify hosting urls:
┌──────────────┬────────────────────────────────────────────┐
│ FrontEnd Env │ Domain                                     │
├──────────────┼────────────────────────────────────────────┤
│ main         │ https://main.d28aXXXXXXXXXX.amplifyapp.com │
└──────────────┴────────────────────────────────────────────┘
```
これでAmplifyのホスティングおよびCICDのセットアップは完了。

### 6. ブランチを切る

`feature/v11`としてブランチを切り、開発開始。

```bash
> git checkout -b feature/v1
Switched to a new branch 'feature/v1'
```

### 7. mkdocs.ymlを編集する

mkdocs.ymlの中身を編集する。
主な編集項目は以下の通り。

|設定名|内容|設定例|
|:--|:--|:--|
|site_name|タイトルに表示されるサイト名|mkdocsサンプル|
|logo|タイトルに表示される画像|images/kabutpomushi.jpg|
|copyright|コピーライト|© 2022, Kabutomushi, Inc. All rights reserved.|
|markdown_extensions|Material for MkDocsの各種拡張モジュール|admonition、fontawesome_markdownなど|
|extra_css|CSS定義|ここではFont Awesomeのものを使用|

Material for MkDocsは、デフォルトのままだと若干素っ気ないMkDocsに様々な彩りを与えてくれる拡張モジュール。
各種オプションについては、[公式](https://squidfunk.github.io/mkdocs-material/reference/admonitions/)の他、ググるといろいろな先人の知恵が出てくる。
自分はこのあたりを参考にさせていただきつつ（感謝！）、同僚とあれこれトライアンドエラーした。

[MkDocsに「mkdocs-material」を使用してMaterialデザインを適応する](https://mebee.info/2020/11/05/post-15718/)
[MkDocsによるドキュメント作成](https://zenn.dev/mebiusbox/articles/81d977a72cee01)
[MkDocs - 拡張プラグイン集（1）](https://dev.classmethod.jp/articles/mkdocs-plugins-1/)

作成した`mkdocs.yml`のサンプルは以下の通り。

```bash
> cd mkdocs
> cat mkdocs.yml
site_name: MkDocsサンプル
theme:
  name: material
  language: ja
  logo: images/kabutomushi.jpg
  palette:
    primary: black
copyright: © 2022, Kabutomushi, Inc. All rights reserved.

plugins:
  - search:
      lang: ja

markdown_extensions:
  - attr_list
  - admonition
  - pymdownx.highlight:
      use_pygments: true
      pygments_style: colorful
      linenums: false
  - pymdownx.superfences
  - pymdownx.details
  - fontawesome_markdown

extra_css:
  - "https://maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css"
```

### 8. MkDocsサイトを作る

MkDocsサイトの開発は、基本的に以下の流れで進む。

1. docs配下にソースを配置し、
2. `mkdocs serve`で動確（`https://localhost:8000`）し、
3. `mkdocs build`でアーティファクトを生成する。

本稿では3.はamplify.ymlを設定してAmplify CICDに自動ビルドしてもらうので、1.と2.を繰り返してサイトを開発していく感じになる。
詳細は省く（前出の先人リンクを参照）が、以下がポイント。

- マークダウン記法で記述していく。
    - ヘッダー、図版、テーブルなどを駆使して作っていく。Visual Studio Codeなどで作るのが便利。
    - コードハイライト（`pymdownx.highlight`）やアラート修飾（`admonition`）、カスタムアイコン（`fontawesome`）などを使うと、
- 画像はimages/にまとめる。
- `index.md`が本体だが、`section1.md`、`section2.md`...といった形で、連番でセクションを作っていくことができる。
- セクションは左ペインに列挙される。
    - いわば「章」として機能する。ハンズオンの利用者が全体像を把握したり、セクションを辿りやすくするために、適切な章立ては重要。
- マークダウンのヘッダー行は右ペインに列挙される。
    - いわば「項」として機能する。こちらも同様。

例えば以下のような構造になる。

```bash
> cd docs
> pwd
/Users/（略）/mkdocs-sample/mkdocs
> tree
.
├── docs
│   ├── images
│   │   └── kabutomushi.jpg
│   ├── index.md
│   ├── section1.md
│   ├── section2.md
│   └── section3.md
└── mkdocs.yml

2 directories, 6 files
```

### 9. ローカルでテスト

`mkdocs.yml`のある親フォルダで`mkdocs serve`を実行すると、ローカルでMkDocsサイトをホストしてブラウザで確認できる。

```bash
> cd ..
> mkdocs serve
INFO     -  Building documentation...
INFO     -  Cleaning site directory
INFO     -  Documentation built in 0.31 seconds
INFO     -  [10:23:51] Serving on http://127.0.0.1:8000/
```

こんな感じ。

![mkdocs-sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609876/b3c8add3-4477-dbf7-03e2-1fea64017db4.png)

### 10. コミット、プッシュ、ビルド、デプロイ

一通りできたので、コミットしてレポジトリにプッシュする。

```bash
> git add .
> git commit -m "MkDocs initial build"
...（中略）...
> git push origin feature/v1
...（略）...
> 
```
レポジトリに移動し、プルリク作成/承認/マージ（`feature/v1` -> `main`）を行う。
先程設定したAmplify構成に従って、`main`へのマージをトリガーとして、Amplify環境でのビルドとデプロイが開始する。
![deploy-start.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609876/e7d589d9-e802-da25-804e-dabf779347f9.png)

その間に、ローカルブランチを綺麗にしておく。

```bash
> git checkout main
Switched to branch 'main'
Your branch is up to date with 'origin/main'.
> git pull --rebase --prune
From https://github.com/itsuki3/mkdocs-sample
 - [deleted]         (none)     -> origin/feature/v1
remote: Enumerating objects: 1, done.
（略）
> git branch -d feature/v1
Deleted branch feature/v1 (was eb615d3).
```

待つことしばし。
Amplify Consoleでデプロイ完了を確認したら、アクセスしてみる。
![complete.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609876/ac84ae9e-6154-f502-8d59-682aec144900.png)
これで完了。

## まとめ

MkDocsで作ったハンズオンサイトをAmplifyでデプロイする方法でした。

MkDocsはマークダウンベースで細かい調整もしやすいし、拡張モジュールで表現力も高められるので大変便利。
AmplifyもいたってシンプルなステップでCICDからデプロイまで実装が可能。今回はやらなかったが、カスタムURLやACM証明書連携も簡単にできる。CloudFrontやS3、Route 53を手組みするよりだいぶ楽だなと改めて感じた。