LabHub
学习 学习路径 课程

Ansible 基础

权限 640 变成 1204 的那一天 — 把文件当作状态来管

在 LabHub 中继续学习

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

목표

파일과 디렉터리를 명령이 아니라 상태로 선언합니다. 따옴표 없는 8진수가 남기는 권한을 직접 재고, 백업과 검증으로 되돌릴 근거와 깨진 설정 차단을 붙이고, 표식이 붙은 구획·링크·상태 보고서·경로 점검기까지 만듭니다.

왜 중요한가

셸로 mkdir·cp·chmod·sed -i 네 줄을 그대로 옮겨 놓으면 자동화처럼 보이지만 세 가지가 동시에 무너집니다. 두 번째 실행이 첫 번째와 달라지고, 무엇을 덮어썼는지 아무 데도 남지 않고, 깨진 설정이 그대로 올라갑니다. Ansible 의 파일 모듈은 이 셋을 각각 statebackupvalidate 로 답합니다. 여기에 여러 줄 구획을 안전하게 관리하는 blockinfile 의 표식, 배포에 쓰는 링크의 두 종류, 그리고 아무것도 바꾸지 않고 사실만 읽는 stat 이 더해지면 설정 배포의 골격이 완성됩니다. 이 실습은 그 골격을 한 번에 한 조각씩 손으로 세우고, 마지막에는 '지금 이 경로가 어떤 상태인가' 를 판정하는 도구를 직접 만들어 봅니다.

단계

  1. /root/ans/files/hosts.iniweb 그룹의 호스트 web1(ansible_host=127.0.0.1, ansible_port=2222, ansible_user=root)을 적고, /root/ans/files/p01.yml 로 네 디렉터리를 만드세요 — /root/ans/files/tree/conf/root/ans/files/tree/logs/root/ans/files/out0755, /root/ans/files/tree/secrets0700 입니다.
  2. /root/ans/files/p02.yml 로 세 파일을 만드세요 — /root/ans/files/tree/secrets/api.key"0600", /root/ans/files/tree/conf/motd.txt"0644", 그리고 /root/ans/files/scratch/decimal.txt따옴표 없이 mode: 644 로 적습니다. 그런 다음 stat -c %adecimal.txt 에 대해 내놓는 값을 /root/ans/files/out/mode-trap.txt 에 한 줄로 적으세요.
  3. /root/ans/files/p03.yml/root/ans/files/tree/conf/app.conf 를 배치하세요. 내용은 listen_port={{ app_port }}env=prod 두 줄이고 app_port 의 기본값은 8080, 권한은 "0644", backup 을 켭니다. 같은 플레이북이 /root/ans/files/tree/conf/deprecated.conf/root/ans/files/tree/logs/archive/old.log 도 만들게 하세요. 먼저 기본값으로 한 번 돌린 뒤 -e app_port=9090 으로 다시 돌려 백업이 생기게 하고, 그 백업 경로가 /root/ans/files/out/backup-path.txt 에 남게 하세요.
  4. /root/ans/files/p04.yml/root/ans/files/tree/conf/app.json 을 배치하세요. 내용은 app_json 변수에서 오고 기본값은 serviceweb, port8080 인 JSON 이며, copyvalidate 를 붙여 JSON 문법을 검사하게 합니다. 그런 다음 같은 플레이북을 -e "app_json=not json at all" 로 한 번 더 돌려 실패한 출력을 /root/ans/files/out/validate-fail.txt 에 남기세요.
  5. /root/ans/files/p05.yml/root/ans/files/tree/conf/hosts.block 을 다루세요. 파일이 없을 때만 127.0.0.1 localhost 한 줄로 만들고(이미 있으면 덮지 않습니다), blockinfile 로 표식 # {mark} ANSIBLE MANAGED BLOCK: web pool 을 쓰는 구획에 10.10.0.11 web110.10.0.12 web2 두 줄을 넣으세요. 플레이북을 두 번 돌려도 블록이 한 벌이어야 합니다.
  6. /root/ans/files/p06.yml 로 네 가지를 하세요 — 없을 때만 /root/ans/files/tree/logs/app.log 를 만들고, /root/ans/files/tree/logs/latest.log 가 그 파일을 가리키는 심볼릭 링크가 되게 하고, /root/ans/files/tree/conf/motd.hard/root/ans/files/tree/conf/motd.txt 의 하드 링크가 되게 하고, 마지막으로 latest.log 경로에 "0640" 을 걸되 링크를 따라가게 해서 app.log 의 권한이 바뀌게 하세요.
  7. /root/ans/files/p07.yml/root/ans/files/tree/conf/app.conf 의 상태를 stat 으로 확인하되 체크섬은 sha256 으로 받고, /root/ans/files/out/stat-report.jsonpath·exists·mode·size·checksum 다섯 키를 담은 JSON 을 남기세요. 이어서 /root/ans/files/tree/conf/app.jsonfetch 로 가져와 /root/ans/files/fetched/app.json 한 파일로 떨어지게 하세요.
  8. /root/ans/files/p08.yml/root/ans/files/tree/conf/deprecated.conf/root/ans/files/tree/logs/archive 를 없는 상태로 만드세요. 그리고 경로 목록 파일을 인자로 받아 경로마다 <경로> LINK <가리키는 곳> · <경로> DIR <권한> · <경로> FILE <권한> · <경로> ABSENT 중 하나를 한 줄로 내는 /root/ans/files/audit.sh 를 쓰세요. /root/ans/files/paths.txt 에 위의 두 경로와 /root/ans/files/tree/conf/app.conf, /root/ans/files/tree/logs/latest.log, /root/ans/files/tree/secrets 를 적고 결과를 /root/ans/files/out/state-report.txt 에 저장하세요.

