Skip to document
pieroot log
Markdown Preview

Ansible로 노드 자동화를 완벽하게 마스터하는 방법: 설치부터 첫 Playbook 실행까지

Frontmatter

Ansible은 에이전트리스 IT 자동화 도구로, SSH와 Python을 기반으로 하여 서버 설정 및 애플리케이션 배포를 관리한다. Ubuntu에서 Ansible을 설치하는 방법, Inventory 파일 구성, Ad-hoc 명령어 사용법, 그리고 첫 번째 Playbook 작성 및 실행 방법을 다룬다. 멱등성을 강조하며, SSH 키 설정과 보안 주의사항도 포함되어 있다.

Ansible로 노드 자동화를 완벽하게 마스터하는 방법: 설치부터 첫 Playbook 실행까지
노드 확장을 할 때 너무나도 기본 세팅이 하기 귀찮다. 네트워크 스펙을 NIC를 자동 감지하여 세팅하지 못하더라도 OVS만 연결하면 되기에 일단 Ansible 구성을 해보려고 한다.
이번 글에서는 Ansible을 설치하고, 기본적인 사용법을 익혀보는 과정을 정리한다. Inventory 구성부터 Ad-hoc 명령어, 그리고 첫 번째 Playbook까지 다뤄본다.
📌
이 글에서 다루는 내용
  • Ansible이란 무엇인가, 왜 쓰는가
  • Ubuntu에서 Ansible 설치 (apt)
  • Inventory 파일 구성
  • Ad-hoc 명령어로 간단한 작업 실행
  • 첫 번째 Playbook 작성 및 실행
  • 실전 팁과 주의사항

🤔 Ansible이란?

Ansible은 에이전트리스(agentless) IT 자동화 도구다. 서버 설정, 애플리케이션 배포, 오케스트레이션 등을 코드로 관리할 수 있게 해준다.
핵심은 SSH와 Python으로 동작한다는 점이다. 그 말은 즉, 최신 Ubuntu 서버뿐만 아니라 대부분의 Unix 서버들은 기본 세팅만으로도 사용이 가능하다는 것이다. 대상 서버에 별도의 에이전트를 설치할 필요가 없으니 관리 포인트가 확 줄어든다.
💡
Ansible의 핵심 구성 요소
  • Control Node: Ansible이 설치된 관리 서버. 여기서 명령을 내린다
  • Managed Node: Ansible이 관리하는 대상 서버. SSH만 열려있으면 된다
  • Inventory: 관리 대상 서버 목록. IP나 호스트명을 그룹별로 정리한 파일
  • Playbook: 자동화 작업을 정의한 YAML 파일. "어떤 서버에 무슨 작업을 할지" 선언한다
  • Module: 실제 작업을 수행하는 단위. apt, copy, service 등 수백 개가 내장되어 있다
비교 항목
Ansible
Chef / Puppet
에이전트 필요
❌ 불필요 (SSH만 있으면 됨)
✅ 필요 (각 노드에 설치)
설정 언어
YAML (사람이 읽기 쉬움)
Ruby 기반 DSL
학습 곡선
낮음 🟢
높음 🔴
실행 방식
Push (제어 노드에서 밀어넣기)
Pull (에이전트가 당겨가기)
사실 노드 3대 초기 세팅하는 데 Ansible까지 필요한가 싶긴 하지만, 한 번 만들어두면 다음번에는 명령어 한 줄이면 끝이니까.

📦 Ansible 설치 (Ubuntu)

Python으로 동작하기에 pip로 설치를 진행해도 괜찮지만, 어느 정도 서버를 사용해본 유저라면 시스템의 Python은 가능하면 건드리지 않는 게 좋다는 걸 알 것이다. pip로 시스템 Python에 이것저것 설치하다가 의존성 꼬이면... 그날 하루가 통째로 날아간다 😭
Ubuntu로 설치할 것이기에 apt 패키지를 이용해 진행하겠다.

1단계: 시스템 업데이트

shell
sudo apt update
이 명령어는 마치 시스템을 설정할 때 의식을 치루는 것과 같다. 마음을 경건하게 하는 과정과 같다 이말이다.

2단계: PPA 추가 및 설치

