본문 바로가기
카테고리 없음

Ansible과 K8s 무중단 배포 (Ansible, 블루그린, 프로브)

by ricepuppy9733 2026. 6. 10.

서버 10대에 nginx를 수동으로 깔아본 적 있으신가요? 저는 있습니다. 그리고 그 경험 덕분에 Ansible의 소중함을 뼛속 깊이 알게 됐습니다. 이 글은 Ansible로 반복 작업을 자동화하고, 쿠버네티스 환경에서 블루/그린 배포와 Probe를 활용해 무중단 배포를 구현한 과정을 정리한 기록입니다.

 

Ansible과 K8s 무중단 배포

Ansible이 필요한 이유, 직접 겪어보니

서버가 한 대일 땐 SSH 접속해서 명령어 치면 그만입니다. 그런데 관리해야 할 노드가 세 대, 다섯 대를 넘어가는 순간부터 상황이 달라집니다. 같은 명령어를 여러 번 반복하다 보면 어느 서버에 뭘 했는지 헷갈리기 시작하고, 결국 실수가 나옵니다. 제가 직접 겪어본 일입니다.

Ansible은 스토리지, 서버, 네트워킹 구성을 자동화하는 구성 관리 플랫폼(Configuration Management Platform)입니다. 여기서 구성 관리 플랫폼이란 여러 서버의 상태를 코드로 정의해두고, 그 상태를 일괄로 적용·유지하는 도구를 말합니다. 즉, "이 서버들엔 nginx가 설치돼 있어야 한다"는 내용을 파일로 써두면 Ansible이 알아서 처리해줍니다.

Ansible의 구조는 크게 세 축으로 나뉩니다.

  • Control Node: Ansible이 설치된 서버로, 여기서 모든 명령을 내립니다.
  • Managed Node: 실제로 관리 대상이 되는 서버들입니다. Ansible을 설치할 필요가 없습니다.
  • Inventory: Managed Node의 IP 주소, 호스트 정보, 그룹 정보를 정의한 목록 파일입니다.

특히 인상적인 건 멱등성(Idempotency)이라는 개념입니다. 멱등성이란 같은 작업을 여러 번 반복 실행해도 결과가 항상 동일하게 유지되는 성질을 말합니다. 예를 들어 nginx가 이미 설치된 서버에 Ansible 플레이북을 다시 돌려도 에러 없이 "이미 있으니 패스" 하고 넘어갑니다. 처음엔 그냥 넘겼던 개념인데, 실제로 플레이북을 반복 실행하면서 이 특성이 얼마나 실용적인지 체감했습니다.

Playbook으로 JDK 설치 자동화하기

Ansible의 핵심 실행 단위는 플레이북(Playbook)입니다. 플레이북이란 어떤 서버에 어떤 작업을 어떤 순서로 실행할지 YAML 형식으로 정의한 파일입니다. 쉽게 말해 "서버에 내릴 작업 지시서"라고 보면 됩니다.

제가 실습에서 사용한 플레이북은 hosts: all로 모든 관리 노드에 JDK 17을 설치하는 내용이었습니다. become: yes 옵션은 sudo 권한으로 실행하겠다는 선언이고, apt 모듈의 state: present는 해당 패키지가 설치된 상태를 보장하라는 의미입니다. 없으면 설치하고, 있으면 그냥 두는 방식이니 멱등성이 자연스럽게 적용됩니다.

Control Node에서 먼저 SSH 키를 생성하고(ssh-keygen), 각 Managed Node에 공개 키를 복사(ssh-copy-id)하는 과정이 선행돼야 합니다. 이렇게 하면 이후 Ansible 실행 시 패스워드 없이 자동으로 접속이 가능해집니다. 처음에 이 키 설정을 귀찮다고 건너뛰었다가 나중에 다시 처음부터 했던 기억이 납니다. 순서를 지키는 게 생각보다 중요합니다.

실행 명령어는 ansible-playbook -i hosts.yml playbook.yml 형태입니다. -i 옵션으로 커스텀 인벤토리 파일을 지정할 수 있고, 기본 인벤토리는 /etc/ansible/hosts를 바라봅니다. Ansible 공식 문서에 따르면 모듈(Module) 단위로 기능이 분리되어 있어, 데이터베이스 관리·사용자 관리·네트워크 장치 관리 등 목적에 맞는 모듈을 플레이북 안에서 조합해 사용할 수 있습니다(출처: Ansible 공식 문서).

쿠버네티스 Probe로 진짜 무중단 배포 구현하기

서버 자동화를 넘어서 쿠버네티스(K8s) 환경으로 넘어오면 무중단 배포가 핵심 과제가 됩니다. 여기서 핵심은 livenessProbe와 readinessProbe, 두 가지 Probe입니다.

livenessProbe란 컨테이너가 현재 살아있는지 여부를 주기적으로 확인하는 헬스 체크 메커니즘입니다. 지정한 시간 안에 응답이 없으면 쿠버네티스가 해당 Pod를 자동으로 재시작합니다. 무한 루프나 메모리 에러로 서버가 응답 불능 상태에 빠졌을 때 사람이 개입하지 않아도 자가 치유(Self-healing)가 가능한 이유가 바로 이 Probe 덕분입니다.

