본문 바로가기
Kubernetes

[Ansible] 개념 정리 및 실습

by interlude-3 2026. 1. 17.
본 글은 gasida님의 k8s-deploy 스터디 자료를 기반으로 작성되었습니다.

 

 

Ansible이란?


Ansible은 IT 인프라를 자동으로 관리해주는 도구입니다.

 

여러 대의 서버에 같은 작업을 반복해야 할 때 하나하나 손으로 하지 않고 자동으로 처리할 수 있습니다.

10대의 서버에 모두 같은 소프트웨어를 설치해야 한다면

일일이 접속해서 10번 설치하는 대신, Ansible에게 한 번만 명령하면 알아서 모든 서버에 설치해줍니다.

 

 

Ansible의 주요 특징


Agent가 필요 없습니다 - 서버에 SSH만 설치되어 있으면 바로 사용할 수 있고, 관리하려는 서버에 별도 프로그램을 깔 필요가 없습니다.

 

YAML 언어로 작성합니다 - 복잡한 프로그래밍 언어가 아닌, 사람이 읽기 쉬운 YAML 형식으로 작성합니다. 일반 문서처럼 읽을 수 있어서 배우기 쉽습니다.

ex)
- name: 웹서버 설치하기
  hosts: webservers
  tasks:
    - name: nginx 설치
      apt:
        name: nginx
        state: present

 

멱등성을 보장합니다 - 같은 명령을 여러 번 실행해도 결과가 같습니다. 이미 설치된 프로그램이라면 다시 설치하지 않고 넘어가고, 실수로 두 번 실행해도 여러번 실행되지 않아 안전합니다.

 

푸시 방식으로 동작합니다 - 중앙 서버에서 명령을 내리면 각 서버로 전달되는 방식입니다. 관리자가 원할 때 바로 실행할 수 있어 통제가 쉽습니다.

 

 

언제 사용하면 좋을까?


여러 서버를 동시에 설정해야 할 때

- 신규 서버 10대에 동일한 환경을 구축한다면, 수동으로 하면 몇 시간 걸릴 작업을 몇 분으로 단축할 수 있습니다.

 

반복적인 배포 작업이 많을 때

- 매주 새로운 버전을 배포해야 한다면, 한 번 작성한 Ansible 스크립트로 계속 재사용할 수 있습니다.

 

서버 환경을 표준화하고 싶을 때

- 개발, 테스트, 운영 환경을 동일하게 유지하려면 Ansible로 관리하면 실수가 줄어듭니다.

 

빠르게 시작하고 싶을 때

- 복잡한 설정 없이 바로 사용할 수 있어서, IT 자동화를 처음 시도하는 팀에게 좋습니다.

 

클라우드 인프라를 관리할 때

- AWS, Azure, GCP 등의 클라우드 자원을 코드로 관리할 수 있습니다.

 

 

다른 도구와 비교해보면


Puppet, Chef

- 에이전트 기반 구조와 Ruby DSL로 인해 초기 설정과 학습 부담이 있는 반면, Ansible은 SSH 기반의 에이전트리스 방식으로 비교적 빠르게 도입할 수 있습니다.

 

Terraform

- Terraform은 인프라 생성에 특화되어 있다면, Ansible은 서버 설정과 애플리케이션 배포에 더 강합니다.

두가지 도구를 함께 사용하여 Terraform으로 서버를 만들고, Ansible로 그 서버를 설정하는 경우가 많습니다.

 

Shell Script 

- 쉘 스크립트는 유연하지만 관리가 어렵고 에러 처리가 복잡합니다. Ansible은 구조화된 방식으로 작성하며, 멱등성 덕분에 안전하게 실행할 수 있습니다.

 

 

Ansible의 핵심 구성 요소


> 실행 환경

  • Control Node : Ansible이 설치된 관리 서버
  • Managed Nodes : 실제로 작업이 수행되는 서버들