참고

디렉터리 트리를 상태로 선언하기

/root/ans/files/hosts.iniweb 그룹의 호스트 web1(ansible_host=127.0.0.1, ansible_port=2222, ansible_user=root)을 적고, /root/ans/files/p01.yml 로 네 디렉터리를 만드세요 — /root/ans/files/tree/conf/root/ans/files/tree/logs/root/ans/files/out0755, /root/ans/files/tree/secrets0700 입니다.

ansible.builtin.file 에서 디렉터리를 뜻하는 state 값 하나면 중간 경로까지 함께 만들어 줍니다. mode 는 반드시 따옴표를 친 문자열로 적으세요 — 다음 단계에서 왜 그런지 직접 재 봅니다. 채점기는 플레이북을 점검 모드로 한 번 더 돌려 변경이 0 인지도 봅니다.

따옴표 없는 8진수가 남기는 권한 직접 재기

/root/ans/files/p02.yml 로 세 파일을 만드세요 — /root/ans/files/tree/secrets/api.key"0600", /root/ans/files/tree/conf/motd.txt"0644", 그리고 /root/ans/files/scratch/decimal.txt따옴표 없이 mode: 644 로 적습니다. 그런 다음 stat -c %adecimal.txt 에 대해 내놓는 값을 /root/ans/files/out/mode-trap.txt 에 한 줄로 적으세요.

YAML 은 앞에 0 이 없는 숫자를 10진수로 읽습니다. 그 정수가 그대로 권한 비트로 쓰이면 어떤 값이 되는지는 머리로 계산하지 말고 실제로 만들어 stat 으로 재 보세요. scratch 디렉터리도 같은 플레이북에서 함께 만듭니다.

덮어쓰기 전의 내용을 남기기

/root/ans/files/p03.yml/root/ans/files/tree/conf/app.conf 를 배치하세요. 내용은 listen_port={{ app_port }}env=prod 두 줄이고 app_port 의 기본값은 8080, 권한은 "0644", backup 을 켭니다. 같은 플레이북이 /root/ans/files/tree/conf/deprecated.conf/root/ans/files/tree/logs/archive/old.log 도 만들게 하세요. 먼저 기본값으로 한 번 돌린 뒤 -e app_port=9090 으로 다시 돌려 백업이 생기게 하고, 그 백업 경로가 /root/ans/files/out/backup-path.txt 에 남게 하세요.

copy 의 백업 기능은 덮어쓰기 직전의 내용을 같은 디렉터리에 남깁니다. 반환값에 그 경로가 담기므로 register 로 받아 두면 다음 태스크에서 바로 쓸 수 있습니다. 첫 실행에는 덮어쓸 것이 없어 백업이 생기지 않으니, 경로를 기록하는 태스크에는 is defined 조건을 붙이세요.

검사를 통과한 설정만 제자리에 놓기

/root/ans/files/p04.yml/root/ans/files/tree/conf/app.json 을 배치하세요. 내용은 app_json 변수에서 오고 기본값은 serviceweb, port8080 인 JSON 이며, copyvalidate 를 붙여 JSON 문법을 검사하게 합니다. 그런 다음 같은 플레이북을 -e "app_json=not json at all" 로 한 번 더 돌려 실패한 출력을 /root/ans/files/out/validate-fail.txt 에 남기세요.

