VirtualBoxのCUIコンソールでクリップボードのコピーペースト

VirtualBoxのCUI(Character User Interface)コンソールでCtrl-Vでコピーペーストをしようとしたけど^Vが表示されるだけで困っている。コピーペーストはマウスを使わないといけないのかな。

そんな人の悩みに答えます。

この記事では、次のことがわかります。
1. Gnomeデスクトップの端末で、コピーペーストをする方法
2. Gnomeデスクトップが立ち上がる前のVirtualBoxのコンソールでコピーペーストをする方法
3. まとめ

1. Gnomeデスクトップの端末で、コピーペーストをする方法

Gnomeデスクトップが立ち上がっている場合、コピーペーストは端末アプリの編集に、コピーと貼り付けがあります。コピーしたいところをマウスで白黒反転させておいてから、コピーを選び、貼り付けたいところにカーソルを持っていって、貼り付けを選べばいいです。

なお、ゲストOSとホストOSの間でコピーペーストができない場合は、VirtualBoxのGuestAdditionsが動作しているかどうか確認してください。

このときに、キーボードショートカットのCtrl-C/Ctrl-Vを使おうとすると、画面に^Vと表示されてしまって貼り付けできません。

解決方法は、Ctrl-Shift-CとCtrl-Shift-Vを使えばよいです。

Ctrl-Cは、プロセスの終了に割り当てられているため、Gnomeデスクトップの設定でこうなっています。

2. Gnomeデスクトップが立ち上がる前のVirtualBoxのコンソールでコピーペーストをする方法

Gnomeデスクトップが立ち上がる前のVirtualBoxのコンソールでは、ショートカットキーは使えません。そこで、xselというコマンドを使います。

サーバーバージョンのCentOSを使っていて、Gnomeデスクトップがない場合などに相当します。

ここでは、CentOSについて説明します。

2-1. xselのインストールと動作の確認

コンソールでxselと打ち込んでコマンドがない場合は、xselをインストールします。このときに、Xvfbという画面のないXサーバーを使いますので、同時にインストールします。

sudo yum install xsel Xvfb

Xvfbを立ち上げます。

Xvfb -screen 0 1280x720x24 &
export DISPLAY=:0

もし、Xvfbが立ち上がっていなくてxselを使おうとすると、次のようなエラーが出ます。DISPLAY変数がexportされてないときも同様です。

xsel: Can't open display :(null)

準備の最後にVBoxClientを立ち上げます。

VBoxClient --clipboard

これで、ホストOSとゲストOS間でコピーペーストできます。準備は終わりです。

例えば、文字列aaaをクリップボードへにコピーするには、次のようにします。

echo aaa |xsel --input --clipboard

クリップボードからのペーストは次のようにします。

xsel --output --clipboard

これでクリップボードをコマンドで使うことができるようになりました。

2-2. pbcopy/pbpasteコマンドにまとめる

いちいちxselのコマンドを打ち込むのは手間がかかりますので、pbcopy/pbpasteというコマンドにまとめます。pbcopy/pbpasteは同名のMac OSのコマンドです。

ホームディレクトリの.bash_profileの最後にaliasで定義します。

.bash_profile

alias pbcopy="xsel --input --clipboard"
alias pbpaste="xsel --output --clipboard"

aliasを書いたあとは $ source .bash_profileで有効にします。

2-3. viで使う

コンソールの中でviを使ったとき、コピーペーストするにはもう一工夫必要でした。viの中では、:r! 外部コマンドを打つとコマンドの実行結果が入力されます。上で設定したpbpasteを実行しようとしてもエラー127のcommand not foundになってしまいます。

そのため、環境変数BASH_ENVの設定と、.bashenvの設定が必要でした。

.bashenvというファイルを作ります。
.bashenv

shopt -s expand_aliases
alias pbcopy="xsel --input --clipboard"
alias pbpaste="xsel --output --clipboard"

.bashrcの最後でこのファイルを有効にします。

export BASH_ENV=~/.bashenv

これで、viのコマンドモードで

:r!pbpaste

とすると、クリップボードにコピーされた内容を取り込むことができます。

コピーしたいときはビジュアルモードで範囲を選択して、次のようにします。

:!pbcopy;pbpaste

ちなみにpbcopyとpbpasteの間はセミコロンです。

pbopyの前のビックリマークが必要です。また、pbpasteがないと切り取りになってしまいます。

3. まとめ

VirtualBoxのCUI(Character User Interface)コンソールでコピーペーストを使えるようにしました。

CentOSのGnomeデスクトップが立ち上がる前のコピーペーストの方法について説明しました。

