orangeProse別館

orangeProse(本ブログ)の補助

WindowsでもVagrantでChefしたい、rbenvも(11.12.4-1版)

f:id:hidex7777:20140512174308p:plain

以前、Chefの導入編の記事を書きましたが、4月に、Ubuntu14.04 LTSのまっさらなVagant Boxをつくったので、Chefのレシピを書いておきたいと思います。

ところで。

心を入れ替えます。

導入編から書きなおしてみます。

方針としては、Chefリポジトリは(1)Git+GitHubで管理する、(2)Vagrantプロジェクトの中に入れる(ディレクトリ構成のはなし)。

「Chefって結局なんなの?」という方は『入門Chef Solo - Infrastructure as Code』を読んで下さい。

  • ChefとChef-Soloを(ひとまず)区別しましょう(ローカル開発環境=Vagrantで使うのはChef-Soloです)
  • 「冪等性(べきとうせい: Idempotence)」「収束(Convergence)」がキーワードですよ
  • NodeのことをClientとよんだりする(厳密にはChefのAPIと通信できるすべての端末のこと、したがってknifeもChef Clientのひとつ)
  • knife-soloとはChef-Soloを扱うにさいして便利なツールです

こう書いてみると当たり前のことばかりですが、Chefの概念図だけ頭にあると、こんがらがってきます。

ぼくはこの本を読んで、Chefライフがすべてうまく行き始めた気がしてきました。不思議なマジックをもった本です。

筆者の環境:

VagrantにはUbuntuサーバ14.04のボックスが登録されている:

>vagrant box list
Trusty      (virtualbox, 0)

Vagrantプラグインvagrant-omunibusは便利ですがknife solo prepareで済むので、個人的には必要ないかな―と思っています。本番環境でVagrant使うかどうかわかんないですし。

あとvagrant-berkshelfは開発が終わるようなので、見送ります。gemでインストールするBerkshelfは終わるわけではないので、gemで入れましょう。

この記事では、rbenvとruby-buildでrubyをインストールするのに使います。

下準備

>pwd
/c/Users/hidex7777

>mkdir mychef3
>cd mychef3
>vagrant init Trusty
>vim Vagrantfile
(Vagrantfileの修正)
 config.vm.network "private_network", ip: "192.168.33.10"

:wq

>vagrant up 
>vagrant ssh
$ exit
>vagrant ssh-config --host mychef3 >> %HOME%\.ssh\config
>ssh mychef3
$ exit

Macとかの場合、ssh-config --hostの出力先は~/.ssh/configにします。

WorkstationにChefとかをインストール

Step 2: Set up your workstationの"Run the Chef installer"の指示に従ってChef Clientをインストールします(前回、WindowsはGemでインストールするべきだと書きましたが、いまのインストーラならそちらを使うべきかと思います。knifeとかのツールもこれで使えるようになります)。

Windows版インストーラ

11.12.4-1がWin7で使える記事執筆時点の最新版みたいです。

インストールが終わったらコンソールを再起動して:

>path
C:\opscode\chef\bin;C:\opscode\chef\embedded\bin;

にパスが通っているのを確認。

knifeの設定:

>knife configure

いろいろ聞かれますがぜんぶYとかEnterでOK。

便利なツールknife-soloは入れておきます:

>gem install knife-solo

Windowsの場合

ちなみに、Windows版だとないと困るgemを、前もってアンインストールしておきましたが:

gem uninstall win32-process
gem uninstall windows-pr

このChefのインストールで、これらも入りました。

さらに、Windowsだとやはりrsyncがないので、cwRsyncのFree Editionをダウンロード、解凍して、中身をぜんぶパスが通っているディレクトリ(ぼくの場合はC:\Users\hidex7777\bin)に入れて、ssh.exeとssh-keygen.exeを削除

以下の環境変数も追記:

chef-repo作成

>pwd
/c/Users/hidex7777/mychef3

>knife solo init chef-repo
  • ~/mychef3/chef-repo/.chef/knife.rb

ができていればたぶんOK。

自作のレシピは、つくられたディレクトリのなかのsite-cookbooksに入れます。

とりあえずGitHubにpush

GitHub側であらかじめchef-repoリポジトリをつくってあるとして:

