본문 바로가기
IT study/Linux

04. ansible 실습

by 핸조 2022. 12. 10.
yaml syntax

기본자료형

scalar : 스트링 또는 숫자
sequence : 배열 또는 리스트
mapping : 해시 또는 딕셔너리, 키/value 형태


---
# A list of tasty fruits
- Apple
- Orange
- Strawberry
- Mango
...

# An employee record
martin:
    name: Martin D'vloper
    job: Developer
    skill: Elite

# Employee records
-  martin:
    name: Martin D'vloper
    job: Developer
    skills:
      - python
      - perl
      - pascal
-  tabitha:
    name: Tabitha Bitumen
    job: Developer
    skills:
      - lisp
      - fortran
      - erlang


---
martin: {name: Martin D'vloper, job: Developer, skill: Elite}
['Apple', 'Orange', 'Strawberry', 'Mango']


include_newlines: |
            exactly as you see
            will appear these three
            lines of poetry

fold_newlines: >
            this is really a
            single line of text
            despite appearances

---
# An employee record

name: Martin D'vloper
job: Developer
skill: Elite
employed: True
foods:
    - Apple
    - Orange
    - Strawberry
    - Mango
languages:
    perl: Elite
    python: Elite
    pascal: Lame
education: |
    4 GCSEs
    3 A-Levels
    BSc in the Internet of Things

yaml 변수

변수이름 규칙은 대체로 다른언어와 비슷하다.
변수이름은 문자로 시작해야 하고 특수문자는 '_' 만 사용가능하다.
ok
--------
foobar
foo_bar
foo_bar2

not ok
--------
foo bar
foo-bar
1st_foobar
foo.bar

변수정의
inventory 내에서 변수정의
playbook 에서 변수 정의
vars 블록에서 정의
var_files 로 외부파일에서 정의

- hosts: all
  vars:
    service: httpd
    service_port: 80

- hosts: all
  vars_files:
    - vars/service.yml

users.yml
----------------
service: httpd
service_port: 80

playbook 에서 변수사용
변수를 이중괄호로 묶어서 사용한다.
{{service}}
{{service_port}}

example)
vars:
  service: httpd

tasks:
  - name: install {{httpd}} packages
    yum:
      name: "{{httpd}}"
      state: present

* key 에 대한 value 가 변수로 시작하는 경우에는 value 와 변수를
구분하기 위하여 반드시 변수가 포함된 이중괄호를 큰따옴표를 붙여야 한다.

----------------------------------------
host 변수 및 그룹 변수
[web_servers]
server2.example.com  service=httpd

[db_servers]
server3.example.com
server4.example.com

[db_servers:vars]
service=mariadb
----------------------------------------
inventory 파일에 변수를 등록하면 inventory 가
복잡해지고 관리하기 좋지 않다.
그래서 group_vars 및 host_vars 디렉토리를 사용하는것이
권장된다.

~/sample/group_vars/test
service: httpd
~/sample/group_vars/test2
service: vsftpd

~/sample/host_vars/test
service: httpd
~/sample/host_vars/tets2
service: vsftpd
~/sample/host_vars/test3
service: mariadb
---------------------------------------
command line 에서 변수정의

ansible-playbook server2.example.com test.yml -e "service=httpd"

배열변수

user1_uid: 1000
homedir: /home/user1
user2_uid: 1001
homedir: /home/user2
user3_uid: 1002
homedir: /var/user3
...
==> 이 많은 변수들을 아래처럼 
배열로 바꿔서 사용할 수 있다.
python 에서는 아래처럼 정의할수 있다.
users = { 'user1':{'uid':1000,'homedir':'/home/user1'},user2:{'uid':10001,'homedir':'/home/user2'},..}
users.get('user2') ; key 대한 value 출력

users:
  user1:
    uid: 1000
    homedir: /home/user1
  user2:
    uid: 1001
    homedir: /home/user2
  .....

변수사용
users.user1.uid ==> 1000
또는 users['user1']['uid']

users.user2.homedir ==> /home/user2
또는 users['user2']['homedir']

register
- task 의 실행결과를 변수에 저장 (주로 디버깅을 위한 목적으로 사용)




example)
---
- name : test
  hosts: all
  tasks:
    - name: install package
      yum:
        name: tftp-server
        state: installed
      register: install_result
    - debug: var=install_result   
   
-----------------------------------
* debug 모듈
디버깅을 하기 위한 목적으로 사용하며 메시지나 변수값을 출력해준다

매직변수
- ansible 에 의해 자동으로 설정되는 변수
hostvars
- 관리대상 호스트의 변수를 얻을때 사용
group_names 
- 현재 호스타 속한 그룹리스트
groups
- inventory 내의 전체 그룹 및 모든호스트
inventory_hostname
- inventory 에 실제기록되어 있는 호스트 이름