shell
sudo apt install software-properties-common
sudo add-apt-repository --yes --update ppa:ansible/ansible
sudo apt install ansible
📝
왜 PPA를 추가하는가?
Ubuntu 기본 저장소에도 Ansible이 있지만, 버전이 꽤 오래된 경우가 많다. Ansible 공식 PPA를 추가하면 최신 안정 버전을 받을 수 있다. 특히 최신 모듈이나 기능이 필요한 경우 PPA 사용을 강력 권장한다.
💡
ansible vs ansible-core 차이
  • ansible-core: 최소한의 런타임 + 내장 모듈/플러그인만 포함. 가벼움
  • ansible: "batteries included" 패키지. 커뮤니티가 선별한 다양한 Collection이 포함되어 있어 바로 사용하기 편함
처음 시작한다면 ansible 패키지를 설치하는 게 편하다. 나중에 필요한 Collection만 골라서 쓰고 싶다면 ansible-core로 갈아타면 된다.

3단계: 설치 확인

shell
ansible --version
shell
ansible [core 2.17.x]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ...
이렇게 버전 정보가 출력되면 설치 완료다. ✅

📋 Inventory 구성

Ansible은 어떤 서버에 작업을 할 것인지를 Inventory 파일에서 읽어온다. 설치하면 기본적으로 /etc/ansible/hosts 파일이 생성되지만, 프로젝트별로 따로 관리하는 게 훨씬 깔끔하다.

기본 Inventory 파일 (INI 형식)

프로젝트 디렉토리를 만들고 Inventory 파일을 작성한다:
shell
mkdir ~/ansible-lab && cd ~/ansible-lab
plain text
# inventory.ini

[control]
controller ansible_host=172.30.0.11

[compute]
compute01 ansible_host=172.30.0.21
compute02 ansible_host=172.30.0.22
compute03 ansible_host=172.30.0.23

[storage]
storage01 ansible_host=172.30.2.101
storage02 ansible_host=172.30.2.102
storage03 ansible_host=172.30.2.103

[all:vars]
ansible_user=root
ansible_python_interpreter=/usr/bin/python3
📝
Inventory 파일 해설
  • [compute], [storage]: 호스트 그룹. 그룹 단위로 작업을 실행할 수 있다
  • ansible_host: 실제 접속할 IP 주소
  • [all:vars]: 모든 호스트에 적용되는 변수. ansible_user는 SSH 접속 유저, ansible_python_interpreter는 대상 서버의 Python 경로

YAML 형식 Inventory

YAML이 더 익숙하다면 이렇게도 작성할 수 있다:
yaml
# inventory.yml
all:
  vars:
    ansible_user: root
    ansible_python_interpreter: /usr/bin/python3
  children:
    compute:
      hosts:
        compute01:
          ansible_host: 172.30.0.21
        compute02:
          ansible_host: 172.30.0.22
        compute03:
          ansible_host: 172.30.0.23
    storage:
      hosts:
        storage01:
          ansible_host: 172.30.2.101
        storage02:
          ansible_host: 172.30.2.102
        storage03:
          ansible_host: 172.30.2.103
두 형식 모두 동작은 동일하니 취향에 맞게 선택하면 된다.

Inventory 확인

작성한 Inventory가 제대로 파싱되는지 확인한다:
shell
# 호스트 목록 확인
ansible-inventory -i inventory.ini --list

# 그래프 형태로 확인 (그룹 구조 파악에 유용)
ansible-inventory -i inventory.ini --graph
shell
@all:
  |--@control:
  |  |--controller
  |--@compute:
  |  |--compute01
  |  |--compute02
  |  |--compute03
  |--@storage:
  |  |--storage01
  |  |--storage02
  |  |--storage03
  |--@ungrouped:

🔑 SSH 키 설정

Ansible은 SSH로 통신하기 때문에, 비밀번호 없이 접속할 수 있도록 SSH 키를 배포해야 한다. 이미 키가 있다면 이 단계는 건너뛰어도 좋다.
shell
# SSH 키 생성 (이미 있으면 스킵)
ssh-keygen -t ed25519 -C "ansible-control"

# 대상 서버에 키 배포
ssh-copy-id root@172.30.0.21
ssh-copy-id root@172.30.0.22
ssh-copy-id root@172.30.0.23
⚠️
비밀번호 방식으로도 가능하지만...
--ask-pass (-k) 옵션을 사용하면 비밀번호 입력 방식으로도 접속할 수 있다. 하지만 서버가 10대, 20대 늘어나면 매번 비밀번호 입력하는 건 자동화의 의미가 없어진다. SSH 키 한 번 세팅해두면 편하다.

연결 테스트