>cd chef-repo
>git init
>git add .
>git commit -m "first commit"
>git remote add origin https://github.com/hidex7777/chef-repo.git
>git push -u origin master

NodeをChefに対応させる

>knife solo prepare mychef3
  • ~/mychef3/chef-repo/nodes/mychef3.json

というファイルができていれば、たぶんOKです。

defsetというcookbookをつくってみる

>knife cookbook create defset -o site-cookbooks
  • ~/mychef3/chef-repo/site-cookbooks/defset/recipes/default.rb

ができていればたぶんOK。

/chef-repo/.chef/knife.rbに

cookbook_path    ["cookbooks", "site-cookbooks"]

という記述があることを確認します。

(このknife.rbは~/.chef/knife.rbとは別のファイルです)

とりあえずHello Worldをやっておきます。

default.rbをテキストエディタで開いて:

log "hello world"

と記入。

~/mychef3/chef-repo/nodes/mychef3.jsonに:

{
  "run_list":[
    "recipe[defset]"
  ]
}

と記入。

CookbookをNodeに反映

>pwd
/c/Users/hideo64temp/mychef3/chef-repo

>knife solo cook mychef3

  * log[Hello World] action write

ここまででいちおうコミットしておく:

>git status
>git add .
>git commit -m "add defset"
>git push origin master

ここまでは前回と同じです。

今回は、もうちょっと先に進みたいと思います。

ここから先は、すべてdefsetのdefault.rbに追記していきます。

aptitudeupdateしてdist-upgradeする

aptのupgradeはユーザがrecipeで自動化するべきではない、と述べられています。

そのため、これはインストール後、手動でやるべきとされています。

パッケージを最新版にしたければ、packageのリソース内に記述するべきであると。

例:

package "nginx" do
  action :upgrade
end

とはいえ、使い捨てのVagrantにそこまで気を使う必要もない気がするので、次のように書いてしまう:

execute "aptitude-dist-upgrade" do
    command "aptitude dist-upgrade -y"
    action :nothing
end

execute "aptitude-update" do
    command "aptitude update -y"
    notifies :run, "execute[aptitude-dist-upgrade]", :immediately
end

cookのとき、dist-upgradeのほうはaction :nothingなのでスルーされて、updateが実行されたときにnotifiesでdist-upgradeを:runするようになっています。

なお、「この書き方ではaptシステムを使っているディストリビューションでしか有効でなく、普遍性がないではないか」という批判は正しいのですが、「個人的レシピは徐々に育てる」をモットーにしていきたいと思います。

.bashrcファイル中のHISTSIZEとHISTFILESIZEをそれぞれ90000にする

templateリソースを使います。

ぼくはConsole2を使っているので、chef操作をしているタブとは別タブで、sshログインしておきます。

ssh mychef3したコンソールのタブで、

cp /home/vagrant/.bashrc /vagrant/.bashrc.erb

でコピーしておく。

Nodeの/vagrantディレクトリは、WorkstationのVagrantfileがあるディレクトリと共有フォルダになっているので、手元にコピーがきます。

このファイルをおもむろにコピーして、/chef-repo/site-cookbooks/defset/templates/defaultディレクトリにペーストします。

この.bashrc.erbファイルをテキストエディタで開き、以下の部分を次のように書き換えます:

# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=<%= node['bashrc']['histsize'] %>
HISTFILESIZE=<%= node['bashrc']['histfilesize'] %>

サイズは変数にしておきます。ファイル名は拡張子.erbをつけて.bashrc.erbとして保存。

/chef-repo/nodes/mychef3.jsonテキストエディタで開き、次のように変数の値(Attribute)を用意しておきます:

{
    "bashrc":{
        "histsize": 90000,
        "histfilesize": 90000
    },
    "run_list":[
        "recipe[defset]"
    ]
}

/chef-repo/site-cookbooks/defset/recipes/default.rbにtemplateリソースの記述をします:

template ".bashrc" do
    path "/home/vagrant/.bashrc"
    source ".bashrc.erb"
    mode 0644
end

コンソールのChef操作タブに戻り、

> knife solo cook mychef3

でNodeに反映させます。

-HISTSIZE=1000
-HISTFILESIZE=2000
+HISTSIZE=90000
+HISTFILESIZE=90000

