Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

구성(Configuration) 복잡도의 저주

최근 Docker를 만든 Solomon Hykes의 새 프로젝트인 CI/CD 파이프라인 Dagger를 조금씩 살펴보고 있는데 Dagger가 BuildKit과 CUE 기반이라서 문서를 읽을수록 CUE를 좀 알아야 겠다는 생각하고 있었다. CUE를 알아서 Dagger의 파이프라인 정의를 이해할 수 있어서...

Dagger 문서에서 구성(Configuration, 이하 "구성") 언어에 관해 The Configuration Complexity Curse라는 글을 추천해 주고 있어서 찬찬히 읽어볼 겸 번역을 했다. 구성 언어에 관해 사실 지금 YAML에도 큰 불만은 없었기에 왜 CUE가 필요한지, 어떤 문제를 해결하는지 궁금했다. 물론 오히려 YAML에 불만이 많았다면 자세히 살펴보지 않아도 빠르게 이해할 수 있었을 것이기에 CUE가 어떤 문제를 해결하는지 더 이해해 보려는 단계에 있다.

해당 글은 2019년에 작성된 글이라 지금 시점에서는 시간이 좀 지나긴 했지만, 글의 저자인 LinkedIN의 SRE인 Cedric Charly허락받고 번역한 글이다.



구성(Configuration) 복잡도의 저주

YAML 엔지니어가 되지 마세요

자신이 업계에 막 진입한 새로운 소프트웨어 엔지니어라고 생각해 보자. 이론을 공부하고 주말에 사이드 프로젝트를 하면서 준비가 되었다고 생각했다. 하지만 이제 새로운 도구와 개념의 파도에 휩싸이게 된다. 마이크로 서비스? REST? 클라우드 컴퓨팅? RPC(IDL은 무엇인가?)? Docker(컨테이너는 무엇인가?)? Kubernetes? 지속적 통합? 지속적 배포? 배테랑이라고 하더라도 천천히 끓는 물에 있는 개구리처럼 어느 날 하늘을 보고 일이 복잡해졌다는 것을 깨닫게 된다.

어떻게 이렇게 된 것일까? 이들 각각은 유용해 보이지만 이 도구들을 함께 잘 사용하는 방법을 직접 찾아내야 한다. 먼저 도구를 YAML(아주 많은 YAML)로 구성해야 한다. 이제 이 도구는 다른 모든 도구와 함께 동작하도록 통합되어야 한다. 운이 좋다면 이러한 복잡성을 패키징하고 추상화해주는 플랫폼 팀이 회사 내부에 있을 수도 있다. 그렇지 않다면 이 모든 도구를 포함하는 지나치게 복잡한 시스템을 만들게 되어 단순히 모든 것을 온전히 유지보수하기 위해 구성을 조정해야 한다.

터널의 끝에 빛이 있다고 생각하지만, 이 업계 전반에 걸쳐 소프트웨어 플랫폼을 만드는 경험에서 겪는 문제에 Kubernetes 같은 최첨단 프로젝트조차도 고통받는다.

Kubernetes: 맨 끝에 있는 거북이

YAML 파일을 직접 작성하고 kubectl로 클러스터에 적용한다. 새로운 분산 시스템 엔지니어라는 것을 만족하기도 전에 YAML 파일에 값을 동적으로 전달할 방법이 필요하다는 것을 깨닫게 된다. 그리고 수많은 도구에 압도된다. 아래 기법의 하나를 사용해 봤거나 고려해 본 적이 있다면 동의할 것이다.

텍스트 템플릿: Jinja 같은 텍스트 템플릿 라이브러리에 관심이 가게 된다. 대부분 HTML 템플릿으로 사용해 본 적이 있으므로 여기서 사용하지 않은 이유도 없다. 값을 템플릿으로 만드는 간단한 스크립트를 작성해서 클러스터에 적용하거나 다른 무언가를 사용할 수 있다. 텍스트 템플릿 라이브러리로 구성 파일을 작성하는 것은 비극으로 가는 길이다. helm chart 템플릿을 작성해 보았다면 템플릿이 빠르게 위험해지고 깨지기 쉬워진다는 것을 알 것이다. 텍스트 수준에서 템플릿을 작성하기 때문에 템플릿을 작성하는 사람은 데이터 자체를 추상화하고 빌드하는 도구가 부족하며 들여쓰기 같은 사소한 것이 템플릿을 깨뜨린다는 것을 알게 된다. 다시 한번 반복해서 말할 필요가 있다. 데이터 구성에 텍스트 템플릿을 사용하지 마라.

