しふみんのブログ

しふみんのブログです。

CentOSローカル開発環境構築用のAnsibleのplaybookを作った

概要

VagrantでCentOS6.6にGit,(私の)dotfiles,Zsh,Oh-My-Zsh,peco,tmux,Vim,Nginx,MySQL,rbenvをインストールしてローカル開発環境構築を自動化するAnsibleのplaybookを作った。

以下が作ったplaybook。

github.com

背景

Railsで遊ぶためにVagrantでローカル開発環境を構築しようと思ったけど、どうせなら環境構築を自動化したいと思い、構成管理ツールの中で興味があったAnsibleの勉強がてらVagrantCentOSのローカル開発環境構築用のAnsibleのplaybookを作った。Railsと言いながらrbenvのインストールまでの自動化になっている^^;

環境

実行

$ git clone git@github.com:shifumin/vagrant-ansible-centos.git
$ cd vagrant-ansible-centos
$ vagrant up

playbookの内容

CentOS6.6に

をインストールする。

各rolesの詳しい内容は以下のとおり。

yum_repo

yum_install

  • 必要そうなパッケージをインストール
  • Development Tools をグループインストール

Git

  • 依存パッケージのインストール
  • ソースコードからGitをダウンロードして解凍してインストール

dotfiles

Zsh

  • 依存パッケージのインストール
  • ソースコードからZshをダウンロードして解答してインストール
  • Oh-My-Zshのインストール
  • ログインシェルをzshに変更

peco

  • pecoのバイナリをダウンロードして解答して/usr/local/binにコピーする。

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 Style8.1.3. Folded Style 辺りに書いてあった。

終わり

ゆくゆくはさくらVPSCentOS本番環境構築自動化に取り組みたい。

・・・の前に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を使い出す前に押さえておきたかったディレクトリ構成のベストプラクティス - 双六工場日誌

Ansible で git clone させる - Qiita

Vagrant 1.7+でSSH接続エラーが出た場合の対処法 | mawatari.jp