LabHub
배우기 러닝패스 코스

Infrastructure as Code

Monday's apply tried to delete the rule fixed by hand on Friday night

LabHub 에서 이어서 보기

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

목표

코드 밖에서 생긴 변경을 plan -refresh-only 로 따로 읽고, 그대로 적용하면 사라질 것을 계획 JSON 에서 찾은 뒤, 흡수·되돌림·제외 세 가지 해소를 직접 하고 매일 돌릴 감지 스크립트를 만듭니다.

왜 중요한가

선언형 도구는 코드를 진실로 삼으므로 콘솔에서 고친 옳은 수정도 다음 적용에서 되돌립니다. 그래서 드리프트를 발견하면 먼저 무엇이 사라질지 읽고, 흡수할지 되돌릴지를 사람이 정해야 합니다. ignore_changes 는 모든 드리프트를 숨겨 주는 스위치가 아니고, 프로바이더가 읽지 않는 속성의 변경은 계획에 아예 나타나지 않습니다. 이 한계를 알아야 감지 결과가 비었을 때 '일치한다' 와 '안 보인다' 를 구분할 수 있습니다.

단계

  1. /root/iac-drift/main.tfrules 변수(기본값 ["allow 443"]), 규칙마다 한 줄씩 out/firewall.rules 에 쓰는 local_file.fw, out/motd.txtmaintenance window: sun 02:00 한 줄을 쓰는 local_file.motd 를 두고 init·apply 하세요.
  2. 장애 대응 중 누군가 /root/iac-drift/out/firewall.rules 끝에 allow 8443 한 줄을 손으로 더했습니다(직접 더하세요). 코드는 건드리지 않고 tofu plan -refresh-only 로 밖에서 생긴 변경만 본 출력을 /root/iac-drift/drift.txt 에 저장하세요.
  3. 코드를 바꾸지 말고 tofu plan -out=/root/iac-drift/monday.tfplan 으로 계획을 저장하세요(적용하지 않음). 그 계획이 firewall.rules 에 쓸 내용과 지금 파일을 비교해, 적용하면 사라질 줄만 /root/iac-drift/lost.txt 에 적으세요.
  4. 긴급 수정이 옳았다고 판단했습니다. rules 기본값을 ["allow 443", "allow 8443"] 로 바꾸고 apply 하세요. 그 뒤 firewall.rules 는 두 줄이고 계획은 깨끗해야 합니다.
  5. 이번에는 누군가 out/motd.txtmaintenance window: none 으로 바꿨습니다(직접 바꾸세요). 이건 잘못된 변경입니다. 되돌리기 전에 tofu plan -refresh-only 출력을 /root/iac-drift/revert-drift.txt 에 저장하고, 코드는 그대로 둔 채 apply 해 공지를 코드의 내용으로 되돌리세요.
  6. main.tfout/cache.confcache v1 을 쓰고 lifecycle { ignore_changes = [content] } 가 걸린 local_file.cache 를 더해 apply 하세요. (가) 파일을 손으로 cache tampered 로 바꾼 뒤 tofu plan 출력을 /root/iac-drift/ignore.txt 에 저장하고 apply 로 되돌립니다. (나) 코드의 내용을 cache v2 로 바꾸고 계획이 깨끗한지 봅니다(적용하지 않음). (다) chmod 600 out/firewall.rulestofu plan -detailed-exitcode 의 종료 코드를 /root/iac-drift/perm.txtperm=<코드> 로 적으세요.
  7. /root/iac-drift/detect.sh <작업디렉터리> 를 만드세요. plan -refresh-only 를 계획 파일로 저장해 밖에서 바뀐 리소스의 주소를 모아, 드리프트가 없으면 OK 와 0, 있으면 DRIFT <주소들(공백 구분, 정렬)> 한 줄과 2, 실패하면 ERROR 와 1 로 끝냅니다. 작업 디렉터리에 파일을 남기지 않습니다. 채점기는 /root/iac-drift 의 사본에서 파일을 바꿔 가며 확인합니다.

참고

기준선: 방화벽 규칙과 공지를 코드로 적용한다

/root/iac-drift/main.tfrules 변수(기본값 ["allow 443"]), 규칙마다 한 줄씩 out/firewall.rules 에 쓰는 local_file.fw, out/motd.txtmaintenance window: sun 02:00 한 줄을 쓰는 local_file.motd 를 두고 init·apply 하세요.

for 식으로 규칙마다 줄바꿈을 붙이고 join 으로 이어 붙이면 됩니다. 적용 뒤 계획이 비어 있어야 기준선입니다.

금요일 밤의 긴급 수정을 계획에서 본다

