

这是 AWS CDK v2 开发者指南。旧版 CDK v1 于 2022 年 6 月 1 日进入维护阶段，并于 2023 年 6 月 1 日终止支持。

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 配置可使用 AWS CDK 的环境
<a name="configure-env"></a>

您可以通过多种方式配置 AWS 环境，以便可以使用 AWS 云开发工具包 (AWS CDK)。根据您的具体需求，管理 AWS 环境的最佳方法会有所不同。

应用程序中的每个 CDK 堆栈最终都必须与环境相关联，才能确定堆栈的部署位置。

有关 AWS 环境的介绍，请参阅 [AWS CDK 的环境](environments.md)。

## 指定环境的方式
<a name="configure-env-where"></a>

可以在凭证和配置文件中指定环境，也可以使用 AWS 构造库中 `Stack` 构造的 ` [env](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Stack.html#env) ` 属性指定环境。

### 凭证和配置文件
<a name="configure-env-where-files"></a>

您可以使用 AWS 命令行界面 (AWS CLI) 创建 `credentials` 和 `config` 文件，用于存储、组织和管理 AWS 环境信息。要了解有关这些文件的更多信息，请参阅《AWS 命令行界面用户指南》**中的[配置和凭证文件设置](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html)。

存储在这些文件中的值按*配置文件*进行组织。您如何命名配置文件以及这些文件中的键值对将因所用配置编程访问权限的方法而异。要了解有关不同方法的更多信息，请参阅[为 AWS CDK CLI 配置安全凭证](configure-access.md)。

通常，AWS CDK 会解析 `credentials` 文件中的 AWS 账户信息以及 `config` 文件中的 AWS 区域信息。

配置好 `credentials` 和 `config` 文件后，您可以通过 AWS CDK CLI 和环境变量指定要使用的环境。

### 堆栈构造的 env 属性
<a name="configure-env-where-env"></a>

您可以使用 `Stack` 构造的 ` [env](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Stack.html#env) ` 属性为每个堆栈指定环境。此属性定义了要使用的账户和区域。您可以将硬编码值传递给此属性，也可以传递 CDK 提供的环境变量。

要传递环境变量，请使用 `AWS_DEFAULT_ACCOUNT` 和 `AWS_DEFAULT_REGION` 环境变量。这些环境变量可以传递 `credentials` 和 `config` 文件中的值。您也可以使用 CDK 代码中的逻辑来确定这些环境变量的值。

## AWS CDK 的环境优先级
<a name="configure-env-precedence"></a>

如果您使用多种方法指定环境，则 AWS CDK 会遵循以下优先级：

1. 使用 `Stack` 构造的 `env` 属性指定的硬编码值。

1.  使用 `Stack` 构造 的 `env` 属性指定的 `AWS_DEFAULT_ACCOUNT` 和 `AWS_DEFAULT_REGION` 环境变量。

1. 与 `credentials` 和 `config` 文件中的配置文件关联并使用 `--profile` 选项传递到 CDK CLI 的环境信息。

1. 来自 `credentials` 和 `config` 文件的 `default` 配置文件。

## 何时指定环境
<a name="configure-env-when"></a>

使用 CDK 进行开发时，首先要定义 CDK 堆栈，其中包含代表 AWS 资源的构造。接下来，将每个 CDK 堆栈合成一个 AWS CloudFormation 模板。然后，您可以将 CloudFormation 模板部署到您的环境中。您指定环境的方式决定着何时应用您的环境信息，并可能影响 CDK 的行为和结果。

### 在模板合成时指定环境
<a name="configure-env-when-synth"></a>

当您使用 `Stack` 构造的 `env` 属性指定环境信息时，模板合成时将应用您的环境信息。运行 `cdk synth` 或 `cdk deploy` 会生成特定于环境的 CloudFormation 模板。

如果您在 `env` 属性中使用环境变量，则必须使用 CDK CLI 命令的 `--profile` 选项传入包含来自凭证和配置文件中的环境信息的配置文件。然后，模板合成时将应用此信息，以生成特定于环境的模板。

