대규모로 사용할 수 있도록 Deployment Manager 구조화

계획에 없이 '코드로서의 인프라' 시스템이 'Hello World' 예시를 넘어서 확장될 경우, 코드가 비구조화되는 경향이 있습니다. 계획에 없는 구성은 하드 코딩됩니다. 유지관리 성능은 크게 저하됩니다.

이 문서 및 포함된 코드 예시를 사용해서 배포를 규모에 맞게 보다 효율적으로 구성할 수 있습니다.

또한 팀 전체에 이름 지정 규칙 및 내부 권장사항을 적용할 수 있습니다. 이 문서는 기술적으로 숙련된 사용자를 대상으로 하며 사용자가 일반적으로 Python, Google Cloud 인프라, Deployment Manager, 코드형 인프라에 대한 기본 지식이 있다고 가정합니다.

시작하기 전에

단일 코드베이스를 사용한 다중 환경

12개 이상의 리소스가 포함된 대규모 배포의 경우 표준 권장사항을 따르게 되면 일반 템플릿에 대한 문자열 및 논리 하드 코딩을 방지하기 위해 상당한 양의 외부 속성(구성 매개변수)을 사용해야 합니다. 이러한 속성은 비슷한 환경(배포, 테스트, 프로덕션 환경 등)이나 비슷한 서비스로 인해 부분적으로 중복된 경우가 많습니다. 예를 들어 모든 표준 서비스는 비슷한 LAMP 스택에서 실행됩니다. 이러한 권장사항을 따르면 구성 속성의 집합이 커지고 중복성이 크게 증가하여, 유지관리가 어려워지고 작업자 오류가 발생할 가능성이 커질 수 있습니다.

다음 표는 배포에 있어 계층적 구성과 단일 구성 간의 차이점을 보여주는 코드 샘플입니다. 이 표에서는 단일 구성에서의 일반적인 중복성을 보여줍니다. 이 표에서는 계층적 구성을 사용함으로써, 반복 섹션을 계층에서 한 수준 위로 이동하여 반복을 방지하고 작업자 오류 가능성을 줄이는 방법을 보여줍니다.

템플릿 중복성이 없는 계층적 구성 중복성이 있는 단일 구성

project_config.py

config = { 'ProjectId': 'qwerty123456', 'ProjectOwner': 'Bob', 'ProjectAbbrevation': 'SNP' }

해당 없음

frontend_config.py

config = {'ServiceName': 'frontend'}

config = { 'ProjectId': 'qwerty123456', 'ProjectOwner': 'Bob', 'ProjectAbbrevation': 'SNP', 'ServiceName': 'frontend' }

backend_config.py

config = {'ServiceName': 'backend'}

config = { 'ProjectId': 'qwerty123456', 'ProjectOwner': 'Bob', 'ProjectAbbrevation': 'SNP', 'ServiceName': 'backend' }

db_config.py

config = {'ServiceName': 'db'}

config = { 'ProjectId': 'qwerty123456', 'ProjectOwner': 'Bob', 'ProjectAbbrevation': 'SNP', 'ServiceName': 'db' }

대규모 코드베이스를 보다 효과적으로 처리하기 위해서는 구성 속성이 단계별로 병합된 구조화된 계층적 레이아웃을 사용합니다. 이를 위해서는 구성에 대해 파일을 하나만 사용하는 것이 아니라 여러 파일을 사용합니다. 또한 도우미 함수를 사용하고 코드베이스의 일부를 조직 내에서 공유합니다.

이 문서에 포함된 코드 예시인 Organization_with_departments에는 미리 정의되어 있지만 맞춤설정이 가능한 구조의 코드베이스, 구성 병합을 위한 도우미 스크립트, 이름 지정을 위한 도우미 함수, 완전한 예시 구성 집합이 포함된 코드베이스가 들어 있습니다. 작동 가능한 예시는 Deployment Manager 샘플 GitHub 저장소에서 찾을 수 있습니다.

코드를 구조화하고 계층적으로 구성하면 몇 가지 이점이 있습니다.

  • 구성을 여러 파일로 분할하면 속성 구조 및 가독성이 향상됩니다. 또한 중복을 방지할 수 있습니다.
  • 논리적인 방식으로 값을 계층화하기 위해 계층별 병합을 설계함으로써 여러 프로젝트 또는 구성요소에서 재사용 가능한 최상위 구성 파일을 만들 수 있습니다.
  • 각 속성을 덮어 쓰는 대신 한 번만 정의하므로 속성 이름의 네임스페이스를 신경 쓰지 않아도 됩니다.
  • 적절한 변수에 따라 적절한 구성이 로드되기 때문에 템플릿이 실제 환경을 확인할 필요가 없습니다.

