AWS CloudFormation - Şablonlardaki özel değişkenler


18

CloudFormation şablon parametrelerinden türetilen sık kullanılan değerler için kısayol tanımlamanın herhangi bir yolu var mı?

Örneğin - Bunu ELB adıyla bir Multi-AZ Projesi yığını oluşturan bir senaryo var projectve denilen ELB arkasında iki örneklerini project-1ve project-2. Ben sadece ELBHostNameşablona parametre geçmek ve daha sonra inşa etmek için kullanın:

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

Bu yapı veya çok benzer, EC2 ana bilgisayar adı, Route53 kayıtları vb. Oluşturmak için şablon boyunca birçok kez tekrarlanır.

Bunu tekrar tekrar yerine, bunun çıktısını Fn::Joinbir çeşit değişkene atamak ve sadece bunu ifade etmek istiyorum "Ref":.

İdeal olarak:

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

ya da benzer şekilde basit bir şey.

Amazon CloudFormation ile bu mümkün mü?


ELBHostName full, açıkça Cloudformation'a geçirdiğiniz bir parametre mi? Öyleyse, neden Ref kullanıyorsunuz? Şablonunuza değişkenler eklemek için Bıyık kullanabilir ve bunu Cloudformation'a göndermeden önce JSON'a dönüştürebilir. Temel hazırlık işleminizin nasıl göründüğüne bağlıdır.
Canuteson

Yanıtlar:


5

Aynı işlevselliği arıyordum. SpoonMeiser'ın önerdiği gibi iç içe bir yığın kullanmak akla geldi, ama sonra gerçekten ihtiyacım olan şeyin özel işlevler olduğunu fark ettim. Neyse ki CloudFormation, AWS :: CloudFormation :: CustomResource'un kullanımına izin verir, bu da biraz çalışma ile birinin bunu yapmasına izin verir. Bu, sadece değişkenler için aşırıya kaçma gibi geliyor (ilk başta CloudFormation'da olması gerektiğini iddia ettiğim bir şey), ancak işi hallediyor ve ek olarak, tüm esnekliklere izin veriyor (python / düğüm seçiminizi yapın / java). Lamda işlevlerinin paraya mal olduğu unutulmamalıdır, ancak yığınlarınızı saatte birkaç kez oluşturmadığınız / silmediğiniz sürece burada kuruşlardan bahsediyoruz.

İlk adım, bu sayfada giriş değerini alıp çıktıya kopyalamaktan başka bir şey yapmayan bir lambda işlevi yapmaktır . Lambda fonksiyonunun her türlü çılgın şeyi yapmasını sağlayabilirdik, ancak kimlik fonksiyonuna sahip olduktan sonra, başka her şey kolaydır. Alternatif olarak, yığının kendisinde lambda işlevi yaratılabilir. 1 hesapta birçok yığın kullandığımdan, bir sürü artık lambda işlevi ve rolüne sahip olacağım (ve tüm rollerin birlikte oluşturulması gerekiyor --capabilities=CAPABILITY_IAM, çünkü bir role de ihtiyacı var.

Lambda işlevi oluştur

  • Lambda ana sayfasına gidin ve en sevdiğiniz bölgeyi seçin
  • Şablon olarak "Boş İşlev" i seçin
  • "İleri" yi tıklayın (tetikleyici yapılandırmayın)
  • Doldurun:
    • İsim: CloudFormationIdentity
    • Açıklama: Bulut Formation'da aldığı şeyi, değişken desteği döndürür
    • Oynatma Süresi: python2.7
    • Kod Giriş Türü: Kod Satırını Düzenle
    • Kod: aşağıya bakın
    • işleyici: index.handler
    • Rol: Özel bir Rol oluşturun. Bu noktada, yeni bir rol oluşturmanıza izin veren bir açılır pencere açılır. Bu sayfadaki her şeyi kabul edin ve "İzin Ver" i tıklayın. Bulut izleme günlüklerine gönderme izinleriyle bir rol oluşturacaktır.
    • Bellek: 128 (bu minimumdur)
    • Zaman aşımı: 3 saniye (bol olmalıdır)
    • VPC: VPC yok

Ardından aşağıdaki kodu kod alanına kopyalayıp yapıştırın. İşlevin üst kısmı, sadece garip bir nedenden ötürü lambda işlevi CloudFormation aracılığıyla oluşturulduğunda otomatik olarak kurulan cfn-yanıt python modülünün kodudur. handlerFonksiyon yeterince açıklayıcı olduğunu.

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")
  • Sonrakine tıkla"
  • "İşlev Oluştur" u tıklayın

Artık lambda işlevini "Test" düğmesini seçip örnek şablon olarak "CloudFormation Create Request" i seçerek test edebilirsiniz. Günlüğünüzde kendisine beslenen değişkenlerin döndürüldüğünü görmelisiniz.

CloudFormation şablonunuzda değişken kullanın

Artık bu lambda fonksiyonuna sahip olduğumuza göre, bunu CloudFormation şablonlarında kullanabiliriz. Önce lambda işlevi Arn'ı not edin ( lambda ana sayfasına gidin, yeni oluşturulan işlevi tıklayın, Arn sağ üstte olmalı, gibi bir şey arn:aws:lambda:region:12345:function:CloudFormationIdentity).

Şimdi şablonunuzda, kaynak bölümünde aşağıdaki gibi değişkenlerinizi belirtin:

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]]]]

