LoginSignup
8
10

More than 5 years have passed since last update.

Apolloを使ってAWSにMesos+Marathon+Chronos環境を構築する

Last updated at Posted at 2015-09-27

Apollo

ApolloはMesosクラスタおよび関連のサービスをデプロイするためのツールです。

現在は、AWS, Digital Ocean, GCPに対応しています。OpenStackへの対応も予定されています。

関連のサービスとしては現在はChronos, Marathon等に対応しています。将来的にはKubernetesSparkにも対応していく計画のようです。

Apollo/roadmap.md at master · Capgemini/Apollo

様々なオープンソースのツールを使っているのが特徴です。以下のようなツールが使用されています。

AWSにMesosクラスタをデプロイする

AWSへのデプロイはVPCを使った方法と使わない方法の2種類が用意されていますが、今回は構成要素が少ないVPCを使わない方法で試してみます。

Apollo/aws-public.md at master · Capgemini/Apollo

AWS, Atlasアカウントの用意

  • AWSアカウント
    • AmazonEC2FullAccessポリシーを設定し、インスタンスやELBの操作ができるようにしておきます
  • Atlasアカウント
    • TerraformからAtlasに登録されたArtifactを使用するためにアカウントを作成しトークンを取得しておきます
      • Atlas by HashiCorp
      • AWSについてはTerraformの不具合のためAMIのIDをハードコーディングしています(2015/09/23時点)

Terraform, Pythonのインストール

  • Terraformは最新版をインストールしておきます
    • ドキュメントだと>=0.5.0になっていますが古いとバージョンチェックで弾かれる可能性があります
  • Python >=2.7.5をインストールしておきます

SSH鍵の作成

ドキュメントに従いSSH鍵を作成します。

Apollo/aws-public.md at master · Capgemini/Apollo

レポジトリのクローン

$ git clone https://github.com/Capgemini/apollo.git
$ cd apollo

Pythonパッケージのインストール

Ansibleなどクラスタ構築に使用されるPythonパッケージがインストールされます。

$ pip install -r requirements.txt

環境変数の設定

Apolloがクラスタ構築を行うための環境変数を設定します。
今回は以下の環境変数を設定します。AWS, Atlasの認証情報についてはお使いの環境にあわせて書き換えてください。

direnvなどを使うと何度もコマンドを実行しなくて済むので楽です。

export APOLLO_PROVIDER=aws-public
export TF_VAR_access_key=AWS_ACCESS_KEY
export TF_VAR_secret_key=AWS_SECRET_KEY
export TF_VAR_key_name="deployer"
export TF_VAR_key_file=AWS_SSH_KEY
export ATLAS_TOKEN=ATLAS_TOKEN

slaveの数、リージョン、インスタンスタイプ等も環境変数により設定することが可能です。
使用可能な環境変数については以下のファイルを参照してください。

bootstrap/aws-public/config-default.sh

クラスタの構築・削除

以下のコマンドでクラスタが構築・起動されます。
Terraform・AnsibleでAWSのリソースが作成・設定されていく様子をみることができます。

完了するとブラウザでConsulやMarathon等のウィンドウが開きます。

$ /bin/bash bootstrap/apollo-launch.sh

Ansibleの設定等で失敗してしまう場合は、pipやAnsibleのバージョンをあげるとうまくいくかもしれません。

クラスタの削除

クラスタが不要になったら以下のコマンドでクラスタが削除されます。

$ bash bootstrap/apollo-down.sh

Mesosクラスタを使ってみる

Ansible Dynamic Inventoryを使ってホストの情報を取得する

ApolloはTerraformで作成したインスタンスをAnsibleでデプロイする際に、Terraformで作成したインスタンスの情報を.tfstateファイルからDynamic Inventoryを使って取得しています。

Dynamic InventoryのスクリプトはCiscoCloud/terraform.py(をフォークしたCapgemini/terraform.py)を使用しています。

inventory/terraform.py にファイルがあるので、次のようにホストの情報を取得することができます。

$ ./inventory/terraform.py --list
$ ./inventory/terraform.py --host apollo-mesos-master-0

Anisbleを使った各ホスト上でのコマンド実行とロールによるホストのグルーピング

Dynamic Inventoryで取得したホスト情報を使って、各ホストでコマンドを実行することができます。

$ ansible -i inventory/terraform.py "*" -a hostname
apollo-mesos-slave-0 | success | rc=0 >>
ip-10-0-0-51

apollo-mesos-master-2 | success | rc=0 >>
ip-10-0-2-8

apollo-mesos-master-1 | success | rc=0 >>
ip-10-0-1-247

apollo-mesos-master-0 | success | rc=0 >>
ip-10-0-0-43

またロールごとにコマンドを実行することも可能です。
次のようにマスター、スレーブごとにコマンドを実行することができます。