계층적으로 코드베이스 구조화

Deployment Manager 배포에는 여러 Python 파일과 함께 YAML 구성 또는 스키마 파일이 포함됩니다. 이러한 파일이 배포의 코드베이스를 구성합니다. Python 파일을 사용하는 목적은 여러 가지입니다. Python 파일은 배포 템플릿, 일반 코드 파일(도우미 클래스) 또는 구성 속성이 저장된 코드 파일로 사용될 수 있습니다.

코드베이스를 계층적으로 구조화하기 위해서는 표준 구성 파일 대신 일부 Python 파일을 구성 파일로 사용합니다. 이 방식은 배포를 단일 YAML 파일에 연결하는 것보다 뛰어난 유연성을 제공합니다.

인프라를 실제 코드로 취급

깨끗한 코드를 위한 중요한 원칙 중 하나는 DRY(불필요한 반복 금지)입니다. 모든 것은 한 번만 정의하세요. 이렇게 하면 코드가 더 깨끗해지고, 검토 및 검증도 더 쉬워지고, 유지관리도 더 쉽습니다. 속성을 한 곳에서만 수정하면 되고, 작업자 오류 위험도 줄어듭니다.

구성 파일이 적고 중복이 최소화된 가벼운 코드베이스의 경우, 이러한 지침을 사용해서 DRY 원칙에 따라 코드를 구조화하세요.

조직, 부서, 환경, 모듈

코드베이스를 깨끗하고 계층적으로 구성하기 위한 기본 원칙은 조직, 부서, 환경, 모듈을 사용하는 것입니다. 이러한 원칙은 선택적이고 확장 가능합니다. 이러한 원칙에 따른 예제 코드베이스의 계층 다이어그램은 구성 계층을 참조하세요.

다음 다이어그램에서는 하나의 환경에 모듈이 배포되어 있습니다. 이 구성의 병합자는 구성 파일이 사용되는 컨텍스트에 따라 각 수준에서 적절한 구성 파일을 선택합니다. 또한 시스템 및 부서를 자동으로 정의합니다.

환경에 배포된 모듈

다음 목록에서 번호는 덮어쓰기 순서를 나타냅니다.

  1. 조직 속성

    이 속성은 구조에서 최상위 수준입니다. 이 수준에서는 이름 지정 규칙에 사용하는 organization_nameorganization_abbreviation과 같은 구성 속성과 모든 팀에서 공유하고 적용하려는 도우미 함수를 저장할 수 있습니다.

  2. 부서 속성

    조직에는 부서가 포함됩니다(구조에 부서가 포함된 경우). 각 부서의 구성 파일에서는 다른 부서에서 사용되지 않는 속성을 공유합니다(예: department_name 또는 cost_center).

  3. 시스템(프로젝트) 속성

    각 부서에는 시스템이 있습니다. 시스템은 전자상거래 플랫폼과 같이 잘 정의된 소프트웨어 스택입니다. Google Cloud 프로젝트는 아니지만 작동하고 있는 서비스 생태계입니다.

    시스템 수준에서 팀은 그 위의 수준보다 훨씬 더 큰 자율권을 갖습니다. 여기에서 팀 전체 및 시스템 전체 매개변수(예: system_name, default_instance_size 또는 naming_prefix)의 도우미 함수(예: project_name_generator(), instance_name_generator() 또는 instance_label_generator())를 정의할 수 있습니다.

  4. 환경 속성

    시스템은 서로 상당히 비슷한 Dev, Test 또는 Prod와 선택적으로 QAStaging과 같은 여러 환경을 포함할 가능성이 높습니다. 이러한 환경은 동일한 코드베이스를 사용하고 구성 수준에서만 차이가 있는 것이 이상적입니다. 환경 수준에서 ProdQAdefault_instance_size와 같은 속성을 덮어쓸 수 있습니다.

  5. 모듈 속성

    시스템 규모가 클 경우에는 블록을 하나 통째로 두는 대신, 이를 여러 모듈로 분할합니다. 예를 들어 코어 네트워킹 및 보안을 여러 블록으로 이동할 수 있습니다. 또한 백엔드, 프런트엔드, 데이터베이스 계층을 여러 모듈로 나눌 수도 있습니다. 모듈은 타사에서 개발한 템플릿으로, 적절한 구성만 추가하여 사용할 수 있습니다. 모듈 수준에서는 상속된 시스템 수준 속성을 덮어쓰도록 설계된 속성을 포함하여 특정 모듈에만 관련된 속성을 정의할 수 있습니다. 환경 및 모듈 수준은 시스템에서 병렬적으로 나뉘어 있지만, 모듈은 병합 프로세스에서 환경을 따릅니다.

  6. 환경 특정 모듈 속성

    모듈 속성 중 일부는 인스턴스 크기, 이미지, 엔드포인트와 같은 환경에 의존할 수 있습니다. 환경 특정 모듈 속성은 가장 구체적인 수준이며, 이전에 정의된 값을 덮어쓰기 위한 단계식 병합에서 마지막 지점입니다.