데이터 계층화: YAML 위에 오버레이 상속 메커니즘을 구축하면 원시 YAML은 유지하면서 자신만의 규칙에 따라 이러한 개별 문서를 합칠 수 있는 도구로 원시 YAML을 감싸게 된다. kustomize가 가장 많이 알려진 도구로 지금은 kubectl에 통합되었다. 이는 충분히 잘 동하는 것처럼 보이고 간단한 사용 사례에는 적용할 수 있다. 하지만 데이터 구성 언어와 비교하면 구성이 복잡해지며 규모가 커질 때 이러한 전략은 무너지게 된다. 불투명한 도구에 의미가 갇히게 되고 언어 기능으로 노출되지 않기 때문에 템플릿을 작성하는 사람은 구성이 복잡해질 때 추상화와 타입 검사의 부족함을 느끼게 된다.

데이터 구성 언어(DCL): 오늘날 데이터 구성의 가장 진보한 형태로 시스템의 구성을 관리해야 한다면 이러한 도구를 추천할 것이다. 이전의 기법을 "YAML 엔지니어링"이라고 부른다면 DCL은 데이터를 정의하고 의미 수준에서 데이터와 동작하도록 설계된 실제의 언어이다. DCL의 예시로는 (kubecfg/ksonnet에서 사용되는) jsonnet, (dhall-kubernetes에서 사용되는) dhall, (isopod에서 사용되는) starlark가 있다. Google 내부에서는 (kubecfg에 영감을 준) borgcfg라는 도구를 사용하는데 이 도구는 (Kubernetes에 영향을 준) Borg deployment를 구성하기 위해 jsonnet같은 언어로 구성을 평가한다. 시스템이 복잡해지고 규모가 커지면서 DCL은 타입, 함수, 컴프리핸션, 조건 같은 추상화를 가지고 재사용할 수 있는 구성을 만들게 되었다.

그러므로 YAML을 그대로 사용하는 것보다 진보한 것을 원한다면 이러한 접근 방법 중 하나를 도입하고 개발과 릴리스 프로세스에 통합해야 한다. Kubernetes를 직접 작업할 때는 도움이 되겠지만 기반 인프라스트럭처를 구성할 때는 어떨까? AWS나 Azure 같은 클라우드의 매니지드 Kubernetes 배포에서도 CloudFormation이나 Terraform 같은 도구가 필요하다. 이러한 도구는 스택에서 리소스를 관리하기 위해 고유한 추상화를 가지거나 필요로 한다. 그래서 Kubernetes를 구성하려고 만들어진 도구를 재사용할 수 없게 되고 더 낮은 수준에서 클라우드를 구성하는 다른 시스템에 다시 통합해야 한다. 이는 거북이 위에 거북이가 올라간 소리로 들린다.

복잡한 시스템 == 복잡한 구성

위 Kubernetes 예시는 구성 관리가 얼마나 어려운지 보여주지만 사실 Kubernetes는 구성 문제를 보여주는 수많은 선언적 시스템 중 하나일 뿐이다. 규모와 복잡도가 상당히 커지면서 모든 선언적 시스템과 도구가 추상화되어야 하지만 이를 위한 공통 도구는 부재한 상황이다. Terraform 구성은 추상화할 필요가 없다고 생각할 수도 있지만 많은 팀이 인프라스트럭처를 일관되게 배포하도록 하려면 재사용할 수 있는 추상화는 아주 중요해진다. 이는 지속적 통합에도 마찬가지다. 한 프로젝트에서 YAML 파일을 유지보수하는 것은 괜찮지만 조직에 수백 개의 서비스가 있다면 노력을 들여서 일관된 자동화와 검사 세트를 만들 가치가 있다.

