Infra Architecture/Compute Platforms

Compute Platforms - 09. 이미지 빌드와 Immutable Infrastructre

서버를 만들고 고치지 않는다 — 이미지 빌드와 Immutable Infrastructure

2010년, Netflix의 엔지니어 Cory Scott과 Ruslan Belkin은 매일 수천 대의 서버를 재배포하는 시스템을 구축했다. 서버가 장애 나면 고치는 게 아니라 — 버리고 새로 만들었다. 서버 한 대를 고치는 데 30분이면, 이미지로 새 서버를 만드는 데 5분이었다. "고치는 것"보다 "새로 만드는 것"이 더 싸고 빠르고 일관된다. 이 철학을 Immutable Infrastructure(불변 인프라) 라 부른다. foundations 06의 IaC 글에서 잠깐 소개했고, 이 글은 그것을 구체 도구로 풀어간다.

이 글은 서버 이미지를 만들고, 그 이미지로 서버를 양산하는 과정을 다룬다. Packer로 golden image를 만들고, Ansible·Chef·Puppet으로 설정을 적용하고, 클라우드 AMI(Amazon Machine Image)로 배포하는 흐름. foundations 06에서 본 "mutable vs immutable"의 개념을 — 실제 도구와 워크플로로 번역하는 글이다. "서버를 소모품으로"가 어떻게 실천되는지.

Mutable vs Immutable — 두 가지 철학

이미지 빌드를 이해하려면, 서버 관리의 두 패러다임을 먼저 봐야 한다.

Mutable(가변) 인프라 — 서버를 만든 뒤 계속 고친다. SSH로 접속해 패키지를 업데이트하고, 설정을 바꾸고, 서비스를 재시작한다. 시간이 지나면 서버마다 미세하게 다른 상태가 된다 — foundations 06에서 본 "눈송이 서버(snowflake server)". 장점은 — 변경이 즉시적이고 유연하다. 단점은 — 재현이 불가능하고, "이 서버가 왜 이렇게 됐는지"를 아무도 모르는 상태가 된다.

Immutable(불변) 인프라 — 서버를 한 번 만들면 고치지 않는다. 변경이 필요하면 새 이미지를 만들고, 새 서버를 띄운 뒤, 기존 서버를 버린다. 서버는 소모품(disposable)이다. 장점은 — 재현 가능(같은 이미지에서 만든 서버는 항상 같다), 장애 복구가 빠름(새 서버로 교체), 테스트가 신뢰 가능(개발 환경과 운영 환경이 같은 이미지). 단점은 — 이미지 빌드·교체에 시간이 든다는 것.

flowchart TD
    CHANGE["서버 변경 필요"] --> Q{"인프라 스타일?"}
    Q -->|Mutable| SSH["기존 서버에 SSH<br/>패키지 업데이트·설정 변경"]
    SSH --> SNOW["눈송이 서버<br/>(재현 불가, 추적 불가)"]
    Q -->|Immutable| BUILD["새 이미지 빌드"]
    BUILD --> DEPLOY["새 서버 배포,<br/>기존 서버 폐기"]
    DEPLOY --> CLEAN["모든 서버 동일<br/>(재현 가능, 추적 가능)"]

Immutable이 항상 옳은 건 아니다. 개발 환경이나 소규모 서버에서는 mutable이 더 실용적이다 — 이미지를 빌드하는 오버헤드가 변경 자체보다 클 수 있으니까. 하지만 — 프로덕션 환경에서, 특히 자동 확장(auto-scaling)이 필요한 서비스에서는 immutable이 정답이다. 서버를 빠르게 만들고, 빠르게 버리고, 항상 같은 상태를 유지해야 하니까.

Packer — 이미지를 코드로 만드는 도구

Packer는 HashiCorp가 만든 이미지 빌드 도구다. 2013년 발표. "코드로 서버 이미지를 만든다" — foundations 06의 IaC 원칙이 이미지 빌드에 적용된 것이다. Packer의 핵심 아이디어는 — 이미지 빌드 과정을 코드(Template) 로 정의하고, 그 코드를 실행하면 — 다양한 플랫폼(AWS AMI·GCP Image·Vagrant Box·Docker Image)의 이미지를 동시에 만들어 준다.