$ ansible -i inventory mesos_masters -a hostname
apollo-mesos-master-1 | success | rc=0 >>
ip-10-0-1-247

apollo-mesos-master-0 | success | rc=0 >>
ip-10-0-0-43

apollo-mesos-master-2 | success | rc=0 >>
ip-10-0-2-8

$ ansible -i inventory mesos_slaves -a hostname
apollo-mesos-slave-0 | success | rc=0 >>
ip-10-0-0-51

ロールごとのコマンド実行を可能にするための設定はinventory/inventory に書かれています。このファイルの先頭部分をみると次のようになっておりロールでホストをグループ分けしていることがわかります。(詳しい書き方はドキュメントを参照)

inventory/inventory
[role=mesos_masters]

[role=mesos_slaves]

[mesos_masters:children]
role=mesos_masters

[mesos_slaves:children]
role=mesos_slaves

ロールはTerraformでaws_instanceを定義するときにtagで設定されており、terraform.pyがAnsibleのロールとして出力しています。

terraform/aws-public/mesos-masters.tf
  tags = {                                                                         
    Name = "apollo-mesos-master-${count.index}"                                    
    role = "mesos_masters"                                                         
  }  
terraform/aws-public/terraform.tfstate
                            "tags.#": "2",                                         
                            "tags.Name": "apollo-mesos-master-0",                  
                            "tags.role": "mesos_masters",
$ ./inventory/terraform.py --host apollo-mesos-master-0  | jq .role
"mesos_masters"

各ホストで起動しているDockerコンテナを調べる

ApolloはMesosクラスタのコンポーネントをホストに直接インストールするのではなくDockerコンテナで実行しています。

Ansibleでdocker psコマンドを実行することで、各ホストで起動しているコンテナを調べることができます。root権限が必要なので-b オプションを付ける必要があります。

$ ansible -b -i inventory "*" -a "docker ps" 
apollo-mesos-master-2 | success | rc=0 >>
CONTAINER ID        IMAGE                                           COMMAND                  CREATED             STATUS              PORTS                    NAMES
142da24684f5        mesosphere/marathon:v0.10.1                     "./bin/start --artifa"   26 minutes ago      Up 26 minutes       0.0.0.0:8080->8080/tcp   marathon
cd390ecd4616        mesosphere/mesos-master:0.23.0-1.0.ubuntu1404   "mesos-master --regis"   26 minutes ago      Up 26 minutes                                mesos-master
2922dffe01d9        mesosphere/mesos:0.23.0-1.0.ubuntu1404          "/usr/share/zookeeper"   26 minutes ago      Up 25 minutes                                zookeeper
b8f0bbe70dd1        google/cadvisor:latest                          "/usr/bin/cadvisor"      27 minutes ago      Up 27 minutes       0.0.0.0:8081->8080/tcp   cadvisor
88300025f4a5        gliderlabs/registrator:master                   "/bin/registrator -in"   27 minutes ago      Up 27 minutes                                registrator
82658e458a68        andyshinn/dnsmasq                               "dnsmasq -k -r /etc/d"   27 minutes ago      Up 27 minutes                                dnsmasq

apollo-mesos-slave-0 | success | rc=0 >>
CONTAINER ID        IMAGE                                          COMMAND                  CREATED             STATUS              PORTS                    NAMES
07910110c741        asteris/haproxy-consul                         "/launch.sh"             24 minutes ago      Up 24 minutes                                haproxy
fb02b0131fd1        mesosphere/mesos-slave:0.23.0-1.0.ubuntu1404   "mesos-slave"            25 minutes ago      Up 25 minutes                                mesos-slave
c09d8e11694b        google/cadvisor:latest                         "/usr/bin/cadvisor"      27 minutes ago      Up 27 minutes       0.0.0.0:8081->8080/tcp   cadvisor
27d3f8363a00        gliderlabs/registrator:master                  "/bin/registrator -in"   27 minutes ago      Up 27 minutes                                registrator
a1ed902190ca        andyshinn/dnsmasq                              "dnsmasq -k -r /etc/d"   27 minutes ago      Up 27 minutes                                dnsmasq

apollo-mesos-master-0 | success | rc=0 >>
CONTAINER ID        IMAGE                                           COMMAND                  CREATED             STATUS              PORTS                    NAMES
29b10699aaeb        mesosphere/marathon:v0.10.1                     "./bin/start --artifa"   26 minutes ago      Up 26 minutes       0.0.0.0:8080->8080/tcp   marathon
a58baf126727        mesosphere/mesos-master:0.23.0-1.0.ubuntu1404   "mesos-master --regis"   26 minutes ago      Up 26 minutes                                mesos-master
61f62dc803c5        mesosphere/mesos:0.23.0-1.0.ubuntu1404          "/usr/share/zookeeper"   26 minutes ago      Up 25 minutes                                zookeeper
7f8d7bb4d946        google/cadvisor:latest                          "/usr/bin/cadvisor"      27 minutes ago      Up 27 minutes       0.0.0.0:8081->8080/tcp   cadvisor
e711621714e9        gliderlabs/registrator:master                   "/bin/registrator -in"   27 minutes ago      Up 27 minutes                                registrator
69c456497a81        andyshinn/dnsmasq                               "dnsmasq -k -r /etc/d"   27 minutes ago      Up 27 minutes                                dnsmasq