이 글의 핵심 주점은 이 문제의 원인에 관한 것이다.

큰 규모에서 실행되도록 시스템이 커짐에 따라 구성도 커지고 복잡해진다. 이렇게 커지는 구성의 복잡성을 관리하는 적합한 도구가 업계에 부재한 상태이다.

클라우드와 Kubernetes 같은 플랫폼의 혁신은 작은 팀에게는 너무 어렵고 복잡하던 일을 간단한 API 호출로 해결할 수 있게 만들었다. 하지만 모든 조직이 모든 플랫폼의 베스트 프랙티스 기반을 다지는 데 사용할 수 있는 라이브러리를 만드는 방법을 찾아내야 한다. 사용해야 하는 모델에 가깝다고 생각하는 현재의 DCL 조차도 큰 규모의 구성을 관리하기에는 핵심 요소가 빠져있다.

CUE, Configure, Unify, Execute

규모가 커지면서 다양한 시스템에서 사용되어야 하는 구성을 관리하는 방법이 필요하다. 이 문제를 해결하는 도구는 다음 두 가지 핵심 속성을 가져야 한다.

  1. 도구는 큰 규모의 구성을 만들고 재사용할 수 있게 유지하는데 필요한 기초 요소를 가지는 언어이다.
  2. 이러한 조합만을 위해 새로운 커스텀 도구를 만들지 않고서도 도구는 다양한 시스템에 구성을 조정하고 적용한다.

이 문제를 해결하려는 많은 언어와 구성 언어가 있다. CUE는 (새로운) 데이터 구성 언어로 이 문제를 해결하는데 새로운 접근 방식을 사용한다. 또한 CUE는 큰 규모 구성에 필요한 위 두 가지를 모두 해결하려는 비전을 가지고 있고 오늘날 우리가 볼 수 있는 너무 일반적인 도구 랩핑을 마침내 피했다. cuelang의 창시자 Marcel van Lohuizen은 Google에서 borgcfg를 작업했다. 큰 회사에서 구성을 관리하며 배운 것으로 cuelang이 오늘날의 구성 문제의 해결책이 되도록 많이 적용했다.

왜 CUE인가?

구성에는 다른 프로그래밍 모델이 필요하다

위의 Kubernetes 예제에서 범용적인 프로그래밍 언어는 사용하지 않았다. CUE가 첫 번째 구성 언어조차 아닌데 왜 이미 있는 무언가를 재사용하지 않고 완전히 새로운 도구를 선택해야 하는가?

CUE는 논리 프로그래밍의 다른 모델에 기반을 두고 있어서 구성에 적합하다. 언어의 기반은 유효성 검사, 템플릿, 쿼리, 코드 생성 같은 작업을 일등급 기능으로 만든다. CUE는 그래프 통합(graph unification)을 중심으로 설계되었다. 그래프 통합은 타입과 값의 세트가 방향을 가진 그래프로 모델링 될 수 있어서 모든 그래프의 가장 구체적인 표현으로 통합될 수 있다. CUE에서 그래프는 구성 구조체이고 같은 키의 값은 가장 구체적인 값으로 간소화된다. 그래프 통합 모델은 계산 언어학(computational linguistics)에서 성공적으로 사용되었는데 계산 언어학에서는 사람 언어의 문법 정의를 10만 라인의 구성으로 생각할 수 있다.

이는 예제로 보는 것이 더 이해하기 쉽다. CUE의 정의 예제를 살펴보자.

// Schema
municipality: {
  name:    string
  pop:     int
  capital: bool
}

// Schema & Data
largeCapital: municipality
largeCapital: {
  name:    string
  pop:     >5M
  capital: true
}

// Data
moscow: largeCapital
moscow: {
  name:    "Moscow"
  pop:     11.92M
  capital: true
}

