🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

Ansible 아키텍처와 핵심 개념 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 12. 29. · 0 Views

Ansible 아키텍처와 핵심 개념 완벽 가이드

서버 100대를 한 번에 관리할 수 있는 Ansible의 핵심 아키텍처를 초급 개발자 눈높이에 맞춰 설명합니다. Push 기반 아키텍처부터 멱등성, Playbook까지 실무에 바로 적용할 수 있는 내용을 담았습니다.


목차

  1. Push 기반 아키텍처 이해
  2. SSH를 통한 원격 실행
  3. 멱등성 개념
  4. 모듈의 역할
  5. Playbook과 Task
  6. Ansible 설정 파일 구조

1. Push 기반 아키텍처 이해

입사 2개월 차 김개발 씨는 오늘도 서버 관리 작업에 골머리를 앓고 있습니다. 새로운 보안 패치를 10대의 서버에 적용해야 하는데, 서버마다 일일이 접속해서 명령어를 실행하는 것이 너무 번거롭습니다.

"이걸 자동화할 방법은 없을까요?" 선배 박시니어 씨가 웃으며 답합니다. "Ansible을 한번 써보세요."

AnsiblePush 기반 아키텍처를 사용하는 자동화 도구입니다. 마치 총괄 매니저가 각 팀원에게 업무 지시를 내리는 것처럼, 하나의 제어 노드에서 여러 관리 노드로 명령을 전달합니다.

별도의 에이전트 설치 없이 SSH만으로 동작하기 때문에 설정이 매우 간단합니다. 이 구조를 이해하면 대규모 서버 관리가 얼마나 쉬워지는지 알 수 있습니다.

다음 코드를 살펴봅시다.

# Ansible 인벤토리 파일 (inventory.ini)
[webservers]
web1.example.com
web2.example.com
web3.example.com

[dbservers]
db1.example.com
db2.example.com

# 간단한 ping 테스트 명령
# ansible all -i inventory.ini -m ping
# 제어 노드에서 모든 서버로 명령을 Push합니다

김개발 씨는 처음 들어본 Ansible이라는 도구가 궁금해졌습니다. 박시니어 씨가 화이트보드 앞으로 가서 그림을 그리기 시작합니다.

"자, 여기 봐요. 이게 Ansible의 핵심 구조예요." 화이트보드에는 하나의 큰 원과 여러 개의 작은 원들이 화살표로 연결되어 있습니다.

Push 기반 아키텍처란 정확히 무엇일까요? 쉽게 비유하자면, Push 아키텍처는 마치 본사에서 각 지점으로 공문을 보내는 것과 같습니다.

본사 직원이 각 지점에 전화를 걸어 지시 사항을 전달하면, 각 지점은 그 지시를 실행합니다. 반대로 Pull 아키텍처는 각 지점이 주기적으로 본사에 전화해서 "새로운 지시 사항 있나요?"라고 물어보는 방식입니다.

Ansible은 전자의 방식을 택했습니다. 왜 이런 방식을 선택했을까요?

전통적인 구성 관리 도구들은 각 서버에 에이전트를 설치해야 했습니다. Puppet이나 Chef 같은 도구들이 대표적입니다.

이들은 각 서버에 설치된 에이전트가 주기적으로 중앙 서버에 접속해서 변경 사항을 가져오는 Pull 방식을 사용했습니다. 서버가 10대, 100대로 늘어나면 각 서버마다 에이전트를 설치하고 관리하는 것이 큰 부담이 되었습니다.

바로 이런 문제를 해결하기 위해 Ansible은 에이전트리스 아키텍처를 채택했습니다. Ansible을 사용하면 관리 대상 서버에 아무것도 설치할 필요가 없습니다.

이미 모든 리눅스 서버에 설치되어 있는 SSH만 있으면 됩니다. 제어 노드에서 명령을 실행하면, 그 명령이 SSH를 통해 각 서버로 전달되고 즉시 실행됩니다.

무엇보다 관리가 단순해진다는 큰 이점이 있습니다. Ansible의 구조를 좀 더 자세히 살펴보겠습니다.

먼저 제어 노드가 있습니다. 이곳은 Ansible이 설치되어 있고, 모든 명령이 시작되는 곳입니다.

개발자나 운영자가 작업하는 곳이죠. 다음으로 관리 노드들이 있습니다.

이들은 Ansible로 관리하려는 서버들입니다. 웹 서버일 수도 있고, 데이터베이스 서버일 수도 있습니다.

제어 노드에서 명령을 실행하면 어떤 일이 일어날까요? Ansible은 먼저 인벤토리 파일을 읽습니다.

인벤토리 파일에는 관리할 서버들의 목록이 적혀 있습니다. 위의 예제처럼 webservers 그룹에 3대의 웹 서버가, dbservers 그룹에 2대의 데이터베이스 서버가 등록되어 있을 수 있습니다.

그런 다음 Ansible은 SSH를 통해 각 서버에 접속합니다. 필요한 파이썬 스크립트를 임시로 전송하고, 실행하고, 결과를 받아온 뒤 깔끔하게 정리합니다.

실제 현업에서는 어떻게 활용할까요? 예를 들어 전국에 100대의 웹 서버를 운영하는 쇼핑몰 회사가 있다고 가정해봅시다.

긴급 보안 패치가 나왔습니다. 예전 같았으면 운영팀이 밤을 새워 100대의 서버에 일일이 접속해서 패치를 적용해야 했습니다.

하지만 Ansible을 사용하면 한 줄의 명령으로 모든 서버에 동시에 패치를 적용할 수 있습니다. 많은 기업에서 이런 방식으로 수천 대의 서버를 관리하고 있습니다.

하지만 주의할 점도 있습니다. Push 방식의 특성상 제어 노드가 다운되면 자동화 작업을 실행할 수 없습니다.

