IaC(Infrastructure as Code)

Ansible Part. 4 (Handler)

cwchoiit 2024. 3. 18. 10:41
728x90
반응형
SMALL
728x90
SMALL

Handler

핸들러는 이벤트 기반으로 동작하는 Task. 예를 들어, 지금까지는 Tasks 내부에 여러 Task를 정의하고 순차적으로 실행이 됐는데, 만약 어떤 Task가 다른 Task에 의존성이 있어야 하는 경우 그 의존성을 만족하여 실행하게 하는 게 쉽지 않다. 이를 해결하는 방법 중 하나가 Handler라고 생각하면 된다. 

 

예시를 들어보자. 만약, 내가 Nginx 서버 설정을 변경했으면 서버 설정이 변경됐으니 Nginx를 재실행해야 변경 사항이 적용되는데 서버 설정을 변경하고 Ansible이 변경을 감지했을 때 재실행하게 하고 싶을 때 Handler를 사용하면 된다.

 

실습

파일 구조가 다음과 같이 되어 있다.

여기서 default 파일이 Nginx 서버 설정 파일인데 이 파일을 보자.

default

해당 파일을 보면 index에 blue.html 파일이 가장 먼저 있다. 이러면 Nginx는 세 파일 중 blue.html을 뿌려주게 된다.

server {
	listen 80 default_server;
	listen [::]:80 default_server;

	root /var/www/html;

	index blue.html index.htm index.nginx-debian.html;

	server_name _;

	location / {
		# First attempt to serve request as file, then
		# as directory, then fall back to displaying a 404.
		try_files $uri $uri/ =404;
	}
}

 

Playbook을 실행한 후 확인해 보자.

example.yaml

Ubuntu 대상으로만 진행하는 YAML 파일이고 이 파일을 보면 하단에 "Copy nginx configuration file" Task가 있다. 이때 서버 설정 파일을 복사해서 리모트 호스트에 Nginx 설정 파일이 위치해야 하는 곳에 복사하게 된다. 

---

- name: Example
  hosts: ubuntu
  become: true
  tasks:
  # Docs: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/user_module.html
  - name: "Create a user"
    user: "name=fastcampus shell=/bin/bash"

  - name: "Hello World"
    command: "echo 'Hello World!'"

  # Docs: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/lineinfile_module.html
  - name: "Add DNS server to resolv.conf"
    lineinfile:
      path: /etc/resolv.conf
      line: 'nameserver 8.8.8.8'

  # Docs: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_module.html
  - name: "Install Nginx"
    apt:
      name: nginx
      state: present
      update_cache: true

  # Docs: https://docs.ansible.com/ansible/latest/collections/ansible/posix/synchronize_module.html
  - name: "Upload web directory"
    synchronize:
      src: files/html/
      dest: /var/www/html
      archive: true
      checksum: true
      recursive: true
      delete: true

  # Docs: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/copy_module.html
  - name: "Copy nginx configuration file"
    copy:
      src: files/default
      dest: /etc/nginx/sites-enabled/default
      owner: "{{ ansible_user }}"
      group: "{{ ansible_user }}"
      mode: '0644'

  # Docs: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/service_module.html
  - name: "Ensure nginx service started"
    service:
      name: nginx
      state: started

  handlers:
  - name: Restart Nginx
    service:
      name: nginx
      state: restarted

 

이대로 Playbook을 실행해 보자. 

ansible-playbook -i inventory example.yaml

 

그럼 Ubuntu의 Public IP로 접속해 보면 다음과 같이 파란 화면으로 보일 것이다. 합리적이다.

 

그럼 내가 이 상태로 Nginx 설정 파일을 다음과 같이 blue.html이 아닌 red.html로 바꾸고 다시 실행하면 어떻게 될까?

server {
	listen 80 default_server;
	listen [::]:80 default_server;

	root /var/www/html;

	index red.html index.htm index.nginx-debian.html;

	server_name _;

	location / {
		# First attempt to serve request as file, then
		# as directory, then fall back to displaying a 404.
		try_files $uri $uri/ =404;
	}
}

 

아무런 변화가 일어나지 않을 것이다. 왜냐하면 설정 파일이 변경되어도 Nginx가 재실행되지 않으면 변경 사항을 적용하지 않을 테니까. 그러면 이럴 때 핸들러를 사용하면 된다. 이런 변화가 있을 때 핸들러가 실행되도록 말이다. 그게 바로 YAML 파일에 이 부분이다.

  handlers:
  - name: Restart Nginx
    service:
      name: nginx
      state: restarted

 

그러나, 핸들러만 이렇게 등록한다고 핸들러가 동작하는 게 아니고 핸들러라는 이벤트를 트리거해야 한다. 그건 아래처럼 작성하면 된다.

- name: "Copy nginx configuration file"
    copy:
      src: files/default
      dest: /etc/nginx/sites-enabled/default
      owner: "{{ ansible_user }}"
      group: "{{ ansible_user }}"
      mode: '0644'
    notify:
    - Restart Nginx

 

이처럼 Nginx 설정 파일을 복사하는 Task에 notify라는 키를 추가해서 핸들러의 이름을 넣어주면, 이 Task를 작업할 때 Changed라는 상태가 나타나면 핸들러가 트리거 된다. 실행해 보자. 다음과 같이 해당 Task에서 Changed가 발생했고 그에 따라 핸들러를 트리거한다. 그럼 모든 Task가 끝나고 Handler가 실행된다.

 

이제 다시 들어가서 확인해 보자. 다음과 같이 빨간 화면이 보인다. 이게 핸들러다.

 

 

핸들러를 사용할 때 알고 있어야 하는 점

  • Playbook 내에서 같은 이벤트를 여러번 호출하더라도 동일한 핸들러는 한번만 실행된다.
  • 모든 핸들러는 Playbook 내에 모든 작업이 완료된 후에 실행된다.
  • 핸들러는 이벤트 호출 순서에 따라 실행되는 것이 아니라 핸들러 정의 순서에 따라 실행된다.

나머지는 다 말 그대로이고, 마지막 문장인 핸들러 정의 순서에 따라 실행된다는 것은 무슨말이냐면 핸들러 정의를 다음과 같이했다고 가정하자.

handlers:
  - name: Restart Nginx
    service:
      name: nginx
      state: restarted
  - name: Stop Nginx
  	service:
      name: nginx
      state: stopped

두 개의 핸들러가 이러한 순서대로 정의됐을 때, 내가 만약에 Stop Nginx를 먼저 notify로 호출하고 가장 마지막 Task에서 Restart Nginx 핸들러를 호출했다고 해도 Restart Nginx -> Stop Nginx 순으로 핸들러가 실행된다는 의미이다. 그러니까 이 부분을 주의해야한다. 

728x90
반응형
LIST

'IaC(Infrastructure as Code)' 카테고리의 다른 글

Ansible Part. 6 (Loop)  (0) 2024.03.18
Ansible Part. 5 (Variables)  (0) 2024.03.18
Ansible Part. 3 (Playbook)  (0) 2024.03.18
Ansible Part. 2 (Adhoc)  (3) 2024.03.17
Ansible Part. 1 (Inventory)  (3) 2024.03.17