如何使用aws cdk管理多个环境?
How to manage multiple environments using 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
提供上下文参数,并在代码中使用它的值来获取相关设置。
实际上大多数(如果不是全部)常用结构,如 Stack
、App
、NestedStack
都具有 node
属性,因此您可以从应用中的任何位置访问上下文.
使用它有 2 个注意事项:
它不允许访问较低级别的密钥(或者至少没有记录)。这意味着您不能使用 self.try_get_context("dev.vpc.vpc_id")
,您需要通过 self.try_get_context("dev")
检索顶级密钥并自行向下。
如果您的上下文中有 bool
参数并尝试使用 CLI 密钥 --context key=False
覆盖它们,这些参数将变成 str
,并且如果您使用以下常识性语法,则很容易落入陷阱:
if self.try_get_context("deploy_vpc"):
MyVPC(app, "my new vpc")
由于“False”被评估为 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)
...
我正在将我们的基础代码从 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
提供上下文参数,并在代码中使用它的值来获取相关设置。
实际上大多数(如果不是全部)常用结构,如 Stack
、App
、NestedStack
都具有 node
属性,因此您可以从应用中的任何位置访问上下文.
使用它有 2 个注意事项:
它不允许访问较低级别的密钥(或者至少没有记录)。这意味着您不能使用
self.try_get_context("dev.vpc.vpc_id")
,您需要通过self.try_get_context("dev")
检索顶级密钥并自行向下。如果您的上下文中有
bool
参数并尝试使用 CLI 密钥--context key=False
覆盖它们,这些参数将变成str
,并且如果您使用以下常识性语法,则很容易落入陷阱:
if self.try_get_context("deploy_vpc"):
MyVPC(app, "my new vpc")
由于“False”被评估为 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)
...