또한 제어 노드에서 모든 관리 노드에 SSH 접속이 가능해야 하므로, 네트워크 방화벽 설정을 신경 써야 합니다. 따라서 제어 노드는 보안이 철저하게 관리되는 곳에 두어야 합니다.

다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 설명을 들은 김개발 씨는 눈이 반짝였습니다.

"와, 에이전트 설치 없이 SSH만으로 가능하다니 정말 간단하네요!" Push 기반 아키텍처를 제대로 이해하면 왜 Ansible이 인기 있는지 알 수 있습니다. 간단한 구조 덕분에 배우기 쉽고, 유지보수도 편합니다.

여러분도 오늘 배운 내용을 바탕으로 간단한 서버 관리부터 시작해 보세요.

실전 팁

💡 - 제어 노드는 리눅스나 macOS여야 하지만, 관리 노드는 Windows도 가능합니다

  • 인벤토리 파일을 그룹별로 잘 정리하면 특정 서버군에만 명령을 실행하기 쉽습니다
  • SSH 키 기반 인증을 설정하면 비밀번호 없이 안전하게 접속할 수 있습니다

2. SSH를 통한 원격 실행

김개발 씨가 다음 질문을 던집니다. "그런데 Ansible이 SSH로 어떻게 명령을 실행하는 건가요?

제가 직접 SSH로 접속하는 것과 다른가요?" 박시니어 씨가 고개를 끄덕입니다. "좋은 질문이에요.

Ansible의 SSH 사용법을 자세히 알아보죠."

Ansible은 SSH 프로토콜을 통해 관리 노드에 접속하여 명령을 실행합니다. 마치 리모컨으로 TV를 제어하는 것처럼, SSH를 통해 원격 서버를 제어합니다.

Python 스크립트를 임시로 전송하고 실행한 뒤 결과를 받아오는 방식으로 동작합니다. 이 과정을 이해하면 Ansible이 어떻게 에이전트 없이도 강력한 자동화를 제공하는지 알 수 있습니다.

다음 코드를 살펴봅시다.

# ansible.cfg 설정 파일
[defaults]
inventory = ./inventory.ini
remote_user = ansible
private_key_file = ~/.ssh/ansible_key
host_key_checking = False

# SSH 연결 테스트 및 정보 수집
# ansible webservers -m setup -a "filter=ansible_distribution*"
# setup 모듈이 SSH를 통해 시스템 정보를 수집합니다

# 실제 명령 실행 예제
# ansible webservers -m command -a "uptime"
# SSH로 접속하여 uptime 명령을 실행하고 결과를 반환합니다

김개발 씨는 지금까지 SSH를 단순히 서버에 접속하는 도구로만 생각했습니다. 터미널을 열고 "ssh user@server" 명령을 입력하면 원격 서버에 접속되고, 그곳에서 직접 명령을 입력하는 것이 전부였습니다.

하지만 Ansible은 SSH를 훨씬 더 똑똑하게 사용합니다. SSH를 통한 원격 실행의 원리를 살펴보겠습니다.

쉽게 비유하자면, SSH는 마치 우편 배달 시스템과 같습니다. 우체부가 편지를 배달하고 답장을 받아오듯이, SSH는 명령을 전달하고 실행 결과를 가져옵니다.

일반적으로 우리가 SSH를 사용할 때는 우체부와 함께 직접 집을 방문하는 것과 같지만, Ansible이 SSH를 사용할 때는 우체부에게 심부름을 시키는 것과 같습니다. 직접 가지 않아도 일을 처리할 수 있는 것이죠.

Ansible이 없던 시절에는 어땠을까요? 시스템 관리자들은 Shell 스크립트를 작성해서 각 서버에 일일이 접속하여 실행했습니다.

10대의 서버라면 for 루프를 돌며 SSH 명령을 10번 실행하는 스크립트를 만들었죠. 문제는 한 서버에서 오류가 나면 어떻게 처리할지, 어느 서버는 성공하고 어느 서버는 실패했는지 추적하기가 어려웠습니다.

더 큰 문제는 병렬 실행이나 재시도 같은 기능을 직접 구현해야 했다는 점입니다. 바로 이런 문제를 해결하기 위해 Ansible은 SSH 기반 자동화 프레임워크를 제공합니다.

Ansible을 사용하면 복잡한 SSH 연결 관리를 신경 쓸 필요가 없습니다. 인증 방식, 연결 재시도, 병렬 실행, 오류 처리 등이 모두 자동으로 처리됩니다.

또한 실행 결과를 구조화된 형태로 받아볼 수 있어 성공/실패 여부를 쉽게 파악할 수 있습니다. 무엇보다 멱등성을 보장하는 모듈 시스템이 제공된다는 큰 이점이 있습니다.

Ansible이 SSH를 사용하는 과정을 단계별로 살펴보겠습니다. 먼저 Ansible은 설정 파일을 읽어 SSH 연결 정보를 확인합니다.

위의 예제에서 remote_user는 접속할 사용자 이름이고, private_key_file은 SSH 키 파일의 경로입니다. host_key_checking을 False로 설정하면 처음 접속하는 서버에 대해 fingerprint 확인을 건너뜁니다.

다음으로 Ansible은 실행할 모듈에 해당하는 Python 코드를 생성합니다. 그런 다음 SSH를 통해 원격 서버에 접속하여 /tmp 디렉토리에 임시 파일을 생성하고 Python 스크립트를 전송합니다.

스크립트가 전송되면 어떤 일이 일어날까요? 원격 서버에서 Python 인터프리터가 스크립트를 실행합니다.

예를 들어 setup 모듈이라면 시스템 정보를 수집하는 코드가 실행되고, command 모듈이라면 지정된 명령어가 실행됩니다. 실행이 완료되면 결과가 JSON 형태로 표준 출력에 출력됩니다.

