Nomad 導入

Nomad 導入

Nomadはオーケストレーションツールでオンプレやクラウド環境を超えてコンテナやコンテナではないアプリケーションのデプロイ管理ができます。

インストール

macOS Catalina Version 10.15.7で実行しています。

最初にHomeBrewでnomadをインストールします。

$ brew install nomad

インストールされたことを確認

$ nomad -v
Nomad v1.1.3

devモード

devモードで起動します。他のモードとして通常モードがあり、通常モードではサーバとクライアントを分けて起動することができたり、柔軟な設定が可能です。

起動

エージェントを起動。devモードでサーバーを起動します。

$ nomad agent -dev
==> No configuration files loaded
==> Starting Nomad agent...
==> Nomad agent configuration:

       Advertise Addrs: HTTP: 127.0.0.1:4646; RPC: 127.0.0.1:4647; Serf: 127.0.0.1:4648
            Bind Addrs: HTTP: 127.0.0.1:4646; RPC: 127.0.0.1:4647; Serf: 127.0.0.1:4648
                Client: true
             Log Level: DEBUG
                Region: global (DC: dc1)
                Server: true
               Version: 1.1.3

==> Nomad agent started! Log data will stream in below:

    2021-08-08T00:29:53.496+0900 [DEBUG] agent.plugin_loader.docker: using client connection initialized from environment: plugin_dir=
    2021-08-08T00:29:53.497+0900 [DEBUG] agent.plugin_loader.docker: using client connection initialized from environment: plugin_dir=
    2021-08-08T00:29:53.497+0900 [INFO]  agent: detected plugin: name=docker type=driver plugin_version=0.1.0
    2021-08-08T00:29:53.497+0900 [INFO]  agent: detected plugin: name=mock_driver type=driver plugin_version=0.1.0
    2021-08-08T00:29:53.497+0900 [INFO]  agent: detected plugin: name=raw_exec type=driver plugin_version=0.1.0
    2021-08-08T00:29:53.497+0900 [INFO]  agent: detected plugin: name=exec type=driver plugin_version=0.1.0
    2021-08-08T00:29:53.497+0900 [INFO]  agent: detected plugin: name=qemu type=driver plugin_version=0.1.0
    2021-08-08T00:29:53.497+0900 [INFO]  agent: detected plugin: name=java type=driver plugin_version=0.1.0
    2021-08-08T00:29:53.502+0900 [INFO]  nomad.raft: initial configuration: index=1 servers="[{Suffrage:Voter ID:127.0.0.1:4647 Address:127.0.0.1:4647}]"
    2021-08-08T00:29:53.502+0900 [INFO]  nomad.raft: entering follower state: follower="Node at 127.0.0.1:4647 [Follower]" leader=
    2021-08-08T00:29:53.503+0900 [INFO]  nomad: serf: EventMemberJoin: 147ddac625fa.ant.amazon.com.global 127.0.0.1
    2021-08-08T00:29:53.504+0900 [INFO]  nomad: starting scheduling worker(s): num_workers=8 schedulers=[service, batch, system, _core]
    2021-08-08T00:29:53.504+0900 [INFO]  client: using state directory: state_dir=/private/var/folders/3x/2yhk0tsd2r7djkrt82cnhsv8gmbt28/T/NomadClient353248954
    2021-08-08T00:29:53.505+0900 [INFO]  nomad: adding server: server="147ddac625fa.ant.amazon.com.global (Addr: 127.0.0.1:4647) (DC: dc1)"
    2021-08-08T00:29:53.507+0900 [INFO]  client: using alloc directory: alloc_dir=/private/var/folders/3x/2yhk0tsd2r7djkrt82cnhsv8gmbt28/T/NomadClient116304081
    2021-08-08T00:29:53.559+0900 [DEBUG] client.fingerprint_mgr: built-in fingerprints: fingerprinters=[arch, cni, consul, cpu, host, memory, network, nomad, signal, storage, vault, env_aws, env_gce, env_azure]
    2021-08-08T00:29:53.559+0900 [DEBUG] client.fingerprint_mgr: CNI config dir is not set or does not exist, skipping: cni_config_dir=/opt/cni/config
    2021-08-08T00:29:53.559+0900 [DEBUG] client.fingerprint_mgr: fingerprinting periodically: fingerprinter=consul period=15s
    2021-08-08T00:29:53.559+0900 [DEBUG] client.fingerprint_mgr.cpu: detected cpu frequency: MHz=1400
    2021-08-08T00:29:53.559+0900 [DEBUG] client.fingerprint_mgr.cpu: detected core count: cores=8
    2021-08-08T00:29:53.559+0900 [DEBUG] client.fingerprint_mgr.cpu: detected reservable cores: cpuset=[]
    2021-08-08T00:29:53.610+0900 [DEBUG] client.fingerprint_mgr.network: link speed could not be detected and no speed specified by user, falling back to default speed: mbits=1000
    2021-08-08T00:29:53.610+0900 [DEBUG] client.fingerprint_mgr.network: detected interface IP: interface=lo0 IP=127.0.0.1
    2021-08-08T00:29:53.610+0900 [DEBUG] client.fingerprint_mgr.network: detected interface IP: interface=lo0 IP=::1
    2021-08-08T00:29:53.610+0900 [DEBUG] client.fingerprint_mgr.network: link speed could not be detected, falling back to default speed: mbits=1000
    2021-08-08T00:29:53.610+0900 [DEBUG] client.fingerprint_mgr.network: link speed could not be detected, falling back to default speed: mbits=1000
    2021-08-08T00:29:53.610+0900 [DEBUG] client.fingerprint_mgr.network: link speed could not be detected, falling back to default speed: mbits=1000
    2021-08-08T00:29:53.610+0900 [DEBUG] client.fingerprint_mgr.network: link speed could not be detected, falling back to default speed: mbits=1000
    2021-08-08T00:29:53.610+0900 [DEBUG] client.fingerprint_mgr.network: link speed could not be detected, falling back to default speed: mbits=1000
    2021-08-08T00:29:53.610+0900 [DEBUG] client.fingerprint_mgr.network: link speed could not be detected, falling back to default speed: mbits=1000
    2021-08-08T00:29:53.610+0900 [DEBUG] client.fingerprint_mgr.network: link speed could not be detected, falling back to default speed: mbits=1000
    2021-08-08T00:29:53.610+0900 [DEBUG] client.fingerprint_mgr.network: link speed could not be detected, falling back to default speed: mbits=1000
    2021-08-08T00:29:53.610+0900 [DEBUG] client.fingerprint_mgr.network: link speed could not be detected, falling back to default speed: mbits=1000
    2021-08-08T00:29:53.610+0900 [DEBUG] client.fingerprint_mgr.network: link speed could not be detected, falling back to default speed: mbits=1000
    2021-08-08T00:29:53.610+0900 [DEBUG] client.fingerprint_mgr.network: link speed could not be detected, falling back to default speed: mbits=1000
    2021-08-08T00:29:53.610+0900 [DEBUG] client.fingerprint_mgr.network: link speed could not be detected, falling back to default speed: mbits=1000
    2021-08-08T00:29:53.610+0900 [DEBUG] client.fingerprint_mgr.network: link speed could not be detected, falling back to default speed: mbits=1000
    2021-08-08T00:29:53.610+0900 [DEBUG] client.fingerprint_mgr.network: link speed could not be detected, falling back to default speed: mbits=1000
    2021-08-08T00:29:53.610+0900 [DEBUG] client.fingerprint_mgr.network: link speed could not be detected, falling back to default speed: mbits=1000
    2021-08-08T00:29:53.615+0900 [DEBUG] client.fingerprint_mgr: fingerprinting periodically: fingerprinter=vault period=15s
    2021-08-08T00:29:54.873+0900 [WARN]  nomad.raft: heartbeat timeout reached, starting election: last-leader=
    2021-08-08T00:29:54.874+0900 [INFO]  nomad.raft: entering candidate state: node="Node at 127.0.0.1:4647 [Candidate]" term=2
    2021-08-08T00:29:54.874+0900 [DEBUG] nomad.raft: votes: needed=1
    2021-08-08T00:29:54.874+0900 [DEBUG] nomad.raft: vote granted: from=127.0.0.1:4647 term=2 tally=1
    2021-08-08T00:29:54.874+0900 [INFO]  nomad.raft: election won: tally=1
    2021-08-08T00:29:54.874+0900 [INFO]  nomad.raft: entering leader state: leader="Node at 127.0.0.1:4647 [Leader]"
    2021-08-08T00:29:54.874+0900 [INFO]  nomad: cluster leadership acquired
    2021-08-08T00:29:54.879+0900 [INFO]  nomad.core: established cluster id: cluster_id=695b378c-f623-61ae-a0d8-d3281d4e8367 create_time=1628350194878909000
    2021-08-08T00:29:55.619+0900 [DEBUG] client.fingerprint_mgr.env_gce: could not read value for attribute: attribute=machine-type error="Get "http://169.254.169.254/computeMetadata/v1/instance/machine-type": context deadline exceeded (Client.Timeout exceeded while awaiting headers)"
    2021-08-08T00:29:55.619+0900 [DEBUG] client.fingerprint_mgr.env_gce: error querying GCE Metadata URL, skipping
    2021-08-08T00:29:57.624+0900 [DEBUG] client.fingerprint_mgr.env_azure: could not read value for attribute: attribute=compute/azEnvironment error="Get "http://169.254.169.254/metadata/instance/compute/azEnvironment?api-version=2019-06-04&format=text": context deadline exceeded (Client.Timeout exceeded while awaiting headers)"
    2021-08-08T00:29:59.629+0900 [DEBUG] client.fingerprint_mgr: detected fingerprints: node_attrs=[arch, cpu, host, network, nomad, signal, storage]
    2021-08-08T00:29:59.629+0900 [INFO]  client.plugin: starting plugin manager: plugin-type=csi
    2021-08-08T00:29:59.629+0900 [INFO]  client.plugin: starting plugin manager: plugin-type=driver
    2021-08-08T00:29:59.629+0900 [INFO]  client.plugin: starting plugin manager: plugin-type=device
    2021-08-08T00:29:59.629+0900 [DEBUG] client.device_mgr: exiting since there are no device plugins
    2021-08-08T00:29:59.630+0900 [DEBUG] client.plugin: waiting on plugin manager initial fingerprint: plugin-type=device
    2021-08-08T00:29:59.630+0900 [DEBUG] client.plugin: finished plugin manager initial fingerprint: plugin-type=device
    2021-08-08T00:29:59.630+0900 [DEBUG] client.plugin: waiting on plugin manager initial fingerprint: plugin-type=driver
    2021-08-08T00:29:59.630+0900 [DEBUG] client.driver_mgr: initial driver fingerprint: driver=raw_exec health=healthy description=Healthy
    2021-08-08T00:29:59.630+0900 [DEBUG] client.driver_mgr: initial driver fingerprint: driver=mock_driver health=healthy description=Healthy
    2021-08-08T00:29:59.630+0900 [DEBUG] client.driver_mgr: initial driver fingerprint: driver=exec health=undetected description="exec driver unsupported on client OS"
    2021-08-08T00:29:59.632+0900 [DEBUG] client.driver_mgr: initial driver fingerprint: driver=qemu health=undetected description=
    2021-08-08T00:29:59.633+0900 [DEBUG] client.server_mgr: new server list: new_servers=[127.0.0.1:4647] old_servers=[]
    2021-08-08T00:29:59.687+0900 [DEBUG] client.driver_mgr: initial driver fingerprint: driver=docker health=healthy description=Healthy
    2021-08-08T00:29:59.825+0900 [DEBUG] client.driver_mgr: initial driver fingerprint: driver=java health=healthy description=Healthy
    2021-08-08T00:29:59.825+0900 [DEBUG] client.driver_mgr: detected drivers: drivers="map[healthy:[raw_exec mock_driver docker java] undetected:[exec qemu]]"
    2021-08-08T00:29:59.825+0900 [DEBUG] client.plugin: finished plugin manager initial fingerprint: plugin-type=driver
    2021-08-08T00:29:59.825+0900 [INFO]  client: started client: node_id=7cd596ff-0354-861c-9fd0-2467e2f2237a
    2021-08-08T00:29:59.827+0900 [DEBUG] client: updated allocations: index=1 total=0 pulled=0 filtered=0
    2021-08-08T00:29:59.829+0900 [DEBUG] client: allocation updates: added=0 removed=0 updated=0 ignored=0
    2021-08-08T00:29:59.829+0900 [DEBUG] client: allocation updates applied: added=0 removed=0 updated=0 ignored=0 errors=0
    2021-08-08T00:29:59.830+0900 [INFO]  client: node registration complete
    2021-08-08T00:29:59.831+0900 [DEBUG] client: state updated: node_status=ready
    2021-08-08T00:30:00.830+0900 [DEBUG] client: state changed, updating node and re-registering
    2021-08-08T00:30:00.831+0900 [INFO]  client: node registration complete

