CDK Deploy-Twice: When Your Infrastructure Needs to Know About Itself
And the endpoint is exported as a stack output:
new cdk.CfnOutput(this, 'ServiceEndpoint', { value: service.attrEndpoint, description: 'Re-deploy with --context baseUrl=<this value> to wire BASE_URL', });
tryGetContext returns undefined if the value was not passed in, so deploy one works fine. It simply runs without BASE_URL set. Deploy two wires it in. Therefore, two deploys, one working service, zero existential crises.
The deploy pattern
Deploy 1: provision the infrastructure, get the endpoint:
cdk deploy EcsExpressStack
Deploy 2: pass the endpoint back in as context:
SERVICE_URL=$(aws cloudformation describe-stacks \ --stack-name EcsExpressStack \ --query "Stacks[0].Outputs[?OutputKey=='ServiceEndpoint'].OutputValue" \ --output text) cdk deploy EcsExpressStack --context baseUrl=$SERVICE_URL
Why this is not a CDK bug
CDK synthesizes a CloudFormation template before anything is deployed. At synth time, late-bound values like ALB endpoints exist only as CloudFormation tokens, which are placeholders that resolve later. You can use them within the same stack (they resolve correctly in the template), but you cannot read them back into your TypeScript logic during synth. This is because the template has not run yet, and therefore the value does not exist yet. This is simply the correct order of operations.
tryGetContext sidesteps this. You supply the value externally on a subsequent deploy, once CloudFormation has resolved it.
When you will run into this
- A service that builds URLs pointing to itself
- A resource that needs its own ARN or DNS name as a config value
- Cross-stack references where stack B’s input is stack A’s output and you have not wired them through
CfnOutputandFn.importValue
The pattern feels a little awkward the first time. It stops feeling awkward once you understand why it works that way. Then starts feeling awkward again when you dust off that old forgotten side project (you know, that one).
So which came first: the service or the endpoint?
The endpoint… but only after the service… which needed the endpoint to configure itself… which required the service to exist first.
At this point, I recommend not thinking about it too hard.
Fuente: Artículo original