패키지 및 작동하는 서비스 관리

AnsibleBeginner
지금 연습하기

소개

패키지가 설치된 것, 구성 파일이 존재하는 것, 서비스가 응답하는 것은 서로 다른 결과입니다. 각각을 명시적으로 관리합니다. 유틸리티를 설치하고 제거하며 nginx를 구성하고 실행 상태를 선언한 다음 핸들러로 변경된 구성을 다시 로드합니다. 두 관리 노드의 실제 HTTP 응답으로 서비스가 작동함을 확인합니다.

패키지 설치 및 제거 상태 선언하기

이 단계에서는 작은 유틸리티를 설치하고 점검한 다음 재사용 가능한 패키지 선언으로 제거합니다.

apt 모듈은 관리 호스트의 Ubuntu 패키지를 관리합니다. state: present는 설치를, state: absent는 제거를 요청합니다. 이 환경에는 준비된 패키지 목록과 캐시된 다운로드가 있으므로 update_cache: false를 유지하세요. 목록을 새로 고치거나 최신 버전을 요청하면 불필요한 네트워크 의존성이 생깁니다. 운영 환경의 업데이트 정책은 다를 수 있습니다.

컨트롤러 프로젝트로 이동합니다.

cd /home/labex/project

변수로 원하는 tree 패키지 상태를 선택하는 플레이북을 만듭니다. 패키지 작업은 대상에서 become이 필요합니다. install_recommends: false는 선택적인 권장 패키지를 피합니다.

cat > packages.yml <<'YAML'
- name: Declare a utility package state
  hosts: all
  gather_facts: false
  become: true
  vars:
    utility_state: present
  tasks:
    - name: Converge the tree package
      ansible.builtin.apt:
        name: tree
        state: "{{ utility_state }}"
        update_cache: false
        install_recommends: false
YAML

유틸리티를 설치합니다.

ansible-playbook packages.yml

tree 명령은 디렉터리 트리를 표시합니다. 여기서는 버전 옵션으로 각 관리 노드에 실행 파일이 실제 설치되었음을 보여 줍니다.

ansible all -m ansible.builtin.command -a 'tree --version'

각 대상은 tree 버전을 반환해야 합니다. 플레이북을 반복합니다. 이미 있는 패키지는 다시 설치할 필요가 없어야 합니다.

ansible-playbook packages.yml

이제 재사용 태스크를 편집하는 대신 추가 변수로 제거 상태를 요청합니다.

ansible-playbook packages.yml -e utility_state=absent

같은 제거 상태를 반복합니다. 이제 두 요약 행 모두 changed=0, failed=0, unreachable=0을 보여야 합니다.

ansible-playbook packages.yml -e utility_state=absent

패키지 상태는 설치에 대한 선언이며 서비스가 실행되거나 응답한다는 증거가 아닙니다. 다음 단계에서 nginx를 배포하는 동안 tree는 제거된 상태로 두세요.

실제 웹 서비스 구성 및 시작하기

이 단계에서는 nginx를 설치하고 검증된 완전한 구성을 배포하며 서비스 실행 상태를 명시적으로 유지합니다.

두 관리 노드는 SSH 엔드포인트와 파일 시스템이 별개인 컨테이너입니다. systemd를 실행하지 않습니다. service 모듈은 사용 가능한 서비스 관리자를 이용합니다. 이 대상에서 systemctl을 실행하지 마세요. systemd 부팅 정책을 약속하는 대신 현재 실행 상태를 관리합니다.

컨트롤러에 정적 페이지를 만듭니다. 정확한 관리 바이트를 예측할 수 있도록 줄바꿈으로 끝납니다.

printf 'Ansible service ready\n' > page.txt

완전한 nginx 구성을 작성합니다. events와 http는 nginx 최상위 컨텍스트이고 server는 웹 사이트를 정의하며 listen은 포트 8080, root는 문서 디렉터리, index는 / 요청의 페이지를 선택합니다. 이는 Ansible YAML이 아닌 nginx 설정입니다.

cat > nginx-course.conf <<'NGINX'
events {}
http {
    server {
        listen 8080;
        root /var/www/ansible-site;
        index index.html;
    }
}
NGINX

배포 플레이북을 만듭니다. apt 태스크는 policy_rc_d: 101로 패키지 설치 도구가 암묵적으로 nginx를 시작하지 못하게 하고 이후 service 태스크가 실행 상태를 명시적으로 선언합니다. copy 태스크의 validate는 대상을 대체하기 전에 임시 후보 파일(%s)에 nginx 구성 테스트를 실행합니다.

핸들러는 handlers 아래에 나열된 이름 있는 동작입니다. 구성을 변경한 태스크가 Reload nginx에 알리면 플레이 끝에 한 번 실행됩니다. 구성 변경이 없으면 알림도 없습니다. 일반 service 태스크는 started를 사용하여 무조건 재시작하지 않고 이미 실행 중인 서비스를 유지합니다.

