mdbook2pages

pyama2000/mdbook2pages

Markdownからbookを作成するツールにrust-lang/mdBookを利用します。 このツールはGitBookに似ていますが、Rustで書かれたものになっています。 mdBook向けに書かれたMarkdownファイル群をGitHubにプッシュすることでGitHub ActionsでCI/CDを行い、 本サイトのようにGitHub Pagesにデプロイします。

1. プロジェクトの構成図

mdbook2pages
├── .github
│  ├── actions
│  │  └── build
│  │     └── Dockerfile
│  └── workflows
│     └── main.yml
├── book
├── book.toml
├── docker-compose.yml
├── Dockerfile
├── README.md
├── src
│  ├── introduction.md
│  ├── production
│  │  ├── mdbook2pages.md
│  │  ├── moses.md
│  │  ├── musa.md
│  │  ├── spotify_api.md
│  │  ├── tex2pdf.md
│  │  └── tof.md
│  └── SUMMARY.md
└── theme
   ├── custom.css
   └── highlight.css

2. mdBook環境の構築

mdBookはRust製のツールなのでローカルまたはDockerでRust + mdBookを 実行できる環境を構築する必要があります。ここではDockerを使って環境を構築したいと思います。
Dockerfileは以下のようにシンプルなものになっています。
※ コンパイルが必要なため時間がかかります。

2.1 Dockerfile

FROM rust:latest

RUN cargo install mdbook --vers "^0.3.5"

EXPOSE 3000

WORKDIR /mdbook

cargo installでmdbookをインストールしてますが、--vers "^0.3.5"とすることで インストールするバージョンを0.3.5から0.3.xまでに指定しています。

2.2 docker-compose.yml

version: "3"
services:
  mdbook:
    build: . 
    volumes:
      - ./:/mdbook
    ports:
      - 3000:3000
    container_name: mdbook2pages_mdbook

docker-compose up --buildで2.1節のDockerfileをビルドします。 これでmdBookを編集、閲覧できる環境が整いました。

3. mdBookの使い方

3.1 プロジェクトの初期化

mdbook initで最小限の構成でmdBookを開始できます。

$ mdbook init

mdbook2pages
├── book
└── src
   ├── chapter_1.md
   └── SUMMARY.md

bookディレクトリはmdBookでビルドしたファイルが格納されるディレクトリで、デプロイする際に利用します。
srcディレクトリはMarkdownファイル群になっており、SUMMARY.mdはサイドメニューです。

# Summary

- [Chapter 1](./chapter_1.md)

3.2 Markdownのビルド、閲覧

mdbook buildで3.1節で作成されたMarkdownファイル群をビルドできます。ビルドされたファイルは bookディレクトリに格納されているので、book/index.htmlをブラウザで開くと閲覧ができます。

mdbook serve --hostname 0.0.0.0srcディレクトリ以下のファイルを監視し、変更があった場合自動で再ビルドします。 また、http://localhost:3000にアクセスすることで閲覧することができます。 mdBookはデフォルトで3000番ポートを使用していますが、-pオプションでポート番号を変更できます。

summary image

3.3 記事の追加

srcディレクトリ以下にMarkdownファイルを追加、またはSUMMARY.mdや他のMarkdownファイルで 他の記事をリンクするとビルド時に自動的にファイルが生成されます。
また、src/productionのようにディレクトリを作成して、そこにMarkdownファイルを追加することもできます。

$ cat SUMMARY.md
# Summary

- [自己紹介](./introduction.md)
- [制作物](./production/tof.md)
    - [mdbook2pages](./production/mdbook2pages.md)
    - [moses](./production/moses.md)
    - [musa](./production/musa.md)
    - [spotify_api](./production/spotify_api.md)
    - [TeX2PDF](./production/tex2pdf.md)
    - [New file](./production/new_file.md)  # 存在しないファイル

$ mdbook build

mdbook2pages
├── book
└── src
   ├── introduction.md
   ├── production
   │  ├── mdbook2pages.md
   │  ├── moses.md
   │  ├── musa.md
   │  ├── new_file.md  # 自動で生成される
   │  ├── spotif_api.md
   │  ├── tex2pdf.md
   │  └── tof.md
   └── SUMMARY.md

4. GitHub Actionsとの連携

mdBookで作成したbookをGitHub ActionsでGitHub Pagesにデプロイします。

ファイル構成

mdbook2pages
└── .github
   ├── actions
   │  └── build
   │     └── Dockerfile
   └── workflows
      └── main.yml

4.1 GitHub Pages用のリポジトリを作成

GitHub Pagesは、GitHubのリポジトリからHTML、CSS、JavaScriptファイルを取得し、 ウェブサイトを公開できる静的なウェブサイトホスティングサービスです。

GitHub Pages用に<USER_NAME>.github.ioというリポジトリを作成してください。
※ この例ではpyama2000.github.io

Create GitHub Pages repository

リポジトリを作成することができたら、適当にindex.htmlをプッシュし、 https://<USER_NAME>.github.ioでユーザのウェブサイトにアクセスすることができます。

