目次
こんにちは。grasys清水です。
最近Kubernetes(:以下k8s)が何かと話題ですよね。その熱の煽りを受けてか、業務でGKEを触る機会がだんだんと増えています。
ただ、今回はk8sに関する記事ではありません。
今回は選択肢を増やす、という意味で似たようなプロダクトHashiCorp社が提供する Nomad をご紹介します。
k8sを使うと何かと考えなくちゃいけないことが増えたり、運用が複雑に感じることもしばしばあって、『あれ、結果トータルとしてどれほどの恩恵を受けられているのか』と疑問に思った方もいるのではないでしょうか?
k8sのボリュームがいろんな意味で大きく、それを負担に感じてる方にはNomadは良いソリューションの一つかもしれません。
まだまだ人気的なものでいえば下火なのか、あまり日本語の記事が見つかりません。そこで、今回の記事を 第一回 として、何回かに分けてNomadの機能・使い方について色々ご紹介したいと思います。k8sとは別の選択肢が欲しい、と言う方々の参考になればと思います。
Nomad とはなんぞや
一言で言うと オーケストレーター です。
通常の(またはバッチ)アプリケーションに加え、コンテナ化されたアプリのデプロイをマネージングできます。
ただ、k8sのようなネットワークや権限の制御機能など高尚な機能はありません。薄〜くk8sを使うイメージです。
その分、複雑に抽象化された概念が少なく、オペレーションもシンプル。
使いどころを模索するアプローチとしては
- わざわざk8sを使うほどでもないけど、docker imageを使いたい
- ちょっとした条件をつけてバッチを走らせたい(空いたリソースで一つだけバッチを走らせたいなど)
- クロスプラットフォームを実現したい
といった感じでしょうか。
また、同社のプロダクトでもある Consul や Vault と親和性が高く、うまく機能を組み合わせることで実現できる事の幅がぐんと広がるのも魅力の一つです。
第一回である今回の記事では、Nomadの基本的な構築方法、使い方、概念等をご紹介します。
極力、細かな解説は後回し(後々の記事に)します。
インストール
環境
インスタンスは合計3台使います。今回は検証用なので下記のスペック↓です。
name: nomad-cluster01/02/03
OS: CentOS 7.6
machine-type: n1-standard-1(vCPU *1, 3.75GB mem)
インストール手順
今回はversion 0.9.1を入れます。
下準備はサイトの デプロイメントガイド に従って入れていきます。
サイトのダウンロードページから持ってきて解凍します。
mkdir -p /usr/lcoal/src
cd /usr/local/src
curl -O https://releases.hashicorp.com/nomad/0.9.1/nomad_0.9.1_linux_amd64.zip
unzip nomad_0.9.1_linux_amd64.zip
mv nomad /usr/local/bin/
できたらタブ補完を有効にします。
nomad -autocomplete-install
complete -C /usr/local/bin/nomad nomad
確認
$ nomad -v
Nomad v0.9.1-dev (8d48b77bca93a4908c83cd15519b74718d797157)
下準備〜起動まで
ひとまず、nomad agentを一通り動かせるところまでやってみましょう。
作業するのは一台のインスタンスだけです。
nomad agentの挙動にはserver
モードと client
モードの2種類があります。まずは動作確認のため、1台のサーバ上にそれぞれserverとclientを設置します。各モードついては後ほど解説します。
nomadのデータディレクトリを作成します。
$ sudo mkdir -p /opt/nomad
次は Unit を作成します。
$ cat << EOF > /usr/local/etc/systemd/nomad.service
[Unit]
Description=Nomad
Documentation=https://nomadproject.io/docs/
Wants=network-online.target
After=network-online.target
[Service]
ExecReload=/bin/kill -HUP $MAINPID
ExecStart=/usr/local/bin/nomad agent -config /etc/nomad.d
KillMode=process
KillSignal=SIGINT
LimitNOFILE=infinity
LimitNPROC=infinity
Restart=on-failure
RestartSec=2
StartLimitBurst=3
StartLimitIntervalSec=10
TasksMax=infinity
[Install]
WantedBy=multi-user.target
EOF
$ systemctl daemon-reload
そこからどんどん必要なconfigurationファイルを置いていきます。
↑上記のUnitの設定のままであれば /etc/nomad.d
の下にファイルを置けば、すべて読み込んでくれます。
設定ファイルの作成
confを置くディレクトリを作成
$ sudo mkdir --parents /etc/nomad.d
$ sudo chmod 700 /etc/nomad.d
まずは、serverとclientに共通するnomadの基本になるconfを作成します。dataディレクトリを変えた場合は、パスを変更しておきましょう。
また、dataディレクトリには シムリンク を使わないようにしてください。
※ ちなみに、 log_json = true でjson形式のログを吐くようにしてます。
$ cat << EOF > /etc/nomad.d/nomad.hcl
datacenter = "dc1"
data_dir = "/opt/nomad"
log_json = true
EOF
シムリンクだとデプロイの際、エラーになってしまいす。
2019-05-12T01:49:10Z Driver Failure failed to launch command with executor: rpc error: code = Unknown desc = failed to create container(2e7fee0b_7008_e4c1_d0b4_a5d59c9c8741): /usr/local/var/nomad/alloc/9ae5113a-02e7-d8d1-e8de-ac84eae78b77/server is not an absolute path or is a symlink
次は、 server
の挙動を設定するファイルを作成します。
server.hcl
を同じディレクトリの下に置きます。
cat << EOF > /etc/nomad.d/server.hcl
server {
enabled = true
bootstrap_expect = 1
}
EOF
最後に、 client
の設定ファイルを作成します。
client.hcl
を同様に。
cat << EOF > /etc/nomad.d/client.hcl
client {
enabled = true
}
EOF
最初の設定はシンプルですね。
起動
では起動してみましょう。
sudo systemctl enable nomad
sudo systemctl start nomad
sudo systemctl status nomad
どうでしょう?うまく起動したでしょうか?
ServerとClient
ここで一旦、ServerとClientの解説をします。
Server
Nomadに置ける Server とは、クラスタ全体のマネージングを担っている機能です。クラスタ全体の状態を記憶し、スケジューリングの意思決定を行います。
Serverは投票によってNomad leader serverを決める必要があるため、クラスタ全体で3台ないし5台
使用することが推奨されています。また、スペックは 4〜8core + 16〜32GB of memory + 40-80 GB fast diskが推奨されています。(今回は検証なので1coreで作っていますが)
先ほど、ファイルを作成する際は bootstrap_expect=1
に設定していましたが、ひとまず、単体でserverモードを動かすために変更しているものです。クラスタリングする際は、serverの台数に合わせてパラメータを変更してください。
# 3台のserverを動かす時
server {
enabled = true
bootstrap_expect = 3
}
Client
ServerからJobのリクエストを受け処理を行う実行部隊です。常に「俺は生きてるよ〜」とServerに対して自身の状態を報告しています。
CPUやmemoryなどの色々な閾値を設定することができ、その値を元にnodeの実行が完了した不要なjobなどを削除(garbage collection)してくれたりします。
Serverに比べると通信量が少ないのでagentとしては軽量です。
クラスタリング
Server クラスタリング
起動までうまくいけば、次は マニュアルでクラスタリング の設定をしてみましょう。
先ほど使用したインスタンスとは別に二台のインスタンスにnomadをインストールしておきます。
で、全台の server.hcl
に下記のパラメータを追加してください。
bootstrap_expect = 3 # 1→3に書き換える
server_join {
retry_join = ["<nomad-cluster01のIP>:4648"]
}
そしたら nomad-cluster01 から順に起動していきます!
全台起動が完了したら、ステータスを確認してみましょう。この場合は nomad server members
で確認するのが便利です。
$ nomad server members
Name Address Port Status Leader Protocol Build Datacenter Region
nomad-cluster01.global 10.140.0.31 4648 alive true 2 0.9.1 dc1 global
nomad-cluster02.global 10.140.0.29 4648 alive false 2 0.9.1 dc1 global
nomad-cluster03.global 10.140.0.30 4648 alive false 2 0.9.1 dc1 global
全台で試してみてください。
互いに認識できているのがわかると思います。
ちょっとこれだけだと味気ないので、leaderである nomad-cluster01 のnomad agentプロセスを落としてみます。
$ systemctl stop nomad
ではもう一度確認。
$ nomad server members
Name Address Port Status Leader Protocol Build Datacenter Region
nomad-cluster01.global 10.140.0.31 4648 failed false 2 0.9.1 dc1 global
nomad-cluster02.global 10.140.0.29 4648 alive false 2 0.9.1 dc1 global
nomad-cluster03.global 10.140.0.30 4648 alive true 2 0.9.1 dc1 global
おお、ちゃんとleaderが変わってますね。
プロセスをもう一度起動みたり、余裕のある方はパラメータをいじって試してみてください。
色々試したところ、 初回起動
さえうまくいけば、プロセスが立ち上がるたびに自動でクラスタへrejoinしてくれるようです。(初回起動の時点で retry_join = [IP]
のnomad agentが起動していないとクラスタリングされません)
ちなみに、下記のコマンドでもクラスタリング可能です。
$ nomad server join <known-address>
Client の認識
Serverのクラスタリングが終われば、 clientを認識させなければいけません。
要領は同じで、 client.hcl
に記載するかクライアントがあるサーバで nomad node config -update-servers
コマンドを使うだけ。
:configファイルの場合
client {
enabled = true
servers = ["<known-address>:4647"]
}
:コマンドの場合
$ nomad node config -update-servers <IP>:4647
もし、この時点で認識できていない場合は、 nomad node status
をしても何も起こりません。
$ nomad node status
$
ちゃんと認識できていれば下記のように出るはずです。
$ nomad node status
ID DC Name Class Drain Eligibility Status
48c8da6b dc1 nomad-cluster03 <none> false eligible ready
5dcf2b23 dc1 nomad-cluster02 <none> false eligible ready
74e2e49c dc1 nomad-cluster01 <none> false eligible ready
Jobの実行
jobはClientにアプリケーションを実行させる機能のこと。
一連の流れ
Jobを実行させるための流れは下記です。
- job file を書く
- 登録されるJobの確認
- jobの登録
- 実行されたjobのステータス(またはlogの)確認
まずは
nodeのステータスを確認。ちゃんとServerから見えてますね。
nomad node status
ID DC Name Class Drain Eligibility Status
4eba7433 dc1 nomad-cluster01 <none> false eligible ready
119babd9 dc1 nomad-cluster02 <none> false eligible ready
8ce4c355 dc1 nomad-cluster03 <none> false eligible ready
あと、テストできるものであればなんでも良いのですが、goで書かれた http-echo をビルドしておきましょう。
ただテキストを返すシンプルなweb-serverです。
$ http-echo -listen=":5678" -text="hello world"
別のターミナルから
$ curl http://localhost:5678
hello world
1. job file を書く
jobのファイルを作ります。ファイル名は hey.nomad
です(なんでもかまいません)
# ↓ 任意のjob名
job "hello" {
datacenters = ["dc1"]
group "example" {
task "server" {
driver = "exec"
config {
command = "/usr/bin/http-echo"
args = [
"-listen", ":5678",
"-text", "hello world",
]
}
resources {
network {
mbits = 10
port "http" {
static = "5678"
}
}
}
}
}
}
~
まず、注目したいのが下記の部分。
これが、jobをCLI上で操作するのに頻出するIDになります。
job "hello" {
}
2. 登録されるJobの確認
fileができたらひとまず nomad job plan
をしてみましょう。
これから何が起こるのかを確認することができます。 Terraform を使った事のある方には既視感があるかもしれません。
$ nomad job plan hey.nomad
+ Job: "hello"
+ Task Group: "example" (1 create)
+ Task: "server" (forces create)
Scheduler dry-run:
- All tasks successfully allocated.
Job Modify Index: 0
To submit the job with version verification run:
nomad job run -check-index 0 hey.nomad
When running the job with the check-index flag, the job will only be run if the
server side version matches the job modify index returned. If the index has
changed, another user has modified the job and the plan's results are
potentially invalid.
3. jobの登録
次は nomad run
。これでデプロイを実行します。
$ nomad job run hey.nomad
==> Monitoring evaluation "4d230d5d"
Evaluation triggered by job "hello"
Allocation "20553d38" created: node "4eba7433", group "example"
Evaluation status changed: "pending" -> "complete"
==> Evaluation "4d230d5d" finished with status "complete"
ほうほう。 8ce4c355 のノードにあると出てきましたね。
ステータスを確認してみます。 コマンドは nomad job status
です。
$ nomad job status
ID Type Priority Status Submit Date
hello service 50 running 2019-05-12T01:42:24Z
さて、これはちゃんと動いてるんでしょうか?
デプロイされているはず nomad-cluster01(4eba7433) のインスタンスで curl http://localhost:5678
と打ってみましょう。 hello world と返ってくればOKです。
4. 実行されたjobのステータス(またはlogの)確認
jobのステータスがどうなっているのか詳しく確認したいですね。
詳しく見たいときは nomad job status <job-name>
です。
さっきのjobファイルでつけたjobの名前は hello です。
$ nomad job status hello
ID = hello
Name = hello
Submit Date = 2019-05-12T02:50:35Z
Type = service
Priority = 50
Datacenters = dc1
Status = running
Periodic = false
Parameterized = false
Summary
Task Group Queued Starting Running Failed Complete Lost
example 0 0 1 1 0 0
Allocations
ID Node ID Task Group Version Desired Status Created Modified
5b5c529f 4eba7433 example 0 run running 1h41m ago 1h34m ago
いいですね。動いてくれていそうです。
Allocations とはclientノードとjobのtask間のマッピングされた情報のこと。直訳すると”割り当て”。
また、nomadのjobにおける概念の中で最も小さい単位が task にあたる。
allocationsの詳しい情報を見ることでtaskのより細かな状態を知ることができます。コマンドは、 nomad alloc status <Allocation ID>
です。
$ nomad alloc status 5b5c529f
ID = 5b5c529f
Eval ID = 601098bd
Name = hello.example[0]
Node ID = 4eba7433
Job ID = hello
Job Version = 0
Client Status = running
Client Description = Tasks are running
Desired Status = run
Desired Description = <none>
Created = 1h56m ago
Modified = 1h48m ago
Task "server" is "running"
Task Resources
CPU Memory Disk Addresses
4/100 MHz 1.9 MiB/300 MiB 300 MiB http: 10.140.0.31:5678
Task Events:
Started At = 2019-05-12T03:04:43Z
Finished At = N/A
Total Restarts = 0
Last Restart = N/A
Recent Events:
Time Type Description
2019-05-12T03:04:43Z Started Task started by client
2019-05-12T02:57:28Z Task Setup Building Task Directory
2019-05-12T02:57:28Z Received Task received by client
ちゃんと動いてくれていそうです。
また、ログも確認することができます。 nomad alloc logs <Allocation ID>
でログを確認できます。
$ nomad alloc logs 5b5c529f-501e-11aa-bfb1-d3b7fb7ce3c5
2019/05/12 04:35:51 localhost:5678 [::1]:36054 "GET / HTTP/1.1" 200 12 "curl/7.29.0" 230.717µs
2019/05/12 05:01:41 localhost:5678 [::1]:36682 "GET / HTTP/1.1" 200 12 "curl/7.29.0" 287.317µs
jobの停止
taskの削除は nomad job stop <job ID>
でできます。
$ nomad job stop hello
==> Monitoring evaluation "0e4d5128"
Evaluation triggered by job "hello"
Evaluation status changed: "pending" -> "complete"
==> Evaluation "0e4d5128" finished with status "complete"
さて、もう一回 job statusします。
$ nomad job status
ID Type Priority Status Submit Date
hello service 50 dead (stopped) 2019-05-12T02:50:35Z
ステータスはstoppedになっていますね。では削除してみます。
nomadはHTTP APIを使うことができるので下記のpathへリクエストを投げます。
$ curl -X PUT http://localhost:4646/v1/system/gc
再度確認します
$ nomad job status
No running jobs
綺麗になくなってますね。
今日はここまで。
いかがでしたでしょうか?
今回の記事は入門編ということでチュートリアル的な内容ではありますが、ざっくりと概念についてはイメージできたのではないでしょうか。
次回は consul + nomd
による自動クラスタリング、 Dockerプラグイン
を使ったアプリケーションのデプロイなどより実践的な構築を記事にしたいと思います。
ではでは、また次回。
株式会社grasys(グラシス)は、技術が好きで一緒に夢中になれる仲間を募集しています。
grasysは、大規模・高負荷・高集積・高密度なシステムを多く扱っているITインフラの会社です。Google Cloud (GCP)、Amazon Web Services (AWS)、Microsoft Azureの最先端技術を活用してクラウドインフラやデータ分析基盤など、ITシステムの重要な基盤を設計・構築し、改善を続けながら運用しています。
お客様の課題解決をしながら技術を広げたい方、攻めのインフラ技術を習得したい方、とことん技術を追求したい方にとって素晴らしい環境が、grasysにはあります。
お気軽にご連絡ください。