LabHub
배우기 러닝패스 코스

Ansible Fundamentals

It ran green, so why is the system not in the promised state?

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

태그로 플레이북의 일부만 돌리는 법을 익히고, 그 편의가 어떤 위험과 짝을 이루는지 직접 재 봅니다. 마지막에는 어떤 태그 선택이 완주할 수 있는지 판정하는 도구를 만듭니다.

왜 중요한가

플레이북은 자랍니다. 태스크가 여든 개인데 설정 한 줄만 고치고 싶은 날이 오고, 태그는 그 자리에 놓인 도구입니다. 문법이 쉬워서 사람들은 배운 다음 날부터 운영에서 씁니다. 사고는 거기서 납니다 — 태그는 실행을 자르는 칼인데, 플레이북은 잘려도 되게 설계되어 있지 않기 때문입니다. 앞 태스크가 만든 디렉터리를 뒤 태스크가 쓰고, 설정을 바꾼 태스크가 핸들러를 부릅니다. 일부만 고르면 그 연결이 끊어지고, 운이 나쁘면 실패조차 하지 않은 채 반쯤 맞는 상태가 남습니다. 그래서 이 실습은 태그 문법을 익히는 절반과, 자른 실행이 무엇을 보장하지 못하는지 눈으로 보는 절반으로 되어 있습니다.

단계

  1. /root/anstags/hosts.ini 를 만드세요 — [web]web1(ansible_host=127.0.0.1, ansible_port=2222), [all:vars]ansible_user=root. /root/anstags/site.yml 을 만드세요: 플레이 변수 app_env(기본 lab), 핸들러 reload app(/root/anstags/out/reload.markerreloaded 한 줄을 씁니다), 그리고 태스크 넷입니다 — /root/anstags/app 디렉터리를 0755 로 만드는 배포 자리를 만든다(태그 setup), /root/anstags/app/app.confenv=<app_env> 한 줄을 0644 로 쓰고 핸들러를 notify 하는 설정을 쓴다(태그 config), release_idr-2026 으로 정하는 배포 번호를 정한다(태그 prep, set_fact), /root/anstags/app/release.txtrelease_id 를 0644 로 쓰는 배포 번호를 기록한다(태그 deploy). 전체를 한 번 수렴시켜 출력을 /root/anstags/out/full.txt 에 저장하고, 이어서 --tags config 로 한 번 더 돌려 /root/anstags/out/config.txt 에 저장하세요.
  2. ansible-playbook -i hosts.ini site.yml --list-tags 의 출력을 /root/anstags/out/list-tags.txt 에 저장하세요. 그다음 --list-tasks --tags config 의 출력을 /root/anstags/out/list-config.txt 에 저장하세요. 두 번째 파일에는 설정을 쓴다 는 있고 배포 번호를 기록한다 는 없어야 합니다.
  3. --skip-tags prep,deploy 로 플레이북을 실제로 돌려 출력을 /root/anstags/out/skip.txt 에 저장하세요. 출력에는 배포 자리를 만든다설정을 쓴다TASK [...] 줄이 있고, 배포 번호를 정한다배포 번호를 기록한다 의 줄은 없어야 합니다. 그리고 --list-tasks --skip-tags prep,deploy 의 출력을 /root/anstags/out/list-skip.txt 에 저장하세요.
  4. 플레이 자체에 태그 platform 을 거세요. 그리고 설정을 검증한다 라는 이름의 블록을 태스크 끝에 더하고 그 블록에 태그 verify 를 다세요 — 블록 안에는 태그를 달지 않은 태스크 둘이 들어갑니다: /root/anstags/app/app.conf 의 상태를 읽어 conf_stat 으로 register 하는 설정 파일의 상태를 읽는다, 그 결과로 파일이 있는지 단언하는 설정 파일이 있는지 단언한다. --list-tasks 전체 출력을 /root/anstags/out/inherit.txt 에, --list-tasks --tags verify 출력을 /root/anstags/out/block.txt 에 저장하세요.
  5. 태스크 둘을 더하세요. 어떤 선택에서도 남기는 표식/root/anstags/out/always.markeralways 한 줄을 0644 로 쓰고 태그는 always 하나입니다. 함부로 돌면 안 되는 태스크/root/anstags/out/never.markerdanger 한 줄을 0644 로 쓰고 태그는 neverdanger 둘입니다. --tags config 로 실제로 돌려 출력을 /root/anstags/out/always.txt 에 저장하세요 — 어떤 선택에서도 남기는 표식 이 함께 돌아야 합니다. 그리고 --list-tasks --tags danger 출력을 /root/anstags/out/danger.txt 에 저장하세요. /root/anstags/out/never.marker 는 이 실습이 끝날 때까지 만들어지면 안 됩니다.
  6. /root/anstags/tasks/common.yml 을 만드세요 — 태스크 둘입니다. 공통 점검 하나common-one 을 출력하고 태그가 없습니다. 공통 점검 둘common-two 를 출력하고 태그 deep 을 갖습니다. 그다음 site.yml 끝에 태스크 둘을 더하세요 — import 로 공통 점검을 끌어온다(import_tasks 로 그 파일을 끌어오고 태그 imported)와 include 로 공통 점검을 끌어온다(include_tasks 로 같은 파일을 끌어오고 태그 included). --list-tasks --tags imported 출력을 /root/anstags/out/reuse-import.txt 에, --list-tasks --tags included 출력을 /root/anstags/out/reuse-include.txt 에 저장하세요.
  7. 먼저 /root/anstags/out/reload.marker 를 지우세요. 그다음 --start-at-task "배포 번호를 정한다" -e app_env=prod 로 플레이북을 실제로 돌리고 출력을 /root/anstags/out/startat.txt 에 저장하세요. 끝난 뒤 /root/anstags/app/app.conf 의 내용과 /root/anstags/out/reload.marker 의 존재 여부를 이어서 /root/anstags/out/aftermath.txt 에 남기세요 — 첫 줄은 conf=<app.conf 의 env 줄>, 둘째 줄은 marker=<yes 또는 no> 입니다.
  8. /root/anstags/tag-check.sh <태그목록> 을 만드세요. 그 선택으로 site.yml점검 모드로 돌려 보고, 정상으로 끝나면 첫 줄에 SAFE <태그목록> 을 내고 0 으로, 끝나지 않으면 첫 줄에 UNSAFE <태그목록> rc=<종료코드> 를 내고 1 로 끝냅니다. 그다음 ./tag-check.sh deploy./tag-check.sh prep,deploy 를 차례로 돌려 두 줄을 /root/anstags/out/tagcheck.txt 에 이어 저장하세요. 앞은 UNSAFE, 뒤는 SAFE 여야 합니다.

