사전 선언적 설정
개념

선언적 설정

gabury1고친 사람 github-actions[bot]

선언적 설정은 시스템을 어떻게 만들지 대신 어떤 모습이어야 하는지만 적는 방식입니다. 「웹 서버가 세 대 떠 있어야 한다」처럼 결과만 적습니다. 그 모습으로 만드는 일은 도구가 맡습니다. 도구는 지금 모습을 살펴 모자란 것만 채웁니다. 그래서 같은 설정을 여러 번 적용해도 결과가 같습니다.

쉽고 빠른 이해

선언적 설정은 할 일의 순서 대신 끝났을 때의 모습을 적는 방식입니다. 「서버를 띄워라」를 세 번 적는 대신 「서버가 세 대 있어야 한다」를 한 번 적습니다.

이렇게 하는 까닭은 순서를 적은 스크립트가 지금 상태를 안 보기 때문입니다. 서버가 이미 세 대일 때 스크립트를 또 돌리면 여섯 대가 됩니다. 결과를 적어 두면 몇 번을 돌려도 세 대입니다.

어떻게 도나:

  1. 설정 파일에서 있어야 할 모습을 읽습니다
  2. 시스템이 지금 어떤지 살핍니다
  3. 둘이 다른 만큼만 만들거나 지우거나 고칩니다

대가도 있습니다. 무엇을 어떤 순서로 할지는 도구가 정합니다. 그래서 적용하기 전에는 도구가 무엇을 할지 짐작하기 어렵습니다. 한 번만 해야 하는 일이나 순서가 중요한 일은 이 방식으로 적기 어렵습니다.

상세

택시를 타면 손님은 목적지만 말합니다. 어느 길로 갈지, 어디서 꺾을지는 기사가 정합니다. 손님이 「직진, 다음 골목에서 좌회전」을 하나하나 불러 주는 것과는 다른 부탁입니다.

이 절은 웹 서버 세 대를 띄우는 일 하나를 두 방식으로 적어 봅니다. 순서를 적는 방식과 결과를 적는 방식입니다. 적용하기 전 서버 수가 달라질 때 두 방식의 결과가 어떻게 갈리는지를 봅니다. 거기서 선언적 설정의 쓸모와 대가를 끌어냅니다.

순서를 적는 방식

서버 한 대를 띄우는 명령 start_web 이 있다고 해 봅시다. 서버 세 대가 필요하면 이 명령을 세 번 적은 스크립트를 만듭니다. 아래는 서버가 하나도 없을 때 돌린 모습입니다. 오른쪽 주석은 그 줄을 마친 뒤 떠 있는 서버 수입니다.

터미널
start_web   # 1대
start_web   # 2대
start_web   # 3대

이렇게 할 일을 차례로 적은 스크립트를 명령형 스크립트라 합니다. 명령형은 「이것을 해라」라는 명령을 늘어놓는다는 뜻입니다. 스크립트는 지금 서버가 몇 대인지 보지 않습니다. 적힌 명령만 차례로 합니다.

그래서 서버가 이미 세 대일 때 같은 스크립트를 한 번 더 돌리면 여섯 대가 됩니다. 스크립트를 쓴 사람은 「세 대가 있어야 한다」를 원했습니다. 하지만 그 뜻은 스크립트 어디에도 적혀 있지 않습니다.

결과를 적는 방식

같은 일을 결과로 적으면 아래처럼 됩니다. 명령이 없습니다. 서버가 몇 대 떠 있어야 하는지와 어느 포트를 쓰는지만 있습니다.

YAML
웹서버:
  대수: 3
  포트: 8080

이렇게 끝났을 때의 모습을 적는 방식이 선언적 설정입니다. 선언은 「이렇다」고 밝혀 둔다는 뜻입니다. 이 파일을 읽고 시스템을 파일대로 맞추는 일은 따로 있는 도구가 맡습니다.

아래 표는 같은 목표를 두 방식으로 적용했을 때 끝난 뒤의 서버 수입니다. 적용하기 전에 떠 있던 서버 수를 0대·2대·3대·5대 네 경우로 바꿔 가며 견줍니다.

적용 전 명령형 스크립트 선언적 설정
0대 3대 3대 · 세 대를 띄움
2대 5대 3대 · 한 대를 띄움
3대 6대 3대 · 아무것도 안 함
5대 8대 3대 · 두 대를 내림