のようにdiffが表示されればOKのはずです。

Vagrantにログインしているタブに切り替えて、llコマンドで.bashrcファイルのモードが-rw-r--r--(つまり0644)になっているのを確認。

vi .bashrcで、ファイルが適切に書き換えられているのを確認する。

.bash_aliasesファイルにalias eng='export LANG=en_US.UTF-8'alias jpn='export LANG=ja_JP.UTF-8'の行を追記

これはssh接続でなく直接サーバのターミナルを開いたときに、日本語がちゃんと表示されないのを回避するためのエイリアス

ssh接続のときはjpnで日本語表示、ターミナルで直接開いたときはengで英語表示にする。

これもtemplateを使う。

たぶんインストールしたばかりのサーバには.bash_aliasesファイルはないので、Workstation側で作る。

alias eng='export LANG=en_US.UTF-8'
alias jpn='export LANG=ja_JP.UTF-8'

と書いて、.bash_aliases.erbとして/chef-repo/site-cookbooks/hell/templates/defaultに保存する(この時点ではerbにする意味はないのですが)。

/chef-repo/site-cookbooks/defset/recipes/default.rbに追記する:

template ".bash_aliases" do
    path "/home/vagrant/.bash_aliases"
    source ".bash_aliases.erb"
    mode 0644
end

vim-noxをインストールしてデフォルトエディタにする

vim-noxのインストールのnotifiesからupdate-alternativesを呼び出すようにする(default.rbに追記):

execute "update-alternatives-editor" do
    command "update-alternatives --set editor /usr/bin/vim.nox"
    action :nothing
end

package "vim-nox" do
    action :install
    notifies :run, "execute[update-alternatives-editor]", :immediately
end

etckeeperとgitとtigのインストール

Chefで完全管理して冪等性が保たれているのにetckeeperもなにもないだろう、という気もしますが、なければないで不安なので、入れます。

vim-noxのときのように、actionに:nothingを指定しておいて、他から呼び出すように書いてもいいのだけれど、どれかが何かのはずみでインストールされてしまうと、他がインストールされなくってめんどくさいので、個別に書きます:

package "etckeeper" do
     action :install
end

package "tig" do
    action :install
end

package "git" do
    action :install
end

もちろんvim-noxのところでやったように

package "git" do
    action :install
    notifies :install, "package[tig]", :immediately
end

とやってもよいでしょう(tigのactionは:nothingに)。

/etc/etckeeper/etckeeper.confの編集

.bashrcのときと同じように、ssh mychef3したコンソールのタブで、

cp /etc/etckeeper/etckeeper.conf /vagrant/etckeeper.conf.erb

でコピーしておく。

このファイルを/chef-repo/site-cookbooks/defset/templates/defaultディレクトリにペーストします。

次の部分を書き換えます:

# The VCS to use.
#VCS="hg"
VCS="git"
#VCS="bzr"
#VCS="darcs"

これも、この時点ではerbにする意味はないですが(変数の埋め込みがないので)、念の為にerbファイルにしてtemplateとして扱うのがベターかと思います。

伊藤直也本でもそう述べられています。

template "etckeeper.conf" do
  path "/etc/etckeeper/etckeeper.conf"
  source "etckeeper.conf.erb"
  mode 0644
end

ntpをインストール

package "ntp" do
  action :install
end

ntpはサービスですが、Ubuntuは「インストールしたサービスは、常時動いている。止めたきゃアンインストールせよ」という方針のOSなので、基本的にはサービスのスタートを考えなくてよいとも言えます。

時刻が著しくズレていて同期がとれなくなった場合のことを考えて、設定ファイルを書き換えてもよいかもしれません:

service "ntp" do
  supports :status => true, :start => true, :stop => true, :restart => true, :reload => true
  action :nothing
end

execute "ntpdate" do
  command "ntpdate ntp.nict.jp"
  action :nothing
  notifies :start, "service[ntp]", :immediately
end

template "ntp.conf" do
  path "/etc/ntp.conf"
  source "ntp.conf.erb"
  mode 0644
  notifies :stop, "service[ntp]", :immediately
  notifies :run, "execute[ntpdate]", :immediately
end

この場合もあらかじめ

$ cp /etc/ntp.conf /vagrant/ntp.conf.erb

