前回に引き続き、dockerコンテナの設定を行います。

今回は各種設定をansibleで行ってみます。

コンテナの設定ということであればDockerfileで行うべきところですが、 物理サーバや各種Virtual Machineにも流用することを考えると、 ansibleやchefなどの利用は有効だと思います。

事前準備

最初に前回作成したコンテナを起動して、IPアドレスを控えておきます。

$ docker start srv1
srv1
$ docker ps -a
CONTAINER ID        IMAGE                          COMMAND               CREATED             STATUS              PORTS               NAMES
0211f0f72f4b        croissant/ubuntu-base:latest   "/usr/sbin/sshd -D"   5 days ago          Up 4 seconds        22/tcp              srv1
$ docker inspect srv1 | grep IPAddress
"IPAddress": "172.17.0.1",

ansibleはpython製ツールですが、実際にはYAMLを編集するだけなので、chefと比べてかなりシンプルに設定できるようです。

今回は開発用環境の構築が主眼になっていますので、 必要なものをまとめてインストールすることにします。

具体的には以下のことを自動化します。

  • mysqlのインストール (aptitude)
  • rbenv (事前に必要なパッケージをインストールして、git clone等)
  • emacs (事前に必要なパッケージをインストールして、ソースをビルド)

ansibleのインストール

ansibleのインストールはaptitudeで行います。

インストールの確認も兼ねて、疎通確認のコマンドを実行してみます。

$ sudo aptitude install ansible
...
$ echo 172.17.0.1 > host             
$ ansible -i host -u docker 172.17.0.1 -m ping
172.17.0.1 | success >> {
  "changed": false,
  "ping": "pong"
}

実例 - mysqlのインストール

mysqlはaptitudeでインストールします。

通常ではコマンドライン一行でインストールできます。

パッケージ情報のアップデートを行ってからインストールするため、通常では実行するコマンドは以下のようになります。

$ sudo aptitude update
$ sudo aptitude install mysql-server mysql-client libmysqlclient-dev

これを実行する設定をYAMLに記述します。

ansibleでは、このYAMLファイルのことを’playbook’と呼んでいるようで、実行の際のコマンドは’ansible-playbook’になります。

playbookの記述

最低限必要な設定は概ね以下のとおりです。

  • hosts: – 対象のホスト hostファイルの記述方法によって、グルーピング可能
  • sudo: コマンドをsudoで実行するフラグ
  • user: 実行ユーザ
  • tasks: 実行内容のリスト

’- name: ‘ でタスクに名前を設定します。

‘command: ‘ で実行するコマンドを設定します。

パスワードの自動設定

mysql-serverをインストールする際、rootユーザのパスワード入力を要求されますが、 そのままではそこでインストール処理がストップします。

この問題に対しては、かなり強引ですが、ひとまず仮パスワードを予め設定しておき、 入力しなくて済むようにすることで回避します。

$ sudo debconf-set-selections <<< 'mysql-server-5.6 mysql-server/root_password password root'
$ sudo debconf-set-selections <<< 'mysql-server-5.6 mysql-server/root_password_again password root'

上記のやりかたでも通らないようです。

ansibleでは’shell:’の場合、コマンドが/bin/sh起動になるので、 chefでのインストール例で使用しているものはそのままではエラーになります。

また、’command:’ではリダイレクト等の記号を使用できないため、動作しません。

結局、環境変数(or シェル変数?)’DEBIAN_FRONTEND’を設定する方法で回避することにしました。

具体的な設定例は以下のようになりました。

mysql.yml

---
- hosts: 172.17.0.1
  sudo: true
  user: docker
  tasks:
    - name: install aptitude
      command: apt-get -y install aptitude
    - name: update packages
      command: aptitude -y update
    - name: install mysql
      command: aptitude -y install mysql-server-5.6 mysql-client-5.6
      environment:
        DEBIAN_FRONTEND: 'noninteractive'

インストールを実行します。

-i オプションで指定するhostファイルは疎通確認の際に使用したものです。

$ ansible-playbook -i host mysql.yml
PLAY [172.17.0.1] *************************************************************
...
PLAY RECAP ********************************************************************
172.17.0.1                 : ok=4    changed=3    unreachable=0    failed=0

実例 - rbenvのインストールと設定

mysqlはaptitudeでインストールしましたが、rbenvについてはgit cloneでインストールしたあと、 任意のバージョンのrubyをインストールします。

変数の定義

playbook内で使用できる変数を定義できます。

以下のような記述です。

  vars:
    ruby_ver: 2.2.3
    target: /home/docker/.rbenv

先ほどのmysqlの場合と同じ要領で設定を行います。

---
- hosts: 172.17.0.1
  user: docker
  vars:
    ruby_ver: 2.2.3
    target: /home/docker/.rbenv
  tasks:
    - name: install dependencies
      command: >
        sudo aptitude -y install
        build-essential
        bison
        libreadline6-dev
        curl
        zlib1g-dev
        libssl-dev
        libyaml-dev
        libsqlite3-dev
        sqlite3
        libxml2-dev
        libxslt1-dev
        autoconf
        libncurses5-dev
    - name: clone rbenv
      command: test -e  || git clone https://github.com/sstephenson/rbenv.git 
    - name: clone ruby-build
      command: test -e /plugins/ruby-build || git clone https://github.com/sstephenson/ruby-build.git /plugins/ruby-build
    - name: add PATH
      command: touch ~/.bashrc ; echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
    - name: add eval
      command: echo 'eval "$(rbenv init -)"' >> ~/.bashrc
    - name: reload bashrc
      command: source /home/docker/.bashrc
    - name: install ruby
      command: rbenv install 

