そろそろ DeNA Engineers' Blog について振り返っておくか

by mazgi | December 25, 2020
dena-tech | #aws #circleci #dena #dena-engineers-blog #docker #github #hugo #terraform

この記事は「DeNA Advent Calendar 2020」の 25 日目の記事です。

前回「この Blog をリニューアルしてます」と書いた @mazgi です。

色々な方のおかげで今年 2020 年 4 月に無事リニューアルが完了し、その後も安定的に運用され多くの方が記事を読んでくださっているようでありがたい限りです。

世の中にはリニューアルやリプレイスを含めて「新しく作りました」という情報が多く公開されていますが、作ってその後どうなったかの情報を知る機会はそれらのいわば華やかなニュースに比べると少ないと感じます。

そこでアドベントカレンダー最終日を引き当ててしまったこの機会に「DeNA のエンジニア Blog、リニューアルしてどうなったん?成功なん?失敗なん?」という話を書かせてください。

リニューアルのご紹介(再)

リニューアル前の旧 Blog は 2010 年に構築され当時スタンダードだったと言える Movable Type (以下 MT と表記) が内製 VM プラットフォーム上の Linux でホストされていました。
しかし 10 年で技術は進み、Blog のような静的な Web サイトを公開するためにサーバーを運用する必要はなくなりました。

そこで新 Blog へのリニューアルに際しては「絶対にサーバー立てないぞ」と強い気持ちを持って臨みました。
結果、以前ご紹介したような Hugo + GitHub Enterprise + CircleCI Enterprise + Amazon S3 を中心とした、インフラ運用が限りなく不要な構成を設計し構築できました。

具体的な構成については以前の記事や、
DeNA Engineers’ Blog をリニューアルしている話

あるいはもう少し細かい内容を個人の Blog に書いていますのでご参照いただけますと幸いです。
GitHub+CircleCI+S3 で NoOps な Blog を構築した

当 Blog はこのまま成長を続け、また数年後には「構成がレガシーなんで再構築しますね」と誰かが進化させてくれることでしょう。
そう願っていますし、そうあるべきです。

リニューアルの結果

Blog は書きやすくなったのか?(Account 編)

旧 Blog はそもそも執筆方法が失伝していました。
正確には MT のアカウントが社内の他のアカウントから独立しており、検索能力に長けた人が社内 Wiki の奥深くに記された MT のアカウント申請方法を知ることができる状況でした。

もちろん一度書けば次回以降は執筆方法もわかりますし MT のアカウントを保持できるのですが、初めて書こうとする人にとっては不便な状況でした。
おそらくは 10 年の間に社内システムが改善され各種アカウントが統合される中で、MT が取り残されてしまったのでしょう。
歴史を感じました。

新 Blog では GitHub Enterprise のアカウントがあれば執筆でき、社内であればレビューに参加できるようにしました。
技術職をはじめ多くの従業員が GitHub Enterprise アカウントを持っているので、そもそも「Blog を書くためにアカウントを申請する」ハードル自体を取り除くことができました。

また Blog 記事の Pull Request はその更新が Slack に流れるので、よりオープンに多くの人がレビューに参加したり「このネタいいな、わしも書きたいことがあるぞ」と Blog 執筆自体への興味も持っていただける土壌ができたと考えています。

しかしながら、ただ仕組みだけが置かれていても Blog 記事は書かれず、技術広報の皆さんが日々地道に記事自体や記事を読んでいただけるよう工夫を続けてくださっているからこそ、今の状態があるのだと感じています。

Blog 記事を読んでもらうためもうひと工夫!技術広報が出来る事

Blog は書きやすくなったのか?(Writing & Review 編)

旧 Blog では最終的にはもちろん MT の Web UI 上で submit されますので、各自が原稿を書き、メールや Google Docs でレビューを依頼していたようです。
つまり執筆者とレビュー依頼を受けた人くらいしか「その記事が書かれている」こと自体を知る機会がありませんでした。

もちろん Google Docs であれば社内で広くレビューを受けることもできますので、例えば意図して Google Docs の URL を Google Groups や IRC(もうありません), Slack channel で社内に共有し広くレビューを求めていた方もおられるでしょう。

新 Blog にリニューアル後は MT への submit が前述通り GitHub Enterprise への Pull Request に変わり、原稿もサーバー上の MT データから Git リポジトリ上の Markdown ファイルになりました。

DeNA では CTO や技術系マネージャー陣も普段から GitHub Enterprise を使っていますので、mention や reviewers へのアサインで気軽にレビューを依頼できます。