Önce Identitylambda işlevi için Arn içeren bir değişken belirtiyorum. Bunu bir değişkene buraya koymak, onu sadece bir kez belirtmem gerektiği anlamına gelir. Tüm değişkenlerimi tür haline getiriyorum Custom::Variable. CloudFormation, Custom::özel kaynaklar için ile başlayan herhangi bir tür adını kullanmanızı sağlar .

Not Identitydeğişken iki kez lambda fonksiyonu için Arn içerir. Bir kez kullanılacak lambda işlevini belirtin. Değişkenin değeri olarak ikinci kez.

Şimdi Identitydeğişken var, ben ServiceToken: !GetAtt [Identity, Arn](JSON kodu gibi bir şey olması gerektiğini düşünüyorum) kullanarak yeni değişkenler tanımlayabilirsiniz "ServiceToken": {"Fn::GetAtt": ["Identity", "Arn"]}. Her biri 2 alana sahip 2 yeni değişken oluşturuyorum: Name ve Arn. Şablonumun geri kalanında kullanabileceğim !GetAtt [ClientBucketVar, Name]ya !GetAtt [ClientBucketVar, Arn]ben İhtiyacınız olduğunda.

Dikkat kelimesi

Özel kaynaklarla çalışırken, lambda işlevi çökerse, 1 ile 2 saat arasında sıkışıp kalırsınız, çünkü CloudFormation (çöktü) işlevinden vazgeçmeden önce bir saat boyunca yanıt bekler. Bu nedenle, lambda işlevinizi geliştirirken yığın için kısa bir zaman aşımı belirtmek iyi olabilir.


Müthiş cevap! Bunu okudum ve yığınlarımda çalıştırdım, ancak benim için, hesabımda lambda işlevlerinin çoğalması konusunda endişelenmiyorum ve bağımsız şablonları ( cloudformation-toolgem kullanarak modülerleştiriyorum ) seviyorum, bu yüzden lambda oluşturma ardından Identityözel kaynağı oluşturmak yerine doğrudan kullanabilirsiniz . Kodum
Guss

"... 1 ile 2 saat arasında sıkışıp kaldığınızda ..." çünkü bir lambda çöktü ve bir cfn yanıtıyla yanıt vermediği için, curl / wget kullanarak manuel olarak tekrar hareket ettirebilirsiniz. imzalı URL. CloudWatch'a gidip URL'nin askıda kalması durumunda alabilmeniz için lambda'nın başlangıcında her zaman etkinliği / URL'yi yazdırdığınızdan emin olun.
Taylor

12

Bir cevabım yok, ama Fn::Subyerine kullanarak çok fazla acı kurtarabileceğinizi belirtmek istedimFn::Join

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

Yerini

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

3

Hayır. Denedim, ama boş geldim. Bana mantıklı gelen yol "CustomVariables" adlı bir Mappings girişi oluşturmak ve o eve tüm değişkenlerimi yerleştirmekti. Basit Dizeler için çalışır, ancak Eşlemeler içinde İçsel (Refs, Fn :: Joins, vb.) Kullanamazsınız .

İşler:

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

Çalışmaz:

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

Bu sadece bir örnek. Değişkene bağımsız bir Ref koyamazsınız.


1
Belgeler, eşleme değerlerinin değişmez dizeler olması gerektiğini söylüyor.
Ivan Anishchuk

3

Çıktılarındaki tüm değişkenlerinizi çözen iç içe bir yığın kullanabilir ve daha sonra Fn::GetAttbu yığındaki çıktıları okumak için kullanabilirsiniz


2

Dış şablondaki tüm değişkenlerinizi "çözdüğünüz" ve bunları başka bir şablona geçirdiğiniz iç içe şablonlar kullanabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.