Skip to main content

Ansible Role

디렉토리 규약, defaults vs vars, 의존성 관리, Galaxy, 실무 프로젝트 구조


📚 시리즈 네비게이션

이전현재다음
PlaybookRole-

🎯 Role이 필요한 이유

Playbook의 한계

서버가 늘어나고 구성이 복잡해지면 단일 Playbook은 관리하기 어렵다.

# site.yml - 모든 것이 한 파일에
- name: 전체 인프라 구성
hosts: all
become: yes
tasks:
# 공통 설정 (30줄)
# Nginx 설정 (50줄)
# Tomcat 설정 (60줄)
# MariaDB 설정 (40줄)
# 모니터링 설정 (30줄)
# ... 수백 줄

문제점:

  • 한 파일에 수백 줄 → 가독성 저하
  • Nginx 설정을 다른 프로젝트에서 재사용하려면 → 복사/붙여넣기
  • 변수, 템플릿, 핸들러가 뒤섞임 → 유지보수 어려움

Role로 해결

# site.yml - Role로 분리
- name: 전체 인프라 구성
hosts: all
become: yes
roles:
- common
- nginx
- tomcat
- mariadb
- monitoring
항목단일 PlaybookRole
재사용복사/붙여넣기import/include
구조한 파일에 전부디렉토리 규약으로 분리
변수 관리vars에 모두 나열defaults/vars로 분리
템플릿/파일경로 직접 지정자동 탐색
의존성수동 관리meta로 선언
공유어려움Galaxy로 배포

📂 Role 디렉토리 구조

roles/
└── nginx/
├── tasks/
│ └── main.yml # 핵심 작업 (필수)
├── handlers/
│ └── main.yml # 핸들러
├── templates/
│ └── nginx.conf.j2 # Jinja2 템플릿
├── files/
│ └── index.html # 정적 파일
├── vars/
│ └── main.yml # 내부 변수 (오버라이드 비권장)
├── defaults/
│ └── main.yml # 기본 변수 (오버라이드 가능)
├── meta/
│ └── main.yml # 의존성, 메타 정보
└── README.md # 문서

각 디렉토리 역할

디렉토리용도자동 로드
tasks/실행할 작업✅ main.yml
handlers/notify로 트리거되는 작업✅ main.yml
templates/Jinja2 템플릿 파일경로 자동 탐색
files/정적 파일 (copy 모듈용)경로 자동 탐색
vars/내부 변수 (높은 우선순위)✅ main.yml
defaults/기본 변수 (낮은 우선순위)✅ main.yml
meta/의존성, 라이선스, 플랫폼✅ main.yml

💡 templates/files/는 자동 탐색되므로 Task에서 파일명만 적으면 된다:

# Role 안에서는 경로 없이 파일명만
- template:
src: nginx.conf.j2 # templates/nginx.conf.j2 자동 탐색
dest: /etc/nginx/nginx.conf

최소 구조

모든 디렉토리가 필수는 아니다. tasks/main.yml만 있으면 Role로 동작한다.

roles/
└── simple-role/
└── tasks/
└── main.yml # 이것만 있어도 OK

✏️ Role 작성

예시: Nginx Role

defaults/main.yml — 사용자가 오버라이드할 수 있는 기본값:

# roles/nginx/defaults/main.yml
---
nginx_port: 80
nginx_server_name: localhost
nginx_worker_processes: auto
nginx_worker_connections: 1024
nginx_proxy_pass: "http://127.0.0.1:8080"
nginx_log_dir: /var/log/nginx

vars/main.yml — Role 내부에서만 쓰는 고정 변수:

# roles/nginx/vars/main.yml
---
nginx_packages:
- nginx
- curl
nginx_conf_path: /etc/nginx/nginx.conf
nginx_sites_path: /etc/nginx/conf.d

⚠️ defaults vs vars의 차이:

  • defaults: 우선순위 최하. 사용자가 group_vars, host_vars, playbook vars 등으로 자유롭게 오버라이드
  • vars: 우선순위 높음. Role 내부 로직용. 외부에서 쉽게 덮어쓸 수 없음

tasks/main.yml — 핵심 작업:

# roles/nginx/tasks/main.yml
---
- name: Nginx 패키지 설치
apt:
name: "{{ nginx_packages }}"
state: present
update_cache: yes
when: ansible_os_family == "Debian"

- name: Nginx 설정 디렉토리 생성
file:
path: "{{ nginx_sites_path }}"
state: directory
mode: '0755'

- name: Nginx 메인 설정 배포
template:
src: nginx.conf.j2
dest: "{{ nginx_conf_path }}"
owner: root
group: root
mode: '0644'
notify: Restart Nginx

- name: 사이트 설정 배포
template:
src: site.conf.j2
dest: "{{ nginx_sites_path }}/{{ nginx_server_name }}.conf"
notify: Reload Nginx

- name: 기본 사이트 비활성화
file:
path: /etc/nginx/sites-enabled/default
state: absent
notify: Reload Nginx

- name: Nginx 서비스 시작 및 활성화
systemd:
name: nginx
state: started
enabled: yes