Ansible은 이 JSON 결과를 받아서 파싱하고, 임시 파일을 삭제한 뒤 SSH 연결을 종료합니다. 모든 과정이 자동으로 처리됩니다.

실제 현업에서는 어떻게 활용할까요? 예를 들어 클라우드 환경에서 오토스케일링으로 새 서버가 계속 생성되는 상황을 생각해봅시다.

새 서버가 생성될 때마다 초기 설정을 해야 합니다. 예전 같았으면 초기화 스크립트를 만들어 각 서버에서 실행했을 것입니다.

하지만 Ansible을 사용하면 제어 노드에서 한 번의 명령으로 새 서버들을 자동으로 설정할 수 있습니다. AWS, Azure, GCP 등 모든 클라우드에서 동일한 방식으로 동작합니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 SSH 키 권한 설정을 잘못하는 것입니다.

SSH 개인키 파일은 반드시 600 권한을 가져야 합니다. 그렇지 않으면 SSH가 보안상의 이유로 연결을 거부합니다.

또한 known_hosts 파일 관리도 중요합니다. 따라서 처음 설정할 때는 host_key_checking을 신중하게 설정해야 합니다.

다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 설명을 들은 김개발 씨는 감탄했습니다.

"SSH를 이렇게 활용할 수 있다니 놀랍네요!" SSH를 통한 원격 실행을 제대로 이해하면 Ansible의 동작 방식이 명확해집니다. 복잡해 보이지만 실제로는 SSH라는 익숙한 프로토콜 위에서 동작하기 때문에 안전하고 신뢰할 수 있습니다.

여러분도 오늘 배운 내용을 바탕으로 SSH 키 설정부터 시작해 보세요.

실전 팁

💡 - SSH 키는 ssh-keygen으로 생성하고, ssh-copy-id로 관리 노드에 배포하면 편리합니다

  • ControlPersist 옵션을 사용하면 SSH 연결을 재사용하여 성능을 크게 향상시킬 수 있습니다
  • 방화벽 환경에서는 SSH 포트가 열려 있는지 먼저 확인하세요

3. 멱등성 개념

김개발 씨가 첫 Ansible 명령을 실행했습니다. 같은 명령을 두 번 실행했는데, 첫 번째는 "changed"가 표시되고 두 번째는 "ok"만 표시되었습니다.

"왜 결과가 다르죠?" 박시니어 씨가 웃으며 답합니다. "그게 바로 멱등성이에요.

Ansible의 가장 중요한 특징 중 하나죠."

멱등성은 같은 작업을 여러 번 실행해도 결과가 동일하게 유지되는 성질을 말합니다. 마치 전등 스위치를 여러 번 켜도 전등은 켜진 상태로 유지되는 것과 같습니다.

Ansible의 대부분의 모듈은 멱등성을 보장하여, 이미 원하는 상태라면 아무것도 변경하지 않습니다. 이 개념을 이해하면 안전하게 자동화 스크립트를 반복 실행할 수 있습니다.

다음 코드를 살펴봅시다.

---
# install_nginx.yml - 멱등성을 보장하는 Playbook
- hosts: webservers
  become: yes
  tasks:
    - name: Nginx 패키지 설치
      apt:
        name: nginx
        state: present
      # 이미 설치되어 있다면 아무것도 하지 않습니다

    - name: Nginx 서비스 시작
      service:
        name: nginx
        state: started
        enabled: yes
      # 이미 실행 중이라면 재시작하지 않습니다

김개발 씨는 처음에는 혼란스러웠습니다. 분명 같은 명령을 실행했는데 왜 결과가 다를까요?

첫 번째 실행에서는 노란색으로 "changed: 1"이 표시되었고, 두 번째 실행에서는 초록색으로 "ok: 1"만 표시되었습니다. 뭔가 잘못된 건 아닐까요?

박시니어 씨가 차분히 설명을 시작합니다. "이게 바로 Ansible을 특별하게 만드는 핵심 개념이에요." 멱등성이란 정확히 무엇일까요?

쉽게 비유하자면, 멱등성은 마치 목적지를 찾아가는 네비게이션과 같습니다. 이미 목적지에 도착했다면 네비게이션은 "도착했습니다"라고 말할 뿐 더 이상 길 안내를 하지 않습니다.

다시 목적지 검색을 해도 "이미 목적지에 있습니다"라고 알려줍니다. Ansible도 마찬가지입니다.

이미 원하는 상태라면 시스템을 변경하지 않고 "이미 원하는 상태입니다"라고 알려줄 뿐입니다. 멱등성이 없으면 어떤 문제가 생길까요?

전통적인 Shell 스크립트를 생각해봅시다. "apt install nginx" 명령을 실행하면 nginx를 설치합니다.

하지만 이미 nginx가 설치되어 있어도 같은 작업을 다시 시도합니다. 운이 좋으면 "이미 최신 버전입니다"라는 메시지만 보겠지만, 경우에 따라서는 설정 파일이 덮어써지거나 서비스가 재시작될 수 있습니다.

프로덕션 환경에서 이런 일이 생기면 서비스 장애로 이어질 수 있습니다. 바로 이런 문제를 해결하기 위해 Ansible은 선언적 방식멱등성을 채택했습니다.

Ansible을 사용하면 "이렇게 하라"는 명령형이 아니라 "이런 상태여야 한다"는 선언형으로 작성합니다. 위의 예제를 보면 "state: present"라고 적혀 있습니다.

이는 "nginx가 설치되어 있어야 한다"는 뜻입니다. Ansible은 먼저 현재 상태를 확인합니다.