구성 병합을 위한 도우미 클래스

config_merger 클래스는 적절한 구성 파일을 자동으로 로드하고 콘텐츠를 단일 딕셔너리에 병합하는 도우미 클래스입니다.

config_merger 클래스를 사용하려면 다음 정보를 제공해야 합니다.

  • 모듈 이름
  • 환경 이름이 포함된 전역 컨텍스트

ConfigContext 정적 함수를 호출하면 병합된 구성 딕셔너리가 반환됩니다.

다음 코드는 이 클래스의 사용 방법을 보여줍니다.

  • module = "frontend"는 속성 파일이 로드되는 컨텍스트를 지정합니다.
  • 환경은 context.properties["envName"]에서 자동으로 선택됩니다.
  • 전역 구성

    cc = config_merger.ConfigContext(context.properties, module)
    
    print cc.configs['ServiceName']
    

백그라운드에서 도우미 클래스는 구성의 구조에 맞게 정렬되어야 하고, 모든 수준을 올바른 순서로 로드하고, 적절한 구성 값을 덮어써야 합니다. 수준이나 덮어쓰기 순서를 변경하려면 구성 병합자 클래스를 수정합니다.

일상적인 용도에서는 일반적으로 이 클래스를 수정할 필요가 없습니다. 일반적으로는 템플릿과 적절한 구성 파일을 편집한 후 모든 구성이 포함된 출력 딕셔너리를 사용합니다.

예제 코드에는 다음 3개의 하드 코딩된 구성 파일이 포함되어 있습니다.

  • org_config.py
  • department_config.py
  • system_config.py

저장소를 초기화하는 동안 조직 및 부서 구성 파일을 기호화된 링크로 만들 수 있습니다. 이러한 파일은 논리적으로는 프로젝트팀의 코드베이스에 포함되지 않지만 전체 조직 및 부서에 공유되기 때문에 별도의 코드 저장소에 둘 수 있습니다.

구성 병합자는 또한 해당 구조의 남은 수준과 일치하는 파일을 찾습니다.

  • envs/[environment name].py
  • [environment name]/[module name].py
  • modules/[module name].py

구성 파일

Deployment Manager는 하나의 구성 파일(특정한 배포를 위한 단일 파일)을 사용합니다. 이 파일은 부서 간에 공유될 수 없습니다.

config-merger 클래스를 사용할 때는 이 구성 파일을 사용하지 않기 때문에 구성 속성은 이 구성 파일로부터 완전히 분리됩니다. 대신 Python 파일 모음을 사용함으로써, 배포의 유연성이 크게 증가합니다. 이러한 파일은 배포 간에 공유될 수도 있습니다.

모든 Python 파일에는 구조화되었지만 분산된 방식으로 구성을 저장할 수 있게 해주는 변수가 포함될 수 있습니다. 가장 좋은 방법은 협의된 구조에 따라 딕셔너리를 사용하는 것입니다. 구성 병합자는 병합 체인의 모든 파일에서 configs라는 딕셔너리를 찾습니다. 이러한 개별 configs는 하나로 병합됩니다.

병합 중, 경로 및 이름이 동일한 속성이 딕셔너리에서 여러 번 표시될 경우, 구성 병합자는 해당 속성을 덮어씁니다. 컨텍스트 특정 값에 따라 기본값을 덮어쓰는 경우와 같은 일부 상황에서는 이러한 동작이 유용합니다. 하지만 속성 덮어쓰기를 피해야 하는 경우도 많습니다. 속성 덮어쓰기를 방지하려면 개별 네임스페이스를 추가하여 고유하게 만듭니다. 다음 예에서는 구성 딕셔너리에 추가 수준을 만들어서 하위 딕셔너리로 만드는 네임스페이스를 추가합니다.

