Deep Learningの開発環境を作ったり壊したりをもっと気軽にしたいので、Ansibleで環境構築を自動化してみました。
想像していたよりもずっと簡単だったので、アプリ系・機械学習系エンジニアに「IaC怖くないよ」と伝えたいのが本記事の趣旨です。Ansibleを既に使われてる方からしたら拙い内容ですがご容赦ください。
TL;DR
- ホスト名の設定
- aptサーバーを日本サーバーに変更
- aptコマンドでインストール
- nvidia-driverのインストール
- docker-ce + nvidia-docker2のインストール
- dockerサービスの再起動
を下記のコマンドで自動化した。
# Ansibleのインストール。最新のインストール手順は公式ページを参照すること
# cf. https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html
sudo apt update
sudo apt install software-properties-common
sudo apt-add-repository --yes --update ppa:ansible/ansible
sudo apt install ansible
# Playbookの取得
# e.g.
curl -L https://raw.githubusercontent.com/chmod644/deeplearning-setup-playbook/d7db096cbd42741f68f2461c01280f138eee3c5a/playbook.yml -o playbook.yml
# ansible-playbookを実行
ansible-playbook playbook.yml -u ansible -i localhost, -c local --ask-become-pass
感想
使ってみた感想としては、**想像してたよりずっと学習コストが低い。**Ansibleや他のIaCツールも未経験の状態でスタートして、環境構築を自動化するとこまで1日で辿りつけてしまった。
今回はマシン1台の環境構築を自動化しただけなので、構成管理というには初歩も初歩だろうけど、本当に簡単で驚いてしまった。
Ansibleのメリットは色々な記事で説明されてるので今更だが、改めて実感したので一応書いておく。
- モジュールが豊富で、基本的な作業(apt, yum, wget, systemctlなどなど)はたいてい簡単に記述できる
- 構成情報を記述するplaybookはyaml形式なので、記述方法を覚える学習コストが低いもしくはゼロ
- QiitaやStack Overflow, GitHub issueにも情報が多いので調べやすい
- Ansibleで管理される側のノードには基本的にpythonだけあればよいので事前準備が楽(エージェントレス)
目標
開発マシンに対して以下の作業を自動化するのを目標とした。
- ホスト名の設定
- aptサーバーを日本サーバーに変更
- aptコマンドでインストール
- nvidia-driverのインストール
- docker-ce + nvidia-docker2のインストール
- dockerサービスの再起動
※社内環境で使う際にはDNS設定やドメイン参加のような初期設定が必要だが、今回は自宅マシンで検証したのでそのあたりは自動化対象にしてない。
なお、環境構築に使ったのは開発マシン1台とした。つまりControl Node(Ansibleの実行ノード)もManaged Node(Ansibleで管理されるノード)も同一の開発マシンである。
手順
ユーザが行う手順は以下の通り。
- ansible本体のインストール
- playbook.ymlをイントラ上のサーバーからダウンロード
- ローカルホストを指定してansibleを実行
開発マシンのスペック:
- Ubuntu 18.04
- GeForce GTX 1060
- (Ansible 2.8 ※本手順でインストールする)
1. Ansible本体のインストール
Ansibleのインストール手順 にしたがってインストールする。
2. playbookをダウンロード
開発マシンはGitすら入ってない想定。なのでplaybookはcurlやwgetで取得できるのが望ましいと思って1ファイルにまとめた。
curl -L https://raw.githubusercontent.com/chmod644/deeplearning-setup-playbook/d7db096cbd42741f68f2461c01280f138eee3c5a/playbook.yml -o playbook.yml
playbook の内容は後述する。
3. ローカルホストを指定して実行する
ansible-playbook playbook.yml -i localhost, -c local --ask-become-pass
コマンドライン引数について
-
-i localhost,
: Managed Nodeとしてlocalhostを指定している。カンマは必須なので注意。IPアドレスでもよい -
-c local
: ssh接続せずlocalhostで、カレントユーザーまま実行する。-u <ユーザー名>
やremote_user
で指定されたユーザーは無視される。(Ansible標準動作ではssh接続するが、Connection Pluginsという機能でssh以外の接続もできる) -
--ask-become-pass
: sudo権限で実行するためのパスワードを対話的に入力する。上記のように-c local
が指定された場合は、カレントユーザーのパスワードを指定すればよい。
Playbookの内容
playbookはGitHubにもあげている。
拙い記述で恥ずかしいが、フィードバックしてもらえるのを期待して晒してみる。もっとよい書き方とか誤りがあればコメントいただきたい。
- hosts: localhost
# sudo権限でtasksを実行する。
become: yes
vars:
# ディストリビューションの番号を 18.04 -> 1804 に置換
ubuntu_dist_for_nvidia_cuda: "{{ ansible_distribution_version | regex_replace('\\.', '')}}"
tasks:
# --- ここからホスト名の設定 ---
# ホスト名を標準入力から待ち受けている。
- name: prompt hostname
pause:
prompt: "HOSTNAME [{{ ansible_fqdn }}]"
register: hostname_input
# ホスト名が入力されたらその値を、入力されなかったら
# 初期ホスト名(ansible_fqdn)を変数hostnameにセットする
- name: set default hostname
set_fact:
hostname: "{{ hostname_input.user_input | default(ansible_fqdn, true) }}"
# 初期ホスト名とhostnameの内容が違う場合はホスト名を設定し直す。
- name: set hostname
hostname:
name: "{{ hostname }}"
when: hostname != ansible_fqdn
# --- ここまでホスト名の設定 ---
# aptリポジトリを日本サーバーに変更する。
- name: set japanese apt server
replace:
path: /etc/apt/sources.list
regexp: '(http:\/\/archive\.ubuntu\.com\/ubuntu\/|http:\/\/us\.archive\.ubuntu\.com\/ubuntu\/)'
replace: 'http://jp.archive.ubuntu.com/ubuntu/'
# 使いそうなパッケージを入れてる。
- name: install apt packages
apt:
name: [git]
state: present
update_cache: yes
# --- ここからNVidiaドライバのインストール ---
- name: add nvidia-driver registory key
apt_key:
url: http://developer.download.nvidia.com/compute/cuda/repos/{{ ansible_distribution | lower }}{{ ubuntu_dist_for_nvidia_cuda }}/{{ ansible_architecture }}/7fa2af80.pub
state: present
- name: add nvidia-driver repository source
apt_repository:
repo: deb https://developer.download.nvidia.com/compute/cuda/repos/{{ ansible_distribution | lower }}{{ ubuntu_dist_for_nvidia_cuda }}/{{ ansible_architecture }} /
state: present
update_cache: no
filename: nvidia-cuda
- name: install nvidia-driver
apt:
name: [nvidia-418]
state: present
update_cache: yes
# --- ここまでNVidiaドライバのインストール ---
# --- ここからDocker+NVidia-Dockerのインストール ---
# Dockerの依存パッケージをインストール
- name: install docker dependencies
apt:
name: [apt-transport-https, ca-certificates, curl, gnupg-agent, software-properties-common]
state: present
update_cache: yes
# Dockerのaptレジストリの認証キーを取得
- name: add docker registory key
apt_key:
url: https://download.docker.com/linux/debian/gpg
state: present
# Dockerのaptレジストリを追加。/etc/apt/source.list.d/<filename>.listに追加される。
- name: add docker repository source
apt_repository:
repo: deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable
state: present
update_cache: no
filename: docker
# nvidia-dockerも同じように認証キーとレジストリを追加する
- name: add nvidia-docker repository key
apt_key:
url: https://nvidia.github.io/nvidia-docker/gpgkey
state: present
# { ansible_distribution | lower }}{{ ansible_distribution_version }} は ubuntu18.04とパースされる。
- name: add nvidia-docker repository source
get_url:
url: https://nvidia.github.io/nvidia-docker/{{ ansible_distribution | lower }}{{ ansible_distribution_version }}/nvidia-docker.list
dest: /etc/apt/sources.list.d/nvidia-docker.list
owner: root
group: root
mode: 0644
- name: install docker and nvidia-docker
apt:
name: ['docker-ce=5:18.09.6~3*', 'nvidia-docker2=2.0.3+docker18.09.6-3', docker-ce-cli, containerd.io]
state: present
update_cache: yes
register: nvidia_docker_apt
# Docker+NVidia-Dockerのバージョンを固定する
- name: keep versions of docker and nvidia-docker
dpkg_selections:
name: "{{ item }}"
selection: hold
with_items: [docker-ce, nvidia-docker2]
# --- ここまでDocker+NVidia-Dockerのインストール ---
# DockerとNVidia-Dockerのインストールで変更があればdockerサービスを再起動する
- name: reload docker configuration
service:
name: docker
state: reloaded
when: nvidia_docker_apt.changed == True
# カレントユーザーをdockerグループに追加
- name: add user to docker group
user:
name: '{{ ansible_user }}'
groups: docker
append: yes
動作確認
Dockerコンテナでnvidia-smiを動かしてみる。
$ docker run --runtime=nvidia --rm nvidia/cuda:9.0-base nvidia-smi
Tue Jun 18 18:30:59 2019
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 410.78 Driver Version: 410.78 CUDA Version: 10.0 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 GeForce GTX 106... Off | 00000000:01:00.0 Off | N/A |
| 28% 40C P8 6W / 120W | 0MiB / 6078MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
ハマったところ
- Connection pluginに
local
を指定するとremote_userの設定が無視されること。しばらく気づかなかった。 - replaceの正規表現の仕様はPythonのreライブラリと同じらしい。
- たまに
apt
モジュールのところでFailed to update apt cache ...
というエラーメッセージで落ちる。この現象はansible-playbook
の前にsudo apt-get clean
を実行することで解消可能。apt-get clean
相当のこともAnsibleで実行できるようにと要望が出されているがまだ実装されてない様子。 - Ansibleに直接関係ないが、nvidia-docker2のバージョンとdocker-ceのバージョンは揃える必要があるため、明確にバージョン指定してやらないといけない。
- パッケージの固定は
dpkg_selections
モジュールで行う。apt
と違ってnameにリストが指定できないので注意。
TODO
- Ansibleに詳しい人にレビューしてもらう
- CUDA/cuDNNのインストールを自動化 ※cuDNNのダウンロードにWeb画面上でのサインインが必要なため保留
- 社内環境でのドメイン参加・共通セットアップの自動化
- パッケージのバージョンを変数化する
- Best Practices — Ansible Documentation に則ってリファクタする
-
Ansibleの挙動確認
- 対話的なコマンドの実行 (expect – Executes a command and responds to prompts — Ansible Documentationが使えるらしい)
- Control NodeからManaged Nodesへのファイルコピー
参考
- Installation Guide — Ansible Documentation
- [Ansible] AnsibleのPlaybookをlocalhostに対して実行する - Qiita
- Ansible Playbook to install nvidia-docker2
- Ansibleをはじめる人に。 - Qiita
- Ansible 入門 - Qiita
- Get Docker CE for Ubuntu | Docker Documentation
- NVIDIA/nvidia-docker: Build and run Docker containers leveraging NVIDIA GPUs
- Ansibleでパスワードをスマートに - Qiita
- apt-getの利用リポジトリを日本サーバーに変更する - Qiita
- ansible で prompt (入力待ち) の実現とその周辺テクニックのまとめ - Qiita
- NVIDIA/ansible-role-nvidia-docker
- Support apt-mark hold · Issue #18889 · ansible/ansible