Packer Template의 구조를 보자.

{
  "builders": [{
    "type": "amazon-ebs",
    "region": "us-east-1",
    "source_ami": "ami-0abcdef1234567890",
    "instance_type": "t3.medium",
    "ssh_username": "ubuntu",
    "ami_name": "my-app-{{timestamp}}"
  }],
  "provisioners": [
    {
      "type": "shell",
      "script": "install-nginx.sh"
    },
    {
      "type": "ansible",
      "playbook_file": "site.yml"
    }
  ]
}

이 Template이 하는 일:

  1. builder — AWS에서 임시 EC2 인스턴스를 하나 띄운다(source_ami에서 시작).
  2. provisioner — 그 인스턴스에 셸 스크립트와 Ansible playbook을 실행해 nginx와 앱을 설치한다.
  3. 완료되면 그 인스턴스의 EBS 볼륨을 AMI(Amazon Machine Image) 로 저장한다.
  4. 임시 인스턴스를 종료한다.

결과 — my-app-<timestamp>라는 AMI가 AWS 계정에 생긴다. 이 AMI에서 새 EC2 인스턴스를 만들면 — nginx와 앱이 이미 설치된 상태로 시작한다. 100대를 만들든 1000대를 만들든, 전부 같은 상태다.

Packer의 장점은 — 한 번의 코드로 여러 플랫폼 이미지를 만든다는 것이다. 같은 Template에서 AWS AMI·GCP Image·VMware Template·Docker Image를 동시에 만들 수 있다(buidler를 여러 개 정의). 플랫폼 간 이식성이 자동으로 생긴다. 또한 — 이미지 빌드 과정이 버전 관리(Git) 되고, 코드 리뷰를 거치고, CI/CD 파이프라인으로 자동화된다. 이미지가 "누가 언제 어떻게 만들었는지"가 코드 히스토리에 남는다.

설정 관리(Configuration Management) — Ansible, Chef, Puppet

이미지 안의 서버 설정(OS 패키지·설정 파일·사용자·서비스)은 — Packer의 provisioner가 적용한다. 가장 흔한 provisioner가 설정 관리 도구(configuration management tool) 다. 세 가지 주류가 있다.

Ansible — 선언적 YAML, 에이전트 없음

Ansible은 2012년 Michael DeHaan이 발표, 2015년 Red Hat이 인수. 특징은 — 에이전트가 필요 없다. SSH로 대상 서버에 접속해서 Python 스크립트를 실행하는 방식. 대상 서버에 아무것도 설치할 필요가 없다(Python 3만 있으면 됨). 설정은 YAML playbook으로 작성한다.

# Ansible playbook 예시 (site.yml)
---
- hosts: all
  become: yes
  tasks:
    - name: Install nginx
      apt:
        name: nginx
        state: present
        update_cache: yes

    - name: Copy nginx config
      copy:
        src: nginx.conf
        dest: /etc/nginx/nginx.conf
      notify: restart nginx

    - name: Ensure nginx is running
      service:
        name: nginx
        state: started
        enabled: yes

  handlers:
    - name: restart nginx
      service:
        name: nginx
        state: restarted

Ansible의 장점 — 에이전트 없음(SSH만 있으면 됨), YAML의 단순함, 멱등성(idempotency, 같은 playbook을 여러 번 실행해도 결과가 같음). 단점 — SSH 기반이라 대규모(수천 대)에서는 느릴 수 있다. 현대 인프라에서 가장 널리 쓰이는 설정 관리 도구.

Chef·Puppet — 1세대 설정 관리