> 관리 대상 정의

  • Inventory : 어떤 서버들을 관리할지 목록으로 정의

> 자동화 실행 단위

  • Playbooks : 무엇을 할지 정의한 시나리오
    • Plays: 특정 서버 그룹에서 실행할 작업 묶음
    • Tasks: 개별 작업 하나하나
    • Handlers: 변경 발생 시에만 실행되는 특수 작업
    • Roles: 재사용 가능한 구성 패키지

> 실제 작업 수행

  • Modules : Tasks에서 호출되는 실제 작업 코드

> 확장 기능

  • Plugins : Ansible의 동작 방식을 커스터마이징

> 배포 단위

  • Collections : Playbooks, Roles, Modules, Plugins를 하나로 묶은 패키지
<실행 흐름 요약>
1. Control Node에서 Playbook 실행
2. Inventory에서 대상 서버 목록을 읽음
3. Playbook 안의 Tasks가 Modules를 호출
4. Plugins가 실행 방식을 제어
5. SSH를 통해 Managed Nodes에서 작업 수행
6. 변경사항이 있으면 Handlers 실행

각 구성 요소를 더 자세히 살펴보겠습니다.

 

1. Control Node vs Managed Nodes

 

Ansible은 크게 두 종류의 노드로 구성됩니다.

 

Control Node (제어 노드)

- 지휘자 역할을 하는 컴퓨터로, Ansible이 설치되어 있고 여기서 모든 명령을 내립니다. Playbook을 실행하고, 관리 대상 목록(Inventory)을 읽어들이고, 실제 작업 코드(모듈)를 각 서버로 보내는 일을 담당하며 보통 개발자나 운영자의 로컬 PC 또는 별도 관리 서버가 이 역할을 합니다.

 

Managed Nodes (관리 대상 노드)

- 실제로 관리받는 서버들입니다. Control Node가 SSH로 접속해서 작업을 수행합니다. 여기에 별도로 Ansible을 설치할 필요가 없다는 게 장점이고 SSH만 연결되면 바로 관리할 수 있습니다.

 

2. Inventory

 

Inventory는 "관리할 서버 목록"입니다.

어떤 서버들을 관리할지, 각 서버의 IP는 무엇인지, 서버들을 어떻게 그룹으로 묶을지 등을 정의합니다.

웹서버 그룹, 데이터베이스 그룹으로 나눠서 관리할 수 있고, 각 서버나 그룹에 필요한 변수도 함께 지정할 수 있습니다.

[webservers]
web1.example.com
web2.example.com

[databases]
db1.example.com
db2.example.com

 

Inventory는 단순한 텍스트 파일일 수도 있고, 스크립트로 동적으로 생성할 수도 있습니다.

클라우드 환경에서는 실시간으로 서버 목록을 가져오는 동적 Inventory를 많이 사용합니다. 흔히 hostfile이라고도 부릅니다.

 

3. Playbooks

 

Playbook은 Ansible 자동화의 핵심입니다. "어떤 작업을 어떤 순서로 할 것인가"를 정의한 시나리오라고 보면 됩니다.

ansible-playbook 명령으로 실행하며, 하나 이상의 Play로 구성됩니다.

 

3-1. Plays

Play는 어떤 서버에서 무엇을 할 것인가를 정의합니다.

하나의 Play는 특정 호스트 그룹과 그 그룹에서 실행할 작업(Task) 목록을 연결합니다.

- name: 웹서버 설정하기
  hosts: webservers
  tasks:
    - name: nginx 설치
      apt:
        name: nginx
        state: present

 

3-2. Roles

Role은 재사용 가능한 구성 단위입니다.

복잡한 설정을 하나의 패키지로 묶어서 여러 Playbook에서 재사용할 수 있게 해줍니다. 예를 들어 "웹서버 설정"이라는 Role을 만들면, 패키지 설치, 설정 파일 배포, 서비스 시작 등 모든 과정을 하나로 묶을 수 있습니다. 다른 프로젝트에서도 이 Role을 가져다 쓰면 되니 효율적입니다. Role 안에는 Task, Handler, 변수, 템플릿, 플러그인 등이 모두 포함될 수 있습니다.

