tl;dr
事前に行うこと
- 対象のはてなブログの記事入力モードを Markdown に変更
- Qiita の記事のタイトルが
[Docker]Qiitaからはてなブログへ記事を移行のように[]から始まるものをだと yaml のパースの関係で上手くいかないので【】等に置換 - 環境変数が必要であるためカレントディレクトリに
.envを作成
# .env HATENA_BLOG_DOMAIN= # ex: kotaroooo0-dev.hatenablog.com HATENA_USER_NAME= # ex: kotaroooo0 HATENA_API_KEY= # そのブログに投稿するための API キー。はてなユーザのパスワードではありません。ブログの詳細設定画面 の「APIキー」で確認できます。 QIITA_API_KEY= # https://qiita.com/settings/applications からトークン取得
入力コマンド
$ docker run --env-file .env adachikun/qiitatohatena
はじめに
以下の記事で Qiita からはてなブログへの移行方法を紹介した。 kotaroooo0-dev.hatenablog.com
goコマンドを持っていない人もいるだろうし、Docker で環境を用意して 1 コマンドで移行できるように Docker イメージを作成した。
今度はgoコマンドではなく、dockerコマンドが必要になるのですが。
開発について
実現したいこと
- ユーザーが 1 コマンドで記事を移行をすることができる
- ユーザーは
docker runだけで移行を完了したい
- ユーザーは
問題点
1.環境変数を DockerコンテナまたはDockerイメージにどう渡すか
APIKEY やブログドメインなど個人差があるものは外部から注入する必要がある。
解決策 1: docker build時にENVで注入する
- 環境変数ごとにイメージを作り直す必要がでてくるため、1 コマンドで記事を移行することはできなくなる
解決策 2: docker run時に-eオプションで注入する
-e HOGE=hoge FUGA=fugaのように設定するが、数が多くなると使いにくくなる
解決策 3: docker run時に--env-fileオプションで注入する
$ docker run --env-file .env adachikun/qiitatohatena
2.環境変数を設定ファイルにどう反映させるか
環境変数は設定ファイルで使う。
どのように環境変数を含んだ設定ファイルを作成するかという問題がある。
1 でdocker run時に.envから環境変数をコンテナに注入するということになったので、DockerfileのCMDの命令で反映させる。
解決策 1: ファイルに対して環境変数を出力して 0 から設定ファイルを作成
- 地獄
解決策 2: sedで環境変数を書き換えることで設定ファイルを作成
- 環境変数が多いと辛い
- 書き換えの独自ルールが必要になり可読性や汎用性が下がる
解決策 3: 軽量テンプレートエンジンのenvsubstにより環境変数を書き換えることで設定ファイルを作成
- Docker で設定ファイルに環境変数を埋め込めこむ汎用的な方法
- 今回はこの方法を採用
docker build時に以下のファイルをイメージにコピーしておく。
# ~/.config/blogsync/config.yaml.tmp ${HATENA_BLOG_DOMAIN}: username: ${HATENA_USER_NAME} password: ${HATENA_API_KEY} default: local_root: /Documents
docker run時に以下のスクリプトに実行することで環境変数が埋め込まれた設定ファイルを作成する。
# setup.sh cat ~/.config/blogsync/config.yaml.tmp | envsubst > ~/.config/blogsync/config.yaml
envsubstについてさらに詳しくはこちら
kakakakakku.hatenablog.com
3.Dockerfile をどう書くか
(注意) 以下のDockerfileではイメージサイズやビルド時間についてはなにも考慮されていないため、次記事で最適化された Docker イメージについて書く。
RUNとCMDの違い
RUNはdocker buildでイメージが作成されるときに実行されるCMDはdocker runでコンテナが作成されるときに実行されるCMDはDockerfile内で 1 度しか使うことができないので、複数の処理を行いたい場合はスクリプトを書きCMDで実行する
CMDとENTRYPOINTの違い(両方ともdocker run時に実行されるコマンド)
ENTRYPOINTは必ず実行されるコマンドCMDはデフォルトの引数ENTRYPOINTの方がコンテナを実行モジュールのように明示的に捉えることができるためこちらを採用
COPYとADDの違い
- ただ、ローカルファイルをイメージに追加したい場合は
COPYADDはセキュリティ上のリスクがある- リモート上のリソースも取得できるので攻撃され得る
- 圧縮ファイルを自動解凍するので攻撃され得る
# Dockerfile # goが使えるイメージをとってくる FROM golang:latest # 移行に必要なライブラリをとってくる RUN go get -u github.com/tenntenn/qiitaexporter RUN go get -u github.com/x-motemen/blogsync # envsubstをとってくる RUN apt-get update RUN apt-get install gettext-base -y # /Documentsを作業リポジトリにしファイルをイメージ内へコピーする WORKDIR /Documents COPY blogsync.template /Documents COPY setup.sh /Documents # blogsyncのconfigファイルをイメージ内へコピーする RUN mkdir -p ~/.config/blogsync COPY config.yaml.tmp /root/.config/blogsync # コンテナ実行時にsetup.shを走らせる RUN chmod +x setup.sh ENTRYPOINT ./setup.sh
4. ブログ記事が多いと移行に時間がかかる
これはなんらかの方法で並列処理しないといけないと思っていたところ、xargsが標準で並列処理できる機能を持っていた。
-Pオプションで並列数を指定することができる。
# setup.sh find posts -name "*.md" | xargs -I $ -P 5 sh -c "blogsync post ${HATENA_BLOG_DOMAIN} < $"