---
title: "~第一回~ NomadクラスタをGCEに構築する | grasys blog"
url: "https://blog.grasys.io/post/shimichan/nomad_cluster_on_gce"
description: "こんにちは。grasys清水です。 最近Kubernetes(:以下k8s)が何かと話題ですよね。その熱の煽りを受けてか、業務でGKEを触る機会がだんだんと増えています。 ただ、今回はk8sに関する記事ではありません。 今回は選択肢を増やす、という意味で似たようなプロダクトHashiCorp社が提供する Nomad…"
---

# ~第一回~ NomadクラスタをGCEに構築する

-   ![](/_astro/noicon.CTHOhNiB_1HMs6A.webp)[shimichan](/authors/shimichan/)
-   公開日：2019年5月12日
-   カテゴリー：[Tech](/categories/tech/)
-   タグ：[#Compute Engine](/tags/compute-engine/)[#nomad](/tags/nomad/)[#入門](/tags/入門/)

![~第一回~ NomadクラスタをGCEに構築する](/_astro/og-image.DDSiu2Ny_XHpDd.webp)

こんにちは。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を入れます。

下準備はサイトの [デプロイメントガイド](https://www.nomadproject.io/guides/operations/deployment-guide.html) に従って入れていきます。

サイトの[ダウンロードページ](https://www.nomadproject.io/downloads.html)から持ってきて解凍します。

Plain textcontent\_copy

```
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/
```

できたらタブ補完を有効にします。

Plain textcontent\_copy

```
nomad -autocomplete-install
complete -C /usr/local/bin/nomad nomad
```

確認

Plain textcontent\_copy

```
$ nomad -v
Nomad v0.9.1-dev (8d48b77bca93a4908c83cd15519b74718d797157)
```

## 下準備〜起動まで

ひとまず、nomad agentを一通り動かせるところまでやってみましょう。

作業するのは一台のインスタンスだけです。

nomad agentの挙動には`server` モードと `client` モードの2種類があります。まずは動作確認のため、1台のサーバ上にそれぞれserverとclientを設置します。各モードついては後ほど解説します。

nomadのデータディレクトリを作成します。

Plain textcontent\_copy

```
$ sudo mkdir -p /opt/nomad
```

次は _Unit_ を作成します。

Plain textcontent\_copy

```
$ 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を置くディレクトリを作成

Plain textcontent\_copy

```
$ sudo mkdir --parents /etc/nomad.d
$ sudo chmod 700 /etc/nomad.d
```

まずは、serverとclientに共通するnomadの基本になるconfを作成します。dataディレクトリを変えた場合は、パスを変更しておきましょう。

また、dataディレクトリには _シムリンク_ を使わないようにしてください。

※ ちなみに、 _log\_json = true_ でjson形式のログを吐くようにしてます。

Plain textcontent\_copy

```
$ cat << EOF > /etc/nomad.d/nomad.hcl
datacenter = "dc1"
data_dir = "/opt/nomad"
log_json = true
EOF
```

シムリンクだとデプロイの際、エラーになってしまいす。

Plain textcontent\_copy

```
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` を同じディレクトリの下に置きます。

Plain textcontent\_copy

```
cat << EOF > /etc/nomad.d/server.hcl
server {
  enabled = true
  bootstrap_expect = 1
}
EOF
```

最後に、 `client` の設定ファイルを作成します。

`client.hcl` を同様に。

Plain textcontent\_copy

```
cat << EOF > /etc/nomad.d/client.hcl
client {
  enabled = true
}
EOF
```

最初の設定はシンプルですね。

#### 起動

では起動してみましょう。

Plain textcontent\_copy

```
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の台数に合わせてパラメータを変更してください。

Plain textcontent\_copy

```
# 3台のserverを動かす時
server {
  enabled = true
  bootstrap_expect = 3
}
```

### Client

ServerからJobのリクエストを受け処理を行う実行部隊です。常に「俺は生きてるよ〜」とServerに対して自身の状態を報告しています。

CPUやmemoryなどの色々な閾値を設定することができ、その値を元にnodeの実行が完了した不要なjobなどを削除(garbage collection)してくれたりします。

Serverに比べると通信量が少ないのでagentとしては軽量です。

## クラスタリング

#### Server クラスタリング

起動までうまくいけば、次は **マニュアルでクラスタリング** の設定をしてみましょう。

先ほど使用したインスタンスとは別に二台のインスタンスにnomadをインストールしておきます。

で、全台の `server.hcl` に下記のパラメータを追加してください。

Plain textcontent\_copy

```
  bootstrap_expect = 3 # 1→3に書き換える
  server_join {
    retry_join = ["<nomad-cluster01のIP>:4648"]
  }
```

そしたら _nomad-cluster01_ から順に起動していきます！

全台起動が完了したら、ステータスを確認してみましょう。この場合は `nomad server members` で確認するのが便利です。

Plain textcontent\_copy

```
$ 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プロセスを落としてみます。

Plain textcontent\_copy

```
$ systemctl stop nomad
```

ではもう一度確認。

Plain textcontent\_copy

```
$ 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が起動していないとクラスタリングされません)

ちなみに、下記のコマンドでもクラスタリング可能です。

Plain textcontent\_copy

```
$ nomad server join <known-address>
```

#### Client の認識

Serverのクラスタリングが終われば、 clientを認識させなければいけません。

要領は同じで、 `client.hcl` に記載するかクライアントがあるサーバで `nomad node config -update-servers` コマンドを使うだけ。

：configファイルの場合

Plain textcontent\_copy

```
client {
  enabled = true
  servers = ["<known-address>:4647"]
}
```

：コマンドの場合

Plain textcontent\_copy

```
$ nomad node config -update-servers <IP>:4647
```

もし、この時点で認識できていない場合は、 `nomad node status` をしても何も起こりません。

Plain textcontent\_copy

```
$ nomad node status
$
```

ちゃんと認識できていれば下記のように出るはずです。

Plain textcontent\_copy

```
$ 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を実行させるための流れは下記です。

1.  job file を書く
2.  登録されるJobの確認
3.  jobの登録
4.  実行されたjobのステータス(またはlogの)確認

#### まずは

nodeのステータスを確認。ちゃんとServerから見えてますね。

Plain textcontent\_copy

```
 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](https://github.com/hashicorp/http-echo) をビルドしておきましょう。

ただテキストを返すシンプルなweb-serverです。

Plain textcontent\_copy

```
$ http-echo -listen=":5678" -text="hello world"
```

別のターミナルから

Plain textcontent\_copy

```
$ curl http://localhost:5678
hello world
```

#### 1\. job file を書く

jobのファイルを作ります。ファイル名は `hey.nomad` です(なんでもかまいません)

Plain textcontent\_copy

```
# ↓ 任意の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になります。

Plain textcontent\_copy

```
job "hello" {
}
```

#### 2\. 登録されるJobの確認

fileができたらひとまず `nomad job plan` をしてみましょう。

これから何が起こるのかを確認することができます。 **Terraform** を使った事のある方には既視感があるかもしれません。

Plain textcontent\_copy

```
$ 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` 。これでデプロイを実行します。

Plain textcontent\_copy

```
$ 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` です。

Plain textcontent\_copy

```
$ 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** です。

Plain textcontent\_copy

```
$ 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>` です。

Plain textcontent\_copy

```
$ 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>` でログを確認できます。

Plain textcontent\_copy

```
$ 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>` でできます。

Plain textcontent\_copy

```
$ 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します。

Plain textcontent\_copy

```
$ nomad job status
ID     Type     Priority  Status          Submit Date
hello  service  50        dead (stopped)  2019-05-12T02:50:35Z
```

ステータスはstoppedになっていますね。では削除してみます。

nomadはHTTP APIを使うことができるので下記のpathへリクエストを投げます。

Plain textcontent\_copy

```
$ curl -X PUT http://localhost:4646/v1/system/gc
```

再度確認します

Plain textcontent\_copy

```
$ nomad job status
No running jobs
```

綺麗になくなってますね。

### 今日はここまで。

いかがでしたでしょうか？

今回の記事は入門編ということでチュートリアル的な内容ではありますが、ざっくりと概念についてはイメージできたのではないでしょうか。

次回は `consul + nomd` による自動クラスタリング、 `Dockerプラグイン` を使ったアプリケーションのデプロイなどより実践的な構築を記事にしたいと思います。

ではでは、また次回。

## この記事を書いた人

[![](/_astro/shimichan.B6KTYu8c_Z1NDayG.webp)](/authors/shimichan/)

### [shimichan](/authors/shimichan/)

shimichanのプロフィールと執筆記事をご覧いただけます。

[プロフィールと記事一覧](/authors/shimichan/)