Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.

Terraform 추천 사용패턴 #1

이 글은 HashiCorp에서 최근에 공개Terraform Recommended Practices를 번역한 글입니다. HashiCorp로부터 정식으로 번역 허락을 받고 번역해서 블로그에 올립니다. 좋은 도구와 함께 번역을 허락해 준 HashiCorp에 감사드립니다.

웹사이트에 올라온 글을 블로그에 올리려니 글이 길어서 아래 2개의 글로 나누어서 올립니다.

번역 용어와 관련해서...

제목이 Recommended Practices이므로 이 글에서는 Practices라는 단어가 아주 많이 사용된다. Best Practices 같은 경우는 "모범 사용사례", 여기서는 "추천 사용사례"로 번역하는 것이 보통이지만 이 글에서는 각 조직에서 현재 Terraform을 사용하는 방식을 지칭하면서 practices라는 단어를 사용하기 때문에 "사용사례"로 번역하는 것이 자연스럽지 않아서 "사용방법"이라고 번역하였다.

infrastructure as code는 코드로 인프라스트럭처를 관리하는 방법을 의미하지만 적절한 번역 용어가 마땅치 않아서 infrastructure as code를 영문 표기를 그대로 합니다. 더불어 이글에서 추천하고 있는 collaborative infrastructure as code도 앞부분인 collaborative만 "협업"이라고 번역하고 뒤에는 영문으로 표기하는 게 어색해서 collaborative infrastructure as code도 영문 그대로 표기하였다.

테라폼 추천 사용방법(Terraform Recommended Practices)

이 문서는 소수의 개인부터 전체 조직에까지 Terraform의 사용을 더 발전시키고자 하는 기업 사용자를 위한 안내 문서다.



소개

HashiCorp는 클라우드 기술을 도입하는 IT 조직을 돕는데 특화되어 있다. 우리가 일하면서 봤을 때 프로비저닝에서 가장 좋은 접근은 핵심 작업 흐름에 Terraform을 사용하고 조직 내 여러 팀, 역할, 애플리케이션, 배포 계층의 경계 관리에 Terraform Enterprise를 사용하는 collaborative infrastructure as code라고 생각한다. 최고 기술 수준의 프로비저닝 사용패턴에 도달하는 것은 가는 중에 여러 단계가 있는 여행이다.

이 문서에서는 우리가 추천하는 Terraform 사용패턴과 이를 적용하는 방법을 설명하고 있다. 여기서는 HashiCorp의 도구에 의존하는 기초 사용패턴에 특별히 집중하면서 이 도구들을 사용하는 과정을 다루고 있다.

  • 1편: 추천 작업 흐름의 개요는 Terraform Enterprise의 collaborative infrastructure as code 작업 흐름의 전체적인 개요이다. 여기서는 인프라를 관리하고 감시하고 사람들이 상호작용하는 방법을 설명한다.
  • 2편: 현재 프로비저닝 사용패턴의 평가는 현재 인프라스트럭처 프로비저닝 사용패턴의 상태 평가를 돕는 질문 목록이다. 아직 적용할 필요가 있는 기초 사용패턴을 이해하고 집중할 수 있도록 프로비저닝과 관련된 운영 성숙도의 네가지 단계를 정의한다.
  • 3편: 프로비저닝 사용패턴을 발전시키는 방법에서는 운영 성숙도의 네가지 단계로 프로비저닝 사용패턴을 발전시키는 방법에 대한 안내이다. 많은 조직이 이미 이 단계 가운데 어딘가에 있으므로 2편에서 배운 것을 바탕으로 이 여행에서 어디에 있는지 알 수 있다.

    3편은 4개의 페이지로 나누어져 있다.

    • 3.1편: 수동변경에서 반자동으로 바꾸는 방법
    • 3.2편: 반자동에서 Infrastructure as Code로 바꾸는 방법
    • 3.3편: Infrastructure as Code에서 Collaborative Infrastructure as Code로 바꾸는 방법
    • 3.4편: Collaborative Infrastructure as Code로의 고급스러운 개선

1편: 추천 작업 흐름의 개요

Terraform의 목적은 어떤 인프라스트럭처든지 간에 하나의 작업 흐름으로 프로비저닝하는 것이다. 이번 편에서는 큰 규모의 조직에서 Terraform의 사용을 관리할 때 우리가 추천하는 사용패턴을 설명한다. 이는 우리가 "collaborative infrastructure as code"라고 부르는 사용패턴의 모음이다.

프로비저닝의 근본적인 도전