さらに従来の個別に原稿を共有して依頼するレビュー方法に加えて、レビュー用 URL が発行される仕組みを作りました。
レビュー用 URL は社内誰でもアクセスできるので、GitHub Enterprise アカウントを持っていない法務やビジネス職の方にも URL を 1 つ知らせるだけでレビューを依頼できます。

加えてレビュー用 URL は Pull Request へのコメントとして Slack channel に流れるので、意図せずともより多くの人の目に触れる機会も生まれました。

一方で、何かエディタを提供できているわけではないので、普段 Markdown を書く機会が少ない方にはまだ少しハードルが感じられるかもしれません。
もし原稿フォーマット自体は Markdown のまま、執筆用のエディタや UI のバリエーションを提供できたら便利かもしれないですね。

旧 Blog から新 Blog への移行は順調だったのか?

Web アプリケーションを含む Web サイトの公開を経験したことがある方にはおなじみの話ですが、Blog のような静的 Web サイトを新しく作って切り替えることはそれほど難しくありません。
新たなホスティング先を用意し、DNS レコードを更新するだけです。

一方でそう簡単ではないのはコンテンツの移行です。
10 年分の、様々な人が複数の MT フォーマットで書いた記事を移行するのはどうしても手間がかかります。

しかしこの 10 年の記事は会社の大切な技術史の一部です。
リニューアル前の記事を塩漬けにしてしまうことは難しくありませんが、社内技術のメインストリームが Perl から多彩な言語に広がっても、世の中のケイタイがフィーチャーフォンからスマートフォンに変わっても、記事を引き続き読んでいただける状態で移行したいと考えました。

一方で Blog 公開自体ではなんら売り上げが立つわけでもないのでかけられるコストは限られています。
そこで機械的にフォーマットを変換し、人力で変換内容を確認することにしました。

まず、MT から Hugo フォーマットに変換するそのものズバリのツールを見つけられなかったので、簡単な CLI ツールを作りました。

MT フォーマットを Hugo の記事に変換するツールは以下で公開しています。
https://github.com/mazgi/mt-to-hugo-article-converter

PyPi でパッケージも公開しているので pip install していただければ使えるはずです、たぶん。
https://pypi.org/project/mt-to-hugo-article-converter/

次に、作った変換ツールや、変換対象の原稿や画像などのアセットを 1 つの GitHub Enterprise リポジトリにまとめました。

各アセットは更新も考慮しました。
原稿は旧 Blog の Web UI から export した MT フォーマットのファイルを所定のファイル名でこのリポジトリに commit しました。
画像は commit された原稿を元に前述のツールの機能でダウンロードしました。

また、同じリポジトリ内に機械的に変換した記事を Hugo でプレビューできる機能も含めました。

これらの機能を 1 つの repository にまとめ、また docker 化することで、変換作業のための環境構築を簡略化しました。
今回は作業環境を Mac に限定できたので、Mac 上での手順を README にまとめました。

README

以上で作業してくださる方にお渡しできる状態となりました。

幸い、今回は移行作業中の旧 Blog への記事執筆が少なく、変換作業中は大きな手戻りもなく無事移行できました。
総じて 10 年分の記事を移行したにしては省リソースで完了できたと評価しています。
私はツールと環境を整えただけなのですが、人力で記事の変換を確認してくださった皆様と作業用の PC をすぐに用立ててくださった情シス部門の方には本当に感謝しています。

また、元々の Blog が MT できちんと構築され長期で運用し続けられていたからこそ機械的に変換できました。
この点も元の Blog を構築/運用してくださった皆様のおかげと感謝しています。

旧 Blog から新 Blog への URL 変更はどう対処したのか?

Blog や CMS を移行する場合、コンテンツの URL 変更は 1 つの悩みです。
色々な事情で FQDN が変わることもありますし、CMS などのシステムを変更する際には path やクエリパラメタも変わり得ます。

特に旧 Blog は多くのブックマークもいただいており、ぜひブックマークやすでに SNS に投稿された URL を経由した場合でも引き続き記事を読んでいただける状態を維持したいと考えました。

そこで旧 Blog から新 Blog への URL を map し redirect する小さなライブラリを作りました。
https://github.com/mazgi/express-middleware-redirector

しかし小規模とはいえライブラリを Web アプリケーションとして公開すると、どうしてもインフラ運用も必要になってしまいます。 そこでアプリケーションを Express Middleware として実装し、 Serverless Framework を用いて AWS Lambda 上で運用する方針を決めました。