여기서 정의된 3개의 구조체를 볼 수 있는데 각각은 다양한 타입과 값이 혼합되어 있다. 여기서 하나의 구조체의 타입과 값 조합이 중요하다. CUE에서 타입은 값이다. 이는 타입을 필드에 할당할 수 있고 그 즉시 구성에서 값을 제약하는 데 사용할 수 있다는 의미이다. 필드는 각 구조체에서 구체적인 값을 더 제약하는 것도 볼 수 있다. largeCapital은 인구 크기에 새로운 제약사항을 가진 municipiality이다. moscow는 모든 필드에 구체적인 값(가장 구체적인 타입)을 가지는 largeCapital이다. largeCapital, moscow 구조체 사이에서 largeCapitalmoscow를 포함하고 moscowlargeCapital의 인스턴스다.

이론적인 기초와 CUE가 다른 구성 언어와 무엇이 다른지 더 자세히 이해하고 싶다면 The Logic of CUE를 읽어보길 권한다. 이 글이 좋다면 이 비디오도 추천한다. 여기서 이론을 더 자세히 살펴보더라도 The Logic of CUE 보다 잘 설명할 수는 없을 것이다. 대신 CUE이 기반이 어떻게 구성에 유용한 기능을 가능하게 하는지 설명할 것이다.

타입 검사와 보일러 플레이트 제거

위에서 얘기한 새로운 구성 도구에 필요한 것으로 돌아가 보자. 타입과 추상화가 큰 규모의 구성을 관리하는데 가장 큰 요소이다. 타입으로 데이터에서 제약 사항을 표현하고 잠재적인 수많은 사용자에게 의도를 선언한다. 구성을 정의하고 자동화된 문서로 제공될 때 타입은 사용자를 에러에서 보호해준다. 웹사이트의 예제를 살펴보자.

Spec :: {
  kind: string

  name: {
    first:   !="" // 지정되어야 하고 비어있으면 안된다
    middle?: !="" // 선택적이지만 지정할 때는 비어있으면 안된다
    last:    !=""
  }

  // 최소는 최대보다 엄격하게 작아야 하고 반대도 마찬가지다
  minimum?: int & <maximum
  maximum?: int & >minimum
}

// spec은 Spec 타입이다.
spec: Spec
spec: {
  knid: "Homo Sapiens" // 오타가 난 필드로 에러

  name: first: "Jane"
  name: last:  "Doe"
}

CUE에서 Spec 타입에 필요한 필드가 무엇이고 각 필드의 제약사항이 무엇인지 볼 수 있다. CUE의 타입 시스템은 표현력이 뛰어나서 다른 필드의 선택 사항과 제약 사항을 지정하기 위해 필드를 단순히 타입으로 표시할 수 있다. 이러한 타입과 값의 혼합은 과소평가 되어 있다. 반면 JSON에서는 사용되는 JSON을 문서화하고 유효성 검사를 하기 위해 상당한 노력을 들여 (OpenAPI처럼) 별도의 명세 형식을 만들어야 한다. CUE에서는 추가적인 노력이나 도구 없이도 구성을 평가하는 동안 타입을 검사하고 유효성을 검사할 수 있다.

범용적인 언어와 데이터 언어를 포함해서 현재 대부분의 구성 도구는 장황함을 줄이려고 보일러 플레이트 코드와 중복 코드를 제거하는 데 집중하고 있다. 개발자가 이러한 패러다임에 익숙하므로 대부분은 (베이스 타입을 정의하고 수정하는) 상속 같은 오버라이드 모델을 사용하고 있다. 이것이 CDL이 업계에서 널리 사용되지 않는 핵심 이유라고 생각한다. 비록 이것이 명확한 모델로 보이더라도 상속은 작은 규모든 큰 규모든 구성에서 문제점을 가진다. 작은 프로젝트에서 초기에 추상화를 정의하는 것은 보상은 작으면서 커다란 선행 요청이 될 수 있다. 결국 중복 제거의 이점을 얻으려면 먼저 중복 구성이 필요하다(달리 말하자면 너무 빠른 추상화는 역효과가 날 수 있다). CUE에서는 구성을 정의하면 바로 자동 유효성 검사와 문서를 얻을 수 있다. 기본값을 함께 사용하면 공통 데이터를 재사용하려는 노력이 필요 없어진다.