config = {
    'Zip_code': '1234'
    'Count': '3'
    'project_module': {
        'admin': 'Joe',
    }
}

config = {
    'Zip_code': '5555'
    'Count': '5'
    'project_module_prod': {
        'admin': 'Steve',
    }
}

도우미 클래스 및 이름 지정 규칙

이름 지정 규칙은 Deployment Manager 인프라를 적절히 관리하기 위한 가장 좋은 방법입니다. my project 또는 test instance 같이 모호하거나 일반적인 이름은 사용하지 않는 것이 좋습니다.

다음 예는 조직 전체에서 사용되는 인스턴스 이름 지정 규칙입니다.

def getInstanceName(self, name):
  return '-'.join(self.configs['Org_level_configs']['Org_Short_Name'],
                  self.configs['Department_level_configs']['Department_Short_Name'],
                  self.configs['System_short_name'],
                  name,
                  self.configs["envName"])

도우미 함수를 제공하면 협의된 규칙에 따라 각 인스턴스 이름을 쉽게 지정할 수 있습니다. 또한 이 함수 이외의 다른 곳에서는 인스턴스 이름이 사용되지 않기 때문에 코드 검토도 쉽게 할 수 있습니다. 이 함수는 상위 수준 구성에서 이름을 자동으로 선택합니다. 이 방식은 불필요한 입력을 방지하는 데에도 도움이 됩니다.

이러한 이름 지정 규칙을 대부분의 Google Cloud 리소스와 라벨에 적용할 수 있습니다. 더 복잡한 함수의 경우에는 기본 라벨을 생성하는 것도 가능합니다.

예제 코드베이스의 폴더 구조

예시 코드베이스의 폴더 구조는 유연성이 뛰어나고 맞춤설정이 가능합니다. 하지만 구성 병합자 및 Deployment Manager 스키마 파일에 부분적으로 하드 코딩되어 있습니다. 즉, 수정이 필요한 경우 구성 병합자와 스키마 파일에서 해당 변경사항을 반영해야 합니다.

├── global
│   ├── configs
│   └── helper
└── systems
    └── my_ecom_system
        ├── configs
        │   ├── dev
        │   ├── envs
        │   ├── modules
        │   ├── prod
        │   └── test
        ├── helper
        └── templates
    

global 폴더에는 여러 프로젝트팀에서 공유하는 파일이 포함됩니다. 단순성 확보 차원에서 구성 폴더에는 조직 구성과 모든 부서 구성 파일이 포함됩니다. 이 예에는 부서에 대한 개별 도우미 클래스가 없습니다. 개발자는 조직 또는 시스템 수준에서 도우미 클래스를 추가할 수 있습니다.

global 폴더는 별도의 Git 저장소에 존재할 수 있습니다. 개별 시스템에서 해당 파일을 참조할 수 있습니다. 또한 기호화된 링크를 사용할 수도 있지만, 특정 운영체제에서는 혼란이나 중단을 일으킬 수 있습니다.

├── configs
│   ├── Department_Data_config.py
│   ├── Department_Finance_config.py
│   ├── Department_RandD_config.py
│   └── org_config.py
└── helper
    ├── config_merger.py
    └── naming_helper.py

systems 폴더에는 하나 이상의 서로 다른 시스템이 포함됩니다. 이러한 시스템은 서로 구분되며, 구성을 공유하지 않습니다.

├── configs
│   ├── dev
│   ├── envs
│   ├── modules
│   ├── prod
│   └── test
├── helper
└── templates

configuration 폴더에는 이 시스템에 고유한 모든 구성 파일이 포함되며, 기호화된 링크로 전역 구성을 참조합니다.

├── department_config.py -> ../../../global/configs/Department_Data_config.py
├── org_config.py -> ../../../global/configs/org_config.py
├── system_config.py
├── dev
│   ├── frontend.py
│   └── project.py
├── prod
│   ├── frontend.py
│   └── project.py
├── test
│   ├── frontend.py
│   └── project.py
├── envs
│   ├── dev.py
│   ├── prod.py
│   └── test.py
└── modules
    ├── frontend.py
    └── project.py

Org_config.py:

config = {
  'Org_level_configs': {
    'Org_Name': 'Sample Inc.',
    'Org_Short_Name': 'sampl',
    'HQ_Address': {
      'City': 'London',
      'Country': 'UK'
    }
  }
}

helper 폴더에서는 도우미 클래스를 더 추가하고 전역 클래스를 참조할 수 있습니다.

