JOURNAL

このサイトを支えている環境について、開発者目線で軽く紹介

基本この日誌では道具そのものの話ばかりしているんですが、たまには舞台裏のインフラの話も書いてみます。……とはいえ私はインフラの専門家ではないので、本職のサーバーエンジニアの方が読んだら「いやそこはこう組むべきでしょ!」というツッコミが山ほど飛んできそうな構成です…。💦

この店には、PHPだけで動く静かな道具もあれば、LINE Botのようにバックエンドで外部APIと通信する道具、React/TypeScriptで独立ビルドする道具など、生まれも育ちもバラバラな奴らが同じ屋根の下に同居しています。それぞれに専用サーバーを用意していたらサーバー代で破産してしまうので、Docker(コンテナ技術)を使って1台のサーバー内に小さな個室(コンテナ)をいくつも作り、そこに道具たちを1人ずつ住まわせるシェアハウスのような構成にしています。

1. 「自分のPCでは動いたんですけど」という呪いの言葉からの脱出

個人開発で一番心が削られる瞬間、それは「手元のPC(Windows)では完璧に動いていたのに、本番サーバー(Linux)に上げたらなぜか盛大に爆死する」という怪奇現象です。

ファイル名の大文字小文字の解釈の違い、PHPの微妙なマイナーバージョンのズレ、必要な拡張モジュールが入ってない……などなど。エラー画面の前で夜中に頭を抱えるのが本当に嫌で、開発環境も本番もまったく同じOS・ミドルウェアの箱(コンテナ)として持ち運べるDockerを導入しました。定義ファイル(Dockerfile)に構成を書いておけば、どこへ持って行ってもほぼ同じ顔をして動いてくれる。Dockerの導入自体は今更というか、現在の開発では導入していない方が少ないのではないでしょうか?

なお、手元のPC(WindowsやMac)でこの環境を動かすためのアプリ「Docker Desktop」を導入すると、コンテナの稼働状況やログもGUIから手軽に確認・管理できます。導入されていない方はDocker公式サイトのダウンロードページから入手可能です。

Dockerの概要
▲ Docker Desktopの画面

(※余談:UbuntuなどLinux環境にDocker Desktopを入れる場合の注意点)
WindowsやMacではインストーラーを実行すればすんなり動くDocker Desktopですが、UbuntuなどのLinux環境に導入する場合は少し注意が必要です。特にUbuntuの新しいLTSバージョン(24.04など)がリリースされた直後は、Docker Desktop公式パッケージ側のOS対応や依存関係の更新に数ヶ月以上のタイムラグが発生することがよくあります。
「最新OSを入れたのにDocker Desktopがエラーで入らない!」という時は、そもそも対応版がまだ出ていないことが原因です。無理にDesktop版の対応を待たず、昔ながらの「Docker Engine(CLI版)」を公式リポジトリから直接インストールしてコマンドラインでやり過ごすのが、一番平和で確実な回避策だったりします。以前、新しいLTS版が出た直後に導入してError祭りで大変な思いをした記憶があります😅

2. docker compose up -d という全能感(とYAMLの罠)

設定ファイル(docker-compose.yml)を書いて、コマンドラインにdocker compose up -dと打ち込む瞬間、何台もの仮想サーバーが一斉に立ち上がる様子を見ていると、「もしかして自分、ものすごい凄腕エンジニアなんじゃないか…?」という謎の無敵感に包まれます。

# コマンド1発で全サービスが起動する全能感
$ docker compose up -d
[+] Running 5/5
 ✔ Container web-apache      Started
 ✔ Container db-mysql        Started
 ✔ Container bot-backend     Started
 ✔ Container queue-worker    Started
 ✔ Container phpmyadmin      Started

……が、そんな全能感に浸った直後、YAMLファイルのスペースが1個ズレていただけでyaml: line 24: did not find expected keyと怒られ、あっさり現実へ引き戻されるまでがお約束のワンセットです。インデント1個で動かなくなるあの繊細さ、胃が痛くなります😅

今はこのあたりの設定まで、指示した構成でAIが準備してくれるので、少し前まで苦しんでいたインデント地獄を味わうことはほぼなくなりました。

3. ポート番号の熾烈な椅子取りゲーム

コンテナをぽこぽこ増やしていくと次に勃発するのが、ローカル開発環境でのポート番号の奪い合いです。

「8080番は誰が使ってる?」「3000番はReactで、3306番はMySQL、8000番はAPIサーバーで……あれ、8081番って何のコンテナだっけ?」。新しいツールを立ち上げようとしてBind for 0.0.0.0:8080 failed: port is already allocated(そのポートはもう使われとるぞ!)と怒られるたびに、「誰だお前!どこのコンテナだ!」と犯人探しをする羽目になります。なので、結構ありえないようなポート番号をあえて指定することも!

4. 気づけば数十GB…DockerによるSSD圧迫テロ

Dockerで一番恐ろしいのは、便利さに甘えてビルドや検証を繰り返しているうちに、背後でディスク容量を静かに食い潰していくことです。

使わなくなった古いイメージやビルドキャッシュ、<none>という名もなき亡霊のような中間データがいつの間にか溜まりまくり、「あれ? PCの空き容量が50GB消えてるんだけど?!」と青ざめたことが何度もあります。そんなときの救世主が、不要なデータを一括掃除してくれるこの呪文です。

# 未使用のコンテナ・イメージ・キャッシュを一掃する必殺技
$ docker system prune -a --volumes

これを叩くときは毎回「本当に消しちゃいけない大事なデータまで消えないよね…?」と心臓がバクバクしますが、実行後に一気に数十GBの空き容量がポンと戻ってきたときの爽快感はちょっとクセになります(※本番環境で実行するときは本当に気をつけてください)。

5. それでもコンテナで同居させて良かったこと

色々文句や失敗も書きましたが、やっぱりコンテナにして一番助かっているのは「1つの道具がバグで炎上しても、隣の道具は優雅にお茶を飲んでいられる」という完全な隔離構造です。

仮に新しく作ったLINE Botの処理が暴走してメモリを食い潰しても、メインサイトのApacheや他のWeb道具には一切類焼しません。個人でいろんな実験的な道具を気兼ねなく追加できるのは、間違いなくこのDockerの個室隔離のおかげです。

Dockerで得たメリット裏で払っている代償(あるある)
「環境の差異」による理不尽なバグの撲滅YAMLのインデント1個で撃沈する繊細さ
1台のサーバーで多種多様なツールの同居ローカル開発でのポート番号椅子取りゲーム
万が一の暴走時も他コンテナへ類焼しない油断すると数十GB単位でSSDを食い潰す肥大化
コマンド1発で環境を丸ごと再現・デプロイ「prune」コマンドを叩くときの心臓への負担

便利さと引き換えにディスク容量やメモリの監視という新たな宿題は増えましたが、個人開発の小さな道具屋を支える縁の下の力持ちとして、これからもDockerにはお世話になろうと思っています。