이미 nginx가 설치되어 있으면 아무것도 하지 않고 "ok"를 반환합니다. 설치되어 있지 않으면 설치하고 "changed"를 반환합니다.

코드를 한 줄씩 살펴보겠습니다. 먼저 apt 모듈은 패키지 관리를 담당합니다.

name은 패키지 이름이고, state는 원하는 상태입니다. present는 "설치되어 있어야 함"을 의미하고, absent는 "설치되어 있지 않아야 함"을 의미합니다.

내부적으로 apt 모듈은 "dpkg -l | grep nginx" 같은 명령으로 현재 상태를 확인합니다. 다음으로 service 모듈은 서비스 상태를 관리합니다.

state: started는 "실행 중이어야 함"을 의미하고, enabled: yes는 "부팅 시 자동 시작되어야 함"을 의미합니다. 이 Playbook을 여러 번 실행하면 어떻게 될까요?

첫 번째 실행에서는 nginx가 설치되어 있지 않으므로 apt 모듈이 패키지를 설치합니다. "changed" 상태가 됩니다.

서비스도 실행되지 않았으므로 service 모듈이 서비스를 시작합니다. 역시 "changed"입니다.

두 번째 실행에서는 nginx가 이미 설치되어 있고 서비스도 실행 중입니다. 따라서 모든 태스크가 "ok"를 반환하고 시스템에는 아무런 변경이 일어나지 않습니다.

열 번을 실행해도 결과는 같습니다. 실제 현업에서는 어떻게 활용할까요?

예를 들어 매일 밤 자동으로 실행되는 설정 관리 작업이 있다고 가정해봅시다. 모든 웹 서버가 정확히 같은 상태를 유지해야 합니다.

Ansible Playbook을 cron으로 매일 밤 실행하면, 혹시 누군가 실수로 설정을 변경했더라도 다음 날 아침에는 자동으로 올바른 상태로 복구됩니다. 멱등성 덕분에 이미 올바른 상태의 서버에는 아무런 영향을 주지 않으면서도, 잘못된 상태의 서버만 정확하게 고칠 수 있습니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 command 모듈이나 shell 모듈을 무분별하게 사용하는 것입니다.

이 모듈들은 멱등성을 보장하지 않습니다. 왜냐하면 Ansible이 임의의 Shell 명령의 결과를 예측할 수 없기 때문입니다.

따라서 가능하면 apt, yum, copy, template 같은 전용 모듈을 사용해야 합니다. 정말로 command를 써야 한다면 creates나 removes 같은 조건을 함께 사용하여 멱등성을 직접 구현해야 합니다.

다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 설명을 들은 김개발 씨는 고개를 끄덕였습니다.

"아, 그래서 두 번째 실행에서는 changed가 아니라 ok가 나왔군요!" 멱등성을 제대로 이해하면 Ansible을 안전하게 사용할 수 있습니다. 프로덕션 환경에서 같은 Playbook을 여러 번 실행해도 걱정할 필요가 없습니다.

여러분도 오늘 배운 내용을 바탕으로 멱등성을 보장하는 Playbook을 작성해 보세요.

실전 팁

💡 - check 모드를 사용하면 실제로 변경하지 않고 무엇이 바뀔지 미리 확인할 수 있습니다

  • diff 모드를 함께 사용하면 파일 변경 내용을 자세히 볼 수 있습니다
  • command 모듈 대신 가능하면 전용 모듈을 사용하여 멱등성을 보장하세요

4. 모듈의 역할

김개발 씨가 Ansible 문서를 읽다가 수많은 모듈 목록을 보고 당황했습니다. "이게 다 뭐예요?

종류가 너무 많아요!" 박시니어 씨가 웃으며 답합니다. "모듈은 Ansible의 핵심 부품이에요.

각각의 모듈은 특정 작업을 위한 전문가라고 생각하면 돼요."

모듈은 Ansible이 실제 작업을 수행하는 단위입니다. 마치 공구함의 각 도구가 특정 용도를 가진 것처럼, 각 모듈은 특정 작업을 전문적으로 처리합니다.

패키지 설치, 파일 복사, 서비스 관리, 클라우드 리소스 생성 등 다양한 모듈이 있습니다. 이들을 적재적소에 사용하면 복잡한 인프라 작업도 간단하게 자동화할 수 있습니다.

다음 코드를 살펴봅시다.

---
# modules_example.yml - 다양한 모듈 활용 예제
- hosts: webservers
  become: yes
  tasks:
    - name: 패키지 설치 (apt 모듈)
      apt:
        name: ['nginx', 'git', 'curl']
        state: present
        update_cache: yes

    - name: 설정 파일 복사 (copy 모듈)
      copy:
        src: ./nginx.conf
        dest: /etc/nginx/nginx.conf
        owner: root
        group: root
        mode: '0644'
      notify: Restart Nginx

    - name: 디렉토리 생성 (file 모듈)
      file:
        path: /var/www/html
        state: directory
        owner: www-data
        group: www-data

  handlers:
    - name: Restart Nginx
      service:
        name: nginx
        state: restarted

김개발 씨는 Ansible 공식 문서를 펼쳐보았습니다. 모듈 목록이 끝없이 이어집니다.

파일 관리, 패키지 관리, 클라우드 서비스, 네트워크 장비, 데이터베이스까지. "이걸 다 배워야 하나요?" 불안한 마음이 밀려옵니다.

박시니어 씨가 안심시킵니다. "전부 다 알 필요는 없어요.

자주 쓰는 핵심 모듈 10개 정도만 알아도 대부분의 작업을 할 수 있습니다." 모듈이란 정확히 무엇일까요? 쉽게 비유하자면, 모듈은 마치 레고 블록과 같습니다.

각 블록은 특정한 모양과 기능을 가지고 있습니다. 집을 지을 때 벽돌 블록을 쓰고, 지붕을 만들 때는 경사진 블록을 씁니다.

