Dockerでoverlay NWやoverlayfsがサポートされたがそれぞれKernel 3.16、3.18以上が必要になってくる。Ubuntu公式の14.04 TrustyのVagrant boxのKernelバージョンがこの条件を満たしておらず、毎回Kernelアップデートをするのが面倒だった。そこで、Dockerのoverlay NWやoverlayfsを試すためのVagrant Ubuntu14.04 boxを作ってみようと思う。

成果物

今回作成したVagrant boxはAtlasで公開した。利用するときは以下を実行する。

➤  vagrant box add takanabe/ubuntu1404-docker

開発環境

➤  system_profiler SPSoftwareDataType
Software:

    System Software Overview:

      System Version: OS X 10.10.5 (14F27)
      Kernel Version: Darwin 14.5.0

➤  vagrant -v
Vagrant 1.7.4

VagrantでUbuntu14.04のVMを作る

いつもどおり手元にあるUbuntu14.04のboxを使ってVMを起動する。

➤  vagrant box list
ubuntu14.04           (virtualbox, 0)
➤  vagrant init ubuntu14.04
➤  vagrant up

Ubuntuのバージョンを確認する

起動したVMにログインして各種情報を確認する。

➤  vagrant ssh

$ uname -a
Linux vagrant-ubuntu-trusty-64 3.13.0-36-generic #63-Ubuntu SMP Wed Sep 3 21:30:07 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 14.04.1 LTS
Release:        14.04
Codename:       trusty

現状はKernel v3.13が利用されてていることが確認できる。

UbuntuのKernelバージョンを上げる

Ubuntuが公式に管理しているKernel情報はここを見ればわかる。今回はこの中のKernel v3.19.8を使う。Kernelのバージョンアップ方法はここを見ると良い。

mkdir kernel-v3.19.8 && cd kernel-v3.19.8
wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v3.19.8-vivid/linux-headers-3.19.8-031908-generic_3.19.8-031908.201505110938_amd64.deb
wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v3.19.8-vivid/linux-headers-3.19.8-031908_3.19.8-031908.201505110938_all.deb
wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v3.19.8-vivid/linux-image-3.19.8-031908-generic_3.19.8-031908.201505110938_amd64.deb
sudo dpkg -i linux-*.deb 
cd ..
rm -rf kernel-v3.19.8

まだ、バージョンが変わっていないことを確認してリブートする。

$ uname -a
Linux vagrant-ubuntu-trusty-64 3.13.0-36-generic #63-Ubuntu SMP Wed Sep 3 21:30:07 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

$ reboot

リブート後Kernelのバージョンを確認するとちゃんと3.19.8になっている。

➤  vagrant ssh

$ uname -a
Linux vagrant-ubuntu-trusty-64 3.19.8-031908-generic #201505110938 SMP Mon May 11 13:39:59 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 14.04.1 LTS
Release:        14.04
Codename:       trusty

必要なパッケージを入れる

ついでに常用するパッケージを入れておくと便利。

$ sudo apt-get update
$ sudo apt-get install zsh
$ which zsh
$ chsh # which zshで表示されたzshへのパスを入力する

vim、tmux、zshなんかは良く使うので設定をファイルを入れておくと捗る。とりあえずzshは自分の使い慣れた設定ファイルを作っておく。

~/.zshrc

## **** Fundamental setting/基本設定 **** ##
export LANG=ja_JP.UTF-8
#PATH settings

#Color settings
export LSCOLORS=exfxcxdxbxegedabagacad
export LS_COLORS='di=34:ln=35:so=32:pi=33:ex=31:bd=46;34:cd=43;34:su=41;30:sg=46;30:tw=42;30:ow=43;30'

alias ls="ls -GF"
alias gls="gls --color"
zstyle ':completion:*' list-colors 'di=34' 'ln=35' 'so=32' 'ex=31' 'bd=46;34' 'cd=43;34'
## **** Complimentarity function/補完機能 **** ##

#Basic complimentrity/補完機能を有効にする
autoload -U compinit
compinit

## **** Command history /コマンド履歴**** ##
# ヒストリを保存するファイル
HISTFILE=~/.zsh_history
# メモリ上のヒストリ数
HISTSIZE=6000000
# 保存するヒストリ数
SAVEHIST=6000000
# zshプロセス間でヒストリを共有する
setopt share_history

