AWS CloudFormation-템플릿의 사용자 지정 변수


18

CloudFormation 템플릿 파라미터에서 파생 된 자주 사용되는 값에 대한 바로 가기를 정의 할 수있는 방법이 있습니까?

예를 들어 - 나는 ELB 이름을 가진 다중 AZ 프로젝트 스택을 생성하는 스크립트를 가지고 project와라는 ELB 뒤에 두 인스턴스 project-1project-2. 나는 ELBHostName매개 변수를 템플릿 에만 전달 하고 나중에 그것을 사용하여 구성합니다.

"Fn::Join": [
    ".", [
        { "Fn::Join": [ "", [ { "Ref": "ELBHostName" }, "-1" ] ] },
        { "Ref": "EnvironmentVersioned" },
        { "Ref": "HostedZone" }
    ]
]

EC2 호스트 이름, Route53 레코드 등을 생성하기 위해이 구성 또는 이와 유사한 작업이 템플릿 전체에서 여러 번 반복됩니다.

반복해서 반복하는 대신 그 결과를 Fn::Join일종의 변수에 지정하고 참조 할 수있는 것처럼 참조하고 싶습니다."Ref": statement .

이상적으로는

Var::HostNameFull = "Fn::Join": [ ... ]
...
{ "Name": { "Ref": "Var::HostNameFull" } }

또는 비슷하게 간단한 것.

Amazon CloudFormation에서도 가능합니까?


ELBHostName이 Cloudformation에 명시 적으로 전달하는 매개 변수로 가득 차 있습니까? 그렇다면 왜 Ref를 사용합니까? Mustache를 사용하여 템플릿에 변수를 포함시키고 Cloudformation으로 전달하기 전에 JSON으로 변환 할 수 있습니다. 프로비저닝 프로세스의 모양에 따라 다릅니다.
Canuteson

답변:


5

나는 같은 기능을 찾고있었습니다. SpoonMeiser가 제안한대로 중첩 스택을 사용하면 마음에 들었지만 실제로 필요한 것은 사용자 정의 함수라는 것을 깨달았습니다. 운 좋게 CloudFormation을 사용하면 AWS :: CloudFormation :: CustomResource를 사용할 수 있습니다. 약간의 작업만으로도 를 사용할 수 있습니다. 이것은 변수에 대한 잔인한 느낌 (먼저 CloudFormation에 있어야한다고 주장하는 것)이지만 작업을 완료하고 모든 유연성을 허용합니다 (파이썬 / 노드 선택) /자바). 람다 함수는 비용이 많이 들지만 시간당 여러 번 스택을 만들거나 삭제하지 않는 한 여기에서 돈을 벌고 있습니다.