팩트변수 
- ansible 이 managed node(host) 에서 자동으로 검색한 변수
팩트에는 다음과 같증 정보가 포함되어 있다.

호스트이름
커널버전
환경변수
CPU 정보
메모리정보
디스크정보
네트워크정보
운영체제버전
IP 주소

팩트는 managed node 의 상태를 파악하고 해당 상태에 따라서 여러가지
조치를 하기위한 방법

adhoc 명령어로 팩트수집
ansible hostname -m setup

특정 팩트변수만 수집하려면
{{ ansible_facts['devices']['xvda']['model'] }}
{{ansible_factc['nodename']}}

이런식으로 사용가능하다.

* 플레이북이 실행될때 팩트를 수집하지 않을려면
- hosts: all
  gather_facct: no




제어구문
when 
- 조건부 작업실행: 조건을 만족할때만 실행

- hosts: all
  vars:
    install_pkg: true

  tasks:
    - name: telnet-servie is installed
      yum:
        name: httpd
	state: present
      when: install_pkg
----------------------------------------
- hosts: all
  vars:
    pkg_name: httpd
  
  tasks:
    - name: "{{pkg_name}}} is installed
      yum:
        name: "{{pkg_name}}
      when: pkg_name is defined

조건문 연산자
== : 같다
!= : 같지않다
< : 작다
> : 크다
<= : 작거나 같다
>= : 크거나 같다
is defined : 정의 되어 있다
is not defined : 정의 안되어 있다
my_var1 in list_vars : 첫번째 변수의 값이 두번째 변수의 목록에 있다.

- hosts: all
  vars:
    manager_user: devops2
    system_manager:
      - root
      - manager
      - devops
      - admin
      - devops2

  tasks:
    - name: test
      user:
        name: "{{manager_user}}"
        groups: wheel
        append: yes
      when: manager_user in system_manager

 
------------------------------------------

- hosts: all
  tasks:
    - name: mariadb status
      command: /usr/bin/systemctl is-active mariadb
      ignore_errors: yes
      register: result

   - name: restart apache if mariadb running
     service:
       name: httpd
       state: restarted
     when: result.rc == 0  

-----------------------------------------

tasks:
  - command: /bin/false
    register: result
    ignore_errors: True

  - command: /bin/something
    when: result is failed

  # In older versions of ansible use ``success``, now both are valid but succeeded uses the correct tense.
  - command: /bin/something_else
    when: result is succeeded

  - command: /bin/still/something_else
    when: result is skipped

------------------------------------

tasks:
    - command: echo {{ item }}
      loop: [ 0, 2, 4, 6, 8, 10 ]
      when: item > 5

-----------------------------------
ssevera에 2이상이고 8이하 인 숫자를 저장하라
/tmp/item.txt에 저장

with_list = loop 동일

become:no //become은 루트 no로하면 권한상승 사용X


tasks:
    - name: gather site specific fact data
      action: site_facts
    - command: /usr/bin/thingy
      when: my_custom_fact_just_retrieved_from_the_remote_system == '1234'

------------------------------------
- hosts: all
  remote_user: root
  vars_files:
    - "vars/common.yml"
    - [ "vars/{{ ansible_facts['os_family'] }}.yml", "vars/os_defaults.yml" ]
  tasks:
  - name: make sure apache is started
    service: name={{ apache }} state=started
-----------------------------------------------

- name: test play
  hosts: all

  tasks:

      - shell: cat /etc/motd
        register: motd_contents

      - shell: echo "motd contains the word hi"
        when: motd_contents.stdout.find('hi') != -1
-------------------------------------------------------

- name: check registered variable for emptiness
  hosts: all

  tasks:

      - name: list contents of directory
        command: ls mydir
        register: contents

      - name: check contents for emptiness
        debug:
          msg: "Directory is empty"
        when: contents.stdout == ""
---------------------------------------------------------

loops

loop는 with_list 와 같다.

- name: add several users
  user:
    name: "{{ item }}"
    state: present
    groups: "wheel"
  loop:
     - testuser1
     - testuser2


- name: nested loop test
  user:
    name: "{{item.name}}"
    state: present
    groups: "{{item.groups}}"
  with_items:
    - { name: 'user1', groups: 'user1'}
    - { name: 'admin', groups: 'wheel'}


nested loop

  mysql_user
    name: "{{ item[0] }}"
    priv: "{{ item[1] }}".*:ALL
    append_privs: yes
    password: redhat
    ((state: present))--> 넣으면 계정생성 됨
  with_netsted //이중반복문
   - [ 'dbuser1', 'dbuser2' ]
   - [ 'testdb','mydb','sampledb']

--------------------------------
cursorcloumn
cursorline
ansible-doc mysql_user //mysql 모듈을 찾는다