# コマンド履歴検索
autoload history-search-end
zle -N history-beginning-search-backward-end history-search-end
zle -N history-beginning-search-forward-end history-search-end
bindkey "^P" history-beginning-search-backward-end
bindkey "^N" history-beginning-search-forward-end
# ヒストリに追加されるコマンド行が古いものと同じなら古いものを削除
setopt hist_ignore_all_dups
# スペースで始まるコマンド行はヒストリリストから削除
setopt hist_ignore_space
# ヒストリを呼び出してから実行する間に一旦編集可能
setopt hist_verify
# 余分な空白は詰めて記録
setopt hist_reduce_blanks
# 古いコマンドと同じものは無視
setopt hist_save_no_dups
# historyコマンドは履歴に登録しない
setopt hist_no_store
# 補完時にヒストリを自動的に展開
setopt hist_expand
# 履歴をインクリメンタルに追加
setopt inc_append_history
## ヒストリファイルにコマンドラインだけではなく実行時刻と実行時間も保存する。
setopt extended_history
## 同じコマンドラインを連続で実行した場合はヒストリに登録しない。
setopt hist_ignore_dups
# スペースで始まるコマンドラインはヒストリに追加しない。
setopt hist_ignore_space
# C-sでのヒストリ検索が潰されてしまうため、出力停止・開始用にC-s/C-qを使わない。
setopt no_flow_control

# インクリメンタルからの検索
bindkey "^R" history-incremental-search-backward
bindkey "^S" history-incremental-search-forward

## **** Keybiding/キーバインド **** ##

#Keybinding/キーバインドをvi風にする
bindkey -v
#keybindの追加。
bindkey "^A" beginning-of-line
bindkey "^E" end-of-line

## Prompt definition/プロンプトの設定**** ##
#vi mode の[insert] of [normal]の表示
function zle-line-init zle-keymap-select {

local max_path_chars=30
local user_char='➤'
local root_char='❯❯❯'
local success_color='%F{071}'
#local failure_color='%F{124}'
local failure_color='%F{red}'
local vcs_info_color='%F{242}'

case $KEYMAP in
vicmd)
PROMPT="%B[%F{red}NORMAL%f]:%b%B%n@%m%b
%(?.${success_color}.${failure_color})%(!.${root_char}.${user_char})%f  "
RPROMPT="%F{blue}%~%f"
;;
main|viins)
PROMPT="%B[%F{blue}INSERT%f]:%b%B%n@%m%b
%(?.${success_color}.${failure_color})%(!.${root_char}.${user_char})%f  "
RPROMPT="%F{blue}%~%f"
;;
esac
zle reset-prompt
}
zle -N zle-line-init
zle -N zle-keymap-select


local max_path_chars=30
local user_char='➤'
local root_char='❯❯❯'
local success_color='%F{071}'
local failure_color='%F{124}'
local vcs_info_color='%F{242}'


# Define prompts.
autoload -Uz add-zsh-hook
autoload -Uz vcs_info

PROMPT="%B[%F{blue}INSERT%f]:%b%B%n@%m%b
%(?.${success_color}.${failure_color})%(!.${root_char}.${user_char})%f  "
RPROMPT="%F{blue}%~%f"

## **** Options/オプション**** ##
# 実行結果をコピペしやすいようにコマンド実行後は右プロンプトを消す。
setopt transient_rprompt
#command correction/コマンドの訂正
setopt correct

#/移動履歴をバッファに溜める
setopt auto_pushd

#/# 補完候補を詰めて表示する
setopt list_packed

#/補完候補表示時などにピッピとビープ音をならないように設定
setopt nolistbeep

# 初期化
autoload -U compinit
compinit

## 補完方法毎にグループ化する。
### 補完方法の表示方法
###   %B...%b: 「...」を太字にする。
###   %d: 補完方法のラベル
zstyle ':completion:*' format '%B%d%b'
zstyle ':completion:*' group-name ''

## 補完侯補をメニューから選択する。
### select=2: 補完候補を一覧から選択する。
###           ただし、補完候補が2つ以上なければすぐに補完する。
zstyle ':completion:*:default' menu select=2

## 補完候補に色を付ける。
### "": 空文字列はデフォルト値を使うという意味。
zstyle ':completion:*:default' list-colors ""

## 補完候補がなければより曖昧に候補を探す。
### m:{a-z}={A-Z}: 小文字を大文字に変えたものでも補完する。
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'

## 補完方法の設定。指定した順番に実行する。
### _oldlist 前回の補完結果を再利用する。
### _complete: 補完する。
### _match: globを展開しないで候補の一覧から補完する。
### _ignored: 補完候補にださないと指定したものも補完候補とする。
### _approximate: 似ている補完候補も補完候補とする。
### _prefix: カーソル以降を無視してカーソル位置までで補完する。
zstyle ':completion:*' completer \
    _oldlist _complete _match _ignored _approximate _prefix

## 補完候補をキャッシュする。
zstyle ':completion:*' use-cache yes
## 詳細な情報を使う。
zstyle ':completion:*' verbose yes
## sudo時にはsudo用のパスも使う。
zstyle ':completion:sudo:*' environ PATH="$SUDO_PATH:$PATH"

## カーソル位置で補完する。
setopt complete_in_word
## globを展開しないで候補の一覧から補完する。
setopt glob_complete
## 補完時にヒストリを自動的に展開する。
setopt hist_expand
## 補完候補がないときなどにビープ音を鳴らさない。
setopt no_beep
## 辞書順ではなく数字順に並べる。
setopt numeric_glob_sort