CloudFormation 模板中的环境信息优先于其他方法。例如，如果您使用 `cdk deploy --profile <profile>` 提供了不同的环境，则配置文件将被忽略。

以这种方式提供环境信息时，您可以在 CDK 应用程序中使用与环境相关的代码和逻辑。这也意味着，根据作为合成条件的机器、用户或会话，合成后的模板可能会有所不同。这种方法在开发过程中通常是可以接受或可取的，但不建议用于生产用途。

### 在堆栈部署时指定环境
<a name="configure-env-when-deploy"></a>

如果您不使用 `Stack` 构造的 `env` 属性指定环境，CDK CLI 将在合成时生成一个与环境无关的 CloudFormation 模板。然后，您可以使用 `cdk deploy --profile <profile>` 指定要部署到的环境。

如果您在部署与环境无关的模板时未指定配置文件，CDK CLI 将在部署时尝试使用 `credentials` 和 `config` 文件的 `default` 配置文件中的环境值。

如果部署时未获得环境信息，则 AWS CloudFormation 将在部署时尝试通过与环境相关的属性（例如 `stack.account`、`stack.region` 和 `stack.availabilityZones`）解析环境信息。

对于与环境无关的堆栈，堆栈中的构造不能使用环境信息，您也不能使用需要环境信息的逻辑。例如，您不能编写类似 `if (stack.region ==== 'us-east-1')` 的代码，也不能使用需要环境信息的构造方法，例如 ` [Vpc.fromLookup](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.Vpc.html#static-fromwbrlookupscope-id-options) `。要使用这些功能，必须使用 `env` 属性指定环境。

对于与环境无关的堆栈，任何使用可用区的构造都将看到两个可用区，从而允许将堆栈部署到任何区域。

## 如何使用 AWS CDK 指定环境
<a name="configure-env-how"></a>

### 为每个堆栈指定硬编码环境
<a name="configure-env-how-hard-coded"></a>

使用 `Stack` 构造的 `env` 属性为您的堆栈指定 AWS 环境值。以下是示例：

**Example**  

```
const envEU  = { account: '2383838383', region: 'eu-west-1' };
const envUSA = { account: '8373873873', region: 'us-west-2' };

new MyFirstStack(app, 'first-stack-us', { env: envUSA });
new MyFirstStack(app, 'first-stack-eu', { env: envEU });
```

```
const envEU  = { account: '2383838383', region: 'eu-west-1' };
const envUSA = { account: '8373873873', region: 'us-west-2' };

new MyFirstStack(app, 'first-stack-us', { env: envUSA });
new MyFirstStack(app, 'first-stack-eu', { env: envEU });
```

```
env_EU = cdk.Environment(account="8373873873", region="eu-west-1")
env_USA = cdk.Environment(account="2383838383", region="us-west-2")

MyFirstStack(app, "first-stack-us", env=env_USA)
MyFirstStack(app, "first-stack-eu", env=env_EU)
```

```
public class MyApp {

    // Helper method to build an environment
    static Environment makeEnv(String account, String region) {
        return Environment.builder()
                .account(account)
                .region(region)
                .build();
    }

    public static void main(final String argv[]) {
        App app = new App();

        Environment envEU = makeEnv("8373873873", "eu-west-1");
        Environment envUSA = makeEnv("2383838383", "us-west-2");

        new MyFirstStack(app, "first-stack-us", StackProps.builder()
                .env(envUSA).build());
        new MyFirstStack(app, "first-stack-eu", StackProps.builder()
                .env(envEU).build());

        app.synth();
    }
}
```

```
Amazon.CDK.Environment makeEnv(string account, string region)
{
    return new Amazon.CDK.Environment
    {
        Account = account,
        Region = region
    };
}

var envEU = makeEnv(account: "8373873873", region: "eu-west-1");
var envUSA = makeEnv(account: "2383838383", region: "us-west-2");

new MyFirstStack(app, "first-stack-us", new StackProps { Env=envUSA });
new MyFirstStack(app, "first-stack-eu", new StackProps { Env=envEU });
```

