RDS只读副本-Cloudformation的多可用区

时间:2019-07-05 08:21:13

标签: amazon-web-services amazon-cloudformation amazon-rds

在控制台上创建只读副本时,可以使用多可用区部署。 AWS also announced last year只读副本支持MutliAZ

Read replica available in Console

但是,当尝试在Cloudformation中复制它时,出现此错误

enter image description here

这是我Cloudformation中的摘录:

Resources:
  MasterDB:
    Type: AWS::RDS::DBInstance
    Properties:
      AllocatedStorage: 100
      BackupRetentionPeriod: 10
      DBInstanceClass: !Ref DBInstanceClass
      Engine: postgres
      EngineVersion: '10.6'
      MasterUsername: !Ref DBUsername
      MasterUserPassword: !Ref DBPassword
      MultiAZ: false 
      PubliclyAccessible: true

  ReplicaDB:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceClass: !Ref DBInstanceClass
      SourceDBInstanceIdentifier: !Ref MasterDB
      MultiAZ: true
      PubliclyAccessible: true 

documentation中,它指出:

  

将只读副本创建为多可用区数据库实例独立于   源数据库是否为多可用区数据库实例。

...因此MasterDB未设置为MultiAZ应该不是问题。

我的Cloudformation模板是否有错误?还是Cloudformation不支持MultiAZ for Read Replicas?

谢谢!

1 个答案:

答案 0 :(得分:0)

我有同样的问题。我能够解决的唯一方法是在CloudFormation中使用自定义资源lambda。 lambda获取数据库实例的ID(在本例中为副本ID),然后使用boto3将其更改为Multi-Az副本。

这是lambda函数的模板:

# Create a python lambda function which 
# can enable Multi-AZ for read replicas.
#
# This lambda is meant to be executed by custom resource
# from other template in CloudFormaton
---

Resources:

    EnableMultiAz:
        Type: AWS::Lambda::Function
        Properties:
            Description: Create an AMI of an instance
            FunctionName: EnableMultiAzForDBInstance
            Handler: index.lambda_handler
            Role: !GetAtt LambdaExecutionRole.Arn
            Runtime: python3.7
            Timeout: 60
            Code: 
                ZipFile: |
                    import json
                    import boto3
                    import logging
                    import time

                    from botocore.vendored import requests

                    logger = logging.getLogger()
                    logger.setLevel(logging.INFO)

                    SUCCESS = "SUCCESS"
                    FAILED = "FAILED"

                    # from https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-lambda-function-code-cfnresponsemodule.html
                    def send(event, context, responseStatus, responseData, physicalResourceId=None, noEcho=False):

                        responseUrl = event['ResponseURL']

                        print(responseUrl)

                        responseBody = {
                            'Status': responseStatus,
                            'Reason': 'See ' + context.log_stream_name,
                            'PhysicalResourceId': physicalResourceId or context.log_stream_name,
                            'StackId': event['StackId'],
                            'RequestId': event['RequestId'],
                            'LogicalResourceId': event['LogicalResourceId'],
                            'NoEcho': noEcho,
                            'Data': responseData
                        }

                        json_responseBody = json.dumps(responseBody)

                        print("Response body:\n" + json_responseBody)

                        headers = {
                            'content-type' : '',
                            'content-length' : str(len(json_responseBody))
                        }

                        try:
                            response = requests.put(responseUrl,
                                                    data=json_responseBody,
                                                    headers=headers)
                            print("Status code: " + response.reason)
                        except Exception as e:
                            print("send(..) failed executing requests.put(..): " + str(e))

                    def lambda_handler(event, context):

                        print('event: ', json.dumps(event))

                        try:

                            return_data = {}

                            if 'RequestType' in event:

                                rds = boto3.client('rds')

                                dbinstance_id = event['ResourceProperties']['DBinstanceId'] 

                                if event['RequestType'] == 'Create':   

                                    r = rds.modify_db_instance(
                                            DBInstanceIdentifier=dbinstance_id, 
                                            MultiAZ=True, ApplyImmediately=True)        
                            send(event, context, SUCCESS, return_data)            

                        except Exception as e:
                            logger.error('custom response lambda failed due to: ' + str(e))
                            send(event, context, FAILED, {})


    LambdaExecutionRole:
        Type: AWS::IAM::Role
        Properties:
            RoleName: lambda-execution-role-with-rds
            AssumeRolePolicyDocument:
                Version: '2012-10-17'               
                Statement:
                    - Effect: Allow
                      Principal: {'Service': ['lambda.amazonaws.com']}
                      Action: ['sts:AssumeRole']
            ManagedPolicyArns:
                - arn:aws:iam::aws:policy/AWSLambdaExecute
            Path: '/'
            Policies:
                - PolicyName: PassRolePolicy
                  PolicyDocument: 
                      Version: "2012-10-17"
                      Statement: 
                          - Effect: "Allow"
                            Action: "iam:PassRole"
                            Resource: "*"
                - PolicyName: EnableMultiAZReadReplica
                  PolicyDocument: 
                      Version: "2012-10-17"
                      Statement: 
                          - Effect: "Allow"
                            Action: 
                                - "rds:ModifyDBInstance"                           
                            Resource: "*"                            



Outputs:

    LambdaArn:
        Value: !GetAtt EnableMultiAz.Arn

    LambdaRoleArn:
        Value: !GetAtt LambdaExecutionRole.Arn

您将此lambda模板放置在S3中,然后将其作为父模板:

    # Define nested stack that creates the lambda
    MyCustomLambdaToMakeMultiAzReplicas:
        Type: AWS::CloudFormation::Stack
        Properties:      
            TemplateURL: "<url to lambda template in s3>"
            TimeoutInMinutes: 1    

    # Define a custom resource using the lambda. Replica 
    # db instance id is passed to the lambda and the lambda is
    # executed       
    EnableMultiAzForReplica: 
        Type: "Custom::CustomLambdaToMakeMultiAzReplicas"
        Properties: 
            ServiceToken: !GetAtt MyCustomLambdaToMakeMultiAzReplicas.Outputs.LambdaArn
            DBinstanceId: !Ref ReadReplicaDbInstanceId