Chef(2009년)와 Puppet(2005년)은 Ansible보다 먼저 나온 설정 관리 도구. 둘 다 — 대상 서버에 에이전트를 설치해야 하고, 중앙 서버(Chef Server·Puppet Master)와 통신한다. 설정은 Chef는 Ruby DSL로, Puppet은 자체 DSL(Puppet Language)로 작성한다. 2010년대에 널리 쓰였지만 — Ansible의 단순함(에이전트 없음, YAML)에 밀려 점유율이 줄고 있다.

특성 Ansible Chef Puppet
에이전트 없음 (SSH) 있음 (chef-client) 있음 (puppet agent)
언어 YAML playbook Ruby DSL Puppet DSL
중앙 서버 선택적 (Ansible AWX/Tower) 필수 (Chef Server) 필수 (Puppet Master)
멱등성 기본 보장 직접 구현 기본 보장
학습 곡선 완만 가파름 (Ruby 지식 필요) 중간
2026년 점유율 가장 높음 감소 중 감소 중

golden image(황금 이미지) — 한 번 만들고 양산

이미지 빌드의 결과물이 golden image(황금 이미지) 다. 모든 설정·패키지·보안 패치가 적용된 "완벽한" 서버 이미지. 이 이미지에서 새 서버를 만들면 — 즉시 사용 가능한 상태로 시작한다. 03-bare-metal-provisioning 글에서 "황금 이미지, golden image"로 잠깐 언급했다.

golden image의 워크플로는 이렇다.

flowchart LR
    CODE["1. 코드 정의<br/>(Packer + Ansible)"] --> BUILD["2. 이미지 빌드<br/>(Packer 실행)"]
    BUILD --> TEST["3. 이미지 테스트<br/>(TestKitchen, InSpec)"]
    TEST --> PUBLISH["4. 이미지 배포<br/>(AMI, Container Registry)"]
    PUBLISH --> DEPLOY["5. 서버 배포<br/>(Auto Scaling, K8s)"]
  1. 코드 정의 — Packer Template(JSON/HCL)과 Ansible playbook으로 이미지에 뭘 넣을지 정의. Git에 커밋.
  2. 이미지 빌드packer build template.json을 실행하면, 임시 서버를 띄우고, Ansible을 돌리고, 이미지를 만든다.
  3. 이미지 테스트 — 만들어진 이미지가 정상인지 자동 테스트(InSpec·Serverspec·TestKitchen). 보안 스캔(CIS benchmark·CVE 확인)도 이 단계에서.
  4. 이미지 배포 — 테스트를 통과하면 이미지를 AMI로 등록하거나 Container Registry에 푸시한다.
  5. 서버 배포 — Auto Scaling Group이나 Kubernetes가 새 이미지로 서버를 교체한다. 블루-그린 배포나 카나리 배포로 점진적 교체.

이 워크플로가 CI/CD for infrastructure 다. 애플리케이션 코드의 CI/CD(빌드 → 테스트 → 배포)와 같은 패턴이 — 인프라에도 적용된다. foundations 06의 IaC 철학이 완전히 실현되는 것이다.

AMI(Amazon Machine Image) — 클라우드의 golden image

AWS에서 golden image를 AMI(Amazon Machine Image) 라 부른다. AMI는 EC2 인스턴스의 "마스터 복사본" — OS·소프트웨어·설정이 다 들어있는 EBS 스냅샷. AMI에서 새 EC2 인스턴스를 만들면 — 그 스냅샷이 새 EBS 볼륨으로 복사되고, 인스턴스가 그 위에서 부팅된다.

클라우드 AMI의 장점은 — 재현성과 속도다. 서버 한 대를 처음부터 설정하는 데 30분이 걸리지만, AMI에서 만드는 데는 30초면 충분하다(스냅샷 복사만 하면 되니까). Auto Scaling이 트래픽 증가 시 새 인스턴스를 1분 안에 띄울 수 있는 이유가 AMI다 — 03 글에서 본 클라우드 인스턴스 부팅 시간의 상당 부분이 AMI 복사인 것.

GCP는 Image, Azure는 VHD(Virtual Hard Disk) 또는 Managed Image, 일반적인 용어로는 machine image라 부른다. 클라우드 벤더마다 이름이 다르지만 원리는 같다.