別のターミナルで作業

example.nomadという名前でコメントを省略したものについて以下のようなファイルが作成されます。nomad job init実行時に-shortオプションをつけるとコメント無しのJobファイルが作成されます。

固定ポートを使用する場合は、network以下でポート番号の指定をしている部分をtoからstaticに変更することで可能です。ただし、基本的にジョブの種類がsystemかロードバランサーのような特殊なジョブのときのみに使用することが推奨されています。

port Parameters

Deploymentがin progressと表示されて、しばらくするとsuccessfulになります。デプロイが正常に完了しない場合は、failedになります。

Play

Jobの一覧を確認。ここでは、example.nomadファイル中で定義したjobのexampleが確認できます。

job名であるexampleを引数に指定するとより詳細を確認できます。AllocationsのIDを確認からAllocations IDを確認できます。これはnomad job run example.nomad実行時に、ログ出力でAllocationの行に記載されるIDと同じものになります。

確認したAllocation IDを引数に以下のコマンドを実行すると、リソース割当ての詳細を確認できます。Task ResourcesAddressにIPアドレスおよびポート番号が確認できないIssueがあるようです。コンテナにアクセスするための代替案については後ほど言及します。

[feature] Expose contents of DriverNetwork via API #3285

同じくAllocation IDを指定してログを確認できます。追加の引数でnomad alloc logs 38353085 redisのようにnomadファイルで指定したtask名を指定することもできます。