cat > web.yml <<'YAML'
- name: Deploy a working web service
  hosts: all
  gather_facts: false
  become: true
  tasks:
    - name: Install nginx without refreshing the prepared package lists
      ansible.builtin.apt:
        name: nginx
        state: present
        update_cache: false
        install_recommends: false
        policy_rc_d: 101

    - name: Prepare the site directory
      ansible.builtin.file:
        path: /var/www/ansible-site
        state: directory
        owner: root
        group: root
        mode: "0755"

    - name: Deploy the static page
      ansible.builtin.copy:
        src: /home/labex/project/page.txt
        dest: /var/www/ansible-site/index.html
        owner: root
        group: root
        mode: "0644"

    - name: Validate and deploy nginx configuration
      ansible.builtin.copy:
        src: /home/labex/project/nginx-course.conf
        dest: /etc/nginx/nginx.conf
        owner: root
        group: root
        mode: "0644"
        validate: /usr/sbin/nginx -t -c %s
      notify: Reload nginx

    - name: Keep nginx running
      ansible.builtin.service:
        name: nginx
        state: started

  handlers:
    - name: Reload nginx
      ansible.builtin.service:
        name: nginx
        state: reloaded
YAML

구문을 확인한 다음 배포를 적용합니다.

ansible-playbook web.yml --syntax-check
ansible-playbook web.yml

두 노드 모두 nginx를 설치하고 파일을 받아 성공적으로 시작해야 합니다. 최초 구성 변경은 다시 로드하는 핸들러도 예약합니다. 패키지 버전만 확인해서는 이러한 서비스 동작을 확인할 수 없습니다.

curl은 HTTP 클라이언트입니다. --fail은 성공이 아닌 HTTP 상태를 명령 실패로 처리하고 --silent는 진행 출력을 없애며 --show-error는 실패 세부 정보를 유지합니다. 각 관리 호스트에서 그 호스트 자신의 루프백 인터페이스를 대상으로 실행합니다.

ansible all -m ansible.builtin.command -a 'curl --fail --silent --show-error http://127.0.0.1:8080/'

각 결과에는 Ansible service ready가 있어야 합니다. 컨트롤러와 각 대상은 루프백 인터페이스가 별개입니다. 이 명령은 컨트롤러가 아니라 두 대상 서비스를 확인합니다.

핸들러를 통해 구성 변경 적용하기

이 단계에서는 실행 중인 nginx 설정을 변경하고 핸들러를 관찰하며 HTTP 응답으로 설정을 확인합니다.

nginx의 server_tokens 지시문은 응답 헤더가 nginx 버전을 노출할지 제어합니다. 컨트롤러 구성을 다음의 완전한 버전으로 대체하여 http 안에 server_tokens off를 추가합니다.

cat > nginx-course.conf <<'NGINX'
events {}
http {
    server_tokens off;
    server {
        listen 8080;
        root /var/www/ansible-site;
        index index.html;
    }
}
NGINX

같은 플레이북을 적용합니다.

ansible-playbook web.yml

구성 복사는 두 호스트 모두에서 changed를 보고하고 Reload nginx에 알려야 합니다. 핸들러는 새 구성이 검증을 통과한 후 실행 중인 서비스를 다시 로드합니다. 핸들러 실행이 구성을 적용합니다. 파일을 복사하기만 해서는 프로세스가 무엇을 로드했는지 알 수 없습니다.

curl의 -I는 HTTP 헤더를 요청합니다. 두 호스트의 실제 서비스 응답을 확인합니다.

ansible all -m ansible.builtin.command -a 'curl --fail --silent --show-error -I http://127.0.0.1:8080/'

두 응답 모두 성공 HTTP 상태와 버전 접미사 없는 nginx Server 헤더를 가져야 합니다. 날짜 같은 다른 헤더 필드는 달라집니다.

전체 플레이북을 반복합니다.

ansible-playbook web.yml

두 호스트 모두 실패 또는 연결 불가 태스크 없이 changed=0을 보고해야 하며 다시 로드하는 핸들러가 예약되지 않아야 합니다. 정적 페이지는 계속 사용 가능하고 tree는 제거된 상태이며 nginx는 설치되어 실행 중입니다.

요약

패키지 설치와 제거를 선언하고 설치를 서비스 실행 상태와 분리했으며, 후보 검증을 포함하는 완전한 nginx 구성을 배포했습니다. 변경된 구성은 다시 로드하는 핸들러에 알렸고 실제 HTTP 응답으로 실행 중인 동작을 확인했으며 변경 없는 반복 실행은 추가 변경이나 재로드를 피했습니다.