```
env_EU := awscdk.Environment{
	Account: jsii.String("8373873873"),
	Region:  jsii.String("eu-west-1"),
}

env_USA := awscdk.Environment{
	Account: jsii.String("2383838383"),
	Region:  jsii.String("us-west-2"),
}

MyFirstStack(app, "first-stack-us", &awscdk.StackProps{
	Env: &env_USA,
})

MyFirstStack(app, "first-stack-eu", &awscdk.StackProps{
	Env: &env_EU,
})
```

我们建议将此方法用于生产环境。通过以这种方式显式指定环境，您可以确保堆栈始终部署到特定环境中。

### 使用环境变量指定环境
<a name="configure-env-how-env"></a>

AWS CDK 提供了两个可以在 CDK 代码中使用的环境变量：`CDK_DEFAULT_ACCOUNT` 和 `CDK_DEFAULT_REGION`。如果您在堆栈实例的 `env` 属性中使用这些环境变量，则可以使用 CDK CLI `--profile` 选项传入包含来自凭证和配置文件中的环境信息。

以下示例演示了如何指定这些环境变量：

**Example**  
通过 Node 的 `process` 对象访问环境变量。  
您需要 `DefinitelyTyped` 模块，以便在 TypeScript 中使用 `process`。`cdk init` 会为您安装这个模块。但是，如果您使用的是添加模块之前创建的项目，或者您没有使用 `cdk init` 设置项目，则应手动安装此模块。  

```
npm install @types/node
```

```
new MyDevStack(app, 'dev', {
  env: {
    account: process.env.CDK_DEFAULT_ACCOUNT,
    region: process.env.CDK_DEFAULT_REGION
}});
```
通过 Node 的 `process` 对象访问环境变量。  

```
new MyDevStack(app, 'dev', {
  env: {
    account: process.env.CDK_DEFAULT_ACCOUNT,
    region: process.env.CDK_DEFAULT_REGION
}});
```
使用 `os` 模块的 `environ` 字典访问环境变量。  

```
import os
MyDevStack(app, "dev", env=cdk.Environment(
    account=os.environ["CDK_DEFAULT_ACCOUNT"],
    region=os.environ["CDK_DEFAULT_REGION"]))
```
使用 `System.getenv()` 获取环境变量的值。  

```
public class MyApp {

    // Helper method to build an environment
    static Environment makeEnv(String account, String region) {
        account = (account == null) ? System.getenv("CDK_DEFAULT_ACCOUNT") : account;
        region = (region == null) ? System.getenv("CDK_DEFAULT_REGION") : region;

        return Environment.builder()
                .account(account)
                .region(region)
                .build();
    }

    public static void main(final String argv[]) {
        App app = new App();

        Environment envEU = makeEnv(null, null);
        Environment envUSA = makeEnv(null, null);

        new MyDevStack(app, "first-stack-us", StackProps.builder()
                .env(envUSA).build());
        new MyDevStack(app, "first-stack-eu", StackProps.builder()
                .env(envEU).build());

        app.synth();
    }
}
```
使用 `System.Environment.GetEnvironmentVariable()` 获取环境变量的值。  

```
Amazon.CDK.Environment makeEnv(string account=null, string region=null)
{
    return new Amazon.CDK.Environment
    {
        Account = account ?? System.Environment.GetEnvironmentVariable("CDK_DEFAULT_ACCOUNT"),
        Region = region ?? System.Environment.GetEnvironmentVariable("CDK_DEFAULT_REGION")
    };
}

new MyDevStack(app, "dev", new StackProps { Env = makeEnv() });
```

```
import "os"

MyDevStack(app, "dev", &awscdk.StackProps{
	Env: &awscdk.Environment{
		Account: jsii.String(os.Getenv("CDK_DEFAULT_ACCOUNT")),
		Region:  jsii.String(os.Getenv("CDK_DEFAULT_REGION")),
    },
})
```