프로비저닝 사용패턴을 개선할 때 모두가 직면하는 두 가지 도전이 있다. 기술적 복잡성과 조직적 복잡성이 그 두 도전이다.

  1. 기술적 복잡성 - 다른 인프라스트럭처 프로바이더는 새로운 리소스를 프로비저닝할 때 다른 인터페이스를 사용하고 작업을 매일 하면서 이러한 인터페이스의 불일치성 때문에 추가 비용이 발생한다. 더 많은 인프라스트럭처와 협업자가 생길 때마다 이 비용은 더욱 커지게 된다.

    Terraform은 프로비저닝 작업을 분리해서 이러한 복잡성을 해결한다. 이는 infrastructure as code 구성을 읽고 리소스 간의 관계를 결정할 때 하나의 핵심 엔진을 사용하고 인프라스트럭처 프로바이더에서 리소스를 생성하고 수정하고 삭제할 때 다수의 프로바이더 플러그인을 사용한다. 이러한 프로바이더 플러그인은 IaaS(AWS, GCP, Microsoft Azure, OpenStack 등), PaaS(Heroku 등), SaaS 서비스(GitHub, DNSimple, Cloudflare 등)와 통신할 수 있다.

    다시 말하면 Terraform은 리소스 수준의 추상화가 아니라 작업 흐름 수준의 추상화 모델을 사용한다. 이는 인프라스트럭처를 관리할 때 하나의 작업 흐름을 사용하지만 동등하지 않은 리소스에 보편적인 개념을 적용하는 대신 각 프로바이더의 독특함을 인정한다.

  2. 조직적 복잡성 - 인프라스트럭처 규모에 따라 이를 유지하는 데는 더 많은 팀을 필요로 하게 된다. 효율적인 협업을 하려면 팀 간에 인프라스트럭처 소유권을 위임하고 충돌 없이 작업을 동시에 할 수 있도록 권한을 위임하는 것이 중요하다. Terraform과 Terraform Enterprise는 대규모 애플리케이션의 컴포넌트를 위임하듯이 인프라스트럭처를 위임하도록 할 수 있다.

    대규모 애플리케이션을 위임하기 위해 회사는 애플리케이션을 더 작게 나누고 특정 팀이 자신의 마이크로서비스 컴포넌트에 집중하게 한다. 각 마이크로서비스는 API를 제공하고 API가 변경되지 않는 한 마이크로서비스 팀은 서로의 기능에 의존하면서 동시에 변경할 수 있다.

    비슷하게 인프라스트럭처 코드도 제한된 범위를 가지고 특정 팀이 소유한 더 작은 Terraform 구성으로 분리할 수 있다. 이러한 독립적인 구성은 정보를 알리기 위해 출력 변수를 사용하고 서로 간의 워크스페이스에서 출력 데이터에 접근하려고 원격 상태 리소스를 사용한다. 마이크로서비스가 API로 통신하고 연결하듯이 Terraform 워크스페이스는 원격 상태로 연결된다.

    Terraform 구성이 느슨하게 연결되어 있다면 다른 팀에 개발과 유지 보수를 위임할 수 있다. 이를 효율적으로 하려면 코드에 대한 접근 제어가 필요하다. 버전 관리 시스템으로 누가 코드를 커밋할 수 있는지 제어할 수 있지만 Terraform은 실제 인프라스트럭처에 영향을 주기 때문에 누가 코드를 실행할 수 있는지도 관리해야 한다.

    Terraform의 중앙 실행 환경을 제공해서 모든 워크스페이스에서 조직내의 접근 관리 결정을 지원하고 시행하는 것이 Terraform Enterprise(TFE)가 프로비저닝의 조직적 복잡성을 해결하는 방법이다. 이는 동시에 개발하도록 인프라스트럭처 소유권을 위임할 수 있게 한다.

페르소나, 책임, 원하는 사용자 경험

대규모 인프라스트럭처를 관리하는 네 가지 주요 페르소나가 있다. 이러한 역할을 다른 책임과 요구사항을 가지며 Terraform Enterprise는 여러 가지 도구와 권한으로 이를 지원한다.

중앙 IT

이 팀은 공통 인프라스프럭처의 사용패턴을 정의하고 팀 간의 정책을 적용하고 공유 서비스를 유지 보수할 책임을 진다.

중앙 IT 사용자는 모든 인프라스트럭처의 상태와 일치성을 볼 수 있는 대시보드가 있어서 잘못된 설정이나 기능 장애를 빠르게 수정할 수 있다. Terraform Enterprise는 Terraform의 실행 데이터와 완전히 통합되어 있고 Terraform의 워크스페이스 개념 및 실행에 맞춰서 설계되었으므로 범용적인 CI 시스템보다 더 통합된 작업 흐름 경험을 제공한다.

조직 아키텍트

이 팀은 사업 단위 내에서 전역 인프라스트럭처를 분리하고 위임하는 방법을 정의한다. 이 팀은 각 워크스페이스가 노출해야 하는 API를 정의해서 워크스페이스 간의 연결성도 만들어야 하고 조직 단위의 변수와 정책도 정해야 한다.

조직 아키텍트는 모든 워크스페이스의 상태와 연결성 그래프를 보는 대시보드를 가진다.

워크스페이스 소유자

이 사람은 여러 환경에 걸친 Terraform 구성을 구축하는 워크스페이스의 특정 세트를 가집니다. 그리고 워크스페이스의 상태와 dev, UAT, staging, production에 걸친 전체 변경사항 생명주기를 관리할 책임이 있다. 이들은 자신의 도메인 영역에서 프로덕션에 변경사항을 적용하는 주요 승인자이다.

워크스페이스 소유자는 다음 사항을 원한다.

  • 인프라스트럭처 코드를 사용하는 모든 워크스페이스의 상태를 보는 대시보드
  • 환경 간에 변경사항을 적용하는(promote) 간결한 방법
  • 여러 환경의 Terraform 구성에서 사용하는 변수를 설정하는 인터페이스

워크스페이스 기여자

기여자는 infrastructure as code 구성을 갱신해서 워크스페이스에 변경사항을 제출한다. 이 사람들은 보통 프로덕션에 변경사항을 적용하도록 승인하지는 않지만 dev, UAT, staging,에는 변경사항을 만든다.

워크스페이스 기여자는 워크스페이스에 변경사항을 제툴하고 워크스페이스 간에 변경사항을 적용하는 워크플로우를 가진다. 이들은 워크스페이스 변수의 서브 셋과 각자가 소유한 개인 변수를 수정할 수 있다.

워크스페이스 기여자는 보통 Terraform의 운영 모델과 명령행 인터페이스에 이미 익숙한 상태고 TFE 웹 인터페이스에 빠르게 적응할 수 있다.

추천 Terraform 워크스페이스 구조


워크스페이스에 대해