validate 문자열 안의 %s 자리에 임시 파일 경로가 들어갑니다. 검사 명령은 JSON 을 읽어 보고 문제가 있으면 0 이 아닌 값으로 끝나면 됩니다. 실패한 실행의 출력을 남길 때는 표준 오류도 함께 받아야 하고, 실패한 명령 때문에 스크립트가 멈추지 않게 하세요. 실패한 뒤에도 원래 파일이 멀쩡한지 확인해 보세요.

표식이 붙은 구획만 갈아 끼우기

/root/ans/files/p05.yml/root/ans/files/tree/conf/hosts.block 을 다루세요. 파일이 없을 때만 127.0.0.1 localhost 한 줄로 만들고(이미 있으면 덮지 않습니다), blockinfile 로 표식 # {mark} ANSIBLE MANAGED BLOCK: web pool 을 쓰는 구획에 10.10.0.11 web110.10.0.12 web2 두 줄을 넣으세요. 플레이북을 두 번 돌려도 블록이 한 벌이어야 합니다.

copy 에는 이미 있는 파일을 덮지 않게 하는 스위치가 있습니다. 그것을 빼면 두 번째 실행에서 블록이 통째로 사라졌다가 다시 붙습니다. 표식 문자열의 {mark} 자리에 BEGIN 과 END 가 각각 들어갑니다 — 이 문구를 나중에 바꾸면 블록이 두 벌이 됩니다. 채점기는 플레이북을 점검 모드로 다시 돌려 변경이 0 인지도 봅니다.

심볼릭 링크와 하드 링크, 그리고 follow

/root/ans/files/p06.yml 로 네 가지를 하세요 — 없을 때만 /root/ans/files/tree/logs/app.log 를 만들고, /root/ans/files/tree/logs/latest.log 가 그 파일을 가리키는 심볼릭 링크가 되게 하고, /root/ans/files/tree/conf/motd.hard/root/ans/files/tree/conf/motd.txt 의 하드 링크가 되게 하고, 마지막으로 latest.log 경로에 "0640" 을 걸되 링크를 따라가게 해서 app.log 의 권한이 바뀌게 하세요.

심볼릭 링크와 하드 링크는 state 값이 다릅니다. 둘 다 srcdest 를 받습니다. 마지막 태스크는 이미 있는 파일의 속성만 맞추는 state 를 쓰고, 링크를 따라갈지 정하는 인자를 명시적으로 켜세요. 리눅스에서는 심볼릭 링크 자체의 권한이 의미가 없어서, 권한은 링크가 아니라 그 끝의 파일에 걸립니다.

상태를 읽어 보고서로 남기고 컨트롤러로 가져오기

/root/ans/files/p07.yml/root/ans/files/tree/conf/app.conf 의 상태를 stat 으로 확인하되 체크섬은 sha256 으로 받고, /root/ans/files/out/stat-report.jsonpath·exists·mode·size·checksum 다섯 키를 담은 JSON 을 남기세요. 이어서 /root/ans/files/tree/conf/app.jsonfetch 로 가져와 /root/ans/files/fetched/app.json 한 파일로 떨어지게 하세요.

stat 은 아무것도 바꾸지 않고 사실만 돌려줍니다. 체크섬은 알고리즘을 지정해야 반환값에 담깁니다. fetch 는 기본으로 호스트 이름 디렉터리를 만들고 원본 경로를 그대로 재현하므로, 파일 하나로 떨어뜨리려면 그 동작을 끄는 인자를 켜야 합니다. 보고서는 사전을 만들어 JSON 으로 바꾸는 필터를 쓰면 한 태스크로 끝납니다.

치우는 것도 상태다 — 그리고 경로 점검기 만들기

/root/ans/files/p08.yml/root/ans/files/tree/conf/deprecated.conf/root/ans/files/tree/logs/archive 를 없는 상태로 만드세요. 그리고 경로 목록 파일을 인자로 받아 경로마다 <경로> LINK <가리키는 곳> · <경로> DIR <권한> · <경로> FILE <권한> · <경로> ABSENT 중 하나를 한 줄로 내는 /root/ans/files/audit.sh 를 쓰세요. /root/ans/files/paths.txt 에 위의 두 경로와 /root/ans/files/tree/conf/app.conf, /root/ans/files/tree/logs/latest.log, /root/ans/files/tree/secrets 를 적고 결과를 /root/ans/files/out/state-report.txt 에 저장하세요.

권한은 stat -c %a 가 내놓는 그대로 적습니다. 판정 순서가 이 단계의 전부입니다 — -d-f 는 심볼릭 링크를 따라가므로, 링크를 나중에 보면 링크가 디렉터리나 파일로 둔갑합니다. 채점기는 자기가 만든 별도의 경로 목록으로도 이 스크립트를 돌려 보므로, 답을 적어 둔 스크립트는 통과하지 못합니다.