Play에서 필요할 때 import하거나 include해서 사용합니다.

 

3-3. Tasks

Task는 실제로 수행할 개별 작업입니다.

"nginx 설치하기", "설정 파일 복사하기", "서비스 재시작하기" 같은 구체적인 동작 하나하나가 Task입니다.

각 Task는 하나의 Module을 실행합니다. 간단한 명령 한 줄(ad-hoc 명령)도 내부적으로는 단일 Task 형태로 동작합니다.

 

3-4. Handlers

Handler는 특별한 종류의 Task입니다. 일반 Task와 달리, 변경사항이 발생했을 때만 실행됩니다.

가장 흔한 사용 예는 서비스 재시작으로, 설정 파일을 수정했을 때만 서비스를 재시작하도록 만들 수 있습니다.

설정 파일이 이미 최신 상태라면 재시작하지 않아서 불필요한 작업을 줄일 수 있습니다.

 

4. Modules

 

Module은 실제로 작업을 수행하는 코드 조각입니다.

사용자 계정 만들기, 패키지 설치하기, 파일 복사하기, 네트워크 설정하기 등 다양한 기능을 제공합니다.

Task는 Module을 호출하는 역할만 하고, 실제 작업은 Module이 수행합니다. Ansible은 수천 개의 내장 Module을 제공하기 때문에 대부분의 일반적인 작업은 이미 만들어진 Module로 처리할 수 있습니다.

Module은 Collection 단위로 관리되며, 필요한 Module만 선택해서 사용할 수 있습니다.

 

5. Plugins

 

Plugin은 Ansible의 핵심 동작 방식을 확장하는 코드입니다.

Module이 "무엇을 할 것인가"라면, Plugin은 "어떻게 할 것인가"를 제어합니다.

주요 Plugin 종류는 다음과 같습니다.

 

Connection Plugin

- 서버에 어떻게 접속할지 결정합니다. SSH, WinRM(Windows), Docker 등 다양한 접속 방식을 지원합니다.

 

Filter Plugin

- 데이터를 가공하고 변환합니다. 문자열 처리, 리스트 정렬, JSON 파싱 등을 할 수 있습니다.

 

Callback Plugin

- 실행 결과를 어떻게 출력할지 제어합니다. 로그 형식을 바꾸거나 외부 시스템에 알림을 보낼 수 있습니다.

이 외에도 다양한 Plugin이 있으며, 필요하면 직접 만들 수도 있습니다.

 

6. Collections

 

Collection은 Ansible 콘텐츠를 배포하는 단위입니다.

Playbook, Role, Module, Plugin을 하나의 패키지로 묶어서 공유할 수 있게 해줍니다. 예를 들어 AWS 관리를 위한 amazon.aws Collection이나 Kubernetes 관리를 위한 kubernetes.core Collection 같은 것들이 있습니다. Ansible Galaxy라는 공개 저장소를 통해 다른 사람들이 만든 Collection을 설치하고 사용할 수 있습니다.

Collection 안의 각 구성 요소는 독립적으로 사용할 수 있어서, 필요한 부분만 골라 쓸 수 있습니다.

 

 

Ansible 학습 로드맵


학습 순서 요약

 

초반부 (기초 다지기): Playbook → 변수 → Facts

  • Ansible의 기본 동작 원리를 이해합니다
  • 간단한 자동화 작업을 직접 실행해봅니다
  • 서버 정보를 수집하고 활용하는 방법을 배웁니다

중반부 (똑똑하게 만들기): 반복문 → 조건문 → 핸들러

  • Playbook을 효율적으로 작성하는 기법을 익힙니다
  • 상황에 맞게 작동하도록 제어하는 법을 배웁니다
  • 변경사항에 대응하는 방법을 이해합니다