Terraform Enterprise에서 조직의 주요 단위는 워크스페이스다. 워크스페이스는 Terraform이 실행해야 하는 모든 것의 묶음이고 Terraform 구성(보통 VCS 저장소에서 가져온다.), 구성의 변숫값, 실행시마다 작업을 추적하기 위한 상태 데이터를 모두 포함한다.

오픈 소스 Terraform에서 워크스페이스는 로컬 디스크에 저장된 별도의 상태 파일일 뿐이다. TFE는 워크스페이스에 접근 제어를 하고 실행 상태를 감시하는 등 공유 리소스를 유지하고 있다.

Terraform 구성마다, 환경마다 하나의 워크스페이스

워크스페이스는 TFE가 관리를 위임하기 위한 기본 도구로 여기서 워크스페이스의 구조는 조직의 권한 구조와 일치해야 한다. 인프라스트럭처 컴포넌트의 환경마다 하나의 워크스페이스를 사용하는 것이 가장 좋은 접근이다. 즉, Terraform 구성 * 환경 = 워크스페이스다.

이 접근은 다른 도구들이 환경을 보는 관점과는 다르다. 특히 프로덕션이나 스테이징 환경 등 모든 것을 하나의 Terraform 워크스페이스로 관리하면 안 된다. 대신 더 작은 워크스페이스를 만들어서 위임하기 쉽게 해야 한다. 이는 동시에 모든 구성이 완전히 같은 환경을 사용하지 않아도 됨을 의미한다. UAT 환경이 보안 인프라스트럭처에 맞지 않는다면 이를 사용하도록 강제하지 않아야 한다.

컴포넌트와 환경을 둘 다 사용해서 워크스페이스의 이름을 지어라. 예를 들어 내부 빌링 앱과 네트워킹 인프라스트럭처를 관리하는 Terraform 구성이 있다면 다음과 같은 워크스페이스 이름을 사용할 수 있다.

  • billing-app-dev
  • billing-app-stage
  • billing-app-prod
  • networking-dev
  • networking-stage
  • networking-prod

워크스페이스의 위임

각 워크스페이스가 하나의 인트라스트럭처 컴포넌트의 한 환경이므로 컴포넌트의 소유권을 위임하고 환경 간의 코드 적용을 관리하기 위해 워크스페이스마다 접근 제어를 사용할 수 있다. 예를 들면 다음과 같다.

  • 컴포넌트 관리를 돕는 팀은 dev나 staging에서 변수를 실행하거나 수정하는데 Terraform을 사용하기 시작할 수 있다.
  • 컴포넌트의 소유자나 시니어 기여자는 다른 기여자의 작업을 리뷰한 후에 프로덕션에서 Terraform 실행을 시작할 수 있다.
  • 중앙 IT와 조직의 아키텍트는 모두가 어떤 작업을 해야 하는지 정확히 알 수 있도록 모든 워크스페이스의 권한을 관리할 수 있다.
  • 해당 컴포넌트를 관리하는 역할을 가지지 않은 팀은 해당 워크스페이스에 접근하지 못한다.

TFE를 효과적으로 사용하려면 조직이 가진 책임 구분에 맞게 워크스페이스와 권한의 구분을 확실하게 나누어야 한다. 워크스페이스를 효율적으로 분리하기가 어렵다면 인프라스트럭처 영역에서 책임이 혼란스럽고 명확하지 않음을 보여주는 것이다. 실제로 그렇다면 해당 코드의 문제를 해결하고 소유권의 경계를 더 명확하게 해야 할 때이다.

관련 워크스페이스 간의 변경사항 적용(도입 예정)

차기 TFE 버전에서는 워크스페이스 간 적용 파이프라인을 만들 수 있게 할 것입니다.

앞에서 설명했듯이 각 워크스페이스는 해당 Terraform 구성에 한정된 환경이다. 지금은 더 높은 환경에서 사용하는 코드를 이전 환경에서 성공적으로 통과한 코드와 일치하도록 바꿈으로써 수동으로 코드 적용을 해야 한다.

나중에는 버전 관리자에서 직접 코드를 가져오는 대신 적용 관계를 설정하고 더 높은 환경은 이전 환경에서 직접 코드를 가져올 수 있다. 이는 높은 환경에서는 확인된 코드만 실행됨을 보장할 수 있다.

변수와 정책 관리

Terraform Enterprise는 계층 순서에 따라 서로 덮어쓸 수 있는 변수를 여러 곳에서 설정할 수 있다. 이 모든 단계에서 TFE는 Vault에 변수를 안전하게 저장한다.

조직

모든 워크스페이스는 조직 수준의 기본 변수를 사용할 수 있다. 예를 들어 조직은 모든 리소스에 사용하는 기본 빌링 태그를 지정할 수 있다.

조직은 최하위 단계의 계층이다. 이어서 설명하는 모든 단계는 이 계층을 덮어쓸 수 있다.

워크스페이스

워크스페이스 수준의 변수다. 대부분의 변수는 워크스페이스 계층에 저장한다. AMI ID, 머신 개수, SSL 인증서 등을 저장하기 좋은 계층이다.

사용자

특정 사용자에게 연결된 변수로 모든 워크스페이스에서 사용되며 워크스페이스의 변수를 덮어쓸 수 있다. 예를 들어, 각 사용자는 자신의 ARN과 연결할 수 있다.

다음

이제 Terraform Enterprise 작업 흐름의 윤곽을 알게 되었다. 이제는 조직의 프로비저닝 사용패턴을 평가해볼 차례이다.

2편: 현재 프로비저닝 사용패턴의 평가