SSH 키 배포가 끝났으면 Ansible로 연결을 테스트한다:
shell
ansible all -i inventory.ini -m ping
shell
compute01 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
compute02 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
compute03 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
모든 호스트에서 pong이 돌아오면 성공이다! 🎉
💡
ping 모듈은 ICMP ping이 아니다!
Ansible의 ping 모듈은 실제로 SSH 접속 → Python 실행 → 응답 반환의 과정을 거친다. 즉, SSH 연결과 Python 환경이 모두 정상인지 한 번에 확인할 수 있는 모듈이다.

⚡ Ad-hoc 명령어

Playbook까지 작성하기엔 좀 과한, 간단한 일회성 작업은 Ad-hoc 명령어로 처리할 수 있다.

기본 문법

shell
ansible <대상> -i <inventory> -m <모듈> -a "<인자>"

자주 쓰는 예시들

shell
# 모든 compute 노드의 업타임 확인
ansible compute -i inventory.ini -m command -a "uptime"

# 모든 서버의 디스크 용량 확인
ansible all -i inventory.ini -m command -a "df -h"

# compute 그룹에 패키지 설치
ansible compute -i inventory.ini -m apt -a "name=htop state=present" --become

# 특정 서비스 재시작
ansible compute -i inventory.ini -m service -a "name=ssh state=restarted" --become

# 파일 복사
ansible all -i inventory.ini -m copy -a "src=./config.txt dest=/tmp/config.txt"
📝
자주 쓰는 모듈 정리
모듈
용도
예시
ping
연결 테스트
-m ping
command
쉘 명령어 실행
-m command -a "uptime"
shell
쉘 명령어 실행 (파이프 등 지원)
-m shell -a "cat /etc/os-release | head -3"
apt
패키지 관리 (Debian/Ubuntu)
-m apt -a "name=vim state=present"
copy
파일 복사
-m copy -a "src=./a.txt dest=/tmp/a.txt"
service
서비스 관리
-m service -a "name=nginx state=started"
setup
시스템 정보 수집 (Facts)
-m setup
⚠️
command vs shell 차이
  • command: 단순 명령어 실행. 파이프(|), 리다이렉션(>) 등을 사용할 수 없다
  • shell: /bin/sh를 통해 실행. 파이프, 리다이렉션, 환경변수 등 모두 사용 가능
보안상 command가 더 안전하므로, 파이프가 필요 없다면 command를 쓰자.

📝 첫 번째 Playbook 작성

Ad-hoc으로 해결할 수 없는 복잡한 작업의 조합은 Playbook으로 정의한다. Playbook은 YAML 형식으로 작성하며, "어떤 호스트에, 어떤 순서로, 무슨 작업을 할지"를 선언한다.

기본 구조

yaml
# setup-base.yml
---
- name: 기본 서버 세팅
  hosts: compute
  become: yes

  tasks:
    - name: apt 캐시 업데이트
      apt:
        update_cache: yes
        cache_valid_time: 3600

    - name: 기본 패키지 설치
      apt:
        name:
          - vim
          - htop
          - curl
          - wget
          - net-tools
          - git
        state: present

    - name: 타임존 설정
      timezone:
        name: Asia/Seoul

    - name: NTP 동기화 활성화
      service:
        name: systemd-timesyncd
        state: started
        enabled: yes
📝
Playbook 구조 해설
  • name: 이 Play의 이름. 실행 시 로그에 표시된다
  • hosts: 작업 대상 그룹. Inventory의 그룹명을 지정
  • become: yes: root 권한으로 실행 (= sudo)
  • tasks: 실행할 작업 목록. 위에서 아래 순서대로 실행된다
  • 각 task의 name은 실행 로그에 표시되므로, 알아보기 쉽게 작성하는 게 좋다

Playbook 실행

shell
# 문법 검사 (실행 전 반드시!)
ansible-playbook -i inventory.ini setup-base.yml --syntax-check

# 드라이 런 (실제 변경 없이 시뮬레이션)
ansible-playbook -i inventory.ini setup-base.yml --check

# 실제 실행
ansible-playbook -i inventory.ini setup-base.yml
shell
PLAY [기본 서버 세팅] ***********************************

TASK [Gathering Facts] *********************************
ok: [compute01]
ok: [compute02]
ok: [compute03]

TASK [apt 캐시 업데이트] *********************************
changed: [compute01]
changed: [compute02]
changed: [compute03]

TASK [기본 패키지 설치] **********************************
changed: [compute01]
changed: [compute02]
changed: [compute03]

TASK [타임존 설정] **************************************
changed: [compute01]
changed: [compute02]
changed: [compute03]

TASK [NTP 동기화 활성화] *********************************
ok: [compute01]
ok: [compute02]
ok: [compute03]