通过使用环境变量指定环境，可以将相同的 CDK 堆栈合成到 AWS CloudFormation 模板中以用于不同环境。这意味着您可以将相同的 CDK 堆栈部署到不同的 AWS 环境，而无需修改 CDK 代码。您只需要指定要在运行 `cdk synth` 时使用的配置文件即可。

当将同一个堆栈部署到不同的环境时，这种方法非常适合开发环境。但是，我们不建议在生产环境中使用这种方法，因为相同的 CDK 代码可能会合成不同的模板，具体取决于作为合成条件的机器、用户或会话。

### 使用 CDK CLI 从凭证和配置文件指定环境
<a name="configure-env-how-files"></a>

部署与环境无关的模板时，请使用任何 CDK CLI 命令的 `--profile` 选项指定要使用的配置文件。以下是使用 `credentials` 和 `config` 文件中定义的 `prod` 配置文件部署名为 `myStack` 的 CDK 堆栈的示例：

```
$ cdk deploy <myStack> --profile <prod>
```

有关 `--profile` 选项以及其他 CDK CLI 命令和选项的更多信息，请参阅 [AWS CDK CLI 命令参考](ref-cli-cmd.md)。

## 使用 AWS CDK 配置环境时的注意事项
<a name="configure-env-considerations"></a>

使用构造在堆栈中定义的服务必须支持要部署到的区域。有关每个区域支持的 AWS 服务列表，请参阅[按区域划分的 AWS 服务](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/)。

您必须拥有有效的 AWS Identity and Access Management (IAM) 凭证，才能使用 AWS CDK 在您指定的环境中执行堆栈部署。

## 示例
<a name="configure-env-examples"></a>

### 从 CDK 堆栈合成与环境无关的 CloudFormation 模板
<a name="configure-env-examples-agnostic"></a>

在本例中，我们会从 CDK 堆栈创建一个与环境无关的 CloudFormation 模板。然后，我们可以将此模板部署到任何环境。

以下是示例 CDK 堆栈。该堆栈为存储桶所在区域定义了一个 Amazon S3 存储桶和一个 CloudFormation 堆栈输出。本例中未定义 `env`：

**Example**  

```
export class CdkAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Create the S3 bucket
    const bucket = new s3.Bucket(this, 'amzn-s3-demo-bucket', {
      removalPolicy: cdk.RemovalPolicy.DESTROY,
    });

    // Create an output for the bucket's Region
    new cdk.CfnOutput(this, 'BucketRegion', {
      value: bucket.env.region,
    });
  }
}
```

```
class CdkAppStack extends cdk.Stack {
  constructor(scope, id, props) {
    super(scope, id, props);

    // Create the S3 bucket
    const bucket = new s3.Bucket(this, 'amzn-s3-demo-bucket', {
      removalPolicy: cdk.RemovalPolicy.DESTROY,
    });

    // Create an output for the bucket's Region
    new cdk.CfnOutput(this, 'BucketRegion', {
      value: bucket.env.region,
    });
  }
}
```

```
class CdkAppStack(cdk.Stack):

    def __init__(self, scope: cdk.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # Create the S3 bucket
        bucket = s3.Bucket(self, 'amzn-s3-demo-bucket',
            removal_policy=cdk.RemovalPolicy.DESTROY
        )

        # Create an output for the bucket's Region
        cdk.CfnOutput(self, 'BucketRegion',
            value=bucket.env.region
        )
```

```
public class CdkAppStack extends Stack {

    public CdkAppStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);

        // Create the S3 bucket
        Bucket bucket = Bucket.Builder.create(this, "amzn-s3-demo-bucket")
            .removalPolicy(RemovalPolicy.DESTROY)
            .build();

        // Create an output for the bucket's Region
        CfnOutput.Builder.create(this, "BucketRegion")
            .value(this.getRegion())
            .build();
    }
}
```