設定が完了するとviでクリップボードへのコピーペーストができるようになります。

Vagrant+Ansibleのデバッグ方法

VagrantとAnsibleを使っていると、たびたびエラーになります。

そのデバッグに役立ったことを紹介します。

Vagrantの場合

Vagrantでプロビジョニングをしてエラーになったときは、次のようにします。

VAGRANT_LOG=info vagrant provision

を実行する。

エラーになると次のような表示が確認できる。

ERROR vagrant: 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.

調べてみるとログの上の方にこんな情報がありました。

 INFO interface: info: Could not get lock /var/lib/dpkg/lock - open (11: Resource temporarily unavailable)
 INFO interface: info: ==> default: Could not get lock /var/lib/dpkg/lock - open (11: Resource temporarily unavailable)

apt-getのエラーのようで、vagrant sshでゲストOSにログインしてapt-getしてみても原因はつかめず。もう1度vagrant provisionしてみると成功しました。一時的にエラーになっただけのようでした。

Ansible単独の場合

AnsibleはSSHで接続できていないと動きません。そのためSSHのチェックが重要になります。
まず、次のコマンドで接続を確かめます。

ansible -vvvv all -m ping

を実行してみる。

表示色が濃い青色で読めないときは、ANSIBLE_NOCOLOR=1をつけます。

ANSIBLE_NOCOLOR=1 ansible -vvvv all -m ping

ログのポイントは次のところです。ESTABLISH SSH CONNECTION FOR USERでssh接続のユーザー名が間違っていないか。

SSH:EXEC sshのところで、この場合sshから192.168.33.10までがsshのコマンドラインになります。とりあえずこのIPアドレスまでをコピーしてペーストして単独で接続できるか見てみます。

<192.168.33.10> ESTABLISH SSH CONNECTION FOR USER: ubuntu
<192.168.33.10> SSH: EXEC ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o 'IdentityFile=".vagrant/machines/default/virtualbox/private_key"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=ubuntu -o ConnectTimeout=10 -o ControlPath=/tmp 192.168.33.10 '/bin/sh -c '"'"'chmod u+x /home/ubuntu/.ansible/tmp/ansible-tmp-1496030041.85-156969875839371/ /home/ubuntu/.ansible/tmp/ansible-tmp-1496030041.85-156969875839371/ping.py && sleep 0'"'"''

sshからIPアドレスまでの部分だけをコピーペーストで新しく張り付けて実行してみます。

ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o 'IdentityFile=".vagrant/machines/default/virtualbox/private_key"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=ubuntu -o ConnectTimeout=10 -o ControlPath=/tmp 192.168.33.10

これで接続できているかまず確認しましょう。

sshで接続できていれば、問題の切り分けができます。あとはpythonのスクリプトが実行できているかどうかです。

MSYS2でansibleを使うときの訂正とpythonのvirtualenvとvenv

MSYS2でansibleを使うときは32bit版ではなくて、インストールするパッケージがmsysのpythonであることが必要でした。
以前の記事を訂正しました。

pythonのバージョンを管理する、python3のvenvやpython2のvirutalenvも、msys用のpythonだと動きますがMinGW用のpythonだと動きません。

スタートメニューのMSYS2 MinGW 32-bitや、MSYS2 MinGW 64-bitのコンソールでは、MinGW用のpythonがインストールしてあるとそちらが優先的に実行されてしまうので注意してください。

msys用のpythonはpipが用意されていませんので、get-pip.pyをcurlでインストールします。

python2の場合、pipでvirtualenvをインストールします。そのうえで-m virtualenvでモジュールを指定して実行します。適当な名前myvenvを指定すると、myvenv/bin/以下にpythonやpipがコピーされます。activateをbashに読み込ませると開発環境が変わります。

カッコつきで(myvenv)のように表示されるとOKです。

deactivateで元に戻ります。

$ pacman -S python2

$ curl -kL https://bootstrap.pypa.io/get-pip.py | python2
$ pip install virtualenv

$ mkdir test
$ cd test
$ python2 -m virtualenv myvenv
$ source myvenv/bin/activate

(myvenv)

$ deactivate

python3をpython2と同居させる場合、pipコマンドをpython2のようにインストールすると、/usr/bin/pipが上書きされてしまいます。
そのため、venvというモジュールを使ってローカルのフォルダにpip関係のモジュールを入れて隔離したほうがいいです。

python2は、virtualenvをpipでインストールしないといけないので、グローバルにインストールするしかないです。

適当な名前myvenvを指定してpython3 -m venvを実行するとpython3の実行ファイルとpipがコピーされて使えるようになります。

$ pacman -S python

