infra
Platform

모듈 맵

[Linux] Ansible 입문 — 인프라 자동화

0 / 20 완료

펼치기

Linux-master · 19 / 20

[Linux] Ansible 입문 — 인프라 자동화

Inventory와 Playbook으로 서버 설정을 코드로 관리하고, 수십 대 서버에 반복 작업을 자동화합니다

🚨INCIDENT ALERT
HIGH

새벽 2시, 보안팀에서 연락이 왔습니다. 전체 30대 서버에 즉시 취약점 패치를 적용해야 한다는 공지입니다. 터미널 탭을 30개 열고 동일한 명령어를 반복 입력하다 보면 실수가 생기고, 한 대라도 빠트리면 감사에서 걸립니다. 더 나쁜 건, 다음 달에 또 같은 일이 생긴다는 것입니다. Ansible을 알면 이런 상황에서 명령 한 줄로 끝납니다.

Ansible 입문 — 인프라 자동화

서버가 3대를 넘는 순간, 같은 명령어를 여러 터미널에서 반복하는 자신을 발견하게 됩니다. Ansible은 그 반복을 코드로 바꿉니다. "어떤 상태여야 하는가"를 YAML로 정의하면, Ansible이 SSH를 통해 모든 서버를 동시에 그 상태로 만들어줍니다.


이번 챕터에서 배울 것

shell 스크립트와 Ansible의 차이는 '명령'과 '상태 선언'의 차이입니다. 스크립트는 "이 명령을 실행해라"고 하지만, Ansible은 "이 서버는 이런 상태여야 한다"고 선언합니다.

  • 1에이전트리스 아키텍처 — SSH만으로 동작하는 원리
  • 2Inventory — 관리할 서버 목록 정의
  • 3Ad-hoc 명령 — Playbook 없이 빠른 단발 작업
  • 4Playbook — YAML로 서버 상태를 코드로 정의
  • 5변수(vars)와 핸들러(handlers) — 조건부 재시작 패턴
  • 6멱등성 — 같은 Playbook을 안전하게 반복 실행
실습 환경 준비

💡개념

에이전트리스 — Ansible이 별도 소프트웨어 없이 동작하는 방식

동작 원리

제어 노드(Control Node)
    │
    ├── SSH 연결
    │
    └── 대상 서버(Managed Node)
            ├── Python 모듈 임시 업로드
            ├── 실행
            └── 결과 반환 → 제거

Ansible은 실행 시 Python 모듈 파일을 /tmp에 임시로 복사하고, 실행 후 삭제합니다. 대상 서버에는 SSH 접근 + Python만 있으면 됩니다.

로컬 터미널
# Ansible 설치 (제어 노드에만)
sudo apt install ansible -y

# 버전 확인
ansible --version

Chef, Puppet과의 차이: Chef/Puppet은 대상 서버에 에이전트 데몬을 상시 설치해야 합니다. Ansible은 SSH 세션만 사용하므로 온보딩 비용이 0에 가깝습니다.


💡개념

Inventory — 관리할 서버를 그룹으로 정의

INI
# /etc/ansible/hosts (또는 -i 옵션으로 파일 지정)

[webservers]
web01.example.com
web02.example.com
192.168.1.10

[dbservers]
db01.example.com ansible_user=ubuntu ansible_port=2222

[production:children]
webservers
dbservers

[all:vars]
ansible_python_interpreter=/usr/bin/python3
로컬 터미널
# Inventory 확인
ansible-inventory --list -y

# 특정 그룹의 서버 핑 테스트
ansible webservers -m ping

# 모든 서버 핑
ansible all -m ping

출력 예시:

web01.example.com | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
🔍실행 후 확인할 것
  • 모든 대상 서버에서 SUCCESS 응답이 돌아왔는가?
  • UNREACHABLE 서버가 있다면 SSH 키 인증이 정상적으로 설정됐는지 확인했는가?
  • ansible-inventory --list -y 로 그룹 구성이 의도대로 되어 있는가?

💡개념

Ad-hoc 명령 — Playbook 없이 단발 작업

로컬 터미널
# 문법: ansible <패턴> -m <모듈> -a "<인수>"

# 모든 서버 업타임 확인
ansible all -m command -a "uptime"

# webservers 그룹에 패키지 설치
ansible webservers -m apt -a "name=nginx state=present" --become

# 서비스 재시작
ansible webservers -m service -a "name=nginx state=restarted" --become

# 파일 복사
ansible dbservers -m copy -a "src=/tmp/my.cnf dest=/etc/mysql/my.cnf"

# 자유 형식 명령 (shell 모듈 — 파이프, 리다이렉션 가능)
ansible all -m shell -a "df -h | grep /dev/sda1"

--become은 sudo 권한으로 실행하는 옵션입니다.


첫 Playbook 작성

Playbook은 YAML 형식으로 "어떤 서버에 어떤 상태를 적용할지"를 정의합니다.