참고

태스크에 태그를 달고 전체를 한 번 수렴시킨다

/root/anstags/hosts.ini 를 만드세요 — [web]web1(ansible_host=127.0.0.1, ansible_port=2222), [all:vars]ansible_user=root. /root/anstags/site.yml 을 만드세요: 플레이 변수 app_env(기본 lab), 핸들러 reload app(/root/anstags/out/reload.markerreloaded 한 줄을 씁니다), 그리고 태스크 넷입니다 — /root/anstags/app 디렉터리를 0755 로 만드는 배포 자리를 만든다(태그 setup), /root/anstags/app/app.confenv=<app_env> 한 줄을 0644 로 쓰고 핸들러를 notify 하는 설정을 쓴다(태그 config), release_idr-2026 으로 정하는 배포 번호를 정한다(태그 prep, set_fact), /root/anstags/app/release.txtrelease_id 를 0644 로 쓰는 배포 번호를 기록한다(태그 deploy). 전체를 한 번 수렴시켜 출력을 /root/anstags/out/full.txt 에 저장하고, 이어서 --tags config 로 한 번 더 돌려 /root/anstags/out/config.txt 에 저장하세요.

태그는 이미 한 번 전체가 돌아간 시스템에 쓰는 도구입니다. 새 서버에 --tags config 만 걸면 디렉터리가 없어 실패하니, 첫 수렴은 반드시 전체로 합니다 — 그래서 이 단계는 전체 실행이 먼저입니다. 태그는 태스크에 tags: [이름] 으로 답니다. --tags config 로 돌린 출력에서 나머지 세 태스크의 TASK [...] 줄이 아예 없는 것을 확인하세요 — 걸러진 태스크는 건너뛴 것으로 표시되는 게 아니라 출력에서 통째로 빠집니다.

돌리기 전에 무엇이 돌지 목록으로 먼저 본다

ansible-playbook -i hosts.ini site.yml --list-tags 의 출력을 /root/anstags/out/list-tags.txt 에 저장하세요. 그다음 --list-tasks --tags config 의 출력을 /root/anstags/out/list-config.txt 에 저장하세요. 두 번째 파일에는 설정을 쓴다 는 있고 배포 번호를 기록한다 는 없어야 합니다.