장애 대응 중 누군가 /root/iac-drift/out/firewall.rules 끝에 allow 8443 한 줄을 손으로 더했습니다(직접 더하세요). 코드는 건드리지 않고 tofu plan -refresh-only 로 밖에서 생긴 변경만 본 출력을 /root/iac-drift/drift.txt 에 저장하세요.

-refresh-only 는 코드의 변경을 계획하지 않고 실제와 상태의 차이만 보여 줍니다. local_file 프로바이더는 파일 내용이 기록과 다르면 그 파일을 '삭제됐다' 고 보고합니다 — 속성 하나가 바뀐 것으로 보이지 않는다는 점을 출력에서 확인하세요.

월요일에 그냥 apply 하면 무엇이 사라지나

코드를 바꾸지 말고 tofu plan -out=/root/iac-drift/monday.tfplan 으로 계획을 저장하세요(적용하지 않음). 그 계획이 firewall.rules 에 쓸 내용과 지금 파일을 비교해, 적용하면 사라질 줄만 /root/iac-drift/lost.txt 에 적으세요.

계획 JSON 의 resource_changes 에서 local_file.fw 의 change.after.content 가 적용 뒤 파일 내용입니다. 지금 파일에만 있는 줄이 사라질 줄입니다. comm 이나 grep -vxF -f 로 줄 단위 차이를 구할 수 있습니다.

옳은 수정이었다 — 코드로 흡수한다

긴급 수정이 옳았다고 판단했습니다. rules 기본값을 ["allow 443", "allow 8443"] 로 바꾸고 apply 하세요. 그 뒤 firewall.rules 는 두 줄이고 계획은 깨끗해야 합니다.

흡수는 코드를 현실에 맞추는 것입니다. 이 프로바이더는 파일을 '삭제됨' 으로 보았기 때문에, 코드를 고친 뒤의 계획도 수정이 아니라 생성으로 나옵니다 — 쓰는 내용이 지금 파일과 같으니 결과는 같습니다.

잘못된 수정이었다 — 코드대로 되돌린다

이번에는 누군가 out/motd.txtmaintenance window: none 으로 바꿨습니다(직접 바꾸세요). 이건 잘못된 변경입니다. 되돌리기 전에 tofu plan -refresh-only 출력을 /root/iac-drift/revert-drift.txt 에 저장하고, 코드는 그대로 둔 채 apply 해 공지를 코드의 내용으로 되돌리세요.

되돌림은 현실을 코드에 맞추는 것입니다. 되돌리기 전에 왜 그런 변경이 있었는지 확인하는 것이 절차의 일부입니다 — 여기서는 drift 출력을 남기는 것으로 그 흔적을 남깁니다.

ignore_changes 가 막는 것과 못 막는 것, 아예 안 보이는 것

main.tfout/cache.confcache v1 을 쓰고 lifecycle { ignore_changes = [content] } 가 걸린 local_file.cache 를 더해 apply 하세요. (가) 파일을 손으로 cache tampered 로 바꾼 뒤 tofu plan 출력을 /root/iac-drift/ignore.txt 에 저장하고 apply 로 되돌립니다. (나) 코드의 내용을 cache v2 로 바꾸고 계획이 깨끗한지 봅니다(적용하지 않음). (다) chmod 600 out/firewall.rulestofu plan -detailed-exitcode 의 종료 코드를 /root/iac-drift/perm.txtperm=<코드> 로 적으세요.

ignore_changes 는 '설정에 적힌 값이 바뀌어도 수정 계획을 세우지 마라' 는 뜻입니다. 프로바이더가 실물을 읽다가 없어졌다고 판단하는 것은 막지 못합니다. 그리고 프로바이더가 읽지 않는 속성의 변경은 드리프트로 잡히지 않습니다.

매일 아침 도는 드리프트 감지

/root/iac-drift/detect.sh <작업디렉터리> 를 만드세요. plan -refresh-only 를 계획 파일로 저장해 밖에서 바뀐 리소스의 주소를 모아, 드리프트가 없으면 OK 와 0, 있으면 DRIFT <주소들(공백 구분, 정렬)> 한 줄과 2, 실패하면 ERROR 와 1 로 끝냅니다. 작업 디렉터리에 파일을 남기지 않습니다. 채점기는 /root/iac-drift 의 사본에서 파일을 바꿔 가며 확인합니다.

계획 JSON 에는 resource_changes 말고도 resource_drift 가 있습니다 — 밖에서 생긴 변경이 거기에 따로 담깁니다. -detailed-exitcode 는 -refresh-only 와 함께 쓸 수 있습니다.