YAML
# webserver-setup.yml
---
- name: 웹 서버 초기 설정
  hosts: webservers
  become: true

  vars:
    nginx_port: 80

  tasks:
    - name: nginx 설치
      apt:
        name: nginx
        state: present
        update_cache: true

    - name: nginx 서비스 활성화 및 시작
      service:
        name: nginx
        state: started
        enabled: true

    - name: 방화벽에 HTTP 허용
      ufw:
        rule: allow
        port: "{{ nginx_port }}"
        proto: tcp

    - name: 커스텀 index.html 배포
      copy:
        content: "<h1>Deployed by Ansible</h1>"
        dest: /var/www/html/index.html
        owner: www-data
        mode: '0644'
      notify: reload nginx

  handlers:
    - name: reload nginx
      service:
        name: nginx
        state: reloaded
로컬 터미널
# 드라이런 (실제 변경 없이 미리 확인)
ansible-playbook webserver-setup.yml --check

# 실행
ansible-playbook webserver-setup.yml

# 특정 태스크만 실행 (태그 사용)
ansible-playbook webserver-setup.yml --tags "install"

# 실행 결과 예시
PLAY [웹 서버 초기 설정] **************************

TASK [nginx 설치] ********************************
changed: [web01.example.com]
ok: [web02.example.com]     ← 이미 설치됨, 변경 없음

PLAY RECAP **************************************
web01 : ok=4  changed=3  unreachable=0  failed=0
web02 : ok=4  changed=1  unreachable=0  failed=0

핵심: changed는 실제로 변경된 태스크, ok는 이미 원하는 상태라 변경 불필요. 이것이 멱등성입니다.

🔍실행 후 확인할 것
  • PLAY RECAP에 failed=0이 표시됐는가?
  • 같은 Playbook을 다시 실행했을 때 changed 수가 0으로 줄어드는가? (멱등성 확인)
  • 대상 서버에서 nginx가 실제로 실행 중인지 systemctl status nginx로 확인했는가?

💡개념

핸들러(Handler) — 변경이 있을 때만 재시작

Handler는 notify된 태스크가 changed를 반환할 때만 실행됩니다.

YAML
tasks:
  - name: nginx 설정 파일 배포
    template:
      src: nginx.conf.j2
      dest: /etc/nginx/nginx.conf
    notify: reload nginx    # ← 변경 시에만 handler 호출

handlers:
  - name: reload nginx
    service:
      name: nginx
      state: reloaded

왜 중요한가: 설정 파일이 바뀌지 않았는데 매번 nginx를 reload하면 불필요한 서비스 중단이 발생합니다. Handler는 "변경이 있을 때만 재시작"을 자동으로 보장합니다.


SSH 키 인증 실패

로컬 터미널
# 증상
web01 | UNREACHABLE! => {
    "msg": "Failed to connect to the host via ssh: Permission denied (publickey,gssapi-keyex,gssapi-with-mic)"
}

# 원인 1: SSH 키가 대상 서버에 등록되지 않음
ssh-copy-id -i ~/.ssh/id_rsa.pub user@web01

# 원인 2: ansible.cfg에 SSH 키 경로 지정 필요
cat ansible.cfg
[defaults]
private_key_file = ~/.ssh/ansible_key

# 원인 3: known_hosts 검사 비활성화 필요 (개발환경)
[defaults]
host_key_checking = False

# 연결 테스트
ansible web01 -m ping -vvv   # -v 옵션으로 상세 디버그

대상 서버에 Python이 없는 경우

로컬 터미널
# Ubuntu 22.04는 python3가 기본, python 심볼릭링크 없음
# Inventory에 명시적으로 python3 지정

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

# 또는 대상 서버에 python-is-python3 패키지 설치
ansible all -m raw -a "apt install -y python3" --become
# raw 모듈은 Python 없이도 SSH 명령을 직접 실행

💼
실무 맥락
현업 패턴

실무에서 Ansible이 쓰이는 순간

10대 서버에 보안 패치 동시 적용:

YAML
---
- name: 보안 패치 적용
  hosts: all
  become: true
  serial: 2    # 동시에 2대씩 처리 (롤링 업데이트)

  tasks:
    - name: apt 업데이트
      apt:
        upgrade: safe
        update_cache: true

    - name: 재부팅이 필요한지 확인
      stat:
        path: /var/run/reboot-required
      register: reboot_required

    - name: 필요 시 재부팅
      reboot:
        reboot_timeout: 300
      when: reboot_required.stat.exists

팀에서 Ansible을 쓰는 패턴:

Git 저장소 (roles/, playbooks/)
    │
    ├── CI/CD 파이프라인이 git push 시 자동 실행
    ├── --check로 스테이징 검증
    └── 승인 후 프로덕션 적용

신입이 자주 실수하는 것: shell 모듈 남용. apt install nginx를 shell 모듈로 실행하면 멱등성이 깨집니다. 반드시 전용 모듈(apt, yum, service 등)을 사용해야 합니다.

지식 확인

퀴즈 — 4문제

Q1

Ansible이 에이전트리스(agentless)로 동작한다는 뜻은?

Q2

Ansible의 멱등성(idempotency)이란?

Q3

Inventory, Module, Playbook의 역할을 올바르게 설명한 것은?

Q4

`ansible-playbook site.yml --check` 명령의 목적은?

0 / 4 답변