Dockerコンテナのオーケストレーション機能を実現するOpenStack Magnumを触ってみた
Dockerは、多くのITエンジニアに注目され、継続して成長している技術である。DockerはlibcontainerというLinuxカーネルのAPIを呼び出すためのドライバーと、OSごとに対応したファイルシステム(aufs、device-mapper等)によって、コンテナという仮想環境を構築する。詳細は、以前の連載「Dockerを知る -周辺ツールと業界動向-」にて解説されている。Dockerが注目を集める理由は、このコンテナという仮想環境が、従来のハイパーバイザ型の仮想環境と比べて軽量でオーバヘッドが少ないことや、実行環境を素早く提供できるという点にある。また最近では、Dockerを管理するための周辺技術も注目されており、代表的なものとしてGoogleがOSSとして公開しているKubernetesやDocker社公式のDocker Swarmなどが挙げられる。さらに、近年話題となっているクラウド基盤ソフトウェアのOpenStackにも、Magnumという機能が追加された。MagnumはOpenStack Containers Teamによって開発されたもので、Dockerコンテナを扱うための機能である。Magnumを使うことによって、コンテナクラスタのデプロイおよび制御を、OpenStack上で行えるようになる。
そこで本記事では、実際にOpenStack Magnumの環境構築およびコンテナの制御を行ってみる。
OpenStack Magnumの仕組み
図1に、OpenStack Magnum公式の構成図を示す。
Magnumは、既存のAPIであるNova、Neutron、Glance、Cinderなどよりも上位のレイヤーに存在する。Magnum APIのBayは、OpenStackのオーケストレーション機能であるHeatによりNovaやNeutron、Glance、Cinderを操作して、コンテナをクラスタリングするための環境を構築し提供する機能などを備える。環境が提供された後はMagnum APIのNode、Pod、Service、RC等を使ってコンテナを制御できる。また、Magnumによるコンテナのオーケストレーション処理は、既存のオーケストレーションツールであるKubernetesやDocker Swarmを、OpenStackに取り込むことで実現している。
環境構築
今回はDevStackを使用して、OpenStack MagnumをUbuntu 14.04上に構築する。
まずは、構築に必要となるパッケージをインストールする。
$ sudo apt-get update $ sudo apt-get install -y python-dev libssl-dev libxml2-dev \ libmysqlclient-dev libxslt-dev libpq-dev git \ libffi-dev gettext build-essential
次に、OpenStackを構築するためのツールであるDevStackを取得する。DevStackは開発者向けのOpenStack導入ツールであり、今後OpenStackのコンポーネントに対して更新があった場合は、今回の手順通りに動作しない可能性がある。ただし、後述のlocal.confでバージョンは指定できる。
$ sudo mkdir -p /opt/stack $ sudo chown $USER /opt/stack $ git clone https://git.openstack.org/openstack-dev/devstack /opt/stack/devstack
DevStackは、local.confというファイルにOpenStack構築時の設定を記述する。<password>となっている部分には、任意のパスワード設定をしている。
$ cat > /opt/stack/devstack/local.conf << END DATABASE_PASSWORD=<password> RABBIT_PASSWORD=<password> SERVICE_TOKEN=<password> SERVICE_PASSWORD=<password> ADMIN_PASSWORD=<password> # nicに応じて変更 PUBLIC_INTERFACE=eth1 # Magnumのリポジトリ enable_plugin magnum https://git.openstack.org/openstack/magnum VOLUME_BACKING_FILE_SIZE=20G END
DevStackを実行する。環境によって異なるが、今回の環境では30分程度で構築が完了した。
$ cd /opt/stack/devstack $ ./stack.sh
認証のための変数を読み込む。引数にユーザ名およびテナント名を指定するが、今回は両方ともadminとする。
$ source /opt/stack/devstack/openrc admin admin
OpenStackの構築および認証が問題なく行えていることを確認するためにサンプルの仮想マシンイメージを表示させる。
$ glance image-list +--------------------------------------+---------------------------------+-------------+------------------+-----------+--------+ | ID | Name | Disk Format | Container Format | Size | Status | +--------------------------------------+---------------------------------+-------------+------------------+-----------+--------+ | 7f5b6a15-f2fd-4552-aec5-952c6f6d4bc7 | cirros-0.3.4-x86_64-uec | ami | ami | 25165824 | active | | bd3c0f92-669a-4390-a97d-b3e0a2043362 | cirros-0.3.4-x86_64-uec-kernel | aki | aki | 4979632 | active | | 843ce0f7-ae51-4db3-8e74-bcb860d06c55 | cirros-0.3.4-x86_64-uec-ramdisk | ari | ari | 3740163 | active | | 02c312e3-2d30-43fd-ab2d-1d25622c0eaa | fedora-21-atomic-5 | qcow2 | bare | 770179072 | active | +--------------------------------------+---------------------------------+-------------+------------------+-----------+--------+
このようにイメージが表示されていれば問題はない。
Bayの作成
ここから実際にMagnumを使用していく。BaymodelおよびBayのイメージ図を以下に示す。
図2に記載されているBayという枠は、Magnumで構築するクラスタの単位であり、Baymodelという「ひな形」をもとに作成される。Baymodelには構築するノードのOSやネットワーク、使用するクラウドオーケストレーションエンジンなどを指定する。Bayを作成すると、Baymodelをもとにインスタンス、ネットワーク、オーケストレーションエンジンを動かすための環境などを自動的に設定、構築してくれる。Bayという単位で管理することによって、クラスタごとの削除、ノード数の変更を容易に行うことができる。今回はKubernetesのエンジンを使用するため、作成されるインスタンスは、コンテナを配置する場所であるMinionとAPIを実行してMinionに対してコンテナの制御などをさせるMasterである。
まず、Baymodelで使用する鍵を作成する。
$ test -f ~/.ssh/id_rsa.pub || ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa
次に、novaに鍵を登録する。
$ nova keypair-add --pub-key ~/.ssh/id_rsa.pub testkey
鍵の登録が完了したら、Baymodelを作成する。
$ magnum baymodel-create --name k8sbaymodel \ --image-id fedora-21-atomic-5 \ --keypair-id testkey \ --external-network-id public \ --dns-nameserver 8.8.8.8 \ --flavor-id m1.small \ --docker-volume-size 5 \ --network-driver flannel \ --coe kubernetes
baymodel-createコマンドで使用したオプションの一覧を、以下の表にまとめた。
オプション名 | 説明 |
---|---|
name | Baymodelの名前を指定する |
image-id | 作成するノードのマシンイメージを指定する。今回はデフォルトで入っているFedoraのイメージを使用する |
keypair-id | ノードの認証に使用する鍵を指定する。今回はひとつ前の手順で作成したtestkeyを使用する |
external-network-id | 外部ネットワークを指定する。今回はデフォルトで入っているpublicを使用する |
dns-namesever | DNSサーバを指定する |
flavor-id | 作成するノードの構成を指定する。今回はデフォルトで入っているm1.smallを使用する |
docker-volume-size | Dockerで使用するボリュームサイズを指定する |
network-driver | コンテナ間で通信するためのネットワークドライバーを指定する |
coe | coeはCloud Orchestration Engineの略で、使用するエンジンを指定する。今回はkubernetesを使用する(他に指定できるのは、現時点ではswarmとmesos) |
このBaymodelをもとに、Bayを作成する。今回使用した環境では、15分程度でBayの作成が完了した。
$ magnum bay-create --name k8sbay --baymodel k8sbaymodel --node-count 1
bay-createコマンドで使用したオプションの一覧を、以下の表にまとめた。
オプション名 | 説明 |
---|---|
name | Bayの名前を指定する |
baymodel | Bayの作成時に使用するBaymodelを指定する。今回は作成したk8sbaymodelを使用する |
node | 作成するノード数を指定 |
watchコマンドで5秒ごとにコマンドを実行し、statusがCREATE_COMPLETEに変わったことを確認する。
$ watch -n 5 magnum bay-list k8sbay +--------------------------------------+---------+------------+-----------------+ | uuid | name | node_count | status | +--------------------------------------+---------+------------+-----------------+ | 9dccb1e6-02dc-4e2b-b897-10656c5339ce | k8sbay | 1 | CREATE_COMPLETE | +--------------------------------------+---------+------------+-----------------+
次にノード数を増やしておく。node_countオプションで、ノードの数を指定する。
$ magnum bay-update k8sbay replace node_count=2
statusがUPDATE_PROGRESSからUPDATE_COMPLETEになり、node_countが2になっていることを確認する。
$ magnum bay-list k8sbay +--------------------------------------+---------+------------+-----------------+ | uuid | name | node_count | status | +--------------------------------------+---------+------------+-----------------+ | 9dccb1e6-02dc-4e2b-b897-10656c5339ce | k8sbay | 2 | UPDATE_COMPLETE | +--------------------------------------+---------+------------+-----------------+
コンテナの作成
今回はApache SparkをBay上にデプロイする。Apache SparkはUC BerkeleyのAMPLabによって開発された、高速でインタラクティブな言語統合クラスタコンピューティング基盤である。今回作成するクラスタの構成図を図3に示す。
作成するコンテナは、以下の4つである。
spark-master | Sparkのマスターノードが入っているコンテナ |
---|---|
spark-worker×2 | Sparkのワーカノード(スレイブノード)が入っているコンテナ |
spark-driver | Sparkアプリケーションを起動するためのdriverが入っているコンテナ |
今回はKubernetesをエンジンとして使用しているため、コンテナはPodというものに内包して作成される。Podとは、複数のコンテナの集まりを示した単位である。今回の場合は一つのPodに対して一つのコンテナとしているが、本来は複数のコンテナをまとめることができる。また、Serviceとしてspark-master-serviceを登録する。ServiceはL3プロキシのような、ネットワークをつかさどる役割を持つ。また設定されたPodに対して、ラウンドロビンのアクセス分配が可能である。今回の作成例では、Podの数が一つしかないspark-masterがServiceに設定されているため、アクセス分配は発生しない。Kubernetesに関しては、以前の連載記事「注目すべきDockerの周辺技術 PanamaxとKubernetes」で詳しく解説されているので、参考にしてほしい。
Sparkのexampleを使用するために、Kubernetesをダウンロードして解凍する。
$ cd $ wget https://github.com/kubernetes/kubernetes/releases/download/v1.1.0-alpha.1/kubernetes.tar.gz $ tar -xvzf kubernetes.tar.gz
spark-masterのPodを作成する。
$ cd kubernetes/examples/spark $ magnum pod-create --manifest ./spark-master.json k8sbay
Serviceを作成する。
$ magnum coe-service-create --manifest ./spark-master-service.json --bay k8sbay
manifestファイルの記述を変更して、Replication Controllerを作成する。今回は、ノードの数に合わせてreplicasの数を2に変更する。Replication Controllerは対象のPodをreplicasの数になるように管理してくれる。管理対象のPodはspark-workerとしている。今回はreplicasの数を2としたので、何らかの要因でPodの数が増減した場合はPodの数が2になるように調整される。
$ sed -i 's/(\"replicas\": )3/2/' spark-worker-controller.json $ magnum rc-create --manifest ./spark-worker-controller.json --bay k8sbay
Sparkの動作確認
まず、作成したBayを確認する。
$ magnum bay-show k8sbay +--------------------+------------------------------------------------------------+ | Property | Value | +--------------------+------------------------------------------------------------+ | status | UPDATE_COMPLETE | | uuid | c1a2ee79-adc7-425d-ad62-906377b4ee89 | | status_reason | Stack UPDATE completed successfully | | created_at | 2015-09-28T07:40:25+00:00 | | updated_at | 2015-09-28T07:52:19+00:00 | | bay_create_timeout | 0 | | api_address | 172.24.4.4:8080 | | baymodel_id | b1496fcc-05cc-4ca7-b471-dd806e598897 | | node_count | 2 | | node_addresses | [u'172.24.4.6', u'172.24.4.7'] | | master_count | 1 | | discovery_url | https://discovery.etcd.io/11a1b540f86420e7f3369afc36a02e23 | | name | k8sbay | +--------------------+------------------------------------------------------------+
今回はノードが2つあり、作成したコンテナはKubernetesによって、どちらかのノードに割り当てられている。まず、node_addressesに書かれている2つのIPアドレスに対して接続を行い、spark-driverがどちらのノードに割り当てられているかを確認する。docker psコマンドにおけるIMAGEの項目に「gcr.io/google_containers/spark-driver」と記載されているものが、spark-driverのコンテナである。
まず、一方のノードをIPアドレスで指定して、sshでログインする。
$ ssh minion@172.24.4.6
ノード内のコンテナを確認する。
$ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STA 90b83253cf33 gcr.io/google_containers/spark-worker:1.4.0_v1 "/start.sh" 2 minutes ago Up er-controller-gv0nt_default_48378678-7154-11e5-be23-fa163ed643ba_c71039c7 bdf6adb9bf6d gcr.io/google_containers/pause:0.8.0 "/pause" 2 minutes ago Up ller-gv0nt_default_48378678-7154-11e5-be23-fa163ed643ba_d1ffafea b90ade19891a gcr.io/google_containers/spark-master:1.4.0_v1 "/start.sh" 29 minutes ago Up er_default_2a982590-7150-11e5-be23-fa163ed643ba_ac8bfd61 71e8827bb519 gcr.io/google_containers/pause:0.8.0 "/pause" 31 minutes ago Up t_2a982590-7150-11e5-be23-fa163ed643ba_cc982738
spark-driverがノードに存在しなかったらノードから抜ける。
$ exit
続いて、もう一つのノードも確認する。
$ ssh minion@172.24.4.7 $ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STA 2dc1adbe3855 gcr.io/google_containers/spark-driver:1.4.0_v1 "/start.sh" 2 minutes ago Up er_default_674d685b-7154-11e5-be23-fa163ed643ba_92f6e3d1 c3259cc5efc8 gcr.io/google_containers/pause:0.8.0 "/pause" 2 minutes ago Up _674d685b-7154-11e5-be23-fa163ed643ba_c45dd5f8 952e8851a0d9 gcr.io/google_containers/spark-worker:1.4.0_v1 "/start.sh" 3 minutes ago Up er-controller-xnyg2_default_4837549c-7154-11e5-be23-fa163ed643ba_2ea06215 e4fe6ca02616 gcr.io/google_containers/pause:0.8.0 "/pause" 3 minutes ago Up ller-xnyg2_default_4837549c-7154-11e5-be23-fa163ed643ba_09e3d738
IMAGEの項目に「gcr.io/google_containers/spark-driver」というimageがあることを確認する。spark-driverが存在している場合は、引き続き作業を行うので、ログインしたままにしておく。
まず、spark-driverのコンテナに入る。-itの後にはspark-driverのCONTAINER IDを指定する。
$ sudo docker exec -it 2dc1adbe3855 bash root@spark-driver:/#
次に、pysparkを起動する。
root@spark-driver:/# pyspark Python 2.7.9 (default, Mar 1 2015, 12:57:24) [GCC 4.9.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. 15/10/13 02:49:17 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin Welcome to ____ __ / __/__ ___ _____/ /__ _\ \/ _ \/ _ `/ __/ '_/ /__ / .__/\_,_/_/ /_/\_\ version 1.4.0 /_/ Using Python version 2.7.9 (default, Mar 1 2015 12:57:24) SparkContext available as sc, HiveContext available as sqlContext.
以下のコードを実行して、Sparkのクラスタに所属しているspark-workerをリスト形式で表示する。
>>> import socket >>> sc.parallelize(range(1000)).map(lambda x:socket.gethostname()).distinct().collect() ['spark-worker-controller-gv0nt', 'spark-worker-controller-xnyg2']
このように2つのspark-workerコンテナがSparkのクラスタに所属していることが確認できた。
まとめ
今回は、OpenStack Magnumの環境構築およびコンテナの制御を行った。実際に触ってみて、いくつかメリットとして感じたことがある。
オーケストレーションツールの選択が可能
今回はKubernetesを使用したが、そのほかにもDocker SwarmやMesosなどにも対応している。今後は、Magnumで対応するオーケストレーションエンジンが、さらに増えることを期待したい。
オーケストレーションツールの導入が不要
Kubernetesのようなツールは、導入するだけでも多くの時間を必要とする可能性があるので、OpenStackの導入さえ乗り越えればツール導入の手間を省けるのはありがたいと感じる。
クラスタのテナント管理
MagnumでBayを作成する際は、OpenStackの認証機能であるKeystoneの認証を通して行う。Kubernetes単体ではクラスタに認証をかけることはできなかったが、Magnumで扱うクラスタはテナントごとに管理されているため、セキュアなものとなる。
今後、連携してほしい機能としては感じたのは、ネットワーク関連の機能である。現時点ではエンジンにKubernetesを指定した場合、ノード内およびノード間でコンテナに対して接続することはできるが、OpenStackの外からコンテナに対して接続することができない(現時点ではMagnumのプロジェクトにBlueprintsとして登録されている)。今後、この辺の問題をNeutronなどと連携して解決してほしいと思う。
Support the kubernetes service external-load-balancer feature
https://blueprints.launchpad.net/magnum/+spec/external-lb
OpenStack Magnumはまだまだ発展途上で、実用に供するためには、もう少し時間がかかると思われる。特に、Magnumの内部で動いているコンテナオーケストレーションツールの動作が不安定に感じられた。今後、Magnumに対する機能追加や内部で動作しているエンジンの動作が安定することで、Magnumが多くの人に使われ始めることを期待している。
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- Openstack Magnumの環境を構築する
- KubernetesのマニフェストをMagnumで実行する
- OpenStack Magnumとコンテナ
- Kubernetes環境の選択肢
- コンテナ連携が進むOpenStack
- コンテナは場所を選ばない!「オンプレ or クラウド×コンテナ」(後編)
- Kubernetes環境を構築して、実際にコンテナを動かしてみよう
- Open Infrastructure Summitで紹介されたCERNやAdobeの事例
- Oracle Cloud Hangout Cafe Season5 #3「Kubernetes のセキュリティ」(2022年3月9日開催)
- KubernetesのConfig&Storageリソース(その1)