롤
롤 (Roles)
롤(role)은 알려진 파일 구조를 기반으로 관련된 vars, files, tasks, handlers 그리고 다른 Ansible 아티팩트를 자동으로 로드하게 해 줘요. 콘텐츠를 롤로 그룹화하면 쉽게 재사용하고 다른 사용자와 공유할 수 있어요.
출처: 문서
본문
롤은 알려진 파일 구조를 기반으로 관련된 vars, files, tasks, handlers 및 기타 Ansible 아티팩트를 자동으로 로드하게 해 줘요. 콘텐츠를 롤로 그룹화한 뒤에는 쉽게 재사용하고 다른 사용자와 공유할 수 있어요.
롤 디렉터리 구조
Ansible 롤은 일곱 개의 메인 표준 디렉터리로 구성된 정의된 디렉터리 구조를 가져요. 각 롤에 이 디렉터리 중 최소 하나는 포함해야 해요. 롤이 사용하지 않는 디렉터리는 생략할 수 있어요. 예:
# playbooks
site.yml
webservers.yml
fooservers.yml
roles/
common/ # this hierarchy represents a "role"
tasks/ #
main.yml # <-- tasks file can include smaller files if warranted
handlers/ #
main.yml # <-- handlers file
templates/ # <-- files for use with the template resource
ntp.conf.j2 # <------- templates end in .j2
files/ #
bar.txt # <-- files for use with the copy resource
foo.sh # <-- script files for use with the script resource
vars/ #
main.yml # <-- variables associated with this role
defaults/ #
main.yml # <-- default lower priority variables for this role
meta/ #
main.yml # <-- role dependencies
library/ # roles can also include custom modules
module_utils/ # roles can also include custom module_utils
lookup_plugins/ # or other types of plugins, like lookup in this case
webtier/ # same kind of structure as "common" was above, done for the webtier role
monitoring/ # ""
fooapp/ # ""
기본적으로 Ansible은 대부분의 롤 디렉터리에서 관련 콘텐츠를 담은 main.yml 파일(main.yaml과 main도 포함)을 찾아요:
tasks/main.yml- 롤이 플레이에 제공해서 실행하는 작업 목록.handlers/main.yml- 부모 플레이에 import되어 롤이나 플레이 안의 다른 롤·작업이 사용하는 핸들러.defaults/main.yml- 롤이 제공하는 변수 중 우선순위가 매우 낮은 값 (자세한 내용은 변수 사용하기 참고). 롤 자신의 기본값은 다른 롤의 기본값보다 우선하지만, 그 외 다른 모든 변수 소스는 이를 덮어써요.vars/main.yml- 롤이 플레이에 제공하는 높은 우선순위의 변수 (자세한 내용은 변수 사용하기 참고).files/stuff.txt- 롤과 그 자식 롤에서 사용할 수 있는 하나 이상의 파일.templates/something.j2- 롤이나 자식 롤에서 사용할 템플릿.meta/main.yml- 롤 의존성을 포함한 롤 메타데이터와 지원 플랫폼 같은 선택적 Galaxy 메타데이터. 갤럭시에 단독 롤로 업로드하려면 필요하지만, 플레이에서 롤을 사용하는 데는 필요하지 않아요.
참고
- 위 파일 중 어느 것도 롤에 필수는 아니에요. 예를 들어
files/something.txt나vars/for_import.yml만 제공해도 여전히 유효한 롤이에요.- 단독(standalone) 롤에는
library/my_module.py같은 커스텀 모듈이나 플러그인도 포함할 수 있으며, 이 롤 안에서 사용할 수 있어요 (롤에 모듈·플러그인 임베딩 자세한 내용 참고).- '단독(stand alone)' 롤은 컬렉션의 일부가 아니라 개별 설치 가능한 콘텐츠인 롤을 말해요.
vars/와defaults/의 변수는import_role/include_role의public옵션으로 비활성화하지 않는 한 플레이 범위로 import돼요.
일부 디렉터리에 다른 YAML 파일을 추가할 수 있지만, 기본적으로 사용되지는 않아요. 그것들은 직접 include/import하거나 include_role/import_role을 쓸 때 지정할 수 있어요. 예를 들어 플랫폼별 작업을 별도 파일에 두고 tasks/main.yml에서 참조할 수 있어요:
# roles/example/tasks/main.yml
- name: Install the correct web server for RHEL
ansible.builtin.import_tasks: redhat.yml
when: ansible_facts['os_family']|lower == 'redhat'
- name: Install the correct web server for Debian
ansible.builtin.import_tasks: debian.yml
when: ansible_facts['os_family']|lower == 'debian'
# roles/example/tasks/redhat.yml
- name: Install web server
ansible.builtin.yum:
name: "httpd"
state: present
# roles/example/tasks/debian.yml
- name: Install web server
ansible.builtin.apt:
name: "apache2"
state: present
또는 롤을 로드할 때 그 작업들을 직접 호출할 수도 있는데, 이 경우 main.yml 파일을 우회해요:
- name: include apt tasks
ansible.builtin.include_role:
name: package_manager_bootstrap
tasks_from: apt.yml
when: ansible_facts['os_family'] == 'Debian'
defaults와 vars 디렉터리는 중첩된 디렉터리도 포함할 수 있어요. 변수 파일이 디렉터리라면 Ansible은 그 안의 모든 변수 파일과 디렉터리를 알파벳순으로 읽어요. 중첩 디렉터리에 변수 파일과 디렉터리가 모두 있다면 Ansible은 디렉터리를 먼저 읽어요. 다음은 vars/main 디렉터리의 예시예요:
roles/
common/ # this hierarchy represents a "role"
vars/
main/ # <-- variables associated with this role
first_nested_directory/
first_variables_file.yml
second_nested_directory/
second_variables_file.yml
third_variables_file.yml
롤 저장하고 찾기
기본적으로 Ansible은 다음 위치에서 롤을 찾아요:
- 컬렉션을 사용한다면 컬렉션 안에서
- 플레이북 파일 기준
roles/라는 디렉터리에서 - 구성된 roles_path에서. 기본 검색 경로는
~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles예요. - 플레이북 파일이 있는 디렉터리에서
롤을 다른 위치에 저장한다면 roles_path 구성 옵션을 설정해서 Ansible이 롤을 찾게 하세요. 공유 롤을 단일 위치에 체크인하면 여러 플레이북에서 사용하기 쉬워져요. ansible.cfg에서 설정을 관리하는 방법은 Ansible 구성하기를 참고하세요.
또는 롤을 정규화된 경로로 호출할 수도 있어요:
---
- hosts: webservers
roles:
- role: '/path/to/my/roles/common'
롤 사용하기
롤은 다음 방식으로 사용할 수 있어요:
- 플레이 레벨에서
roles옵션으로: 플레이에서 롤을 사용하는 전통적인 방식이에요. - 작업 레벨에서
include_role로: 플레이의tasks섹션 어디에서든include_role로 롤을 동적으로 재사용할 수 있어요. - 작업 레벨에서
import_role로: 플레이의tasks섹션 어디에서든import_role로 롤을 정적으로 재사용할 수 있어요. - 다른 롤의 의존성으로 (이 페이지의
meta/main.yml에 있는dependencies키워드 참고).
플레이 레벨에서 롤 사용하기
롤을 사용하는 전통적(원래) 방법은 특정 플레이에 roles 옵션을 쓰는 것이에요:
---
- hosts: webservers
roles:
- common
- webservers
플레이 레벨에서 roles 옵션을 쓰면, 각 롤 'x'는 다음 디렉터리에서 main.yml(main.yaml과 main도 포함)을 찾아요:
roles/x/tasks/roles/x/handlers/roles/x/vars/roles/x/defaults/roles/x/meta/- 롤 안의 어떤 copy, script, template, include 작업이든 상대·절대 경로로 경로를 지정하지 않고 roles/x/{files,templates,tasks}/의 파일을 참조할 수 있어요.
참고:
vars와defaults는 같은 이름의 디렉터리와도 일치할 수 있고, Ansible은 그 디렉터리에 포함된 모든 파일을 처리해요. 자세한 내용은 '롤 디렉터리 구조'를 참고하세요.
참고:
include_role/import_role을 사용하면main대신 커스텀 파일 이름을 지정할 수 있어요.meta디렉터리는 커스터마이징을 허용하지 않으므로 예외예요.
플레이 레벨에서 roles 옵션을 쓰면 Ansible은 롤을 정적 import로 취급해서 플레이북 파싱 중에 처리해요. Ansible은 각 플레이를 다음 순서로 실행해요:
- 플레이에 정의된 모든
pre_tasks. - pre_tasks가 트리거한 모든 핸들러.
roles:에 나열된 각 롤을 나열된 순서대로. 롤의meta/main.yml에 정의된 롤 의존성은 태그 필터링과 조건부를 적용받아 먼저 실행돼요. 자세한 내용은 '롤 의존성 사용하기'를 참고하세요.- 플레이에 정의된 모든
tasks. - 롤이나 작업이 트리거한 모든 핸들러.
- 플레이에 정의된 모든
post_tasks. - post_tasks가 트리거한 모든 핸들러.
참고: 롤 안의 작업에 태그를 사용한다면 pre_tasks, post_tasks, 롤 의존성도 함께 태그해서 함께 전달해야 해요. 특히 pre/post 작업과 롤 의존성이 모니터링 중단(outage) 창 제어나 로드 밸런싱에 쓰일 때 그래요. 태그 추가와 사용에 대한 자세한 내용은 태그 (Tags)를 참고하세요.
roles 옵션에 다른 키워드를 전달할 수 있어요:
---
- hosts: webservers
roles:
- common
- role: foo_app_instance
vars:
dir: '/opt/a'
app_port: 5000
tags: typeA
- role: foo_app_instance
vars:
dir: '/opt/b'
app_port: 5001
tags: typeB
role 옵션에 태그를 추가하면 Ansible은 그 태그를 롤 안의 모든 작업에 적용해요.
참고:
ansible-core2.15 이전에는 플레이북의roles:섹션 안의vars:가 플레이 변수에 추가되어 롤 전후의 플레이 안 모든 작업에서 사용할 수 있었어요. 이 동작은 DEFAULT_PRIVATE_ROLE_VARS로 바꿀 수 있어요. 최신 버전에서는vars:가 플레이의 변수 범위로 누출되지 않아요.
롤 include하기: 동적 재사용
플레이의 tasks 섹션 어디에서든 include_role로 롤을 동적으로 재사용할 수 있어요. roles 섹션에 추가된 롤은 플레이의 다른 작업보다 먼저 실행되지만, include된 롤은 정의된 순서대로 실행돼요. include_role 작업 앞에 다른 작업이 있다면 그 작업들이 먼저 실행돼요.
롤을 include하려면:
---
- hosts: webservers
tasks:
- name: Print a message
ansible.builtin.debug:
msg: "this task runs before the example role"
- name: Include the example role
ansible.builtin.include_role:
name: example
- name: Print a message
ansible.builtin.debug:
msg: "this task runs after the example role"
롤을 include할 때 변수와 태그를 포함한 다른 키워드를 전달할 수 있어요:
---
- hosts: webservers
tasks:
- name: Include the foo_app_instance role
ansible.builtin.include_role:
name: foo_app_instance
vars:
dir: '/opt/a'
app_port: 5000
tags: typeA
# ...
include_role 작업에 태그를 추가하면 Ansible은 그 태그를 include 자체에 만 적용해요. 즉 --tags를 전달해서 롤에서 선택된 작업만 실행할 수 있는데, 그 작업들이 include 문과 같은 태그를 가질 때 그래요. 자세한 내용은 재사용 파일에서 태그된 작업 선택적으로 실행하기를 참고하세요.
롤을 조건부로 include할 수 있어요:
---
- hosts: webservers
tasks:
- name: Include the some_role role
ansible.builtin.include_role:
name: some_role
when: "ansible_facts['os_family'] == 'RedHat'"
롤 import하기: 정적 재사용
플레이의 tasks 섹션 어디에서든 import_role로 롤을 정적으로 재사용할 수 있어요. 동작은 roles 키워드를 쓰는 것과 같아요. 예:
---
- hosts: webservers
tasks:
- name: Print a message
ansible.builtin.debug:
msg: "before we run our role"
- name: Import the example role
ansible.builtin.import_role:
name: example
- name: Print a message
ansible.builtin.debug:
msg: "after we ran our role"
롤을 import할 때 변수와 태그를 포함한 다른 키워드를 전달할 수 있어요:
---
- hosts: webservers
tasks:
- name: Import the foo_app_instance role
ansible.builtin.import_role:
name: foo_app_instance
vars:
dir: '/opt/a'
app_port: 5000
# ...
import_role 문에 태그를 추가하면 Ansible은 그 태그를 롤 안의 모든 작업에 적용해요. 자세한 내용은 태그 상속: 여러 작업에 태그 추가하기를 참고하세요.
롤 인자 검증 (Role argument validation)
버전 2.11부터 인자 스펙(argument specification)을 기반으로 롤 인자 검증을 활성화할 수 있어요. 이 스펙은 meta/argument_specs.yml 파일(.yaml 확장자도 가능)에 정의돼요. 이 인자 스펙이 정의되면 롤 실행 시작 부분에 새 작업이 삽입되어, 롤에 제공된 파라미터를 스펙에 대해 검증해요. 파라미터가 검증에 실패하면 롤 실행은 실패해요.
참고: Ansible은 롤
meta/main.yml파일에 정의된 롤 스펙도 지원해요. 다만 이 파일 안에 스펙을 정의하는 롤은 2.11 미만 버전에서 동작하지 않아요. 이런 이유로 하위 호환성을 유지하려면meta/argument_specs.yml파일을 사용하는 것을 권장해요.
참고: 의존성을 정의한 롤에 롤 인자 검증을 사용하면, 의존하는 롤의 인자 검증이 실패하더라도 그 의존성들에 대한 검증이 의존하는 롤보다 먼저 실행돼요.
참고: Ansible은 삽입된 롤 인자 검증 작업에 always 태그를 붙여요. 롤이 정적으로 import되면
--skip-tags플래그를 사용하지 않는 한 이 작업이 실행돼요.
스펙 형식 (Specification format)
롤 인자 스펙은 롤 meta/argument_specs.yml 파일의 최상위 argument_specs 블록에 정의해야 해요. 모든 필드는 소문자예요.
entry-point-name
- 롤 엔트리 포인트의 이름.
- 엔트리 포인트를 지정하지 않은 경우
main이어야 해요. - 실행할 tasks 파일의 기본 이름이 되며,
.yml이나.yaml확장자는 붙지 않아요.
short_description
- 엔트리 포인트에 대한 짧고 한 줄짜리 설명. 이상적으로는 문장이 아니라 구(phrase)여야 해요.
short_description은ansible-doc -t role -l로 표시돼요.- 문서의 롤 페이지 제목의 일부가 되기도 해요.
- 짧은 설명은 항상 문자열이고 절대 리스트가 아니어야 하며, 마침표로 끝나지 않아야 해요.
- 이 필드에서 Ansible 마크업을 사용할 수 있어요.
description
- 여러 줄을 포함할 수 있는 더 긴 설명.
- 단일 문자열이거나 문자열 리스트일 수 있어요. 문자열 리스트라면 각 리스트 요소가 새 문단이 돼요.
- 이 필드에서 Ansible 마크업을 사용할 수 있어요.
version_added
- 엔트리 포인트가 추가된 롤의 버전.
- float가 아닌 문자열이에요. 예:
version_added: '2.1'. - 컬렉션에서는 엔트리 포인트가 추가된 컬렉션 버전이어야 해요. 예:
version_added: 1.0.0.
author
- 엔트리 포인트 작성자의 이름.
- 단일 문자열이거나 문자열 리스트일 수 있어요. 작성자마다 리스트 항목 하나를 사용하세요. 작성자가 한 명뿐이라면 문자열이나 한 요소짜리 리스트를 쓰세요.
options
- 옵션은 흔히 "파라미터(parameters)"나 "인자(arguments)"라고 불러요. 이 섹션은 그 옵션들을 정의해요.
- 각 롤 옵션(인자)에 대해 다음을 포함할 수 있어요:
option-name
- 옵션/인자의 이름.
description
- 이 옵션이 무엇을 하는지 자세히 설명. 완전한 문장으로 작성해야 해요.
- 단일 문자열이거나 문자열 리스트일 수 있어요. 문자열 리스트라면 각 리스트 요소가 새 문단이 돼요.
- 이 필드에서 Ansible 마크업을 사용할 수 있어요.
version_added
- 이 옵션이 초기 롤/엔트리 포인트 릴리스 이후에 추가된 경우에만 필요해요. 즉, 최상위
version_added필드보다 큰 값이에요. - float가 아닌 문자열이에요. 예:
version_added: '2.1'. - 컬렉션에서는 옵션이 추가된 컬렉션 버전이어야 해요. 예:
version_added: 1.0.0.
type
- 옵션의 데이터 타입.
type의 허용 값은 Argument spec을 참고하세요. 기본값은str이에요. - 옵션 타입이
list라면elements를 지정해야 해요.
참고: 타입 검증은 강제 변환(coercive) 방식이라 기대
type으로 변환할 수 있는 값은 검증을 통과해요. 다만 런타임에는 롤이 원래의 강제 변환되지 않은 값을 받아요. 예를 들어str을 기대하는 값에int1을 전달하면 검증을 통과해요. 이 경우 롤은 강제 변환된str"1"대신int1을 받아요. 필요에 따라| string이나| bool같은 필터로 값을 강제 변환하세요.
required
true일 때만 필요해요.- 없으면 옵션은 필수가 아니에요.
default
required가false/없으면default를 지정할 수 있어요 (없으면null로 가정).- 문서의 기본값이 코드의 기본값과 일치하는지 확인하세요. 롤 변수의 실제 기본값은 항상 롤 기본값에서 온다는 점을 기억하세요 (본 페이지 '롤 디렉터리 구조'에 정의됨).
- 기본값 필드는 추가 정보나 조건이 필요하지 않는 한 description의 일부로 나열해서는 안 돼요.
- 옵션이 boolean 값이라면
ansible-lint와 호환되도록true/false를 사용해야 해요.
choices
- 옵션 값의 목록.
- 비어 있으면 없어야 해요.
elements
- type이
list일 때 리스트 요소의 데이터 타입을 지정해요.
options
- 이 옵션의 type이 dict 또는 dict의 리스트라면 여기서 그 구조를 정의할 수 있어요.
샘플 스펙 (Sample specification)
# roles/myapp/meta/argument_specs.yml
---
argument_specs:
# roles/myapp/tasks/main.yml entry point
main:
short_description: Main entry point for the myapp role
description:
- This is the main entrypoint for the C(myapp) role.
- Here we can describe what this entrypoint does in lengthy words.
- Every new list item is a new paragraph. You can have multiple sentences
per paragraph.
author:
- Daniel Ziegenberg
options:
myapp_int:
type: "int"
required: false
default: 42
description:
- "The integer value, defaulting to 42."
- "This is a second paragraph."
myapp_str:
type: "str"
required: true
description: "The string value"
myapp_list:
type: "list"
elements: "str"
required: true
description: "A list of string values."
version_added: 1.3.0
myapp_list_with_dicts:
type: "list"
elements: "dict"
required: false
default:
- myapp_food_kind: "meat"
myapp_food_boiling_required: true
myapp_food_preparation_time: 60
- myapp_food_kind: "fruits"
myapp_food_preparation_time: 5
description: "A list of dicts with a defined structure and with a default value."
options:
myapp_food_kind:
type: "str"
choices:
- "vegetables"
- "fruits"
- "grains"
- "meat"
required: false
description: "A string value with a limited list of allowed choices."
myapp_food_boiling_required:
type: "bool"
required: false
default: false
description: "Whether the kind of food requires boiling before consumption."
myapp_food_preparation_time:
type: int
required: true
description: "Time to prepare a dish in minutes."
myapp_dict_with_suboptions:
type: "dict"
required: false
default:
myapp_host: "bar.foo"
myapp_exclude_host: true
myapp_path: "/etc/myapp"
description: "A dict with a defined structure and default values."
options:
myapp_host:
type: "str"
choices:
- "foo.bar"
- "bar.foo"
- "ansible.foo.bar"
required: true
description: "A string value with a limited list of allowed choices."
myapp_exclude_host:
type: "bool"
required: true
description: "A boolean value."
myapp_path:
type: "path"
required: true
description: "A path value."
original_name:
type: list
elements: "str"
required: false
description: "An optional list of string values."
# roles/myapp/tasks/alternate.yml entry point
alternate:
short_description: Alternate entry point for the myapp role
description:
- This is the alternate entrypoint for the C(myapp) role.
version_added: 1.2.0
options:
myapp_int:
type: "int"
required: false
default: 1024
description: "The integer value, defaulting to 1024."
한 플레이에서 롤을 여러 번 실행하기
Ansible은 각 정의마다 파라미터가 다르지 않으면, 롤을 플레이에서 한 번만 실행해요. 예를 들어 Ansible은 이런 플레이에서 롤 foo를 한 번만 실행해요:
---
- hosts: webservers
roles:
- foo
- bar
- foo
Ansible이 롤을 한 번 이상 실행하게 강제하는 방법은 두 가지가 있어요.
다른 파라미터 전달하기
각 롤 정의에 다른 파라미터를 전달하면 Ansible은 롤을 한 번 이상 실행해요. 다른 변수 값을 제공하는 것은 다른 롤 파라미터를 전달하는 것과 같지 않아요. 이 동작에는 roles 키워드를 사용해야 해요. import_role과 include_role은 롤 파라미터를 받지 않기 때문이에요.
이 플레이에서 foo 롤을 두 번 실행해요:
---
- hosts: webservers
roles:
- { role: foo, message: "first" }
- { role: foo, message: "second" }
이 문법도 foo 롤을 두 번 실행해요:
---
- hosts: webservers
roles:
- role: foo
message: "first"
- role: foo
message: "second"
이 예시들에서 Ansible은 각 롤 정의가 서로 다른 파라미터를 가지기 때문에 foo를 두 번 실행해요.
allow_duplicates: true 사용하기
롤의 meta/main.yml 파일에 allow_duplicates: true를 추가하세요:
# playbook.yml
---
- hosts: webservers
roles:
- foo
- foo
# roles/foo/meta/main.yml
---
allow_duplicates: true
이 예시에서 Ansible은 명시적으로 허용했기 때문에 foo를 두 번 실행해요.
롤 의존성 사용하기 (Using role dependencies)
롤 의존성을 사용하면 롤을 쓸 때 다른 롤을 자동으로 가져올 수 있어요.
롤 의존성은 전제 조건이지, 진짜 의존성이 아니에요. 롤에는 부모/자식 관계가 없어요. Ansible은 나열된 모든 롤을 로드하고, dependencies 아래 나열된 롤을 먼저 실행한 뒤, 그것들을 나열한 롤을 실행해요. 플레이 객체는 dependencies 목록이 호출한 롤을 포함한 모든 롤의 부모예요.
롤 의존성은 롤 디렉터리 안의 meta/main.yml 파일에 저장돼요. 이 파일에는 지정된 롤 앞에 삽입할 롤과 파라미터 목록이 포함되어야 해요. 예:
# roles/myapp/meta/main.yml
---
dependencies:
- role: common
vars:
some_parameter: 3
- role: apache
vars:
apache_port: 80
- role: postgres
vars:
dbname: blarg
other_parameter: 12
Ansible은 dependencies에 나열된 롤을 항상 그것들을 나열한 롤보다 먼저 실행해요. Ansible은 roles 키워드를 사용할 때 이 패턴을 재귀적으로 실행해요. 예를 들어 roles: 아래에 롤 foo를 나열하고, 롤 foo가 meta/main.yml의 dependencies 아래에 롤 bar를 나열하며, 롤 bar가 meta/main.yml의 dependencies 아래에 롤 baz를 나열하면, Ansible은 baz, 그다음 bar, 그다음 foo 순서로 실행해요.
한 플레이에서 롤 의존성을 여러 번 실행하기
Ansible은 중복 롤 의존성을 roles: 아래에 나열된 중복 롤처럼 처리해요. 즉 각 정의마다 파라미터, 태그, when 절이 다르지 않으면, Ansible은 롤 의존성을 여러 번 정의해도 한 번만 실행해요. 한 플레이의 두 롤이 모두 세 번째 롤을 의존성으로 나열한다면, Ansible은 그 롤 의존성을 한 번만 실행해요(각 정의에 다른 파라미터·태그·when 절을 전달하거나, 여러 번 실행할 롤에 allow_duplicates: true를 쓰지 않는 한). 자세한 내용은 Galaxy 롤 의존성을 참고하세요.
참고: 롤 중복 제거는 부모 롤의 호출 시그니처(invocation signature)를 고려하지 않아요. 또한 롤 파라미터 대신
vars:를 사용하면 변수 범위가 바뀌는 부작용이 있어요.vars:를 사용하면 그 변수들이 플레이 레벨로 범위가 지정돼요. 아래 예시에서vars:를 쓰면n이 그 앞에서 호출된 롤을 포함해 플레이 전체에서4로 정의될 거예요. 이 외에도 롤 중복 제거가 변수 평가 이전에 발생한다는 점을 알아야 해요. 즉 Lazy Evaluation 때문에 겉보기에 다른 롤 호출이 동등해져서, 롤이 한 번 이상 실행되지 않을 수 있어요.
예를 들어 car라는 롤이 다음과 같이 wheel라는 롤에 의존한다고 해볼게요:
---
dependencies:
- role: wheel
n: 1
- role: wheel
n: 2
- role: wheel
n: 3
- role: wheel
n: 4
그리고 wheel 롤은 tire와 brake 두 롤에 의존해요. wheel의 meta/main.yml은 다음과 같아요:
---
dependencies:
- role: tire
- role: brake
그리고 tire와 brake의 meta/main.yml은 다음과 같아요:
---
allow_duplicates: true
결과 실행 순서는 다음과 같아요:
tire(n=1)
brake(n=1)
wheel(n=1)
tire(n=2)
brake(n=2)
wheel(n=2)
...
car
롤 의존성에 allow_duplicates: true를 사용하려면, 그것을 나열한 롤이 아니라 dependencies 아래에 나열된 롤에 지정해야 해요. 위 예시에서 allow_duplicates: true는 tire와 brake 롤의 meta/main.yml에 나타나요. wheel 롤은 car가 정의한 각 인스턴스가 서로 다른 파라미터 값을 사용하므로 allow_duplicates: true가 필요하지 않아요.
참고: Ansible이 서로 다른 곳에 정의된 변수 값 중에서 어떻게 고르는지(변수 상속과 범위) 자세한 내용은 변수 사용하기를 참고하세요. 또한 중복 제거는 플레이 레벨에서만 발생하므로 같은 플레이북의 여러 플레이는 롤을 다시 실행할 수 있어요.
롤에 모듈과 플러그인 임베딩하기
참고: 이 내용은 단독(standalone) 롤에만 적용돼요. 컬렉션 안의 롤은 플러그인 임베딩을 지원하지 않아요. 플러그인을 배포하려면 컬렉션의
plugins구조를 사용해야 해요.
커스텀 모듈(모듈을 개발해야 할까요?)이나 플러그인(플러그인 개발하기)을 작성했다면, 그것을 롤의 일부로 배포하고 싶을 수 있어요. 예를 들어 회사 내부 소프트웨어 설정을 돕는 모듈을 작성했는데, 조직의 다른 사람들이 이 모듈을 사용하길 바라지만 모든 사람에게 Ansible 라이브러리 경로 설정법을 알려주고 싶지 않다면, 그 모듈을 internal_config 롤에 포함시킬 수 있어요.
롤에 모듈이나 플러그인을 추가하려면: 롤의 'tasks'와 'handlers' 구조 옆에 'library'라는 디렉터리를 추가하고, 'library' 디렉터리 안에 직접 모듈을 포함하세요.
이런 구조가 있다고 가정해볼게요:
roles/
my_custom_modules/
library/
module1
module2
그 모듈은 롤 자체뿐 아니라 이 롤 다음에 호출되는 모든 롤에서도 사용할 수 있어요:
---
- hosts: webservers
roles:
- my_custom_modules
- some_other_role_using_my_custom_modules
- yet_another_role_using_my_custom_modules
필요하다면 Ansible 코어 배포의 모듈을 수정하려고 롤에 모듈을 임베딩할 수도 있어요. 예를 들어 특정 모듈이 프로덕션 릴리스로 출시되기 전에 개발 버전을 사용하려면, 그 모듈을 복사해서 그 사본을 롤에 임베딩하면 돼요. 코어 컴포넌트에서 API 시그니처가 바뀔 수 있고 이 해결책이 동작을 보장하지 않으므로 주의해서 사용하세요.
같은 메커니즘을 사용해서 동일한 스키마로 롤에 플러그인을 임베딩하고 배포할 수 있어요. 예를 들어 필터 플러그인의 경우:
roles/
my_custom_filter/
filter_plugins
filter1
filter2
그러면 이 필터들은 'my_custom_filter' 이후에 호출되는 어떤 롤의 Jinja 템플릿에서도 사용할 수 있어요.
롤 공유하기: Ansible Galaxy
Ansible Galaxy는 커뮤니티가 개발한 다양한 Ansible 롤을 찾고, 다운로드하고, 평가하고, 리뷰할 수 있는 무료 사이트로, 자동화 프로젝트에 큰 도약을 얻을 수 있는 좋은 방법이에요.
ansible-galaxy 클라이언트는 Ansible에 포함되어 있어요. Galaxy 클라이언트는 Ansible Galaxy에서 롤을 다운로드할 수 있게 해 주고, 자신만의 롤을 만들기 위한 훌륭한 기본 프레임워크를 제공해요.
자세한 내용은 Ansible Galaxy 문서 페이지를 읽어보세요.
더 알아보기 (Learn more)
- Galaxy 사용자 가이드 — 새 롤을 만들고 Galaxy에서 공유하는 방법, 롤 관리
- 재사용 파일과 롤 (Reusing files and roles) — include와 import의 동적/정적 차이
- 태그 (Tags) — 롤이나 작업을 선택·건너뛰는 데 태그 사용하기
- 모듈을 개발해야 할까요? — 커스텀 모듈 작성하기