byteTutoのEC2へのデプロイ
デプロイフロー
git pushをmainブランチに実行 →.github/workflows/deploy.ymlが起動- test ジョブ:
docker build、nginx -t、スモークテスト(/healthz、トップページ、404、CSPヘッダー) - publish ジョブ: マルチアーキテクチャイメージ(amd64 + arm64)を
ghcr.io/bytetuto/website:<sha7>と:latestにプッシュ - deploy ジョブ: SSHでEC2に接続、
/opt/bytetuto/.envを書き込み、docker-compose.yml+deploy/*.shをコピー、deploy/deploy.shを実行 deploy.sh: イメージをプル、up -dで起動、/healthzを最大40秒待機。失敗 → 自動的に.last_imageのイメージにロールバック
PRの場合はtestジョブのみ実行されます。
GitHubのシークレット / 変数(Settings → Secrets and variables → Actions)
- シークレット:
EC2_HOST、EC2_USER(ec2-user または ubuntu)、EC2_SSH_KEY(完全な秘密鍵)、EC2_KNOWN_HOSTS(推奨:ssh-keyscan -H <ip>の出力) - 変数:
DOMAIN(例: bytetuto.com)、LETSENCRYPT_EMAIL - GitHub環境
production(手動承認が必要な場合あり)
便利なコマンド(EC2上、/opt/bytetuto ディレクトリ内)
- 状態確認:
docker compose ps· ログ:docker compose logs -f web - ヘルスチェック:
curl -fsS http://127.0.0.1/healthz - 特定バージョンを再デプロイ:
IMAGE=ghcr.io/bytetuto/website:<sha7> bash deploy/deploy.sh - 手動ロールバック: 以前のタグ(GitHubのPackagesタブで確認可能)を使って
deploy.shを再実行 - HTTPS(DNS設定完了後、一度だけ実行):
bash deploy/init-ssl.sh(最初はSTAGING=1でテスト推奨) - 証明書自動更新: cronジョブ
/etc/cron.d/bytetuto-certbot(1日2回実行)、ログはcertbot-renew.log
nginxがHTTPとHTTPSを切り替える仕組み
nginx/40-bytetuto-ssl.sh がコンテナ起動時に実行されます:
$DOMAIN の証明書が存在する場合 → https.conf.template、それ以外 → http.conf.template。
init-ssl.sh 実行後は、docker compose restart web を実行するだけでHTTPSに切り替わります。
クイック診断
| 症状 | 原因 |
|---|---|
Deployジョブ: Permission denied (publickey) | EC2_SSH_KEY または EC2_USER が間違っている |
docker: permission denied | ユーザーがdockerグループに属していない → ec2-setup.sh 実行後、再接続が必要 |
pull access denied | GHCRパッケージがプライベートでログインに失敗、またはパッケージを公開していない |
| 外部からのHTTPタイムアウト | Security Groupでポート80/443が開放されていない |
| certbotが失敗する | DNSがまだ伝播していない、またはポート80が閉じている |
exec format error | アーキテクチャの問題: イメージがマルチアーキテクチャであることを確認 |
ルール
.env、SSH鍵、certbot/ディレクトリ内のファイルを決して読んだり表示したりしない。git push、ssh、scp、およびdeploy/ディレクトリやワークフローファイルの変更を行う前には必ず確認を求める。