ユーザ用のサイトは1つしか作成できませんが、プロジェクトごとにもGitHub Pagesを作成することができます。 プロジェクトサイトを公開するにはgh-pagesブランチにHTML、CSS、JavaScriptか、 masterブランチの/docsディレクトリを配置することで公開できます。 プロジェクトサイトのURLはhttps://<USER_NAME>.github.io/<REPOSITORY_NAME>となります。

詳細についてはGitHub Pages について - GitHub ヘルプを参照してください。

4.2 秘密鍵・公開鍵の作成

GitHub Pagesを公開するのに公開アクションであるGitHub Pages action · Actions · GitHub Marketplaceを使用します。そのために秘密鍵・公開鍵を生成し、 それぞれのリポジトリに配置する必要があります。

以下のコマンドで秘密鍵と公開鍵のペアを作成します。

$ ssh-keygen -t rsa -b 4096 -C "$(git config user.email)" -f gh-pages -N ""

-CオプションでGitに登録しているメールアドレスをコメントとして渡し、 -Nオプションでパスフレーズを空白として、-fオプションによってpg-pagesというファイル名で キーペアを作成します。 作成したキーペアはコマンドを実行したディレクトリの直下に生成されます。

作成されたキーペアの公開鍵(gh-pages)の内容を4.1節で作成したGitHub Pages用のリポジトリ (<USER_NAME>.github.io)のSettings > Deploy keysに任意の名前で登録します。 また、Allow write accessにチェックを入れるのを忘れないでください。

Add Deploy keys

秘密鍵は、mdBookでビルドするリポジトリ(ここではmdbook2pages)のSettings > SecretsACTIONS_DEPLOY_KEYという名前で登録します。

Add Secrets

4.3 アクションを作成

ワークフローでmdBookをビルドするアクションを定義します。
.github/actions/build/Dockerfileを作成し、以下のように記述してください。

FROM rust:latest

RUN cargo install mdbook --no-default-features --features output --vers "^0.3.5"

CMD ["mdbook", "build"]

2.1節で作成したDockerfileと似ていますが、mdBookのインストールの際に--no-default-featuresオプションと --featuresオプションでoutputを指定することで、出力するためだけの機能をもったmdBookを インストールすることができます。
CMD命令により、ビルドされたコンテナに入ると自動的にmdbook buildコマンドが実行されます。

4.4 ワークフローを作成

以上によりmdBookのビルド、公開するアクションの準備が整ったのでいよいよワークフローを定義します。
.github/workflows/main.ymlが以下のコードとなっています。

name: CI/CD
on:
  push:
    branches:
    - master
    paths:
    - "src/**.md"
    - "book.toml"

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - name: Build
      uses: ./.github/actions/build
    - name: Deploy
      uses: peaceiris/actions-gh-pages@v2
      env:
        ACTIONS_DEPLOY_KEY: ${{ secrets.ACTIONS_DEPLOY_KEY }}
        EXTERNAL_REPOSITORY: <USER_NAME>/<USER_NAME>.github.io
        PUBLISH_BRANCH: master
        PUBLISH_DIR: ./book

ワークフローの詳しい書き方は割愛しますが、このYAMLファイルにより、masterブランチに src/**.mdまたはbook.tomlファイルがプッシュされたら、deployジョブが実行されます。
deployジョブではファイルを取得し、Buildステップでは4.3節で定義したアクションを実行、 mdbook buildによってHTML一式をbookディレクトリ以下に生成します。
その後、peaceiris/actions-gh-pages@v2アクションによってデプロイを行っています。 環境変数を与えることで外部リポジトリにプッシュしたりプッシュするブランチを指定できます。 ACTIONS_DEPLOY_KEYは4.2節で登録したSecretsを参照し、EXTERNAL_REPOSITORYで外部リポジトリを 定義しています。EXTERNAL_REPOSITORYUSER_NAME はご自身のユーザ名に置き換えてください。 PUBLISH_BRANCHでプッシュするブランチを指定します。最後に、PUBLISH_DIRBuildステップで 生成されたbookディレクトリをプッシュします。

その他の環境変数はREADME.mdに記載されているので、こちらを参照してください。

5. 完成したコードをプッシュ

4章までに作成したコードをリポジトリ(ここではmdbook2pages))にプッシュするとGitHub Actionsが 自動で実行され、エラーが発生しなかったらUSER_NAME.github.ioにHTML一式がプッシュされているはずです。

Result of GitHub Actions

GitHub Pages commit

おわりに

GitHub Actionsを利用することで、継続的にテストやビルド、デプロイ(CI/CD)ができるようになり、 プッシュするだけでウェブサイトが更新されるようになりました。以前では、手動でビルドし、 ビルドしたものをサーバにアップして...などの手順がめんどくさかったですが、GitHub Actionsによって Markdownファイルを書き、プッシュするだけですべての手順を自動でやってくれるため、 書くことに集中することができるようになりました。 また、mdBookではCSSやJavaScriptを独自に定義することができるため、今後はこのCSSやJavaScriptを リント、フォーマッティング、テストを行うアクションを定義したいと思います。