DevOps/Ansible

[Ansible] Playbook Style Guide

`작은거인` 2020. 1. 21. 18:01

Table of Contents

  1. Practices
  2. Start of Files
  3. End of Files
  4. Quotes
  5. Environment
  6. Booleans
  7. Key value pairs
  8. Sudo
  9. Hosts Declaration
  10. Task Declaration
  11. Include Declaration
  12. Spacing

Practices

Playbook을 작성할 때 모범 사례를 따르는 것이 좋다.
Best Practices

Why?

Ansible 개발자는 Playbook의 작동 방식과 특정 파일의 위치를 잘 알고 있기 때문에, 많은 문제를 피할 수 있다.

Why Doesn't Your Style Follow Theirs?

이 가이드의 목적은 Ansible Playbook 전체에서 사용할 수 있는 일관된 스타일을 정의하고 강력하고 읽기 쉬운 코드를 작성하는 것이다.

Start of Files

목적이 무엇인지 설명하고 필요한 경우 주석으로 표시하고, 그 뒤에 빈줄, ---을 표시 한다

#bad
- name: 'Change s1m0n3's status'
  service:
    enabled: true
    name: 's1m0ne'
    state: '{{ state }}'
  become: true

#good
# Example usage: ansible-playbook -e state=started playbook.yml
# This playbook changes the state of s1m0n3 the robot

---

- name: 'Change s1m0n3's status'
  service:
    enabled: true
    name: 's1m0ne'
    state: '{{ state }}'
  become: true

Why?

파일을 열거나 head 명령을 사용하여 스크립트의 목적과 사용법을 보다 쉽게 찾을 수 있다

End of Files

마지막 라인은 항상 줄바꿈으로 파일을 끝내야 한다

Why?

일반적은 Unix 모범 사례이며, 터미널에서 파일을 인쇄 할 때 프롬프트가 잘못 정렬되는 것을 방지한다

Quotes

문자열에서는 큰 따옴표보다 작은 따옴표를 선호한다. 큰 따옴표는 작은 따옴표 안에 중첩되거나 (Ex> Jinja 맵 참조), 문자열에 이스케이프 문자가 필요한 경우 (Ex> 줄 바꾸기를 나타내는 "\n" 사용). 긴 문자열을 작성해야하는 경우 "folded, scalar" 스타일을 사용하면 모든 따옴표를 생략한다. 쿼터를 사용하면 안되는 경우는 부울논리 (Ex> true/false), 숫자 (Ex> 42), 그리고 Ansible 환경을 참조 하는 것 (Ex> 부울 논리 또는 값을 할당 할 변수의 이름)

# bad
- name: start robot named S1m0ne
  service:
    name: s1m0ne
    state: started
    enabled: true
  become: true

# good
- name: 'start robot named S1m0ne'
  service:
    name: 's1m0ne'
    state: 'started'
    enabled: true
  become: true

# double quotes w/ nested single quotes
- name: 'start all robots'
  service:
    name: '{{ item["robot_name"] }}''
    state: 'started'
    enabled: true
  with_items: '{{ robots }}'
  become: true

# double quotes to escape characters
- name 'print some text on two lines'
  debug:
    msg: "This text is on\ntwo lines"

# folded scalar style
- name: 'robot infos'
  debug:
    msg: >
      Robot {{ item['robot_name'] }} is {{ item['status'] }} and in {{ item['az'] }}
      availability zone with a {{ item['curiosity_quotient'] }} curiosity quotient.
  with_items: robots

# folded scalar when the string has nested quotes already
- name: 'print some text'
  debug:
    msg: >
      “I haven’t the slightest idea,” said the Hatter.

# don't quote booleans/numbers
- name: 'download google homepage'
  get_url:
    dest: '/tmp'
    timeout: 60
    url: 'https://google.com'
    validate_certs: true

# variables example 1
- name: 'set a variable'
  set_fact:
    my_var: 'test'

# variables example 2
- name: 'print my_var'
  debug:
    var: my_var
  when: ansible_os_family == 'Darwin'

# variables example 3
- name: 'set another variable'
  set_fact:
    my_second_var: '{{ my_var }}'

Why?

문자열이 YAML의 기본 유형이지만 명시적으로 유형을 설정하면 구문 강조가 더 좋아 보인다. 또한 원하는 문자열을 올바르게 이스케이프해야 할 때 잘못된 문자열 문제를 해결하는데 도움이 된다.

Environment

환경 변수가 있는 서버를 프로비저닝 할 때 lininfile이 있는 /etc/evnironment에 추가해라. 설치중인 서비스 또는 어플리케이션과 관련된 허용이 가능한 역할에서 이 작업을 수행해라. 예를 들어 Tomcat 설치의 경우 CATALINA_HOME 환경 변수는 Tomcat 및 관련 웹앱을 포함하는 폴더를 참조하는 데 자주 사용된다.

- name: 'add line CATALINA_HOME to /etc/environment'
  lineinfile:
    dest: '/etc/environment'
    line: 'CATALINA_HOME={{ tomcat_home }}'
    state: 'present'
  sudo: true

Why?

환경 정의 파일은 일반적으로 공유되므로 템플릿을 사용하여 파일을 보내면 문제가 발생할 수 있다. lininfile에 포함 된 특정 환경 변수를 사용하면 환경 변수에 종속 된 어플리케이션을 쉽게 추적할 수 있다.

Booleans

# bad
- name: 'start sensu-client'
  service:
    name: 'sensu-client'
    state: 'restarted'
    enabled: 1
  become: 'yes'

# good
- name: 'start sensu-client'
  service:
    name: 'sensu-client'
    state: 'restarted'
    enabled: true
  become: true

Why?

