はじめに
capistrano大好き芸人の私ですが、内部で使われているsshkitは使ったことがありません。
最近はcapiの仕様把握にsshkitのコードも読むようになったんですが、まずは使わないとということでササっと使ってみます。
sshkit
文字通り、リモートサーバに対してsshでコマンドを送り込むツールです。sshpassの簡単版、かつRuby製。
環境構築
Vagrantでササっとね。
take@MacBook-Air ~/v/sshkit> cat Vagrantfile Vagrant.configure(2) do |config| config.vm.box = "CentOS71" config.vm.define :sshkit do | sshkit | sshkit.vm.hostname = "sshkit" sshkit.vm.network :private_network, ip: "192.168.33.10" end end
Vagrant up!
take@MacBook-Air ~/v/sshkit> vagrant up Bringing machine 'sshkit' up with 'virtualbox' provider... ==> sshkit: Importing base box 'CentOS71'... ==> sshkit: Matching MAC address for NAT networking... ==> sshkit: Setting the name of the VM: sshkit_sshkit_1471449306450_7881 ==> sshkit: Clearing any previously set network interfaces... ==> sshkit: Preparing network interfaces based on configuration... sshkit: Adapter 1: nat sshkit: Adapter 2: hostonly ==> sshkit: Forwarding ports... sshkit: 22 => 2222 (adapter 1) ==> sshkit: Booting VM... ==> sshkit: Waiting for machine to boot. This may take a few minutes... sshkit: SSH address: 127.0.0.1:2222 sshkit: SSH username: vagrant sshkit: SSH auth method: private key sshkit: Warning: Connection timeout. Retrying... sshkit: sshkit: Vagrant insecure key detected. Vagrant will automatically replace sshkit: this with a newly generated keypair for better security. sshkit: sshkit: Inserting generated public key within guest... sshkit: Removing insecure key from the guest if it's present... sshkit: Key inserted! Disconnecting and reconnecting using new SSH key... ==> sshkit: Machine booted and ready! GuestAdditions 4.3.30 running --- OK. ==> sshkit: Checking for guest additions in VM... ==> sshkit: [vagrant-hostsupdater] Checking for host entries ==> sshkit: [vagrant-hostsupdater] Writing the following entries to (/etc/hosts) ==> sshkit: [vagrant-hostsupdater] 192.168.33.10 sshkit # VAGRANT: f84bf2d975137fc696642d0375f8d9dc (sshkit) / 75284f8d-ceb2-46ee-8043-7ced9bb6b630 ==> sshkit: [vagrant-hostsupdater] This operation requires administrative access. You may skip it by manually adding equivalent entries to the hosts file. Password: ==> sshkit: Setting hostname... ==> sshkit: Configuring and enabling network interfaces... ==> sshkit: Mounting shared folders... sshkit: /vagrant => /Users/take/vagrant/sshkit
take@MacBook-Air ~/v/sshkit> ping 192.168.33.10 PING 192.168.33.10 (192.168.33.10): 56 data bytes 64 bytes from 192.168.33.10: icmp_seq=0 ttl=64 time=0.596 ms 64 bytes from 192.168.33.10: icmp_seq=1 ttl=64 time=0.516 ms ^C --- 192.168.33.10 ping statistics --- 2 packets transmitted, 2 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 0.516/0.556/0.596/0.040 ms take@MacBook-Air ~/v/sshkit> vagrant ssh Last login: Wed Aug 17 17:02:14 2016 from 10.0.2.2
sshkitを使う
capiで入ってるかと思ったけど、バージョンが更新されたのかな。
take@MacBook-Air ~/v/sshkit> sudo gem install sshkit Password: Fetching: sshkit-1.11.2.gem (100%) Successfully installed sshkit-1.11.2 Parsing documentation for sshkit-1.11.2 Installing ri documentation for sshkit-1.11.2 Done installing documentation for sshkit after 0 seconds 1 gem installed
単純にuptimeを実行するだけのコードを書きます。
take@MacBook-Air ~/v/sshkit> cat sample.rb require 'sshkit' require 'sshkit/dsl' include SSHKit::DSL on "192.168.33.10" do |host| execute :uptime end
実行すると。。。失敗。
take@MacBook-Air ~/v/sshkit> ruby sample.rb INFO [4b19d6d3] Running /usr/bin/env uptime on 192.168.33.10 /Library/Ruby/Gems/2.0.0/gems/net-ssh-2.9.1/lib/net/ssh/verifiers/secure.rb:50:in `process_cache_miss': fingerprint 11:48:65:bc:27:f5:30:82:7d:81:c2:b7:79:ac:36:ae does not match for "192.168.33.10" (Net::SSH::HostKeyMismatch) from /Library/Ruby/Gems/2.0.0/gems/net-ssh-2.9.1/lib/net/ssh/verifiers/secure.rb:35:in `verify' from /Library/Ruby/Gems/2.0.0/gems/net-ssh-2.9.1/lib/net/ssh/verifiers/strict.rb:16:in `verify' from /Library/Ruby/Gems/2.0.0/gems/net-ssh-2.9.1/lib/net/ssh/verifiers/lenient.rb:15:in `verify' from /Library/Ruby/Gems/2.0.0/gems/net-ssh-2.9.1/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb:173:in `verify_server_key' from /Library/Ruby/Gems/2.0.0/gems/net-ssh-2.9.1/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb:68:in `exchange_keys' from /Library/Ruby/Gems/2.0.0/gems/net-ssh-2.9.1/lib/net/ssh/transport/algorithms.rb:364:in `exchange_keys' from /Library/Ruby/Gems/2.0.0/gems/net-ssh-2.9.1/lib/net/ssh/transport/algorithms.rb:205:in `proceed!' from /Library/Ruby/Gems/2.0.0/gems/net-ssh-2.9.1/lib/net/ssh/transport/algorithms.rb:196:in `send_kexinit' from /Library/Ruby/Gems/2.0.0/gems/net-ssh-2.9.1/lib/net/ssh/transport/algorithms.rb:151:in `accept_kexinit' from /Library/Ruby/Gems/2.0.0/gems/net-ssh-2.9.1/lib/net/ssh/transport/session.rb:195:in `block in poll_message' from /Library/Ruby/Gems/2.0.0/gems/net-ssh-2.9.1/lib/net/ssh/transport/session.rb:173:in `loop' from /Library/Ruby/Gems/2.0.0/gems/net-ssh-2.9.1/lib/net/ssh/transport/session.rb:173:in `poll_message' from /Library/Ruby/Gems/2.0.0/gems/net-ssh-2.9.1/lib/net/ssh/transport/session.rb:210:in `block in wait' from /Library/Ruby/Gems/2.0.0/gems/net-ssh-2.9.1/lib/net/ssh/transport/session.rb:208:in `loop' from /Library/Ruby/Gems/2.0.0/gems/net-ssh-2.9.1/lib/net/ssh/transport/session.rb:208:in `wait' from /Library/Ruby/Gems/2.0.0/gems/net-ssh-2.9.1/lib/net/ssh/transport/session.rb:87:in `initialize' from /Library/Ruby/Gems/2.0.0/gems/net-ssh-2.9.1/lib/net/ssh.rb:202:in `new' from /Library/Ruby/Gems/2.0.0/gems/net-ssh-2.9.1/lib/net/ssh.rb:202:in `start' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/backends/connection_pool.rb:59:in `call' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/backends/connection_pool.rb:59:in `with' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/backends/netssh.rb:155:in `with_ssh' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/backends/netssh.rb:108:in `execute_command' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/backends/abstract.rb:141:in `block in create_command_and_execute' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/backends/abstract.rb:141:in `tap' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/backends/abstract.rb:141:in `create_command_and_execute' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/backends/abstract.rb:74:in `execute' from sample.rb:6:in `block in <main>' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/backends/abstract.rb:29:in `instance_exec' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/backends/abstract.rb:29:in `run' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/runners/parallel.rb:12:in `block (2 levels) in execute'
はい。vagrantで作ったのでssh関係で引っかかるかなと予想はしていたんですが、あたってしまいました。
しかし、finger printが違うといっているので、過去に同じIPに接続したときのknown_hostを見に行ってるのでしょう。該当のエントリを削除しました。
take@MacBook-Air ~/v/sshkit> ruby sample.rb INFO [b6b8b67a] Running /usr/bin/env uptime as vagrant@192.168.33.10 /Library/Ruby/Gems/2.0.0/gems/net-ssh-2.9.1/lib/net/ssh.rb:219:in `start': Authentication failed for user vagrant@192.168.33.10 (Net::SSH::AuthenticationFailed) from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/backends/connection_pool.rb:59:in `call' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/backends/connection_pool.rb:59:in `with' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/backends/netssh.rb:155:in `with_ssh' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/backends/netssh.rb:108:in `execute_command' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/backends/abstract.rb:141:in `block in create_command_and_execute' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/backends/abstract.rb:141:in `tap' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/backends/abstract.rb:141:in `create_command_and_execute' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/backends/abstract.rb:74:in `execute' from sample.rb:13:in `block in <main>' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/backends/abstract.rb:29:in `instance_exec' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/backends/abstract.rb:29:in `run' from /Library/Ruby/Gems/2.0.0/gems/sshkit-1.11.2/lib/sshkit/runners/parallel.rb:12:in `block (2 levels) in execute'
さてAuthentication failedということで、keyの位置を教えてあげたほうが良さそうです。
take@MacBook-Air ~/v/sshkit> vagrant ssh-config Host sshkit HostName 127.0.0.1 User vagrant Port 2222 UserKnownHostsFile /dev/null StrictHostKeyChecking no PasswordAuthentication no IdentityFile /Users/take/vagrant/sshkit/.vagrant/machines/sshkit/virtualbox/private_key IdentitiesOnly yes LogLevel FATAL
コードを以下のように変更
take@MacBook-Air ~/v/sshkit> cat sample.rb require 'sshkit' require 'sshkit/dsl' include SSHKit::DSL remote_host = SSHKit::Host.new('192.168.33.10') remote_host.user = "vagrant" remote_host.ssh_options = { keys: %w(/Uers/take/vagrant/sshkit/.vagrant/machines/sshkit/virtualbox/private_key), auth_methods: %w(publickey) } on remote_host do |host| execute :uptime end
無事成功!
take@MacBook-Air ~/v/sshkit> ruby sample.rb INFO [a3837d1b] Running /usr/bin/env uptime as vagrant@192.168.33.10 INFO [a3837d1b] Finished in 0.116 seconds with exit status 0 (successful).
参考 qiita.com
おわりに
capiをがっつり使ってきましたが、sshkitを使い倒すことも大事かと思います。capiより身軽に使えるので便利な気がする。ソースリーディングとドキュメント翻訳も今後はやっていきたい。