http://localhost:4646/のURLにアクセスすることでブラウザ上でGUIを通して操作することもできます。

コンテナに接続

先程、nomad alloc status <ALLOCATION_ID>を実行した際に、Task ResourcesAddressにIPアドレスおよびポート番号が確認できませんでしたので、確認するための代替案について言及します。

まずは以下のコマンドでコンテナIDを確認します。

確認したコンテナID(c08ced4cdb8d)もしくはコンテナ名(redis-433ee0d0-b2a8-a617-6d8d-05a575c7523c)を指定して以下のように実行します。すると動的にマッピングされたポート番号が確認できます。

以下の方法でも取得可能です。

無事に接続できることが確認できます。

設定ファイルの変更

ためしに.nomadファイルのgroup以下のcountを1から3に変更してみます。すると、現状との差分について以下のように確認できます。

先程と同様にnomad job run example.nomadを実行すると、コンテナが3つ起動していることが確認できます。

それぞれのコンテナにはホスト側のネットワークインターフェイスにポート番号が割り振られていることも確認できます。逆に言うと、.nomadファイルでnetwork以下のportでポート番号をtoではなく、staticで指定すると、ホスト側でポート番号がバッティングするのでセットアップできないことが理由で、nomad job run <.nomadファイル>を実行してもin progressから進まなくなります。