부울 값을 표현하는 방식은 True/False, true/falswe, yes/no, 1/0 등이 있다. 다양한 표현 방식 중에서 하나를 고수하는 것을 선호 한다. 이것의 주된 이유는 Java와 JavaScript가 부울값에 대해 비슷한 명칭을 가지고 있기 때문이다.

Key value pairs

key: value를 정의할 때는 하나의 공백만 사용해라

# bad
- name : 'start sensu-client'
  service:
    name    : 'sensu-client'
    state   : 'restarted'
    enabled : true
  become : true


# good
- name: 'start sensu-client'
  service:
    name: 'sensu-client'
    state: 'restarted'
    enabled: true
  become: true

YAML은 인간 친화적인 데이터 직렬화 형식이므로 가독성을 높여주므로, key: value 는 수에 관계없이 항상 개행을 하자.

# bad
- name: 'create checks directory to make it easier to look at checks vs handlers'
  file: 'path=/etc/sensu/conf.d/checks state=directory mode=0755 owner=sensu group=sensu'
  become: true

- name: 'copy check-memory.json to /etc/sensu/conf.d'
  copy: 'dest=/etc/sensu/conf.d/checks/ src=checks/check-memory.json'
  become: true

# good
- name: 'create checks directory to make it easier to look at checks vs handlers'
  file:
    group: 'sensu'
    mode: '0755'
    owner: 'sensu'
    path: '/etc/sensu/conf.d/checks'
    state: 'directory'
  become: true

- name: 'copy check-memory.json to /etc/sensu/conf.d'
  copy:
    dest: '/etc/sensu/conf.d/checks/'
    src: 'checks/check-memory.json'
  become: true

Why?

읽는 것이 쉽고, 버전 관리를 위한 변경 충돌을 줄일 수 있다

Sudo

작업을 sudo권한으로 실행해야 할때, become 구문을 사용하자

#bad
- name: 'template client.json to /etc/sensu/conf.d/'
  template:
    dest: '/etc/sensu/conf.d/client.json'
    src: 'client.json.j2'
  sudo: true

# good
- name: 'template client.json to /etc/sensu/conf.d/'
  template:
    dest: '/etc/sensu/conf.d/client.json'
    src: 'client.json.j2'
  become: true

Why?

sudo 사용은 더 이상 사용되지 않는다. Ansible version 1.9.1

Hosts Declaration

host 섹션은 다음과 같은 일반적인 순서를 따라야 한다

# host declaration
# host options in alphabetical order
# pre_tasks
# roles
# tasks

# example
- hosts: 'webservers'
  remote_user: 'centos'
  vars:
    tomcat_state: 'started'
  pre_tasks:
    - name: 'set the timezone to America/Boise'
      lineinfile:
        dest: '/etc/environment'
        line: 'TZ=America/Boise'
        state: 'present'
      become: true
  roles:
    - { role: 'tomcat', tags: 'tomcat' }
  tasks:
    - name: 'start the tomcat service'
      service:
        name: 'tomcat'
        state: '{{ tomcat_state }}'

Why?

이러한 방법에 대한 적절한 정의는 일관되고 쉽게 읽을 수 있는 코드를 생성한다

Task Declaration

작업은 다음과 같은 일반적인 순서를 따르는 방식으로 정의한다

# task name
# tags
# task map declaration (e.g. service:)
# task parameters in alphabetical order (remember to always use multi-line map syntax)
# loop operators (e.g. with_items)
# task options in alphabetical order (e.g. become, ignore_errors, register)

# example
- name: 'create some ec2 instances'
  tags: 'ec2'
  ec2:
    assign_public_ip: true
    image: 'ami-c7d092f7'
    instance_tags:
      Name: '{{ item }}'
    key_name: 'my_key'
  with_items: '{{ instance_names }}'
  ignore_errors: true
  register: ec2_output
  when: ansible_os_family == 'Darwin'

Why?

호스트 정의와 유사하게 여기에 잘 정의 된 스타일이 있으면 일관된 코드를 만드는 데 도움이 된다.

Include Declaration

include 문의 경우 파일 이름을 사용하고, include 문의 사이에는 빈줄만 사용해야 한다.(Tag가 있는 경우)

# bad
- include: other_file.yml

- include: 'second_file.yml'

- include: third_file.yml tags=third

# good

- include: 'other_file.yml'
- include: 'second_file.yml'

- include: 'third_file.yml'
  tags: 'third'

Why?

이것은 당신의 코드에 문장을 포함시키는 가장 읽기 쉬운 방법이다.

Spacing

두 개의 호스트 블록 사이에 빈 줄이 있어야 한다. 들여쓰기 할 때 2개의 공백을 사용하여 하위 항목을 나타내고 여러 줄은 `-` 로 시작해야 한다. 간격의 대한 예제는 링크를 참조 하자 style.yml

Why?

읽기 쉬운 멋진 코드를 생성한다

Variable Names

playpool에서 snake_case 변수 이름을 사용하자

# bad
- name: 'set some facts'
  set_fact:
    myBoolean: true
    myint: 20
    MY_STRING: 'test'

# good
- name: 'set some facts'
  set_fact:
    my_boolean: true
    my_int: 20
    my_string: 'test'

Why?

Ansible은 모듈 이름으로 snake_case를 사용하므로 규칙을 변수 이름으로 확장하는 것이 좋습니다.

snake_case 는 각 요소의 초기 문자가 일반적으로 소문자로 표시되고 첫 번째 문자가 대문자 또는 소문자로 "foo_bar"와 같이 공백이없는 하나의 밑줄 문자로 요소가 분리되는 복합 단어 또는 구문을 작성하는 방법

출처: https://github.com/sepiros62/ansible-styleguide