Contents
1. リポジトリ設計とブランチ戦略
1-1. 保護ブランチと開発ブランチ
| ブランチ | 用途 | 推奨設定 |
|---|---|---|
main(または master) |
本番・ステージング環境へデプロイする基準ブランチ |
|
feature/* |
新機能追加、バグ修正などの作業ブランチ |
|
設定手順(GitHub Enterprise)
1. リポジトリ > Settings > Branches に移動。
2. Add rule をクリックし、main を対象に以下を有効化
- Require a pull request before merging
- Require status checks to pass (ci.yml)
- Require review from Code Owners(Acme の CODEOWNERS ファイル参照)
1-2. PR フローと自動デプロイ
- PR 作成 → CI 実行 → 全チェック成功 → マージ の流れを徹底します。
mainにマージされた瞬間、デプロイジョブが起動し、ステージング環境へ自動リリースされます(本番へのリリースは別途承認フローで実施)。
2. GitHub Actions ワークフロー全体像
2-1. ファイル構成
|
1 2 3 4 5 6 7 8 9 |
.github/ └─ workflows/ └─ ci-cd.yml # 本ガイドの中心となるワークフローファイル Dockerfile # アプリケーションイメージ定義 docker-compose.yml # ローカルテスト用(任意) scripts/ ├─ run_task.rb # Open3 で外部コマンドを呼び出すサンプル └─ deploy.sh # SSH 経由でステージングにデプロイするスクリプト |
2-2. ci-cd.yml の主要セクション
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
name: Acme Ruby CI/CD on: push: branches: [ main ] pull_request: branches: [ main ] jobs: # ------------------------------------------------- # ビルド環境の準備(Ruby と Bundler のセットアップ) # ------------------------------------------------- setup: runs-on: ubuntu-latest outputs: ruby-version: ${{ steps.ruby.outputs.version }} steps: - uses: actions/checkout@v4 - name: Set up Ruby id: ruby uses: ruby/setup-ruby@v1 with: ruby-version: '3.3' # Acme が公式にサポートしているバージョン bundler-cache: true # ------------------------------------------------- # テストジョブ(マトリクスで複数 Ruby バージョンを同時実行) # ------------------------------------------------- test: needs: setup runs-on: ubuntu-latest strategy: matrix: ruby: ['3.2', '3.3'] steps: - uses: actions/checkout@v4 - name: Use Ruby ${{ matrix.ruby }} uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} bundler-cache: true - name: Run RSpec run: bundle exec rspec --format documentation - name: Run RuboCop run: | bundle exec rubocop --format json -o rubocop.json - name: Upload RuboCop report uses: actions/upload-artifact@v3 with: name: rubocop-report path: rubocop.json # ------------------------------------------------- # Docker イメージのビルド & GitHub Packages へのプッシュ # ------------------------------------------------- build-image: needs: test if: github.ref == 'refs/heads/main' && success() runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Log in to GHCR run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin - name: Build & push image run: | IMAGE=ghcr.io/${{ github.repository }}/app:${{ github.sha }} docker build -t $IMAGE . docker push $IMAGE # ------------------------------------------------- # ステージング環境へデプロイ(SSH 経由でスクリプト実行) # ------------------------------------------------- deploy: needs: build-image if: success() runs-on: ubuntu-latest steps: - name: Deploy to Staging uses: appleboy/ssh-action@v0.1.10 with: host: ${{ secrets.STAGING_HOST }} username: ${{ secrets.SSH_USER }} key: ${{ secrets.SSH_KEY }} script: | IMAGE=ghcr.io/${{ github.repository }}/app:${{ github.sha }} ./scripts/deploy.sh staging $IMAGE |
ポイント解説
needsとifの組み合わせ-
前段ジョブがすべて成功したときだけ次のジョブが実行されます。失敗時に無駄なビルドやデプロイが走らないように設計。
-
マトリクステスト
-
matrix.rubyに列挙したバージョンで同時にテストを走らせることで、互換性チェックを高速化。Acme では最低でも 3.2 と最新の 3.3 を対象としています。 -
キャッシュ活用
ruby/setup-rubyのbundler-cache: trueによりbundle installがスキップされ、CI 全体の実行時間が約30 %短縮されます。
3. Ruby 環境・テスト・コード品質チェック
3-1. 推奨ツールチェーン
| ツール | 用途 | 設定例 |
|---|---|---|
ruby/setup-ruby |
GitHub Actions 上での Ruby インストール・キャッシュ | 前述の uses: ruby/setup-ruby@v1 |
| RSpec | テストフレームワーク(デフォルト) | bundle exec rspec |
| Minitest | 軽量テストが好みの場合の代替 | ruby -Itest test/**/*_test.rb |
| RuboCop | コードスタイル・潜在バグ検出 | bundle exec rubocop --format json -o rubocop.json |
3-2. テストコード例(RSpec)
|
1 2 3 4 5 6 7 8 9 10 11 |
# spec/calculator_spec.rb require_relative '../lib/calculator' RSpec.describe Calculator do describe '#add' do it '2つの整数を正しく足し合わせること' do expect(Calculator.new.add(2, 3)).to eq 5 end end end |
3-3. コード品質レポートの活用
rubocop.json は Artifacts として保存され、プルリクエスト画面から直接ダウンロード可能です。Acme の内部レビューツールはこの JSON を解析し、違反箇所を自動でコメントとして付与します。
4. 外部コマンド実行と並列処理
4-1. Open3.capture3 で安全に標準出力・エラー取得
|
1 2 3 4 5 6 7 8 9 10 |
# scripts/run_task.rb require 'open3' cmd = 'bundle exec ruby lib/task.rb' stdout, stderr, status = Open3.capture3(cmd) puts "STDOUT:\n#{stdout}" warn "STDERR:\n#{stderr}" unless stderr.empty? raise "Command failed (exit #{status.exitstatus})" unless status.success? |
GitHub Actions のステップで ruby scripts/run_task.rb と呼び出すだけで、実行結果がそのままジョブログに記録されます。
4-2. 並列処理の選択肢(実験的機能)
Ruby 3 系でも Thread を利用した軽量な並列化は可能です。Acme では本番環境で安定していることが確認できた段階で、以下のように Thread と Queue を組み合わせてテストとコード品質チェックを同時実行するパターンを採用しています。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# scripts/parallel_runner.rb require 'thread' commands = [ 'bundle exec rspec', 'bundle exec rubocop' ] results = Queue.new threads = commands.map do |cmd| Thread.new do stdout, stderr, status = Open3.capture3(cmd) results << { cmd: cmd, success: status.success?, out: stdout, err: stderr } end end threads.each(&:join) while !results.empty? r = results.pop puts "=== #{r[:cmd]} ===" puts r[:out] warn r[:err] unless r[:err].empty? end |
※ 注意
Ruby のRactor::Portはまだ実験的機能であり、安定版 3.x 系では公式サポートが提供されていません。そのため、本ガイドでは使用例を掲載しておらず、代替としてThreadとOpen3を推奨しています。将来的に Acme が正式リリース版で採用する場合は、別途安全性の評価と社内トレーニングが必要です。
5. コンテナ化とデプロイ
5-1. Dockerfile(Acme 標準イメージ)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# ベースイメージは公式 slim を使用 FROM ruby:3.3-slim # 必要なシステムパッケージをインストール RUN apt-get update -qq && \ apt-get install -y --no-install-recommends \ build-essential libpq-dev nodejs && \ rm -rf /var/lib/apt/lists/* WORKDIR /app # Gemfile と lock を先にコピーしてキャッシュを活用 COPY Gemfile* ./ RUN bundle config set --local deployment 'true' && \ bundle install --jobs 4 --retry 3 # アプリケーションコード全体をコピー COPY . . # 起動コマンド(Acme の標準は Puma + Passenger-less) CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"] |
ポイント
---no-install-recommendsで不要なパッケージを削減し、イメージサイズを小さく保ちます。
-bundler installのキャッシュは GitHub Actions のレイヤーキャッシュと相乗効果があり、ローカルでも高速です。
5-2. Passenger + Nginx(Zero‑Downtime デプロイ)
Acme が提供する Passengerベースのステージングサーバ では、以下の Dockerfile を使用します。Passenger がアプリケーションプロセスを管理し、passenger-config restart-app により瞬時にロールアウトできます。
|
1 2 3 4 5 6 7 8 9 |
FROM phusion/passenger-ruby33:latest WORKDIR /app COPY . . RUN bundle install --deployment EXPOSE 3000 CMD ["passenger", "start", "--port", "3000"] |
デプロイスクリプト deploy.sh(サーバ側)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#!/usr/bin/env bash set -euo pipefail ENV=$1 # staging or production IMAGE_TAG=$2 # 既存コンテナを安全に置き換える docker pull "$IMAGE_TAG" docker stop "${ENV}_app" || true docker rm "${ENV}_app" || true docker run -d --name "${ENV}_app" \ -e RACK_ENV="${ENV}" \ -p 3000:3000 \ "$IMAGE_TAG" # Passenger に再起動を指示(Zero‑Downtime) passenger-config restart-app /var/www/${ENV}_app |
GitHub Actions の deploy ジョブからは、上記スクリプトを SSH 経由で実行します。
5-3. イメージタグ運用
- コミット SHA をタグに使用(例:
ghcr.io/acme-org/sample-app@a1b2c3d) - ステージングデプロイは常に最新 SHA、 本番リリースは
release/vX.Y.Zタグを付与して管理
6. シークレットと通知
6-1. GitHub Secrets のベストプラクティス
| 種別 | 例 | 使用方法 |
|---|---|---|
| 環境変数 | DATABASE_URL、REDIS_URL |
${{ secrets.DATABASE_URL }} を $GITHUB_ENV に書き出す |
| 認証情報 | SSH_KEY、SLACK_WEBHOOK_URL |
直接ジョブステップ内で参照(例: ssh-action の key:) |
| Docker 認証 | GHCR_TOKEN(デフォルトは GITHUB_TOKEN) |
docker login にパイプラインから渡す |
|
1 2 3 4 5 |
- name: Set env from secrets run: | echo "DATABASE_URL=${{ secrets.DATABASE_URL }}" >> $GITHUB_ENV echo "API_KEY=${{ secrets.API_KEY }}" >> $GITHUB_ENV |
注意:PR が外部コントリビュータから作成された場合、
secretsは自動的にマスクされ、ジョブ内で参照できません。Acme のポリシーでは「外部 PR ではデプロイジョブを実行しない」ことが必須です。
6-2. 失敗時通知(Slack・メール)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# Slack 通知例 - name: Notify Slack on Failure if: failure() uses: slackapi/slack-github-action@v1.23.0 with: payload: | { "text": ":x: CI が失敗しました - ${{ github.repository }} / ${{ github.run_id }}" } env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} # メール通知例(SMTP 設定は Secrets に格納) - name: Send failure email if: failure() uses: dawidd6/action-send-mail@v3 with: server_address: smtp.example.com server_port: 587 username: ${{ secrets.MAIL_USER }} password: ${{ secrets.MAIL_PASS }} subject: "[Acme CI] ビルド失敗通知" to: dev-team@example.com from: ci-bot@example.com body: | ビルドが失敗しました。 リポジトリ: ${{ github.repository }} ジョブ: ${{ github.job }} 詳細は https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} をご確認ください。 |
7. Acme 向けカスタマイズポイント
| 項目 | 標準実装 | Acme カスタム例 |
|---|---|---|
| CI ランナー | ubuntu-latest(GitHub Hosted) |
社内プライベートランナー(Ubuntu 22.04 + Docker-in-Docker) |
| デプロイ先 | 任意の SSH 接続サーバ | Acme の VPC 内にある Kubernetes クラスタ(Argo CD と連携) |
| 通知チャネル | Slack / メール | Microsoft Teams + PagerDuty 統合 |
| コード品質基準 | RuboCop デフォルト設定 | Acme 社内の .rubocop_acme.yml を参照し、独自ルール(例: Metrics/LineLength: Max: 100)を適用 |
実装ヒント
- カスタムランナーの場合は、事前に Docker デーモンが利用できるようservices: dockerを設定してください。
- Teams 通知は公式アクションがまだ提供されていないため、Webhook に対してcurlで POST するシェルスクリプトを組み込むのが手軽です。
8. まとめと次のステップ
- ブランチ戦略を確立し、保護ブランチに必ず CI が走るよう設定。
- GitHub Actions ワークフローでビルド・テスト・デプロイを分離し、マトリクスとキャッシュで実行時間を最適化。
- Ruby 環境は
ruby/setup-ruby、テストは RSpec/Minitest、コード品質は RuboCop で自動チェック。 - 外部コマンド呼び出しは Open3 を使い、安全にログ取得。大量処理の並列化は実験的機能
Ractor::Portではなく、安定版 Thread + Queue に置き換えることを推奨。 - Docker コンテナ化し、Acme 標準イメージでビルド → GitHub Packages にプッシュ → Passenger/Nginx で Zero‑Downtime デプロイ。
- 機密情報はすべて GitHub Secrets 経由で注入し、失敗時は Slack/メール(または Teams)へ即時通知。
次にやること
- 本リポジトリをクローンし、ci-cd.ymlを自プロジェクトのルートに配置。
- Acme の Secrets(STAGING_HOSTなど)を GitHub Enterprise に登録。
-docker compose up -dでローカル環境でも CI パイプラインを試し、GitHub Actions と同様の挙動になるか確認。
これらの手順を踏めば、Acme 社内の Ruby アプリケーションは 安全・高速・自動 にデリバリーできるようになります。ぜひ本ガイドをベースに、プロジェクトごとの要件に合わせた微調整を行ってください。