후반부 (실무 레벨업): Role → Tag → Ansible Galaxy → Content Collection

  • 코드를 재사용 가능하게 구조화합니다
  • 대규모 프로젝트를 효율적으로 관리하는 방법을 배웁니다
  • 커뮤니티 자원을 활용하고 공유하는 법을 익힙니다

 


 

Ansible 경험하기


0. 서버 준비

Server Name OS IP CPU MEM Disk
ansible-server Ubuntu 22.04 192.168.105.151 2 16G 20G
node1 Ubuntu 22.04 192.168.105.152 4 16G 30G
node2 Ubuntu 22.04 192.168.105.153 4 16G 30G
node3 Ubuntu 22.04 192.168.105.154 4 16G 30G

 

# ansible 접근을 위한 SSH 인증 구성
for i in {1..3}; do sshpass -p '***' ssh-copy-id -o StrictHostKeyChecking=no root@node$i; done

# ssh 접속 테스트
> for i in {1..3}; do echo ">> node$i <<"; ssh node$i hostname; echo; done  
>> node1 <<
node1

>> node2 <<
node2

>> node3 <<
node3

# python 정보 확인
> for i in {1..3}; do echo ">> node$i <<"; ssh node$i python3 -V; echo; done 
>> node1 <<
Python 3.10.12

>> node2 <<
Python 3.10.12

>> node3 <<
Python 3.10.12

 

1. Ansible 설치

# 파이썬 버전 확인
> python3 --version
Python 3.10.12

# ansible 설치
> apt install software-properties-common -y
> add-apt-repository --yes --update ppa:ansible/ansible
> apt install ansible -y

# ansible 버전 확인
> ansible --version
ansible [core 2.17.14]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.10.12 (main, Jan  8 2026, 06:52:19) [GCC 11.4.0] (/usr/bin/python3)
  jinja version = 3.0.3
  libyaml = True

 

2. 호스트 선정

# 인벤토리 파일 생성
>  cat <<EOT > inventory
[web]
node1
node2

[db]
node3

[all:children]
web
db
EOT


# 인벤토리 검증
> ansible-inventory -i ./inventory --list | jq
{
  "_meta": {
    "hostvars": {}
  },
  "all": {
    "children": [
      "ungrouped",
      "web",
      "db"
    ]
  },
  "db": {
    "hosts": [
      "node3"
    ]
  },
  "web": {
    "hosts": [
      "node1",
      "node2"
    ]
  }
}

> ansible-inventory -i ./inventory --graph
@all:
  |--@ungrouped:
  |--@web:
  |  |--node1
  |  |--node2
  |--@db:
  |  |--node3

 

Ansible Configuration Settings — Ansible Community Documentation

** ansible config 적용 우선 순위
1) ANSIBLE_CONFIG (environment variable if set)
2) ansible.cfg (in the current directory)
3) ~/.ansible.cfg (in the home directory)
4) /etc/ansible/ansible.cfg

 

3. playbook 실행

# 플레이북 환경설정
# 앤서블 프로젝트 디렉터리에 ansible.cfg 파일을 생성하면 다양한 앤서블 설정 적용 가능

> cat ansible.cfg 
[defaults]
inventory = ./inventory
remote_user = root
ask_pass = false

[privilege_escalation]
become = true
become_method = sudo
become_user = root
become_ask_pass = false
** 모듈 작성 방식 비교
1) 짧은 형식 (Short-form) - Ansible이 자동으로 ansible.builtin 컬렉션에서 찾아줌
2) FQCN 형식 (Fully Qualified Collection Name) - 컬렉션명.모듈명 형태로 명확하게 지정

현대적인 Ansible에서는 FQCN 사용 권장

