如何使用aws-cdk管理多个环境



我正在将我们的基础代码从Terraform转移到AWS cdk。我正试图找到一种最佳的方法来管理多个环境,这些环境有多个堆栈需要部署。如果我遵循文档中的建议,我将不得不为多个环境定义多个堆栈,这可能会让人感到困惑。例如

const app = new cdk.App();
new DevStack1(app, 'dev-stack-1', settings.dev)
new DevStack2(app, 'dev-stack-2', settings.dev)
.
.

new ProdStack1(app, 'prod-stack-1', settings.prod)
new ProdStack2(app, 'prod-stack-2', settings.prod)
.
.

在同一环境中的不同堆栈之间共享设置。然后我必须一个接一个地部署每个堆栈。有更好的方法吗?

编辑:由于这个答案有合理的视图量,我想更新它以反映更好、更CDK的本地方法。我会在下面保留原来的答案,因为它可能对某些人更有效。

CDK参数可以直接存储在context密钥下的cdk.json中,并使用ConstructNode.try_get_context(param_name)在应用程序内部检索。

见官方文件:https://docs.aws.amazon.com/cdk/latest/guide/get_context_var.html

因此,这是cdk.json的一个例子,对于不同的环境具有不同的参数:

{
"app": "python3 app.py",
"context": {
"dev": {
"vpc": {
"vpc_id": "blabla"
}
},
"stage": {
"vpc": {
"vpc_id": "bleble"
}
}
}

现在,您还可以通过CLI键--context env_name=dev提供上下文参数,并在代码中使用其值来获取相关设置。

实际上,大多数(如果不是所有的话(常用结构,如StackAppNestedStack,都具有node属性,因此您可以从应用程序中的任何位置访问上下文。

使用它有两个注意事项:

  1. 它不允许访问较低级别的密钥(或者至少没有文档记录(。这意味着你不能使用self.try_get_context("dev.vpc.vpc_id"),你需要通过self.try_get_context("dev")检索顶级密钥,然后自己往下走。

  2. 如果您的上下文中有bool参数,并试图使用CLI键--context key=False覆盖它们,这些参数将被转换为str,如果您使用常识语法:,则很容易陷入陷阱

if self.try_get_context("deploy_vpc"):
MyVPC(app, "my new vpc")

由于";"错误";被评估为True,作为一个非空字符串,您将不会得到您期望的结果。


旧答案

我不确定是否对此达成共识,因为CDK仍然是一个新事物,并且还支持多种语言。但我个人所做的是将不同环境的设置存储在YAML文件中,然后通过环境变量提供该文件。

Python示例:

Config是一个YAML文件,其中包含一些项目,如资源所需的标签、应用程序级别的一些设置(如帐户ID和区域(和一些堆栈级别的设置(如资源名称等(。

假设是标准项目布局,其中有app.py主文件和带有堆栈描述的cdk/cdk_stack.py文件。在app.py:中

from ruamel.yaml import YAML
...
from cdk.cdk_stack import MyStack

def load_config() -> dict:
"""
Import settings from YAML config
:return: dict with configuration items
"""
# This variable should always be set
# CDK doesn't work well with argparse
config_path = os.getenv("CONFIG_PATH")
if not config_path:
raise RuntimeError("You need to supply config file path with CONFIG_PATH env variable")
# We don't verify config content, let fail in case something is missing
with open(config_path) as config_file:
config = YAML().load(config_file.read())
return config
def init_app() -> core.App:
"""
Initiates CDK main_app for deployment
:return: main_app
"""
main_app = core.App()
config = load_config()
# Account ID and region have to be explicitly set in order to import existing resources
MyStack(
main_app,
"my stack",
env={
'account': config["account_id"],
'region': config["region"]
},
config=config
)
# Tags are applied to all tagable resources in the stack
for key, value in config["tags"].items():
core.Tag.add(scope=main_app, key=key, value=value)
return main_app

if __name__ == '__main__':
app = init_app()
app.synth()

然后在cdk/cdk_stack.py:中

class MyStack(core.Stack):
"""
Describes CF resources
"""
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
# Pop the config object first, since parent object doesn't expect it and will crash
config = kwargs.pop("config")
super().__init__(scope, id, **kwargs)
...

最新更新