├── config_merger.py -> ../../../global/helper/config_merger.py
└── naming_helper.py -> ../../../global/helper/naming_helper.py

templates 폴더에서는 Deployment Manager 템플릿을 저장하거나 참조할 수 있습니다. 기호화된 링크는 여기에서도 제대로 작동합니다.

├── project_creation -> ../../../../../../examples/v2/project_creation
└── simple_frontend.py

예제 코드베이스 사용

코드로서의 인프라의 기초로 이러한 계층 방식 적용을 시작하기 위한 가장 좋은 방법은 예제 코드베이스를 복제하고 hierarchical_configuration 폴더 내용을 복사하는 것입니다.

  1. 예제 저장소를 확인합니다.

    git clone https://github.com/GoogleCloudPlatform/deploymentmanager-samples.git
    cd deploymentmanager-samples/community/hierarchical_configuration/Organization_with_departments/systems/my_ecom_system
    gcloud config set deployment_manager/glob_imports True
    
  2. 시스템 설정을 위해 다음 기호화된 링크를 사용해서 로컬 컨텍스트에 대한 전역 파일을 참조합니다.

    ln -sf ../../../global/helper/config_merger.py helper/config_merger.py
    ln -sf ../../../global/helper/naming_helper.py helper/naming_helper.py
    ln -sf ../../../global/configs/org_config.py configs/org_config.py
    
  3. 전역 목록에서 적절한 부서를 선택합니다.

    ln -sf ../../../global/configs/Department_Data_config.py configs/department_config.py
    
  4. 올바른 환경 컨텍스트를 설정하려면 --properties 플래그를 사용하여 envName 속성을 지정합니다. 이 속성을 사용하면 동일한 명령어를 사용하여 다른 환경을 대상으로 동일 코드를 실행할 수 있습니다. [MY-PROJECT-ID]는 자체 Google Cloud 프로젝트의 프로젝트 ID를 나타냅니다.

    [MY-PROJECT-ID]
    gcloud deployment-manager deployments create hierarchy-org-example-dev
    --template env_demo_project.py --properties=envName:dev
    gcloud deployment-manager deployments create hierarchy-org-example-test
    --template env_demo_project.py --properties=envName:test
    gcloud deployment-manager deployments create hierarchy-org-example-prod
    --template env_demo_project.py --properties=envName:prod
    

권장사항

다음 권장사항은 코드를 계층적으로 구조화하는 데 도움이 됩니다.

스키마 파일

Deployment Manager 요구사항에 따라, 스키마 파일에서는 배포 중에 어떤 식으로든 사용된 파일 모두를 일일이 나열해야 합니다. 전체 폴더를 추가하면 더 짧고 일반적인 코드가 됩니다.

  • 도우미 클래스:
- path: helper/*.py
  • 구성 파일:
- path: configs/*.py
- path: configs/*/*.py
  • 벌크(glob 스타일) 가져오기
gcloud config set deployment_manager/glob_imports True

다중 배포

네트워킹, 방화벽, 백엔드, 프런트엔드 등 서로 다른 모듈이더라도, 동일한 구성 집합을 사용하도록 시스템에 여러 배포를 포함하는 것이 좋습니다. 다른 배포에서 이러한 배포의 출력에 액세스해야 할 수 있습니다. 준비된 다음 배포 출력을 쿼리하고, 이를 구성 폴더에 저장할 수 있습니다. 이러한 구성 파일은 병합 프로세스 중에 추가할 수 있습니다.

기호화된 링크는 gcloud deployment-manager 명령어에서 지원되며, 링크된 파일이 올바르게 로드됩니다. 하지만 기호화된 링크는 일부 OS에서 지원되지 않습니다.

구성 계층

다음 다이어그램은 여러 수준 및 관계를 간단히 보여줍니다. 각 직사각형은 파일 이름이 빨간색으로 표시된 속성 파일을 나타냅니다.

다른 수준 및 해당 관계가 표시된 구성 계층

컨텍스트 인식 병합 순서

구성 병합자는 각 파일이 사용되는 컨텍스트를 기준으로 각 수준에서 적합한 구성 파일을 선택합니다. 컨텍스트는 개발자가 환경에 배포하는 모듈입니다. 이 컨텍스트는 시스템 및 부서를 자동으로 정의합니다.

다음 다이어그램에서 숫자는 계층 내 덮어쓰기 순서를 나타냅니다.

덮어쓰기 순서 다이어그램

다음 단계