Step 12-13. Provisioning & Configuration — 인프라 준비와 내부 세팅

이전 단계: 06-full-pipeline.md 돌아가기: 09-hands-on.md


용어 안내

이 문서에서 “슬롯”은 학습용 비유다. 실무 용어가 아니다. 각 슬롯 옆에 실무에서 실제로 쓰는 용어를 병기한다.


Step 12. Terraform으로 인프라를 코드로 만들기 — ⑥ Provisioning (인프라 준비)

왜 인프라를 코드로 만들어야 하는가? (WHY)

AWS 콘솔에서 클릭클릭으로 서버를 만들었다고 하자. 3개월 뒤, 그 서버를 어떻게 만들었는지 아무도 기억하지 못한다. 설정이 다르면? 처음부터 클릭을 다시 해야 한다.

코드로 인프라를 정의하면:

  • git으로 이력 관리 — 누가, 언제, 왜 바꿨는지 추적 가능
  • 동일한 환경을 반복 생성 — 개발/스테이징/운영이 같은 코드로 만들어짐
  • 코드 리뷰 — 인프라 변경도 PR로 검토 가능

핵심 용어 3가지

Provisioning (프로비저닝)

  • 영어 뜻: “미리 준비해두다, 공급하다” — 필요한 것을 사전에 마련하는 행위
  • IT 뜻: 서버·네트워크·DB 같은 인프라 자원을 생성하는 것
  • 비유: 빈 땅에 집을 짓는 것. 벽, 지붕, 수도관을 설치하는 단계
  • 실무 용어: “인프라 프로비저닝”

IaC (Infrastructure as Code)

  • 영어 뜻: “Infrastructure as Code” = “인프라를 코드로”
  • IT 뜻: 콘솔에서 클릭 대신 코드 파일로 인프라를 정의하는 방법론
  • 비유: 건축 설계도. 구두 지시가 아니라 도면을 보고 집을 짓는 것
  • 실무 용어: “IaC”

Terraform (테라폼)

  • 영어 뜻: “terra(땅) + form(형태를 만들다)” = 땅의 형태를 바꾸다
  • IT 뜻: HashiCorp이 만든 IaC 도구. 코드를 작성하면 인프라를 자동으로 생성·변경·삭제
  • 비유: 건축 시공 회사. 설계도(코드)를 주면 집(인프라)을 지어주는 업체
  • 실무 용어: “Terraform”, “IaC 도구”

로컬 체험 방법

Terraform에는 Docker Provider가 있다. 클라우드 계정 없이, 로컬 Docker 컨테이너를 Terraform으로 관리할 수 있다.

AWS에서는 aws_instance(EC2 서버)를 만들고, 여기서는 docker_container를 만든다. Terraform 사용법은 동일하다.


12-1. 사전 준비

# Mac: Homebrew로 Terraform 설치
brew tap hashicorp/tap
brew install hashicorp/tap/terraform  

# 설치 확인 — 버전이 출력되면 성공
terraform --version

12-2. main.tf 작성

# 프로젝트 루트에서 terraform 디렉토리를 만들고 이동
mkdir -p terraform && cd terraform
# --- Terraform 설정 블록 ---
# 어떤 프로바이더(인프라 제공자)를 사용할지 선언한다
terraform {
  required_providers {
    docker = {
      source  = "kreuzwerker/docker"   # Docker 프로바이더의 출처
      version = "~> 3.0"               # 3.x 버전 사용 (~>는 "이 메이저 버전 내에서")
    }
  }
}

# --- 프로바이더 설정 ---
# Docker를 인프라 대상으로 사용한다 (로컬 Docker 데몬에 연결)
provider "docker" {}

# --- 리소스 1: Docker 이미지 ---
# docker pull nginx:alpine 과 같은 역할
resource "docker_image" "nginx" {
  name = "nginx:alpine"   # 가져올 이미지 이름과 태그
}

# --- 리소스 2: Docker 컨테이너 ---
# docker run --name tf-nginx -p 8080:80 nginx:alpine 과 같은 역할
resource "docker_container" "nginx" {
  name  = "tf-nginx"                      # 컨테이너 이름
  image = docker_image.nginx.image_id     # 위에서 가져온 이미지 참조
  ports {
    internal = 80     # 컨테이너 내부 포트 (nginx 기본 포트)
    external = 8080   # 호스트에서 접근할 포트
  }
}

