핵심 인사이트 (3줄 요약)
- 본질: 선언형 (Declarative)은 원하는 최종 상태를 기술하고 시스템이 그 상태로 수렴하게 만드는 방식이며, 명령형 (Imperative)은 사람이 실행 순서와 예외 처리까지 직접 지휘하는 방식이다.
- 가치: 선언형은 멱등성, 차이 비교, 감사 추적, 자동 복구에 강하고, 명령형은 부트스트랩, 복잡한 조건 분기, 일회성 절차에서 더 높은 표현력을 준다.
- 판단 포인트: 장기 운영할 인프라 기준선은 선언형으로 두고, 순서 자체가 핵심인 예외 작업만 명령형으로 분리해야 운영 복잡도와 드리프트가 폭증하지 않는다.
Ⅰ. 개요 및 필요성
클라우드 인프라를 Infrastructure as Code (IaC)로 다룰 때 가장 먼저 갈리는 축은 "무엇이 되어야 하는가"를 적을지, "어떻게 만들 것인가"를 적을지다. 선언형은 목표 상태를 적고 도구가 현재 상태와 비교해 필요한 변경만 수행한다. 반면 명령형은 생성, 수정, 연결, 검증 순서를 사람이 직접 써 내려가며, 실패했을 때의 복구 책임도 스크립트 작성자에게 남는다.
초기 클라우드 운영은 Command Line Interface (CLI)나 Shell Script 중심의 명령형 접근이 자연스러웠다. 작은 규모에서는 빠르고 직관적이지만, 팀이 커지고 환경이 늘어나면 "같은 스크립트를 다시 돌려도 안전한가", "누가 콘솔에서 바꿨는가", "실패 후 어디까지 적용되었는가"가 더 큰 문제가 된다. 이 지점에서 선언형 접근이 중요해진다.
아래 그림은 같은 목표라도 운영 책임이 어디에 놓이는지가 다름을 보여준다.
┌────────────────────────────────────────────────────────────────────┐
│ Same goal, different ownership of change │
├───────────────────────────────┬────────────────────────────────────┤
│ Imperative │ Declarative │
├───────────────────────────────┼────────────────────────────────────┤
│ step 1: create network │ network.cidr = 10.0.0.0/16 │
│ step 2: create subnet │ subnet.count = 3 │
│ step 3: attach route │ route.private = nat-gw │
│ fail at step 2 => partial │ diff engine => converge to target │
│ rollback logic is manual │ retry => same target, same result │
└───────────────────────────────┴────────────────────────────────────┘
운영자가 원하는 것은 "명령을 많이 친 사실"이 아니라 "환경이 원하는 모습으로 유지되는 사실"이다. 선언형은 바로 이 유지 문제를 해결하기 위해 등장했고, Kubernetes와 Terraform이 널리 채택되면서 현대 클라우드 운영의 기본 철학이 되었다.
- 📢 섹션 요약 비유: 명령형은 가구를 조립하는 순서를 한 칸씩 불러 주는 방식이고, 선언형은 "거실에 책장이 하나 있어야 한다"는 완성 사진을 주고 공구함이 알아서 맞추게 하는 방식이다.
Ⅱ. 아키텍처 및 핵심 원리
선언형과 명령형의 차이는 문법보다 제어 루프에 있다. 선언형 도구는 Desired State를 입력으로 받아 실제 상태를 읽고, 차이를 계산한 뒤 필요한 변경만 적용한다. 이 입력은 보통 Git에 저장된 HashiCorp Configuration Language (HCL)나 YAML Ain't Markup Language (YAML) 같은 선언 파일이다. 반면 명령형 도구는 작성된 순서대로 Application Programming Interface (API)를 호출하며, 중간 실패와 부분 적용을 직접 다뤄야 한다.
┌────────────────────────────────────────────────────────────────────┐
│ Declarative control loop │
├────────────────────────────────────────────────────────────────────┤
│ Git / HCL / YAML │
│ │ │
│ ▼ │
│ Planner / Controller │
│ │ compare desired vs actual │
│ ▼ │
│ Cloud API / Cluster API │
│ │ │
│ ▼ │
│ Actual State ────────────────┐ │
│ ▲ │ drift / refresh │
│ └───────────────────────┘ │
└────────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────────┐
│ Imperative execution path │
├────────────────────────────────────────────────────────────────────┤
│ Script step1 -> step2 -> step3 -> step4 │
│ │ │ │
│ └─ fail here => partial state + explicit recovery needed │
└────────────────────────────────────────────────────────────────────┘
| 비교 항목 | 선언형 접근 | 명령형 접근 |
|---|---|---|
| 입력 | 목표 상태 | 절차와 순서 |
| 성공 기준 | 실제 상태 = 원하는 상태 | 각 명령이 순서대로 성공 |
| 재실행 | 보통 No-op 또는 차이만 반영 | 조건문 없으면 중복 실행 위험 |
| 드리프트 처리 | Diff/Refresh로 감지 가능 | 별도 진단 로직 필요 |
| 의존성 관리 | 엔진이 그래프를 계산 | 사람이 순서를 설계 |
| 장애 복구 | 다시 Apply해 수렴 | 재시도·롤백 스크립트 필요 |
중요한 포인트는 선언형도 내부적으로는 결국 명령을 실행한다는 사실이다. 차이는 "순서를 없앴다"가 아니라 "순서와 차이 계산의 책임을 도구가 가져갔다"는 데 있다. 그래서 선언형의 핵심 역량은 텍스트 문법이 아니라 상태 추적, 멱등성, Reconciliation Loop다.
- 📢 섹션 요약 비유: 선언형은 내비게이션에 목적지만 넣는 방식이고, 명령형은 "직진 300m, 우회전, 다시 좌회전"을 종이에 적어 주는 방식이다. 길을 다시 계산하는 책임이 누구에게 있느냐가 핵심이다.
Ⅲ. 비교 및 연결
실무 도구를 보면 두 철학은 깔끔하게 양분되지 않는다. Terraform과 Kubernetes는 대표적 선언형이고, Amazon Web Services (AWS) CLI나 Shell Script는 대표적 명령형이다. 하지만 Ansible은 모듈 수준에서는 선언형에 가깝고, shell 태스크를 쓰면 다시 명령형이 된다. 즉 도구 이름보다 "상태를 누가 소유하는가"를 봐야 한다.
| 도구/패턴 | 기본 성향 | 왜 그렇게 보나 |
|---|---|---|
| Terraform | 선언형 | 리소스와 원하는 속성을 기술하고 Plan/Apply가 차이를 계산 |
Kubernetes apply | 선언형 | API Server와 Controller가 Desired State를 계속 수렴 |
Ansible package, service | 준선언형 | 현재 상태를 확인하고 필요한 조치만 수행 |
| Shell Script / Amazon Web Services (AWS) CLI | 명령형 | 단계와 조건, 예외 복구를 사용자가 직접 작성 |
kubectl run, kubectl edit | 명령형 성향 | 즉석 변경은 빠르지만 Git 기준선과 멀어지기 쉬움 |
선언형 접근은 GitOps, 멱등성, 드리프트 탐지와 강하게 연결된다. 반대로 명령형 접근은 부트스트랩, 데이터 마이그레이션, 장애 시 임시 우회처럼 "절차 자체가 비즈니스 로직"인 작업과 잘 맞는다. 예를 들어 Terraform 백엔드를 처음 만드는 초기 단계나, 데이터베이스 스키마를 안전한 순서로 변경하는 작업은 명령형 절차가 더 분명할 수 있다.
반대로 장기적으로 살아 있는 네트워크, 보안 정책, Kubernetes Deployment 같은 자원을 명령형만으로 관리하면 운영 부담이 누적된다. 왜냐하면 "현재 무엇이 맞는 상태인가"라는 기준이 스크립트 곳곳에 흩어지고, 콘솔 수동 수정이 섞이면 재실행 신뢰도가 빠르게 무너지기 때문이다.
- 📢 섹션 요약 비유: 선언형과 명령형은 망치와 드라이버의 관계가 아니라, 설계도와 작업지시서의 관계에 더 가깝다. 오래 유지할 건물은 설계도가 필요하고, 특별 공정은 작업지시서가 필요하다.
Ⅳ. 실무 적용 및 기술사 판단
실무에서는 "둘 중 하나만 순수하게 사용"하기보다 경계를 명확히 나누는 것이 중요하다. 기준선이 되는 인프라는 선언형으로 두고, 예외 절차는 별도 파이프라인 단계나 운영 스크립트로 분리해야 한다. 선언형 파일 안에 과도한 local-exec, shell, kubectl edit 관행을 숨기면 겉만 선언형이고 실제 운영은 명령형 부채가 된다.
┌────────────────────────────────────────────────────────────────────┐
│ Selection guide │
├────────────────────────────────────────────────────────────────────┤
│ Is it a long-lived desired state? │
│ ├─ yes -> prefer declarative │
│ │ (IaC, Git review, drift detection, safe re-apply) │
│ └─ no │
│ │ │
│ ▼ │
│ Is strict sequence / human checkpoint the main value? │
│ ├─ yes -> imperative with guard, log, rollback plan │
│ └─ no -> wrap into declarative or operator pattern │
└────────────────────────────────────────────────────────────────────┘
| 상황 | 권장 판단 | 이유 |
|---|---|---|
| Virtual Private Cloud (VPC), Identity and Access Management (IAM), Load Balancer 같은 기준선 인프라 | 선언형 | 감사, 재현, 재실행 안전성이 핵심 |
| Kubernetes 애플리케이션 배포 | 선언형 | 롤링 업데이트와 자동 복구가 컨트롤러 철학과 맞음 |
| 백엔드 부트스트랩, 원타임 마이그레이션 | 명령형 + 체크포인트 | 순서와 중간 검증이 중요 |
| 장애 시 임시 우회 | 명령형 가능, 이후 선언형에 환원 | 긴급 조치는 빠르게, 기준선은 다시 코드화 |
| 복잡한 조건 분기 자동화 | 명령형 또는 Operator | 상태보다 절차가 핵심일 수 있음 |
안티패턴
- 선언형 도구 안에서 외부 스크립트를 남발해 실제 상태를 숨기는 것
- 운영 중 콘솔에서 고친 내용을 Git과 IaC에 반영하지 않는 것
- 장기 자원을 일회성 스크립트로만 관리해 "정답 상태"가 문서화되지 않는 것
- 명령형이 더 쉽다는 이유로 드리프트 탐지와 재현성을 포기하는 것
기술사 답안에서는 "선언형이 우월하다"보다 "기준선은 선언형, 절차성 예외는 명령형"이라는 판단 구조를 제시하는 편이 좋다. 핵심은 도구 선택이 아니라 운영 책임 분리다.
- 📢 섹션 요약 비유: 학교 운영에서 시간표는 선언형이고, 소풍 당일 비가 와서 실내 행사로 바꾸는 안내 방송은 명령형이다. 학교 전체는 시간표로 굴리고, 예외 상황만 방송으로 처리해야 질서가 유지된다.
Ⅴ. 기대효과 및 결론
선언형 접근이 잘 자리 잡으면 인프라는 "한 번 성공하는 스크립트"가 아니라 "계속 같은 상태로 수렴하는 시스템"이 된다. 그 결과 코드 리뷰, 변경 추적, 재해 복구, 환경 복제, GitOps 자동화까지 연결된다. 특히 팀 규모가 커질수록 선언형은 기술 편의보다 조직적 안정성 효과가 더 크다.
물론 선언형이 모든 문제를 해결하는 것은 아니다. 데이터 마이그레이션, 외부 승인 절차, 순서가 중요한 배치 작업처럼 상태보다 절차가 중요한 영역은 여전히 명령형이 더 적합하다. 또한 선언형 도구도 상태 저장소, 잠금, 드리프트 관리가 허술하면 쉽게 신뢰를 잃는다.
결국 이 주제는 "무엇이 더 현대적인가"가 아니라 "누가 운영 복잡도를 짊어질 것인가"의 문제로 기억해야 한다. 장기 상태는 선언형에 맡기고, 절차적 예외만 명령형으로 격리하는 설계가 가장 실용적이다.
- 📢 섹션 요약 비유: 선언형은 집의 청사진이고, 명령형은 공사 당일 작업 순서표다. 청사진 없이 집을 오래 관리할 수 없고, 순서표 없이 특수 공정을 처리할 수도 없다.
📌 관련 개념 맵
| 개념 | 연결 포인트 |
|---|---|
| Desired State | 선언형 접근의 기준선, "무엇이 되어야 하는가"를 정의 |
| Idempotency | 같은 선언을 다시 적용해도 같은 결과로 수렴하는 성질 |
| Drift | 실제 상태가 코드에서 벗어난 상태, 선언형 운영의 핵심 관측 대상 |
| Reconciliation Loop | 현재 상태와 목표 상태의 차이를 계속 줄이는 제어 구조 |
| GitOps | Git을 Desired State의 단일 진실원천으로 두는 운영 모델 |
| Bootstrap Script | 선언형 제어면을 만들기 전 필요한 최소한의 명령형 절차 |
📈 관련 키워드 및 발전 흐름도
Manual ClickOps / Shell Script
│
├─ problem: hidden order, drift, retry fear
▼
Infrastructure as Code (IaC)
│
├─ Declarative: Terraform / Kubernetes / GitOps
└─ Imperative: bootstrap / migration / emergency fix
▼
State ownership + safe re-apply + audited change management
이 흐름은 인프라 운영이 "명령 실행"에서 "상태 수렴 관리"로 이동해 온 과정과, 여전히 남는 절차성 예외 작업의 위치를 함께 보여준다.
👶 어린이를 위한 3줄 비유 설명
- 선언형은 "방에 책상 하나가 있어야 해"라고 완성된 모습을 말하는 거예요.
- 명령형은 "책상 가져오고, 여기 놓고, 나사 조여"처럼 순서를 하나씩 말하는 거예요.
- 방을 오래 같은 모습으로 지키려면 목표 모양은 선언형으로 정하고, 특별한 심부름만 따로 시키는 게 좋아요.