Nomad Job Files
Definizione dei job Nomad per ogni microservizio Visla GPS.
Struttura Base di un Job
job "nome-servizio" {
datacenters = ["visla-dc1"]
type = "service" # service, batch, system
group "nome-gruppo" {
count = 2 # Numero di repliche
network {
port "http" {
to = 8080
}
}
service {
name = "nome-servizio"
port = "http"
# Registrazione in Consul
tags = [
"traefik.enable=true",
"traefik.http.routers.nome.rule=PathPrefix(`/api/nome`)"
]
check {
type = "http"
path = "/health"
interval = "10s"
timeout = "3s"
}
}
task "app" {
driver = "docker"
config {
image = "gcr.io/visla-gps/nome-servizio:latest"
ports = ["http"]
}
env {
# Variabili d'ambiente
}
resources {
cpu = 500 # MHz
memory = 512 # MB
}
}
}
}
Core Services
Auth Service
job "auth-service" {
datacenters = ["visla-dc1"]
type = "service"
group "api" {
count = 2
network {
port "http" { to = 8080 }
}
service {
name = "auth"
port = "http"
tags = [
"traefik.enable=true",
"traefik.http.routers.auth.rule=PathPrefix(`/api/auth`) || PathPrefix(`/api/openid`)",
"traefik.http.routers.auth.entrypoints=websecure",
"traefik.http.routers.auth.tls.certresolver=letsencrypt"
]
check {
type = "http"
path = "/health"
interval = "10s"
timeout = "3s"
}
}
task "auth" {
driver = "docker"
config {
image = "gcr.io/visla-gps/auth:${NOMAD_META_VERSION}"
ports = ["http"]
}
template {
data = <<EOF
DATABASE_URL=postgresql://visla_app:{{ with secret "kv/data/database" }}{{ .Data.data.password }}{{ end }}@10.0.0.5:5432/visla_production
REDIS_URL=redis://10.0.0.10:6379
JWT_SECRET={{ with secret "kv/data/jwt" }}{{ .Data.data.secret }}{{ end }}
GOOGLE_CLIENT_ID={{ with secret "kv/data/oauth/google" }}{{ .Data.data.client_id }}{{ end }}
GOOGLE_CLIENT_SECRET={{ with secret "kv/data/oauth/google" }}{{ .Data.data.client_secret }}{{ end }}
EOF
destination = "secrets/env"
env = true
}
resources {
cpu = 500
memory = 512
}
}
}
meta {
VERSION = "latest"
}
}
Devices Service
job "devices-service" {
datacenters = ["visla-dc1"]
type = "service"
group "api" {
count = 2
network {
port "http" { to = 8080 }
}
service {
name = "devices"
port = "http"
tags = [
"traefik.enable=true",
"traefik.http.routers.devices.rule=PathPrefix(`/api/devices`)",
"traefik.http.routers.devices.entrypoints=websecure",
"traefik.http.routers.devices.tls.certresolver=letsencrypt"
]
check {
type = "http"
path = "/health"
interval = "10s"
timeout = "3s"
}
}
task "devices" {
driver = "docker"
config {
image = "gcr.io/visla-gps/devices:${NOMAD_META_VERSION}"
ports = ["http"]
}
template {
data = <<EOF
DATABASE_URL=postgresql://visla_app:{{ with secret "kv/data/database" }}{{ .Data.data.password }}{{ end }}@10.0.0.5:5432/visla_production
REDIS_URL=redis://10.0.0.10:6379
EOF
destination = "secrets/env"
env = true
}
resources {
cpu = 500
memory = 512
}
}
}
}
Tracking Service
job "tracking-service" {
datacenters = ["visla-dc1"]
type = "service"
group "api" {
count = 2
network {
port "http" { to = 8080 }
}
service {
name = "tracking"
port = "http"
tags = [
"traefik.enable=true",
"traefik.http.routers.tracking.rule=PathPrefix(`/api/tracking`) || PathPrefix(`/api/positions`)",
"traefik.http.routers.tracking.entrypoints=websecure"
]
check {
type = "http"
path = "/health"
interval = "10s"
timeout = "3s"
}
}
task "tracking" {
driver = "docker"
config {
image = "gcr.io/visla-gps/tracking:${NOMAD_META_VERSION}"
ports = ["http"]
}
template {
data = <<EOF
DATABASE_URL=postgresql://visla_app:{{ with secret "kv/data/database" }}{{ .Data.data.password }}{{ end }}@10.0.0.5:5432/visla_production
REDIS_URL=redis://10.0.0.10:6379
EOF
destination = "secrets/env"
env = true
}
resources {
cpu = 500
memory = 512
}
}
}
}
Data Pipeline Services
Decoder Service
[!IMPORTANT] Il decoder riceve connessioni TCP dai dispositivi GPS. Richiede porte statiche.
job "decoder-service" {
datacenters = ["visla-dc1"]
type = "service"
group "decoder" {
count = 3
network {
# Porta statica per dispositivi GPS
port "tcp" {
static = 5000
to = 5000
}
port "health" {
to = 8080
}
}
service {
name = "decoder"
port = "health"
check {
type = "http"
path = "/health"
interval = "10s"
timeout = "3s"
}
}
task "decoder" {
driver = "docker"
config {
image = "gcr.io/visla-gps/decoder:${NOMAD_META_VERSION}"
ports = ["tcp", "health"]
}
template {
data = <<EOF
REDIS_URL=redis://10.0.0.10:6379
TCP_PORT=5000
EOF
destination = "secrets/env"
env = true
}
resources {
cpu = 1000
memory = 1024
}
}
}
}
Position Filter
job "position-filter" {
datacenters = ["visla-dc1"]
type = "service"
group "filter" {
count = 2
task "filter" {
driver = "docker"
config {
image = "gcr.io/visla-gps/position-filter:${NOMAD_META_VERSION}"
}
template {
data = <<EOF
REDIS_URL=redis://10.0.0.10:6379
INPUT_STREAM=positions:raw
OUTPUT_STREAM=positions:filtered
EOF
destination = "secrets/env"
env = true
}
resources {
cpu = 500
memory = 256
}
}
}
}
DB Persister
job "db-persister" {
datacenters = ["visla-dc1"]
type = "service"
group "persister" {
count = 2
task "persister" {
driver = "docker"
config {
image = "gcr.io/visla-gps/db-persister:${NOMAD_META_VERSION}"
}
template {
data = <<EOF
DATABASE_URL=postgresql://visla_app:{{ with secret "kv/data/database" }}{{ .Data.data.password }}{{ end }}@10.0.0.5:5432/visla_production
REDIS_URL=redis://10.0.0.10:6379
INPUT_STREAM=positions:enriched
EOF
destination = "secrets/env"
env = true
}
resources {
cpu = 500
memory = 512
}
}
}
}
WebSocket Service
job "websocket-service" {
datacenters = ["visla-dc1"]
type = "service"
group "ws" {
count = 3
network {
port "ws" { to = 8080 }
}
service {
name = "websocket"
port = "ws"
tags = [
"traefik.enable=true",
"traefik.http.routers.ws.rule=PathPrefix(`/ws`)",
"traefik.http.routers.ws.entrypoints=websecure"
]
check {
type = "http"
path = "/health"
interval = "10s"
timeout = "3s"
}
}
task "websocket" {
driver = "docker"
config {
image = "gcr.io/visla-gps/websocket:${NOMAD_META_VERSION}"
ports = ["ws"]
}
template {
data = <<EOF
DATABASE_URL=postgresql://visla_app:{{ with secret "kv/data/database" }}{{ .Data.data.password }}{{ end }}@10.0.0.5:5432/visla_production
REDIS_URL=redis://10.0.0.10:6379
JWT_SECRET={{ with secret "kv/data/jwt" }}{{ .Data.data.secret }}{{ end }}
EOF
destination = "secrets/env"
env = true
}
resources {
cpu = 500
memory = 512
}
}
}
}
Deploy Commands
# Deploy singolo job
nomad job run auth-service.nomad
# Deploy tutti i servizi
for job in *.nomad; do
echo "Deploying $job..."
nomad job run "$job"
done
# Verifica status
nomad job status auth-service
# Visualizza allocazioni
nomad job allocs auth-service
# Logs di un'allocazione
nomad alloc logs <alloc-id>
# Scala un servizio
nomad job scale auth-service api 5
# Rolling update
nomad job run -var="VERSION=v1.2.3" auth-service.nomad
Directory Structure Consigliata
nomad-jobs/
├── core/
│ ├── auth-service.nomad
│ ├── devices-service.nomad
│ ├── tracking-service.nomad
│ ├── sharing-service.nomad
│ ├── commands-service.nomad
│ └── notifications-service.nomad
├── pipeline/
│ ├── decoder-service.nomad
│ ├── position-filter.nomad
│ ├── position-enricher.nomad
│ ├── db-persister.nomad
│ └── event-detector.nomad
├── infra/
│ ├── traefik.nomad
│ └── prometheus.nomad
└── deploy.sh