```
namespace MyCdkApp
{
    public class CdkAppStack : Stack
    {
        public CdkAppStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
        {
            // Create the S3 bucket
            var bucket = new Bucket(this, "amzn-s3-demo-bucket", new BucketProps
            {
                RemovalPolicy = RemovalPolicy.DESTROY
            });

            // Create an output for the bucket's Region
            new CfnOutput(this, "BucketRegion", new CfnOutputProps
            {
                Value = this.Region
            });
        }
    }
}
```

```
func NewCdkAppStack(scope constructs.Construct, id string, props *CdkAppStackProps) awscdk.Stack {
	stack := awscdk.NewStack(scope, &id, &props.StackProps)

	// Create the S3 bucket
	bucket := awss3.NewBucket(stack, jsii.String("amzn-s3-demo-bucket"), &awss3.BucketProps{
		RemovalPolicy: awscdk.RemovalPolicy_DESTROY,
	})

	// Create an output for the bucket's Region
	awscdk.NewCfnOutput(stack, jsii.String("BucketRegion"), &awscdk.CfnOutputProps{
		Value: stack.Region(),
	})

	return stack
}
```

当我们运行 `cdk synth` 时，CDK CLI 会生成一个 CloudFormation 模板，该模板使用伪参数 ` AWS::Region` 作为存储桶所在区域的输出值。此参数将在部署时解析：

```
Outputs:
  BucketRegion:
    Value:
      Ref: AWS::Region
```

要将此堆栈部署到凭证和配置文件的 `dev` 配置文件中指定的环境中，应运行以下命令：

```
$ cdk deploy CdkAppStack --profile dev
```

如果我们不指定配置文件，CDK CLI 将尝试在凭证和配置文件中使用 `default` 配置文件中的环境信息。

### 在模板合成时使用逻辑确定环境信息
<a name="configure-env-example-logic"></a>

在本例中，我们将 `stack` 实例的 `env` 属性配置为使用有效的表达式。我们另外指定了两个环境变量，`CDK_DEPLOY_ACCOUNT` 和 `CDK_DEPLOY_REGION`。这些环境变量可能会在合成时覆盖默认值（如有）：

**Example**  

```
new MyDevStack(app, 'dev', {
  env: {
    account: process.env.CDK_DEPLOY_ACCOUNT || process.env.CDK_DEFAULT_ACCOUNT,
    region: process.env.CDK_DEPLOY_REGION || process.env.CDK_DEFAULT_REGION
}});
```

```
new MyDevStack(app, 'dev', {
  env: {
    account: process.env.CDK_DEPLOY_ACCOUNT || process.env.CDK_DEFAULT_ACCOUNT,
    region: process.env.CDK_DEPLOY_REGION || process.env.CDK_DEFAULT_REGION
}});
```

```
MyDevStack(app, "dev", env=cdk.Environment(
    account=os.environ.get("CDK_DEPLOY_ACCOUNT", os.environ["CDK_DEFAULT_ACCOUNT"]),
    region=os.environ.get("CDK_DEPLOY_REGION", os.environ["CDK_DEFAULT_REGION"])
    )
)
```

```
public class MyApp {

    // Helper method to build an environment
    static Environment makeEnv(String account, String region) {
        account = (account == null) ? System.getenv("CDK_DEPLOY_ACCOUNT") : account;
        region = (region == null) ? System.getenv("CDK_DEPLOY_REGION") : region;
        account = (account == null) ? System.getenv("CDK_DEFAULT_ACCOUNT") : account;
        region = (region == null) ? System.getenv("CDK_DEFAULT_REGION") : region;

        return Environment.builder()
                .account(account)
                .region(region)
                .build();
    }

    public static void main(final String argv[]) {
        App app = new App();

        Environment envEU = makeEnv(null, null);
        Environment envUSA = makeEnv(null, null);

        new MyDevStack(app, "first-stack-us", StackProps.builder()
                .env(envUSA).build());
        new MyDevStack(app, "first-stack-eu", StackProps.builder()
                .env(envEU).build());

        app.synth();
    }
}
```