이들을 조합하면 복잡한 구조물을 만들 수 있습니다. Ansible 모듈도 마찬가지입니다.

각 모듈은 특정 작업을 위한 빌딩 블록이고, 이들을 조합하면 복잡한 인프라 자동화를 구현할 수 있습니다. 모듈이 없으면 어떻게 될까요?

예전에는 각 작업마다 Shell 명령어를 직접 작성해야 했습니다. 파일을 복사하려면 "cp" 명령을 쓰고, 권한을 변경하려면 "chmod"를 쓰고, 소유자를 바꾸려면 "chown"을 썼습니다.

문제는 OS마다 명령어가 다를 수 있다는 점입니다. Ubuntu는 apt를 쓰지만 CentOS는 yum을 씁니다.

이런 차이를 모두 if 문으로 처리해야 했습니다. 코드가 길어지고 유지보수가 어려웠습니다.

바로 이런 문제를 해결하기 위해 Ansible은 추상화된 모듈 시스템을 제공합니다. Ansible 모듈을 사용하면 OS의 차이를 신경 쓸 필요가 없습니다.

package 모듈은 자동으로 OS를 감지하여 Ubuntu에서는 apt를, CentOS에서는 yum을 사용합니다. copy 모듈은 파일 복사, 권한 설정, 소유자 변경을 한 번에 처리합니다.

무엇보다 모든 모듈이 멱등성을 보장한다는 큰 이점이 있습니다. 위의 코드를 한 줄씩 살펴보겠습니다.

먼저 apt 모듈은 데비안 계열 OS의 패키지를 관리합니다. name에 리스트를 전달하면 여러 패키지를 한 번에 설치할 수 있습니다.

update_cache는 "apt update"를 먼저 실행하라는 의미입니다. 다음으로 copy 모듈은 로컬 파일을 원격 서버로 복사합니다.

src는 원본 경로, dest는 목적지 경로입니다. owner와 group으로 소유자를, mode로 권한을 설정할 수 있습니다.

notify는 변경이 발생했을 때 handler를 실행하라는 의미입니다. file 모듈은 무엇을 할까요?

file 모듈은 파일이나 디렉토리를 관리합니다. state: directory는 디렉토리를 생성하라는 의미입니다.

이미 존재하면 아무것도 하지 않습니다. 권한과 소유자도 함께 설정할 수 있습니다.

마지막으로 handlers 섹션의 service 모듈은 시스템 서비스를 관리합니다. state: restarted는 서비스를 재시작하라는 의미입니다.

notify를 통해 설정 파일이 변경되었을 때만 재시작이 일어납니다. 모듈들은 어떻게 연결될까요?

copy 모듈에서 notify: Restart Nginx를 선언했습니다. 만약 nginx.conf 파일이 변경되면 Ansible은 이를 기억합니다.

모든 task가 완료된 후, handlers 섹션의 "Restart Nginx"가 실행됩니다. 이렇게 하면 여러 설정 파일을 변경하더라도 서비스는 한 번만 재시작됩니다.

불필요한 재시작을 방지하는 똑똑한 방법입니다. 실제 현업에서는 어떻게 활용할까요?

예를 들어 마이크로서비스 아키텍처에서 새로운 서비스를 배포한다고 가정해봅시다. git 모듈으로 코드를 받아오고, template 모듈으로 환경별 설정 파일을 생성하고, docker_container 모듈으로 컨테이너를 실행합니다.

각 모듈이 자기 역할에 충실하므로 Playbook이 읽기 쉽고 이해하기 쉽습니다. 수천 개의 모듈이 있지만 실제로는 10-20개 정도만 자주 사용합니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 모듈의 매개변수를 잘못 사용하는 것입니다.

각 모듈은 필수 매개변수와 선택적 매개변수를 가지고 있습니다. 문서를 잘 읽어보지 않고 추측으로 작성하면 오류가 발생합니다.

따라서 "ansible-doc 모듈명" 명령으로 문서를 확인하는 습관을 들여야 합니다. 터미널에서 바로 예제를 볼 수 있어 매우 편리합니다.

다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 설명을 들은 김개발 씨는 안도의 한숨을 쉬었습니다.

"아, 자주 쓰는 것만 알면 되는군요!" 모듈을 제대로 이해하면 Ansible의 진정한 힘을 발휘할 수 있습니다. 각 모듈의 역할을 이해하고 적재적소에 사용하면 복잡한 인프라도 간단한 코드로 관리할 수 있습니다.

여러분도 오늘 배운 핵심 모듈부터 하나씩 익혀 보세요.

실전 팁

💡 - ansible-doc 명령으로 모듈 문서와 예제를 터미널에서 바로 볼 수 있습니다

  • 모듈은 대부분 Python으로 작성되어 있어 필요하면 직접 커스텀 모듈을 만들 수 있습니다
  • Galaxy에서 커뮤니티가 만든 유용한 모듈과 role을 찾아 활용할 수 있습니다

5. Playbook과 Task

김개발 씨가 지금까지 배운 내용을 정리하려고 합니다. "모듈은 알겠는데, 이걸 어떻게 조직화해야 하죠?" 박시니어 씨가 새 파일을 열며 답합니다.

"그게 바로 Playbook과 Task의 역할이에요. 모듈을 조립하는 설계도라고 생각하면 됩니다."

Playbook은 Ansible의 자동화 시나리오를 정의하는 YAML 파일입니다. 마치 연극 대본처럼 어떤 서버에서 어떤 작업을 순서대로 실행할지 기술합니다.

Task는 Playbook 내의 개별 작업 단위로, 하나의 모듈 호출에 해당합니다. Playbook과 Task의 구조를 이해하면 복잡한 배포 시나리오도 체계적으로 작성할 수 있습니다.

