HashiCorp Nomad
DevOpsツール
HashiCorp Nomad
概要
HashiCorp Nomadは、シンプルで柔軟なワークロードオーケストレーターです。コンテナ、VM、バイナリアプリケーションを統一してスケジューリングし、Kubernetesよりも軽量でシンプルな選択肢を提供します。
詳細
HashiCorp Nomad(ノマド)は、HashiCorpが開発したワークロードオーケストレーションプラットフォームです。2015年にリリースされ、「シンプルで柔軟なワークロードオーケストレーター」として設計されました。コンテナ(Docker、Podman)、仮想マシン(QEMU)、バイナリアプリケーション、Java アプリケーション等、多様なワークロードを統一してスケジューリング可能。単一バイナリでの簡単デプロイ、Kubernetesより少ない概念とシンプルな設定、HashiCorpスタック(Vault、Consul、Terraform)との密な統合が特徴です。高性能なスケジューラー、マルチリージョン・マルチクラウド対応、ゼロダウンタイムデプロイ、ローリングアップデート、カナリアデプロイメント等の高度な機能を提供。特にエッジコンピューティング、IoT、規模の小さなクラスター、混在ワークロード環境での利用に適しており、Kubernetesの複雑さを避けたい組織に人気。現在では、金融、製造、エネルギー等の業界で、インフラストラクチャの簡素化とHashiCorpエコシステム統合を求める企業での採用が拡大しています。
メリット・デメリット
メリット
- シンプル: Kubernetesより少ない概念で理解しやすい
- マルチワークロード: コンテナ・VM・バイナリの統一管理
- 軽量: 少ないリソースでの動作と単一バイナリデプロイ
- HashiCorpスタック統合: Vault、Consul、Terraformとの密な連携
- エッジ対応: 小規模環境・分散環境に最適
- 運用性: 直感的なWeb UI とシンプルな設定
- 柔軟性: 既存インフラとの統合が容易
- マルチリージョン: 複数データセンター間での統一管理
デメリット
- エコシステム: Kubernetesほどの豊富なツール群なし
- 機能制限: 高度なオーケストレーション機能の不足
- 学習リソース: ドキュメントとコミュニティがKubernetesより少ない
- サードパーティ対応: Kubernetes向けツールの対応状況
- ネットワーク: 複雑なネットワーク設定への制約
- ストレージ: 永続ボリューム管理の機能が限定的
- 企業サポート: エンタープライズサポートが限定的
- 人材: Kubernetes経験者の方が多く採用しやすい
主要リンク
書き方の例
Nomadクラスター構築
# Nomad バイナリダウンロード・インストール
wget https://releases.hashicorp.com/nomad/1.6.0/nomad_1.6.0_linux_amd64.zip
unzip nomad_1.6.0_linux_amd64.zip
sudo mv nomad /usr/local/bin/
# 設定ファイル作成(サーバーモード)
sudo mkdir -p /etc/nomad.d
cat > /etc/nomad.d/nomad.hcl << EOF
datacenter = "dc1"
data_dir = "/opt/nomad/data"
bind_addr = "0.0.0.0"
server {
enabled = true
bootstrap_expect = 3
server_join {
retry_join = ["10.0.1.10", "10.0.1.11", "10.0.1.12"]
}
}
client {
enabled = true
servers = ["10.0.1.10:4647", "10.0.1.11:4647", "10.0.1.12:4647"]
}
ui_config {
enabled = true
}
consul {
address = "127.0.0.1:8500"
}
vault {
enabled = true
address = "http://vault.example.com:8200"
}
EOF
# systemd サービス設定
cat > /etc/systemd/system/nomad.service << EOF
[Unit]
Description=Nomad
Documentation=https://www.nomadproject.io/
Requires=network-online.target
After=network-online.target
[Service]
Type=notify
ExecStart=/usr/local/bin/nomad agent -config=/etc/nomad.d/
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable nomad
sudo systemctl start nomad
Job定義(Docker コンテナ)
# web-app.nomad
job "web-app" {
datacenters = ["dc1"]
type = "service"
group "web" {
count = 3
network {
port "http" {
static = 8080
to = 80
}
}
service {
name = "web-app"
port = "http"
tags = [
"web",
"nginx",
"frontend"
]
check {
type = "http"
path = "/health"
interval = "30s"
timeout = "2s"
}
}
task "nginx" {
driver = "docker"
config {
image = "nginx:alpine"
ports = ["http"]
mount {
type = "bind"
source = "local/nginx.conf"
target = "/etc/nginx/nginx.conf"
}
}
template {
data = <<EOF
events {
worker_connections 1024;
}
http {
upstream app {
server {{ range service "app-backend" }}{{ .Address }}:{{ .Port }};{{ end }}
}
server {
listen 80;
location / {
proxy_pass http://app;
}
location /health {
return 200 "OK";
}
}
}
EOF
destination = "local/nginx.conf"
}
resources {
cpu = 100
memory = 128
}
env {
ENV = "production"
}
}
}
update {
max_parallel = 1
min_healthy_time = "10s"
healthy_deadline = "3m"
progress_deadline = "10m"
auto_revert = true
canary = 1
}
}
Job定義(バイナリアプリケーション)
# go-app.nomad
job "go-app" {
datacenters = ["dc1"]
type = "service"
group "app" {
count = 2
network {
port "api" {
to = 8080
}
}
service {
name = "go-api"
port = "api"
check {
type = "tcp"
interval = "10s"
timeout = "2s"
}
}
task "api-server" {
driver = "exec"
artifact {
source = "https://releases.example.com/myapp/v1.2.3/myapp-linux-amd64"
destination = "local/"
mode = "file"
}
config {
command = "local/myapp-linux-amd64"
args = ["--port", "${NOMAD_PORT_api}"]
}
env {
DATABASE_URL = "postgresql://user:${vault_secret}@db.example.com:5432/myapp"
}
vault {
policies = ["database-read"]
}
resources {
cpu = 200
memory = 256
}
logs {
max_files = 3
max_file_size = 10
}
}
}
}
Batch Job(データ処理)
# batch-job.nomad
job "data-processing" {
datacenters = ["dc1"]
type = "batch"
periodic {
cron = "0 2 * * *" # 毎日午前2時
prohibit_overlap = true
}
group "process" {
count = 1
task "etl" {
driver = "docker"
config {
image = "python:3.9"
command = "python"
args = ["process_data.py"]
mount {
type = "bind"
source = "local/script"
target = "/app"
}
}
artifact {
source = "git::https://github.com/company/data-scripts.git"
destination = "local/script"
}
env {
AWS_ACCESS_KEY_ID = "${aws_access_key}"
AWS_SECRET_ACCESS_KEY = "${aws_secret_key}"
DATA_BUCKET = "my-data-bucket"
}
vault {
policies = ["aws-s3-access"]
}
resources {
cpu = 500
memory = 1024
}
}
}
}
システムJob(ログ収集)
# log-collector.nomad
job "log-collector" {
datacenters = ["dc1"]
type = "system"
group "collector" {
task "fluentd" {
driver = "docker"
config {
image = "fluentd:latest"
mount {
type = "bind"
source = "/var/log"
target = "/var/log"
readonly = true
}
mount {
type = "bind"
source = "local/fluent.conf"
target = "/fluentd/etc/fluent.conf"
}
}
template {
data = <<EOF
<source>
@type tail
path /var/log/nomad/nomad.log
pos_file /var/log/fluentd/nomad.log.pos
tag nomad.log
format json
</source>
<match nomad.**>
@type elasticsearch
host {{ range service "elasticsearch" }}{{ .Address }}{{ end }}
port {{ range service "elasticsearch" }}{{ .Port }}{{ end }}
index_name nomad-logs
</match>
EOF
destination = "local/fluent.conf"
}
resources {
cpu = 100
memory = 128
}
}
}
}
CSI Storage Plugin
# csi-plugin.nomad
job "csi-plugin" {
datacenters = ["dc1"]
type = "system"
group "csi-node" {
task "csi-plugin" {
driver = "docker"
config {
image = "my-registry/csi-driver:latest"
args = [
"--endpoint=${CSI_ENDPOINT}",
"--nodeid=${node.unique.id}"
]
privileged = true
}
csi_plugin {
id = "ebs"
type = "node"
mount_dir = "/csi"
}
resources {
cpu = 100
memory = 128
}
}
}
}
Nomad CLI操作
# Job管理
nomad job run web-app.nomad
nomad job status web-app
nomad job stop web-app
nomad job restart web-app
# スケーリング
nomad job scale web-app 5
# デプロイメント確認
nomad deployment list
nomad deployment status <deployment-id>
nomad deployment promote <deployment-id>
# Allocation管理
nomad alloc status <alloc-id>
nomad alloc logs <alloc-id>
nomad alloc exec <alloc-id> /bin/sh
# ノード管理
nomad node status
nomad node drain <node-id>
nomad node eligibility <node-id> ineligible
# システム確認
nomad server members
nomad operator autopilot get-config
nomad system gc
# メトリクス・モニタリング
nomad metrics
nomad monitor -log-level DEBUG
高可用性設定
# nomad.hcl (HA設定)
server {
enabled = true
bootstrap_expect = 3
server_join {
retry_join = ["provider=aws tag_key=Environment tag_value=production"]
}
encrypt = "base64-encrypted-gossip-key"
autopilot {
cleanup_dead_servers = true
last_contact_threshold = "200ms"
max_trailing_logs = 250
server_stabilization_time = "10s"
}
}
acl {
enabled = true
}
tls {
http = true
rpc = true
ca_file = "/etc/nomad.d/ca.pem"
cert_file = "/etc/nomad.d/server.pem"
key_file = "/etc/nomad.d/server-key.pem"
}