잡 스펙의 `service` 블록

잡 스펙의 service 블록

service 블록은 지정된 공급자(Nomad 또는 Consul)에 서비스를 등록하도록 Nomad에 지시해요. 이 문서 섹션은 구성을 다루지만, 외부 통합에 대한 더 자세한 정보는 Nomad 서비스 디스커버리 문서도 읽어야 해요.

출처: 문서

본문

배치 job -> group -> **service**
job -> group -> task -> **service**
job "docs" {
  group "example" {
    task "server" {
      service {
        tags = ["leader", "mysql"]

        port = "db"

        provider = "consul"

        weights {
          passing = 5
          warning = 1
        }

        meta {
          meta = "for your service"
        }

        check {
          type     = "tcp"
          port     = "db"
          interval = "10s"
          timeout  = "2s"
        }

        check {
          type     = "http"
          name     = "app_health"
          path     = "/health"
          interval = "20s"
          timeout  = "5s"

          check_restart {
            limit = 3
            grace = "90s"
            ignore_warnings = false
          }
        }

        identity {
          aud = ["consul.io"]
        }
      }
    }
  }
}

이 문서 섹션은 서비스 디스커버리를 위한 잡 파일 필드와 블록만 다뤄요. Nomad를 Consul과 함께 사용하는 방법에 대한 자세한 내용은 Consul 통합 문서를 참고하세요.

service 블록은 태스크 그룹 레벨에도 위치할 수 있어요. 이렇게 하면 같은 태스크 그룹 안의 서비스들이 Consul 서비스 메시 통합에 참여할 수 있어요.

매개변수 (Parameters)

  • provider (string: "consul") - 서비스 등록에 사용할 서비스 등록 공급자. 유효한 옵션은 consul 또는 nomad. 단일 태스크 그룹 안의 모든 서비스는 같은 공급자 값을 사용해야 해요.

  • cluster (string: "default")

Enterprise

- provider가 "consul"일 때 사용할 Consul 클러스터. Nomad 클라이언트는 에이전트 구성에서 같은 consul.name으로 구성된 클러스터에서 Consul 토큰을 가져와요. Nomad Community Edition에서는 이 필드가 무시돼요.

  • check ([Check]: nil) - 서비스와 연관된 헬스 체크. 서비스에 대한 여러 체크를 정의하기 위해 여러 번 지정할 수 있어요. 현재 Nomad 공급자를 사용하는 체크는 tcp와 http 체크를 지원해요. Consul 통합은 grpc, http, script¹, tcp 체크를 지원해요.

  • weights (Weights: nil) - 서비스의 건강 상태에 따라 DNS SRV 요청에서 서비스 인스턴스가 어떻게 가중되는지 지정. Consul weights 문서에 설명돼 있어요. provider = "consul"일 때만 사용 가능. weight 블록은 다음 필드를 지원해요:

    • passing int: 1 - passing 상태의 서비스 가중치.
    • warning int: 1 - warning 상태의 서비스 가중치.
  • connect - Consul 서비스 메시 통합을 구성. 그룹 서비스에서만, 그리고 provider = "consul"일 때만 사용 가능.

  • kind (string: <optional>) - 서비스 등록 중 Consul에 전달할 Consul Service Kind를 구성. provider = "consul"일 때만 사용 가능하며, Consul 서비스 메시 게이트웨이가 정의되면 무시돼요.

  • identity ([Identity]: nil) - 서비스를 등록하기 위해 Consul에서 Service Identity 토큰을 얻을 때 사용할 Workload Identity를 지정. provider = "consul"일 때만 사용 가능. 일반적으로 생략할 수 있으며 Nomad가 서버의 consul.service_identity 블록으로 폴백해요.

  • name (string: "<job>-<taskgroup>-<task>") - 이 서비스가 Consul에 광고될 이름. 제공되지 않으면 잡, 태스크 그룹, 태스크 이름을 대시로 연결한 "docs-example-server"처럼 기본 설정돼요. 각 서비스는 클러스터 안에서 고유한 이름을 가져야 해요. 이름은 RFC-1123 §2.1을 따라야 하고 영숫자와 하이픈 문자(즉 [a-z0-9\-])로 제한되며, 길이가 64자 미만이어야 해요.