이 두 도구는 대상에 붙지도 않고 아무것도 바꾸지도 않습니다 — 운영에서 태그를 처음 쓸 때 가장 먼저 걸어야 하는 것이 이것입니다. --list-tags 는 '이 플레이북에 어떤 태그가 있는가' 를 알려 주고, --list-tasks 는 '이번 선택으로 무엇이 돌 것인가' 를 순서대로 알려 줍니다. --list-tasks--tags 를 함께 주면 선택이 그대로 반영됩니다. 태스크마다 붙은 태그 목록도 같은 줄에 나오니 상속을 눈으로 확인할 때도 씁니다.

빼는 쪽으로 고른다

--skip-tags prep,deploy 로 플레이북을 실제로 돌려 출력을 /root/anstags/out/skip.txt 에 저장하세요. 출력에는 배포 자리를 만든다설정을 쓴다TASK [...] 줄이 있고, 배포 번호를 정한다배포 번호를 기록한다 의 줄은 없어야 합니다. 그리고 --list-tasks --skip-tags prep,deploy 의 출력을 /root/anstags/out/list-skip.txt 에 저장하세요.

고르는 방법은 두 가지입니다 — 넣을 것을 부르거나(--tags) 뺄 것을 부르거나(--skip-tags). 태그가 늘어나면 뒤쪽이 편할 때가 많습니다. 둘을 함께 줄 수도 있는데, 그때는 뺀 것이 이깁니다. 목록은 쉼표로 잇습니다. 돌리기 전에 목록으로 먼저 확인하는 습관은 --skip-tags 에서도 똑같이 값어치가 있습니다.

블록과 플레이에 건 태그가 아래로 흐른다

플레이 자체에 태그 platform 을 거세요. 그리고 설정을 검증한다 라는 이름의 블록을 태스크 끝에 더하고 그 블록에 태그 verify 를 다세요 — 블록 안에는 태그를 달지 않은 태스크 둘이 들어갑니다: /root/anstags/app/app.conf 의 상태를 읽어 conf_stat 으로 register 하는 설정 파일의 상태를 읽는다, 그 결과로 파일이 있는지 단언하는 설정 파일이 있는지 단언한다. --list-tasks 전체 출력을 /root/anstags/out/inherit.txt 에, --list-tasks --tags verify 출력을 /root/anstags/out/block.txt 에 저장하세요.

태그는 붙은 자리에서 아래로 흐릅니다. 블록에 달면 블록 안 모든 태스크가 갖고, 플레이에 달면 그 플레이의 모든 태스크가 갖습니다. 그 사실은 --list-tasks 의 각 줄 끝에 붙는 TAGS: [...] 에 그대로 드러납니다 — 블록 안 태스크에 아무것도 안 달았는데 태그가 둘 보이면 상속이 눈에 보인 것입니다. 상태를 읽는 모듈과 전제 조건을 단언하는 모듈은 이름이 떠오르지 않으면 ansible-doc -l ansible.builtin | grep -iE 'stat|assert' 로 찾으세요.

언제나 도는 태스크와 절대 안 도는 태스크

태스크 둘을 더하세요. 어떤 선택에서도 남기는 표식/root/anstags/out/always.markeralways 한 줄을 0644 로 쓰고 태그는 always 하나입니다. 함부로 돌면 안 되는 태스크/root/anstags/out/never.markerdanger 한 줄을 0644 로 쓰고 태그는 neverdanger 둘입니다. --tags config 로 실제로 돌려 출력을 /root/anstags/out/always.txt 에 저장하세요 — 어떤 선택에서도 남기는 표식 이 함께 돌아야 합니다. 그리고 --list-tasks --tags danger 출력을 /root/anstags/out/danger.txt 에 저장하세요. /root/anstags/out/never.marker 는 이 실습이 끝날 때까지 만들어지면 안 됩니다.

특수 태그는 다섯 개입니다 — always·never·tagged·untagged·all. 앞의 둘이 실무에서 쓰입니다. always 는 어떤 선택에서도 빠지면 안 되는 태스크(공통 변수 설정, 사실 수집)에 걸고, never 는 코드로는 남기되 손이 미끄러져 돌면 안 되는 태스크에 겁니다 — 주석 처리는 언젠가 풀리지만 never 는 풀리지 않습니다. never 가 붙은 태스크를 부르려면 함께 붙인 다른 이름표를 직접 불러야 합니다. 그 태스크는 --list-tasks 를 그냥 돌렸을 때 목록에 나오지도 않습니다 — 그것부터 확인해 보세요.

