Magento デプロイ自動化 — GitHub Actions を検討した末に見送り、Mac→SSH 直結に落ち着いた理由
流行りの GitHub Actions を真剣に検討したものの見送り、Mac から SSH で直接デプロイスクリプトを回す構成に落ち着いた記録。手動トリガー + メインリポジトリなしという組み合わせでの選択。
Magento + Hyvä のサイトを運用していると、コードを直すたびにこの長いコマンド列を打つことになる。
maintenance:enable → composer install → setup:upgrade → setup:di:compile
→ tailwind build → static 整理 → static-content:deploy (ロケール9個)
→ cache:flush → maintenance:disable
モジュールやテーマの git pull まで前に付くと、画面一杯では収まらない。頻繁にやる作業がこれだけ長くて手打ちなら、自動化は選択肢ではなく必須だ。この記事は、その自動化をどう設計したか — 正確には 流行りの方法(GitHub Actions)を真剣に検討した末に、なぜ見送ったか についての記録だ。
候補たち
最初に思い浮かんだ選択肢は3つ。GitHub Actions で push トリガーのデプロイ、macOS アプリの開発、そして単純な SSH スクリプト。
macOS アプリはすぐに見送った。ボタン1つ押すためにアプリを作るのは、シェルの alias や Raycast が1秒で代替してしまう。残ったのは GitHub Actions と スクリプト で、しばらくは GitHub Actions のほうに傾いていた。かっこよく見えたから。
GitHub Actions を見送った理由
設計を具体化していくうちに、自分の状況と噛み合わないポイントが浮かび上がってきた。
第一に、メインリポジトリが存在しない。 Magento のルートが1つのリポジトリではなく、カスタムモジュールがそれぞれ別々の git リポジトリとして散らばっている。そうなると「どのリポジトリの push にトリガーを掛けるのか?」という時点からして曖昧だ。ワークフローの YAML をどこに置くかも定まらない。
第二に、このデプロイには承認ゲートも自動トリガーも必要ない。 GitHub Actions がもたらす価値 — push の自動トリガー、承認ゲート、中央集約されたデプロイログ — のうち、このワークフローに必要なものが1つもない。通すべき承認ステップはなく、トリガーもどのみち意図的に手動でいい。
第三に、そうなると GitHub は結局 「SSH コマンド1行を代わりに実行してくれる中継所」 の役割しか果たさない。その中継のために SSH デプロイキーを新たに発行し、GitHub Secrets を登録し、ワークフローファイルの置き場所を悩む — それは純粋なオーバーヘッドだ。手動デプロイ1つのために決裁システムを作るようなものだった。
そこで GitHub を丸ごと外すことにした。流れはこれだけシンプルになる。
[Mac] Raycast ボタン
│ ssh -t (直結)
▼
[サーバー] deploy.sh → 各モジュール/テーマ git pull → ビルド
進める中で学んだ落とし穴2つ
1) && チェーンはサイトをメンテナンスモードに閉じ込める
もともとのコマンドは maintenance:enable && composer install && ... && maintenance:disable という形だった。問題は、途中のステップ(特にロケール9個を回す static deploy)が1つでも失敗するとチェーンがそこで止まり、maintenance:disable が永遠に実行されない ことだ。サイトがメンテナンス画面に閉じ込められてしまう。
解決策はスクリプトに trap を仕込むこと。失敗してもしなくても、終了時にメンテナンスモードを解除する。
cleanup() {
local code=$?
if [ "$code" -ne 0 ]; then
echo "✖ 失敗(exit $code) — メンテナンスモード解除"
bin/magento maintenance:disable || true
fi
}
trap cleanup EXIT手打ちの && チェーンにはこういう安全装置がない。スクリプトに移すだけで事故を1つ防げる。
2) 本番で composer update は危険だ
もともと composer update を使っていた。だが update は composer.json の制約範囲内で依存をすべて最新に上げる — コアやサードパーティのモジュールが予告なく変わりうる。再現可能なデプロイには composer install(lock のまま)が正しい。自分のモジュールだけ新バージョンを取り込みたいなら、全体 update ではなく composer update yohan/* --with-dependencies のようにターゲットを絞る。
ワークフローはモジュールごとに置くものではない
これは概念を一度整理したら明確になった。デプロイの「トリガー」はソースコードのリポジトリと紐づいているわけではない。実際にすべてのモジュールを git pull する主体は サーバー上の deploy.sh 1つ だ。その中の配列が「このサイトはこれらのモジュール + これらのテーマで構成される」という単一のレジストリの役割を果たす。
GIT_DIRS=(
"app/code/Yohan/ModuleA"
"app/code/Yohan/ModuleB"
"app/design/frontend/Hyva/Hyva_K-SALE"
"app/design/frontend/Hyva/Hyva_K-SALE-2"
)
for d in "${GIT_DIRS[@]}"; do git -C "$d" pull --ff-only; doneモジュールが10個あってもトリガーは1つ。新しいモジュールはこの配列に1行追加すれば終わりだ。個々のモジュールリポジトリは単なるコード置き場であって、CI もワークフローも要らない。
最終形
Mac には Raycast Script Command が1つ。サイトをドロップダウンで選ぶと、該当するサーバーへ ssh -t(進行ログをリアルタイムで)して deploy.sh を実行する。
ssh -t "$SSH_HOST" "cd '$REMOTE_PATH' && ./deploy.sh"サーバーには trap + ロギングを備えた deploy.sh が1つ。テーマが複数あれば tailwind ビルドを配列で回し、static のクリーンアップは pub/static/frontend/Hyva を丸ごと削除してテーマ数に依存しないようにする。
必要なのは「Mac からそのサーバーへ SSH できること」だけ。すでに VS Code Remote-SSH を使っていたのでキーはあった。GitHub Secrets も、デプロイキーの発行も、ワークフローの YAML も、すべて消えた。
では GitHub Actions はいつ使うのか
永遠に使わないという話ではない。次の2つの条件のどちらかが生じたら、そのとき導入するのが正しい。デプロイに複数人が関わって「誰がいつデプロイしたか」の記録・承認が必要なとき、または push すればステージングに自動デプロイされるパイプラインが欲しいとき。 それまでは、手動トリガー + メインリポジトリなし という組み合わせなら直結が正解だ。
教訓
流行りのツールが自分の状況の正解とは限らない。GitHub Actions、CI/CD、ビルドアーティファクト — どれも良いものだが、それが解決する問題(チーム協業、自動トリガー、追跡性)を自分が抱えていないなら、純粋なコストになる。「定石」に従う前に、その定石が解く問題が自分にあるのかをまず問うべきだ。必要のない問題にツールを持ち込むこと、つまりオーバーエンジニアリングが最大の敵だ。