표준 Nomad 보간 외에도 다음 키도 사용할 수 있어요:

- [`${JOB}`](https://developer.hashicorp.com/nomad/docs/job-specification/service#job) - 잡의 이름
- [`${TASKGROUP}`](https://developer.hashicorp.com/nomad/docs/job-specification/service#taskgroup) - 태스크 그룹의 이름
- [`${TASK}`](https://developer.hashicorp.com/nomad/docs/job-specification/service#task) - 태스크의 이름
- [`${BASE}`](https://developer.hashicorp.com/nomad/docs/job-specification/service#base) - `${JOB}-${TASKGROUP}-${TASK}`의 줄임말

이름 검증은 두 부분으로 이루어져요. 잡이 등록될 때 초기 검증 패스가 보간이 필요한 변수를 제외하고 서비스 이름이 RFC-1123 §2.1과 길이 제한을 준수하는지 확인해요. 클라이언트가 서비스를 받고 해석 가능한 모든 값이 사용 가능해지면 서비스 이름이 보간되고 다시 검증돼요. 이로 인해 일부 서비스 이름은 제출 시 검증을 통과하지만 런타임에는 실패할 수 있어요.

  • port (string: <optional>) - 이 서비스에 광고할 포트. port 값은 어떤 address_mode를 사용하는지에 따라 달라져요:

    • alloc - 레이블이 있는 포트의 매핑된 to 값과 할당 주소를 광고. to 값이 설정되지 않으면 포트는 할당된 호스트 포트를 사용해요. port 필드는 숫자 포트 또는 같은 그룹의 network 블록에 지정된 포트 레이블일 수 있어요.

    • alloc_ipv6 - alloc와 같지만 dual-stack 또는 IPv6 전용의 경우 IPv6 주소를 사용.

    • driver - 드라이버(예: Docker)가 결정한 포트를 광고. port는 숫자 포트 또는 드라이버의 ports 필드에 지정된 포트 레이블일 수 있어요.

    • host - 이 서비스의 호스트 포트를 광고. port는 network 블록에 지정된 포트 _레이블_과 일치해야 해요.

서비스 종류 허용된 포트 값 유형
일반(Normal) 숫자 또는 포트 매핑 레이블
connect 네이티브 사용 숫자 또는 포트 매핑 레이블
connect 사이드카 사용 숫자
인그레스 게이트웨이 포트 매핑 레이블 (선택)
터미네이팅 게이트웨이 없음 (선택)
메시 게이트웨이 외부 포트 매핑 레이블
  • tags (array<string>: []) - 이 서비스에 연결할 태그 목록. 제공되지 않으면 서비스가 등록될 때 태그가 할당되지 않아요.

  • canary_tags (array<string>: []) - 서비스가 현재 카나리인 할당의 일부일 때 이 서비스에 연결할 태그 목록. 카나리가 승격되면 등록된 태그가 tags 매개변수에 지정된 것으로 업데이트돼요. 제공되지 않으면 등록된 태그는 tags 매개변수의 것과 같아져요.

  • enable_tag_override (bool: false) - Consul의 Catalog API 사용자가 서비스의 태그를 변경해도 Consul의 안티-엔트로피 메커니즘이 그 변경을 덮어쓰지 않게 해요. 자세한 내용은 Consul 문서를 참고하세요. provider = "consul"일 때만 사용 가능.

  • address (string: <optional>) - Consul 또는 Nomad 서비스 등록에 광고할 사용자 정의 주소. 설정되면 address_mode가 auto 모드여야 해요. 보간에 유용해요 - 예를 들어 AWS EC2 인스턴스의 공개 IP 주소를 광고하려면 ${attr.unique.platform.aws.public-ipv4}로 설정하세요.

  • tagged_addresses (map<string|string> - Consul 서비스 등록에 광고할 사용자 정의 태그된 주소를 지정. provider = "consul"일 때만 사용 가능.

  • address_mode (string: "auto") - 이 서비스가 광고할 주소(host, alloc, alloc_ipv6 또는 driver 별). 아래 예시를 참고하세요. 유효한 옵션:

    • alloc - 네트워크 네임스페이스를 만드는 할당의 경우, 이 주소 모드는 네임스페이스 안의 IP 주소를 사용. "bridge"와 "cni" 네트워킹 모드에서만 사용할 수 있어요. 포트 매핑이 필요 없는 상황에는 숫자 포트를 지정할 수 있어요. 이 모드는 "group" 블록에 정의된 서비스에만 설정할 수 있어요.

    • alloc_ipv6 - alloc와 같지만 dual-stack 또는 IPv6 전용의 경우 IPv6 주소를 사용.

    • auto - 드라이버가 호스트 또는 드라이버 주소를 사용할지 결정하게 허용. 기본값은 host이며 Docker에서만 구현돼요. weave 같은 Docker 네트워크 플러그인을 사용하면 Docker가 자동으로 주소를 사용해요.

    • driver - 드라이버가 지정한 IP와 포트 맵에 지정된 포트를 사용. 모든 네트워크 플러그인이 포트 맵을 요구하지 않으므로 숫자 포트를 지정할 수 있어요. SDN 및 오버레이 네트워크 주소를 광고하는 데 유용해요. 드라이버 네트워크를 결정할 수 없으면 태스크가 실패해요. Docker에서만 구현됨. 이 모드는 "task" 블록에 정의된 서비스에만 설정할 수 있어요.

    • host - 호스트 IP와 포트를 사용.

  • task (string: "") - 이 서비스 정의와 연관된 Nomad 태스크 이름. 그룹 서비스에서만 사용 가능. 이 서비스 정의가 Consul 서비스 메시 네이티브 서비스를 나타내고 태스크 그룹에 태스크가 둘 이상이면 반드시 설정해야 해요.

  • meta ([Meta][]: nil) - Consul 서비스에 사용자 정의 메타데이터로 주석을 다는 키-값 맵. provider = "consul"일 때만 사용 가능.

  • canary_meta ([Meta][]: nil) - 서비스가 현재 카나리인 할당의 일부일 때 Consul 서비스에 사용자 정의 메타데이터로 주석을 다는 키-값 맵. 카나리가 승격되면 등록된 meta가 meta 매개변수에 지정된 것으로 업데이트돼요. 제공되지 않으면 등록된 meta는 meta 매개변수의 것으로 설정돼요. provider = "consul"일 때만 사용 가능.

  • on_update (string: "require_healthy") - 배포 건강 상태(잡의 초기 배포 포함)를 결정할 때 체크를 어떻게 평가할지 지정. 잡 제출자가 특정 체크를 준비(readiness) 체크로 정의할 수 있게 해서, 서비스의 체크가 아직 healthy하지 않아도 배포를 진행할 수 있어요. 체크는 기본적으로 서비스 값을 상속해요. 체크 상태는 Consul에서 바뀌지 않으며 업데이트 중 체크의 건강 상태를 결정하는 데만 사용돼요.

    • require_healthy - Nomad가 업데이트 중 체크를 healthy로 간주하려면 체크가 healthy로 보고해야 함.
    • ignore_warnings - 서비스 체크가 warning으로 보고되면 Nomad는 체크를 healthy로 취급. 체크는 여전히 Consul에서 warning 상태로 남아요.
    • ignore - 어떤 상태든 healthy로 취급.

주의: on_update는 특정 check_restart 구성과만 호환돼요. on_update = "ignore_warnings"는 check_restart.ignore_warnings = true를 요구해요. 그러나 check_restart는 on_update = "require_healthy"와 함께 ignore_warnings = true를 지정할 수 있어요. on_update가 ignore로 설정되면 check_restart를 완전히 생략해야 해요.

수명주기 (Lifecycle)

Nomad는 서비스 공급자와의 서비스 등록, 업데이트, 등록 해제를 관리해요. 이러한 각 단계가 언제 발생하고 어떻게 사용자 정의할 수 있는지 이해하는 것이 중요해요.

등록 (Registration): Nomad는 어떤 태스크를 시작하기 전에 group 서비스와 체크를 등록해요. 특정 task의 서비스와 체크는 태스크가 시작된 후에 등록돼요.

업데이트 (Updating): 서비스 또는 체크 정의가 업데이트되면 Nomad도 공급자의 서비스를 업데이트해요. 이 업데이트는 태스크를 재시작하지 않고 발생해요.

등록 해제 (Deregistering): service 블록이 있는 실행 중인 태스크가 종료되면 서비스와 체크는 지연 없이 즉시 공급자에서 등록 해제돼요. 그러나 Nomad가 실행 중인 태스크를 종료해야 한다면 태스크는 다음 순서로 종료돼요:

  1. 공급자에서 서비스와 체크를 즉시 제거. 이렇게 하면 종료 중인 태스크로의 새 트래픽 라우팅이 중지돼요.
  2. shutdown_delay가 설정되면 3단계로 진행하기 전에 구성된 시간을 기다림. 애플리케이션 자체가 kill_signal을 기반으로 우아한 종료를 처리하지 않는다면 shutdown_delay를 설정하는 것이 유용해요. 구성된 지연은 서비스가 더 이상 공급자에 등록되어 있지 않아 추가 요청을 받지 않지만 종료 신호를 받지 않은 기간을 제공해요. 이렇게 하면 애플리케이션이 요청을 완료하고 유휴 상태가 될 시간을 얻어요.
  3. kill_signal을 태스크에 보내고 태스크가 종료될 때까지 기다림. 태스크는 이 시간을 사용해 기존 요청을 우아하게 드레인하고 마무리해야 해요.
  4. kill_timeout 후에도 태스크가 종료되지 않으면 Nomad가 애플리케이션을 강제 종료해요.

예시 (Examples)

다음 예시는 service 블록만 보여줘요. service 블록은 위에 나열된 배치에서만 유효하다는 점을 기억하세요.

기본 서비스 (Basic service)

이 예시는 Nomad 공급자를 사용해 헬스 체크가 없는 "load-balancer"라는 서비스를 등록해요:

service {
  name     = "load-balancer"
  port     = "lb"
  provider = "nomad"
}

이 예시는 Consul 공급자를 사용해 헬스 체크가 없는 "load-balancer"라는 서비스를 등록해요:

service {
  name = "load-balancer"
  port = "lb"
}

이 예시들은 "lb"라고 레이블된 정적 또는 동적 포트를 정의하는 network 블록을 동반해야 해요. 예:

network {
  port "lb" {}
}

드라이버 주소 모드 사용 (Using driver address mode)

Docker 드라이버는 service와 check 블록 모두에서 address_mode 매개변수의 driver 설정을 지원해요. 드라이버 주소 모드는 태스크에 드라이버가 할당한 IP와 포트를 광고하고 헬스 체크할 수 있게 해요. 이렇게 하면 Docker와 함께 Weave 같은 네트워크 플러그인을 사용할 때 호스트 주소 대신 Weave 주소를 Consul에 광고할 수 있어요.

예를 들어 Weave가 있는 환경에서 예시 Redis 잡을 실행하고 Consul이 호스트에서 실행 중이라면 다음 구성을 사용할 수 있어요:

job "example" {
  datacenters = ["dc1"]

  group "cache" {
    network {
      port "db" {
        to = 6379
      }
    }

    task "redis" {
      driver = "docker"

      config {
        image = "redis:7"
        network_mode = "weave"
        ports = ["db"]
      }

      resources {
        cpu    = 500 # 500 MHz
        memory = 256 # 256MB
      }

      service {
        name = "weave-redis"
        port = "db"
        check {
          name     = "host-redis-check"
          type     = "tcp"
          interval = "10s"
          timeout  = "2s"
        }
      }
    }
  }
}

명시적 address_mode는 필요 없어요.

서비스는 기본적으로 auto 주소 모드를 사용해요. "host"나 "bridge"가 아닌 Docker 네트워크 모드를 사용하면 서비스가 자동으로 드라이버 주소(이 경우 Weave의)를 광고해요. 서비스는 컨테이너의 포트인 6379를 광고해요.

하지만 Consul은 종종 Weave 네트워크에 접근할 수 없는 호스트에서 실행되므로 check 블록은 기본적으로 host 주소 모드를 사용해요. TCP 체크는 호스트 IP와 Nomad가 할당한 동적 호스트 포트에 대해 실행돼요.

check는 여전히 service 블록의 db 포트 레이블을 상속하지만, 각각 자체 주소 모드에 따라 포트 레이블을 해석한다는 점에 유의하세요.

Consul이 Weave 네트워크에 접근할 수 있다면 잡은 다음과 같이 구성할 수 있어요:

job "example" {
  datacenters = ["dc1"]
  group "cache" {

    task "redis" {
      driver = "docker"

      config {
        image = "redis:7"
        network_mode = "weave"
        # No port map required.
      }

      resources {
        cpu    = 500 # 500 MHz
        memory = 256 # 256MB
      }

      service {
        name = "weave-redis"
        port = 6379
        address_mode = "driver"
        check {
          name     = "host-redis-check"
          type     = "tcp"
          interval = "10s"
          timeout  = "2s"
          port     = 6379

          address_mode = "driver"
        }
      }
    }
  }
}

이 경우 Nomad는 Redis에 호스트 포트를 할당할 필요가 없어요. service와 check 블록 모두 광고·체크할 포트 번호를 직접 지정할 수 있는데, Nomad가 포트 할당을 관리하지 않기 때문이에요.

IPv6 Docker 컨테이너 (IPv6 Docker containers)

Docker 드라이버는 구성에서 advertise_ipv6_address 매개변수를 지원해요.

advertise_ipv6_address를 사용하면 서비스가 자동으로 IPv6 주소를 광고해요.

서비스와 달리 체크에는 auto 주소 모드가 없어요. Nomad가 체크에 사용할 최고의 주소가 무엇인지 알 방법이 없기 때문이에요. Consul은 HTTP 또는 TCP 체크에 주소에 접근해야 해요.

따라서 check 블록에서 address_mode 매개변수를 driver로 설정해야 해요.

예를 들어 auto 주소 모드를 사용:

job "example" {
  datacenters = ["dc1"]
  group "cache" {

    network {
      port "db" {
        to = 6379
      }
    }


    task "redis" {
      driver = "docker"

      config {
        image = "redis:7"
        advertise_ipv6_address = true
        ports = ["db"]
      }

      resources {
        cpu    = 500 # 500 MHz
        memory = 256 # 256MB
      }

      service {
        name = "ipv6-redis"
        port = "db"
        check {
          name     = "ipv6-redis-check"
          type     = "tcp"
          interval = "10s"
          timeout  = "2s"
          port     = "db"
          address_mode = "driver"
        }
      }
    }
  }
}

또는 숫자 포트와 함께 service와 check에 address_mode=driver를 사용:

job "example" {
  datacenters = ["dc1"]

  group "cache" {

    task "redis" {
      driver = "docker"

      config {
        image = "redis:7"
        advertise_ipv6_address = true
        # No port map required.
      }

      resources {
        cpu    = 500 # 500 MHz
        memory = 256 # 256MB
      }

      service {
        name = "ipv6-redis"
        port = 6379
        address_mode = "driver"
        check {
          name     = "ipv6-redis-check"
          type     = "tcp"
          interval = "10s"
          timeout  = "2s"
          port     = 6379
          address_mode = "driver"
        }
      }
    }
  }
}

service와 check 블록 모두 광고·체크할 포트 번호를 직접 지정할 수 있는데, Nomad가 포트 할당을 관리하지 않기 때문이에요.

더 알아보기 (Learn more)