EnvironmentsAlpha

Create your first environment

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

Configuration

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:

  1. .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=
  2. .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
  3. .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
  4. 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.

Terraform state

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
})

Your first environment

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.

Another environment

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.

Listing your environments

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