AWS 部署环境和创建开发和生产环境

3

大家好,

我正在寻找一种部署应用程序的方法,该应用程序包含以下内容:

  • API网关
  • DynamoDB
  • Lambda函数
  • An S3 bucket

我查看了CloudFormation和CodeDeploy,但是没有EC2,我不确定如何继续操作...

我发现的所有信息都是针对EC2的,我没有找到任何有关部署上述应用程序的信息...

目标是拥有一个部署脚本,可以使用AWS技术自动将应用程序部署到环境中。(基本上是复制我的环境)

非常感谢任何帮助。

编辑:我需要能够从一个AWS账户导出,然后导入到另一个AWS账户。

谢谢!


Serverless Framework可以很顺畅地处理所有这些问题,特别是lambda和apigateway。在它的论坛中,你可以找到许多例子。 - Can Sahin
谢谢您的建议,但我想继续使用AWS堆栈。 - Luc Laverdure
1
如果您正在使用 Python,则由 AWS 团队开发并开源的 Chalice 可大大简化 Lambda + API Gateway 的部署,但它不能解决 Dynamo 或 S3。 对于 S3,AWS Cli 应该足够了,不是吗? - Renato Byrro
我希望所有东西都集中管理...使用CloudFormation似乎是正确的选择,但如果没有EC2,我不确定该如何继续,有人在CloudFormation方面有经验吗? - Luc Laverdure
它是否允许跨AWS账户部署?您能否提供一个示例,将所有内容移动到新的账户和“stage”环境中? - Luc Laverdure
显示剩余7条评论
4个回答

4
为了将您的CloudFormation堆栈部署到“不同”的环境中,您必须对CloudFormation堆栈名称和资源名称进行参数化。(在这个例子中,您不必对AWS::Serverless::Function函数进行参数化,因为如果没有指定函数名称,CloudFormation会自动创建一个函数名称,但对于大多数其他资源,这是必要的)
使用Serverless Application Model (SAM)的示例CloudFormation模板cfn.yml:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Deploys a simple AWS Lambda using different environments.

Parameters:
  Env:
    Type: String
    Description: The environment you're deploying to.

Resources:
  ServerlessFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs12.x
      CodeUri: ./
      Policies:
        - AWSLambdaBasicExecutionRole

  MyBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub 'my-bucket-name-${Env}'

您可以添加其他资源,例如DynamoDB表。如果您使用SAM并在AWS :: Serverless :: Function资源中提供Events部分,则会自动创建API Gateway。请参见{{link1:此SAM示例代码}},来自{{link2:serverless-app-examples}}存储库。

示例deploy.sh脚本:

#!/usr/bin/env bash

LAMBDA_BUCKET="Your-S3-Bucket-Name"
# change this ENV variable depending on the environment you want to deploy
ENV="prd"
STACK_NAME="aws-lambda-cf-environments-${ENV}"

# now package the CloudFormation template which automatically uploads the Lambda function artifacts to S3 -> generated a "packaged" CloudFormation template cfn.packaged.yml
aws cloudformation package --template-file cfn.yml --s3-bucket ${LAMBDA_BUCKET} --output-template-file cfn.packaged.yml

# ... and deploy the packaged CloudFormation template
aws cloudformation deploy --template-file cfn.packaged.yml --stack-name ${STACK_NAME} --capabilities CAPABILITY_IAM --parameter-overrides Env=${ENV}

查看完整的示例代码这里。只需使用./deploy.sh部署脚本并更改ENV变量即可。


我很快就要测试这个,这个能够将文件导出然后导入到另一个AWS账户中吗? - Luc Laverdure
谢谢,我也找到了这个链接:https://docs.aws.amazon.com/lambda/latest/dg/serverless-deploy-wt.html?shortFooter=true#serverless-deploy,可能会有用。 - Luc Laverdure
这是关于账户转移的链接:https://aws.amazon.com/premiumsupport/knowledge-center/account-transfer-s3/ - Luc Laverdure
@LucLaverdure 如果你的意图是移动整个堆栈(即从一个堆栈复制所有资源到另一个堆栈),那么我的示例就不适用了。 - s.hesse
你的生产环境和开发环境可以共享同一个S3存储桶来存储代码吗? - TemporaryFix
1
@Programmatic 是的,Lambda 存储桶可以在生产和开发环境中使用相同的。它只包含临时文件,并且 cloudformation package 命令在上传时会对构件名称进行哈希处理,因此冲突的可能性不是很大。 - s.hesse

