Env Variables in EC2 - VittorioDeMarzi/hero-beans GitHub Wiki
There are two primary methods for managing environment variables within the context of CodePipeline and CodeDeploy:
- Method 1 (Simpler): Include an environment-specific
.env
file in the build artifact. - Method 2 (More Secure & Flexible But in this moment we don't have access to it): Use AWS Systems Manager (SSM) Parameter Store to manage variables and retrieve them during deployment.
.env
File in the Artifact
Method 1: Include a This method is quick and easy. The idea is to instruct the CodeBuild stage to create a .env
file with the correct values before packaging the artifact that will be sent to CodeDeploy.
Step 1: Add Environment Variables in CodeBuild
- Go to your pipeline in CodePipeline, find your Build stage, and click Edit.
- Click on your CodeBuild project name to open it in a new tab.
- In the CodeBuild console, go to Edit > Environment.
- Scroll down to the Additional configuration > Environment variables section.
- Add your variables here. For example:
- Name:
DB_HOST
- Value:
prod.database.endpoint.com
- Type:
Plaintext
(orParameter Store
if they are already in SSM). - Name:
API_KEY
- Value:
your-secret-api-key
- Type:
Secrets Manager
orParameter Store
(recommended for secrets).
- Name:
buildspec.yml
Step 2: Modify the Now, instruct CodeBuild on how to use these variables to create a .env
file. Add these commands to the build
or pre_build
section of the buildspec.yml
file:
version: 0.2
phases:
build:
commands:
- echo "Building the project..."
# Create the .env file using CodeBuild's environment variables
- echo "DB_HOST=${DB_HOST}" > .env
- echo "DB_USER=${DB_USER}" >> .env
- echo "API_KEY=${API_KEY}" >> .env
# ...other build commands...
artifacts:
files:
- '**/*' # Includes all files, including the new .env file
New buildspec.yml
version: 0.2
phases:
install:
runtime-versions:
java: corretto21
pre_build:
commands:
- echo ">>> Cleaning project..."
- ./gradlew clean
- echo ">>> Creating .env file..."
- echo "DB_HOST=${DB_HOST}" > .env
- echo "DB_USER=${DB_USER}" >> .env
- echo "API_KEY=${API_KEY}" >> .env
- echo ".env file created:"
- cat .env
build:
commands:
- echo ">>> Building jar..."
- ./gradlew bootJar --no-daemon
post_build:
commands:
- echo ">>> Build completed. Packaging for deployment..."
artifacts:
files:
- .env
- build/libs/*.jar
- appspec.yml
- scripts/**/*
discard-paths: no
How it works:
- CodeBuild reads the environment variables you configured.
- The command
echo "DB_HOST=${DB_HOST}" > .env
creates the.env
file and writes the first variable to it. - The subsequent commands using
>>
append the other variables to the same file. - The final artifact will contain the code and the ready-to-use
.env
file. - CodeDeploy will then copy it to the EC2 instance along with everything else.
Now we need to tell the start_server.sh
script to load the variables from the .env
file into the shell's environment before it runs the Java application.
A Spring Boot application automatically reads environment variables from the system, but it doesn't read .env
files by default. The script acts as the bridge.
start_server.sh
Script
Updated #!/bin/bash
set -euo pipefail
# Define the path where the application is deployed.
# This should match the 'destination' in the appspec.yml file.
APP_DIR="/home/ubuntu/app"
ENV_FILE="$APP_DIR/.env"
# Check if the .env file exists and load it.
if [ -f "$ENV_FILE" ]; then
echo ">>> [ApplicationStart] Loading environment variables from $ENV_FILE"
# The 'set -a' command automatically exports all variables defined in the sourced file.
set -a
source "$ENV_FILE"
set +a
else
echo ">>> [ApplicationStart] Warning: .env file not found. Proceeding with existing environment variables."
fi
JAR_FILE=$(ls $APP_DIR/build/libs/*.jar | head -n 1 || true)
PROFILE="${1:-${SPRING_PROFILES_ACTIVE:-prod}}"
SPRING_OPTS="--spring.profiles.active=${PROFILE} --logging.config=classpath:logback-spring.xml"
if [ -z "$JAR_FILE" ]; then
echo ">>> [ApplicationStart] No JAR file found!"
exit 1
fi
echo ">>> [ApplicationStart] Starting: $JAR_FILE (profile=${PROFILE})"
# The Java process will now inherit the variables loaded from the .env file.
nohup java $JAVA_OPTS -jar "$JAR_FILE" $SPRING_OPTS > /dev/null 2>&1 &
What's Changed and Why
APP_DIR
Variable: I've added a variable for the application directory (/home/ubuntu/app
). This makes the script easier to read and modify if you ever change the deployment destination in theappspec.yml
.- Check for
.env
File: Theif [ -f "$ENV_FILE" ]; then
block checks if the.env
file actually exists at the specified path. set -a
andsource
: This is the key part.source "$ENV_FILE"
reads the.env
file and defines the variables (e.g.,DB_HOST=...
) in the current shell.set -a
(short forallexport
) ensures that these variables are exported, making them available to any child processes, which in this case is thejava -jar
command.set +a
disables theallexport
setting afterward.
- Updated
JAR_FILE
Path: I updated the path to use the$APP_DIR
variable for consistency.
Now, when CodeDeploy runs this script, it will first load the configuration from the .env
file, and then the Spring Boot application will start up with all the correct settings.