こんにちは、駆け出しエンジニアのよしこ @k2_yoshikoukiです
CI/CDってカッコいいですよね。なんかこう、カッコいいんですよね(語彙力)
しかし「どうやって実装したらいいのかワケワカメ\(^o^)/」というエンジニアの方は多いと思います。でも実際はとても簡単なんだよということを知ってほしかったので、10分で読める記事で CI/CD のうちのCD(自動デプロイ)を実装していきたいと思います。
実作業時間は詰まらなかったら30分かからないくらいです。
ゴール
CI/CD をやってみたいがやったことがないし何から手を付けたら良いか分からないエンジニア向けに、Rails アプリ (6系) で自動デプロイを最速で実装する。
結果、GitHub Actions を使ったCI/CDの大枠を把握できて自力で実装できるようになる
実装フローを見ていく
- Rails アプリを作る
- Heroku に手動デプロイして動作確認
- GitHub Actions の初期設定
-
./.github/workflows/{好きな名前}.yml
の作成 - 必要な鍵などの取得・GitHubへ設定
-
すでにアプリケーションがある方は 3 からです。たった2ステップで自動デプロイが実装できます。早速やっていきましょう
手順
Railsアプリの準備
-
rails new sample-rails-with-gha
~/tmp/sample-rails-with-gha ❯ rails -v Rails 6.0.3.4 ~/tmp/sample-rails-with-gha ❯ ruby -v ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-darwin19] # 後から2.7.2にアップデートします(デバックのため)
bundle install rails server
リポジトリの準備
- GitHub上にリポジトリを作る
https://github.com/new -
ローカルにリポジトリを登録
git remote add origin https://github.com/yoshikouki/sample-rails-with-gha.git
-
アップロード
git add -A git commit -m "rails new" git push -u origin master
-
デプロイの初期設定と初回デプロイ
-
今回はデプロイ先に Heroku を使う(簡単なので)
~/tmp/sample-rails-with-gha master ❯ heroku --version zsh: command not found: heroku
-
Heroku 入ってなかった・・・
brew tap heroku/brew && brew install heroku # https://devcenter.heroku.com/articles/heroku-cli
Heroku アカウントを作っておく
https://signup.heroku.com/-
Heroku にログイン(ターミナル上)
heroku login --interactive
-
Heroku 用のアプリケーションを作る(アップロードする場所を作る)
heroku create # URL を控えておく # https://sleepy-beyond-32826.herokuapp.com/ # `$ heroku open` でも開ける
-
Heroku は sqlite3 に対応していないため、
./Gemfile
を操作する -
Heroku へデプロイする
git push heroku master
-
あらら
- エラーログ
$ heroku logs 2020-11-22T14:39:05.610528+00:00 app[web.1]: I, [2020-11-22T14:39:05.610419 #4] INFO -- : [a6b71e5b-f13a-4224-a857-9b791da3ecc4] Started GET "/" for 133.32.232.41 at 2020-11-22 14:39:05 +0000 2020-11-22T14:39:05.611222+00:00 app[web.1]: F, [2020-11-22T14:39:05.611152 #4] FATAL -- : [a6b71e5b-f13a-4224-a857-9b791da3ecc4] 2020-11-22T14:39:05.611223+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] ActionController::RoutingError (No route matches [GET] "/"): 2020-11-22T14:39:05.611224+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] 2020-11-22T14:39:05.611225+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] actionpack (6.0.3.4) lib/action_dispatch/middleware/debug_exceptions.rb:36:in `call' 2020-11-22T14:39:05.611225+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] actionpack (6.0.3.4) lib/action_dispatch/middleware/show_exceptions.rb:33:in `call' 2020-11-22T14:39:05.611226+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] railties (6.0.3.4) lib/rails/rack/logger.rb:37:in `call_app' 2020-11-22T14:39:05.611226+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] railties (6.0.3.4) lib/rails/rack/logger.rb:26:in `block in call' 2020-11-22T14:39:05.611226+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] activesupport (6.0.3.4) lib/active_support/tagged_logging.rb:80:in `block in tagged' 2020-11-22T14:39:05.611227+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] activesupport (6.0.3.4) lib/active_support/tagged_logging.rb:28:in `tagged' 2020-11-22T14:39:05.611227+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] activesupport (6.0.3.4) lib/active_support/tagged_logging.rb:80:in `tagged' 2020-11-22T14:39:05.611228+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] railties (6.0.3.4) lib/rails/rack/logger.rb:26:in `call' 2020-11-22T14:39:05.611228+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] actionpack (6.0.3.4) lib/action_dispatch/middleware/remote_ip.rb:81:in `call' 2020-11-22T14:39:05.611228+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] actionpack (6.0.3.4) lib/action_dispatch/middleware/request_id.rb:27:in `call' 2020-11-22T14:39:05.611229+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] rack (2.2.3) lib/rack/method_override.rb:24:in `call' 2020-11-22T14:39:05.611229+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] rack (2.2.3) lib/rack/runtime.rb:22:in `call' 2020-11-22T14:39:05.611230+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] activesupport (6.0.3.4) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call' 2020-11-22T14:39:05.611230+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] actionpack (6.0.3.4) lib/action_dispatch/middleware/executor.rb:14:in `call' 2020-11-22T14:39:05.611231+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] actionpack (6.0.3.4) lib/action_dispatch/middleware/static.rb:126:in `call' 2020-11-22T14:39:05.611231+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] rack (2.2.3) lib/rack/sendfile.rb:110:in `call' 2020-11-22T14:39:05.611232+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] actionpack (6.0.3.4) lib/action_dispatch/middleware/host_authorization.rb:76:in `call' 2020-11-22T14:39:05.611232+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] railties (6.0.3.4) lib/rails/engine.rb:527:in `call' 2020-11-22T14:39:05.611232+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] puma (4.3.6) lib/puma/configuration.rb:228:in `call' 2020-11-22T14:39:05.611233+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] puma (4.3.6) lib/puma/server.rb:713:in `handle_request' 2020-11-22T14:39:05.611233+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] puma (4.3.6) lib/puma/server.rb:472:in `process_client' 2020-11-22T14:39:05.611233+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] puma (4.3.6) lib/puma/server.rb:328:in `block in run' 2020-11-22T14:39:05.611234+00:00 app[web.1]: [a6b71e5b-f13a-4224-a857-9b791da3ecc4] puma (4.3.6) lib/puma/thread_pool.rb:134:in `block in spawn_thread' 2020-11-22T14:39:05.612663+00:00 heroku[router]: at=info method=GET path="/" host=sleepy-beyond-32826.herokuapp.com request_id=a6b71e5b-f13a-4224-a857-9b791da3ecc4 fwd="133.32.232.41" dyno=web.1 connect=1ms service=4ms status=404 bytes=1902 protocol=https 2020-11-22T14:39:05.858618+00:00 heroku[router]: at=info method=GET path="/favicon.ico" host=sleepy-beyond-32826.herokuapp.com request_id=831fe7f9-bc01-496d-a9ac-380c9c89dd3c fwd="133.32.232.41" dyno=web.1 connect=1ms service=2ms status=200 bytes=143 protocol=https
- なるほどねえ(分かっていない)
ActionController::RoutingError (No route matches [GET] "/"):
# ./config/routes Rails.application.routes.draw do # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html end
GitHub Actions を設定していく
-
空の設定ファイルを作る
mkdir -p ./.github/workflows tocuh -p ./.github/workflows/sample_cd.yml
-
設定していく
-
設定ファイル
name: Deploy to sample-rails-with-gha on: # master ブランチにプッシュされた場合に動作する push: branches: - master jobs: deploy: runs-on: ubuntu-latest steps: # GitHub リポジトリからコードを引っ張ってくる - name: Checkout uses: actions/checkout@v2 # 前回のコンテナキャッシュがあれば使用する。なければキャッシュを作る - name: Cache multiple paths uses: actions/cache@v2 with: path: vendor/bundle key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }} restore-keys: | ${{ runner.os }}-gems- # Ruby をインストールする - name: Set up Ruby 2.7 uses: actions/setup-ruby@v1 with: ruby-version: 2.7 # バンドラーをインストールし、初期化する - name: Bundle install run: | gem install bundler bundle config path vendor/bundle bundle install --jobs 4 --retry 3 # ヘロクにデプロイする - uses: akhileshns/heroku-deploy@v3.6.8 # This is the action with: heroku_api_key: ${{secrets.HEROKU_API_KEY}} heroku_app_name: "sleepy-beyond-32826" heroku_email: "yoshikouki@gmail.com"
-
簡単な設定ファイルなので説明はファイル内のコメントを参考にしてください。
- アクションという Ruby でいう Gem のような機能を使用しています。
-
ドキュメント
-
secrets.HEROKU_API_KEY
が必要なので Heroku で取得する-
https://dashboard.heroku.com/account
もしくは
自分のアイコン
>Account settings
- 下部
API Key
ここのKeyをコピーする
-
https://dashboard.heroku.com/account
もしくは
-
取得した Key をGitHub で使用できるように設定する
-
sample-rails-with-gha
のリポジトリ >Settings
>Secrets
- GitHub Actions で使用する非公開環境変数の設定画面になる
>
New repository secret
- Name に
HEROKU_API_KEY
Value に先程Herokuで取得したキーをセット >Add secret
-
-
-
準備は整ったので、master/main ブランチにプッシュしてみる
- そして順調にエラーになった
- エラーになった画面
https://github.com/yoshikouki/sample-rails-with-gha/runs/1438564960?check_suite_focus=true
デバッグ
-
actions/cache のドキュメントは bundle がインストールしてある前提だったので
gem install bundler
を追加した -
Gemfile に記述されている ruby-version と GitHub Actions のコンテナ内のRubyを一致させること
uses: actions/setup-ruby@v1 with: ruby-version: 2.7
- GitHub Actions setup-ruby ではマイナーバージョンまでしか指定できないみたいなので、手元Rubyのメンテナンス (ビルド) バージョンをあげることになるかもしれない
- マイナーバージョンが上がるわけではないので、素直に上げておけばいいと思う
そして...
まとめ
以上で Rails アプリ (6系) で自動デプロイまでを最速で実装しました。
以後は、master (main) ブランチへ push するだけで heroku へ自動デプロイされます。これで2〜3コマンド分の実行の手間が省けたことになりますし、あなたはもう完全に CI/CD を習得したエンジニアです。
(実際のところ、今回はCI部分を何も扱っていませんし、デプロイに関してもデータベースを触っていないので中途半端な状態ではあるのですが、最低限は実装できたので良しとしましょう。してください。)