apollo-mesos-master-1 | success | rc=0 >>
CONTAINER ID        IMAGE                                           COMMAND                  CREATED             STATUS              PORTS                    NAMES
b5962e6a9bb4        mesosphere/marathon:v0.10.1                     "./bin/start --artifa"   26 minutes ago      Up 26 minutes       0.0.0.0:8080->8080/tcp   marathon
765e78175de9        mesosphere/mesos-master:0.23.0-1.0.ubuntu1404   "mesos-master --regis"   26 minutes ago      Up 26 minutes                                mesos-master
225f9ee1ff8f        mesosphere/mesos:0.23.0-1.0.ubuntu1404          "/usr/share/zookeeper"   26 minutes ago      Up 25 minutes                                zookeeper
c9a7ef7a0b0c        google/cadvisor:latest                          "/usr/bin/cadvisor"      27 minutes ago      Up 27 minutes       0.0.0.0:8081->8080/tcp   cadvisor
75844473c11b        gliderlabs/registrator:master                   "/bin/registrator -in"   27 minutes ago      Up 27 minutes                                registrator
c332d88a7194        andyshinn/dnsmasq                               "dnsmasq -k -r /etc/d"   27 minutes ago      Up 27 minutes                                dnsmasq

mesos-executeを使ってコマンドを実行する

ここからはMesosphereのチュートリアルに従ってMesosを使ってみます。

Advanced Mesos Course

まずは、Exercise 3: Using Apache Mesosで説明されているmesos-execute コマンドを使ってコマンドを実行してみます。

まずapollo-mesos-master-0 にログインします。SSHに必要なIP、ユーザー名はterraform.pyで確認することができます。

$ ./inventory/terraform.py --host apollo-mesos-master-0 | jq ".ansible_ssh_user, .ansible_ssh_host, .ansible_ssh_port"

ホストにログインできたらdocker exec でmesos-masterコンテナに入ります。
コンテナに入るとプロンプトがubuntu@ip-10-0-0-43:~$ からroot@ip-10-0-0-43:/# のように変わります。

$ sudo docker exec -it mesos-master /bin/bash

コンテナ内で次のコマンドを実行するとMesosクラスタでsleepコマンドが実行されます。

$ MASTER=$(mesos-resolve `cat /etc/mesos/zk` 2>/dev/null)
$ mesos-execute --master=$MASTER --name="cluster-test" --command="sleep 40"

ブラウザでhttp://<apollo-mesos-master-0のIP>:5050 を開くと、実行したコマンドが表示されていることを確認することができます。

スクリーンショット 2015-09-23 15.32.57.png

Marathonを使ってコマンドを実行する

ブラウザでhttp://<apollo-mesos-master-0のIP>:8080 を開くとMarathonのGUIが開きます。

「+ New App」ボタンを押して、IDに「test」、Commandに「python -m SimpleHTTPServer」と入力し「+ Create」ボタンを押します。

スクリーンショット 2015-09-23 19.59.43.png

「/test」がRunningになっていることを確認します。

スクリーンショット 2015-09-23 20.02.56.png

MesosのGUIにも実行したコマンドが表示されています。

スクリーンショット 2015-09-23 20.08.49.png

この画面の右のほうに表示されているIPを調べてhttp://<表示されているIP>:8000 をブラウザで開くと以下のような画面が開きWebサーバーが起動していることを確認することができます。

スクリーンショット 2015-09-23 20.11.42.png

MarathonのGUIで「/test」を選択し、「Destroy App」を押していったんWebサーバーを削除します。

もう一度MaratonのGUIから「+ New App」を押して次のように入力します。
Commandに$PORT 変数を使うことで、ポートを衝突させることなくスケールさせることができるようになります。

スクリーンショット 2015-09-23 20.17.47.png

「/test」を選択し、「scale」ボタンを押して適当な数を指定するとアプリケーションがその数になることが確認できます。GUIのリンクをクリックすると実際にWebサーバーが起動していることが確認できます。

うまくいかない場合

Waitingから進まない場合

ステータスが「Waiting」のまま変わらなくなってしまう場合があるようです。(特に起動直後の/chronosとか)

スクリーンショット 2015-09-23 18.10.42.png

