基本的にVagrantはプロビジョニングを行う際sudoをつけてコマンドを実行しますが、Boxでrequirettyが有効になっていると作成した仮想マシン上でsudoをつけてコマンドが実行できずエラーが発生してしまいます。
クラウド系のプラグインはサービスプロバイダが提供しているイメージ・テンプレートをボックスとして使用するものが多いので、そのままではrequirettyが有効になっている場合があります。自分でrequirettyを無効化したイメージを作成し直すこともできますが、
既存のイメージを使用することができればサービスプロバイダが提供している様々なイメージが利用しやすくなります。
そこで今回はrequirettyが有効なイメージを使用する方法を調べてみます。
今回調べた方法はあくまで一時的にrequirettyを回避する方法です。何度も使用するイメージについてはrequirettyを無効化しておいた方が後で問題がでないと思います。
TL;DR
- requirettyが有効なテンプレートでも
config.ssh.pty=true
とすることでsudoをすることができる。 - ログインユーザーがrootであれば
config.ssh.sudo_command
を使ってsudo無しでコマンドを実行するように設定できる - Rsync Synced Folderを使う場合
rsync__rsync_path
でsudo無しでrsyncを実行するよう設定できる
環境
動作の確認は以下の環境で行いました。
- Vagrant (1.7.4)
- vagrnt-cloudstack (1.1.0)
- IDCFクラウド
Vagrantfile
以下のVagrntfileをテスト用に使用します。
vagrant-cloudstackを使用してIDCFクラウド上にVMを作成しています。IDCFクラウドにはrequirettyが無効化されたVagrant用のテンプレートが用意されているのですが、ここではあえてVagrant用でないrequirettyが有効なテンプレートを使用します。
IDCFクラウドのテンプレートの仕様でデフォルトのログインユーザーがrootのためoverride.ssh.username = "root"
でログインユーザーをrootとしてあります。また、後述するようにrequirettyが有効な場合Rsync Synced Folderにも影響があるのでいったん無効化しておきます。
Vagrant.configure("2") do |config|
config.vm.provider :cloudstack do |cloudstack, override|
override.vm.box = "dummy"
override.vm.box_url = "https://github.com/schubergphilis/vagrant-cloudstack/raw/master/dummy.box"
cloudstack.host = "compute.jp-east.idcfcloud.com"
cloudstack.path = "/client/api"
cloudstack.port = "443"
cloudstack.scheme = "https"
cloudstack.api_key = "#{ENV['CLOUDSTACK_API_KEY']}"
cloudstack.secret_key = "#{ENV['CLOUDSTACK_SECRET_KEY']}"
cloudstack.zone_name = "pascal"
cloudstack.template_name = "CentOS 6.6 64-bit"
cloudstack.service_offering_name = "light.S1"
cloudstack.pf_ip_address = "#{ENV['PUBLIC_IP_ADDRESS']}"
cloudstack.pf_public_port = 2222
cloudstack.pf_private_port = 22
cloudstack.keypair = "#{ENV['CLOUDSTACK_SSH_KEYPAIR']}"
override.ssh.username = "root"
override.ssh.host = "#{ENV['PUBLIC_IP_ADDRESS']}"
override.ssh.private_key_path = "#{ENV['VAGRANT_SSH_PRIVATE_KEY']}"
end
# Synced Folderを無効化
config.vm.synced_folder ".", "/vagrant", disabled: true
# Shell Provisionerの実行
config.vm.provision "shell",
inline: "echo Hello, World"
end
Shell Provisionerを使う
requiretty有効時のShell Provisionerのエラー
環境変数をセットしてvagrant up
(vagrant provision
)を実行すると次のエラーが発生します。これはShell Provisionerがsudoでコマンドを実行しようした際にttyがないため発生しているエラーです。
==> default: Running provisioner: shell...
default: Running: inline script
==> default: sudo
==> default: :
==> default: sudo を実行するには tty がなければいけません。すみません
The SSH command responded with a non-zero exit status. Vagrant
assumes that this means the command failed. The output for this command
should be in the log above. Please read the output to determine what
went wrong.
config.ssh.ptyをtrueにしてptyを使用してエラーを回避する
このエラーの回避方法の一つは、config.ssh.pty
をtrue
として、ptyを使用するようにすることです。
config.ssh - Vagrantfile - Vagrant Documentation
Vagrant.configure("2") do |config|
config.vm.provider :cloudstack do |cloudstack, override|
override.vm.box = "dummy"
override.vm.box_url = "https://github.com/schubergphilis/vagrant-cloudstack/raw/master/dummy.box"
cloudstack.host = "compute.jp-east.idcfcloud.com"
cloudstack.path = "/client/api"
cloudstack.port = "443"
cloudstack.scheme = "https"
cloudstack.api_key = "#{ENV['CLOUDSTACK_API_KEY']}"
cloudstack.secret_key = "#{ENV['CLOUDSTACK_SECRET_KEY']}"
cloudstack.zone_name = "pascal"
cloudstack.template_name = "CentOS 6.6 64-bit"
cloudstack.service_offering_name = "light.S1"
cloudstack.pf_ip_address = "#{ENV['PUBLIC_IP_ADDRESS']}"
cloudstack.pf_public_port = 2222
cloudstack.pf_private_port = 22
cloudstack.keypair = "#{ENV['CLOUDSTACK_SSH_KEYPAIR']}"
override.ssh.username = "root"
override.ssh.host = "#{ENV['PUBLIC_IP_ADDRESS']}"
override.ssh.private_key_path = "#{ENV['VAGRANT_SSH_PRIVATE_KEY']}"
override.ssh.pty = true
end
# Synced Folderを無効化
config.vm.synced_folder ".", "/vagrant", disabled: true
# Shell Provisionerの実行
config.vm.provision "shell",
inline: "echo Hello, World"
end
==> default: Running provisioner: shell...
default: Running: inline script
==> default: Hello, World
config.ssh.sudo_commandでsudoを無効化する
今回の例ではrootでログインしているのでコマンドにsudoをつける必要がありません。
したがって、config.ssh.sudo_command
を上書きしてsudo無しでコマンドを実行するように設定することでエラーを回避することもできます。
config.ssh - Vagrantfile - Vagrant Documentation
Vagrant.configure("2") do |config|
config.vm.provider :cloudstack do |cloudstack, override|
override.vm.box = "dummy"
override.vm.box_url = "https://github.com/schubergphilis/vagrant-cloudstack/raw/master/dummy.box"
cloudstack.host = "compute.jp-east.idcfcloud.com"
cloudstack.path = "/client/api"
cloudstack.port = "443"
cloudstack.scheme = "https"
cloudstack.api_key = "#{ENV['CLOUDSTACK_API_KEY']}"
cloudstack.secret_key = "#{ENV['CLOUDSTACK_SECRET_KEY']}"
cloudstack.zone_name = "pascal"
cloudstack.template_name = "CentOS 6.6 64-bit"
cloudstack.service_offering_name = "light.S1"
cloudstack.pf_ip_address = "#{ENV['PUBLIC_IP_ADDRESS']}"
cloudstack.pf_public_port = 2222
cloudstack.pf_private_port = 22
cloudstack.keypair = "#{ENV['CLOUDSTACK_SSH_KEYPAIR']}"
override.ssh.username = "root"
override.ssh.host = "#{ENV['PUBLIC_IP_ADDRESS']}"
override.ssh.private_key_path = "#{ENV['VAGRANT_SSH_PRIVATE_KEY']}"
override.ssh.sudo_command = "%c"
end
# Synced Folderを無効化
config.vm.synced_folder ".", "/vagrant", disabled: true
# Shell Provisionerの実行
config.vm.provision "shell",
inline: "echo Hello, World"
end
privilegedオプションをfalseにしてコマンドをsudo無しで実行する
sudo無しでコマンドを実行するように設定することは、Shell Provisionerのprivileged
オプションをfalse
にすることによっても可能です。この方法でもエラーを回避することができます。
この設定はShell Provisionerのみに影響します。他のVagrantコマンドがsudoを使用している場合にはこの方法で対応することはできません。
Vagrant.configure("2") do |config|
config.vm.provider :cloudstack do |cloudstack, override|
override.vm.box = "dummy"
override.vm.box_url = "https://github.com/schubergphilis/vagrant-cloudstack/raw/master/dummy.box"
cloudstack.host = "compute.jp-east.idcfcloud.com"
cloudstack.path = "/client/api"
cloudstack.port = "443"
cloudstack.scheme = "https"
cloudstack.api_key = "#{ENV['CLOUDSTACK_API_KEY']}"
cloudstack.secret_key = "#{ENV['CLOUDSTACK_SECRET_KEY']}"
cloudstack.zone_name = "pascal"
cloudstack.template_name = "CentOS 6.6 64-bit"
cloudstack.service_offering_name = "light.S1"
cloudstack.pf_ip_address = "#{ENV['PUBLIC_IP_ADDRESS']}"
cloudstack.pf_public_port = 2222
cloudstack.pf_private_port = 22
cloudstack.keypair = "#{ENV['CLOUDSTACK_SSH_KEYPAIR']}"
override.ssh.username = "root"
override.ssh.host = "#{ENV['PUBLIC_IP_ADDRESS']}"
override.ssh.private_key_path = "#{ENV['VAGRANT_SSH_PRIVATE_KEY']}"
end
# Synced Folderを無効化
config.vm.synced_folder ".", "/vagrant", disabled: true
# Shell Provisionerの実行
config.vm.provision "shell", privileged: false,
inline: "echo Hello, World"
end
Rsync Synced Folderを使う
Rsync Synced Folderを使うためには作成した仮想マシンにディレクトリを作成し、ローカルのデータをコピーできるようにする必要があります。
vagrantユーザーで/vagrantを作成する等、一般ユーザーでは権限が不足している場合があるためディレクトリの作成等のコマンドはsudoを付けて実行されます。したがって、Shell Provisionerの場合と同様config.ssh.pty
やconfig.ssh.sudo_command
を設定しrequiretty有効時でもコマンドを実行できるようにしておく必要があります。(Shell ProvisionernのprivilegedオプションはShell Provisionerの動作にのみ影響するのでSynced Folderを使うためには使用できません。)
例えば、config.ssh.pty=true
とした状態でSynced Folderを有効化してみます。
Vagrant.configure("2") do |config|
config.vm.provider :cloudstack do |cloudstack, override|
override.vm.box = "dummy"
override.vm.box_url = "https://github.com/schubergphilis/vagrant-cloudstack/raw/master/dummy.box"
cloudstack.host = "compute.jp-east.idcfcloud.com"
cloudstack.path = "/client/api"
cloudstack.port = "443"
cloudstack.scheme = "https"
cloudstack.api_key = "#{ENV['CLOUDSTACK_API_KEY']}"
cloudstack.secret_key = "#{ENV['CLOUDSTACK_SECRET_KEY']}"
cloudstack.zone_name = "pascal"
cloudstack.template_name = "CentOS 6.6 64-bit"
cloudstack.service_offering_name = "light.S1"
cloudstack.pf_ip_address = "#{ENV['PUBLIC_IP_ADDRESS']}"
cloudstack.pf_public_port = 2222
cloudstack.pf_private_port = 22
cloudstack.keypair = "#{ENV['CLOUDSTACK_SSH_KEYPAIR']}"
override.ssh.username = "root"
override.ssh.host = "#{ENV['PUBLIC_IP_ADDRESS']}"
override.ssh.private_key_path = "#{ENV['VAGRANT_SSH_PRIVATE_KEY']}"
override.ssh.pty = true
end
# Shell Provisionerの実行
config.vm.provision "shell",
inline: "echo Hello, World"
end
しかし、これを実行すると次のようなエラーとなります。
==> default: Rsyncing folder: /Users/atsaki/gitrepos/vagrant-examples/centos/ => /vagrant
There was an error when attempting to rsync a synced folder.
Please inspect the error message below for more info.
Host path: /Users/atsaki/gitrepos/vagrant-examples/centos/
Guest path: /vagrant
Command: rsync --verbose --archive --delete -z --copy-links --no-owner --no-group --rsync-path sudo rsync -e ssh -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i '/Users/atsaki/.ssh/id_rsa_idcfcloud' --exclude .vagrant/ /Users/atsaki/gitrepos/vagrant-examples/centos/ root@xxx.xxx.xxx.xxx:/vagrant
Error: Warning: Permanently added '[xxx.xxx.xxx.xxx]:2222' (RSA) to the list of known hosts.
sudo: sudo を実行するには tty がなければいけません。すみません
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at /SourceCache/rsync/rsync-42/rsync/io.c(452) [sender=2.6.9]
このエラーはrsyncコマンドの--rsync-path "sudo rsync"
のsudoがttyなしで実行されるため発生しています。
rsync__rsync_pathで--rsync-pathからsudoを除く
ログインユーザがrootの場合、--rsync-pathのsudoは不要なのでrsync__rsync_path
オプションで--rsync-path
からsudoを除くことでエラーを回避することができます。
ログインユーザーがrootでない場合でも権限があるディレクトリをSynced Folderにする場合には同様の方法で対応できると思います。
Vagrant.configure("2") do |config|
config.vm.provider :cloudstack do |cloudstack, override|
override.vm.box = "dummy"
override.vm.box_url = "https://github.com/schubergphilis/vagrant-cloudstack/raw/master/dummy.box"
cloudstack.host = "compute.jp-east.idcfcloud.com"
cloudstack.path = "/client/api"
cloudstack.port = "443"
cloudstack.scheme = "https"
cloudstack.api_key = "#{ENV['CLOUDSTACK_API_KEY']}"
cloudstack.secret_key = "#{ENV['CLOUDSTACK_SECRET_KEY']}"
cloudstack.zone_name = "pascal"
cloudstack.template_name = "CentOS 6.6 64-bit"
cloudstack.service_offering_name = "light.S1"
cloudstack.pf_ip_address = "#{ENV['PUBLIC_IP_ADDRESS']}"
cloudstack.pf_public_port = 2222
cloudstack.pf_private_port = 22
cloudstack.keypair = "#{ENV['CLOUDSTACK_SSH_KEYPAIR']}"
override.ssh.username = "root"
override.ssh.host = "#{ENV['PUBLIC_IP_ADDRESS']}"
override.ssh.private_key_path = "#{ENV['VAGRANT_SSH_PRIVATE_KEY']}"
override.ssh.pty = true
end
# rsync__rsync_pathで--rsync-pathからsudoを除く
config.vm.synced_folder ".", "/vagrant", type: "rsync",
rsync__rsync_path: "rsync"
# Shell Provisionerの実行
config.vm.provision "shell",
inline: "echo Hello, World"
end