Docker 이미지 — 컨테이너용 golden image

컨테이너에도 같은 원리가 적용된다. Docker 이미지는 컨테이너의 golden image다. Dockerfile로 정의하고, docker build로 만들고, Container Registry(Docker Hub·ECR·GCR)에 푸시하고, Kubernetes가 그 이미지로 컨테이너를 배포한다. 07 글에서 본 OCI Image Spec이 이 표준이다.

서버 이미지(AMI)와 컨테이너 이미지(Docker image)의 차이는 — 추상화 단계다. AMI는 OS 전체(커널·패키지·설정)를 이미지화하지만, 컨테이너 이미지는 앱과 그 의존성만 이미지화한다(커널은 호스트와 공유). 컨테이너 이미지가 더 가볍고 빠르지만 — OS 수준의 설정(커널 파라미터·systemd 서비스)은 담을 수 없다. 그래서 — VM/베어메탈은 AMI로, 컨테이너는 Docker 이미지로, 각 층에 맞는 이미지 전략을 쓴다.

특성 서버 이미지 (AMI) 컨테이너 이미지 (Docker)
포함 범위 OS 전체 (커널·패키지·설정) 앱 + 의존성만 (커널은 공유)
크기 GB 단위 (500MB ~ 수 GB) MB 단위 (10 ~ 500MB)
빌드 시간 수 분 ~ 수십 분 수 초 ~ 수 분
시작 시간 수십 초 (인스턴스 부팅) 수 초 (컨테이너 시작)
빌드 도구 Packer Dockerfile + docker build
배포 대상 EC2, GCE, 베어메탈 Kubernetes, containerd, Docker

실습 — 이미지 빌드 상태 직접 확인

1. Packer 설치 및 버전 확인

# Packer 버전
packer version
# 또는
packer --version

확인할 것: Packer 1.10+가 2026년 기준 현대적. HCL2(HCL 버전 2) 포맷을 지원하는지.

2. Packer Template 검증

# Template 문법 검사 (이미지 빌드 없이)
packer validate template.pkr.hcl
# 빌드 계획 확인 (무엇이 만들어질지)
packer fmt -check template.pkr.hcl

확인할 것: validateSuccess!를 반환하면 문법이 맞는 것. fmt -check로 포맷 일관성 확인.

3. Ansible playbook 실행 (멱등성 테스트)

# playbook을 두 번 실행해 멱등성 확인
ansible-playbook -i localhost, -c local site.yml
ansible-playbook -i localhost, -c local site.yml
# 두 번째 실행의 changed=0이면 멱등

확인할 것: 첫 실행의 changed=N(N>0), 두 번째 실행의 changed=0. 멱등하면 같은 결과가 보장된다.

# 예상 출력 (멱등 playbook의 두 번째 실행)
PLAY RECAP *********************************************************************
localhost : ok=5  changed=0  unreachable=0  failed=0    # changed=0이 핵심

4. Docker 이미지 레이어 확인

# 이미지 빌드 히스토리 (각 레이어가 무엇을 했는지)
docker image history nginx:latest
# 이미지 크기 분석
docker image inspect nginx:latest --format '{{.Size}}' | awk '{print $1/1024/1024 " MB"}'

확인할 것: history의 각 행이 Dockerfile의 한 명령(FROM·RUN·COPY). SIZE 열에서 어느 레이어가 이미지를 크게 만드는지.

5. AMI 정보 확인 (AWS 환경)

# 본인 계정의 AMI 목록
aws ec2 describe-images --owners self --query 'Images[*].[ImageId,Name,CreationDate]' --output table
# 특정 AMI의 상세 정보
aws ec2 describe-images --image-ids ami-0abcdef1234567890 --query 'Images[0].[Name,Architecture,RootDeviceType]' --output table

확인할 것: AMI 이름 규칙(my-app-<timestamp> 등), 생성일자, 아키텍처(x86_64 vs arm64).