PLAY RECAP ********************************************
compute01   : ok=5  changed=3  unreachable=0  failed=0
compute02   : ok=5  changed=3  unreachable=0  failed=0
compute03   : ok=5  changed=3  unreachable=0  failed=0
failed=0이면 모든 작업이 성공한 것이다! ✅
💡
--check 옵션은 꼭 사용하자!
실제 실행 전에 --check(드라이 런)를 돌리면 어떤 변경이 일어날지 미리 확인할 수 있다. 프로덕션 서버에서 Playbook을 바로 실행했다가 예상치 못한 변경이 발생하면... 그날은 일찍 퇴근 못 한다

🚀 실전 예제: OVS 설치 Playbook

실제로 내가 노드 확장할 때 사용하려는 OVS(Open vSwitch) 설치 Playbook을 작성해보자.
yaml
# setup-ovs.yml
---
- name: OVS 설치 및 기본 브릿지 구성
  hosts: compute
  become: yes

  vars:
    ovs_bridge_name: br-int

  tasks:
    - name: OVS 패키지 설치
      apt:
        name:
          - openvswitch-switch
        state: present
        update_cache: yes

    - name: OVS 서비스 시작 및 활성화
      service:
        name: openvswitch-switch
        state: started
        enabled: yes

    - name: OVS 브릿지 생성
      command: ovs-vsctl --may-exist add-br  ovs_bridge_name 

    - name: OVS 브릿지 확인
      command: ovs-vsctl show
      register: ovs_result

    - name: OVS 상태 출력
      debug:
        var: ovs_result.stdout_lines
📝
새로운 개념들
  • vars: Playbook 내에서 사용할 변수를 정의. 변수명 형태로 참조한다
  • register: 명령어 실행 결과를 변수에 저장
  • debug: 변수 내용을 콘솔에 출력. 디버깅할 때 매우 유용하다

🔧 유용한 팁들

ansible.cfg 설정

매번 -i inventory.ini를 입력하기 귀찮다면, 프로젝트 루트에 ansible.cfg를 만들자:
plain text
# ansible.cfg
[defaults]
inventory = inventory.ini
host_key_checking = False
retry_files_enabled = False
stdout_callback = yaml
⚠️
host_key_checking = False 주의!
이 설정은 SSH 접속 시 호스트 키 검증을 건너뛴다. 신뢰할 수 있는 내부 네트워크에서만 사용하자. 공개 네트워크에서는 보안 위험이 있다.

멱등성(Idempotency) 이해

Ansible의 가장 중요한 특성 중 하나가 멱등성이다. 같은 Playbook을 여러 번 실행해도 결과가 동일하다는 뜻이다.
  • apt로 패키지를 설치할 때, 이미 설치되어 있으면 ok(변경 없음)
  • service로 서비스를 시작할 때, 이미 실행 중이면 ok
  • 즉, "이 상태여야 한다"를 선언하는 것이지, "이 명령을 실행해라"가 아니다
이 때문에 command나 shell 모듈은 멱등성이 보장되지 않는다. 가능하면 전용 모듈(apt, service, copy 등)을 사용하는 게 좋다.

핵심 정리

✅ Ansible: SSH + Python 기반 에이전트리스 자동화 도구. 대상 서버에 아무것도 설치할 필요 없다
✅ 설치: Ubuntu PPA를 통해 최신 안정 버전 설치. 시스템 Python은 건드리지 말자
✅ Inventory: 관리 대상 서버를 그룹별로 정리한 파일. INI, YAML 형식 모두 지원
✅ Ad-hoc: 간단한 일회성 작업에 사용. ansible <대상> -m <모듈> -a "<인자>" 형태
✅ Playbook: 복잡한 작업을 YAML로 선언. --check로 반드시 사전 검증
✅ 멱등성: 같은 Playbook을 여러 번 실행해도 결과는 동일. 가능하면 전용 모듈을 사용하자

주의사항

⚠️ 시스템 Python: pip로 Ansible을 설치할 때는 venv를 사용하거나, apt를 쓰자
⚠️ SSH 키 관리: 비밀번호 방식보다 SSH 키 방식이 자동화에 적합하다
⚠️ command/shell 남용 금지: 멱등성이 보장되지 않으므로, 전용 모듈이 있다면 전용 모듈을 쓰자
⚠️ --check 생활화: 프로덕션에서는 반드시 드라이 런 먼저. 실수는 한 순간이다
⚠️ Inventory 보안: IP, 비밀번호 등이 포함될 수 있으므로, Git에 올릴 때 .gitignore 설정 필수

참고 자료