Ansible 실전 · 플레이북을 시험한다 · 실습
돌려 보기 전에 막는다 — 문법·린트·전제 조건을 관문으로
목표
문법 검사가 통과시키는 나쁜 플레이북에서 출발해 ansible-lint 의 규칙과 프로파일로 한 층씩 끌어올리고, 예외를 가장 좁은 범위로 두는 법을 익히고, assert 로 전제 조건을 먼저 막고, 이 셋을 하나의 관문 스크립트로 묶습니다.
왜 중요한가
앤서블의 위험한 점은 잘못 쓴 플레이북도 잘 돌아간다는 것입니다. 이름 없는 태스크도, 파이프가 든 셸도, 권한을 안 정한 파일 쓰기도 전부 초록색으로 끝납니다. 문제는 여섯 달 뒤에 옵니다 — 리포트가 언제나 changed 라 아무도 안 읽게 되고, 서버마다 파일 권한이 달라지고, 실패한 태스크의 이름이 shell 이라 로그를 봐도 무엇이 죽었는지 모릅니다. 린트는 그 여섯 달을 커밋 직전으로 당겨 옵니다. 다만 린트를 켜는 순간 팀은 곧바로 다음 문제를 만납니다 — 지적이 수백 개 나오고, 그중 몇 개는 정말 예외가 필요합니다. 그때 저장소 전체에서 규칙을 끄는 것과 한 줄만 빼는 것을 구분하지 못하면 린트는 한 달 만에 껍데기가 됩니다. 이 실습은 그 구분과, 린트가 못 보는 것(값이 말이 되는가)을 assert 로 막는 자리까지 함께 세웁니다.
단계
1. /root/anslint/ansible.cfg 의 기본 인벤토리를 ./inventory/hosts.ini 로 두고, 그 파일에 web 그룹의 web1·web2 를 적으세요 (둘 다 ansible_host=127.0.0.1 ansible_port=2222, [all:vars] 의 ansible_user 는 root). /root/anslint/messy.yml 에는 이름 없는 플레이 하나에 태스크 셋을 적습니다 — 이름 없이 파이프가 든 shell 태스크, 소문자로 시작하는 이름의 command: mkdir -p 태스크, copy: content=... dest=... 처럼 한 줄로 적은 태스크입니다. ansible-playbook --syntax-check messy.yml 을 돌려 출력을 /root/anslint/out/syntax.txt 에 저장하세요.
2. ansible-lint -f pep8 messy.yml 의 출력을 /root/anslint/out/lint_before.txt 에 저장하세요(한 줄에 지적 하나씩 나오는 형식입니다). 그다음 같은 파일을 JSON 형식으로 린트해 걸린 규칙 id 만 중복 없이 사전순으로 한 줄씩 /root/anslint/out/rules.txt 에 저장하세요.
3. /root/anslint/site.yml 을 새로 쓰세요 — 이름 있는 플레이 하나에 이름 있는 태스크 셋입니다. 첫째는 /root/anslint/out/data 디렉터리를 만들고, 둘째는 /root/anslint/out/app.conf 에 port=8080 한 줄을 쓰고, 셋째는 /root/anslint/out/upper-<호스트이름>.txt 에 그 호스트 이름을 대문자로 한 줄 씁니다. 셸 명령은 하나도 쓰지 않습니다. ansible-lint --profile basic site.yml 이 통과해야 하고, 플레이북을 실제로 돌려 출력을 /root/anslint/out/run.txt 에 저장하세요.
4. /root/anslint/site.yml 의 모든 모듈을 FQCN(ansible.builtin.<모듈>)으로 바꾸고, 파일과 디렉터리를 만드는 태스크마다 mode 를 적으세요. ansible-lint --profile production site.yml 이 통과해야 하고, 그 출력을 /root/anslint/out/lint_production.txt 에 저장하세요.
5. /root/anslint/site.yml 에 네 번째 태스크를 더하세요 — ansible.builtin.command 로 tar -czf /root/anslint/out/bundle.tgz -C /root/anslint/out app.conf 를 실행하고 changed_when: false 를 붙입니다. 린트는 이 태스크를 command-instead-of-module 로 잡는데, unarchive 모듈은 푸는 일만 하고 묶지는 못하므로 여기서는 셸 명령이 맞습니다. 그 한 줄만 규칙에서 빼는 주석을 달아 --profile production 을 다시 통과시키고, 플레이북을 다시 돌려 묶음을 실제로 만드세요.
6. /root/anslint/site.yml 에 다섯 번째 태스크를 더하세요 — 이름은 소문자로 시작하는 nginx health probe 이고, /root/anslint/out/health.txt 에 ok 한 줄을 씁니다. 그리고 /root/anslint/.ansible-lint 를 만들어 profile: production, exclude_paths 에 messy.yml 과 out/, skip_list 에 name[casing] 을 적으세요. 인자 없이 ansible-lint 를 돌려 디렉터리 전체가 통과하는 것을 확인하고 출력을 /root/anslint/out/lint_repo.txt 에 저장하세요.
7. /root/anslint/checks.yml 을 만드세요 — localhost 에서 팩트를 모으지 않고, 플레이 변수로 app_port: 8080, app_env: staging, allowed_envs: [staging, prod] 를 둡니다. 첫 태스크는 app_port 가 정수이고 1024 이상 65535 이하인지 확인하고, 둘째 태스크는 app_env 가 allowed_envs 안에 있는지 확인합니다. 둘 다 ansible.builtin.assert 로 쓰고 fail_msg 와 success_msg 를 답니다. 기본값 그대로 돌린 출력을 /root/anslint/out/assert_ok.txt 에, -e app_port=80 으로 덮어써 돌린 출력을 /root/anslint/out/assert_fail.txt 에 저장하세요.
8. /root/anslint/gate.sh 를 만드세요 — 첫 인자로 받은 디렉터리(기본값은 현재 디렉터리)로 옮겨 가 세 가지를 차례로 확인합니다. 그 디렉터리 바로 아래의 *.yml 마다 문법 검사를 하고 OK syntax <파일> 또는 FAIL syntax <파일> 을 출력하고, 인자 없이 ansible-lint 를 돌려 OK lint 또는 FAIL lint 를 출력하고, checks.yml 이 있으면 그것을 돌려 OK assert 또는 FAIL assert 를 출력합니다. 하나라도 실패하면 0 이 아닌 값으로 끝납니다. 이 관문을 지금 디렉터리에서 돌려 출력을 /root/anslint/out/gate.txt 에 저장하세요.
참고
- 이 이미지의 ansible-lint 는 6.17.2 입니다. 이 실습에 나오는 규칙 id 는 모두 이 판에서 실제로 나온 것입니다 — 판이 다르면 이름이 다를 수 있으니 언제나
ansible-lint -L로 자기 판의 목록을 확인하세요. - molecule 은 이 이미지에 없습니다. 롤을 여러 시나리오로 띄워 수렴·멱등성까지 시험하는 일은 공식 문서로만 다루고 이 실습에서는 뺐습니다. 여기서 세우는 관문은 molecule 이 있는 팀에서도 그 앞단에 그대로 필요합니다.
- 린트는 위반을 찾으면 0 이 아닌 값으로 끝납니다. 출력을 파일로 저장할 때 그 점을 고려하세요.
- 설정 파일은
.ansible-lint이고 훑을 때만exclude_paths가 걸립니다 — 파일 이름을 직접 주면 무시됩니다. - 흔한 실수: 지적이 많다고
skip_list에 규칙을 우르르 넣는 것. 남는 것은 켜져 있다는 착각뿐입니다. - 흔한 실수: 관문 스크립트가 검사만 하고 언제나 0 으로 끝나는 것. 반드시 나쁜 입력을 물려 확인하세요.
- [ansible-lint 규칙 목록](https://ansible.readthedocs.io/projects/lint/rules/) · [프로파일](https://ansible.readthedocs.io/projects/lint/profiles/) · [설정](https://ansible.readthedocs.io/projects/lint/configuring/) · [assert 모듈](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/assert_module.html) · [Molecule](https://ansible.readthedocs.io/projects/molecule/)
단계 8개
- 문법 검사를 통과하는 나쁜 플레이북
- 린트가 무엇을 잡는지 규칙 id 로 센다
- basic 프로파일까지 끌어올린다
- production 프로파일이 더 요구하는 두 가지
- 규칙은 살려 두고 한 줄만 뺀다
- 저장소 전체에 걸리는 규칙을 설정 파일에 적는다
- 값이 말이 되는지 플레이북 스스로 묻게 한다
- 세 층을 하나의 관문으로 묶는다