LabHub
배우기 러닝패스 코스

Infrastructure as Code

冪等なリソース保証スクリプト

LabHub 에서 이어서 보기

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

목표

디렉터리·파일·줄·권한을 보장하는 멱등 스크립트를 만들고, 두 번 연속 적용해 changed 가 0 이 되는 것으로 멱등성을 증명한다. 상태 파일과 드리프트 감지, 잠금까지 붙인다.

왜 중요한가

멱등성은 같은 작업을 여러 번 실행해도 결과가 동일하다는 성질이고, 자동화를 재실행해도 안전하다는 보증이다. 증명 방법은 두 번 적용해 두 번째 plan 이 변경 없음인지 보는 것이다. 멱등성이 깨지는 자리는 거의 정해져 있다. 전용 모듈 대신 shell 이나 command 로 명령을 직접 실행하는 곳, 그리고 >> 로 줄을 덧붙이는 곳이다. 그래서 이 실습의 스크립트들은 모두 "바꾸기 전에 확인한다"는 같은 골격을 갖는다. 마지막에 붙이는 상태 파일과 잠금은 실제 IaC 도구가 왜 그런 부속을 달고 있는지 몸으로 이해하게 해 준다.

단계

  1. /root/iac2/ensure_dir.sh <경로> 를 만든다. 디렉터리가 없으면 만들고 changed, 이미 있으면 unchanged 를 출력한다. 두 경우 모두 종료코드 0 이다. 출력은 그 낱말만 담은 한 줄이어야 한다(채점은 unchanged 를 줄 전체와 정확히 비교한다).
  2. /root/iac2/ensure_file.sh <경로> <내용> 을 만든다. 파일이 없거나 내용이 다르면 내용을 써 넣고 changed, 이미 같으면 unchanged 를 출력한다.
  3. /root/iac2/ensure_line.sh <파일> "<줄>" 을 만든다. 그 줄이 이미 정확히 있으면 unchanged, 같은 키(줄의 첫 낱말)를 가진 다른 줄이 있으면 그 자리를 새 줄로 교체하고 changed, 아무것도 없으면 끝에 추가하고 changed 를 출력한다. 몇 번을 실행해도 해당 줄은 파일에 정확히 1개여야 하고 나머지 줄은 그대로 남아야 한다.
  4. /root/iac2/ensure_mode.sh <파일> <8진수모드> 를 만든다. stat -c %a 로 현재 권한을 읽어 다르면 chmodchanged, 같으면 unchanged 를 출력한다. 파일이 존재하지 않으면 0 이 아닌 종료코드를 낸다.
  5. /root/iac2/run.sh 를 만든다. 위 네 스크립트를 이용해 리소스를 정확히 4개 보장한다(예: 디렉터리 1 + 파일 2 + 권한 1). 마지막 줄에 요약을 unchanged=<수> changed=<수> 순서로 출력한다. 첫 실행의 출력을 /root/iac2/run1.txt 에, 이어서 두 번째 실행의 출력을 /root/iac2/run2.txt 에 저장한다. 첫 실행의 changed 는 1 이상, 두 번째 실행의 요약은 unchanged=4 changed=0 이어야 한다.
  6. /root/iac2/state.json 을 만든다. resources 배열에 방금 보장한 리소스를 기록하고(2개 이상), 각 원소에 path, type(file 또는 dir), sha256 을 넣는다. typedir 이 아닌 항목은 실제 파일이 존재해야 하고 sha256 값이 sha256sum <경로> 의 첫 필드와 정확히 같아야 한다. 최상위에 applied_at(적용 시각) 도 넣는다.
  7. /root/iac2/drift.sh <상태파일> 을 만든다. 인자로 받은 상태 파일을 읽어 기록된 리소스를 검증한다. 전부 일치하면 종료코드 0, 내용이 바뀌었거나 파일이 사라졌으면 어긋난 경로를 출력하고 0 이 아닌 코드를 낸다. typedir 인 항목은 존재 여부만 확인한다.
  8. /root/iac2/apply-lock.sh 를 만든다. 잠금 파일 경로는 LOCK_FILE 환경변수로 받고 없으면 /root/iac2/.lock 을 쓴다. 잠금이 없으면 조건부로 만들어 잡고, 할 일을 한 뒤 정상 종료할 때 반드시 지운다(종료코드 0, 잠금 파일이 남으면 안 된다). 이미 잠겨 있으면 기다리지 말고 종료코드 2 로 즉시 실패하며 lock 이라는 낱말이 들어간 메시지를 출력한다. 이때 남의 잠금 파일을 지우면 안 된다.

참고

디렉터리 보장

/root/iac2/ensure_dir.sh <경로> 를 만든다. 디렉터리가 없으면 만들고 changed, 이미 있으면 unchanged 를 출력한다. 두 경우 모두 종료코드 0 이다. 출력은 그 낱말만 담은 한 줄이어야 한다(채점은 unchanged 를 줄 전체와 정확히 비교한다).

ensure_dir.sh <경로> 는 없으면 만들고 changed, 이미 있으면 unchanged 를 출력합니다. 둘 다 종료코드 0 입니다. 출력은 그 한 낱말만 담은 한 줄이어야 합니다. 채점은 unchanged 를 줄 전체와 정확히 비교합니다.

파일 내용 보장