다음 코드를 살펴봅시다.

---
# deploy_webapp.yml - 웹 애플리케이션 배포 Playbook
- name:  서버 설정
  hosts: webservers
  become: yes
  vars:
    app_port: 8080
    app_user: webapp

  tasks:
    - name: 애플리케이션 유저 생성
      user:
        name: "{{ app_user }}"
        state: present
        shell: /bin/bash

    - name: 소스 코드 다운로드
      git:
        repo: https://github.com/example/webapp.git
        dest: /opt/webapp
        version: main

    - name: 의존성 설치
      command: npm install
      args:
        chdir: /opt/webapp
        creates: /opt/webapp/node_modules

    - name: 애플리케이션 서비스 파일 배포
      template:
        src: webapp.service.j2
        dest: /etc/systemd/system/webapp.service
      notify: Restart Webapp

  handlers:
    - name: Restart Webapp
      systemd:
        name: webapp
        state: restarted
        enabled: yes
        daemon_reload: yes

김개발 씨는 지금까지 개별 모듈만 실행해봤습니다. "ansible webservers -m ping" 같은 ad-hoc 명령으로 간단한 작업을 했죠.

하지만 실제 업무에서는 여러 작업을 순서대로 실행해야 합니다. 웹 애플리케이션을 배포하려면 사용자를 만들고, 코드를 받아오고, 의존성을 설치하고, 서비스를 시작해야 합니다.

박시니어 씨가 화이트보드에 다시 그림을 그립니다. "Playbook은 이 모든 작업의 청사진이에요." PlaybookTask의 관계를 살펴보겠습니다.

쉽게 비유하자면, Playbook은 마치 요리 레시피와 같습니다. "김치찌개 만들기"라는 레시피가 있다면, 그 안에는 "재료 준비하기", "육수 끓이기", "김치 볶기", "재료 넣고 끓이기" 같은 단계별 지시가 있습니다.

각각의 단계가 Task입니다. 레시피를 순서대로 따라하면 맛있는 김치찌개가 완성되듯이, Playbook을 실행하면 완전히 설정된 서버가 완성됩니다.

Playbook이 없으면 어떻게 될까요? 매번 ad-hoc 명령을 순서대로 실행해야 합니다.

명령어 히스토리를 뒤져가며 이전에 뭘 했는지 찾아야 하고, 실수로 순서를 바꾸면 오류가 발생합니다. 여러 명이 협업할 때는 더 큰 문제입니다.

"이 서버 어떻게 설정한 거예요?"라는 질문에 답하기 어렵습니다. 문서화도 힘들고, 재현하기도 어렵습니다.

바로 이런 문제를 해결하기 위해 Ansible은 코드형 인프라 개념을 Playbook으로 구현했습니다. Playbook을 사용하면 인프라 설정이 코드로 남습니다.

Git으로 버전 관리할 수 있고, 코드 리뷰를 할 수 있습니다. 누구나 Playbook을 실행하면 동일한 환경을 만들 수 있습니다.

또한 문서화가 자동으로 됩니다. Playbook 자체가 "이 서버를 어떻게 설정했는가"에 대한 명확한 답이기 때문입니다.

무엇보다 재사용성이 뛰어나다는 큰 이점이 있습니다. 위의 코드를 구조별로 살펴보겠습니다.

먼저 Playbook의 헤더 부분입니다. name은 이 Playbook의 설명입니다.

hosts는 어느 서버 그룹에서 실행할지 지정합니다. become: yes는 sudo 권한으로 실행하라는 의미입니다.

vars 섹션에서는 변수를 정의합니다. app_port와 app_user 같은 값을 변수로 만들면 재사용이 쉽습니다.

tasks 섹션은 Playbook의 핵심입니다. 각 Task는 name으로 시작합니다.

이것은 사람이 읽을 수 있는 설명입니다. 실행 중에 화면에 표시되므로 무엇을 하는지 명확하게 작성해야 합니다.

그 아래에 모듈 이름과 매개변수가 옵니다. user 모듈은 사용자를 생성하고, git 모듈은 저장소를 clone합니다.

command 모듈은 임의의 명령을 실행하는데, args의 creates를 지정하여 멱등성을 부여했습니다. Task는 어떤 순서로 실행될까요?

Playbook의 Task는 위에서 아래로 순서대로 실행됩니다. 먼저 애플리케이션 유저를 생성하고, 그 다음 소스 코드를 다운로드합니다.

의존성을 설치한 후 서비스 파일을 배포합니다. 만약 중간에 Task가 실패하면 거기서 멈춥니다.

이후 Task는 실행되지 않습니다. 이렇게 하면 부분적으로 설정된 이상한 상태를 방지할 수 있습니다.

template 모듈과 handlers는 어떻게 연동될까요? template 모듈은 Jinja2 템플릿 파일을 렌더링하여 배포합니다.

webapp.service.j2 파일 안에는 "{{ app_port }}" 같은 변수가 들어 있고, 실행 시 8080으로 치환됩니다. 파일이 변경되면 notify를 통해 "Restart Webapp" handler가 예약됩니다.

모든 Task가 끝나면 handlers가 실행되어 systemd 서비스가 재시작됩니다. 실제 현업에서는 어떻게 활용할까요?

예를 들어 개발/스테이징/프로덕션 환경이 있다고 가정해봅시다. 같은 Playbook을 사용하되 변수만 다르게 전달하면 됩니다.

개발 환경에서는 app_port를 8080으로, 프로덕션에서는 80으로 설정할 수 있습니다. inventory 파일에 환경별로 변수를 정의하거나, extra-vars로 명령줄에서 전달할 수 있습니다.

이렇게 하면 환경별로 Playbook을 따로 관리할 필요가 없습니다. 하지만 주의할 점도 있습니다.