とりあえずこのような感じで実行しましたが、エラーが発生しました。

DNS設定

rbenvはdockerユーザのホームディレクトリにインストールするため、sudo設定を行っていません。

dockerユーザでのコマンドでは、どうやら名前解決に失敗しているようで、cloneができません。

これはdocker自体の設定によるものなので、設定を修正しました。

/etc/default/docker

DOCKER_OPTS="--dns 8.8.8.8 -g /path/to/docker"
  • -g /path/to/dockerはディレクトリを変更したためで、通常は不要です。

ディレクトリが存在する場合は実行しない

git cloneはclone対象ディレクトリがある場合はエラーになります。

存在確認を行って、存在する場合は実行しないコマンドにしたつもりですが、 commandの場合はこの記述ではダメで、ansibleの機能で制御する必要があるようです。

when: 1 == result というような記述で、 あらかじめ存在確認のコマンド(test -e など)で結果を保存しておき、 存在確認の結果で実行制御できるようです。

後で動かしてみると、これもダメみたいでした。

他の方法を調べたところ、stat: というモジュールがありましたので、そちらの記述に変更しました。

stat: は指定したpathの状態を取得できるもので、今回は存在確認ができれば良いので、以下のようにしています。

    - stat: path=
      register: rbenv
    - name: clone rbenv
      command: git clone https://github.com/sstephenson/rbenv.git 
      when: not rbenv.stat.exists

ファイルをコピーする

copy: src=xxx dest=xxx というフォーマットで実現できます

環境変数の追加と反映について

.bashrcに追加した環境変数の反映は、通常ではsource等で行いますが、 ansibleで追加したあとはそのままでは反映できないようです。

また、コマンドを実行する記述については、command: の他に shell: もあるようで、 shell: の場合は/bin/sh による実行で、&&や||が使用できます。

playbook内に環境変数を別途定義するか、bash -lc でコマンド実行する方法が紹介されていましたが、 これらも動作しませんでした。

これらはcommandとshellの違いか、環境の違いによるものと思われますが、 PATHの場合は、絶対パス指定という確実な方法があるため、そちらを使用することにしました。

以下の内容がインストールに成功したものです。

rbenv.yml

---
- hosts: 172.17.0.1
  user: docker
  sudo: false
  vars:
    ruby_ver: 2.2.3
    target: /home/docker/.rbenv
    rbenv_path: /home/docker/.rbenv/bin/rbenv
  tasks:
    - name: send bashrc
      copy: src=files/.bashrc dest=~/.bashrc
    - stat: path=
      register: rbenv
    - name: clone rbenv
      command: git clone https://github.com/sstephenson/rbenv.git 
      when: not rbenv.stat.exists
    - stat: path=/plugins/ruby-build
      register: ruby_build
    - name: clone ruby-build
      command: git clone https://github.com/sstephenson/ruby-build.git /plugins/ruby-build
      when: not ruby_build.stat.exists
    - command: touch ~/.bashrc
    - name: add PATH
      shell: echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc && echo 'eval "$(rbenv init -)"' >> ~/.bashrc
    - name: install ruby
      shell: ( init -);  install -s  ;  rehash ;   global 

実例 - emacsのインストール

今度は、emacsをソースコードからビルド&インストールします。

ファイルのダウンロード

ansibleにはファイルをダウンロードする機能があります。

以下のように記述することで、ネット上からファイルをダウンロードできます。

    - name: get emacs src
      get_url: url=http://ftp.jaist.ac.jp/pub/GNU/emacs/emacs-.tar.xz dest=

ディレクトリの変更

tar.gzなどをダウンロードしてビルドする際、展開したディレクトリに移動する必要があります。

ansibleのタスクは、前のタスクの状態を引き継がないようになっているようなので、 カレントディレクトリの変更を明示する必要があります。

    - name: make emacs
      command: make chdir=/emacs-

ビルド自体はrbenvでも行っていますので、ここでは大きな問題は発生しないと思いつつ、 前回のポイントも踏まえてplaybookを記述します。

emacs.yml

---
- hosts: 172.17.0.1
  sudo: true
  user: docker
  vars:
    emacs_ver: 24.5
    src: /usr/src
  tasks:
    - name: get emacs src
      get_url: url=http://ftp.jaist.ac.jp/pub/GNU/emacs/emacs-.tar.xz dest=
    - name: extract emacs src
      command: tar xJf emacs-.tar.xz chdir= creates=/
    - name: configure emacs
      command: >
        ./configure
        --without-toolkit-scroll-bars
        --without-xaw3d
        --without-compress-info
        --without-sound
        --without-pop
        --without-xpm
        --without-tiff
        --without-rsvg
        --without-gconf
        --without-gsettings
        --without-selinux
        --without-gpm
        --without-makeinfo
        --without-x
        chdir=/emacs-
    - name: make emacs
      command: make chdir=/emacs-
    - name: install emacs
      command: make install chdir=/emacs-

includeについて

include: を使用することで、playbook内から他のplaybookを呼び出すことができます。

再利用という観点は今回のケースではそれほど重要ではありませんが、 種別ごとにタスクをまとめておくことで利用しやすくなるでしょう。

再利用については、すでに作成済みのplaybookを呼び出すだけになるので、 とても簡潔に記述できます。

今回作成したものをすべてインストールする場合は、例えば以下のようになります。

srv1.yml

---
- hosts: 172.17.0.1
  sudo: true
  user: docker
- include: common.yml
- include: mysql.yml
- include: rbenv.yml
- include: emacs.yml
  • mysql以外のインストールパッケージはcommon.ymlにまとめています。
  • includeしているファイルのhosts設定はすべてallに変更しました。


blog comments powered by Disqus