# 展開
## --prefix=~/localというように「=」の後でも
## 「~」や「=コマンド」などのファイル名展開を行う。
setopt magic_equal_subst
## 拡張globを有効にする。
## glob中で「(#...)」という書式で指定する。
setopt extended_glob
## globでパスを生成したときに、パスがディレクトリだったら最後に「/」をつける。
setopt mark_dirs


# ジョブ
## jobsでプロセスIDも出力する。
setopt long_list_jobs


# 実行時間
## 実行したプロセスの消費時間が3秒以上かかったら
## 自動的に消費時間の統計情報を表示する。
REPORTTIME=3

# ログイン・ログアウト
## 全てのユーザのログイン・ログアウトを監視する。
watch="all"
## ログイン時にはすぐに表示する。
log

## ^Dでログアウトしないようにする。
setopt ignore_eof


# 単語
## 「/」も単語区切りとみなす。
WORDCHARS=${WORDCHARS:s,/,,}
## 「|」も単語区切りとみなす。
## 2011-09-19
WORDCHARS="${WORDCHARS}|"

## **** /ウィンドウタイトル ##

# 実行中のコマンドとユーザ名とホスト名とカレントディレクトリを表示。
update_title() {
    local command_line=
    typeset -a command_line
    command_line=${(z)2}
    local command=
    if [ ${(t)command_line} = "array-local" ]; then
        command="$command_line[1]"
    else
        command="$2"
    fi
    print -n -P "\e]2;"
    echo -n "(${command})"
    print -n -P " %n@%m:%~\a"
}
# X環境上でだけウィンドウタイトルを変える。
if [ -n "$DISPLAY" ]; then
    preexec_functions=($preexec_functions update_title)
fi

sshの鍵登録をする

vagrant sshコマンドでログインできるように公開鍵を登録する。公開鍵はここから取得する。

cd ~/.ssh/
wget https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pumv mv vagrant.pub authorized_keys

VMからVagrant Boxを作る

既存のVMからVagrant Boxを作るのは簡単。以下のコマンドを実行するだけ。

➤  vagrant halt
➤  vagrant package
➤  vagrant box add ubuntu14.04_for_docker package.box

これで、VMからboxが生成された。後はいつもどおりvagrant init ubuntu14.04_for_dockerで追加されたboxを使うことができる。

➤  mkdir test_customized_box
➤  cd test_customized_box
➤  vagrant init ubuntu14.04_for_docker
➤  vagrant up

終了。。。と思いきや以下のようにエラーが出た。

Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'ubuntu14.04_for_docker'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: test_customized_box_default_1449116982418_22480
==> default: Fixed port collision for 22 => 2222. Now on port 2203.
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 22 => 2203 (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2203
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Connection timeout. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
    default: The guest additions on this VM do not match the installed version of
    default: VirtualBox! In most cases this is fine, but in rare cases it can
    default: prevent things such as shared folders from working properly. If you see
    default: shared folder errors, please make sure the guest additions within the
    default: virtual machine match the version of VirtualBox you have installed on
    default: your host and reload your VM.
    default:
    default: Guest Additions Version: 4.3.10
    default: VirtualBox Version: 5.0
==> default: Mounting shared folders...
    default: /vagrant => /Users/takayuki/Desktop/test_ubuntu/test_customized_box
Failed to mount folders in Linux guest. This is usually because
the "vboxsf" file system is not available. Please verify that
the guest additions are properly installed in the guest and
can work properly. The command attempted was:

mount -t vboxsf -o uid=`id -u vagrant`,gid=`getent group vagrant | cut -d: -f3` vagrant /vagrant
mount -t vboxsf -o uid=`id -u vagrant`,gid=`id -g vagrant` vagrant /vagrant

The error output from the last command was:

stdin: is not a tty
/sbin/mount.vboxsf: mounting failed with the error: No such device

原因を探していたが、同様な症状のFailed to mount folders in Linux guest. This is usually because the “vboxsf” file system is not available.を直す方法という記事が見つかった。

カーネルがアップデートされたことにより、VitualBox GuestAdditionが壊れ、vboxsfのマウント機能が動かなくなったのが原因らしい。

VMにログインして必要なパッケージのアップデートやインストールでも対応可能だが、ホストがからも修正可能なので以下を実行する。

➤  vagrant plugin install vagrant-vbguest
➤  vagrant vbguest
➤  vagrant reload

あとは、またパッケージを作りなおせばOK。一応sshでログインしてKernelバージョンを確認する。

$ uname -a
Linux vagrant-ubuntu-trusty-64 3.19.8-031908-generic #201505110938 SMP Mon May 11 13:39:59 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

できた!

Boxファイルの圧縮の話

今回作成したboxは圧縮などの容量削減対策は一切していない。したい場合はVagrant のベースBOX を更新するとかVagrant用のboxファイルを小さくするを参考にするといい。

参考

UbuntuとKenel

UbuntuのKernelアップデート関連

既存VMからboxを作成する

Box圧縮関連

Vagrant Shared folder トラブルシュート

Vagrant boxをAtlasで公開する