1

基于JSON的示例。

Lambda函数 AWS::Lambda::Function

  • 此示例创建一个Lambda函数和附加到它的IAM角色。

语言:NodeJs


"LambdaRole": {
    "Type": "AWS::IAM::Role",
    "Properties": {
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "Service": [
                            "lambda.amazonaws.com"
                        ]
                    },
                    "Action": [
                        "sts:AssumeRole"
                    ]
                }
            ]
        },
        "Policies": [
            {
                "PolicyName": "LambdaSnsNotification",
                "PolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Sid": "AllowSnsActions",
                            "Effect": "Allow",
                            "Action": [
                                "sns:Publish",
                                "sns:Subscribe",
                                "sns:Unsubscribe",
                                "sns:DeleteTopic",
                                "sns:CreateTopic"
                            ],
                            "Resource": "*"
                        }
                    ]
                }
            }
        ]
    }
},
"LambdaFunctionMessageSNSTopic": {
    "Type": "AWS::Lambda::Function",
    "Properties": {
        "Description": "Send message to a specific topic that will deliver MSG to a receiver.",
        "Handler": "index.handler",
        "MemorySize": 128,
        "Role": {
            "Fn::GetAtt": [
                "LambdaRole",
                "Arn"
            ]
        },
        "Runtime": "nodejs6.10",
        "Timeout": 60,
        "Environment": {
            "Variables": {
                "sns_topic_arn": ""
            }
        },
        "Code": {
            "ZipFile": {
                "Fn::Join": [
                    "\n",
                    [
                        "var AWS = require('aws-sdk');",                        
                        "};"
                    ]
                ]
            }
        }
    }
}

API网关 AWS::ApiGateway::RestApi

  • 这个例子创建了一个角色(Role),RestAPI,Usageplan,Keys以及允许从请求(Request)方法执行Lambda的权限。

