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
の違い
- ただ、ローカルファイルをイメージに追加したい場合は
COPY
ADD
はセキュリティ上のリスクがある- リモート上のリソースも取得できるので攻撃され得る
- 圧縮ファイルを自動解凍するので攻撃され得る
# 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} < $"