import 는 태그를 물려주고 include 는 물려주지 않는다

/root/anstags/tasks/common.yml 을 만드세요 — 태스크 둘입니다. 공통 점검 하나common-one 을 출력하고 태그가 없습니다. 공통 점검 둘common-two 를 출력하고 태그 deep 을 갖습니다. 그다음 site.yml 끝에 태스크 둘을 더하세요 — import 로 공통 점검을 끌어온다(import_tasks 로 그 파일을 끌어오고 태그 imported)와 include 로 공통 점검을 끌어온다(include_tasks 로 같은 파일을 끌어오고 태그 included). --list-tasks --tags imported 출력을 /root/anstags/out/reuse-import.txt 에, --list-tasks --tags included 출력을 /root/anstags/out/reuse-include.txt 에 저장하세요.

둘은 같은 파일을 끌어오지만 언제 끌어오는지가 다릅니다. 하나는 플레이북을 읽는 시점에 그 자리에 펼쳐지고(정적), 다른 하나는 실행 중에 비로소 끼어듭니다(동적). 그 차이가 태그 상속을 가릅니다 — 미리 펼쳐진 쪽은 태그가 태스크 하나하나에 붙고, 실행 중에 끼어드는 쪽은 문 자체에만 붙습니다. 두 목록 파일을 나란히 놓고 끌어온 파일 안의 태스크 이름이 보이는 쪽과 안 보이는 쪽을 확인하세요. 이것이 '오류 없이 아무 일도 안 일어나는' 고장의 정체입니다.

중간부터 돌리면 핸들러도 돌지 않는다

먼저 /root/anstags/out/reload.marker 를 지우세요. 그다음 --start-at-task "배포 번호를 정한다" -e app_env=prod 로 플레이북을 실제로 돌리고 출력을 /root/anstags/out/startat.txt 에 저장하세요. 끝난 뒤 /root/anstags/app/app.conf 의 내용과 /root/anstags/out/reload.marker 의 존재 여부를 이어서 /root/anstags/out/aftermath.txt 에 남기세요 — 첫 줄은 conf=<app.conf 의 env 줄>, 둘째 줄은 marker=<yes 또는 no> 입니다.

--start-at-task 는 그 이름의 태스크부터 시작합니다. 긴 플레이북이 중간에서 죽었을 때 1번부터 다시 돌리지 않으려고 쓰는 도구입니다. 그런데 앞 태스크가 만들었어야 할 것도, 앞 태스크가 보냈어야 할 notify 도 없는 채로 시작합니다 — 그래서 failed=0 으로 끝나도 시스템은 플레이북이 약속한 상태가 아닙니다. -e app_env=prod 를 함께 주었는데 설정 파일이 어떻게 되어 있는지, 핸들러 표식이 생겼는지를 직접 확인해 보세요. 이 단계의 답은 명령이 아니라 그 두 사실입니다.

어떤 태그 선택이 완주할 수 있는지 판정하는 도구

/root/anstags/tag-check.sh <태그목록> 을 만드세요. 그 선택으로 site.yml점검 모드로 돌려 보고, 정상으로 끝나면 첫 줄에 SAFE <태그목록> 을 내고 0 으로, 끝나지 않으면 첫 줄에 UNSAFE <태그목록> rc=<종료코드> 를 내고 1 로 끝냅니다. 그다음 ./tag-check.sh deploy./tag-check.sh prep,deploy 를 차례로 돌려 두 줄을 /root/anstags/out/tagcheck.txt 에 이어 저장하세요. 앞은 UNSAFE, 뒤는 SAFE 여야 합니다.

배포 번호를 기록한다배포 번호를 정한다 가 정한 값을 씁니다. 앞을 빼고 뒤만 고르면 그 변수는 정의되지 않은 채이고, 그것이 부분 실행이 위험한 첫 번째 방식입니다. 이 도구는 그 위험을 사람의 기억이 아니라 명령으로 바꿉니다. 판정에 점검 모드를 쓰는 이유는 운영에서 그대로 돌릴 수 있어야 하기 때문입니다 — 판정하려고 진짜로 바꾸면 도구가 아니라 사고입니다. 게이트가 1 로 끝나므로 결과를 파일에 모을 때 셸이 거기서 멈추지 않게 하세요.