handlers/main.yml — 서비스 재시작/리로드:

# roles/nginx/handlers/main.yml
---
- name: Validate Nginx
command: nginx -t
listen: "Restart Nginx"

- name: Restart Nginx
systemd:
name: nginx
state: restarted

- name: Reload Nginx
systemd:
name: nginx
state: reloaded

templates/nginx.conf.j2 — 메인 설정:

{# roles/nginx/templates/nginx.conf.j2 #}
# Managed by Ansible - Do not edit manually

user nginx;
worker_processes {{ nginx_worker_processes }};
pid /run/nginx.pid;

events {
worker_connections {{ nginx_worker_connections }};
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent"';

access_log {{ nginx_log_dir }}/access.log main;
error_log {{ nginx_log_dir }}/error.log warn;

sendfile on;
tcp_nopush on;
keepalive_timeout 65;

include {{ nginx_sites_path }}/*.conf;
}

templates/site.conf.j2 — 사이트 설정:

{# roles/nginx/templates/site.conf.j2 #}
server {
listen {{ nginx_port }};
server_name {{ nginx_server_name }};

access_log {{ nginx_log_dir }}/{{ nginx_server_name }}_access.log;
error_log {{ nginx_log_dir }}/{{ nginx_server_name }}_error.log;

location / {
proxy_pass {{ nginx_proxy_pass }};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}

location /health {
access_log off;
return 200 "OK\n";
add_header Content-Type text/plain;
}
}

meta/main.yml — 메타 정보:

# roles/nginx/meta/main.yml
---
galaxy_info:
role_name: nginx
author: your_name
description: Nginx reverse proxy role
license: MIT
min_ansible_version: "2.14"
platforms:
- name: Ubuntu
versions:
- jammy # 22.04
- noble # 24.04

dependencies: []

🚀 Role 사용

기본 사용

# site.yml
---
- name: Web Server 구성
hosts: web
become: yes
roles:
- nginx

변수 오버라이드

# site.yml - Role 호출 시 변수 전달
---
- name: Web Server 구성
hosts: web
become: yes
roles:
- role: nginx
vars:
nginx_port: 8080
nginx_server_name: app.example.com
nginx_proxy_pass: "http://192.168.1.20:8080"
# group_vars/web.yml - 그룹 변수로 오버라이드
nginx_port: 80
nginx_server_name: example.com
nginx_worker_connections: 2048

여러 Role 조합

# site.yml
---
- name: 공통 구성
hosts: all
become: yes
roles:
- common

- name: Web Server
hosts: web
become: yes
roles:
- nginx

- name: WAS Server
hosts: was
become: yes
roles:
- java
- tomcat

- name: DB Server
hosts: db
become: yes
roles:
- mariadb

Role 실행 순서

- name: Web 배포
hosts: web
become: yes

pre_tasks: # 1. 먼저 실행
- name: LB에서 제거
debug:
msg: "LB 제거"

roles: # 2. Role 실행
- nginx
- certbot

tasks: # 3. 추가 Task
- name: 앱 배포
copy:
src: app.war
dest: /opt/app/

post_tasks: # 4. 마지막 Task
- name: LB에 등록
debug:
msg: "LB 등록"

# handlers는 모든 단계 후 실행

🔗 Role 의존성

dependencies

Role이 다른 Role에 의존할 때 meta/main.yml에 선언.

# roles/tomcat/meta/main.yml
---
dependencies:
- role: java
vars:
java_version: "11"

실행 순서: commonjavatomcat (의존성 자동 해결)

의존성 중복 실행

기본적으로 같은 Role은 1번만 실행된다.

# roles/app1/meta/main.yml
dependencies:
- common

# roles/app2/meta/main.yml
dependencies:
- common

# site.yml
roles:
- app1 # common 실행 → app1 실행
- app2 # common 건너뜀 (이미 실행) → app2 실행

다른 변수로 여러 번 실행하려면 allow_duplicates: true:

# roles/vhost/meta/main.yml
---
allow_duplicates: true
# site.yml
roles:
- role: vhost
vars:
vhost_name: site1.example.com
- role: vhost
vars:
vhost_name: site2.example.com

📥 include vs import

Role 내부에서 Task를 분할할 때 두 가지 방법.

import_tasks (정적)

Playbook 파싱 시점에 포함. 조건부 포함 불가.

# roles/nginx/tasks/main.yml
---
- import_tasks: install.yml
- import_tasks: config.yml
- import_tasks: service.yml

include_tasks (동적)

실행 시점에 포함. 조건부 포함 가능.

# roles/nginx/tasks/main.yml
---
- include_tasks: install-{{ ansible_os_family | lower }}.yml

- include_tasks: ssl.yml
when: nginx_ssl_enabled | default(false)
roles/nginx/tasks/
├── main.yml
├── install-debian.yml
├── install-redhat.yml
├── config.yml
├── ssl.yml
└── service.yml
항목import_tasksinclude_tasks
시점파싱 시 (정적)실행 시 (동적)
조건부 포함
변수 파일명
tags 상속
--list-tasks표시됨표시 안 됨

💡 일반적으로 import_tasks 사용, 동적 분기가 필요할 때만 include_tasks.


🌐 Ansible Galaxy

커뮤니티 Role을 공유하는 플랫폼.

Role 검색 및 설치

# 검색
ansible-galaxy search nginx

# 설치
ansible-galaxy install geerlingguy.nginx

# 특정 버전 설치
ansible-galaxy install geerlingguy.nginx,3.1.0

# 설치 경로 확인
ansible-galaxy list

requirements.yml

프로젝트에 필요한 Role을 파일로 관리.

# requirements.yml
---
roles:
- name: geerlingguy.nginx
version: "3.1.0"
- name: geerlingguy.java
version: "2.3.0"
- name: geerlingguy.mysql
version: "4.0.0"

# Git 저장소에서 직접
- src: https://github.com/your-org/ansible-role-common.git
scm: git
version: main
name: common
# 일괄 설치
ansible-galaxy install -r requirements.yml

# 강제 재설치
ansible-galaxy install -r requirements.yml --force

Role 초기화

# 표준 구조로 새 Role 생성
ansible-galaxy init roles/nginx

# 생성되는 구조
roles/nginx/
├── README.md
├── defaults/main.yml
├── files/
├── handlers/main.yml
├── meta/main.yml
├── tasks/main.yml
├── templates/
├── tests/
│ ├── inventory
│ └── test.yml
└── vars/main.yml

📂 프로젝트 구조 예시

Role을 활용한 실무 프로젝트 전체 구조:

ansible-3tier/
├── ansible.cfg
├── inventory/
│ ├── production.yml
│ └── staging.yml
├── group_vars/
│ ├── all.yml # 전체 공통 변수
│ ├── web.yml # Web 그룹 변수
│ ├── was.yml # WAS 그룹 변수
│ └── db.yml # DB 그룹 변수
├── roles/
│ ├── common/ # 공통 (NTP, 사용자, 패키지)
│ │ ├── tasks/main.yml
│ │ ├── handlers/main.yml
│ │ └── defaults/main.yml
│ ├── nginx/ # Web Server
│ │ ├── tasks/main.yml
│ │ ├── handlers/main.yml
│ │ ├── templates/
│ │ └── defaults/main.yml
│ ├── java/ # Java (Tomcat 의존성)
│ │ ├── tasks/main.yml
│ │ └── defaults/main.yml
│ ├── tomcat/ # WAS
│ │ ├── tasks/main.yml
│ │ ├── handlers/main.yml
│ │ ├── templates/
│ │ ├── defaults/main.yml
│ │ └── meta/main.yml # depends: java
│ └── mariadb/ # DB
│ ├── tasks/main.yml
│ ├── handlers/main.yml
│ ├── templates/
│ └── defaults/main.yml
├── site.yml # 메인 Playbook
├── web.yml
├── was.yml
├── db.yml
└── requirements.yml # Galaxy 의존성

site.yml:

---
- import_playbook: web.yml
- import_playbook: was.yml
- import_playbook: db.yml

web.yml:

---
- name: Web Server 구성
hosts: web
become: yes
roles:
- common
- nginx

was.yml:

---
- name: WAS Server 구성
hosts: was
become: yes
roles:
- common
- tomcat # meta에서 java 의존성 자동 해결

db.yml:

---
- name: DB Server 구성
hosts: db
become: yes
roles:
- common
- mariadb

✅ Role 작성 권장 사항

변수 설계

# defaults/main.yml - 사용자 인터페이스
nginx_port: 80 # 사용자가 변경 가능
nginx_worker_connections: 1024 # 사용자가 변경 가능

# vars/main.yml - 내부 로직용
nginx_conf_path: /etc/nginx/nginx.conf # 변경하면 안 되는 값
구분defaults/vars/
우선순위최하높음
용도사용자 설정내부 고정값
오버라이드◎ 권장✕ 비권장
예시포트, 도메인, 리소스패키지명, 경로

네이밍

변수명에 Role 이름을 prefix로 붙여서 충돌 방지:

# 나쁜 예: 다른 Role과 변수명 충돌 가능
port: 80
config_path: /etc/nginx/nginx.conf

# 좋은 예: Role명 prefix
nginx_port: 80
nginx_config_path: /etc/nginx/nginx.conf

Task 분할

규모가 큰 Role은 파일을 분리:

# roles/nginx/tasks/main.yml
---
- import_tasks: install.yml
tags: [nginx, install]

- import_tasks: config.yml
tags: [nginx, config]

- import_tasks: service.yml
tags: [nginx, service]

README 작성

# Nginx Role

## 변수

| 변수 | 기본값 | 설명 |
|------|--------|------|
| nginx_port | 80 | 리스닝 포트 |
| nginx_server_name | localhost | 서버명 |

## 사용 예시

\```yaml
roles:
- role: nginx
vars:
nginx_port: 8080
\```

## 의존성

없음

🔗 시리즈 네비게이션

이전다음
Ansible Playbook-

🔗 참고 자료