In Scaffold, the idea of “environments” is the idea that the code that define your infrastructure can be run using multiple different configurations.
For example, the dev environment should use a minimal configuration (no auto-scaling, unique instance...) to reduce costs, while the prod environment should use a set of configuration optimized for power and durability.
Your environments will also often be deployed into separate cloud provider accounts to minimize the risk of one environment affecting others.
Moreover, we don't want that an update in the dev infrastructure could affect the prod one. So your environments, while sharing the same codebase, must not share any Terraform state.
In other words, an "environment" in Scaffold could be summed this way:
Environment = configuration + Terraform state
Scaffold uses the dotenv flow to load your configuration. The dotenv flow use several .env* files that will overwrite each other depending on the current environment:
.env: All infrastructures start with a .env file that will contain all the environment variables used by your infrastructure.
Default public values shared by all environments must be filled while the private ones or the ones that will differ depending on environment must be left blank. This file will be pushed to your Git repository.
# .env
GITHUB_REPO=my-repo # Shared by all environments
GITHUB_BRANCH=
GITHUB_OAUTH_TOKEN=
.env.{environment}: All environments will have an associated .env.{environment} file that will contain all the public overwrites required by the environment.
Only public values must be filled here. This file will be pushed to your Git repository.
# .env.dev
GITHUB_BRANCH=development # Shared by all the people using the dev environment
.env.{environment}.local: All environments will also have an associated .local file that will contain all the private overwrites required by the environment.
All private values must be filled here. This file will not be pushed to your Git repository.
# .env.dev.local
GITHUB_OAUTH_TOKEN=token # Never pushed to Git
MY_VAR: Environment variables that are already set will never be overwritten. In other words, the command line variables have a higher priority over all those defined in env files.
In Scaffold, each environment is mapped to a different Terraform state, stored remotely in a S3 backend.
You will be required to link an AWS account for each environment that you want to create. The use of a local state file is currently not supported.
To link an AWS account, you will need to have configured the AWS CLI with the wanted named profile using the aws configure command.
Under the hood, Scaffold will add several SCAFFOLD_* environment variables to your env files that will be passed to your code to configure the S3 backend and the AWS provider.
// main.ts
// ...
new S3Backend(this, {
key: process.env.SCAFFOLD_AWS_S3_BACKEND_KEY,
bucket: process.env.SCAFFOLD_AWS_S3_BACKEND_BUCKET,
dynamodbTable: process.env.SCAFFOLD_AWS_S3_BACKEND_DYNAMODB_TABLE,
encrypt: true,
region: process.env.SCAFFOLD_AWS_REGION,
profile: process.env.SCAFFOLD_AWS_PROFILE
})
new AwsProvider(this, "aws", {
region: process.env.SCAFFOLD_AWS_REGION,
profile: process.env.SCAFFOLD_AWS_PROFILE
})
Now that your infrastructure code have been downloaded using the aws:static-website command, you will need to initialize it using the init command.
Under the hood, the init command will look for all the .env.{environment} files that don't have a corresponding .local file to detect unconfigured environments. (Remember that the .env.{environment} files are pushed to your Git repository!)
Given that you don't have any environment yet, the init command will simply let you creating a new one.
In your infrastructure directory, run:
$ scaffold init
No environment found. Creating a new one.
? Environment name: dev
Configuring dev:
› Choose an AWS account
On which AWS account do you want to create this infrastructure?
? AWS account: default
› Choose an AWS region
On which region do you want to create this infrastructure?
? AWS region: us-east-1
› Set your domain name
On which domain (or subdomain) should your application be accessible?
? Domain name: dev.my-project.com
› Pick a GitHub repository
Which repository contains your source code?
? Repository: my-github-account/my-react-app
› Choose a branch to deploy from
From which branch do you want to deploy?
? Branch: development
› Set a build command (optional)
Do your website needs to be build (e.g. npm i && npm run build)?
? Build command: npm i && npm run build
? Build output directory: build
Configuring your environment... done
Created .env
Created .env.dev
Created .env.dev.local
Created AWS S3 Backend
S3 bucket: scaffold-5f58ecad9002b01aa151d199-state
DynamoDB table: scaffold_5f58ecad9002b01aa151d199_state_locks
Success! Configured "dev" environment at /.../my-project
You can now review the generated code or create this infrastructure by running:
scaffold apply dev
As you can see, the init command will ask you several questions depending on the environment variables needed by your infrastructure.
The CLI will also ask you for the additional variables that you may have added to your .env files. In this way, all your teammates will have a fully-working infrastructure code each time they configure their local environments.
The init command also takes care of creating all the resources required to manage your Terraform state, namely a S3 bucket and a DynamoDB table for the storage and locking.
If you remember correctly from the previous parts, the infrastructure for your React app needs to have two distinct environments: dev and prod.
The init command is only used to configure unconfigured environments or directly after the first download. If you want to create another environment, you need to run the env:create command.
In your infrastructure directory, run:
$ scaffold env:create prod
Configuring prod:
› Choose an AWS account
On which AWS account do you want to create this infrastructure?
? AWS account: production
› Choose an AWS region
On which region do you want to create this infrastructure?
? AWS region: us-east-1
› Set your domain name
On which domain (or subdomain) should your application be accessible?
? Domain name: my-project.com
› Pick a GitHub repository
Which repository contains your source code?
? Repository: my-github-account/my-react-app
› Choose a branch to deploy from
From which branch do you want to deploy?
? Branch: master
› Set a build command (optional)
Do your website needs to be build (e.g. npm i && npm run build)?
? Build command: npm i && npm run build
? Build output directory: build
Configuring your environment... done
Created .env.prod
Created .env.prod.local
Created AWS S3 Backend
S3 bucket: scaffold-5f58fb9ac849401f0d24f487-state
DynamoDB table: scaffold_5f58fb9ac849401f0d24f487_state_locks
Success! Configured "prod" environment at /.../my-project
You can now review the generated code or create this infrastructure by running:
scaffold apply prod
As you can see, the output resemble the init one. The sole difference is that the .env file have not been created given that it already exists.
If you have been paying attention, you may also have remarked that the Build command and Build output directory have been pre-filled with the default values set in your .env file.
That's it! You now have created a dev and prod environment. To ensure those environments have been successfully configured, you can run the env:list command:
$ scaffold env:list
Configured:
dev
prod
Unconfigured:
No environment