"MSGGatewayRestApi": {
    "Type": "AWS::ApiGateway::RestApi",
    "Properties": {
        "Name": "MSG RestApi",
        "Description": "API used for sending MSG",
        "FailOnWarnings": true
    }
},
"MSGGatewayRestApiUsagePlan": {
    "Type": "AWS::ApiGateway::UsagePlan",
    "Properties": {
        "ApiStages": [
            {
                "ApiId": {
                    "Ref": "MSGGatewayRestApi"
                },
                "Stage": {
                    "Ref": "MSGGatewayRestApiStage"
                }
            }
        ],
        "Description": "Usage plan for stage v1",
        "Quota": {
            "Limit": 5000,
            "Period": "MONTH"
        },
        "Throttle": {
            "BurstLimit": 200,
            "RateLimit": 100
        },
        "UsagePlanName": "Usage_plan_for_stage_v1"
    }
},
"RestApiUsagePlanKey": {
    "Type": "AWS::ApiGateway::UsagePlanKey",
    "Properties": {
        "KeyId": {
            "Ref": "MSGApiKey"
        },
        "KeyType": "API_KEY",
        "UsagePlanId": {
            "Ref": "MSGGatewayRestApiUsagePlan"
        }
    }
},
"MSGApiKey": {
    "Type": "AWS::ApiGateway::ApiKey",
    "Properties": {
        "Name": "MSGApiKey",
        "Description": "CloudFormation API Key v1",
        "Enabled": "true",
        "StageKeys": [
            {
                "RestApiId": {
                    "Ref": "MSGGatewayRestApi"
                },
                "StageName": {
                    "Ref": "MSGGatewayRestApiStage"
                }
            }
        ]
    }
},
"MSGGatewayRestApiStage": {
    "DependsOn": [
        "ApiGatewayAccount"
    ],
    "Type": "AWS::ApiGateway::Stage",
    "Properties": {
        "DeploymentId": {
            "Ref": "RestAPIDeployment"
        },
        "MethodSettings": [
            {
                "DataTraceEnabled": true,
                "HttpMethod": "*",
                "LoggingLevel": "INFO",
                "ResourcePath": "/*"
            }
        ],
        "RestApiId": {
            "Ref": "MSGGatewayRestApi"
        },
        "StageName": "v1"
    }
},
"ApiGatewayCloudWatchLogsRole": {
    "Type": "AWS::IAM::Role",
    "Properties": {
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "Service": [
                            "apigateway.amazonaws.com"
                        ]
                    },
                    "Action": [
                        "sts:AssumeRole"
                    ]
                }
            ]
        },
        "Policies": [
            {
                "PolicyName": "ApiGatewayLogsPolicy",
                "PolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Action": [
                                "logs:CreateLogGroup",
                                "logs:CreateLogStream",
                                "logs:DescribeLogGroups",
                                "logs:DescribeLogStreams",
                                "logs:PutLogEvents",
                                "logs:GetLogEvents",
                                "logs:FilterLogEvents"
                            ],
                            "Resource": "*"
                        }
                    ]
                }
            }
        ]
    }
},
"ApiGatewayAccount": {
    "Type": "AWS::ApiGateway::Account",
    "Properties": {
        "CloudWatchRoleArn": {
            "Fn::GetAtt": [
                "ApiGatewayCloudWatchLogsRole",
                "Arn"
            ]
        }
    }
},
"RestAPIDeployment": {
    "Type": "AWS::ApiGateway::Deployment",
    "DependsOn": [
        "MSGGatewayRequest"
    ],
    "Properties": {
        "RestApiId": {
            "Ref": "MSGGatewayRestApi"
        },
        "StageName": "DummyStage"
    }
},
"ApiGatewayMSGResource": {
    "Type": "AWS::ApiGateway::Resource",
    "Properties": {
        "RestApiId": {
            "Ref": "MSGGatewayRestApi"
        },
        "ParentId": {
            "Fn::GetAtt": [
                "MSGGatewayRestApi",
                "RootResourceId"
            ]
        },
        "PathPart": "delivermessage"
    }
},
"MSGGatewayRequest": {
    "DependsOn": "LambdaPermission",
    "Type": "AWS::ApiGateway::Method",
    "Properties": {
        "ApiKeyRequired": true,
        "AuthorizationType": "NONE",
        "HttpMethod": "POST",
        "Integration": {
            "Type": "AWS",
            "IntegrationHttpMethod": "POST",
            "Uri": {
                "Fn::Join": [
                    "",
                    [
                        "arn:aws:apigateway:",
                        {
                            "Ref": "AWS::Region"
                        },
                        ":lambda:path/2015-03-31/functions/",
                        {
                            "Fn::GetAtt": [
                                "LambdaFunctionMessageSNSTopic",
                                "Arn"
                            ]
                        },
                        "/invocations"
                    ]
                ]
            },
            "IntegrationResponses": [
                {
                    "StatusCode": 200
                },
                {
                    "SelectionPattern": "500.*",
                    "StatusCode": 500
                },
                {
                    "SelectionPattern": "412.*",
                    "StatusCode": 412
                }
            ],
            "RequestTemplates": {
                "application/json": ""
            }
        },
        "RequestParameters": {
        },
        "ResourceId": {
            "Ref": "ApiGatewayMSGResource"
        },
        "RestApiId": {
            "Ref": "MSGGatewayRestApi"
        },
        "MethodResponses": [
            {
                "StatusCode": 200
            },
            {
                "StatusCode": 500
            },
            {
                "StatusCode": 412
            }
        ]
    }
},
"LambdaPermission": {
    "Type": "AWS::Lambda::Permission",
    "Properties": {
        "Action": "lambda:invokeFunction",
        "FunctionName": {
            "Fn::GetAtt": [
                "LambdaFunctionMessageSNSTopic",
                "Arn"
            ]
        },
        "Principal": "apigateway.amazonaws.com",
        "SourceArn": {
            "Fn::Join": [
                "",
                [
                    "arn:aws:execute-api:",
                    {
                        "Ref": "AWS::Region"
                    },
                    ":",
                    {
                        "Ref": "AWS::AccountId"
                    },
                    ":",
                    {
                        "Ref": "MSGGatewayRestApi"
                    },
                    "/*"
                ]
            ]
        }
    }
}

