今、職場でcapistranoというツールを使ってデプロイするRailsシステムを扱っている。
つい数週間前とくに問題なく実行完了できたデプロイ処理が、先日エラーで進められなくなっていた。
今回の記事では、その時の「2段構えのエラー」を完全に回避する解に辿り着くまでの顛末を書いておく。
なお、解決の要点は次の2点だった。
- Gemfile へ次の2つを追加して bundle install
gem 'ed25519'
gem 'bcrypt_pbkdf'
- net-sshパッケージを 5.0.2 から 5.2.0 へアップデート
$ bundle update net-ssh
最初の伏兵と遭遇
$ bundle exec cap production deploy
~~省略~~
00:01 deploy:check:directories
01 mkdir -p /var/www/hoge/shared /var/www/hoge/releases
verify_host_key: :secure is deprecated, use :always
(Backtrace restricted to imported tasks)
cap aborted!
NotImplementedError: OpenSSH keys only supported if ED25519 is available
net-ssh requires the following gems for ed25519 support:
* ed25519 (>= 1.2, < 2.0)
* bcrypt_pbkdf (>= 1.0, < 2.0)
See https://github.com/net-ssh/net-ssh/issues/565 for more information
Gem::LoadError : "ed25519 is not part of the bundle. Add it to your Gemfile."
このエラー自体は対処についての情報がメッセージ中にあり、ネット上にも下記のようにピンポイントな記事があってありがたかった。
Capistranoデプロイしようとしたら突然ed25519エラーが出たときの解消法
https://qiita.com/Tosh39/items/7bac004d821299cc4f6b
Gemfileに次を追加して bundle install で解消である。
+ gem 'ed25519'
+ gem 'bcrypt_pbkdf'
ところが。
伏兵は2段構えだった
その後デプロイコマンドを再実行すると、エラー内容が変わった。
00:01 deploy:check:directories
01 mkdir -p /var/www/hoge/shared /var/www/hoge/releases
verify_host_key: :secure is deprecated, use :always
(Backtrace restricted to imported tasks)
cap aborted!
SSHKit::Runner::ExecuteError: Exception while executing as dep-user@192.168.55.31: expected 64-byte String, got 3
もちろん、事前に下記でSSH接続が成功するように .ssh/config 等の設定は済ませ、接続確認もしてある。
$ ssh dep-user@192.168.55.31
Rails や capistrano というツール自体は今回のプロジェクトで初めて触るので良くは知らないのだが、以前 ansible を使った時に「つくづくSSH周りのことを紐解かないといけないエラーばっかり出遭うな」という体験をしていたので、この件もまずはSSH周りの設定を疑ってみた。
まずは ssh-agent 周り
ssh-agent の挙動が影響しないか探ってみることにし、下記の記事などを情報源にアレコレやってみた。
capistranoでデプロイする時のssh-key周りのTips
https://qiita.com/Takkiii/items/c4f2cfd143e97e061e66
ssh-add で Could not open a connection to your authentication agent が出るときの対処法
https://qiita.com/ytheta/items/cbbd0b833c19784dfa1e
が、今回の件とは関係無さそうだった。
SSHKitを単体で使ってみる
そこで「最終的にSSH接続を実行しているライブラリ単体で動かせるかどうかを確かめよう」と考えた。
下記の記事等の情報源から、SSHkit を単体で使う実験をしてみた。
sshkitを単体で使ってみる
https://qiita.com/cazador/items/2d675f911b23d4fed160
SSHKitを実際に使ってみて理解する
http://48n.jp/blog/2016/06/14/learn-ssh-kit/
簡易なスクリプトを作って、
$ cat hoge.rb
require 'sshkit'
require 'sshkit/dsl'
require 'ed25519'
require 'bcrypt_pbkdf'
include SSHKit::DSL
SSHKit.config.output_verbosity = Logger::DEBUG
remote_host = SSHKit::Host.new('192.168.55.31')
remote_host.user = "dep-user"
remote_host.ssh_options = {
verify_host_key: :always,
keys: %w(~/.ssh/hoge_rsa),
forward_agent: true,
auth_methods: %w(publickey)
}
on remote_host do
execute :ls
end
これを実行してみるも、どうも的を射たメッセージが得られない。
$ bundle exec ruby hoge.rb
INFO [86e23d74] Running /usr/bin/env ls as dep-user@192.168.55.31
DEBUG [86e23d74] Command: /usr/bin/env ls
/home/hoge/repo/vendor/bundle/ruby/2.4.0/gems/sshkit-1.17.0/lib/sshkit/runners/parallel.rb:15:in `rescue in block (2 levels) in execute': Exception while executing as dep-user@192.168.55.31: Authentication failed for user dep-user@192.168.55.31 (SSHKit::Runner::ExecuteError)
from /home/hoge/repo/vendor/bundle/ruby/2.4.0/gems/sshkit-1.17.0/lib/sshkit/runners/parallel.rb:11:in `block (2 levels) in execute'
とはいえ、
これによって capistrano そのもののことは考えなくていいことはわかった。
改めて capistrano 実行時のエラーを眺めてみる
手がかりになりそうなキーワードを求めてアレコレ眺めていて、
expected 64-byte String, got 3
でググってみたらこんな検索結果が出てきた。
Error "expected 64-byte String, got 3" · Issue #442 · capistrano/sshkit
https://github.com/capistrano/sshkit/issues/442
英語のやり取りを頑張って読み進めていったら
Upgrading net-ssh from 5.0.2 to 5.1.0 solved this issue for me.
やっと光が見えた!
問題を完全回避できた
晴れて、下記にて net-ssh をアップデートすることで net-sshパッケージが 5.0.2 から 5.2.0 へアップデートされ、
先程の hoge.rb もエラー無く実行できるようになった。
$ bundle update net-ssh
そしてこれによって capistrano の処理も初期処理から先へ話が進んだ。
capistrano のことはやっぱりまだよく知らない
以上は「capistrano によるデプロイがエラーでコケる」という事態に対処した記録ですが、
最初から「sshコマンドではイケているユーザによるSSHログインがcap処理では通らない」ということに目星を付けたので、 capistrano そのもののことはほとんど調べることなくひたすらSSHのトラブルシュートで乗り越えました。
capistrano なり ansible なり、SSHを介してデプロイを行うツールを使う際は、事前にssh周りの知識を脳内整理しておいた方がいいと思います!
今回の記事は以上です。