** 플레이북 실행 시 warning 메세지
- 지금은 잘 동작하지만 예기치 않게 Python 인터프리터가 바뀔 수 있다는 것을 의미
- 암묵적 Python 자동 선택을 지양하고, 명시적 설정을 권장
- 기본값 : ansible_python_interpreter=auto
- inventory에 ansible_python_interpreter=/usr/bin/python3 추가하여 설정

 

# 플레이북 실행하기

# 1. "debug" 모듈 사용 예제   (ansible.builtin.debug)

> cat first-playbook.yml 
---
- hosts: all
  tasks:
    - name: Print debug message
      debug:
        msg: Hello Ria

> ansible-playbook --syntax-check first-playbook.yml      // 문법 체크

playbook: first-playbook.yml

> ansible-playbook first-playbook.yml

PLAY [all] *********************************************************************************************************************
TASK [Gathering Facts] *****************************************************************************************************
ok: [node2]
ok: [node1]
ok: [node3]

TASK [Print debug message] ***********************************************************************************************
ok: [node1] => {
    "msg": "Hello Ria"
}
ok: [node2] => {
    "msg": "Hello Ria"
}
ok: [node3] => {
    "msg": "Hello Ria"
}

PLAY RECAP *****************************************************************************************************************
node1                      : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
node2                      : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
node3                      : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0



# 2. "service" 모듈 사용 예제    (ansible.builtin.service)
started : Start service httpd, if not started
stooped : Stop service httpd, if started
restarted : Restart service httpd, in all cases
reloaded : Reload service httpd, in all cases
> cat restart-service.yml 
---
- hosts: all
  tasks:
    - name: Restart sshd service
      service:
        name: ssh
        state: restarted

> ansible-playbook restart-service.yml

PLAY [all] ********************************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************
ok: [node1]
ok: [node2]
ok: [node3]

TASK [Restart sshd service] ***********************************************************************************************
changed: [node1]
changed: [node3]
changed: [node2]

PLAY RECAP ****************************************************************************************************************
node1                      : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
node2                      : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
node3                      : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

# OS 별 조건 분리도 가능

> cat restart-service.yml 
---
- hosts: all
  tasks:
    - name: Restart sshd service
      service:
        name: ssh
        state: restarted
      when: ansible_facts['os_family'] == 'RedHat'

> ansible-playbook restart-service.yml

PLAY [all] ********************************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************
ok: [node2]
ok: [node1]
ok: [node3]

TASK [Restart sshd service] ***********************************************************************************************
skipping: [node1]
skipping: [node2]
skipping: [node3]

PLAY RECAP ****************************************************************************************************************
node1                      : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
node2                      : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
node3                      : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
** 변수 설정
- 같은 Playbook을 다른 환경(개발/운영)이나 다른 서버에 재사용하려면 변수가 필수입니다.
- 같은 이름의 변수가 여러 곳에 정의되어 있다면 우선순위에 따라 결정됩니다.
추가변수(우선순위 높음) > 플레이변수 > 호스트변수 > 그룹변수(우선순위 낮음)

[4가지 변수 정의 방법]
1. 그룹 변수 (Group Variables)
- Inventory에서 정의한 그룹 전체에 적용되는 변수입니다.
- 변수 정의 위치 : Inventory나 별도 파일 (Playbook에 명시 안 해도 Ansible이 자동으로 찾아서 로딩)

2. 호스트 변수 (Host Variables)
특정 서버 하나에만 적용되는 변수입니다.
- 변수 정의 위치 : Inventory나 별도 파일 (Playbook에 명시 안 해도 Ansible이 자동으로 찾아서 로딩)

3. 플레이 변수 (Play Variables)
Playbook 내에서 정의하는 변수입니다.
- 변수 정의 위치 : Playbook 안에서만 정의 (변수를 별도 파일에 작성할 수는 있지만 Playbook 안에서 vars_files로 명시적으로 선언 필수)

4. 추가 변수 (Extra Variables)
Playbook 실행 시 커맨드라인에서 전달하는 변수입니다.
- 변수 정의 위치 : 실행 시 커맨드라인에서만 정의