Terraform Enterprise는 여러 가지 기초적인 IT 사용패턴에 의존하고 있다. Terraform Enterprise의 collaborative infrastructure as code 작업 흐름을 실행하기 전에 현재 어떤 사용패턴을 이미 사용하고 있고 어떤 사용 패턴을 적용해야 하는지를 이해해야 한다.

아래 내용은 퀴즈나 인터뷰 형식으로 작성했고 많은 조직에서 우리가 알게 된 운영 성숙도의 단계를 의미하는 여러 가지 답변이 있다. 메모장을 옆에 놓고 아래 내용을 읽으면서 현재 조직이 자동화와 협업에서 개선할 수 있는 질문을 적어봐라.

이 퀴즈에는 통과나 실패 점수는 없지만, 현재 조직의 답변이 무엇인지 아는 것은 중요하다. 일단 가장 관심을 가져야 하는 IT 사용패턴이 무엇인지 알고 나면 현재 상태에서 우리가 추천하는 사용패턴까지 갈 수 있는 가장 직접적인 방법을 3편에서 소개할 것이다.

운영 성숙도의 4가지 단계

각 질문에는 여러 답변이 있으며 각 답변은 운영 성숙도의 각 단계와 맞는다. 여기서 말하는 단계는 다음과 같다.

  1. 수동

    • 인프라스트럭처를 UI나 CLI로 프로비저닝한다.
    • 구성 변경사항을 추적할 수 있는 히스토리가 없고 그 내용을 전혀 볼 수 없다.
    • 적절한 작명 표준이 없거나 제한적으로만 있다.
  2. 반자동

    • 인프라스트럭처를 UI/CLI, infrastructure as code, 스크립트, 구성 관리의 조합으로 프로비저닝한다.
    • 각 조직이 다른 기록 유지 방법을 사용하므로 제한적으로만 추적 가능하다.
    • 기록유지 방법이 다르므로 롤백하기가 어렵다.
  3. infrastructure as code

    • 인프라스트럭처를 Terraform OSS로 프로비저닝한다.
    • 프로비저닝과 배포 프로세스가 자동화되어 있다.
    • 인프라스트럭처 구성에 일관성이 있고 필요한 모든 내용이 완전히 문서로 만들어 져 있다.(시스템관리자 머릿속에만 있는 것은 없다.)
    • 수정 히스토리를 기록하려고 소스 파일을 버전 관리에 저장하고 있다. 필요하다면 이전 버전으로 롤백할 수 있다.
    • 일부 Terraform 코드가 모듈로 분리되어 있어서 조직의 공통 아키텍처 패턴을 일관성 있게 재사용하도록 권장한다.
  4. collaborative infrastructure as code

    • 조직 내의 사용자들이 Terraform으로 인프라스트럭처를 안전하게 프로비저닝 할 수 있고 이때 충돌이 발생하지 않으며 접근 권한을 명확하게 이해할 수 있다.
    • 조직 내의 전문가가 표준화된 인프라스트럭처 템플릿을 만들 수 있고 초심자는 조직의 인프라스트럭처 권장 사용사례를 따르기 위해 이 템플릿을 사용할 수 있다.
    • 워크스페이스의 접근제어로 워크스페이스의 커미터와 승인자가 프로덕션 환경을 보호할 수 있다.
    • Terraform을 직접 작성하지 않는 기능 그룹은 인프라스트럭처의 상태를 볼 수 있고 Terraform Enterprise의 UI로 변경할 수 있다.

이번 편을 마지막까지 보고 운영 성숙도에서 현재 어떤 단계에 있는지 명확하게 이해해야 한다. 3편에서는 현 단계에서 다음 단계로 이동하는 추천 방법을 설명할 것이다.

아래 질문의 답변은 조직이 인프라스트럭처를 프로비저닝하고 그 변경사항의 작업 흐름, 운영 모델, 보안 모델에 사용하는 방법을 이해하는 데 도움이 될 것이다.

현재 사용패턴을 이해하고 나면 Terraform Enterprise를 도입하는데 남은 단계를 구분할 수 있다.

현재의 구성 및 프로비저닝 사용패턴

현재 조직에서 어떻게 인프라스트럭처를 구성하고 프로비저닝 하는가? 자동화되고 일관적인 사용패턴은 인프라스트럭처를 더 알기 쉽고 신뢰할 수 있게 하며 장애 처리에 드는 시간을 줄일 수 있게 한다.

아래 질문은 구성과 프로비저닝 자동화의 현재 단계를 평가하는 데 도움을 준다.

Q1. 인프라스트럭처를 현재 어떻게 관리하고 있는가?

  1. UI나 CLI로 관리한다. 이는 일회성 작업에는 가장 쉬운 방법처럼 보이지만 반복적인 작업에서는 가치 있는 엔지니어링 시간을 가장 많이 소비하게 만든다. 변경사항을 추적하고 관리하기도 어렵다.
  2. 재사용 가능한 명령행 스크립트를 사용하거나 UI와 infrastructure as code의 조합으로 관리한다. 이는 순수 애드혹(ad-hoc) 관리보다는 더 빠르고 신뢰할 수 있으며 자주 해야 하는 작업을 반복할 수 있지만, 일관성이 없고 버저닝되지 않으므로 시간이 지날수록 관리하기가 어려워진다.
  3. infrastructure as code 도구(Terraform, CloudFormation)로 관리한다. infrastructure as code는 확장성 있고 반복 가능하면서 버저닝이 되는 인프라스트럭처를 구성할 수 있게 한다. 각 운영자의 생산성이 엄청나게 증가하고 적절하게 사용하면 환경 간 일관성을 강제할 수 있다.
  4. 범용적인 자동화 프레임워크(Jenkins + 스크립트 / Jenkins + Terraform 등)로 관리한다. 이는 관리 작업 흐름을 중앙화하지만 프로비저닝 작업에 맞춰서 만들어진 도구는 아니다.