초보 개발자들이 흔히 하는 실수 중 하나는 Playbook을 너무 길게 작성하는 것입니다. 수백 줄짜리 Playbook은 읽기도 어렵고 유지보수도 힘듭니다.

따라서 역할별로 Playbook을 분리하거나 Role이라는 개념을 사용해야 합니다. 또한 Task의 name을 대충 작성하면 실행 로그를 읽기 어렵습니다.

명확하고 구체적으로 작성하는 습관이 중요합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.

박시니어 씨의 설명을 들은 김개발 씨는 신이 났습니다. "와, 이제 복잡한 배포 과정도 코드로 관리할 수 있겠네요!" Playbook과 Task를 제대로 이해하면 반복 가능하고 예측 가능한 인프라 관리가 가능해집니다.

한 번 작성한 Playbook은 몇 번이고 재사용할 수 있습니다. 여러분도 오늘 배운 내용을 바탕으로 간단한 배포 Playbook부터 작성해 보세요.

실전 팁

💡 - tags를 사용하면 Playbook의 특정 Task만 선택적으로 실행할 수 있습니다

  • when 조건문으로 특정 상황에서만 Task를 실행하도록 제어할 수 있습니다
  • include_tasks나 import_tasks로 Playbook을 모듈화하여 재사용성을 높일 수 있습니다

6. Ansible 설정 파일 구조

김개발 씨가 첫 Playbook을 작성했습니다. 하지만 실행할 때마다 인벤토리 파일 경로를 지정해야 해서 불편합니다.

"이걸 기본값으로 설정할 수는 없나요?" 박시니어 씨가 답합니다. "ansible.cfg 파일을 만들면 되죠.

Ansible의 동작을 제어하는 설정 파일이에요."

Ansible 설정 파일은 Ansible의 동작 방식을 제어하는 구성 파일입니다. 마치 자동차의 계기판 설정처럼 기본값, 경로, 동작 옵션 등을 지정합니다.

ansible.cfg, 인벤토리 파일, group_vars, host_vars 등의 구조를 이해하면 프로젝트를 체계적으로 구성할 수 있습니다. 설정을 잘 관리하면 실행 명령이 간결해지고 협업이 쉬워집니다.

다음 코드를 살펴봅시다.

# ansible.cfg - 프로젝트 설정 파일
[defaults]
inventory = ./inventory/production
remote_user = ansible
private_key_file = ~/.ssh/ansible_key
host_key_checking = False
retry_files_enabled = False
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts
fact_caching_timeout = 86400

[privilege_escalation]
become = True
become_method = sudo
become_user = root
become_ask_pass = False

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
pipelining = True
control_path = /tmp/ansible-ssh-%%h-%%p-%%r

# inventory/production - 인벤토리 파일 예제
[webservers]
web1.example.com
web2.example.com

[dbservers]
db1.example.com

[all:vars]
ansible_python_interpreter=/usr/bin/python3

김개발 씨는 매번 긴 명령어를 입력하는 것이 지겹습니다. "ansible-playbook -i inventory/production -u ansible --private-key ~/.ssh/ansible_key deploy.yml" 같은 명령어를 타이핑할 때마다 오타가 나기도 합니다.

더 간단한 방법은 없을까요? 박시니어 씨가 프로젝트 루트에 새 파일을 만들기 시작합니다.

"ansible.cfg라는 파일을 만들면 이 모든 옵션을 저장할 수 있어요." Ansible 설정 파일 구조를 이해해 봅시다. 쉽게 비유하자면, Ansible 설정 파일은 마치 스마트폰의 환경설정과 같습니다.

매번 사진을 찍을 때마다 해상도를 선택하는 대신, 환경설정에서 기본 해상도를 지정해두면 편합니다. Ansible도 마찬가지입니다.

자주 사용하는 옵션을 설정 파일에 저장해두면 명령어가 훨씬 간결해집니다. 프로젝트마다 다른 설정을 사용할 수도 있습니다.

설정 파일이 없으면 어떻게 될까요? 모든 옵션을 명령줄에서 지정해야 합니다.

인벤토리 파일 경로, SSH 사용자 이름, 개인키 파일, sudo 옵션 등을 매번 입력해야 합니다. 명령어가 길어져서 읽기 어렵고, Shell 히스토리에서 찾기도 힘듭니다.

팀원마다 다른 옵션을 사용하면 일관성도 떨어집니다. "제 컴퓨터에서는 되는데요?"라는 말이 자주 나옵니다.

바로 이런 문제를 해결하기 위해 Ansible은 계층적 설정 파일 시스템을 제공합니다. Ansible은 여러 위치에서 설정 파일을 찾습니다.

우선순위가 있어서 더 구체적인 설정이 일반적인 설정을 덮어씁니다. 첫 번째는 환경변수 ANSIBLE_CONFIG입니다.

두 번째는 현재 디렉토리의 ansible.cfg입니다. 세 번째는 홈 디렉토리의 .ansible.cfg입니다.

마지막으로 시스템 전역 /etc/ansible/ansible.cfg를 찾습니다. 보통은 프로젝트 루트에 ansible.cfg를 두어 프로젝트별 설정을 관리합니다.

설정 파일의 구조를 살펴보겠습니다. INI 형식으로 작성되며 섹션으로 나뉩니다.

defaults 섹션에는 가장 일반적인 설정이 들어갑니다. inventory는 기본 인벤토리 파일 경로입니다.

이제 "-i" 옵션 없이 Playbook을 실행할 수 있습니다. remote_user는 SSH 접속 시 사용할 기본 사용자입니다.

host_key_checking을 False로 하면 처음 접속하는 서버에 대해 확인 절차를 건너뜁니다. 성능 최적화 옵션도 중요합니다.