DynamoDB AWS::DynamoDB::Table

  • 此示例创建了名为 MyCrossConfig 的 DynamoDB 表以及与之相关的警报。

"TableMyCrossConfig": {
  "Type": "AWS::DynamoDB::Table",
  "Properties": {
    "TableName": "MyCrossConfig",
    "AttributeDefinitions": [
      {
        "AttributeName": "id",
        "AttributeType": "S"
      }
    ],
    "KeySchema": [
      {
        "AttributeName": "id",
        "KeyType": "HASH"
      }
    ],
    "ProvisionedThroughput": {
      "ReadCapacityUnits": "5",
      "WriteCapacityUnits": "5"
    }
  }
},
"alarmTargetTrackingtableMyCrossConfigProvisionedCapacityLowdfcae8d90ee2487a8e59c7bc0f9f6bd9": {
  "Type": "AWS::CloudWatch::Alarm",
  "Properties": {
    "ActionsEnabled": "true",
    "AlarmDescription": {
      "Fn::Join": [
        "",
        [
          "DO NOT EDIT OR DELETE. For TargetTrackingScaling policy arn:aws:autoscaling:",
          {
            "Ref": "AWS::Region"
          },
          ":",
          {
            "Ref": "AWS::AccountId"
          },
          ":scalingPolicy:7558858e-b58c-455c-be34-6de387a0c6d1:resource/dynamodb/table/MyCrossConfig:policyName/DynamoDBReadCapacityUtilization:table/MyCrossConfig."
        ]
      ]
    },
    "ComparisonOperator": "LessThanThreshold",
    "EvaluationPeriods": "3",
    "MetricName": "ProvisionedReadCapacityUnits",
    "Namespace": "AWS/DynamoDB",
    "Period": "300",
    "Statistic": "Average",
    "Threshold": "5.0",
    "AlarmActions": [
      {
        "Fn::Join": [
          "",
          [
            "arn:aws:autoscaling:",
            {
              "Ref": "AWS::Region"
            },
            ":",
            {
              "Ref": "AWS::AccountId"
            },
            ":scalingPolicy:7558858e-b58c-455c-be34-6de387a0c6d1:resource/dynamodb/table/MyCrossConfig:policyName/DynamoDBReadCapacityUtilization:table/MyCrossConfig"
          ]
        ]
      }
    ],
    "Dimensions": [
      {
        "Name": "TableName",
        "Value": "MyCrossConfig"
      }
    ]
  }
}

s3 存储桶 AWS::S3::Bucket

  • 此示例创建一个名称为configbucket-+AWS::AccountId的存储桶

"ConfigBucket": {
  "Type": "AWS::S3::Bucket",
  "Properties": {
    "BucketName": {
      "Fn::Join": [
        "",
        [
          "configbucket-",
          {
            "Ref": "AWS::AccountId"
          }
        ]
      ]
    }
  },
  "DeletionPolicy": "Delete"
}

现在您需要将所有内容放在一起,在模板中进行引用等操作。
希望这能帮到您!

我是指一个部署所有服务的脚本示例,这些已经被创建了...抱歉之前表述不清...我需要一个部署脚本,基本上是复制我的环境... - Luc Laverdure
你还能帮忙吗? - Luc Laverdure

0

0

我猜你可以使用CloudFormation来创建这样的应用程序,但我对此并不熟悉。

我成功的做法是编写小脚本,利用awscli实用程序来完成此操作。此外,您需要一个设置新环境的策略。

通常,我会在DynamoDB表和S3存储桶上使用不同的后缀来表示不同的环境。Lambda + API Gateway已经内置了不同版本的概念,因此您也可以在那里支持不同的环境。

对于非常小的项目,我甚至设置了我的Dynamo模式,以支持单个表中的多个环境。这对于小型或个人项目非常有用,因为更便宜。


我非常确定我需要使用CloudFormation,但是如上所述,所有的示例(例如WordPress部署)都使用EC2... - Luc Laverdure
你不需要使用CloudFormation来部署到AWS。它们只是一种便利,当在预配置的EC2实例上运行时,可能很容易创建。但是,不,你不需要一个CloudFormation文件来部署AWS服务。另外,我也有印象手动生成它们可能会比较困难。 - jeff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接