12-3. Terraform 3단계 실행

Provisioning의 핵심 흐름은 딱 3단계다.

① init — 초기화

# 프로바이더 플러그인을 다운로드한다
# npm install이 node_modules를 받는 것과 같은 원리
terraform init

② plan — 미리보기

# "이런 것들이 만들어질 예정입니다"를 보여준다
# 실제로 만들지는 않는다 — 안전하게 확인만
terraform plan

출력에서 + resource가 보이면 “새로 만들 것”이라는 뜻이다.

③ apply — 실제 실행

# 실제로 인프라(컨테이너)를 생성한다
# "Do you want to perform these actions?" → yes 입력
terraform apply

12-4. 결과 확인 + 삭제

# nginx가 정상 작동하는지 확인
# "Welcome to nginx!" 페이지가 응답되면 성공
curl localhost:8080

# Docker로 직접 확인해도 된다
docker ps | grep tf-nginx

# 모든 리소스를 삭제한다
# Terraform이 만든 것만 정확히 삭제한다
terraform destroy

핵심 인사이트: terraform plan → apply → destroy 이 3단계가 Provisioning의 핵심 흐름이다. AWS에서도 똑같이 동작한다. docker_container 대신 aws_instance를 쓸 뿐이다.

선택 실습: 기존 Express 앱 이미지(my-app:latest)도 main.tf에 docker_image + docker_container 리소스로 추가해보자. terraform apply 하면 nginx와 Express 앱이 동시에 생성된다.


Step 13. Ansible로 컨테이너 내부 설정하기 — ⑦ Configuration (내부 세팅)

Provisioning vs Configuration — 왜 도구가 2개인가? (WHY)

Terraform으로 서버(컨테이너)를 만들었다. 하지만 빈 서버에는 아무것도 없다. 필요한 소프트웨어를 설치하고, 설정 파일을 넣고, 서비스를 시작해야 한다.

서버가 1대면 SSH로 들어가서 하면 된다. 10대면? 100대면? 하나하나 접속해서 같은 명령을 치는 건 비현실적이다.

  • Terraform = 집을 짓는 것 (벽, 지붕, 배관)
  • Ansible = 집 안에 가구를 넣는 것 (소파, 침대, 커튼)
  • 이 두 도구는 경쟁이 아니라 보완 관계

핵심 용어

Configuration (컨피규레이션)

  • 영어 뜻: “설정, 구성” — 부품을 조합해서 원하는 상태로 맞추는 것
  • IT 뜻: 이미 만들어진 서버 안에 소프트웨어를 깔고 설정하는 것
  • 비유: 새 집에 가구 배치, 인터넷 개통, 벽지 도배를 하는 것
  • 실무 용어: “구성 관리(Configuration Management)”

Ansible (앤서블)

  • 영어 뜻: SF 소설에서 온 단어 — “초광속 통신 장치”
  • IT 뜻: 여러 서버에 동시에 명령을 실행하는 자동화 도구. SSH로 접속해서 작업
  • 비유: 인테리어 업체. 집 100채에 동시에 같은 가구를 배치해주는 회사
  • 실무 용어: “Ansible”, “구성 관리 도구”

Docker 컨테이너를 **“미니 서버”**로 취급하고, Ansible이 SSH로 접속해서 내부를 설정한다.

13-1. 사전 준비

# Ansible 설치 (둘 중 하나 선택)
pip install ansible        # Python pip으로 설치
# 또는
brew install ansible       # Mac Homebrew로 설치

# 설치 확인
ansible --version

13-2. SSH 가능한 컨테이너 직접 빌드하기

최신 Ansible(2.20+)은 관리 대상(target) 서버에 Python 3.8 이상을 요구한다. 기성 SSH 이미지(rastasheep/ubuntu-sshd:18.04)는 Python 3.6이라 호환이 안 된다. 짧은 Dockerfile로 직접 만들어 쓰는 게 가장 확실하고, 실무에서 EC2 초기 세팅을 하는 흐름과도 가장 비슷하다.

# my-infra-lab 루트에서 ansible-target 디렉토리 생성
mkdir -p ansible-target

ansible-target/Dockerfile 작성:

# Ubuntu 22.04 기반 — Python 3.10 내장 (최신 Ansible 호환)
FROM ubuntu:22.04