Stop

以下のようにジョブを終了できます。

ステータスは以下のようになります。

通常モード

先程はdevモードで設定を行ないましたが、ここでは通常モードで設定を行ないます。通常モードではサーバとクライアントを分けて起動することができたり、様々な柔軟な設定を行うことができます。ここでは、サーバ1台、クライアント3台構成です。

HashiCorp Nomad Workshopを参考にさせていただきました。

Nomadサーバ用の.hclファイルを作成します。

Nomadクライアント用の.hclファイルを作成します。

残り2つのクライアントも同様に設定します。

起動用にスクリプトを作成します。

作成した起動用スクリプトを実行します。

一方でjobを実行します。

コンテナが起動していることが確認できます。

ポートマッピングも確認できます。

終了するときは、devモードと同様にnomad job stop exampleを実行します。

デーモン状態で起動していますので、ps aux | grep nomadで対象プロセスを確認して、プロセスを終了するために、プロセスIDをスペース区切りで列挙して指定してkillします。

Errors

API error (500): toomanyrequests: You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limit

最終的に以下のようにfailedになった

エージェントを起動した方のログで以下の出力がされていた

2020/11/20ごろにDockerHubが行った制約によるものの様子。 6時間で匿名ユーザーは100まで、FreeのDocker Hubユーザーは、200までpullできるようです。

docker login -u *** -p ***はしていなかったので、匿名ユーザー扱いだが、特に直近6時間でpullしていないため、理由が不明でした。

Understanding Docker Hub Rate Limiting

が、より詳細にと書かれたリンク先にIPアドレスに基づいて制限されることが書かれていました。

Download rate limit

Scaling Docker to Serve Millions More Developers: Network Egress

これに気づいて、社内VPNで接続していたものを切断してみました。無事にデプロイすることができました。

nomad job run <.nomadファイル>を実行しても起動しない

Pattern 1: mac OSでmode = "bridge"を指定

NomodではDockerのドライバーを使用した際にbridgeモードが適用されますが、明示的に.nomadファイルにmodeをbridgeと指定すると、nomad job run <.nomadファイル>を実行してもin progressから進まなくなります。

Networking

理由は、NomadのネットワーキングモードのbridgeがLinux向けだからのようです。そのため、mode = "bridge"はmacOS上では記載してはいけないようです。

"missing network" constraint w/ bridge network #8684

Pattern 2: .nomadファイルでnetwork以下のportでポート番号をtoではなく、staticで指定して、複数のコンテナを起動

ホスト側でポート番号がバッティングするのでセットアップできないことが理由で、nomad job run <.nomadファイル>を実行してもin progressから進まなくなります。

References

Last updated