순차적 Ansible 플레이북을 사용한 다단계 배포 마스터하기
Ansible을 사용하여 복잡한 다단계 애플리케이션 배포를 설계하고 실행하는 방법을 알아보세요. 이 가이드에서는 별도의 배포 단계를 위한 순차적 플레이북 생성, 효과적인 오류 처리 구현, 롤백 전략 개발을 다룹니다. 실용적인 예제와 모범 사례를 통해 강력하고 자동화된 애플리케이션 전달을 마스터하세요.
순차적 Ansible 플레이북을 사용한 다단계 배포 마스터하기
"파일을 복사하고 서비스를 다시 시작하세요"라는 말이 더 이상 정직하지 않을 때 다단계 Ansible 배포가 필요해집니다. 실제 배포에는 데이터베이스 마이그레이션, 기능 플래그 변경, 패키지 롤아웃, 서비스 재로드, 상태 확인, 새 버전이 실패할 경우 롤백 경로가 필요할 수 있습니다. 이 모든 것이 명확한 경계 없이 하나의 큰 플레이북에 있다면, 실패한 배포는 매번 읽기 연습으로 변합니다.
순차적 플레이북은 각 단계에 명확한 작업을 부여합니다. CI/CD 파이프라인, AWX, Ansible Automation Platform 또는 간단한 셸 스크립트에서 실행할 수 있습니다. 중요한 것은 버튼을 누르는 도구가 아닙니다. 중요한 것은 배포에 순서가 있고, 각 단계를 안전하게 재시도할 수 있으며, 실패 처리가 명시적이라는 것입니다.
다단계 배포에 순차적 플레이북이 필요한 이유
애플리케이션을 배포하는 것은 단순히 파일을 복사하는 것 이상을 포함하는 경우가 많습니다. 다음과 같은 작업이 필요할 수 있습니다:
- 환경 준비: 디렉토리 생성, 권한 설정, 종속성 설치.
- 데이터베이스 업데이트: 스키마 마이그레이션 실행, 초기 데이터 시드.
- 애플리케이션 코드 배포: 새 코드 버전 전송, 서비스 다시 시작.
- 서비스 구성: 애플리케이션 구성 업데이트, 데몬 재로드.
- 배포 후 확인: 스모크 테스트 실행, 서비스 가용성 확인.
일부 작업은 롤백하기 쉽고 다른 작업은 그렇지 않기 때문에 순서가 중요합니다. 이전 릴리스로 심볼릭 링크를 되돌리는 것은 일반적으로 간단합니다. 파괴적인 데이터베이스 마이그레이션을 되돌리는 것은 간단하지 않을 수 있습니다. 이러한 차이는 YAML을 작성하기 전에 배포 계획을 수립해야 합니다.
이를 별개의 순차적 플레이북으로 나누면 여러 가지 이점이 있습니다:
- 모듈성: 각 플레이북은 단일 단계에 집중하므로 이해, 유지 관리 및 재사용이 더 쉽습니다.
- 가독성: 복잡한 로직이 관리 가능한 덩어리로 나뉩니다.
- 제어: 특정 단계를 독립적으로 또는 더 큰 워크플로의 일부로 실행할 수 있습니다.
- 오류 격리: 한 단계에서 오류가 발생하면 원인을 더 쉽게 찾고 배포의 다른 부분에 영향을 주지 않고 특정 변경 사항을 롤백할 수 있습니다.
- 멱등성: 잘 작성된 플레이북은 본질적으로 멱등성을 가지므로 여러 번 실행해도 한 번 실행한 것과 동일한 효과를 냅니다. 이는 안전한 재시도에 중요합니다.
절충점이 있습니다. 별도의 플레이북은 오케스트레이션 작업을 추가합니다. 변수, 아티팩트 및 상태가 한 단계에서 다른 단계로 이동해야 할 수 있습니다. 소규모 내부 서비스의 경우 태그가 지정된 블록이 있는 하나의 플레이북으로 충분할 수 있습니다. 마이그레이션 및 롤백 요구 사항이 있는 고객 대면 애플리케이션의 경우 추가 구조가 일반적으로 그만한 가치가 있습니다.
다단계 배포 워크플로 설계
Ansible 코드를 작성하기 전에 배포 단계를 계획하세요. 논리적 단계, 종속성 및 실행 순서를 식별하세요. 일반적인 워크플로는 다음과 같습니다:
- 배포 전 확인: 대상 환경이 준비되었는지 확인합니다.
- 데이터베이스 마이그레이션: 필요한 데이터베이스 스키마 변경 사항을 적용합니다.
- 애플리케이션 배포: 새 버전의 애플리케이션 코드를 배포합니다.
- 서비스 다시 시작/재로드: 새 코드로 애플리케이션 서비스를 온라인 상태로 만듭니다.
- 배포 후 확인: 배포 성공을 확인하기 위해 테스트를 실행합니다.
각 단계에 대해 필요한 Ansible 작업과 어떤 플레이북에 포함될지 고려하세요.
또한 어떤 단계가 프로덕션 상태를 변경할 수 있는지 결정하세요. 스모크 테스트 플레이북은 조용히 구성을 수리해서는 안 됩니다. 사전 점검 플레이북은 배포 계약의 명시적 일부가 아닌 한 누락된 패키지를 설치해서는 안 됩니다. 읽기 전용 검사를 변경 단계와 분리하면 워크플로를 더 신뢰할 수 있습니다.
다음은 실용적인 디렉토리 레이아웃입니다:
deploy/
inventories/
staging.ini
production.ini
group_vars/
all.yml
production.yml
playbooks/
00-preflight.yml
01-migrate-db.yml
02-deploy-app.yml
03-reload-services.yml
04-smoke-test.yml
rollback-app.yml
숫자는 마법이 아닙니다. 파일 목록과 CI 로그에서 순서를 보이게 할 뿐입니다.
플레이북 순차 실행
Ansible은 --playbook-dir 및 ansible-playbook 명령을 사용하여 플레이북을 차례로 실행하는 간단한 방법을 제공합니다. 가장 간단한 방법은 CI/CD 파이프라인이나 명령줄에서 명령을 연결하는 것입니다.
다음 플레이북 파일이 있다고 가정해 보겠습니다:
01-database-migration.yml02-deploy-application.yml03-restart-services.yml04-smoke-tests.yml
다음과 같이 순차적으로 실행할 수 있습니다:
ansible-playbook -i inventory.ini 01-database-migration.yml
ansible-playbook -i inventory.ini 02-deploy-application.yml
ansible-playbook -i inventory.ini 03-restart-services.yml
ansible-playbook -i inventory.ini 04-smoke-tests.yml
실제로는 실패한 단계가 파이프라인을 중지하도록 시퀀스를 래핑합니다:
set -euo pipefail
ansible-playbook -i inventories/production.ini playbooks/00-preflight.yml
ansible-playbook -i inventories/production.ini playbooks/01-migrate-db.yml
ansible-playbook -i inventories/production.ini playbooks/02-deploy-app.yml
ansible-playbook -i inventories/production.ini playbooks/03-reload-services.yml
ansible-playbook -i inventories/production.ini playbooks/04-smoke-test.yml
set -e는 그 자체로 배포 전략은 아니지만 최악의 실수인 실패한 단계 후에도 아무 일도 없었던 것처럼 계속하는 것을 방지합니다. CI 시스템은 일반적으로 자체 실패 동작을 제공하지만 동일한 아이디어가 적용됩니다.
ansible-playbook --skip-tags 또는 --limit 사용
더 고급 시나리오에서는 여러 논리적 단계를 단일 플레이북에 결합할 수 있지만 태그를 사용하여 실행을 제어합니다. 그러나 진정한 다단계 분리를 위해서는 별도의 플레이북이 일반적으로 선호됩니다. 플레이북의 하위 집합을 실행하거나 특정 플레이북을 건너뛰려면 명령줄 인수를 사용할 수 있습니다.
플레이북 건너뛰기: 03-restart-services.yml이 일시적인 서비스 문제로 실패하면 원인을 수정한 후 해당 단계만 다시 실행할 수 있습니다. 이전 단계가 이후 단계가 의존하는 아티팩트나 상태를 생성할 때는 맹목적으로 단계를 건너뛰지 마십시오.
특정 단계로 제한: --limit 플래그를 사용하여 특정 호스트 또는 그룹으로 실행을 제한할 수도 있으며, 이는 테스트에 유용할 수 있습니다.
롤링 배포의 경우 --limit는 블래스트 반경을 줄일 수도 있습니다:
ansible-playbook -i inventories/production.ini playbooks/02-deploy-app.yml --limit web_canary
하나의 호스트 또는 하나의 소규모 그룹에 대해 배포를 실행하고, 확인한 다음 나머지 플릿으로 계속 진행합니다. 이는 로드 밸런서가 재로드 또는 다시 시작 전에 호스트 드레이닝을 지원할 때 특히 유용합니다.
오류 처리 및 롤백 전략 통합
강력한 배포에는 문제 발생 시 계획이 필요합니다.
ignore_errors 및 failed_when
기본적으로 Ansible은 작업이 실패하면 실행을 중지합니다. 이 동작을 제어할 수 있습니다:
ignore_errors: true: 작업이 실패하더라도 플레이북이 계속 실행되도록 허용합니다. 일반적으로 중요하지 않은 작업이나 후속 작업이 정리 또는 보상을 수행할 때 주의해서 사용하십시오.failed_when:: 작업이 실패한 것으로 간주되어야 하는 사용자 정의 조건을 정의합니다. 이는 예상되는 치명적이지 않은 오류를 처리하거나 특정 결과의 유효성을 검사하는 데 강력합니다.
- name: 서비스 상태 확인 (잠재적으로 치명적이지 않음)
command: systemctl status myapp
register: service_status
ignore_errors: true
- name: 서비스가 활성 상태가 아니면 실패
fail:
msg: "Service myapp이(가) 실행 중이 아닙니다!"
when: "service_status.rc != 0"
ignore_errors를 드물게 사용하십시오. 결과를 등록하고 명확한 결정을 내리는 것이 종종 더 좋습니다. 무시된 실패로 가득 찬 배포 로그는 사람들이 실패 읽기를 중단하도록 가르칩니다.
명령의 경우 존재할 때 목적에 맞게 구축된 모듈을 선호하십시오. 예를 들어, 셸 아웃 대신 ansible.builtin.service, ansible.builtin.systemd, ansible.builtin.copy, ansible.builtin.template 및 패키지 모듈을 사용하십시오. 모듈은 일반적으로 더 나은 멱등성과 더 명확한 변경 및 실패 상태를 제공합니다.
롤백 플레이북
중요한 배포의 경우 전용 롤백 플레이북을 준비하십시오. 이러한 플레이북은 해당 배포 플레이북이 수행한 변경 사항을 되돌리도록 설계되어야 합니다.
01-database-migration-rollback.yml: 스키마 변경 사항을 되돌립니다.02-deploy-application-rollback.yml: 이전 애플리케이션 버전을 배포하거나 백업을 복원합니다.03-restart-services-rollback.yml: 이전 상태로 서비스를 다시 시작합니다.
데이터베이스 롤백은 특별한 주의가 필요합니다. 일부 마이그레이션은 새 스키마를 사용하여 쓰기가 시작된 후에는 안전하게 되돌릴 수 없습니다. 더 안전한 패턴은 종종 확장 및 축소입니다: 이전 버전과 호환되는 스키마 변경 사항을 추가하고, 이전 및 새 형태 모두에서 작동할 수 있는 애플리케이션 코드를 배포하고, 필요한 경우 데이터를 백필한 다음, 이후 배포에서 이전 열 또는 필드를 제거합니다.
이 모델을 사용하면 롤백은 일반적으로 애플리케이션 코드를 되돌리고 호환 가능한 스키마를 그대로 두는 것을 의미하며, 압박 속에서 위험한 데이터베이스 변경을 취소하려고 시도하지 않습니다.
롤백 트리거 예: CI/CD 파이프라인에서 04-smoke-tests.yml 플레이북이 실패하면 역순으로 롤백 플레이북 실행을 트리거합니다.
# 04-smoke-tests.yml이 실패하면:
ansible-playbook -i inventory.ini 03-restart-services-rollback.yml
ansible-playbook -i inventory.ini 02-deploy-application-rollback.yml
ansible-playbook -i inventory.ini 01-database-migration-rollback.yml
block, rescue 및 always 사용
Ansible의 block, rescue 및 always 구문은 단일 플레이북 내에서 오류를 처리하는 더 구조화된 방법을 제공합니다. 플레이북 간 시퀀싱을 위한 것은 아니지만 실패할 수 있는 일련의 작업을 캡슐화하고 실패 시 수행할 작업을 정의하는 데 탁월합니다.
- block:
- name: 새 애플리케이션 코드 배포
copy:
src: /path/to/new/app/
dest: /var/www/myapp/
- name: 애플리케이션 서비스 다시 시작
service:
name: myapp
state: restarted
rescue:
- name: 이전 버전으로 되돌리기 시도
copy:
src: /path/to/old/app/
dest: /var/www/myapp/
- name: 롤백 후 애플리케이션 서비스 다시 시작
service:
name: myapp
state: restarted
always:
- name: 배포 시도 기록
debug:
msg: "배포 시도가 완료되었습니다."
이 접근 방식은 단일 배포 단계 플레이북 내에서 관련 작업을 그룹화하는 데 유용합니다.
플레이북 간 롤백의 경우 오케스트레이터가 결정을 내리도록 하십시오. CI 파이프라인은 이후 단계가 실패한 경우에만 롤백 플레이북을 실행할 수 있습니다. AWX 작업 워크플로는 동일한 성공 및 실패 분기를 시각적으로 모델링할 수 있습니다. 롤백 명령을 지루하고 연습된 상태로 유지하십시오.
단계 간 릴리스 상태 전달
순차적 플레이북은 종종 공유 릴리스 식별자가 필요합니다. 예를 들어, 배포 단계는 설치할 아티팩트를 알아야 하고, 스모크 테스트는 예상되는 버전을 알아야 하며, 롤백은 이전 버전을 알아야 합니다.
해당 상태를 명시적으로 전달하십시오:
ansible-playbook -i inventories/production.ini playbooks/02-deploy-app.yml \
-e release_version=2026.05.24.3 \
-e artifact_url=https://artifacts.example.com/myapp/2026.05.24.3.tar.gz
플레이북 내에서 변경된 사항을 기록하십시오:
- name: 현재 릴리스 마커 쓰기
ansible.builtin.copy:
dest: /opt/myapp/current-release.txt
content: "{{ release_version }}\n"
owner: root
group: root
mode: "0644"
해당 마커는 인시던트 중에 도움이 됩니다. 누군가가 호스트에 SSH로 접속하면 호스트가 실행 중이라고 생각하는 버전을 볼 수 있습니다. 또한 스모크 테스트 플레이북이 마커를 읽고 예상 릴리스와 비교하도록 할 수 있습니다.
고급 고려 사항
플레이북 간 상태 관리
때로는 한 플레이북의 작업이 다른 플레이북에 결과를 알려야 합니다. 다음을 사용하여 이를 달성할 수 있습니다:
- 팩트 캐싱: 팩트 캐싱이 활성화된 경우 한 플레이북이 수집한 팩트를 동일한 Ansible 세션 내에서 실행되는 후속 플레이북에서 사용할 수 있습니다.
- 임시 파일/데이터베이스: 중요한 상태 정보 또는 출력을 임시 파일이나 후속 플레이북이 읽을 수 있는 전용 상태 테이블에 씁니다.
숨겨진 상태보다 명시적 상태를 선호하십시오. 팩트 캐싱은 유용할 수 있지만 값이 오래되었거나 한 실행자가 캐시를 활성화하고 다른 실행자는 그렇지 않은 경우 사람들을 혼란스럽게 할 수 있습니다. 릴리스 파일, 아티팩트 메타데이터, CI 변수 및 배포 레코드는 검사하기 더 쉽습니다.
버전 관리 및 오케스트레이션 도구
복잡한 오케스트레이션의 경우 순차적 Ansible 플레이북을 상위 수준 도구에 통합하는 것을 고려하십시오:
- CI/CD 파이프라인: Jenkins, GitLab CI, GitHub Actions 또는 CircleCI와 같은 도구는 다단계 배포를 정의하고 트리거하는 데 탁월합니다. 파이프라인 구성 내에서
ansible-playbook명령의 시퀀스를 정의합니다. - Ansible Tower/AWX: 엔터프라이즈급 오케스트레이션의 경우 Ansible Tower(현재 Automation Platform) 또는 오픈 소스 대응 제품인 AWX는 여러 플레이북을 연결할 수 있는 복잡한 작업 템플릿을 예약, 모니터링 및 관리하기 위한 강력한 UI를 제공합니다.
여러 사람이 동일한 시스템을 배포하는 경우 중앙 오케스트레이션은 편의성보다는 제어에 가까워집니다. 일관된 인벤토리, 자격 증명, 감사 로그, 승인 및 어떤 단계가 실패했는지에 대한 가시적인 기록을 제공합니다. 이러한 세부 사항은 프로덕션 인시던트 중에 중요합니다.
세분화된 제어를 위한 태깅
별도의 단계에 대해 별도의 플레이북을 주장하지만 플레이북 내에서 태그를 사용할 수도 있습니다. 단일 단계(예: 데이터베이스 마이그레이션)에 대한 매우 큰 플레이북이 있는 경우 특정 작업에 태그를 지정하고 ansible-playbook --tags <tag_name>을 사용하여 해당 작업만 실행할 수 있습니다.
이는 단계 간 시퀀싱보다는 단계 내 세분화된 제어에 더 가깝습니다.
다단계 배포를 위한 모범 사례
- 플레이북 집중 유지: 각 플레이북은 한 가지 작업(예: 데이터베이스 마이그레이션, 애플리케이션 배포)을 잘 수행해야 합니다.
- 플레이북 명확하게 이름 지정: 단계와 순서를 반영하는 명명 규칙을 사용하십시오(예:
01-,02-). - 멱등성 구현: 모든 작업이 멱등성을 가지도록 하여 안전한 재시도를 허용하십시오.
- 롤백 테스트: 롤백 절차가 예상대로 작동하는지 정기적으로 테스트하십시오.
- 버전 관리 사용: 모든 플레이북과 인벤토리 파일을 버전 관리 시스템(Git 등)에 저장하십시오.
- 오케스트레이션 자동화: CI/CD 파이프라인 또는 Ansible Tower/AWX와 같은 도구를 사용하여 순차적 플레이북 실행을 자동화하십시오.
- 워크플로 문서화: 단계, 목적, 종속성 및 롤백 절차를 명확하게 문서화하십시오.
- 스모크 테스트를 실제로 만드십시오: 실제 엔드포인트, 로그인 경로, 큐 작업자 또는 중요한 백그라운드 작업을 확인하십시오. 단순한 프로세스 확인만으로는 충분하지 않습니다.
- 프로덕션 인벤토리 보호: 스테이징 및 프로덕션에 대해 별도의 인벤토리와 자격 증명을 사용하십시오.
--limit의 오타로 인해 잘못된 위치에 배포되어서는 안 됩니다. - 가능하면 직렬 롤아웃 사용:
serial을 사용하면 한 번에 몇 개의 호스트를 업데이트하고 전체 플릿이 영향을 받기 전에 중지할 수 있습니다.
- name: 애플리케이션 점진적으로 배포
hosts: web
serial: 2
tasks:
- name: 릴리스 설치
ansible.builtin.unarchive:
src: "{{ artifact_path }}"
dest: /opt/myapp/releases/{{ release_version }}
remote_src: true
serial을 사용하면 Ansible이 호스트를 배치로 처리합니다. 애플리케이션이 활성 요청을 드롭하지 않고 다시 시작할 수 없는 경우 로드 밸런서 드레이닝과 결합하십시오.
구체적인 배포 흐름
웹 애플리케이션을 위한 안전한 Ansible 배포는 다음과 같을 수 있습니다:
00-preflight.yml은 디스크 공간을 확인하고, 대상 릴리스가 존재하는지 확인하고, 데이터베이스 연결을 확인하고, 호스트가 예상 환경에 있는지 확인합니다. 시스템을 변경하지 않습니다.
01-migrate-db.yml은 이전 버전과 호환되는 마이그레이션만 실행합니다. 마이그레이션 버전을 기록하고 데이터베이스가 요청된 릴리스보다 이미 앞서 있으면 실패합니다.
02-deploy-app.yml은 아티팩트를 다운로드하고, 버전이 지정된 릴리스 디렉토리에 압축을 풀고, 구성을 템플릿화하고, current 심볼릭 링크를 업데이트합니다. 아직 서비스를 다시 시작하지 않습니다.
03-reload-services.yml은 각 호스트를 로드 밸런서에서 드레이닝하고, 서비스를 재로드하거나 다시 시작하고, 로컬 상태 엔드포인트를 기다린 다음 호스트를 서비스로 반환합니다.
04-smoke-test.yml은 사용자가 사용하는 것과 동일한 경로를 통해 공용 엔드포인트를 호출합니다. 로드 밸런서 기본 페이지의 200뿐만 아니라 응답 본문 또는 버전 엔드포인트를 확인합니다.
이 흐름은 한 번의 명령으로 다시 시작하는 것보다 느립니다. 배포가 중간에 실패할 때 추론하기도 훨씬 쉽습니다.
이것을 작동하게 만드는 습관
순차적 Ansible 플레이북은 각각이 좁은 계약(예상하는 것, 변경하는 것, 성공을 증명하는 방법, 실패 시 수행할 작업)을 가질 때 가장 잘 작동합니다. 그 계약은 YAML 파일 수보다 더 중요합니다.
실제 위험을 반영하는 단계(사전 점검, 마이그레이션, 배포, 재로드, 스모크 테스트, 롤백)부터 시작하십시오. 명령을 지루하게 유지하십시오. 필요하기 전에 롤백을 테스트하십시오. 배포가 중단되면 정확히 실패한 단계를 지적하고 전체 자동화 트리를 다시 읽지 않고 다음 단계를 결정할 수 있어야 합니다.