# SSH 서버 + Python3 설치
# Ansible은 SSH로 접속해서 타겟의 Python으로 모듈을 실행한다
RUN apt-get update && apt-get install -y \
      openssh-server \
      python3 \
      sudo \
 && mkdir /var/run/sshd \
 && echo 'root:root' | chpasswd \
 && sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config \
 && rm -rf /var/lib/apt/lists/*

EXPOSE 22

# 컨테이너 시작 시 SSH 데몬 실행 (-D: 포그라운드로 유지)
CMD ["/usr/sbin/sshd", "-D"]
# 이미지 빌드
docker build -t my-ansible-target ./ansible-target

# 컨테이너 실행
# -d: 백그라운드 실행
# -p 2222:22: 호스트 2222번 포트 → 컨테이너 22번(SSH) 포트
docker run -d --name ansible-target -p 2222:22 my-ansible-target

이 컨테이너가 “서버 1대” 역할을 한다. 실무에서는 AWS EC2 인스턴스가 이 자리에 들어간다.

SSH 접속이 되는지 먼저 확인(선택):

# 비밀번호는 root
ssh -p 2222 -o StrictHostKeyChecking=no root@localhost exit
# 오류 없이 끝나면 준비 완료

13-3. inventory.ini — 대상 서버 목록

# ansible 디렉토리를 만들고 이동
mkdir -p ansible && cd ansible
# [servers] = 그룹 이름. 여러 서버를 묶어서 관리할 수 있다
[servers]
# target = 별칭 (아무 이름이나 가능)
# ansible_host = 접속할 주소 (로컬이므로 localhost)
# ansible_port = SSH 포트 (위에서 2222로 매핑했으므로)
# ansible_user / ansible_password = SSH 접속 계정
target ansible_host=localhost ansible_port=2222 ansible_user=root ansible_password=root

13-4. playbook.yml — 실행할 작업 정의

# --- 플레이북: 서버 초기 설정 ---
- name: 서버 초기 설정                 # 이 플레이북의 이름 (로그에 표시됨)
  hosts: servers                      # inventory.ini에서 [servers] 그룹을 대상으로 실행
  tasks:
    # --- 작업 1: curl 설치 ---
    - name: curl 설치                  # 작업 이름 (로그에 표시됨)
      apt:                            # apt 패키지 매니저 사용 (Ubuntu)
        name: curl                    # 설치할 패키지 이름
        state: present                # present = "설치해라" / absent = "삭제해라"
        update_cache: yes             # apt update를 먼저 실행 (패키지 목록 갱신)

    # --- 작업 2: 확인 파일 생성 ---
    - name: 확인 파일 생성              # Ansible이 작업했다는 증거를 남긴다
      copy:                           # 파일을 생성/복사하는 모듈
        content: "Ansible이 이 파일을 만들었습니다 - {{ ansible_date_time.iso8601 }}"
        dest: /tmp/ansible-was-here.txt   # 파일이 생성될 경로

13-5. 실행 및 확인

# 플레이북 실행
# -i: inventory 파일 지정
# SSH 호스트 키 검증을 끄는 환경변수 추가 (로컬 실습용)
ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -i inventory.ini playbook.yml

# 결과 확인 — 컨테이너 안의 파일을 직접 읽는다
docker exec ansible-target cat /tmp/ansible-was-here.txt
# 출력 예: "Ansible이 이 파일을 만들었습니다 - 2026-04-16T..."

TASK [curl 설치]TASK [확인 파일 생성] 옆에 changed가 표시되면 성공이다.

핵심 인사이트: Terraform이 컨테이너(서버)를 만들고, Ansible이 그 안을 세팅한다. 이 두 도구는 경쟁이 아니라 보완 관계다.

13-6. 정리

# 실습이 끝나면 컨테이너 + 빌드 이미지 정리
docker stop ansible-target && docker rm ansible-target
docker rmi my-ansible-target

체크리스트

  • Terraform으로 컨테이너를 코드로 생성/삭제할 수 있다
  • terraform plan → apply → destroy 3단계 흐름을 이해했다
  • Ansible로 컨테이너 내부를 자동 설정할 수 있다
  • Provisioning(인프라 생성)과 Configuration(내부 설정)의 차이를 체감했다

다음 단계: → 08-deploy-and-alerting.md

Comments

  • // 댓글을 불러오는 중...
main ⚠ 0 ✕ 0 Ln 1, Col 1 Spaces: 2 UTF-8 LF Markdown