Configuration & Secrets
[!NOTE] This module explores the core principles of Configuration & Secrets, deriving solutions from first principles and hardware constraints to build world-class, production-ready expertise.
1. The 12-Factor App: Config
One of the core principles of modern software engineering is strictly separating config from code.
You should never rebuild your Docker image just to change a database password or API URL. Instead, you inject these values at runtime using Environment Variables.
2. Injecting Variables
1. The environment Key
The most direct way. Good for non-sensitive defaults.
services:
web:
image: my-app
environment:
- DEBUG=true
- APP_ENV=production
2. The env_file Key
Load variables from a file. This is cleaner and keeps your docker-compose.yaml tidy.
services:
web:
image: my-app
env_file:
- .env
Content of .env:
DEBUG=false
DB_HOST=10.0.0.5
API_KEY=secret123
3. Variable Substitution
You can use variables inside your docker-compose.yaml file. Docker substitutes them from your shell environment or a .env file in the same directory.
services:
db:
image: "postgres:${POSTGRES_VERSION:-15}" # Default to 15 if unset
ports:
- "${HOST_PORT}:5432"
3. Interactive: Variable Flow
See how variables travel from your machine to the container process.
4. Best Practices
- Git Ignore
.env: Never commit secrets to Git. Add.envto your.gitignore. - Use
.env.example: Commit a template file with dummy values so developers know what variables are needed. - Variable Expansion: Use
${VAR:-default}syntax in Compose to provide fallbacks.
5. Reading Env Vars in Code
Go
package main
import (
"fmt"
"os"
)
func main() {
// Read environment variable
dbHost := os.Getenv("DB_HOST")
// Set default if empty
if dbHost == "" {
dbHost = "localhost"
}
fmt.Printf("Connecting to database at %s\n", dbHost)
}
Java
public class Config {
public static void main(String[] args) {
// Read environment variable
String dbHost = System.getenv("DB_HOST");
// Handle null (default value)
if (dbHost == null) {
dbHost = "localhost";
}
System.out.println("Connecting to database at " + dbHost);
}
}