このときはmarathonコンテナを1つ再起動してみると処理が進むことがあります。
再起動が成功するのにしばらく待っても処理が進まない場合には別のホスト(apollo-mesos-master-1, apollo-mesos-master-2)のmarathonコンテナを再起動してみます。

$ ansible -b -i inventory "apollo-mesos-master-0" -a "docker restart marathon"

marathonコンテナの再起動自体に失敗してしまう場合はdockerを再起動してみます。

$ ansible -b -i inventory "apollo-mesos-master-0" -m service -a "name=docker state=restarted"

状態が「Waiting」から「Deploying」や「Running」になれば成功です。

Deployingから進まない場合

「Deploying」から「Running」に進まない場合は、slaveへのコンテナのデプロイに失敗している場合があります。

MesosのUIからstderrを確認したり、適当なコンテナをデプロイして正常に動いているか確認します。

$ ansible -b -i inventory "apollo-mesos-slave-0" -a "docker run --rm hello-world"

うまく動いていないようであればdockerを再起動してみます。

$ ansible -b -i inventory "apollo-mesos-slave-0" -m service -a "name=docker state=restarted"

Marathonを使ってDockerコンテナを動かす

MarathonからでDockerコンテナを動かすこともできます。

以下の内容でjsonファイルを作成します。

outyet.json
{
    "id": "outyet",
        "cpus": 0.2,
        "mem": 20.0,
        "instances": 1,
        "container": {
            "type": "DOCKER",
            "docker": {
                "image": "goexample/outyet",
                "network": "BRIDGE",
                "portMappings": [
                { 
                    "containerPort": 8080,
                    "hostPort": 0,
                    "servicePort": 0,
                    "protocol": "tcp"
                }
                ]
            }
        }
}

MarathonのAPIを使ってAppを作成します。

$ curl -X POST -HContent-Type:application/json -d @outyet.json http://<MarathonのIP>:8080/v2/apps

スクリーンショット 2015-09-27 11.18.19.png

ステータスがRunningにならない場合は、Marathonからのコマンド実行がうまくいかない場合 と同様の対処を試してみます。

Runningになっていれば/outyet をクリックして、表示されるリンク先にとぶと下図のような画面が表示されます。

スクリーンショット 2015-09-27 11.22.06.png

コマンドを実行した場合と同様に「scale」で数を増減させたりすることが可能です。

Chronosを使って定期的にコマンドを実行する

MarathonのGUIから「/chronos」のリンクを開き、表示されているIPアドレスのリンクをクリックすると下図のようなChronosのGUIが開きます。

スクリーンショット 2015-09-23 20.41.24.png

Chronosを使うとMesosクラスタ上で定期的にコマンドを実行することができます。

「+ New Job」を押してNAME, COMMAND, SCHEDULEを次のように入力し、1分ごとに日時を出力するジョブを作成します。

スクリーンショット 2015-09-23 20.43.00.png

「Create」を押すとジョブが作成されます。

スクリーンショット 2015-09-23 20.45.13.png

しばらくするとLASTがSUCCESSになります。

スクリーンショット 2015-09-23 20.46.27.png

MesosのGUIを確認みるとCompleted TasksにChronosにより実行されたタスクが表示されています。

スクリーンショット 2015-09-23 20.47.59.png

各タスクのSandbox>stdoutを確認するとコマンドの出力を確認することができます。

Registered executor on xxx.xxx.xxx.xxx
Starting task ct:1443008927000:0:date:
Forked command at 392
sh -c 'date'
Wed Sep 23 11:48:49 UTC 2015
Command exited with status 0 (pid: 392)

Chronosはあるジョブを他のジョブに依存して実行させることができます。

新規に先ほど作成した「date」に依存する「hello」というジョブを作成してみます。

スクリーンショット 2015-09-23 22.46.57.png

より詳細なChronosの使い方はドキュメントを参照してください。

トップで「Graph」ボタンを押すと依存関係のグラフを表示することができます。

スクリーンショット 2015-09-23 22.50.54.png

MesosのUIをみると1分ごとに「date」が実行され、直後に「hello」が実行されている様子がわかります。

スクリーンショット 2015-09-23 22.51.58.png

最後に

Mesosや関連ツールについてほとんど知識がなかったのですが、構築自体は割とスムーズにできました。使いたいツール群をまとめて試せるのはありがたいです。

構築にはそれほど苦労しませんでしたが、コマンド実行が失敗するなど使い方にはつまずくところが結構ありました。特にDockerコンテナの実行はかなり失敗する確率が高かったです。各ツールについて理解を含めて対応できるようにしていきたいです。Dockerコンテナを複数ホストで動かすだけなら、構築もコマンドの実行もDocker Swarmの方がずっと簡単だと思います。

参考

8
10
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
8
10