변수
변수 (Variables)
이 페이지는 Nomad 변수 기능에 대한 개념 정보를 제공해요. 이 기능을 사용하면 작업 스펙(job specification)에서 암호화된 구성 데이터를 저장하고 사용할 수 있어요. Access Control List (ACL) 정책이 네임스페이스 내 변수에 대한 접근을 어떻게 제한하는지, 작업 태스크의 워크로드 아이덴티티가 변수에 어떻게 접근을 부여하는지, 그리고 변수를 잠그면(lock) 그 변수에 대한 접근을 어떻게 차단하는지 알아봐요.
출처: 문서
본문
소개 (Introduction)
대부분의 Nomad 워크로드는 구성 값이나 시크릿에 접근해야 해요. Nomad에는 이러한 값을 태스크에 제공하는 template 블록이 있어요. Nomad 변수는 파일과 같은 경로에 구성 데이터를 Nomad의 상태 저장소(state store)에 직접 저장할 수 있는 옵션을 제공해서, 태스크 템플릿에서 이러한 변수에 직접 접근할 수 있게 해줘요. Nomad는 이러한 변수의 내용을 서버 간에 Raft 통신으로 암호화하고 복제해요. 변수에 대한 접근은 ACL 정책으로 제어되며, 태스크는 자신의 변수에 접근할 수 있는 암묵적 ACL 정책을 가져요. 커맨드라인, Nomad API, 또는 Nomad 웹 UI에서 변수를 생성·읽기·업데이트·삭제할 수 있어요.
변수 기능은 워크로드가 필요로 하는 작은 구성 데이터를 위한 것임을 참고해 주세요. Nomad 상태 저장소에 쓰는 것은 Nomad가 필요로 하는 리소스를 사용하기 때문에, 크거나 빠르게 변하는 데이터에는 적합하지 않아요. 예를 들어 배치 작업 결과를 변수로 저장하지 마세요. 이들은 외부 데이터베이스에 저장해야 해요. 변수는 또한 HashiCorp Vault의 완전한 대체가 되도록 의도된 것이 아니에요. Vault와 달리 Nomad는 루트 암호화 키를 서버에 저장해요. 자세한 내용은 Key Management를 참고해요.
정책 (Policies)
모든 변수는 특정 Nomad 네임스페이스에 속해요. ACL 정책은 네임스페이스의 variables 아래에 위치한 path 블록 목록을 사용해, 네임스페이스 내 변수에 대한 접근을 경로별로 제한할 수 있어요. ACL 정책의 구문과 구조에 대한 자세한 내용은 ACL 정책 스펙을 참고해요.
경로 정의에는 와일드카드 기호를 포함할 수 있어, 단일 경로 정책 정의가 해당 네임스페이스 내 경로 집합에 적용되도록 할 수 있어요.
다음 예시에서 정책은 dev 네임스페이스에서 project/ 접두사가 붙은 모든 경로(하위 경로 포함)의 변수에 대한 전체 접근을 허용하지만, system/ 접두사가 붙은 경로에는 읽기 접근만 허용해요. 와일드카드는 빈 문자열과 다른 모든 문자를 일치시킬 수 있다는 점을 참고해 주세요. 이 정책은 system/ 접두사가 붙은 경로에는 읽기 접근을 부여하지만, system(끝 슬래시가 없는)이라는 이름의 경로에는 부여하지 않아요.
namespace "dev" {
policy = "write"
capabilities = ["alloc-node-exec"]
variables {
# full access to variables in all "project" paths
path "project/*" {
capabilities = ["write", "read", "destroy", "list"]
}
# read/list access within a "system/" path belonging to administrators
path "system/*" {
capabilities = ["read"]
}
}
}
변수에 사용 가능한 기능(capabilities)은 다음과 같아요.
| 기능 (Capability) | 참고 (Notes) |
|---|---|
| write | 이 경로에서 변수를 생성하거나 업데이트해요. "list" 기능을 포함하지만 "read"나 "destroy" 기능은 포함하지 않아요. |
| read | 이 경로의 변수 복호화된 내용을 읽어요. 또한 "list" 기능을 포함해요. |
| list | 이 경로의 변수 내용이 아닌 메타데이터를 나열해요. |
| destroy | 이 경로의 변수를 삭제해요. |
태스크의 변수 접근 (Task access to variables)
태스크는 template 블록이나 Task API를 사용해 변수에 접근할 수 있어요. 각 태스크의 워크로드 아이덴티티는 nomad/jobs/ 접두사가 붙은 Nomad 소유 경로에 있는 변수에 대해, 그 뒤에 작업 ID, 태스크 그룹 이름, 태스크 이름이 이어지는 경로에 대해 자동으로 읽기·나열 접근을 부여해요. 이것은 다음 정책과 동일해요.
namespace "$namespace" {
variables {
path "nomad/jobs" {
capabilities = ["read", "list"]
}
path "nomad/jobs/$job_id" {
capabilities = ["read", "list"]
}
path "nomad/jobs/$job_id/$task_group" {
capabilities = ["read", "list"]
}
path "nomad/jobs/$job_id/$task_group/$task_name" {
capabilities = ["read", "list"]
}
}
}
예를 들어 "example"이라는 작업의 "cache" 그룹에 있는 "redis"라는 이름의 태스크는, 다음 정책을 가진 것처럼 자동으로 변수에 접근해요.
namespace "default" {
variables {
path "nomad/jobs" {
capabilities = ["read", "list"]
}
path "nomad/jobs/example" {
capabilities = ["read", "list"]
}
path "nomad/jobs/example/cache" {
capabilities = ["read", "list"]
}
path "nomad/jobs/example/cache/redis" {
capabilities = ["read", "list"]
}
}
}
태스크의 워크로드 아이덴티티와 연관된 정책을 만들어 추가 변수에 대한 접근을 제공할 수 있어요. 예를 들어 위 태스크에 "shared" 네임스페이스의 모든 변수에 대한 접근을 부여하려면 다음 정책 파일을 만들 수 있어요.
namespace "shared" {
variables {
path "*" {
capabilities = ["read"]
}
}
}
그런 다음 정책을 만들고 특정 태스크와 연관시켜요.
nomad acl policy apply \
-namespace default -job example -group cache -task redis \
redis-policy ./policy.hcl
정책의 우선순위와 변수에 대한 자동 태스크 접근은 ACL 정책 네임스페이스 규칙과 유사해요. 경로에 가장 구체적인 규칙이 적용되므로, 워크로드 부착(attached) 정책의 정확한 경로 규칙은 변수에 대한 자동 태스크 접근을 덮어쓰지만 와일드카드 규칙은 그렇지 않아요.
예를 들어 prod 네임스페이스의 job example, group web, 그리고 httpd라는 태스크가 다음 정책을 적용받는다고 생각해 봐요.
namespace "*" {
variables {
path "nomad/jobs" {
capabilities = ["list"]
}
path "nomad/jobs/*" {
capabilities = ["deny"]
}
}
}
태스크는 prod 네임스페이스에서 자신의 변수 nomad/jobs/example, nomad/jobs/example/web, nomad/jobs/example/web/httpd에 읽기/나열 접근을 가져요. 왜냐하면 그것들이 접근을 거부하는 와일드카드 규칙보다 더 구체적이기 때문이에요. 태스크는 모든 네임스페이스에서 nomad/jobs에 대해 나열 접근을 가져요. 왜냐하면 그 경로가 nomad/jobs 변수에 대한 자동 태스크 접근보다 더 구체적이기 때문이에요. 그리고 prod 이외의 네임스페이스에서는 nomad/jobs/example(또는 그 아래)에 접근할 수 없어요. 왜냐하면 자동 접근 규칙이 적용되지 않기 때문이에요.
자세한 내용은 Workload Associated ACL Policies를 참고해요.
잠금 (Locks)
Nomad는 변수에 잠금을 설정해 일정 기간 변수가 업데이트되는 것을 차단하는 기능을 제공해요. 변수가 잠기면 모든 사람이 읽을 수 있지만, 잠금 보유자만 업데이트할 수 있어요.
잠금은 세분화된 잠금을 제공하도록 설계되었으며, 느슨하게 결합된 분산 시스템을 위한 Chubby Lock Service에서 큰 영감을 받았어요.
잠금은 ID, TTL, 잠금 지연(lock delay)으로 구성돼요. ID는 Nomad 서버가 생성하며, 변수의 항목이나 잠금 자체를 수정하는 모든 요청에 제공되어야 해요. TTL은 잠금이 보유될 시간을 정의하며, 더 오래 유지해야 한다면 원하는 만큼 새 기간으로 갱신할 수 있어요.
더 이상 필요하지 않으면 해제해야 해요. TTL이 만료될 때까지 갱신이나 해제 호출이 없었다면, 두 보유자가 동시에 존재하는 스플릿 브레인(split-brain) 상황을 피하기 위해 변수는 적어도 잠금 지연 기간 동안 잠긴 상태로 유지돼요.
Nomad 변수 잠금을 통한 리더 선출 (Leader election backed by Nomad variable locks)
HDFS나 Nomad Autoscaler 같은 일부 애플리케이션은 장애 시 중복성을 보장하기 위해 여러 인스턴스를 실행해야 하지만, 한 번에 하나만 리더로 활성 상태여야 해요.
Go Package의 일부로, Nomad는 하나의 변수를 취해 그 위에 잠금을 동기화 메커니즘으로 사용해 여러 인스턴스를 실행하되 항상 한 번에 하나만 실행되도록 하는 헬퍼를 제공해요. 알고리즘은 다음과 같아요.
인스턴스가 시작되자마자 동기화 변수를 잠그려고 시도해요. 성공하면 보조 스레드가 잠금 추적과 필요한 갱신을 담당하는 동안 계속 실행해요. 갱신이 실패하면 메인 프로세스는 강제로 반환되고, 인스턴스는 동기화 변수의 잠금을 획득하려고 다시 시도할 때까지 대기(standby) 상태가 돼요.
한 번에 스레드 1과 3 또는 스레드 2만 실행돼요. 왜냐하면 모든 인스턴스가 잠금을 갱신하면서 정상 실행하거나, 잠금을 획득해 실행할 기회를 기다리기 때문이에요.
메인 프로세스 또는 보호된 함수가 반환하면 헬퍼가 잠금을 해제해 두 번째 인스턴스가 실행을 시작할 수 있게 해요.
실제 구현을 보려면 nomad var lock 명령어 구현 또는 Nomad Autoscaler High Availability 구현을 확인해요.