TT Lab
시작하기
배우기 러닝패스 코스

Terraform 실전

부수기와 내려놓기는 다른 일이다

TT Lab 에서 이어서 보기

한 줄 요약

설정에서 리소스 블록을 지우는 것은 "부숴라" 다. "이제 우리가 관리하지 않는다" 는 뜻은 removed 블록으로 따로 말해야 한다.

왜 이게 필요했나 — 지우기와 내려놓기가 같은 문장이었다

한 팀이 데이터베이스 세 대를 관리하다가 그중 하나를 다른 팀에 넘긴다고 하자. 코드에서 그 블록을 지우는 것이 자연스러워 보인다. 그리고 plan 을 돌리면 destroy 1 이 뜬다. 운영 중인 데이터베이스다.

예전에는 이 상황을 명령으로 풀었다. 상태에서 그 주소를 빼는 명령을 손으로 한 번 치고, 그다음에 코드를 지운다. 동작은 하지만 두 가지가 나쁘다. 첫째, 기록이 없다. 누가 언제 무엇을 상태에서 뺐는지 커밋에 남지 않는다. 둘째, 순서를 틀리면 끝난다. 코드를 먼저 지우고 apply 를 치면 그것으로 상황이 종료된다.

removed 블록은 이 일을 선언으로 옮긴 것이다. 코드에 적히니 리뷰를 받고, 커밋에 남고, 순서가 뒤집힐 여지가 없다.

리소스 블록만 지울 때와 removed 블록을 둘 때

데이터베이스 세 대 중 하나를 다른 팀에 넘기려고 코드에서 그 블록을 정리하는 장면이다. 두 방식은 코드를 고치는 모습이 비슷해 보이지만 계획이 하는 말은 정반대다.

  • 블록만 지운다도구는 부숴라라는 뜻으로 읽는다. 계획에 destroy 1 이 뜨고 운영 중인 데이터베이스가 부서진다. 설정에서 리소스 블록을 지우는 것은 그런 말이다.
  • 지운 자리에 removed 블록을 둔다from 에 그 주소를 적는다. 계획에는 상태에서만 빠지고 파괴되지 않는다는 문구가 뜨고 Plan 줄의 세 숫자가 모두 0 이다. 실물에는 아무 일도 하지 않는다.

여기서 구분할 것 removed 블록은 일이 끝나면 죽은 코드다. 그대로 두면 언젠가 그 주소의 리소스가 다시 필요해질 때 잊으라는 선언과 만들라는 선언이 겹쳐 계획이 막힌다. 또 removed 가 lifecycle 같은 하위 블록을 받는지는 쓰는 판에 달려 있으니 넣어 보고 plan 으로 확인한다.

잠깐, 예측해 보세요 CI 가 validate 만 돌리고 plan 은 사람이 승인 단계에서만 본다. 위의 겹침 오류는 CI 에서 걸러질까?

설명 확인 · 채점 없는 자가 점검

걸러지지 않는다. 본문에 따르면 주소를 상태와 맞춰 보는 일은 계획 단계의 몫이라 validate 는 통과한다. 오류는 plan 을 돌릴 때 비로소 나므로 CI 에 plan 이 들어 있어야 한다.

근거 문서

어떻게 동작하나

# 1) 리소스 블록을 지운다
# 2) 그 자리에 removed 블록을 둔다
removed {
  from = local_file.legacy
}

계획을 돌리면 이렇게 나온다.

# local_file.legacy will be removed from the OpenTofu state
# but will not be destroyed
Plan: 0 to add, 0 to change, 0 to destroy.

읽어야 할 곳이 두 군데다. 첫째, 동작을 가리키는 낱말이 destroy 가 아니다. 둘째, 그래서 Plan: 줄의 세 숫자가 모두 0 이다 — 실물에는 아무 일도 하지 않는다는 뜻이다.

판마다 받는 인자가 다르다. 이것이 이 모듈에서 꼭 가져가야 할 습관인데, removed 블록이 lifecycle 같은 하위 블록을 받는지는 쓰고 있는 판에 달려 있다. 문서 사이트는 기본으로 최신판을 보여 주므로, 문서에 있다고 해서 내 도구가 받는다는 보장이 없다. 확인하는 법은 간단하다 — 넣어 보고 plan 을 돌려 보면 도구가 직접 답한다. 실습 3단계에서 이 파드의 판이 무엇을 받고 무엇을 안 받는지 직접 물어 표로 적는다.

이름만 바꾸는 일은 moved 다. removed 와 헷갈리기 쉬운데 목적이 반대다. moved 는 "같은 객체인데 주소가 바뀌었다" 를 말해 상태의 항목을 새 주소로 옮긴다. 이것이 없으면 도구는 옛 이름이 사라지고 새 이름이 생긴 것으로 읽어 부수고 다시 만든다. 옮겼는지 다시 만들었는지는 식별자를 견주면 바로 안다.

