Ansible Role
디렉토리 규약, defaults vs vars, 의존성 관리, Galaxy, 실무 프로젝트 구조
📚 시리즈 네비게이션
| 이전 | 현재 | 다음 |
|---|---|---|
| Playbook | Role | - |
🎯 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
| 항목 | 단일 Playbook | Role |
|---|---|---|
| 재사용 | 복사/붙여넣기 | 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
⚠️
defaultsvsvars의 차이:
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"
실행 순서: common → java → tomcat (의존성 자동 해결)
의존성 중복 실행
기본적으로 같은 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_tasks | include_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 | - |