readinessProbe는 조금 다릅니다. readinessProbe란 컨테이너가 실제 트래픽을 받을 준비가 완료됐는지 확인하는 장치입니다. Ready 상태를 통과하지 못하면 Service의 엔드포인트 목록에서 제외되어 해당 Pod로는 요청이 전달되지 않습니다. 새 버전이 뜨더라도 준비가 끝나기 전까지는 트래픽이 흘러들어오지 않는다는 뜻입니다.

제가 직접 설정해보니 initialDelaySeconds와 successThreshold 값 조정이 생각보다 민감했습니다. 애플리케이션 기동 시간이 20초를 넘는데 initialDelaySeconds를 5초로 짧게 잡으면 멀쩡한 컨테이너가 계속 재시작되는 상황이 발생합니다. 실제로 이 설정 하나 때문에 Pod가 CrashLoopBackOff 상태에서 못 빠져나오는 걸 겪고 나서야 값을 꼼꼼히 맞추게 됐습니다.

블루/그린 배포와 CI/CD 파이프라인 연결

Probe 기반 롤링 업데이트가 자동화된 점진적 전환이라면, 블루/그린(Blue/Green) 배포는 좀 더 통제된 방식의 전환 전략입니다. 블루/그린 배포란 현재 서비스 중인 버전(Blue)과 새 버전(Green)을 동시에 띄워두고, 테스트가 완료된 시점에 Service의 셀렉터(selector)를 바꿔 트래픽을 전환하는 방식입니다.

가장 큰 장점은 롤백이 단순하다는 점입니다. 새 버전에서 문제가 터지면 셀렉터를 다시 blue로 되돌리면 끝입니다. 반면 단점도 분명합니다. 두 버전이 동시에 실행되는 시간 동안 리소스가 두 배로 사용됩니다. 클러스터 여유 자원이 충분하지 않은 상황이라면 일반적으로 좋은 선택이라고 알려져 있지만, 저는 실제 환경에선 신중하게 판단해야 한다고 생각합니다.

여기에 GitHub Actions를 연결하면 코드 푸시부터 배포까지 전 과정이 자동화됩니다. 파이프라인 흐름을 정리하면 다음과 같습니다.

  1. main 브랜치에 코드가 푸시되면 GitHub Actions 워크플로우가 트리거됩니다.
  2. Gradle로 jar를 빌드하고, Docker 이미지를 빌드해 DockerHub에 push합니다.
  3. appleboy/ssh-action으로 원격 서버에 SSH 접속합니다.
  4. kubectl apply 명령으로 K8s 클러스터에 새 이미지 버전을 배포합니다.

이미지 태그에 ${{ github.run_number }}를 활용하면 빌드 번호가 자동으로 붙어 버전 추적이 편해집니다. 쿠버네티스 공식 문서에 따르면 이처럼 Deployment의 이미지 태그를 변경하는 방식이 컨테이너 기반 롤링 업데이트의 표준적인 트리거 방식으로 권장됩니다(출처: Kubernetes 공식 문서).

LVM(Logical Volume Manager) 설정도 이 실습에서 빠뜨릴 수 없는 부분이었습니다. LVM이란 물리 디스크와 파티션을 추상화하여 논리적 볼륨 단위로 유연하게 관리할 수 있도록 해주는 리눅스 볼륨 관리 시스템입니다. Longhorn 스토리지와 PVC(PersistentVolumeClaim)를 연결하기 전에 VM에 HDD를 추가하고 pvcreate, vgextend, lvextend, resize2fs 순서로 볼륨을 확장하는 작업이 필요했는데, 순서를 건너뛰면 마운트가 실패합니다. 제가 직접 순서를 틀려서 처음부터 다시 한 경험이 있어서 더 기억에 남습니다.

Ansible로 반복 작업을 줄이고, Probe로 배포 안정성을 확보하고, 블루/그린 전략으로 리스크를 최소화하고, CI/CD로 전체를 묶어내는 과정이 처음엔 각각 따로 놀았는데 결국 하나의 흐름으로 이어진다는 걸 실습하면서 느꼈습니다. 다음 단계로는 Istio 서비스 메쉬와 Kiali, Prometheus를 활용한 모니터링 연동이 남아 있는데, 각 컴포넌트가 실제로 어떻게 맞물리는지 정리해서 이어가볼 생각입니다.


참고: https://dltldnr2563.tistory.com/entry/%EC%BD%94%EB%94%A9%EA%B3%B5%EB%B6%8020250916-Ansible-HDD-%EC%B6%94%EA%B0%80-Namespace-%EB%AC%B4%EC%A4%91%EB%8B%A8%EB%B0%B0%ED%8F%AC%EB%B8%94%EB%A3%A8%EA%B7%B8%EB%A6%B0-%ED%94%84%EB%A1%9C%EB%B8%8C


소개 및 문의 · 개인정보처리방침 · 면책조항

© 2026 자동식단생성 연관 블로그