🤖

🤖

:gijutsu_burogu:

1コマンドでQiitaからはてなブログへ記事を移行するできるようにDockerイメージを作った

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コマンドが必要になるのですが。

github.com

開発について

実現したいこと

  • ユーザーが 1 コマンドで記事を移行をすることができる
    • ユーザーはdocker runだけで移行を完了したい

問題点

  1. 環境変数DockerコンテナまたはDockerイメージにどう渡すか
  2. 環境変数を設定ファイルにどう反映させるか
  3. Dockerfile をどう書くか
  4. ブログ記事が多いと移行に時間がかかる

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から環境変数をコンテナに注入するということになったので、DockerfileCMDの命令で反映させる。

解決策 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 イメージについて書く。

RUNCMDの違い
  • RUNdocker buildでイメージが作成されるときに実行される
  • CMDdocker runでコンテナが作成されるときに実行される

    • CMDDockerfile内で 1 度しか使うことができないので、複数の処理を行いたい場合はスクリプトを書きCMDで実行する
CMDENTRYPOINTの違い(両方ともdocker run時に実行されるコマンド)
COPYADDの違い
  • ただ、ローカルファイルをイメージに追加したい場合は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} < $"

注意

  • blogsync.template で指定したこの記事は Qiita の記事をエクスポートしたものです。内容が古くなっている可能性があります。 が記事の最初に追加されます。変更したい場合は、blogsync.templateを編集し、再ビルドしてください。

  • Qiita の MarkdownはてなブログMarkdown で若干の差異があるのでレイアウトが崩れることがあります。

  • 画像の URL は Qiita のS3のものを引き継いでいます。

  • 記事の投稿日時を引き継いでいます。