gathering은 fact 수집 방식을 제어합니다. smart로 설정하면 캐시된 fact가 있으면 재수집하지 않습니다.

fact_caching을 활성화하면 수집한 정보를 파일에 저장하여 다음 실행 시 재사용합니다. 서버가 많을 때 시간이 크게 절약됩니다.

pipelining을 True로 하면 SSH 연결을 더 효율적으로 사용하여 속도가 빨라집니다. privilege_escalation 섹션은 무엇을 할까요?

이 섹션은 권한 상승에 관한 설정입니다. become: True는 기본적으로 sudo를 사용하라는 의미입니다.

Playbook에서 매번 "become: yes"를 쓰지 않아도 됩니다. become_method는 sudo, su, pbrun 등을 선택할 수 있습니다.

become_user는 어느 사용자로 전환할지 지정합니다. 보통 root입니다.

ssh_connection 섹션에서 SSH 동작을 세밀하게 제어합니다. ssh_args에 ControlMaster와 ControlPersist를 설정하면 SSH 연결을 재사용합니다.

같은 서버에 여러 번 접속할 때 매번 새 연결을 만들지 않아 훨씬 빠릅니다. pipelining은 여러 작업을 하나의 SSH 세션으로 묶어서 실행합니다.

control_path는 연결 제어 소켓 파일의 경로입니다. 인벤토리 파일의 구조는 어떻게 될까요?

인벤토리 파일은 관리할 호스트 목록입니다. 그룹으로 묶을 수 있어서 webservers, dbservers처럼 역할별로 분류합니다.

all:vars 섹션은 모든 호스트에 적용되는 변수입니다. ansible_python_interpreter를 지정하면 원격 서버에서 사용할 Python 경로를 명시할 수 있습니다.

그룹별로 group_vars/webservers.yml 같은 파일을 만들어 변수를 관리하면 더 체계적입니다. 실제 현업에서는 어떻게 활용할까요?

예를 들어 개발/스테이징/프로덕션 환경을 분리한다고 가정해봅시다. inventory 디렉토리에 development, staging, production 파일을 만듭니다.

ansible.cfg의 inventory 값을 환경에 따라 바꾸거나, 실행 시 "-i inventory/staging" 같이 지정합니다. group_vars 디렉토리에 각 그룹의 변수를 YAML 파일로 관리하면 암호화도 쉽고 버전 관리도 편합니다.

Ansible Vault로 민감한 정보를 암호화할 수도 있습니다. 하지만 주의할 점도 있습니다.

초보 개발자들이 흔히 하는 실수 중 하나는 ansible.cfg를 Git에 커밋하면서 개인 경로를 하드코딩하는 것입니다. private_key_file에 "/Users/myname/.ssh/key" 같은 절대 경로를 쓰면 다른 사람의 컴퓨터에서 동작하지 않습니다.

따라서 상대 경로를 사용하거나 환경변수를 활용해야 합니다. 또한 host_key_checking을 False로 하는 것은 보안상 위험할 수 있으므로 프로덕션에서는 신중하게 결정해야 합니다.

다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨가 설정 파일을 만들어주자 김개발 씨는 감탄했습니다.

"이제 'ansible-playbook deploy.yml'만 입력하면 되네요!" Ansible 설정 파일 구조를 제대로 이해하면 프로젝트를 깔끔하게 관리할 수 있습니다. 설정을 코드로 관리하면 팀원들과 같은 환경을 공유하기 쉽습니다.

여러분도 오늘 배운 내용을 바탕으로 프로젝트에 ansible.cfg를 추가해 보세요.

실전 팁

💡 - ansible-config dump로 현재 적용된 모든 설정을 확인할 수 있습니다

  • ansible-config list로 사용 가능한 모든 설정 옵션을 볼 수 있습니다
  • 프로젝트 루트에 ansible.cfg를 두고 Git으로 관리하면 팀 전체가 같은 설정을 사용할 수 있습니다

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Ansible#SSH#Idempotency#Playbook#Infrastructure#Ansible,IaC,DevOps

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.

함께 보면 좋은 카드 뉴스

Ansible 인벤토리 관리 완벽 가이드

서버 수백 대를 관리하는 당신, 매번 IP 주소 외우고 계신가요? Ansible 인벤토리로 서버 관리를 체계화하는 방법을 알아봅니다. 정적 인벤토리부터 동적 인벤토리까지, 실무에서 바로 활용할 수 있는 베스트 프랙티스를 담았습니다.

Terraform 소개 및 설치 완벽 가이드

인프라를 코드로 관리하는 IaC의 개념부터 Terraform의 특징, 설치 방법, 그리고 첫 번째 리소스 생성까지 초급 개발자를 위한 친절한 입문 가이드입니다. 실무에서 바로 활용할 수 있는 예제와 팁을 담았습니다.

Ansible 소개 및 설치 완벽 가이드

서버 수십 대를 손쉽게 관리하는 자동화 도구 Ansible의 기초부터 설치, 첫 명령어 실행까지 배웁니다. 초급 개발자를 위한 실무 중심 입문 가이드입니다.

CloudFormation으로 Infrastructure as Code 구현하기

AWS CloudFormation을 사용하여 인프라를 코드로 관리하는 방법을 배웁니다. 스택과 템플릿의 개념부터 실제 리소스 배포까지, 초급자도 쉽게 따라할 수 있는 실습 중심의 가이드입니다.

EC2 인스턴스의 이해와 생성 실습 완벽 가이드

AWS EC2의 기본 개념부터 인스턴스 생성, 접속, 관리까지 베스트셀러 입문서 스타일로 쉽게 배웁니다. 클라우드 컴퓨팅의 핵심인 EC2를 실무 중심 스토리텔링으로 술술 읽으며 이해할 수 있습니다.