Manage Environment Related Config
In this chapter we’ll look at how our services will connect to each other while they are deployed across multiple environments.
Let’s quickly review the setup that we’ve created back in the Organizing services chapter.
- We have two repos — serverless-stack-demo-ext-resources and serverless-stack-demo-ext-api. One has our infrastructure specific resources, while the other has all our Lambda functions.
- The
serverless-stack-demo-ext-resourcesrepo is deployed a couple of long lived environments; likedevandprod. - While, the
serverless-stack-demo-ext-apiwill be deployed to a few ephemeral environments (likefeatureXthat is connected to thedevenvironment), in addition to the long lived environments above.
But before we can deploy to an ephemeral environment like featureX, we need to figure out a way to let our services know which infrastructure environment they need to talk to.
Let’s look at how to do that.
Set a stage environment variable
In the serverless.common.yml file, we defined:
custom:
# Our stage is based on what is passed in when running serverless
# commands. Or fallsback to what we have set in the provider section.
stage: ${opt:stage, self:provider.stage}
resourcesStages:
prod: prod
dev: dev
resourcesStage: ${self:custom.resourcesStages.${self:custom.stage}, self:custom.resourcesStages.dev}
The above code reads the current stage from the serverless commands, and selects the corresponding resourcesStage config.
- If the stage is
prod, it uses theprodinfrastructure. - If the stage is
dev, it uses thedevinfrastructure. - And if stage is
featureX, it falls back to the dev config and uses thedevinfrastructure.
And then in each service, we are going to pass the resourcesStage to the Lambda functions as an environment variable. Open up the serverless.yml file in a service.
...
custom: ${file(../../serverless.common.yml):custom}
provider:
environment:
stage: ${self:custom.stage}
resourcesStage: ${self:custom.resourcesStage}
...
This adds a resourcesStage environment variable to all the Lambda functions in the service. Recall that we can access this via the process.env.resourcesStage variable at runtime.
Create a stage based config
Now in our config.js, we’ll read the resourcesStage from the environment variable process.env.resourcesStage.
const stage = process.env.stage;
const resourcesStage = process.env.resourcesStage;
const adminPhoneNumber = "+14151234567";
const stageConfigs = {
dev: {
stripeKeyName: "/stripeSecretKey/test"
},
prod: {
stripeKeyName: "/stripeSecretKey/live"
}
};
const config = stageConfigs[stage] || stageConfigs.dev;
export default {
stage,
resourcesStage,
adminPhoneNumber,
...config
};
Finally, while calling DynamoDB we can use the config to get the DynamoDB table we want to use. In libs/dynamodb-lib.js:
import AWS from "./aws-sdk";
import config from "../config";
const client = new AWS.DynamoDB.DocumentClient();
export default {
get: (params) => client.get(updateTableName(params)).promise(),
query: (params) => client.query(updateTableName(params)).promise(),
put: (params) => client.put(updateTableName(params)).promise(),
update: (params) => client.update(updateTableName(params)).promise(),
delete: (params) => client.delete(updateTableName(params)).promise(),
};
function updateTableName(params) {
return {
...params,
TableName: `${config.resourcesStage}-${params.TableName}`,
};
}
The above setup ensures that even when we create numerous ephemeral environments for our API services, they’ll always connect back to the dev environment of our resources.
Next, let’s look at how to store secrets across our environments.
For help and discussion
Comments on this chapter