핸들러
- notify 문을 사용하여 명시적으로 호출된 경우에만 실행된다
- 핸들러는 특정작업의 notify문에 나열된 순서가 아니라 핸들러 섹션이
플레이에서 작성된 순서로 항상 실행된다.
- 핸들러는 task 의 모든 작업이 완료된 후에 실행된다.
- notify는 changed 가 있는 경우에만 핸들러에게 알린다.

handler 예제 소스
-------------------------
- name: handler test
  hosts: servera.example.com
  tasks:
    - name: installed package
      yum:
        name: ksh
        state: latest
      notify:
        - display messages2
        - display messages
    - name:
      debug:
        msg: after notify
  handlers:
    - name: display messages
      debug:
        msg: started handler first
    - name: display messages2
      debug:
        msg: statred hadler second
-------------------------------------
---
- hosts: webservers
  vars:
    http_port: 80
    max_clients: 200
  remote_user: devops
  - name: ensure apache is at the latest version
    yum: 
      name: httpd
      state: latest
  - name: write the apache config file
    copy:
      src: /var/lib/httpd.conf.template
      dest: /etc/httpd/httpd.conf
    notify:
    - restart apache
    - restart mysql
  - name: ensure apache is running (and enable it at boot)
    service:
      name: httpd
      state: started
      enabled: yes
  handlers:
    - name: restart mariadb
      service: 
        name: mariadb
        state: restarted
    - name: restart httpd
      service:
        name: httpd
        state: restarted

-------------------------------------------------------------

태그구현
- 태그가 지정된 플레이만 실행하거나 또는 반대로 태그가 지정된 플레이만 
제외할수만 있다.
특정장비에만 필요한 플레이가 있거나 또는 그 반대인 경우 태그를 유용하게
사용할 수 있다.

ansible-playbook -l servera.example.com i.yaml --tags test //hosts가 all 인데 -l 쓰고 지정해주면 거기만 감 --tags test는 yaml파일에 태그 달린 부분만

ansible-playbook i.yaml --skip-tags test //태그 걸린 부분만 안나오게 

$ ansible-playbook yaml파일명 --tags tag이름 ; tag 가 설정된 작업만 실행
$ ansible-playbook yaml 파일명 --skip-tags tag이름 ; tag 가 설정된 작업을
제외하고 나머지 전부 실행


tasks:
  - name: vsftpd is installed
      yum: 
        name: vsftpd
        state: installed

  - name: httpd is installed
    yum:
      name: httpd
      state: latest
    tags: apache

  - name: mariadb is installed
    yum:
      name: mariadb
      state: present
 

오류처리

플레이북 실행시 위에서 아래로 순차적으로 실행이 되는데
실행중 특정 작업이 실패하게 되면 그 아래의 플레이는 더 이상
실행되지 않고 중단된다.
실패한 작업은 무시하고 그 아래의 플레이를 계속 실행하게 하려면
ignore_errors 키워드를 사용하면 된다.

플레이가 실패하게 되면 플레이가 실패하기전에 
알림을 받은(notify) 핸들러도 실행되지 않는데
force_handlers 키워드를 사용하면 플레이가
중단되더라도 핸들러는 실행된다.

아래의 소스파일로 ignore_errors / force_handlers test
- hosts: myserver2.example.com
    tasks:
    - name: test
      command: /usr/bin/cal
      notify: new debug messages
    - name: pkg installed
      yum:
          name: no_exist_package
          state: present
      - name: debug messages
      debug:
        msg: test debug messages....

  handlers:
    - name: new debug messages
      debug:
        msg: handlers messages......


------------------------------

역할구현

- 역할은 컨텐츠를 그룹화하여 다른 사용자와 쉽게 공유할수 있다
- 프로젝트가 크면 역할을 사용하면 관리하기 쉽다
- 역할은 협업작업이 가능하다

역할의 디렉토리 구조
project
├── README.md
├── defaults
│?? └── main.yml
├── files
├── handlers
│?? └── main.yml
├── meta
│?? └── main.yml
├── tasks
│?? └── main.yml
├── templates
├── tests
│?? ├── inventory
│?? └── test.yml
└── vars
    └── main.yml

defaults: 역할변수의 기본값이 설정되어 있는 디렉토리
files: 역할작업에서 참조하는 정적파일이 있는 디렉토리
handlers: 역할의 핸들러가 정의 되어 있는 디렉토리
meta: 작성자,라이센스,플랫폼 등의 역할종속성을 포함한 역할에 대한 정보가 저장되어 있는 디렉토리
templates: jinja2 템플릿이 있는 디렉토리
tests: 역할을 테스트할대 사용하는 인벤토리가 있는 디렉토리
vars: main.yml 파일에 역할변수의 값을 정의하는 디렉토리

'IT study > Linux' 카테고리의 다른 글

05. ansible addhook  (0) 2022.12.10
05. ansible vault  (0) 2022.12.10
03.yaml syntax 설정  (0) 2022.12.10
02. yaml 파일 설정  (0) 2022.12.10
01. ansible 및 yaml 실습  (0) 2022.12.10