```
Amazon.CDK.Environment makeEnv(string account=null, string region=null)
{
    return new Amazon.CDK.Environment
    {
        Account = account ??
            System.Environment.GetEnvironmentVariable("CDK_DEPLOY_ACCOUNT") ??
            System.Environment.GetEnvironmentVariable("CDK_DEFAULT_ACCOUNT"),
        Region = region ??
            System.Environment.GetEnvironmentVariable("CDK_DEPLOY_REGION") ??
            System.Environment.GetEnvironmentVariable("CDK_DEFAULT_REGION")
    };
}

new MyDevStack(app, "dev", new StackProps { Env = makeEnv() });
```

```
var account, region string
var b bool

if account, b = os.LookupEnv("CDK_DEPLOY_ACCOUNT"); !b || len(account) == 0 {
	account = os.Getenv("CDK_DEFAULT_ACCOUNT")
}
if region, b = os.LookupEnv("CDK_DEPLOY_REGION"); !b || len(region) == 0 {
	region = os.Getenv("CDK_DEFAULT_REGION")
}

MyDevStack(app, "dev", &awscdk.StackProps{
	Env: &awscdk.Environment{
		Account: &account,
		Region:  &region,
	},
})
```

用这种方式声明堆栈的环境后，我们可以编写一个简短的脚本或批处理文件，并从命令行参数设置变量，然后调用 `cdk deploy`。示例如下：除前两个参数之外的任何参数都将传递到 `cdk deploy`，以指定命令行选项或参数：

**Example**  

```
#!/usr/bin/env bash
if [[ $# -ge 2 ]]; then
    export CDK_DEPLOY_ACCOUNT=$1
    export CDK_DEPLOY_REGION=$2
    shift; shift
    npx cdk deploy "$@"
    exit $?
else
    echo 1>&2 "Provide account and region as first two args."
    echo 1>&2 "Additional args are passed through to cdk deploy."
    exit 1
fi
```
将脚本另存为 `cdk-deploy-to.sh`，然后执行 `chmod +x cdk-deploy-to.sh` 使其可执行。

```
@findstr /B /V @ %~dpnx0 > %~dpn0.ps1 && powershell -ExecutionPolicy Bypass %~dpn0.ps1 %*
@exit /B %ERRORLEVEL%
if ($args.length -ge 2) {
    $env:CDK_DEPLOY_ACCOUNT, $args = $args
    $env:CDK_DEPLOY_REGION,  $args = $args
    npx cdk deploy $args
    exit $lastExitCode
} else {
    [console]::error.writeline("Provide account and region as first two args.")
    [console]::error.writeline("Additional args are passed through to cdk deploy.")
    exit 1
}
```
该脚本的 Windows 版本使用 PowerShell 提供与 macOS/Linux 版本相同的功能。它还包含允许将其作为批处理文件运行的指令，以便可以轻松地从命令行调用。应将其另存为 `cdk-deploy-to.bat`。文件 `cdk-deploy-to.ps1` 将在调用批处理文件时创建。

然后，我们可以编写使用 `cdk-deploy-to` 脚本的其他脚本，进而部署到特定环境。以下是示例：

**Example**  

```
#!/usr/bin/env bash
# cdk-deploy-to-test.sh
./cdk-deploy-to.sh 123457689 us-east-1 "$@"
```

```
@echo off
rem cdk-deploy-to-test.bat
cdk-deploy-to 135792469 us-east-1 %*
```

以下是使用 `cdk-deploy-to` 脚本部署到多个环境的示例。如果第一次部署失败，则进程将停止：

**Example**  

```
#!/usr/bin/env bash
# cdk-deploy-to-prod.sh
./cdk-deploy-to.sh 135792468 us-west-1 "$@" || exit
./cdk-deploy-to.sh 246813579 eu-west-1 "$@"
```

```
@echo off
rem cdk-deploy-to-prod.bat
cdk-deploy-to 135792469 us-west-1 %* || exit /B
cdk-deploy-to 245813579 eu-west-1 %*
```