큰 규모의 프로젝트에서는 상속이 깊은 추상화 계층을 만든다. 이는 구성에서 값이 어디서 왔는지 알기 어렵게 만들고 언어에 다양한 추상화 메커니즘(상속, 믹스인)이 있다면 더욱 심해진다. 실용적인 수준에서 깊은 계층 구조는 구성에서 일반적이며 끝부분에 있는 서브 트리는 수정하기가 어려울 수 있다. CUE는 그래프 통합과 오버라이드 금지라는 다른 접근을 취하고 있다. 이는 처음부터 깊은 계층을 막아주므로 가독성이 높아지고 값이 어디서 왔는지 찾기 위해 여러 파일을 추적할 필요도 없어진다. 비록 CUE에 상속은 없지만, 값이 다른 값의 인스턴스라는 개념(격자로 된 값)이 있다.

이 모델을 유연성은 덜하지만 대신 훨씬 명확하다. 간단한 예제로 Animal 클래스가 있고 DogCat 클래스를 모두 정의한다고 해보자. 상속에서는 Animal을 베이스 타입으로 정의하고 각 서브 클래스를 나타내기 위해 선택적으로 오버라이드하거나 필드를 추가할 수 있다. 동작하기는 하지만 더 나아가 CatDog의 각 품종을 나타내려고 한다면 각 계층이 원하는 대로 데이터를 수정할 수 있으므로 빠르게 이슈를 만나게 된다. CUE의 접근 방법에서는 각 계층의 데이터를 오버라이드하는 대신 Animal의 인스턴스로 CatDog 모델을 선택한다. 두 타입 모두에서 Animal의 정의를 사용하지만 대신 각 동물을 정의하는 경계에 대한 제약사항을 추가한다. 타입의 계층 구조가 같더라도 각 계층의 데이터는 서브 타입에서만 더 구체적이 될 수 있다. 덕분에 품종 관련해서 DogCorgi로 만드는 추가 제약 사항만 필요하고 각 수준에서는 데이터가 최종값을 허용하기 위해 어떻게 제약되는지만 확인할 수 있다.

스크립팅: 제어의 역전(Inversion of Control)

구성은 절대 자체적으로 만들어지지 않는다. 모든 구성의 목적은 유용한 작업을 위해 다른 시스템에 공급되는 것이다. 특히 오늘날에는 SaaS, 클라우드 업체, 지속적 통합, 빌드 도구, 패키지 매니저 등 수많은 도구와 서비스 사이의 구성을 관리해야 한다. 처음에는 구성 파일을 kubectl 같은 다양한 도구에 연결하는 것으로도 작업을 완료하기 충분했을 것이다. 하지만 이러한 작업은 결국 자동화되어야 하는 더 큰 워크플로우의 일부가 된다. Marcel이 여러 번 확인한 이 문제를 설명한다.

처음 범용적인 구성 언어를 사용하는 것이 귀엽고 kubectl에 결과를 연결하고 무엇을 가졌는지 알 수 있었다. 하지만 이는 번거로워서 스크립트를 작성하게 되었다. 그다음 스크립트는 배포하고 사용하기에 종종 불편했기 때문에 명령행 도구로 바꾸었다. 이러한 도구는 보통 도메인에 한정적인 도구이다. 그래서 빠르든 늦든 이러한 도구는 더 큰 제어 흐름에 일부가 되어야 했고 전체 프로세스를 다시 시작하게 된다. 나는 이러한 다수의 도구를 사용한 죄를 지었다.
Marcel van Lohuizen, CUE Slack

그 결과로 나온 도구는 각 제어 수준에서 중복되는 획일적인 글루(glue) 코드로 구성되는 경향이 있다. 더 나쁜 것은 이 솔루션이 통합되어야 하는 도구 조합에 아주 아주 한정적이라는 것이다. 문제는 대부분 더 일반적이고 유용한 접근 방법을 요구한다.