하나만 다시 만들고 싶을 때는 -replace. 설정은 그대로 두고 "이 주소만 부수고 다시 만들어라" 를 계획에 넣는다. 예전에는 같은 일을 taint 로 했는데, 차이가 중요하다. taint 는 상태 파일을 먼저 고쳐 놓고 다음 계획이 그것을 읽게 한다. 표시해 둔 채 잊어버리면 엉뚱한 사람이 엉뚱한 때에 그 교체를 적용하게 된다. -replace 는 그 실행에만 적용되므로 흔적이 남지 않는다. 그래도 taint·untaint 를 알아 둬야 하는 이유는, 남이 표시해 둔 상태를 만났을 때 당황하지 않기 위해서다.

현장에서 만나는 모습

가장 흔한 사고는 removed 블록을 치우지 않고 남겨 두는 것이다. 일이 끝나면 그 블록은 죽은 코드인데, 죽은 채로 있다가 언젠가 그 주소의 리소스가 다시 필요해지는 날 되살아난다. "잊어라" 와 "만들어라" 가 같은 주소에 동시에 있으면 계획이 막힌다. 더 얄궂은 것은 이 오류가 설정 검증(validate)은 통과하고 계획에서만 난다는 점이다. 주소를 상태와 맞춰 보는 일은 계획 단계의 몫이기 때문이다. CI 가 validate 만 돌리고 있으면 이 문제를 못 잡는다.

두 번째는 조직 분할이다. 팀이 갈라질 때 한쪽 몫을 통째로 넘겨야 하는데, removed 의 from 에는 모듈 주소도 올 수 있어서 모듈 하나를 한꺼번에 내려놓을 수 있다. 다만 받는 쪽이 그 실물을 자기 상태로 가져가는 일은 별도 작업이고, 프로바이더가 그 리소스의 가져오기를 지원해야 한다 — 모든 리소스가 그렇지는 않다.

세 번째는 소유가 비어 있는 기간이다. 내려놓은 시점부터 받는 쪽이 가져갈 때까지 그 실물은 어느 코드도 관리하지 않는다. 그 사이에 아무도 그것을 건드리지 않게 하려면, 넘기는 작업을 문서와 일정으로 감싸야 한다. 도구가 해 줄 수 있는 일이 아니다.

네 번째는 되찾을 수 있는가다. 상태에서 뺀 것을 다시 코드로 관리하려면 가져오기(import)를 해야 하는데, 프로바이더가 그 리소스의 가져오기를 구현해 두지 않았으면 방법이 없다. 이 실습의 파일 리소스가 바로 그런 경우다. 그래서 내려놓기 전에 "이건 되돌릴 수 있는 결정인가" 를 한 번 확인해 두는 편이 안전하다 — 되돌릴 수 없다면 사본을 남기거나, 넘기는 쪽과 받는 쪽이 같은 시각에 작업해야 한다.

내려놓은 자원이 새 주인에게 가기까지

조직이 갈라질 때 한쪽 몫을 넘기는 순서다. 도구가 해 주는 것은 첫 단계뿐이고 나머지는 사람과 프로바이더에 달려 있다. 모듈 하나를 통째로 내려놓을 때는 from 에 모듈 주소를 쓸 수 있다.

  1. 내려놓는다removed 블록을 적용하면 상태에서만 빠지고 실물은 남는다. 선언이 코드에 적혀 리뷰를 받고 커밋에 남는다.
  2. 소유가 빈 기간이 생긴다내려놓은 시점부터 받는 쪽이 가져갈 때까지 그 실물은 어느 코드도 관리하지 않는다. 그 사이 아무도 건드리지 않게 하려면 작업을 문서와 일정으로 감싸야 한다. 도구가 해 줄 일이 아니다.
  3. 받는 쪽이 가져간다받는 쪽이 자기 상태로 import 한다. 프로바이더가 그 리소스의 가져오기를 구현해 둬야 하고 모든 리소스가 그렇지는 않다. 본문 실습의 파일 리소스가 가져올 수 없는 경우다.

여기서 구분할 것 내려놓기 전에 이것이 되돌릴 수 있는 결정인지 확인한다. 되돌릴 수 없다면 사본을 남기거나, 넘기는 쪽과 받는 쪽이 같은 시각에 작업해야 한다.

잠깐, 예측해 보세요 받는 팀이 import 를 시도했는데 프로바이더가 그 리소스의 가져오기를 지원하지 않는다. 이미 상태에서 뺀 실물을 다시 코드로 관리할 방법이 있을까?

설명 확인 · 채점 없는 자가 점검

본문에 따르면 방법이 없다. 그래서 내려놓기 전에 되돌릴 수 있는 결정인지 확인하고, 안 된다면 사본을 남기거나 양쪽이 같은 시각에 작업한다.

근거 문서

다음 실습에서 할 것

/root/tfa-removed 에서 넘겨받은 파일 하나를 removed 로 상태에서만 빼고 실물이 남는 것을 확인합니다. 이 판의 removed 가 무엇을 받는지 직접 물어 표로 적고, moved 로 이름을 바꿔 식별자가 유지되는 것을 1단계 사본과 견주고, 잊으라는 선언과 만들라는 선언이 겹쳤을 때의 오류를 받아 본 뒤, -replace 와 taint 로 하나만 다시 만들고, 마지막으로 모듈 하나를 통째로 내려놓습니다.