Docker展開編 作業記録
ローカル計測 → VPS展開 → 本番稼働まで
型の定義
| 型 | 意味 |
|---|---|
| 調査 | 現状を確認した |
| 修正 | 設定やコードを変えた |
| ビルド | docker build / save / load を実行 |
| トラブル | エラーが発生した |
| 誤り | 判断ミス。後で覆した |
| 余談 | 本筋と関係ない話 |
| 結果 | 作業の結果を計測 |
ざっくり版
| 型 | 何をしたか | 説明 | 備考 |
|---|---|---|---|
| 調査 | ローカルのメモリ実測 | app 43MB / web 9.9MB | ondemandが効いていた |
| 誤り | ローカルだけNginxを採用 | 本番Apacheなのに構成を変えた | 指摘を受けて撤回 |
| 修正 | ローカルをApacheに差し替え | httpd:2.4 + proxy_fcgi | conf設定は本番でも流用 |
| 修正 | アップロード上限を統一 | Apache/PHP 100M、memory 192M | 512MBに512M許可は矛盾 |
| ビルド | docker save + gzip | 950MB → 214MB | パイプで中間ファイル無し |
| トラブル | scpがConnection refused | 自分の家のIPに送っていた | SSH_CONNECTIONの読み違い |
| トラブル | ディスク95%、空き1.3GB | バックアップ15GB蓄積 | cronに削除処理が無かった |
| 修正 | バックアップ全削除 | 二次バックアップと確認して実行 | 95% → 34% |
| ビルド | docker load 成功 | 512MBで950MB展開を完走 | swap 2GBが効いた |
| 修正 | storage/bootstrap作成 | 書き込むものはイメージに置けない | ボリュームの原則 |
| 修正 | .env.dockerを本番化 | DB依存を全部file/syncへ | MySQL 120MBが不要に |
| 誤り | VPSでwebコンテナを外した | ホストApacheから直接9000番へ | ローカルと構成が不一致 |
| トラブル | Primary script unknown | ホストとコンテナでパスが食い違う | Apacheはパスだけ渡す |
| 修正 | webコンテナを復活 | ローカルと同一構成に戻した | |
| トラブル | 500エラー、ログも書けない | storage所有者almaに書けない | UID 33に変更 |
| トラブル | デザイン崩れ | CSSが127.0.0.1:8080を指していた | ASSET_URL未設定 |
| 誤り | restartで反映されると想定 | 環境変数はコンテナ作成時に注入 | force-recreateが必要 |
| トラブル | フォーム送信で404 | POST→301→GET化→ルート不在 | httpsで生成されていなかった |
| 修正 | config:clear 実行 | ビルド時のキャッシュが古いAPP_URLを保持 | これで解決 |
| 結果 | 本番で完走 | HTTPS→Apache→web→app→numpy | app 56MB / 220MB |
フェーズ9: ローカル計測とApache化
| # | 型 | 何をしたか | 説明 | 備考 |
|---|---|---|---|---|
| 75 | トラブル | docker: command not found | Docker Desktopが停止していた | #39とは別原因。統合はONのまま |
| 76 | 調査 | whichでコマンドの実体を確認 | Windows側から差し込まれたパスだった | Desktopが落ちると消える |
| 77 | 調査 | docker images確認 | DISK 952MB / CONTENT 225MB | 転送に効くのはCONTENT側 |
| 78 | トラブル | up -dがwebを起こさない | 8日前の状態を最新と誤判断 | --force-recreateで解決 |
| 79 | 調査 | 待機時メモリ実測 | app 43MB / web 9.9MB | pm=ondemandの効果 |
| 80 | 誤り | ローカルだけNginxを採用 | 設定が数行で済むという都合を優先 | 再現性を自ら破壊していた |
| 81 | 修正 | httpd:2.4に差し替え | httpd.confを抽出し3モジュール有効化 | proxy / proxy_fcgi / rewrite |
| 82 | 修正 | docker/apache.conf作成 | SetHandler "proxy:fcgi://app:9000" | この1行が本番でも効く |
| 83 | 結果 | ローカルでApache版が動作 | デザイン崩れなし | 構成が本番と一致 |
フェーズ10: 設定の統一
| # | 型 | 何をしたか | 説明 | 備考 |
|---|---|---|---|---|
| 84 | 調査 | php.iniの数値が不整合 | upload 512M に対し memory_limit 256M | 受け取れるが処理できない |
| 85 | 修正 | 100MB基準に統一 | upload 100M / post 110M / memory 192M | 設計値に合わせた |
| 86 | 余談 | float64の話 | WAVはメモリ上で4倍に膨らむ | 100MB → 400MB |
| 87 | 誤り | 200MBに上げたいと要望 | 800MB展開。物理456MBでは不可能 | 100MBで妥結 |
フェーズ11: 転送
| # | 型 | 何をしたか | 説明 | 備考 |
|---|---|---|---|---|
| 88 | ビルド | docker save + gzip | パイプで中間ファイルを作らない | 950MB → 214MB |
| 89 | 余談 | tarは圧縮ではない | 束ねるだけ。gzipが圧縮を担当 | Tape ARchiveの略 |
| 90 | トラブル | Connection refused | 125.8.182.165は自分の家のIP | SSH_CONNECTIONの1番目を読んでいた |
| 91 | 調査 | 正しいIPは3番目 | 接続元IP / 元port / 接続先IP / 先port | 133.167.119.103 |
| 92 | トラブル | 転送318KB/秒 | 家庭回線の上りが細い | 11分。次回はGHCR |
| 93 | トラブル | VPS側でtarを叩いた | ファイルはローカルにある | #22 #23と同じ間違い。3回目 |
フェーズ12: ディスク危機
| # | 型 | 何をしたか | 説明 | 備考 |
|---|---|---|---|---|
| 94 | トラブル | ディスク95%、空き1.3GB | 950MB展開に必要な容量ぎりぎり | 100%到達はシステム不安定を招く |
| 95 | 調査 | /varは1GBのみ | 犯人は別の場所 | duで範囲を広げる |
| 96 | 調査 | /home/alma が15GB | 7/25からのバックアップが全残存 | cronに削除処理が無い |
| 97 | 調査 | 7/26だけ13本 | 手動テストの残骸 | 09:16〜10:09 |
| 98 | 修正 | 全削除を実行 | 二次バックアップと確認できたため | 95% → 34% |
フェーズ13: VPSへの展開
| # | 型 | 何をしたか | 説明 | 備考 |
|---|---|---|---|---|
| 99 | 修正 | dockerd再有効化 | #12で止めたものを起こす | available 295Mi |
| 100 | ビルド | docker load成功 | 512MBで950MB展開を完走 | swap 2GBの回収 |
| 101 | 調査 | 2018年の遺跡を発見 | php:8.1-apache / mysql:8.0 / httpd / hello-world | 合計1.2GB |
| 102 | 調査 | 配置先はchirol-yumul.com | index.html 0バイト。2025年4月から放置 | 潰して問題なし |
| 103 | 修正 | storage/bootstrap作成 | 書き込むものはイメージに置けない | ボリュームの原則 |
| 104 | 修正 | publicをイメージから抽出 | docker run -v で /out にコピー | 所有者がrootになる |
| 105 | 修正 | .env.dockerを本番化 | session/queue/cacheをDBからfileへ | MySQL依存を排除 |
| 106 | 誤り | APP_KEYを画面に出力 | key:generate --show をそのまま実行 | 変数経由で再生成 |
フェーズ14: 繋ぎ目との戦い
| # | 型 | 何をしたか | 説明 | 備考 |
|---|---|---|---|---|
| 107 | 誤り | VPSでwebコンテナを外した | ホストApacheから直接9000番へ | ローカルと構成が不一致 |
| 108 | トラブル | Primary script unknown | Apacheはパスだけ渡す。中身は渡さない | ホストとコンテナでパスが違う |
| 109 | 修正 | webコンテナを復活 | ローカルと同一構成に統一 | ProxyPassで8080へ流す |
| 110 | 結果 | curl 127.0.0.1:8080 で200 | コンテナ内は正常動作 | PHP 8.3.30 |
| 111 | トラブル | HTTPS経由で500 | storage所有者almaに書けない | ログすら残らない |
| 112 | 調査 | CLIでは動くがfpmでは死ぬ | CLI=root、fpm=www-data | 権限差が原因と確定 |
| 113 | 修正 | chown -R 33:33 | UID 33がwww-data | 200 OKに復帰 |
| 114 | トラブル | デザイン崩れ | CSSが127.0.0.1:8080を指す | ブラウザから見れば自分のPC |
| 115 | 誤り | restartで反映されると想定 | 環境変数はコンテナ作成時に注入 | force-recreateが必須 |
| 116 | 修正 | ASSET_URL設定 + 再作成 | デザイン復旧 |
フェーズ15: 最後の301
| # | 型 | 何をしたか | 説明 | 備考 |
|---|---|---|---|---|
| 117 | トラブル | フォーム送信で404 | POST → 301 → GET化 → ルート不在 | ルートはPOSTのみ定義 |
| 118 | 調査 | curlで直接POSTすると419 | CSRF無しの正常な反応。ルートは生きている | 犯人はホスト側と確定 |
| 119 | 調査 | ブラウザが「安全でない接続」と警告 | フォームのactionがhttpで生成されていた | ユーザーが本質を先に指摘 |
| 120 | 調査 | TrustProxiesが未設定 | bootstrap/app.phpに記述なし | 環境変数だけでは効かない |
| 121 | 修正 | config:clear / route:clear | ビルド時のキャッシュが古いAPP_URLを保持 | これで解決 |
| 122 | 結果 | 本番で完走 | HTTPS→Apache→web→app→proc_open→numpy | app 56MB / 220MB |
| 123 | 結果 | 最終メモリ実測 | available 274Mi、swap 481Mi | 朝の151Miから大幅改善 |
次回のデプロイ手順(5手)
# ローカル
docker build -t yumul:latest .
docker save yumul:latest | gzip > /tmp/yumul.tar.gz
scp -P *** /tmp/yumul.tar.gz alma@133.167.***.***:/tmp/
# VPS
cd /var/www/html/chirol-yumul.com
docker load < /tmp/yumul.tar.gz
docker run --rm -v $(pwd)/public:/out yumul:latest cp -r /var/www/html/public/. /out/
docker compose up -d --force-recreate
docker compose exec app php artisan config:clear
publicの取り出しが必要なのは、CSSのハッシュ名がビルドごとに変わるため。忘れるとデザインが崩れる。
残タスク
| 項目 | 内容 | 優先度 |
|---|---|---|
| MySQL停止 | DB依存を排除済み。止めれば120MB浮く | 高 |
| DBパスワード変更 | 会話に出力したため | 高 |
| バックアップcron修正 | 削除処理が無い。放置すればまた15GB | 高 |
| TrustProxies設定 | bootstrap/app.phpに追記。恒久対策 | 中 |
| float32化 | numpyの使用量が半分に。100MB超を扱うなら必須 | 中 |
| GHCR移行 | scpの11分が数十秒になる | 低 |
| 2018年の遺跡削除 | 未使用イメージ1.2GB | 低 |
教訓
1. ローカルと本番の構成を一致させる
#80と#107で構成を変え、2回とも撤回した。Dockerの価値は再現性であり、それを自ら壊せば意味がない。片方だけ変えるとパスの食い違いで必ず詰まる。
2. restart では環境変数が反映されない
#115。.envを触ったら--force-recreate。今後も必ず踏む。
3. 設定キャッシュはビルド時に焼き付く
#121。イメージ内のキャッシュが古い値を保持し、環境変数を無視する。デプロイ後はconfig:clearを手順に入れる。
4. 症状から原因を推測する
#119でユーザーが「baseURLがhttpsじゃないのか」と指摘。ログを追うより早く本質に到達した。