Q2. 서비스 프로바이더 계정이 어떤 위상에 있는가?

  1. 수평적 구조로 하나의 계정을 사용한다. 모든 인프라스트럭처를 같은 계정으로 프로비저닝한다.
  2. 수평적 구조로 여러 계정을 사용한다. 환경마다 하나의 계정으로 여러 가지 인프라스트럭처 프로바이더를 사용해서 인프라스트럭처를 프로비저닝한다.
  3. 트리 계정을 사용한다. 이는 마스터 빌링 계정, 감사(audit)/보안/로깅 계정, 프로젝트/환경에 한정된 인프라스트럭처 계정으로 분리된다.

Q3. 다른 환경의 인프라스트럭처를 어떻게 관리하고 있는가?

  1. 수동으로 관리한다. 모든 것을 수동으로 작업하고 구성 관리를 하지 않는다.
  2. 사일로(Silo)로 관리한다. 각 애플리케이션 팀은 자신들만의 방법으로 인프라스트럭처를 관리한다. 일부는 수동으로 관리하고 또 일부는 infrastructure as code나 스크립트를 사용한다.
  3. 환경마다 다른 코드 베이스로 infrastructure as code를 사용한다. infrastructure as code 구성에 여러 가지 코드 베이스를 사용하면서 환경 내에서 코드 적용 절차가 없다면 한 환경에서 다른 환경으로의 변경사항 적용을 추적할 수 없게 된다.
  4. 하나의 코드 베이스로 infrastructure as code를 사용하고 환경 변수만 다르게 사용한다. 환경과 관계없이 모든 리소스를 같은 코드로 프로비저닝하고 예측 가능한 방법으로 배포 계층에 맞춰 변경사항을 적용한다.

Q4. 여러 팀이 인프라스트럭처 구성과 코드를 어떻게 공유하고 협업하는가?

  1. 안한다. infrastructure as code를 사용하지 않는다.
  2. 로컬에서 관리한다. 인프라스트럭처 구성을 로컬에서 관리하며 이메일, 문서, 스프리드 시트로 공유한다.
  3. 티켓 시스템을 이용한다. 변경을 요청하는 이슈나 문제/사고에 관한 티켓으로 코드를 공유한다.
  4. 중앙화되어 있지만 버전 관리는 하지 않는다. 코드를 공유된 파일시스템에 저장하고 보안 그룹을 통해 안전하게 관리한다. 변경사항을 버저닝하지 않고 롤백은 백업이나 스냅숏에서 복구하는 방법을 이용한다.
  5. 구성을 버전 관리 시스템(VCS, Git 저장소 등)에 저장하고 이를 통해 협업한다. 여러 팀은 VCS 작업 흐름을 통해 인프라스트럭처 구성 작업을 협업하고 프로덕션에 적용하기 전 인프라스트럭처 변경사항을 리뷰할 수 있다. 이는 가장 성숙한 접근으로 기록을 가장 잘 보관하면서 여러 부서와 팀이 서로 그 내용을 볼 수 있다.

Q5. infrastructure as code를 작성할 때 재사용할 수 있는 모듈을 사용하는가?

  1. 모든 것을 수동으로 작업한다. 현재 infrastructure as code를 사용하지 않는다.
  2. 모듈을 사용하지 않는다. infrastructure as code를 사용하지만 주로 일회성 구성으로 사용한다. 사용자는 보통 코드를 공유하거나 재사용하지 않는다.
  3. 각 팀 내부에서 모듈을 사용하지만, 팀끼리는 모듈을 공유하지 않는다.
  4. 모듈을 전체 조직에서 공유한다. 공유 소프트웨어 라이브러리처럼 공통 인프라스트럭처 패턴을 위한 모듈을 갱신할 수 있고 전체 조직이 이 혜택을 입는다.

현재의 변경사항 관리 작업 흐름

변경사항 관리는 제품이나 시스템에 변경사항을 조정하고 승인하는 정식 절차를 말한다. 변경사항 관리 절차의 목표는 다음과 같다.

  • 서비스가 깨지는 경우를 최소화한다.
  • 롤백을 줄인다.
  • 변경과 관련된 전체 비용을 줄인다.
  • 불필요한 변경을 막는다.
  • 다른 사용자가 만든 변경사항을 주지 않으면서 사용자가 변경할 수 있게 한다.

아래 질문은 변경사항 관리 작업 흐름의 성숙도를 평가할 수 있게 한다.

Q6. 인프라스트럭처 변경에 대한 접근 권한을 어떻게 관리하는가?

  1. 접근 권한을 제한하거나 감사(audit)하지 않는다. 플랫폼 팀의 모든 사람은 전체 인프라스트럭처를 유연하게 생성하고 변경하고 제거할 수 있다. 이는 불안정하면서 복잡한 시스템을 만들어서 관리하기가 어려워진다.
  2. 접근 권한을 제한하지는 않고 감사(audit)만 한다. 상황이 발생한 뒤에 변경사항을 추적하기는 쉽지만 인프라스트럭처의 안정성을 사전에 보호하지는 못한다.
  3. 서비스 프로바이더 계정에 기반을 둬서 접근 권한을 제한한다. 팀의 사람들은 자신이 책임지는 환경에 따라 다른 계정으로 관리자 접근 권한을 가진다.
  4. 사용자 역할에 따라 접근 권한을 제한한다. 모든 접근 권한을 인프라스트럭처 프로바이더에서 사용자 역할에 따라 제한한다.

