Ansibleでインターネットに繋がらない環境へPythonライブラリをインストールする
インターネットに繋がらないHadoopクラスタの各slaveに対してAnsibleでPythonのライブラリを管理することを想定して試してみましたので、その時の内容を書いておきます。
hadoopクラスタへのpythonライブラリ追加として、とりあえず以下のユースケースを追加しています。
- 一つのノードに全てのライブラリをインストールする
- 全てのノードに一つのライブラリをインストールする
それから要件として既にライブラリがインストール済であればインストールを実行しないようにもしたいと思います。
まず、作成したansibleプロジェクトのディレクトリ構成は以下のようになりました。
ansible ├── devserver.yml ├── install_one_library.yml ├── roles │ └── python │ ├── files │ │ ├── install_shell │ │ │ ├── build_install.sh │ │ │ ├── install.sh │ │ │ └── install_pip.sh │ │ └── library │ │ ├── cython-0.28.2.tar.gz │ │ ├── numpy-1.11.0.tar.gz │ │ ├── numpy-1.14.2.tar.gz │ │ └── pip-10.0.1.tar.gz │ ├── vars │ │ └── library_version.yml │ └── tasks │ ├── init.yml │ ├── install_cython.yml │ ├── install_numpy.yml │ ├── install_pip.yml │ └── main.yml ├── staging.info └── group_vars └── default.yml
それでは各ファイル毎の役割をまとめて行きたい思います。
group_vars/default.yml
--- ansible_home: "/var/ansible"
staging.info
[batch-servers] ip[15:16].localdomain ansible_ssh_user=hoge
- 通常のインベントリファイルと同じです
- hadoopのslaveなど大量にインストールを行う場合は連番で指定するのが良さそうです
devserver.yml
--- - hosts: batch-servers become: yes vars_files: - vars/default.yml - roles/python/vars/library_version.yml roles: - python # ansible-playbook devserver.yml -i staging.info --private-key=~/.ssh/id_rsa # ansible-playbook devserver.yml -i staging.info --private-key=~/.ssh/id_rsa --limit ip15.localdomain
- 全てのpythonライブラリをインストールするためのplaybookファイル
- 特定のノードに入れたい場合は
--limit
でホストを直接指定します。
install_one_library.yml
--- - hosts: batch-servers become: yes vars_files: - vars/default.yml - roles/python/vars/library_version.yml tasks: - include: roles/python/tasks/init.yml - include: roles/python/tasks/install_{{ lib }}.yml # ansible-playbook install_one_library.yml --extra-vars="lib=pip" -i staging.info --private-key=~/.ssh/id_rsa_nopass
- 全てのノードに一つのライブラリをインストールするためのplaybookファイルです
- 実行時に変数libを渡してインストール対象のたtaskを指定します。
- 例えば
--extra-vars="lib=pip"
を指定したらroles/python/tasks/install_pip.yml
のタスクを実行
roles/python/vars/library_version.yml
--- pip_version: 10.0.1 numpy_version: 1.14.2 cython_version: 0.28.2
- インストールするライブラリのバージョンを管理します。
roles/python/files/libraryディレクトリ
- インストール対象のライブラリを直接保存しておきます。
- githubのreleaseからダウンロードしたものを置いておきます
- git cloneしたものにtag指定でソースを取り出した場合たまに
python setup.py --version
があった
roles/python/files/install_shellディレクトリ
- ライブラリインストール用のshellを配置します
- shell内では
library_version.yml
で指定したバージョンがインストール済みかどうかを確認し、指定バージョンが入っていなければインストールします。
roles/python/tasksディレクトリ
- ライブラリインストールのためのtaskファイルを管理します。
-
main.yml
内では初期化用のファイル読み込みと全てのライブラリインストールのためのファイルをincludeします init.yml
は初期用のファイル
roles/python/tasks/main.yml
--- - include: roles/python/tasks/init.yml - include: roles/python/tasks/install_cython.yml - include: roles/python/tasks/install_numpy.yml
- 初期化用と各ライブラリインストールのtaskを読み込んでいます。
roles/python/tasks/init.yml
--- - name: upload python library copy: src: ../files/library dest: "{{ ansible_home }}/python" mode: 0755 - name: upload python install shell copy: src: ../files/install_shell dest: "{{ ansible_home }}/python" mode: 0755 - name: be sure python-setuptools is installed yum: name=python-setuptools state=installed - name: be sure python-devel is installed yum: name=python-devel state=installed - include: roles/python/tasks/install_pip.yml
- pythonライブラリインストールのために必要なモジュールのインストールを行います。
- roles/python/files/library, roles/python/files/install_shellをアップロードします。
- python-setuptoolsとpython-develは事前にインストールされている必要がある
- pipも初期化処理でインストールします。
roles/python/tasks/install_pip.yml
--- - name: Extract pip command: tar zxvf "{{ ansible_home }}/python/library/pip-{{ pip_version }}.tar.gz" --directory "{{ ansible_home }}/python/library/" - name: Install pip command: "{{ ansible_home }}/python/install_shell/install_pip.sh {{ ansible_home }}/python/library/pip-{{ pip_version }} pip"
- pipのインストールを行います。
roles/python/files/install_shell/install_pip.sh
#!/bin/bash LIBRARY_DIR=$1 LIBRARY=pip IS_INSTALLED=0 cd $LIBRARY_DIR set -e trap 'setup_install' ERR function setup_install { python setup.py install } SOURCE_VERSION=`python setup.py --version` if test `python -m ${LIBRARY} -V | grep -oE "${SOURCE_VERSION}[^ ]*" | head -n1` == `echo $SOURCE_VERSION` ; then echo "already installed" else echo "not installed" setup_install fi
- pipのインストール用shellです
- インストール済みかどうかをチェックします
roles/python/tasks/install_numpy.yml
- include: roles/python/tasks/install_cython.yml - name: Extract numpy command: tar zxvf "{{ ansible_home }}/python/library/numpy-{{ numpy_version }}.tar.gz" --directory "{{ ansible_home }}/python/library/" - name: Install numpy command: "{{ ansible_home }}/python/install_shell/build_install.sh {{ ansible_home }}/python/library/numpy-{{ numpy_version }} numpy"
- numpyのインストールを行います。
- 依存するライブラリは includeでタスクを読み込むようにしています。
roles/python/files/install_shell/build_install.sh
#!/bin/bash LIBRARY_DIR=$1 LIBRARY=$2 IS_INSTALLED=0 cd $LIBRARY_DIR function find_installed_version { _LIBRARY=$1 _VERSION_WITH_EQ=`pip freeze | grep $_LIBRARY | grep -oE "==.+"` echo ${_VERSION_WITH_EQ:2} } function setup_build_install { python setup.py build python setup.py install } INSTALLED_VERSION=`find_installed_version $LIBRARY` SOURCE_VERSION=`python setup.py --version` if test `echo $INSTALLED_VERSION` == `echo $SOURCE_VERSION` ; then echo "already installed" else setup_build_install fi
- buildが必要な場合のinstall用shellです