첫 번째 단계는 이 페이지 에서 입력 값을 가져 와서 출력에 복사하는 것 외에 다른 기능 수행하는 것입니다. 우리는 람다 함수가 모든 종류의 미친 것들을 수행하도록 할 수 있지만 일단 정체성 함수를 가지면 다른 것은 쉽습니다. 또는 스택 자체에서 람다 함수를 만들 수도 있습니다. 하나의 계정에서 많은 스택을 사용하기 때문에 남은 람다 함수와 역할이 많이 있습니다 (그리고 모든 스택은 역할이 필요하기 때문에로 만들어야 --capabilities=CAPABILITY_IAM합니다.

람다 함수 생성

  • 람다 홈페이지로 이동 하여 원하는 지역을 선택하십시오.
  • 템플릿으로 "빈 기능"을 선택하십시오.
  • "다음"을 클릭하십시오 (트리거를 구성하지 마십시오)
  • 작성 :
    • 이름 : CloudFormationIdentity
    • 설명 : Cloud Formation에서 지원되는 내용, 변수 지원을 반환합니다.
    • 런타임 : python2.7
    • 코드 입력 유형 : 코드 인라인 편집
    • 코드 : 아래 참조
    • 매니저: index.handler
    • 역할 : 사용자 지정 역할을 만듭니다. 이 시점에서 새 역할을 만들 수있는 팝업이 열립니다. 이 페이지의 모든 내용을 승인하고 "허용"을 클릭하십시오. Cloudwatch 로그에 게시 할 권한이있는 역할을 생성합니다.
    • 메모리 : 128 (최소값)
    • 타임 아웃 : 3 초 (충분해야 함)
    • VPC : VPC 없음

그런 다음 코드 필드에 아래 코드를 복사하여 붙여 넣습니다. 함수의 상단은 cfn-response python module 의 코드이며, 이상한 이유로 CloudFormation을 통해 람다 함수가 생성 된 경우에만 자동 설치됩니다. 이 handler기능은 설명이 필요 없습니다.

from __future__ import print_function
import json

try:
    from urllib2 import HTTPError, build_opener, HTTPHandler, Request
except ImportError:
    from urllib.error import HTTPError
    from urllib.request import build_opener, HTTPHandler, Request


SUCCESS = "SUCCESS"
FAILED = "FAILED"


def send(event, context, response_status, reason=None, response_data=None, physical_resource_id=None):
    response_data = response_data or {}
    response_body = json.dumps(
        {
            'Status': response_status,
            'Reason': reason or "See the details in CloudWatch Log Stream: " + context.log_stream_name,
            'PhysicalResourceId': physical_resource_id or context.log_stream_name,
            'StackId': event['StackId'],
            'RequestId': event['RequestId'],
            'LogicalResourceId': event['LogicalResourceId'],
            'Data': response_data
        }
    )
    if event["ResponseURL"] == "http://pre-signed-S3-url-for-response":
        print("Would send back the following values to Cloud Formation:")
        print(response_data)
        return

    opener = build_opener(HTTPHandler)
    request = Request(event['ResponseURL'], data=response_body)
    request.add_header('Content-Type', '')
    request.add_header('Content-Length', len(response_body))
    request.get_method = lambda: 'PUT'
    try:
        response = opener.open(request)
        print("Status code: {}".format(response.getcode()))
        print("Status message: {}".format(response.msg))
        return True
    except HTTPError as exc:
        print("Failed executing HTTP request: {}".format(exc.code))
        return False

def handler(event, context):
    responseData = event['ResourceProperties']
    send(event, context, SUCCESS, None, responseData, "CustomResourcePhysicalID")
  • "다음"을 클릭하십시오
  • "기능 생성"을 클릭하십시오

"Test"버튼을 선택하여 람다 함수를 테스트하고 "CloudFormation Create Request"를 샘플 템플릿으로 선택할 수 있습니다. 로그에 공급 된 변수가 반환되는 것을 로그에서 확인해야합니다.

CloudFormation 템플릿에서 변수 사용

이제이 람다 함수가 있으므로 CloudFormation 템플릿에서 사용할 수 있습니다. 람다 함수 Arn을 먼저 기록하십시오 ( 람다 홈페이지 로 이동 하여 방금 생성 된 함수를 클릭하십시오. Arn은 오른쪽 상단에 있어야합니다 arn:aws:lambda:region:12345:function:CloudFormationIdentity).

이제 템플릿의 리소스 섹션에서 다음과 같이 변수를 지정하십시오.

Identity:
  Type: "Custom::Variable"
  Properties:
    ServiceToken: "arn:aws:lambda:region:12345:function:CloudFormationIdentity"
    Arn: "arn:aws:lambda:region:12345:function:CloudFormationIdentity"

ClientBucketVar:
  Type: "Custom::Variable"
  Properties:
    ServiceToken: !GetAtt [Identity, Arn]
    Name: !Join ["-", [my-client-bucket, !Ref ClientName]]
    Arn: !Join [":", [arn, aws, s3, "", "", !Join ["-", [my-client-bucket, !Ref ClientName]]]]

ClientBackupBucketVar:
  Type: "Custom::Variable"
  Properties:
    ServiceToken: !GetAtt [Identity, Arn]
    Name: !Join ["-", [my-client-bucket, !Ref ClientName, backup]]
    Arn: !Join [":", [arn, aws, s3, "", "", !Join ["-", [my-client-bucket, !Ref ClientName, backup]]]]

먼저 Identity람다 함수에 Arn을 포함 하는 변수를 지정합니다 . 이 변수를 여기에 넣으면 한 번만 지정하면됩니다. 모든 유형의 변수를 만듭니다 Custom::Variable. CloudFormation을 사용하면 Custom::사용자 지정 리소스로 시작하는 모든 유형 이름을 사용할 수 있습니다 .

점을 유의 Identity변수 회 람다 기능에 대한 급성 망막 괴사를 포함한다. 사용할 람다 함수를 지정하십시오. 변수의 값으로 두 번째입니다.

이제 Identity변수 가 있으므로 ServiceToken: !GetAtt [Identity, Arn](JSON 코드는와 같아야한다고 생각)을 사용하여 새 변수를 정의 할 수 있습니다 "ServiceToken": {"Fn::GetAtt": ["Identity", "Arn"]}. 이름과 Arn이라는 두 개의 필드가있는 두 개의 새 변수를 만듭니다. 나머지 템플릿에서는 사용할 수 !GetAtt [ClientBucketVar, Name]있거나 !GetAtt [ClientBucketVar, Arn]필요할 때마다 사용할 수 있습니다 .

주의의 말씀

커스텀 리소스로 작업 할 때 람다 함수가 충돌하면 CloudFormation이 1 시간 동안 (크래쉬 된) 함수의 응답을 기다리기 때문에 1 시간에서 2 시간 사이에 멈춰 있습니다. 따라서 람다 함수를 개발하는 동안 스택에 짧은 시간 초과를 지정하는 것이 좋습니다.


멋진 답변! 나는 그것을 읽고 내 스택에서 실행했지만 내 계정에서 람다 함수의 확산에 대해 걱정하지 않고 독립형 ( cloudformation-tool보석을 사용하여 모듈화) 템플릿을 좋아 하므로 람다 생성을 템플릿을 만든 다음 Identity사용자 지정 리소스 를 만드는 대신 직접 사용할 수 있습니다 . 내 코드는 여기를 참조하십시오 : gist.github.com/guss77/2471e8789a644cac96992c4102936fb3
Guss

람다가 추락하고 cfn- 응답으로 답장을 보내지 않아서 "... 1 시간에서 2 시간 사이에 멈췄을 때 ..."인 경우 curl / wget on을 사용하여 템플릿을 다시 이동할 수 있습니다. 서명 된 URL 람다 시작 부분에서 항상 이벤트 / URL을 인쇄하여 CloudWatch로 이동하여 URL이 멈추는 경우 URL을 얻을 수 있도록하십시오.
테일러

12

나는 대답을하지 않지만, 사용하여 자신에게 고통을 많이 절약 할 수 있다는 점을 지적 할 않았다 Fn::Sub대신에Fn::Join

{ "Fn::Sub": "${ELBHostName"}-1.${EnvironmentVersioned}.${HostedZone}"}

대체

"Fn::Join": [
    ".", [
        { "Fn::Join": [ "", [ { "Ref": "ELBHostName" }, "-1" ] ] },
        { "Ref": "EnvironmentVersioned" },
        { "Ref": "HostedZone" }
    ]
]

3

아뇨, 시도했지만 비어있었습니다. 나에게 맞는 방법은 "CustomVariables"라는 Mappings 항목을 작성하고 해당 변수를 모두 보유하도록하는 것입니다. 간단한 문자열에서는 작동하지만 Mappings 내에서 내장 함수 (Refs, Fn :: Joins 등)를 사용할 수 없습니다 .

공장:

"Mappings" : {
  "CustomVariables" : {
    "Variable1" : { "Value" : "foo" },
    "Variable2" : { "Value" : "bar" }
  }
}

작동하지 않습니다 :

  "Variable3" : { "Value" : { "Ref" : "AWS::Region" } }

그것은 단지 예일뿐입니다. 독립형 Ref를 변수에 넣지 않습니다.


1
설명서에 따르면 매핑 값은 리터럴 문자열이어야합니다.
Ivan Anishchuk

3

출력의 모든 변수를 해결하는 중첩 스택을 사용한 다음 Fn::GetAtt해당 스택의 출력을 읽는 데 사용할 수 있습니다


2

외부 템플릿의 모든 변수를 "해결"하고 다른 템플릿으로 전달하는 중첩 템플릿을 사용할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.