この redirect を行うアプリケーションは、記事の移行と異なり今後も継続的に稼働し続けますが、AWS Lambda 上で稼働させることによりインフラ運用とインフラ費用を極めて低く抑えることができます。

Serverless Framework を用いて Lambda で稼働させる場合のアプリケーション実装例は前述の repository の sls-aws/src/index.ts にあります。
本番で動いているアプリケーションもほぼこのままの実装です。

import { createRedirector } from "express-middleware-redirector";
import express from "express";
import serverless from "serverless-http";

const app = express();

// eslint-disable-next-line @typescript-eslint/no-var-requires
const config = require("/data/config/app/config.json");
const redirector = createRedirector(config);
app.use(redirector);

export const handler = serverless(app);

これにより旧 URL でアクセスいただいても記事が読める状態を担保し、運用レスにでき、また失伝しがちな「どの記事をどう redirect しているか」の設定も Git リポジトリ上に残すことができました。

redirect についても、記事の移行同様 Docker 化しており、 docker-compose updocker-compose run で作業できるようにしました。
Docker 化することでアプリケーション環境が「読み解けるブラックボックス」になるので、とりあえずは git clone && docker-compose up && docker-compose run 程度で必要な作業を進めつつ、さらに細かい部分に手を入れたくなったら内容を把握していくことができます。
実際、私の手を離れてからも AWS Lambda を初めて触る技術広報の方が更新してくださっています。

なお Hugo の機能として Alias 設定もできます。
もし Hugo を使っておられて同じようなお悩みを抱えておられる方は Alias の使用も検討してみてください。

今回は移行後の Blog 原稿リポジトリの見通しをよくしたかったため Hugo の外で解決しました。

その他雑多な反省や懺悔

いくつか反省もあります。

1 つは記事のディレクトリ階層です。
Hugo は通常では次のように原稿の path を URL に直接反映します。

content/posts/2006.01/an-article.md
▶️ /posts/2006.01/an-article/

で、これは個人の好みの問題もあるのですが、私は次の思想を持っています。

  • IT 技術系の記事は賞味期限が短いため「いつ書かれたか」を容易に把握したい
    • 例えば URL やタイトルなどに年と月くらいが含まれてほしい
  • 意味区切りで delimiter が存在してほしい
    • 例えば 2006-01-my-first-article よりは 2006-01/my-first-article を好む

この思想が反映された結果、Blog の URL と原稿の階層は posts/年.月/タイトル.md となっています。

この構成は理論として正しいとは思っているのですが、10 年分の記事がファイルシステム上に置かれた際、 posts/ 直下に 10y * 12m = 120 のディレクトリが存在してしまいます。
posts/年/月/title にすればよかったなと後悔しています。

Blog 書いて 300 年、知らないうちにディレクトリ数が 3600 個になり ls 結果が重くなってしまった遠い将来の方、犯人は私です、ごめんなさい。
そうなる前に構造を見直してください。

そのほか、CI/CD などもだいぶナイーブな作りだったので日々改善を図っていただいています。
今後も記事を書くついでに Pull Request を送っていただいたりして改善が図られ、また数年経った頃には、その時に適した形でリニューアル含めて検討していただけることを願います。

まとめ

記事の冒頭にも書きましたが、新しく作ることに比べて、そのあとの運用やあるいは不要になってしまったものの畳み方は光が当たらない地味な仕事です。
今回、Blog のリニューアルに際して生じた、移行や転送といった地味かつ必要な課題と解決方法をご紹介することで、もし同じような必要が生じたどなたかのお役に立てば幸いです。

また Blog のような寿命が長く専任者を置きにくいシステムの思想や経緯や失われがちです。
どういう背景や制約があり、どのような思想でそれを選択し実行したのか少しでも残すことで、将来またリニューアルの機会が生じた時に参考にしていただけることを願っています。

私は 2020 年代の Web システムの寿命は 5 年程度ではないかと思っています。
2020 年時点ではそこそこ新しい技術でリニューアルできたこの Blog も、2025 年頃にはより優れた技術スタックが一般的になり、AWS の仕様も変わり、きっとどなたかが「Blog そろそろリニューアルしません?」と言ってくださると信じています。

多くの方のご協力のもと、Git とテキストフォーマットには寄せることができました。
次回リニューアルの際はぜひより一層いい感じの仕組みで作り直してください!

リンク集