LoginSignup
4
3

More than 3 years have passed since last update.

機械学習エンジニアがAnsible入門してみた

Last updated at Posted at 2019-06-18

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で管理されるノード)も同一の開発マシンである。

手順

ユーザが行う手順は以下の通り。

  1. ansible本体のインストール
  2. playbook.ymlをイントラ上のサーバーからダウンロード
  3. ローカルホストを指定して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の挙動確認

参考

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3