명령형 스크립트의 결과는 시작 상태에 따라 달라집니다. 선언적 설정의 결과는 늘 3대입니다. 도구가 할 일이 시작 상태에 따라 바뀌었기 때문입니다.

원하는 상태와 실제 상태

선언적 설정을 다루려면 두 낱말이 필요합니다. 설정 파일에 적힌 모습을 원하는 상태라 합니다. 위 예에서는 「웹 서버 세 대, 포트 8080」입니다.

시스템이 지금 돌고 있는 모습은 실제 상태라 합니다. 서버가 두 대만 떠 있다면 실제 상태는 「웹 서버 두 대」입니다. 이 값은 파일이 아니라 시스템을 들여다봐야 압니다.

선언적 설정을 적용하는 일은 실제 상태를 원하는 상태로 옮기는 일입니다. 두 상태가 처음부터 같으면 할 일이 없습니다.

차이만큼만 움직이는 도구

선언적 설정을 적용하는 도구는 늘 같은 순서로 움직입니다. 먼저 원하는 상태를 읽습니다. 다음에 실제 상태를 살핍니다. 둘을 견준 뒤 다른 곳만 고칩니다.

flowchart TD
    A["설정 파일을 읽는다 · 원하는 상태"] --> C{"두 상태가 같나"}
    B["시스템을 살핀다 · 실제 상태"] --> C
    C -->|같다| D["아무것도 안 한다"]
    C -->|다르다| E["다른 만큼만 고친다"]

고치는 방법은 차이의 모양에 따라 셋으로 갈립니다. 원하는 상태에만 있는 것은 만듭니다. 실제 상태에만 있는 것은 지웁니다. 양쪽에 있으나 값이 다른 것은 고칩니다.

차이 예 도구가 하는 일
모자람 서버가 두 대뿐이다 한 대를 더 띄운다
넘침 서버가 다섯 대다 두 대를 내린다
값이 다름 포트가 9090 이다 8080 으로 바꾼다

이 비교를 한 번 하고 끝내는 도구가 있습니다. 사람이 적용 명령을 칠 때만 비교합니다.

비교를 쉬지 않고 되풀이하는 도구도 있습니다. 이렇게 되풀이하는 구조를 조정 루프라 합니다. 조정 루프는 누가 서버 한 대를 손으로 꺼도 다음 비교에서 알아채고 다시 띄웁니다.

몇 번 적용해도 같은 결과

같은 일을 몇 번 해도 한 번 한 것과 결과가 같은 성질을 멱등성이라 합니다. 선언적 설정은 이 성질을 방식 자체에서 얻습니다. 두 번째 적용 때는 두 상태가 이미 같아서 도구가 할 일이 없기 때문입니다.

이 성질은 적용이 중간에 끊겼을 때 값을 합니다. 서버 세 대 중 두 대를 띄운 뒤 네트워크가 끊겼다고 해 봅시다. 같은 설정을 다시 적용하면 도구는 남은 한 대만 띄웁니다. 어디까지 했는지 사람이 따질 필요가 없습니다.

명령형 스크립트도 멱등하게 짤 수 있습니다. 명령마다 「이미 떠 있나」를 먼저 확인하는 줄을 넣으면 됩니다. 대신 그 확인을 명령마다 사람이 직접 짜야 합니다. 선언적 설정에서는 그 확인을 도구가 대신 합니다.

있어야 할 모습의 기록이 되는 파일

선언적 설정 파일은 시스템이 어떤 모습이어야 하는지를 한 곳에 적은 기록이 됩니다. 곧 원하는 상태의 기록입니다. 명령형 스크립트는 그렇지 않습니다. 스크립트를 읽으면 무엇을 했는지는 알아도 어떤 모습이어야 하는지는 모릅니다.

시스템을 바꿀 때 늘 이 파일을 고쳐 적용하면 이 기록은 실제 상태와도 같아집니다. 누군가 서버에 들어가 손으로 값을 바꾸면 실제 상태가 파일과 어긋납니다. 이 어긋남이 쌓이는 일을 구성 드리프트라 합니다. 조정 루프나 주기적인 재적용은 이런 어긋남을 다시 파일대로 되돌립니다.

