概要
VagrantでCentOS6.6にGit,(私の)dotfiles,Zsh,Oh-My-Zsh,peco,tmux,Vim,Nginx,MySQL,rbenvをインストールしてローカル開発環境構築を自動化するAnsibleのplaybookを作った。
以下が作ったplaybook。
shifumin/vagrant-ansible-centos
https://github.com/shifumin/vagrant-ansible-centos
背景
Railsで遊ぶためにVagrantでローカル開発環境を構築しようと思ったけど、どうせなら環境構築を自動化したいと思い、構成管理ツールの中で興味があったAnsibleの勉強がてらVagrantのCentOSのローカル開発環境構築用のAnsibleのplaybookを作った。Railsと言いながらrbenvのインストールまでの自動化になっている^^;
環境
- VirtualBox 5.0.2
- Vagrant 1.7.4
- Ansible 1.9.2
- Vagrant Box chef/centos-6.6
実行
$ git clone git@github.com:shifumin/vagrant-ansible-centos.git
$ cd vagrant-ansible-centos
$ vagrant up
playbookの内容
CentOS6.6に
- Git 2.5.0
- (私の)dotfiles( https://github.com/shifumin/dotfiles )
- Zsh 5.0.8 (+Oh-My-Zsh)
- peco
- tmux 2.0
- Vim 7.4
- Nginx
- MySQL 5.6
- rbenv
をインストールする。
各rolesの詳しい内容は以下のとおり。
yum_repo
- EPELリポジトリを追加
- Remiリポジトリを追加
- Nginxリポジトリを追加
- MySQL-communityリポジトリを追加
yum_install
- 必要そうなパッケージをインストール
- Development Tools をグループインストール
Git
- 依存パッケージのインストール
- ソースコードからGitをダウンロードして解凍してインストール
dotfiles
- dotfilesをgit cloneする
- 各ドットファイルのシンボリックリンク張りのスクリプトを実行
Zsh
- 依存パッケージのインストール
- ソースコードからZshをダウンロードして解答してインストール
- Oh-My-Zshのインストール
- ログインシェルをzshに変更
peco
- pecoのバイナリをダウンロードして解答して/usr/local/binにコピーする。
tmux
- ソースコードからlibeventをダウンロードして解凍してインストール
- ソースコードからtmuxをダウンロードして解答してインストール
Vim
- Vimパッケージ他のインストール
Nginx
- Nginxパッケージをインストールする
- ginxを起動し、自動起動の設定をonにする
MySQL
- MySQLパッケージをインストールする
- mysqldを起動し、自動起動の設定をonにする。
rbenv
- 依存パッケージのインストール
- rbenvのインストール
- ruby-buildのインストール
- rbenv-default-gemsのインストール
- ~/dotfiles/default-gemsのシンボリックリンク張り
- rbenv-updateのインストール
- ソースコードからRSenseをダウンロードして解凍してインストール
ディレクトリ構成
vagrant-ansible-centos/
├── playbook/
│ ├── group_vars/
│ │ └── all.yml
│ ├── roles/
│ │ ├── dotfiles/
│ │ │ └── tasks/
│ │ │ └── main.yml
│ │ ├── git/
│ │ │ └── ...
│ │ ├── rbenv/
│ │ │ └── ...
│ │ ├── tmux/
│ │ │ └── ...
│ │ ├── vim/
│ │ │ └── ...
│ │ ├── yum_repo/
│ │ │ └── ...
│ │ ├── yum_update/
│ │ │ └── ...
│ │ └── zsh/
│ │ │ └── ...
│ ├── hosts
│ └── site.yml
├── Vagrantfile
└── ansible.cfg
基本的には、公式のベストプラクティスに沿った構成になっているはず。
メインのplaybookは playbook/site.yml 、inventoryファイルは playbook/hosts、変数の格納ファイルは playbook/group_vars/all.yml とした。
詰まったところ
全てがSSH関連でほとんどがgitモジュール関連。
SSH Error: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password)
問題
ansible-playbookしようとすると、初っ端に以下のエラーが出る。
fatal: [192.168.xx.xx] => SSH Error: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
while connecting to 192.168.42.30:22
It is sometimes useful to re-run the command using -vvvv, which prints SSH debug output to help diagnose the issue.
公開鍵が云々。
解決方法
原因はこれらしい。
ansible.cfgに private_key_file を付け加える。
[defaults]
private_key_file = .vagrant/machines/web/virtualbox/private_key
Warning: Permanently added the RSA host key for IP address '192.30.xx.xx' to the list of known hosts
問題
gitモジュールでgit cloneしようとすると、以下のエラーが出る。
failed: [192.168.xx.xx] => {"cmd": "/usr/local/bin/git ls-remote '' -h refs/heads/HEAD", "failed": true, "rc": 128}
stderr: Warning: Permanently added the RSA host key for IP address '192.30.xx.xx' to the list of known hosts.
Permission denied (publickey).
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
msg: Warning: Permanently added the RSA host key for IP address '192.30.xx.xx' to the list of known hosts.
Permission denied (publickey).
fatal: Could not read from remote repository.
known hostsにhostkeyが云々。
解決方法
Vagrant上に構築する仮想環境に秘密鍵を置かずにGithubとやり取りをするためにansible.cfgに ForwardAgent=yes を付け加える。
[ssh_connection]
ssh_args = -o ForwardAgent=yes
Failed to find required executable git
問題
同じく、gitモジュールでgit cloneしようとすると、以下のエラーが出る。
failed: [192.168.xx.xx] => {"failed": true}
msg: Failed to find required executable git
FATAL: all hosts have already failed -- aborting
gitのバイナリがない?って言われる。
解決方法
sudo時にgitへのPATHが通っていないからっぽい。
gitモジュールではsudoじゃなくてユーザで実行させるために、taskに sudo=no をつける。
---
- name: git clone dotfiles repository
sudo: no
git:
repo=git@github.com:shifumin/dotfiles.git
dest=/home/{{ user }}/dotfiles
accept_hostkey=yes
github.com has an unknown hostkey
問題
さらに同じく、gitモジュールでgit cloneしようとすると、以下のエラーが出る。
failed: [192.168.xx.xx] => {"failed": true}
msg: github.com has an unknown hostkey. Set accept_hostkey to True or manually add the hostkey prior to running the git module
github.comに登録されてあるhostkeyが違う?ので、accept_hostkeyを有効にしろって言われる。
解決方法
playbookの一番最初に実行するgitモジュールのtaskに accept_hostkey=yes をつける。
初回のみでいいはず。
---
- name: git clone dotfiles repository
sudo: no
git:
repo=git@github.com:shifumin/dotfiles.git
dest=/home/{{ user }}/dotfiles
accept_hostkey=yes
以下メモ
変数をどこに格納するか
変数をどこに書くかに大分迷ったけど、変数の使い分け等をしない場合は group_vars/all に書いておけば特に指定しなくても全rolesに適用されるようだ。
また、ファイル名をall.ymlとすることで、シンタックスハイライトを付けることができる(YAMLファイルにシンタックスハイライトを設定している場合)
したがって、変数は、 group_vars/all.yml に記述することにした。
ソースコードをダウンロードして解凍してmake installするやり方
他の人の方法を見ていたら色々なやり方・書き方があることが分かって、当初は全てをshellモジュールを使って一気通貫で処理させていた。
例えば以下のように記述していた。
- name: install tmux
shell: |
wget https://github.com/tmux/tmux/releases/download/{{ tmux_ver }}/tmux-{{ tmux_ver }}.tar.gz
tar zxvf tmux-{{ tmux_ver }}.tar.gz
rm -f tmux-{{ tmux_ver }}.tar.gz
cd tmux-{{ tmux_ver }}
./configure
make
make install
args:
chdir: "{{ src_dir }}"
しかし、shellモジュールは冪等性が担保されずに初回以降も毎回実行されて
(上手く条件分岐すれば回避できるだろうけど)スキップされないので、Ansible標準のモジュールを使いtaskを分けるようにした。
つまり、以下のように、get_urlモジュールでソースコードをダウンロードして、unarchiveモジュールで解凍して、最後のmake installだけをshellモジュールで処理するようにした。
---
- name: download tmux source
get_url:
url=https://github.com/tmux/tmux/releases/download/{{ tmux_ver }}/tmux-{{ tmux_ver }}.tar.gz
dest="{{ src_dir }}/tmux-{{ tmux_ver }}.tar.gz"
- name: extract tmux source
unarchive:
src="{{ src_dir }}/tmux-{{ tmux_ver }}.tar.gz"
dest="{{ src_dir }}"
copy=no
- name: install tmux
shell: >
{{ item }}
chdir="{{ src_dir }}/tmux-{{ tmux_ver }}"
creates="{{ bin_dir }}/tmux"
with_items:
- ./configure
- make
- make install
get_urlモジュールはdestに既にファイルが存在する場合はスキップされ、unarchiveモジュールもdestのディレクトリに解凍後のファイルがあればスキップされるので冪等性は保たれる。そして、最後のmake installのshellモジュールはcreatesでインストールされていたらスキップするようにした。
YAMLで複数行にわたる書き方
上記の、ソースコードからmake installするshellモジュールの書き方を考えている時に、どうしたらきれいに書けるだろうと調べていたら、YAMLにはLiteral StyleとFolded Styleという書き方があることを知った。
Literal Style
Literal Styleはインジケータとして "|" を使う書き方で、
text: |
hoge
foo
bar
"text" => "hoge\nfoo\nbar\n"
各行の改行が保存される。
Folded Style
そして、Folded Styleは、インジケータとして ">" を使う書き方で、
shell: >
hoge
foo
bar
"text" => "hoge foo bar\n"
各行の改行が半角スペースに置換され、最終行の改行は保存される。
この2つを使えば、例えば、shellモジュールで./configureした後にmakeしてその後にmake installする処理は、
shell: |
./configure
make
make install
と書けるし、
./configure && make && make intallする処理を複数行に分けて書きたい時は、
shell: >
./configure &&
make &&
make install
と書くことができる。
詳しくは、
YAML Ain’t Markup Language (YAML™) Version 1.2
の 8.1.2. Literal Style と 8.1.3. Folded Style 辺りに書いてあった。
終わり
ゆくゆくはさくらVPSのCentOS本番環境構築自動化に取り組みたい。
・・・の前にNginxとMySQLの初期設定の自動化にも取り組みたい。
参考
Best Practices — Ansible Documentation
Configuration file — Ansible Documentation
git - Deploy software (or files) from git checkouts — Ansible Documentation
YAML Ain’t Markup Language (YAML™) Version 1.2
Ansibleを使い出す前に押さえておきたかったディレクトリ構成のベストプラクティス - 双六工場日誌