CUE의 솔루션은 구성 언어위에 만들어진 열려있고 선언적인 스크립팅 계층이다. 구성 평가는 밀폐되어 있지만(CUE 시맨틱을 활성화하는 데 중요하다) 스크립팅 계층은 데이터 플로우 파이프라인에서 다양한 작업을 실행하는 함수뿐 아니라 주입된 데이터를 자유롭게 조합할 수 있다. 데이터 주입이 다른 구성 언어가 놓친 격차를 좁힐 많은 가능성을 열어준다. 완전히 자동화 파이프라인에 필요한 명령행 플래그, 환경의 데이터(환경 변수, 네트워크로 받은 데이터), 정의된 구성에서 계산한 데이터를 주입할 수 있다.

오늘날에는 여러 시스템 사이에서 같은 구성을 쉽게 사용할 수 있기 때문에(호환성과 접근성) 엄청난 도구 격변을 겪고 있다. 대신 스크립트 계층은 제어의 역전을 제안한다. 접근할 수 없는 스크립트와 도구로 구성 데이터를 가져오는 대신 왜 데이터에 더 가깝게 코드를 푸시하지 않는가? 데이터의 흐름은 다양한 시스템에서 동작하는 도구를 끊임없이 감싸게 한다. 대신 데이터와 데이터 플로우가 일등 시민이 되는 자동화를 정의할 수 있다.

예제 없이는 어떤 의미인지 보여주기 어렵다. 스크립팅 계층은 계속 동작 중이면서 cue help cmd를 실행하는 예제이다.

package foo

import "tool/exec"

city: "Amsterdam"

// Say hello!
command hello: {
  var file: "out.txt" | string // 복사본을 이 파일에 저장한다

  task ask: cli.Ask & {
    prompt:   "What is your name?"
    response: string
  }

  // ask 후에 시작
  task echo: exec.Run & {
    cmd:    ["echo", "Hello", task.ask.response + "!"]
    stdout: string // capture stdout
  }

  // echo 후에 시작
  task write: file.Append & {
    filename: var.file
    contents: task.echo.stdout
  }

  // 마찬가지로 echo 후에 시작
  task print: cli.Print & {
    contents: task.echo.stdout
  }
}

CUE에서 _tool.cue로 끝나는 파일은 commandtask 템플릿과 마찬가지로 주입된 데이터에 접근하는 스크립트 파일로 평가된다. 각 command는 진입점으로 호출할 수 있는 이름이 부여된다. hello commandcue comd hello로 실행될 것이다. 이 명령어는 이름을 물어본 뒤 인사말을 stdout과 파일에 작성한다. 인자를 정의하는 데 사용되는 구조체를 가진 task의 파이프라인으로 이 워크플로우는 구현된다. 어떤 task의 입력이 다른 작업의 출력을 사용하는지 CUE가 알 수 있으므로 데이터 플로우 분석을 통해 병렬 파이프라인을 자동으로 얻을 수 있다. task는 모든 종류의 오퍼레이션을 다룰 수 있다. 현재 사용할 수 있는 task는 여기서 볼 수 있다.

통합과 패키지

CUE는 JSON의 슈퍼 셋이다. 설계에 따라 CUE는 다른 형식과 작업할 때 유용하다. CUE는 다른 데이터 형식에서 임포트하거나 익스포트하는 자동화를 지원한다. 데이터와 스키마를 CUE로 임포팅(JSON, YAML, Protocol Buffer, OpenAPI 정의 같은)하면 표현적이고 확장성 있는 방법으로 구성을 관리할 수 있다. 다른 형식으로 익스포트하면 다른 시스템에 평가된 CUE를 푸시할 때 호환성을 유지할 수 있다. 결국 구성은 그 자체를 위해 작성되는 것이 아니라 다른 곳에서 사용되기 위해 작성되는 것이다.