Q7. 기존에 존재하는 인프라스트럭처를 변경하는 절차는 무엇인가?

  1. 머신에 원격으로 접속해서 수동으로 변경한다. 반복적인 수동 작업은 비효율적이며 휴먼 에러가 발생하기 쉽다.
  2. 런타임 구성 관리(Puppet, Chef 등)를 사용한다. 구성 관리 도구를 사용하면 읽기 좋으면서 감사(audit)할 수 있는 코드에 기반을 두고 빠르고 자동화된 변경사항을 만들 수 있다. 하지만 정적인 결과물(artifact)를 만들지 않으므로 해당 구성의 결과를 항상 100%로 반복할 수 없고 롤백도 부분적으로만 신뢰할 수 있다.
  3. 불변 인프라스트럭처(이미지, 컨테이너)를 사용한다. 정적인 배포 결과물(artifact)로 불변 컴포넌트를 모든 배포에서 교체할 수 있다(바로 변경하는 대신). 일시적인(ephemeral) 계층과 상태를 보관하는 계층 간에 경계가 뚜렷하게 관리하고 있다면 불변 인프라스트럭처를 훨씬 테스트하고 유효성을 검증하고 롤백하기 쉽게 할 수 있다.

Q8. 애플리케이션을 어떻게 배포하는가?

  1. 수동(SSH, WinRM, rsync, robocopy 등)으로 배포한다. 반복적인 수동 작업은 비효율적이며 휴먼 에러가 발생하기 쉽다.
  2. 스크립트(Fabric, Capistrano, 커스텀 스크립트 등)로 배포한다.
  3. 구성 관리 도구(Chef, Puppet, Ansible, Salt 등)를 사용하거나 CloudFormation 템플릿이나 Terraform 구성 파일에 사용자 데이터를 전달해서 배포한다.
  4. 스케쥴러(Kubernetes, Nomad, Mesos, Swarm, ECS 등)로 배포한다.

현재의 보안 모델


Q9. 인프라스트럭처 서비스 프로바이더의 자격증명을 어떻게 관리하고 있는가?

  1. 소스코드에 하드코딩 되어 있다. 이는 보안에 아주 좋지 않다.
  2. 인프라스트럭처 프로바이더의 역할을 사용한다.(AWS의 EC2 instance role 등) 서비스 프로바이더는 제공하는 머신이 무엇인지 알고 있으므로 실제 사용자의 자격증명을 복사해서 제공하지 않고도 API 요청을 보낼 때 일부 머신에 권한을 줄 수 있다.
  3. 비밀정보 관리 솔루션을 사용한다.(Vault, Keywhis, Par처럼) 이 방법을 추천한다.
  4. 짧은 생명을 가지는 토큰을 사용한다. 배포한 임시 자격증명이 빠르게 만료되어 부당하게 사용하기가 아주 어려우므로 가장 안전한 방법의 하나다. 하지만 이는 비밀정보 관리 솔루션보다 사용하기가 더 복잡할 수 있다.

Q10. 인프라스트럭처 프로바이더가 제공하는 사용자와 객체를 어떻게 관리하는가?(로그인, 접근 권한, 역할 관리 등)

  1. 엔지니어들끼리 공유하는 공용 'admin', 'superuser' 계정을 사용한다. 이는 인프라스트럭처 프로바이더 계정이 누출될 가능성이 높다.
  2. 개인이 소유한 사용자 계정을 사용한다. 이는 자격증명을 잃어버릴 가능성을 줄이고 복구하기가 더 쉽지만, 팀이 커지면 확장하기가 어렵다.
  3. LDAP이나 Active Directory와 통합해서 사용한다. 이는 공유 계정보다는 훨씬 안전하지만, 회사 네트워크에 프로바이더가 접근할 수 있도록 설정하는 등 추가적인 아키텍처적인 고려를 해야한다.
  4. OAuth나 SAML을 통한 통합인증(single sign-on)을 사용한다. 이는 프로바이더가 회사 네트워크에 접근하도록 할 필요 없이 인프라스트럭처 프로바이더가 토큰 기반으로 접근할 수 있게 한다.

Q11. 인프라스트럭처 프로바이더 환경들에서 다른 사용자가 만든 변경사항을 어떻게 추적하는가?

  1. 로깅을 하지 않는다. 누가 언제 변경했는지 기록하지 않으면 감사(audit)와 장애 처리가 몹시 어려울 수 있다.
  2. 수동으로 변경사항을 작성한다. 사용자가 인프라스트럭처에 변경한 내용을 공유된 문서에 수동으로 작성한다. 이는 휴먼 에러가 발생하기 쉬운 방법이다.
  3. 감사(audit) 기록 서비스나 로그 관리 서비스(CloudTrail, Loggly, Splunk 등)에 API를 호출해서 모든 것을 로깅한다. 이는 장애처리나 보안 이슈가 발생했을 때 감사(audit) 기록을 볼 수 있게 한다.

Q12. 예전 직원의 접근 권한을 어떻게 철회하는가?

  1. 즉시 처리하지만, 수동으로 철회한다. infrastructure as code를 사용하지 않는다면 인프라스트럭처 프로바이더의 콘솔에서 수동으로 직원의 접근 권한을 제거하는 것이 가장 빠르고 쉬운 방법이다.
  2. 지연해서 처리하며 다른 릴리스의 포함해서 처리한다. 릴리스 과정과 아주 심하게 연결되어 있으며 대부분의 보안 변경사항을 프로덕션에 적용할 때 CAB(변경사항 위원회, Change Advisory Board)의 회의를 통과해야 한다면 이 작업이 지연될 수 있다.
  3. 즉시 처리하며 infrastructure as code에 핫픽스로 처리한다. 가장 안전하고 추천하는 방법이다. 직원이 빌딩을 나가기도 전에 접근 권한을 제거해야 한다.