$ mkdir python3test
$ cd python3test
$ python3 -m venv myvenv
$ source myvenv/bin/activate

(myvenv)

$ deactivate

python2とpython3でpipをインストールすると、pipは後にインストールしたほうになります。先にインストールした方は、pip2もしくはpip3で指定しないといけないです。

混在するのはよくないので、pipはpython2のみでインストールし、python3は-m venvで仮想環境を作ったときに自動でインストールされるpipを使うのがよいです。

MSYS2のAnsibleを使ってVagrantでプロビジョニング

VagrantでゲストOSをセットアップするには、次の3通りがあります。

  1. Vagrantfileの中ではプロビジョニングを使わず、ゲストOSを立ち上げるだけにして、ansible単独でゲストOSを操作する方法
  2. Vagrantfileの中でconfig.vm.provision 'ansible_local'として、Vagrantのansible_localというプロビジョニングを使う方法
  3. Vagrantfileの中でconfig.vm.provision 'ansible'として、Vagrantのプロビジョニングを使う方法

今回は、3番目のVagrantのansibleプロビジョニングを使ってゲストOSをセットアップします。

AnsibleもVagrantも、ansibleプロビジョニングをWindowsホストではサポートしていないのでその点はご了承ください。

前回までに、MSYS2上でAnsibleが動くことがわかりました。

まず、これまでのように、ホストからansible-playbookでゲストOSが操作できることを確認します。

これで素直にVagrantのプロビジョニングのなかでansibleが使えるかというと、エラーが出て使えません。

そこで、Cygwinでの動作例を参考に次のようにしました。

ansble-play.batという次のようなファイルを作ってPATHの通ったところに置きます。

@echo off

REM MSYS2のインストール場所
set MSYS=C:\msys32

REM bash.exeからansible-playbookを起動します
set SH=%MSYS%\usr\bin\bash.exe

"%SH%" -c "/usr/bin/ansible-playbook %*"

これで、Vagrantからansible-playbookを呼び出すことができます。

Vagrantfileは次の通りです。ゲストOSはubuntu/xenial64にしたのですが、このイメージはpythonが含まれていません。そのため、shellプロビジョニングを使ってインストールしました。このとき、aptのソースファイルを書き換えて少し速くインストールするようにしました。

ansibleプロビジョニングでは、Playbookをsite.yml、コンフィグレーションファイルにansible.cfg、インベントリファイルにhostsを指定しました。

Vagrantfile

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "ubuntu/xenial64"

  config.vm.network "private_network", ip: "192.168.33.10"
  
  config.vm.provision "shell", inline: <<-SHELL
		# aptのソースファイルを書き換え
    sed -i s%archive.ubuntu.com/ubuntu%ftp.jaist.ac.jp/pub/Linux/ubuntu/%g /etc/apt/sources.list
    apt-get update
    apt-get -y install python aptitude
  SHELL

  config.vm.provision "ansible" do |ansible|
    ansible.playbook = "site.yml"
    ansible.config_file = "ansible.cfg"
    ansible.inventory_path = "hosts"
    ansible.limit = 'all'
  end
end

次にansible.cfgファイルです。vagrant ssh-configで表示される結果をもとに作ります。Userをremote_userに、IdentityFileをprivate_key_fileにします。

control_pathの設定は、CygwinやMSYS2を使ったときにエラーになるのを回避するためです。こちらの情報をもとにしました。

ansible.cfg

[defaults]
inventory = hosts
remote_user = ubuntu
host_key_checking = False
private_key_file = .vagrant/machines/default/virtualbox/private_key


[ssh_connection]
# for Cygwin, MSYS2
control_path = /tmp

インベントリファイルは、次の通りです。vagrantsというグループで、ubuntu01という名前にしました。IPアドレスはVagrantfileと合わせます。これが違っていてよくSSHのエラーになりました。

hosts

[vagrants]
ubuntu01 ansible_host=192.168.33.10

最後はPlaybookです。Apache2をインストールすることにしました。

vagrantsというグループにubuntuでアクセスします。aptでapache2の最新版ををインストールしてbecome: trueでスーパーユーザーで行います。

site.yml

---
- hosts: vagrants
  user: ubuntu
  tasks:
    - name: install packages Apache2
      apt: name=apache2 update_cache=yes
      become: true

4つのファイルがそろえば、vagrant upでサーバーが設定され、http://192.168.33.10/にアクセスするとApache2の画面を見ることができます。
使ってみて、VagrantのAnsibleプロビジョニングはVagrantと一緒に使うときは便利ですが、Ansible単独で設定したほうが自由度はあるのかなという感じがしました。