이 파일을 Git 같은 버전관리 도구에 넣으면 시스템의 변경 이력이 커밋으로 남습니다. 누가 언제 서버 수를 3에서 5로 바꿨는지가 코드 변경처럼 보입니다. 변경 전에 코드 리뷰를 거칠 수도 있습니다. 서버와 네트워크 설정을 이렇게 코드처럼 다루는 방식을 코드형 인프라라 합니다.

선언적 설정이 치르는 대가

순서를 도구가 정하므로 사람이 순서를 고르기 어렵습니다. 「데이터를 옮긴 뒤에 옛 서버를 끈다」처럼 순서가 중요한 일은 결과만으로는 적히지 않습니다.

한 번만 해야 하는 일도 결과로 적기 어렵습니다. 데이터베이스 표 구조를 바꾸는 스키마 마이그레이션이 대표적입니다. 새 표 구조는 결과로 적을 수 있습니다. 하지만 옛 구조에 쌓인 데이터를 새 구조에 맞게 옮기는 일은 모습이 아니라 한 번 거쳐야 하는 과정입니다.

적용했을 때 도구가 무엇을 할지 파일만 보고 짐작하기 어렵습니다. 파일에서 한 줄을 지우면 도구가 그 줄에 해당하는 서버나 저장소까지 지워 버리기도 합니다. 그래서 많은 도구가 적용 전에 할 일 목록만 먼저 보여 주는 단계를 둡니다. 이 단계를 드라이 런이라 부릅니다.

환경마다 조금씩 다른 설정이 필요해지면 파일이 복잡해집니다. 개발 서버는 한 대, 운영 서버는 세 대 같은 차이를 담으려고 변수와 조건을 넣게 됩니다. 이것이 늘면 설정 파일이 점점 프로그래밍 언어를 닮아 갑니다.

아래 표는 이 대가를 기준으로 어느 쪽이 맞는지 가른 것입니다.

일의 성격 맞는 방식
늘 같은 모습을 유지해야 하는 서버·네트워크·권한 선언적 설정
여러 번 적용되거나 중간에 끊길 수 있는 작업 선언적 설정
한 번만 하는 데이터 이동·표 구조 변경 명령형 스크립트
단계마다 앞 결과를 보고 다음을 정하는 작업 명령형 스크립트

설정 밖의 선언형

결과만 적고 방법을 맡기는 생각은 설정 파일에만 있는 것이 아닙니다. 이런 식으로 프로그램을 짜는 방식 전체를 선언형 프로그래밍이라 합니다. 백엔드 개발자가 매일 쓰는 것 가운데도 있습니다.

SQL(Structured Query Language, 구조화 질의 언어)이 그렇습니다. SELECT 문은 어떤 행을 원하는지만 적습니다. 인덱스를 탈지 표를 끝까지 훑을지는 데이터베이스가 정합니다. 선언적 설정은 같은 생각을 서버와 인프라를 꾸리는 일에 옮긴 것입니다.

관련 항목

선언적 설정과 맞세워지는 방식

명령형 스크립트 · 명령형 프로그래밍 · 절차적 프로그래밍 · 셸 스크립트

선언적 설정을 적용하는 동작 원리

원하는 상태 · 실제 상태 · 조정 루프 · 제어 루프 · 제어 평면 · 수렴 · 멱등성 · 드라이 런

선언적 설정을 쓰는 운영 방식

코드형 인프라 · 설정 관리 · GitOps · 불변 인프라 · 단일 진실 공급원 · 버전관리 · 코드 리뷰

선언적 설정을 채택한 도구

Kubernetes · 테라폼 · 앤서블 · CloudFormation · Docker Compose

선언적 설정을 적는 파일 형식

YAML · JSON · HCL · 설정 파일 · 매니페스트

선언적 설정이 막으려는 장애

구성 드리프트 · 눈송이 서버 · 설정 오류 · 부분 배포

선언형이라는 생각을 공유하는 언어

선언형 프로그래밍 · SQL · HTML · CSS

선언적 설정이 속하는 상위 분야

인프라 · 데브옵스 · 배포 · 플랫폼 엔지니어링

다른 이름: declarative configuration · 선언형 설정 · 선언적 구성 · 선언형 구성