でコピーをもってきて、次のように書き換えるか:

server ntp.nict.jp
#server 0.ubuntu.pool.ntp.org
#server 1.ubuntu.pool.ntp.org
#server 2.ubuntu.pool.ntp.org
#server 3.ubuntu.pool.ntp.org

デフォルトをコメントアウトせずにntp.nict.jpの行を書き加えるだけにするか、どちらでもよいでしょう。

あるいは設定ファイルは書き換えずに、installと同時にstopしてntpdateしてstartする、というだけでもいいかもしれません(ぼくはそうしています)。

パスワード認証の無効化(/etc/ssh/sshd_config)

sshd_configファイルをテンプレート化します。

ssh mychef3してあるタブで:

$ cp /etc/ssh/sshd_config /vagrant/sshd_config.erb

手元にきたコピーを/templates以下にペースト:

#ポート番号を変数化しておく
Port <%= node['sshd_config']['port'] %>

#'#PasswordAuthentication yes'の行を書き換える
<%= node['sshd_config']['passauth'] %>

#'UsePam yes'の行を書き換える
<%= node['sshd_config']['usepam'] %>

mychef3.jsonファイルに変数を追記:

  "sshd_config":{
    "port": 22,
    "passauth": "PasswordAuthentication no",
    "usepam": "UsePam no"
  },

default.rbファイルに追記:

service "ssh" do
  supports :status => true, :start => true, :stop => true, :restart => true, :reload => true
  action :nothing
end

template "sshd_config" do
  path "/etc/ssh/sshd_config"
  source "sshd_config.erb"
  mode 0644
  notifies :restart, "service[ssh]", :immediately
end

UFW有効化、「OpenSSHへのWorkstationからの許可およびそれ以外からのリミット」ルール作成

UFW(Uncomplicated FireWall)をあつかうのに便利なFirewallリソースが公開されているのですが、この記事を書いている時点で、Travis CIのテストがFailしているので、ひとまず避けておくことにします。

ここではより原始的な方法で。

execute "ufw-allow-openssh" do
  command 'ufw insert 1 allow from 192.168.33.0/24 to any app OpenSSH'
  action :nothing
end

execute "ufw-limit-openssh" do
  command 'ufw limit OpenSSH'
  action :nothing
  notifies :run, "execute[ufw-allow-openssh]", :immediately
end

execute "ufw-enable" do
  command 'printf y | ufw enable'
  notifies :run, "execute[ufw-limit-openssh]", :immediately
end

ufw enableしたときに対話的に入力を求められるので(-yオプションがきかない)、printf yで渡しています。

apache2インストール

UbuntuのAPTで配布されているApache2も、バージョンが2.4系統になったようです。

Apacheを入れたらufwにも許可を入れます:

execute "ufw-allow-apache" do
  command 'ufw allow "Apache Full"'
  action :nothing
end

package "apache2" do
  action :install
  notifies :run, "execute[ufw-allow-apache]", :immediately
end

Workstationのブラウザからhttp://192.168.33.10(Vagrantfileで設定したプライベートネットワーク)に接続して"Apache2 Ubuntu Default Page"が表示されれば成功です。

以前の簡素な"It works!"ページからだいぶ様変わりしていてびっくりしました。

ドキュメントルートを/vagrantにしたwwwサイトを作ってa2enable、000-defaultをa2disable

まずデフォルトの設定ファイルをコピー(いつのまにか.confという拡張子が付くようになりました):

$ cp /etc/apache2/sites-available/000-default.conf /vagrant/www.conf.erb
$ echo "from vagrant" > /vagrant/index.html

2.2ではデフォルトのドキュメントルートが/var/wwwでしたが、設定ファイルを開くとわかるように、2.4では/var/www/htmlになっています(Ubuntu)。

また、Directoryディレクティブが書かれていないので(apache2.confに書かれている)、書き加える必要があります。

www.conf.erbファイルをtemplatesディレクトリにペースト、次のように記述:

  DocumentRoot <%= node['wwwconf']['documentroot'] =>

  <Directory <%= node['wwwconf']['directory'] %>>
    Options Indexes FollowSymLinks
    AllowOverride None
    Require all granted
  </Directory>