프로비저닝 사용패턴의 전체적인 성숙도 평가

위의 질문을 모두 리뷰한 후 작성한 노트를 살펴보고 조직의 전체 성숙도 수준을 평가해봐라. 현재의 사용패턴이 주로 수동인가? 반자동인가? infrastructure as code인가? collaborative infrastructure as code인가?

현재의 상태를 기억한 채 다음 편을 읽어보자.

다음

현재 사용패턴을 자세히 살펴봤다. 이제 이를 개선하기 시작할 차례이다.


이 글은 Terraform 추천 사용패턴 #2로 이어진다.

2017/11/26 20:28 2017/11/26 20:28

Terraform workspace의 활용

Terraform으로 인프라스트럭처를 관리하면 기존보다 훨씬 체계적으로 관리할 수 있고 히스토리를 추적하기도 좋아지지만, 실제 인프라스트럭처를 직접 다루기 때문에 실수에 대한 걱정이 있는 것이 사실이다. 물론 이를 방지하기 위해 plan으로 미리 확인해 볼 수 있지만 그래도 잘못 생각하고 apply를 해서 리소스가 제거된다거나 잘못 변경되어 장애가 난다거나 하는 가능성이 충분히 있다. 그리고 이게 애플리케이션이 아니라 인프라스트럭처의 설정이므로 일부 설정은 적용을 해봐야 동작 여부를 확인 가능한 것들이 있다. 그래서 항상 프로덕션에서 apply를 할 때는 두려움이 생겨서 2~3번씩 확인해 보게 된다.

특히 인프라스터럭처의 경우 소소한 변경은 다시 적용하면 되지만 리소스를 잘못 제거하면 장애가 크게 발생하거나 최악으로는 원래 상태로 롤백하기 어려운(혹은 오래 걸리는) 상황이 발생할 수 있다. 100% Terraform으로 관리하고 있다면 롤백 걱정이 줄어들겠지만 복잡한 회사 인프라스트럭처에서 100% 관리하에 두는 것은 쉽지 않다.

이렇게 Terraform을 사용하다 보니 인프라에서 프로덕션 외에 스테이징이나 테스트환경이 있으면 좋겠다는 생각이 자연히 들게 되었다. Infrastructure as code를 하다 보면 소프트웨어 개발에서 오랫동안 쌓아온 패턴을 거의 비슷하게 활용할 수 있다는 것을 알게 되는데 서버 애플리케이션을 배포할 때 코드를 배포판으로 만들어서 테스트 서버나 스테이징 서버에서 테스트하고 이상이 없으면 똑같은 코드를 프로덕션에도 배포하도록 배포 절차를 만드는 것이 일반적이다. 이를 통해 테스트한 소프트웨어가 프로덕션에 배포될 수 있게 보장하는 것인데 Terraform으로도 똑같이 하고 싶어졌다.

프로덕션 인프라스트럭처를 직접 조작하는 것이 부담되고 실수 가능성이 있으므로(특히, 민감한 설정 부분이라면 더욱...) 아예 VPC 레벨이나 계정 차원에서 테스트나 스테이징용 인프라스트럭처가 있고 이쪽에서 설정하고 설정이 이상 없음을 확인하면 같은 설정을 그대로 프로덕션 인프라스트럭처에 적용해서 안심하고 작업할 수 있게 하고 싶었다.(물론 제대로 되려면 여기서 프로덕션 적용은 자동화가 이루어져야 할 것이다.)

워크스페이스

Terraform에는 워크스페이스라는 기능이 있다. 이 기능은 Terraform 0.9 버전에서는 environment라는 이름으로 존재했는데 environment라는 단어의 의미가 모호하다는 이유로 0.10부터는 workspace로 바뀌었다.

이 기능이 존재를 알았을 때부터 위에서 말한 문제를 해결할 수 있을지 확인해 보고 싶었다. 사실 테스트는 지난 9월 정도에 했지만, 블로그에 정리는 이제야 하게 된다.(어느새 2달이!)

Terraform을 사용할 때 인지할 수는 없지만 이미 워크스페이스 내에서 작업을 하고 있다. 기본 워크스페이스는 default라는 이름을 가지는데 이 워크스페이스가 기본 이름이고 제거할 수 없다. 그래서 명시적으로 워크스페이스를 지정하지 않으면 default 워크스페이스를 사용하게 된다.

사용방법

terraform workspace 명령어를 사용하면 관련 명령어를 볼 수 있다.(여기서 사용하는 버전은 Terraform 0.11.0이다.)

$ terraform workspace
Usage: terraform workspace

  Create, change and delete Terraform workspaces.


Subcommands:

    show      Show the current workspace name.
    list      List workspaces.
    select    Select a workspace.
    new       Create a new workspace.
    delete    Delete an existing workspace.

terraform workspace show로 현재 워크스페이스가 default임을 볼 수 있다.

$ terraform workspace show
default

terraform workspace list를 입력하면 전체 워크스페이스의 목록을 볼 수 있고 현재 사용 중인 워크스페이스에 * 표시가 있음을 볼 수 있다.

$ terraform workspace list
* default

terraform workspace new WORKSPACE_NAME으로 새로운 워크스페이스를 생성할 수 있다.

$ terraform workspace new demo
Created and switched to workspace "demo"!

You're now on a new, empty workspace. Workspaces isolate their state,
so if you run "terraform plan" Terraform will not see any existing state
for this configuration.

$ terraform workspace list
  default
* demo

