DevOps/Ansible

Ansible study 2주차

Rainbound-IT 2024. 1. 15. 11:09
반응형

목차

     

     

     

    반복문

    task 내부에 item이라는 변수를 입력하고

    loop라는 키워드 내부에 반복할 구문을 넣는 방식

    item과 loop가 반드시 짝지어져야한다.

    loop 내에 vars라는 변수를 사용해도 된다.

    ---
    - hosts: all
      tasks:
        - name: Check sshd state and rsylog state
          ansible.builtin.service:
            name: "{{ item }}"
            state: started
    
          loop:
            - sshd
            - rsyslog

    task에 item이 뜬다.

     

    사전 목록에 의한 반복문

    여러개의 아이템 사용할때 사용하는 반복문

    ---
    - hosts: all
    
      tasks:
        - name: Create files
          ansible.builtin.file:
            path: "{{ item['log-path'] }}"
            mode: "{{ item['log-mode'] }}"
            state: touch
          loop:
            - log-path: /var/log/test1.log
              log-mode: '0644'
            - log-path: /var/log/test2.log
              log-mode: '0600'

    한 item에 여러가지를 넣을수 있다.

     

    반복문에서 Register 변수 사용

    반복 실행되는 작업의 출력을 캡처할때 Register변수를 사용한다.

    ---
    - hosts: localhost
      tasks:
        - name: Loop echo test
          ansible.builtin.shell: "echo 'I can speak {{ item }}'"
          loop:
            - Korean
            - English
          register: result
    
        - name: Show result
          ansible.builtin.debug:
            var: result

     

     

     

    조건문

    특정 조건을 만족할때 작업 또는 플레이가 실행되도록 하는것

    조건문에는 플레이변수, 작업변수, 앤서블 팩트등을 사용할수 있다.

    사용법은 when 을 사용하여 true인지 false인지 판단하여 실행한다.

    해당 조건에 다음과 같이 사용 할 수 있다.

    • != : 값이 같지 않을 때 true
    • >, >=, <=, < : ‘초과, ‘ 이상’, ‘이하’, ‘미만’ 일 때에 true
    • not : 조건의 부정
    • and, or : ‘그리고’, ‘또는’의 의미로 여러 조건의 조합 가능
    • in : 값이 포함된 경우에 true. 예를 들어 2 in “1, 2, 3” 은 true
    • is defined : 변수가 정의된 경우 true

    변수(vars)를 할당하여 여러 변수를 활용하여 조건(and, or..)을 넣을수도 있다.

     

     

    ---
    - hosts: localhost
      vars:
        run_my_task: true
    
      tasks:
      - name: echo message
        ansible.builtin.shell: "echo test"
        when: run_my_task
        register: result
    
      - name: Show result
        ansible.builtin.debug:
          var: result

     

    ---
    
    - hosts: all
      vars:
        supported_distros:
          - Ubuntu
          - CentOS
    
      tasks:
        - name: Print supported os
          ansible.builtin.debug:
            msg: "This {{ ansible_facts['distribution'] }} need to use dnf"
          when: ansible_facts['distribution'] in supported_distro

     

     

     

    핸들러 및 작업 실패 처리

     핸들러는 다른 작업에서 트리거한 알림에 응답하는 작업이며, 해당 호스트에서 작업이 변경될 때만 핸들러에 통지

     

     

    앤서블 핸들러

    notify 문을 활용하여 handler를 생성하면 된다.

    notify에 있는 task가 성공할 경우 핸들러가 실행된다 하지만 실패하면 실행이 되지 않는다.(일반적인 태스크도 마찬가지)

    태스크가 실패할경우 ignore_errors:문을 추가하면 되고 핸들러가 실패하면 force_handlers 문을 넣으면된다.

     

    ---
    
    - hosts: els
    
      tasks:
        - name: restart rsyslog
          ansible.builtin.service:
            name: "rsyslog"
            state: restarted
          notify:
            - print msg
      handlers:
        - name: print msg
          ansible.builtin.debug:
            msg: "rsyslog is restarted"

     

     

    작업실패 조정

    앤서블에서 셸스크립트를 정상적으로 실행 시키기만 하면 success 가 떨어진다.

    하지만 쉘스크립트가 실행된후 오류가 발생해도 앤서블에선 success로 떨어지게 된다.

    이러한 이유로 앤서블에서 쉘스크립트를 권장하진 않는다.

    이것을 방지하기 위하여 failed_when을 사용하긴하는데 일일이 결과 로그를 입력할수 없고 다른 에러가 발생할경우 피해갈 수 있을 것이다.

     

    ---
    
    - hosts: ansible
      tasks:
        - name: Run user add script
          ansible.builtin.shell: /home/ubuntu/test/adduser-script.sh
          register: command_result
          failed_when: "'Please input user id and password' in command_result.stdout"
    
        - name:
          ansible.builtin.debug:
            msg: "This task is next task"

     

     

    앤서블 블록 및 오류처리

    오류를 제어하는 문법으로, 블록은 잡업을 논리적으로 그룹화 하여 작업 실행 방법을 제어하는데 사용할 수 있다.

     

    • block : 실행할 기본 작업을 정의함
    • rescure : block 절에 정의된 작업이 실패할 경우 실행할 작업을 정의함
    • always : block 및 rescue 절에 정의된 작업의 성공 또는 실패 여부와 관계 없이 항상 실행되는 작업을 정의함
    ---
    - hosts: ansible
      vars:
        logdir: /var/log/daily_log
        logfile: todays.log
    
      tasks:
        - name: Configure Log Env
          block:
            - name: Find Directory
              ansible.builtin.find:
                paths: "{{ logdir }}"
              register: result
              failed_when: "No such file or directory"
    
          rescue:
            - name: Make Directory when Not found Directory
              ansible.builtin.file:
                path: "{{ logdir }}"
                state: directory
                mode: '0755'
    
          always:
            - name: Create File
              ansible.builtin.file:
                path: "{{ logdir }}/{{ logfile }}"
                state: touch
                mode: '0644'

     

    오류 메시지는 다를수 있으므로 만약 디렉토리가 찾아진다면 실 서버에 접속하여 출력을 복붙 하는걸 추천한다.

     

     

    만약 실패하면 디렉토리및 파일을 생성한것을 볼수 있다.

     

    다시 실행하면 다시 create 파일을 한다.

     

     

    롤과 콘텐츠 콜렉션

    내가 만든 플레이북을 다른 사람들과 공유 하거나 다른 사람들이 만든 플레이북을 활용할 수 있는 기능을 구현하는 앤서블 롤, 공유할 수 있는 앤서블 갤럭시 등을 알아보자

     

     

    앤서블 롤 구조

    앤서블 롤을 생성하면 디렉토리가 생성되는데 각 역할은 다음과 같다.

    하위 디렉터리 기능
    defaults 이 디렉터리의 main.yml 파일에는 롤이 사용될 때 덮어쓸 수 있는 롤 변수의 기본값이 포함되어 있습니다. 이러한 변수는 우선순위가 낮으며 플레이에서 변경할 수 있습니다.
    files 이 디렉터리에는 롤 작업에서 참조한 정적 파일이 있습니다.
    handlers 이 디렉터리의 main.yml 파일에는 롤의 핸들러 정의가 포함되어 있습니다.
    meta 이 디렉터리의 main.yml 파일에는 작성자, 라이센스, 플랫폼 및 옵션, 롤 종속성을 포함한 롤에 대한 정보가 들어 있습니다.
    tasks 이 디렉터리의 main.yml 파일에는 롤의 작업 정의가 포함되어 있습니다.
    templates 이 디렉터리에는 롤 작업에서 참조할 Jinja2 템플릿이 있습니다.
    tests 이 디렉터리에는 롤을 테스트하는 데 사용할 수 있는 인벤토리와 test.yml 플레이북이 포함될 수 있습니다.
    vars 이 디렉터리의 main.yml 파일은 롤의 변수 값을 정의합니다. 종종 이러한 변수는 롤 내에서 내부 목적으로 사용됩니다. 또한 우선순위가 높으며, 플레이북에서 사용될 때 변경되지 않습니다

     

     

    앤서블 롤 생성 명령어

    ansible-galaxy role init my-role

     

    이런식으로 폴더 및 파일이 생긴다.

     

     

    롤을 이용한 플레이북 개발

     

    다음과 같은 과정으로 롤을 만들 것이다.

     

    • 프로세스 → 각 구조에 맞게 태스크를 작성 하자
      • 롤이 호출되면 현재 호스트의 운영체제 버전이 지원 운영체제 목록에 포함되는지 확인한다.
      • 운영체제가 CentOS나 레드햇이면 httpd 관련 패키지를 dnf 모듈을 이용해 설치한다.
      • 설치가 끝나면 제어 노드의 files 디렉터리 안에 있는 index.html 파일을 관리 노드의 /var/www/html 디렉터리에 복사한다.
      • 파일 복사가 끝나면 httpd 서비스를 재시작한다.
    • 롤 구조
      • 롤 이름 : my-role
      • tasks (메인 태스크)
        • install service : httpd 관련 패키지 설치
        • copy html file : index.html 파일 복사
      • files (정적 파일)
        • index.html
      • handlers (핸들러)
        • restart service : httpd 서비스 재시작
      • defaults (가변 변수) : 메인 태스크에서 사용된 변수 선언
        • service_title
      • vars (불변 변수) : 메인 태스크와 핸들러에서 사용된 변수 선언
        • service_name : 서비스명
        • src_file_path : 복사할 파일 경로
        • dest_file_path : 파일이 복사될 디렉터리 경로
        • httpd_packages : httpd 관련 패키지 목록
        • supported_distros : 지원 OS 목록

     

    main task 작성

    my-role/tasks/main.yml에서 작업한다.

    loop문을 활용하여 httpd 관련 패키지및 설치를 하고 copy를 통해 파일을 복사하고 restart service라는 핸들러를  호출한다.

    ---
    # tasks file for my-role
    
    - name: install service {{ service_title }}
      ansible.builtin.apt:
        name: "{{ item }}"
        state: latest
      loop: "{{ httpd_packages }}"
      when: ansible_facts.distribution in supported_distros
    
    - name: copy conf file
      ansible.builtin.copy:
        src: "{{ src_file_path }}"
        dest: "{{ dest_file_path }}"
      notify: 
        - restart service

     

    index.hml 파일 작성

    files/index.html 파일을 작성하여 메인페이지에 보여줄 html을 간단하게 하자

     

     

    핸들러 작성

    handlers/main.yml

    서비스 재시작으로 작성

    ---
    # handlers file for my-role
    
    - name: restart service
      ansible.builtin.service:
        name: "{{ service_name }}"
        state: restarted

     

     

    defaults 작성

    defaults/main.yml

    ---
    # defaults file for my-role
    
    service_title: "Apache Web Server"

     

     

    vars 작성

    vars/main.yml 에 불변 변수 정의

    한번 정의 되면 외부에서 수정할수 없다.

    ---
    # vars file for my-role
    
    service_name: apache2
    src_file_path: ../files/index.html
    dest_file_path: /var/www/html
    httpd_packages:
      - apache2
      - apache2-doc
    
    supported_distros:
      - Ubuntu

     

     

    플레이북에 롤 추가

    롤을 생성하고 구조에 맞게 작성하였으나 ansible-playbook명령어로 실행은 할수 없다.

    role을 실행하기 위해서는 롤을 호출해주는 플레이북이 필요하다.

     

    • ansible.builtin.import_role: 롤을 정적으로 추가

    https://docs.ansible.com/ansible/latest/collections/ansible/builtin/import_role_module.html

     

     

    • ansible.builtin.include_role: 롤을 동적으로 추가

    https://docs.ansible.com/ansible/latest/collections/ansible/builtin/include_role_module.html

     

     

    롤 생성한 폴더 밖에서 작업을 진행한다.

    role-example.yml 을 다음과 같이 작성한다.

    ---
    - hosts: ansible
    
      tasks:
        - name: Print start play
          ansible.builtin.debug:
            msg: "Let's start role play"
    
        - name: Install Service by role
          ansible.builtin.import_role:
            name: my-role

     

    그리고 실행

    ansible-playbook 으로 실행하면 된다.

     

     

    해당 서버에 보면 실행이 되어 있다.

     

     

    플레이북에서 Role 섹션 사용하기

    my-role에서 생성한 apache의 포트는 8080 으로 80포트는 열려 있지 않다.

    방화벽에 80포트를 여는

    ansible-galaxy role init my-role2로 새로운 롤 생성하여 테스트 해보자

     

     

    task 작성

    my-role2/tasks/main.yml

    ---
    # tasks file for my-role2
    
    - name: Config firewalld
      ansible.posix.firewalld:
        service: "{{ item }}"
        permanent: true
        state: enabled
      loop: "{{ service_port }}"
    
    - name: Reload firewalld
      ansible.builtin.service:
        name: firewalld
        state: reloaded

     

     

    vars 작성

    my-role2/vars/main.yml

    ---
    # defaults file for my-role2
    
    service_port: 
      - http
      - https

     

     

    플레이북 작성

    role-example2.yml

    ---
    
    - hosts: ansible
    
      roles:
        - my-role
        - my-role2
    
      tasks:
        - name: Print finish role play
          ansible.builtin.debug:
            msg: "Finish role play"

     

     

    실행

     

     

    확인해보면 http와 https 서비스가 허용되어 있는것을 확인할수 있다.

     

     

    특수 작업 세션

    태스크를 이전에 실행할지 아니면 이후에 실행할지 설정하는 방식

    • pre_tasks 섹션: role 섹션보다 먼저 실행되며 이 섹션에서 핸들러에게 알리면 롤, 일반 태스크 이전에 실행이 됩니다.
    • post_tasks 섹션: 일반 태스크의 핸들러 이후에 실행되는 태스크

     

    ---
    
    - hosts: ansible
    
      pre_tasks:
        - name: Print Start role
          ansible.builtin.debug:
            msg: "Let's start role play"
     
      roles:
        - role: my-role
        - role: my-role2
     
      tasks:
        - name: Curl test
          ansible.builtin.uri:
            url: http://tnode1
            return_content: true
          register: curl_result
          notify: Print result
          changed_when: true
    
      post_tasks:
        - name: Print Finish role
          ansible.builtin.debug:
            msg: "Finish role play"
    
      handlers:
        - name: Print result
          ansible.builtin.debug:
            msg: "{{ curl_result.content }}"

     

     

    끝!

    반응형