はじめに
RailsアプリをCapistranoでEC2(Docker使ってない)にデプロイしています。
普段ローカルでbundle exec cap staging deploy
を実行してEC2にデプロイしていたのですが、GitHub Actionsでデプロイできるようにしました。
本記事では以下のシチュエーションを想定しています。
- developブランチで修正する
- ローカルでCapistranoデプロイが既にできている
- ステージングサーバーにデプロイする
- Macを使用している
前提
CapstranoはSSH接続ができることを前提としています。
ローカルでデプロイできるということは、すでにローカル環境がリモートサーバーにSSH接続ができるように設定されているからです。
しかしGitHub Actionsのランナーは当然設定してあげないと、対象のリモートサーバーとはSSH接続ができません。
ランナーがSSH接続できるようになれば、あとはcapコマンドでいい感じに自動でデプロイしてくれるようになります。
つまり、ランナーがリモートサーバーとSSH接続できるようにしてあげることが一番の鍵となります。
そしてSSHの接続設定を簡単に行えるのが、shimataro/ssh-key-action@v2です。
ワークフロー内で秘密鍵をSecretsからコピーする工程があるのですが、最後に.sshディレクトリごと削除してくれます。
ざっくり流れ
- デプロイに必要なファイルの作成・修正
- ローカルでSSHのキーペアを作成する
- 公開鍵をサーバーに登録する
- GitHub Secretsに秘密鍵を登録
- GitHub SecretsにKNOWN_HOSTSを登録
- Actionsを実行
1. デプロイに必要なファイルの作成・修正
ファイル名は自由ですが、.github/workflowsディレクトリを作成してその中にファイルを置いてください。
name: Staging Deploy
on:
push:
branches:
- develop
jobs:
deploy:
name: Capistrano Deploy to Staging
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Install SSH key
uses: shimataro/ssh-key-action@v2
with:
key: ${{ secrets.STAGING_SSH_KEY }}
name: github-actions # optional
known_hosts: ${{ secrets.STAGING_KNOWN_HOSTS }}
if_key_exists: fail # replace / ignore / fail; optional (defaults to fail)
- uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- name: Deploy to EC2
run: |
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/github-actions
BRANCH=develop bundle exec cap staging deploy
以下の2行はsshエージェントを起動し、指定した秘密鍵を登録します。
config/deploy/staging.rb
のssh_options
で使用する秘密鍵のパスを設定しているので不要かもしれませんが、念の為記述しておきます。
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/github-actions
新しく~/.ssh/github-actions
という秘密鍵を作成するため、そちらを参照するように修正してください。
set :ssh_options, {
keys: [
# 以下に変更
File.expand_path('~/.ssh/github-actions')
],
}
必要なファイルの修正が済んだので、いよいよSSHのキーペアの作成をしていきます。
2. ローカルでSSHのキーペアを作成する
使い回しは良くないのでローカルで普段デプロイ時に利用しているキーペアとは別に、Actions用の公開鍵と秘密鍵を作成します。
Macのターミナルで以下を実行してください。
-
-C
...コメント。任意ですが、後々のことを考えて分かりやすい文言を設定しておくと良いです。 -
-f
...生成されるキーのファイル名とパスを指定します。こちらも任意ですが、.sshディレクトリで簡単に識別できるよう、分かりやすい名前にしました。
その他オプションに関してはこちらをご確認ください。
ssh-keygen -t rsa -b 4096 -C "StagingのGitHub Actions" -f ~/.ssh/stg_github_actions
上記を実行後、.sshディレクトリにstg_github_actions
(秘密鍵)とstg_github_actions.pub
(公開鍵)が生成されることを確認してください。
なお、当然ですが秘密鍵はGit管理などしないよう慎重に扱ってください。
3. 公開鍵をサーバーに登録する
サーバーの~/.ssh/authorized_keys
に公開鍵を登録します。
Macのターミナルでリモートユーザー名とホスト名を各自置き換え、以下を実行してください。
ssh-copy-id -i ~/.ssh/stg_github_actions.pub [リモートユーザー]@[リモートサーバーのホスト名]
サーバーにssh接続し、authorized_keysに先ほど作成した公開鍵が記入されてることを確認します。
# ローカルでcat ~/.ssh/stg_github_actions.pubを実行した結果と同じ値が記入されていたらOK
cat ~/.ssh/authorized_keys
もし上記ssh-copy-id
コマンドがうまくいかない場合は、手動でサーバーの~/.ssh/authorized_keys
に公開鍵を記入すれば大丈夫です。
手動で公開鍵をサーバーに登録する手順(必要な人だけクリックで表示)
先ほど作成した公開鍵をの中身をcatで表示し、値をコピーしてください。
cat ~/.ssh/stg_github_actions.pub
sshでリモートサーバーに接続し、~/.ssh/authorized_keys
の最後にペーストします。
vi ~/.ssh/authorized_keys
# ローカルでcat ~/.ssh/stg_github_actions.pubを実行した結果と同じ値が記入されていたらOK
cat ~/.ssh/authorized_keys
4. GitHub Secretsに秘密鍵を登録
先ほど作成した秘密鍵の中身をコピーします。
cat ~/.ssh/stg_github_actions
GitHubの対象リポジトリ>Settings>Secrets and variables>Actions>Repository secrets>New repository secretsで新しいsecretを作成します。
- Name...
STAGING_SSH_KEY
- Value...秘密鍵の値
5. GitHub Secretsにknown_hostsを登録
リモートサーバーにssh接続をすでにしたことがある人は、ローカルのknown_hostsファイルにリモートサーバーの公開鍵情報が登録されていると思います。
known_hostsの中身を表示し、対象のリモートサーバーのホスト名(example.com)かIPアドレスで検索してみてください。
cat ~/.ssh/known_hosts
ヒットした行全てをそのままコピーします。
もし検索がうまくいかない場合は、ssh-keyscanというコマンドの結果をコピーしても大丈夫そうです(試したことがないので保証はしません)
known_hostsをコピーしたら、GitHubの対象リポジトリで新しいsecretを作成します。
- Name...
STAGING_KNOWN_HOSTS
- Value...コピーした値
これで必要なSecretsは揃いました!
6. Actions実行
ymlに以下のトリガーを指定したため、例えばdevelopブランチがpushされたタイミングで実行されます。
トリガーは自由に設定していただいて大丈夫です。
Actions実行後、正常にデプロイできたか確認してください。
on:
push:
branches:
- develop
以上です!
エラー集
私が遭遇したエラーと解決策を載せておくので、参考にしていただければと思います。
Permission denied (publickey). fatal: Could not read from remote repository.
00:02 git:check
01 git ls-remote git@github.com:hoge/repo.git HEAD
01 Permission denied (publickey).
01 fatal: Could not read from remote repository.
01
01 Please make sure you have the correct access rights
01 and the repository exists.
EC2がGitHubにSSH接続できないことが原因でした。
実際リモートサーバー内でgit ls-remote git@github.com:hoge/repo.git HEAD
をすると、Permissionエラーが出ました。
以下の記事を参考に、リモートサーバー上でSSHキーペアを作成→GitHubのリポジトリのSettings>Deploy keysに公開鍵を登録してください。
OpenSSH keys only supported if ED25519 is available (NotImplementedError)
OpenSSH keys only supported if ED25519 is available (NotImplementedError)
net-ssh requires the following gems for ed25519 support:
* ed25519 (>= 1.2, < 2.0)
* bcrypt_pbkdf (>= 1.0, < 2.0)
こちらを参考に、以下をGemfileに記述してbundle install
を実行してください。
group :development do
gem 'ed25519', '>= 1.2', '< 2.0'
gem 'bcrypt_pbkdf', '>= 1.0', '< 2.0'
end