mychef3.jsonアトリビュートを記述:

  "wwwconf":{
    "documentroot": "/vagrant",
    "directory": "/vagrant"
  },

レシピの記述:

service "apache2" do
  supports :status => true, :start => true, :stop => true, :restart => true, :reload => true
  action :nothing
end

execute "a2dissite-default" do
  command 'a2dissite 000-default'
  action :nothing
  notifies :reload, "service[apache2]", :immediately
end

execute "a2ensite-www" do
  command 'a2ensite www'
  action :nothing
  notifies :run, "execute[a2dissite-default]", :immediately
end

template "www.conf" do
  path "/etc/apache2/sites-available/www.conf"
  source "www.conf.erb"
  mode 0644
  notifies :run, "execute[a2ensite-www]", :immediately
end

新しい設定ファイルwwwをensiteすると同時にデフォルトの000-defaultをdissiteするのがポイントです。

mod_sslをa2enmod、apache2リロード

テンプレート用設定ファイルをコピーします:

$ cp /etc/apache2/sites-available/default-ssl.conf /vagrant/www-ssl.conf.erb

書き換えるところはありませんが(DocumentRootを書き換えたければお好きに)、templates/defaultにコピーします。

レシピ:

execute "a2ensite-ssl" do
  command 'a2ensite www-ssl'
  action :nothing
  notifies :reload, "service[apache2]", :immediately
end

execute "a2enmod-ssl" do
  command 'a2enmod ssl'
  action :nothing
  notifies :run, "execute[a2ensite-ssl]", :immediately
end

template "www-ssl.conf" do
  path "/etc/apache2/sites-available/www-ssl.conf"
  source "www-ssl.conf.erb"
  mode 0644
  notifies :run, "execute[a2ensite-ssl]", :immediately
end

service[apache2]はすでに定義してあるものを使います。

WorkstationのChromehttps://192.168.33.10にアクセスしてデフォルトページが表示されれば成功です(証明書が自己証明なので警告メッセージが出ます)。

rbenvとruby-build

rubyのReadline6.3に対応してない問題(https://bugs.ruby-lang.org/issues/9578)があって、rbenvからのインストールが難航していたのですが、この問題に対するパッチが適用されたバージョンならインストール(ビルド)可能です。

最近のものだと:

1.9.3系統はたぶん大丈夫かと……(わかんないですが、ぼくの環境では1.9.3-p392がビルドエラー出ませんでした。Bug#9548をみると1.9.3もRequiredになってますが)。

>gem install berkshelf

Windowsだと死ぬほど時間がかかりますが……。

リポジトリトップに"Berksfile"というファイル名のファイルを作ります:

source "https://api.berkshelf.com"

cookbook 'ruby_build'
cookbook 'rbenv', github: "fnichol/chef-rbenv"

Berkshelfのv0.3系統からBerksfileの書き方も変わったので、注意。

cookbookをインストールします:

>berks vendor

現在のリポジトリにberks-cookbooksというディレクトリがつくられて、そこにインストールされます。

ちなみにv0.2のときみたいにberks installすると、デフォルトでは~/.berkshelf/cookbooksにインストールされます(設定によると思いますが)。

>berks vendor cookbooks

だとcookbooksにインストールしようと試みますが、すでに存在するディレクトリだと怒られます。なので、必要があれば、cookbooksディレクトリを削除してからやりましょう。

/chef-repo/.chef/knife.rbを修正します:

cookbook_path    ["cookbooks", "site-cookbooks", "berks-cookbooks"]

自動的に追加してくれればいいのに……。

mychef3.jsonに追記:

(省略)
  "rbenv": {
    "user_installs": [
      {
        "user": "vagrant",
        "rubies": ["2.1.2"],
        "global": "2.1.2"
      }
    ]
  },
  "run_list":[
    "recipe[defset]",
    "ruby_build",
    "rbenv::user"
  ]
}
>knife solo cook mychef3

必要な依存パッケージも自動的にじゃんじゃかインストールしていってくれます。超楽チン。

>ssh mychef3
$ ruby -v
ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-linux]
$ gem -v
2.2.2
$ rbenv versions
  system
* 2.1.2 (set by /home/vagrant/.rbenv/version)

ふう~大変だった。。。(Readline6.3問題を知らなかったので)

ぼくの現時点のrecipe@GitHub