/root/iac2/ensure_file.sh <경로> <내용> 을 만든다. 파일이 없거나 내용이 다르면 내용을 써 넣고 changed, 이미 같으면 unchanged 를 출력한다.

ensure_file.sh <경로> <내용> 입니다. 쓰기 전에 현재 내용과 비교하세요. 없거나 다르면 쓰고 changed, 같으면 손대지 말고 unchanged. 무조건 쓰면 항상 changed 가 되어 멱등성 증명이 깨집니다.

줄 보장 (중복 없이)

/root/iac2/ensure_line.sh <파일> "<줄>" 을 만든다. 그 줄이 이미 정확히 있으면 unchanged, 같은 키(줄의 첫 낱말)를 가진 다른 줄이 있으면 그 자리를 새 줄로 교체하고 changed, 아무것도 없으면 끝에 추가하고 changed 를 출력한다. 몇 번을 실행해도 해당 줄은 파일에 정확히 1개여야 하고 나머지 줄은 그대로 남아야 한다.

ensure_line.sh <파일> "<줄>" 입니다. >> 로 덧붙이면 실행할 때마다 줄이 쌓입니다. 같은 줄이 이미 있으면 unchanged, 같은 키(첫 낱말)의 다른 줄이 있으면 그 자리를 교체하고 changed, 없으면 끝에 추가하고 changed. 다른 줄은 그대로 남아야 합니다.

권한 보장

/root/iac2/ensure_mode.sh <파일> <8진수모드> 를 만든다. stat -c %a 로 현재 권한을 읽어 다르면 chmodchanged, 같으면 unchanged 를 출력한다. 파일이 존재하지 않으면 0 이 아닌 종료코드를 낸다.

ensure_mode.sh <파일> <8진수모드>stat -c %a 로 현재 권한을 읽어 비교합니다. 다르면 chmod 후 changed, 같으면 unchanged. 없는 파일에 chmod 를 시도하고 성공했다고 보고하면 안 되니 존재 확인을 먼저 하세요.

두 번 돌려 멱등성 증명하기

/root/iac2/run.sh 를 만든다. 위 네 스크립트를 이용해 리소스를 정확히 4개 보장한다(예: 디렉터리 1 + 파일 2 + 권한 1). 마지막 줄에 요약을 unchanged=<수> changed=<수> 순서로 출력한다. 첫 실행의 출력을 /root/iac2/run1.txt 에, 이어서 두 번째 실행의 출력을 /root/iac2/run2.txt 에 저장한다. 첫 실행의 changed 는 1 이상, 두 번째 실행의 요약은 unchanged=4 changed=0 이어야 한다.

run.sh 로 리소스 정확히 4개를 보장하고, 마지막 줄에 unchanged=<수> changed=<수> 순서로 요약을 냅니다. 순서가 중요합니다. 첫 실행 출력은 /root/iac2/run1.txt, 이어서 두 번째 실행 출력은 /root/iac2/run2.txt 로 저장하세요.

상태 파일 남기기

/root/iac2/state.json 을 만든다. resources 배열에 방금 보장한 리소스를 기록하고(2개 이상), 각 원소에 path, type(file 또는 dir), sha256 을 넣는다. typedir 이 아닌 항목은 실제 파일이 존재해야 하고 sha256 값이 sha256sum <경로> 의 첫 필드와 정확히 같아야 한다. 최상위에 applied_at(적용 시각) 도 넣는다.

/root/iac2/state.json 에 방금 적용한 리소스를 기록합니다. 각 원소는 path, type, sha256 을 갖고, 파일 항목의 해시는 sha256sum <경로> 첫 필드와 정확히 같아야 합니다. 최상위에 applied_at 도 넣으세요. run.sh 를 돌린 뒤에 만들어야 해시가 맞습니다.

드리프트 감지

/root/iac2/drift.sh <상태파일> 을 만든다. 인자로 받은 상태 파일을 읽어 기록된 리소스를 검증한다. 전부 일치하면 종료코드 0, 내용이 바뀌었거나 파일이 사라졌으면 어긋난 경로를 출력하고 0 이 아닌 코드를 낸다. typedir 인 항목은 존재 여부만 확인한다.

drift.sh <상태파일> 은 인자로 받은 상태 파일을 읽습니다. 경로를 하드코딩하면 채점이 만든 임시 상태 파일을 못 읽습니다. 내용 변경과 파일 삭제를 모두 잡아야 하고, 어긋난 경로를 출력해야 사람이 무엇을 볼지 압니다.

상태 잠금

/root/iac2/apply-lock.sh 를 만든다. 잠금 파일 경로는 LOCK_FILE 환경변수로 받고 없으면 /root/iac2/.lock 을 쓴다. 잠금이 없으면 조건부로 만들어 잡고, 할 일을 한 뒤 정상 종료할 때 반드시 지운다(종료코드 0, 잠금 파일이 남으면 안 된다). 이미 잠겨 있으면 기다리지 말고 종료코드 2 로 즉시 실패하며 lock 이라는 낱말이 들어간 메시지를 출력한다. 이때 남의 잠금 파일을 지우면 안 된다.

apply-lock.shLOCK_FILE 환경변수를 존중합니다. 잠금이 없으면 조건부로 만들고 정상 종료 때 반드시 지웁니다(0). 이미 잠겨 있으면 기다리지 말고 종료코드 2 로 즉시 실패하며 잠금 때문임을 메시지로 알립니다. 남의 잠금 파일은 절대 지우지 마세요.