CUE 코드 생성의 진짜 의미는 패키지 시스템과 조합할 때 알 수 있다. CUE는 Golang의 패키지 시스템을 가져왔고 URI 임포트를 이용해서 최소 버전 선택을 구현할 계획이다. 이를 통해 일방 프로그래밍 영역에만 존재하던 재사용할 수 있는 추상화를 구성에서 만들 수 있다.

Kubernetes 예제를 보자. Kubernetes는 선언적 인프라스트럭처 상태 수렴기이다. 클라우드 프로바이더처럼 Kubernetes는 여러 리소스에 걸쳐 방대한 API를 노출한다. 이 위에서 Kubernetes는 외부 소스로부터 커스텀 리소스를 정의할 수 있게 한다. 모든 API를 커버하는 DCL 라이브러리를 수동으로 작성하는 것은 엄청난 작업이 될 것이고 빠르게 낡아버릴 것이다. CUE에서는 OpenAPI 명세에서 CUE 코드를 생성할 수 있다. 전체 리소스 API를 커버하고 있어서 그 위에 자신만의 고유한 라이브러리를 올릴 수 있다. 이 글을 읽는 당신이 deployment 정의가 필수 어노테이션과 레이블을 가지면서 컨테이너 레파지토리를 사용하도록 보장되기를 원하는 회사의 플랫폼 엔지니어일 수 있다. 또한 커뮤니티는 모든 워크플로우에 배포되고 통합하기 쉽게 하는 베스트 프랙티스와 패키지 시스템을 권장하는 라이브러리를 만들 수도 있다. 기반 리소스가 변경되면 CUE 코드를 자동 생성해서 라이브러리가 여전히 호환되는지 검사하는 것은 간단한 일이다.

자동화의 꿈

이 모든 아이디어를 합치면 미래 구성의 비전이 된다. 애플리케이션 구성을 위한 라이브러리뿐 아니라 시스템에 데이터를 밀어 넣는 e2e 워크플로우를 실행하는 자동화 라이브러리도 가질 수 있다. CUE의 설계는 큰 규모의 구성을 가능하게 한다. 조직은 고수준으로 제약 사항과 템플릿을 정의할 수 있고 사용자는 구체적인 정의를 만드는 특정 값을 계층화할 수 있다. 조직은 베스트 프랙티스와 정책을 더 쉽게 강제할 수 있고 최전선의 엔지니어는 바로 생산성을 크게 높일 수 있는 템플릿과 자동화를 얻을 수 있다. 분산 패키징을 통해 우리 팀이 만들 수 있는 것에만 갇히지 않고 더 넓은 업계의 베스트 프랙티스와 지식을 활용할 수 있다.

CUE와 당신

이 글을 쓰는 시점(2019년)에서 CUE는 꽤 새로운(alph) 언어이다. 특히, 다른 언어, 플랫폼, 데이터 형식과 통합할 때 완성된 비전에 도달하려면 해야 할 작업이 많이 있다. 다행히도 생태계의 모든 개선 사항은 누구나 사용할 수 있도록 쉽게 공유될 수 있다.

CUE를 선택하는 주요 이유를 요약하자면 CUE를 구성의 요구사항에 대한 진정한 경쟁자로 만드는 이론적 기초 위에서 만들기로 했기 때문이다. 그러므로 CUE가 제공하는 많은 유용한 기능은 그 속성에서(교환성, 연관성, 멱등성) 벗어나 있다. 일하는 방식이 점점 복잡해지는 산업에서 CUE는 훨씬 더 관리할 수 있게 만들어 준다.

당신이 다음 중 하나에 해당한다면 CUE를 살펴봐야 한다.

  • Kubernets/Cloud를 효율적으로 사용하고 싶은 개발자
  • 프로젝트 자동화를 쉽게 공유하고자 하는 애플리케이션 개발자
  • 모든 팀이 사용할 수 있는 유용한 템플릿을 만들고자 하는 플랫폼 개발자
  • 조직 전체에 일관된 정책을 강제하는 간단한 방법을 원하는 아키텍트
  • 너무 많은 YAML을 작성하는데 지친 사람
2022/05/18 03:17 2022/05/18 03:17