여기에 나온 대로 워크스페이스를 새로 생성하면 상태 파일(.tfstate)이 분리된다. 같은 구성 파일(.tf)을 사용하지만 상태 파일은 분리가 되므로 별도로 관리할 수 있게 된다.

$ terraform workspace select default
Switched to workspace "default".

terraform workspace select WORKSPACE_NAME로 git에서 브랜치를 바꾸듯이 워크스페이스를 변경할 수 있다.

워크스페이스의 활용

앞에서 말한 문제를 해결하려고 어떻게 사용 가능한지를 간단히 테스트해보자.

resource "aws_s3_bucket" "main" {
  bucket = "outsider-test${terraform.workspace == "default" ? "-stage" : "-${terraform.workspace}"}"
  acl    = "private"

  versioning = {
    enabled = true
  }
}

위는 S3 버킷을 만드는 간단한 Terraform 구성 파일이다. 워크스페이스 개념 자체는 간단하므로 예시로 너무 복잡한 구성을 사용하면 이해하기가 어려울 것 같아서 다른 의존성이 별로 없는 S3 버킷을 예제로 선택했다. VPC나 EC2 등에서 사용하려면 Terraform 구성파일을 잘 작성하는 것만이 남은 작업이 될 것이다.

여기서는 S3 버킷을 만드는데 중요한 부분은 다음 부분이다.

outsider-tf-demo${terraform.workspace == "default" ? "-test" : "-${terraform.workspace}"}

terraform.workspace는 현재의 워크스페이스 이름을 담고 있는 변수다. 이 값을 비교해서 여기서처럼 워크스페이스에 따라 다른 이름을 줄 수 있다. 다른 경우라면 워크스페이스 이름을 보고 다른 Security Group을 지정하거나 VPC를 다르게 지정하거나 할 수 있다.

아무런 작업을 하지 않으면 default 워크스페이스를 사용하므로 실수를 방지하기 위해서 default를 테스트 용도로 사용하고 프로덕션 등 다른 환경을 위해서는 워크스페이스를 명시적으로 변경해서 하도록 했다. 그래서 여기서 버킷 이름이 outsider-tf-demo를 접두사로 쓰는데 기본 워크스페이스에서는 outsider-tf-demo-test가 버킷 이름이 되고 production 워크스페이스라면 outsider-tf-demo-production이 버킷 이름이 된다.

$ terraform workspace list
* default
  demo

$ terraform plan
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  + aws_s3_bucket.main
      id:                      <computed>
      acceleration_status:     <computed>
      acl:                     "private"
      arn:                     <computed>
      bucket:                  "outsider-test-stage"
      bucket_domain_name:      <computed>
      force_destroy:           "false"
      hosted_zone_id:          <computed>
      region:                  <computed>
      request_payer:           <computed>
      versioning.#:            "1"
      versioning.0.enabled:    "true"
      versioning.0.mfa_delete: "false"
      website_domain:          <computed>
      website_endpoint:        <computed>


Plan: 1 to add, 0 to change, 0 to destroy.

default 워크스페이스인 상태에서 terrafom plan을 하면 S3 버킷 이름이 outsider-test-stage가 된 것을 볼 수 있다. 당연히 apply하면 이 이름 그래도 적용이 되므로 여기서는 plan까지만 했다.

$ terraform workspace new production
Created and switched to workspace "production"!

You're now on a new, empty workspace. Workspaces isolate their state,
so if you run "terraform plan" Terraform will not see any existing state
for this configuration.

$ terraform workspace list
  default
  demo
* production

$ An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  + aws_s3_bucket.main
      id:                      <computed>
      acceleration_status:     <computed>
      acl:                     "private"
      arn:                     <computed>
      bucket:                  "outsider-test-production"
      bucket_domain_name:      <computed>
      force_destroy:           "false"
      hosted_zone_id:          <computed>
      region:                  <computed>
      request_payer:           <computed>
      versioning.#:            "1"
      versioning.0.enabled:    "true"
      versioning.0.mfa_delete: "false"
      website_domain:          <computed>
      website_endpoint:        <computed>


Plan: 1 to add, 0 to change, 0 to destroy.

이번에는 production이라는 워크스페이스를 만든 뒤에 plan을 하면 S3 버킷 이름이 outsider-test-production로 바뀐 것을 볼 수 있다.

구성 파일은 하나도 바꾸지 않은 상태에서 워크스페이스의 변경만으로 상태를 별도로 관리하면서 워크스페이스에 따라 달라지는 값을 다르게 줄 수 있게 되었다. 하나의 구성파일을 잘 만들어 놓고 S3 버킷에 원하는 정책이랑 설정을 하고 스페이징에서 테스트를 마친 뒤에 이상이 없다는 게 확인되면 워크스페이스를 production으로 변경해서 프로덕션 인프라스트럭처에 적용할 수 있다.

이렇게 하면 구성파일을 하나로 관리할 수 있으니 스테이징과 프로덕션의 인프라를 완전히 같게 맞춰놓을 수 있고 스테이징에서 테스트를 마친 뒤에 프로덕션에 적용할 수 있으므로 좀 더 적극적으로 인프라스트럭처를 개선하면서도 프로덕션에서 장애가 발생할 확률을 줄일 수 있다.

일단 워크스페이스를 쓰면 내가 고민했던 문제를 해결할 수 있다는 것은 알았지만 실제 구성 파일은 S3보다 훨씬 더 복잡하므로 구성파일을 작성하는데 초기에는 좀 더 큰 노력이 들 것 같다. 그리고 프로덕션 적용을 자동화해야 더 의미가 있는데 이 부분까지 구축하는 것은 꽤 큰 작업이기는 하다.

2017/11/19 23:25 2017/11/19 23:25