Nabe International | Takeru Boost >> Takeruを回せ! >>

Univa Grid Engine : DockerをUGEで管理する

概要

Univa Grid Engine(以下UGE)の8.4.0以降のバージョンではUGEはDockerに対応しています。 とは言っても、正直言ってこれが意味するところはすぐにはピンと来ないかもしれません。 それは、対応するしないにかかわらず、 $ qsub -b y -N DOCK -cwd docker run -it --rm ..... というように、dockerのジョブであることを意識せずに非dockerのジョブと同じようにqsubすれば ハードウェアリソースの状況を見てジョブをスケジューリングするということが可能である、 ということが一因としてあるのではないかと思います。
今回は、UGEがDockerに対応していることのメリットについて少し挙げてみたいと思います。

UGEがDockerに対応していることのメリット

a) ホスト毎のdockerの有無をリソースとして管理している

計算ノード内でdockerのdaemonが動いているノードと動いていないノードがあった場合、 dockerが動いているノードを実行対象としてくれます。 " # qstat -F docker "と実行してhl:docker=1となっていればそのホストではdockerのジョブの実行が可能です。 hl:docker=0の場合はdockerのジョブは投入されません。
$  qstat -F docker
queuename                      qtype resv/used/tot. np_load  arch          states
---------------------------------------------------------------------------------
all.q@n000                      BIP   0/0/24         0.00     lx-amd64      
              hl:docker=1

b) ホスト毎に保持しているコンテナイメージのリストも管理している

ジョブの中で指定されたコンテナイメージを持っているホストにジョブが投入されるので pullする時間を待つ必要が無く、効率的にジョブが実行される (上記はデフォルトの動作で、"-soft" オプションを付けるとイメージを保持しているホストが無かったり、リソースが埋まっていて すぐにジョブが投入されないような場合には、イメージを持っていないホストにジョブが投入され、docker pullも行われるようになります)
"# qstat -F docker_images"と実行すると各ホストで持っているイメージのリストがカンマ区切りで表示されます。
$  qstat -F docker
queuename                      qtype resv/used/tot. np_load  arch          states
---------------------------------------------------------------------------------
all.q@n000                      BIP   0/0/24         0.00     lx-amd64      
             hl:docker_images=docker.io/bgruening/galaxy-stable:latest,docker.io/nvidia/cuda:latest,docker.io/centos:latest

c) ジョブが完了したらコンテナを削除してくれる

若干地味なメリットかもしれませんし、--rmを付けるのを忘れなければいいという話でもあるかもしれませんが。 ジョブが完了した時だけでなく、何らかの原因でUGEの実行デーモンが落ちてしまったようなケースでも、 sge_container_shepherdというプロセスが残っており、次回デーモン起動時にフォローして削除してくれます。

ジョブの例

例1) centos:latestのコンテナを使って日時とホスト名を返すだけのジョブ

  • ジョブスクリプト
#!/bin/bash

#$ -N DOCKER_DEMO
#$ -l docker
#$ -l docker_images="*centos:latest*"

echo  =="DATE"
date
echo
echo  =="HOSTNAME"
hostname
  • UGEの結果ファイル
==DATE
Mon Oct  9 13:33:04 UTC 2017

==HOSTNAME
2240452d3be2

例2) UGEの-xdオプションを使ってdockerのオプションをUGEに渡すジョブ

  • ジョブスクリプト
#!/bin/bash

#$ -N DOCKER_DEMO
#$ -l docker
#$ -l docker_images="*centos:latest*"
#$ -xd "-v /home:/home" 
#$ -cwd

echo  =="DATE"
date
echo
echo  =="HOSTNAME"
hostname
echo
echo =="HOME"
ls -l /home
  • UGEの結果ファイル : "-v /home:/home"が正しく渡されてホスト機側でls -l /home/と実行したのと同じ出力が得られています。
==DATE
Mon Oct  9 13:49:58 UTC 2017

==HOSTNAME
a2db6ea920ac

==HOME
total 0
drwx------ 4 1000 1000 153 Oct  9 13:47 beowulf
drwx------ 2 1001 1001  62 Oct  9 13:46 takeru
drwx------ 2 1002 1002  62 Oct  9 13:46 voyager

例3) 保持していないコンテナイメージを使って実行するジョブ

  • ジョブスクリプト (ubuntu:latestはどのホストにも無い状態です)
$ qsub -cwd -l docker,docker_images="*ubuntu:latest*" -soft demo.sh
あるいは
$ qsub -b y -cwd -l docker,docker_images="*ubuntu:latest*" -soft cat /etc/os-release
本来なら上記は全てスクリプトに書いた上で $ qsub [スクリプト] としたいところなのですが、 そのように実行すると -softオプションが正しく伝わらずにpullを試みてくれませんので 上記のように実行する必要があります。(調査中)

注意点

dockerのバージョン依存

CentOSでdockerを使う場合、現在は主に3つの選択肢があります。(docker-eeは省略) - docker-ce(docker-ce.repo) : 10/9現在最新 v17.09 - docker-latest(centos repo) : 10/9現在最新 1.13.1-23.git28ae36d.el7.centos.x86_64 - docker(centos repo) : 10/9現在最新 1.12.6-55.gitc4618fb.el7.centos.x86_64 docker-latestとdockerの違いについてはこちらを >> http://rhelblog.redhat.com/2016/10/31/understanding-docker-latest-package/
ただ、docker-ceだとdockerのサービスが動作してる状態でも、hl:docker=1にならず動作しません。 パッケージ名がdocker-engineだった頃からマイナーバージョンの違いによってhl:dockerが0になったり1になったりするので 実際には使用するバージョンで試してみるしかないというところですが、少なくともdocker-ceは動かないと考えていいと思います。
centosのrepositoryから取得するdocker, docker-latestについてはいずれもhl:docker=1になって動作することを確認しています。

まとめ

上記のメリットのところでも挙げた通り、dockerの有無、dockerコンテナイメージの有無をUGE側で管理してくれるため ユーザーがあまり意識をしなくても適切なノードにジョブを割り振ってくれるということが大きいのではないかと思います。 全ての計算ノードが同じハードウェア/ソフトウェア仕様で、保持しているコンテナも同じというような環境であれば ジョブスケジューラー側での対応ということに特別な価値は無いのかもしれませんが、 ハードウェア構成の異なる機器でクラスタが構成されていたり、保持しているコンテナイメージもホスト毎に異なっている といったケースでは、ジョブスケジューラーがDockerに対応しているということのメリットが享受できるはずです。