미검증: Packer·Ansible은 별도 설치 필요(apt install packer, pip install ansible). Docker 명령은 Docker가 설치된 환경에서 동작. AWS CLI는 자격증명이 설정된 환경에서만.

판단 표 — 이미지 전략 선택

환경 권장 이미지 전략 도구 이유
클라우드 EC2/GCE AMI/Machine Image Packer + Ansible Auto Scaling 속도, 재현성
Kubernetes 클러스터 컨테이너 이미지 Dockerfile + CI/CD 빠른 배포, 레이어 공유
베어메탈/온프레 golden image + PXE Packer + Ansible + kickstart 03 글의 프로비저닝과 연결
개발/테스트 환경 Vagrant Box 또는 컨테이너 Packer + Vagrant 또는 Docker 로컬에서 빠르게 띄움
서버리스(FaaS) 함수 패키지(zip 또는 컨테이너) CI/CD 파이프라인 이미지가 아닌 함수 코드

서버는 소모품이다

도입의 Netflix 사건으로 돌아가자. "서버를 고치지 말고 버리고 새로 만든다"는 철학은 2010년엔 급진적이었지만, 2026년엔 클라우드 네이티브의 기본이다. 서버가 장애 나면 고치는 게 아니라 — 새 이미지로 새 서버를 만든다. 보안 패치가 필요하면 — 기존 서버에 SSH로 패치하는 게 아니라, 패치가 적용된 새 이미지를 만들고 서버를 교체한다. 이게 Immutable Infrastructure다.

이미지 빌드를 이해하면 다른 질문에도 답이 보인다. "왜 클라우드 Auto Scaling이 빠른가" → AMI가 미리 만들어져 있으니까. "왜 Docker가 CI/CD에 필수인가" → 이미지로 빌드·테스트·배포가 일관되니까. "왜 서버가 장애 나면 자동 복구되나" → 새 이미지로 새 서버를 만드는 게 자동화돼 있으니까. 서버가 더 이상 "고쳐야 하는 물건"이 아니라 "교체하는 소모품"이 됐다. 그 전환을 가능하게 한 게 이미지 빌드와 Immutable Infrastructure다.

다음 글에서는 서버(VM·컨테이너·베어메탈 모두)의 성능을 분석하는 방법을 다룬다 — 서버 성능 분석. perf·eBPF·flame graph·sar·iostat로 CPU·메모리·디스크·네트워크의 병목을 찾는 방법. Brendan Gregg의 USE method를 비롯한 성능 분석 프레임워크로, "왜 느린가?"라는 질문에 데이터로 답하는 마지막 글이다.


참고

  • HashiCorp, "Packer Documentation" — 이미지 빌드 템플릿·프로비저너. 접근 2026-07-21. URL: https://developer.hashicorp.com/packer/docs
  • DeHaan, M. "Ansible: Up and Running", O'Reilly, 2nd ed 2017 — Ansible 원저자의 실전 가이드. 접근 2026-07-21
  • Morris, K. 2nd ed, O'Reilly, 2020 — Immutable Infrastructure 철학·실천. 접근 2026-07-21
  • Brikman, Y. "Terraform: Up & Running" 2nd ed, O'Reilly, 2019 — Packer·Terraform 연계. 접근 2026-07-21
  • Netflix Tech Blog, "AMIs as Build Artefacts" — Netflix의 golden image 워크플로. 접근 2026-07-21
  • Chef Software, "Chef Infra Documentation" — Chef 설정 관리. 접근 2026-07-21
  • Puppet, "Puppet Documentation" — Puppet 설정 관리. 접근 2026-07-21
  • AWS, "Amazon Machine Images (AMI)" — AMI 공식 문서. 접근 2026-07-21
  • test-kitchen, "Test Kitchen Documentation" — 이미지 테스트 자동화. 접근 2026-07-21
  • InSpec, "InSpec Documentation" — 인프라 테스트 프레임워크(DevSec). 접근 2026-07-21