-
Notifications
You must be signed in to change notification settings - Fork 1
Feat: use PostgreSQL for the database backend #131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 6 commits
354f0f4
9d70d3f
ed38802
7288a6b
efaa9a6
bfc4663
332fb4a
fc0c42e
721edc3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#!/usr/bin/env bash | ||
set -ex | ||
|
||
# Ensure databases, users, migrations, and superuser are set up | ||
should_reset=${REMOTE_CONTAINERS:-false} | ||
if [[ $should_reset == "true" ]]; then | ||
# running in a devcontainer, reset the DB | ||
python manage.py ensure_db --reset | ||
else | ||
python manage.py ensure_db | ||
fi | ||
|
||
# Load data fixtures (if any) | ||
valid_fixtures=$(echo "$DJANGO_DB_FIXTURES" | grep -e fixtures\.json$ || test $? = 1) | ||
|
||
if [[ -n "$valid_fixtures" ]]; then | ||
python manage.py loaddata $DJANGO_DB_FIXTURES | ||
else | ||
echo "No JSON fixtures to load" | ||
fi |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,29 @@ | ||
#!/usr/bin/env bash | ||
set -eu | ||
|
||
# | ||
# S3 bucket name is injected by Copilot as an environment variable | ||
# since it was created via copilot storage init --name pems-db, the variable is 'PEMSDB_NAME' | ||
S3_BUCKET_NAME="$PEMSDB_NAME" | ||
S3_FIXTURE_PATH="fixtures.json" | ||
LOCAL_FIXTURE_PATH="fixtures.json" | ||
DJANGO_DB_FIXTURES="fixtures.json" | ||
|
||
echo "Downloading $S3_FIXTURE_PATH from bucket $S3_BUCKET_NAME" | ||
aws s3 cp "s3://${S3_BUCKET_NAME}/${S3_FIXTURE_PATH}" "${LOCAL_FIXTURE_PATH}" | ||
aws s3 cp "s3://${S3_BUCKET_NAME}/${S3_FIXTURE_PATH}" "${DJANGO_DB_FIXTURES}" | ||
echo "Download complete" | ||
|
||
# initialize Django | ||
# PostgreSQL database settings (username, host, dbname, password, port) are injected by Copilot as an environment variable | ||
# called 'POSTGRESWEB_SECRET' since the database was created via | ||
# copilot storage init -l workload -t Aurora -w web -n postgres-web --engine PostgreSQL --initial-db django | ||
|
||
bin/init.sh | ||
python manage.py migrate | ||
|
||
# effectively reset database by loading downloaded fixtures into the database | ||
echo "Loading data from ${LOCAL_FIXTURE_PATH}" | ||
python manage.py loaddata "${LOCAL_FIXTURE_PATH}" | ||
echo "Data loading complete" | ||
# Load data fixtures (if any) | ||
valid_fixtures=$(echo "$DJANGO_DB_FIXTURES" | grep -e fixtures\.json$ || test $? = 1) | ||
|
||
# start the web server | ||
if [[ -n "$valid_fixtures" ]]; then | ||
python manage.py loaddata $DJANGO_DB_FIXTURES | ||
else | ||
echo "No JSON fixtures to load" | ||
fi | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems like Otherwise, I don't see There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, I struggled with the organization of this shell script for a bit and even though it works, I don't really like the setup because we are not using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Following #131 (comment), 06d8ca9 fixes how Aurora Serverless is set up. |
||
|
||
nginx | ||
|
||
# start the application server | ||
|
||
python -m gunicorn -c $GUNICORN_CONF pems.wsgi | ||
bin/start.sh |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,10 @@ services: | |
context: . | ||
dockerfile: appcontainer/Dockerfile | ||
image: caltrans/pems:web | ||
command: ["-c", "bin/setup.sh && exec bin/start.sh"] | ||
depends_on: | ||
postgres: | ||
condition: service_healthy | ||
env_file: .env | ||
ports: | ||
- "${DJANGO_LOCAL_PORT:-8000}:8000" | ||
|
@@ -15,13 +19,44 @@ services: | |
context: . | ||
dockerfile: .devcontainer/Dockerfile | ||
image: caltrans/pems:dev | ||
depends_on: | ||
- postgres | ||
- pgweb | ||
env_file: .env | ||
# https://code.visualstudio.com/docs/remote/create-dev-container#_use-docker-compose | ||
entrypoint: sleep infinity | ||
volumes: | ||
- ./:/caltrans/app | ||
- ${HOME}/.aws:/home/caltrans/.aws | ||
|
||
postgres: | ||
image: postgres:16 | ||
environment: | ||
- POSTGRES_DB | ||
- POSTGRES_USER | ||
- POSTGRES_PASSWORD | ||
healthcheck: | ||
test: ["CMD", "pg_isready", "-d", "${POSTGRES_DB}", "-U", "${POSTGRES_USER}"] | ||
interval: 10s | ||
timeout: 60s | ||
retries: 6 | ||
start_period: 10s | ||
ports: | ||
- "${POSTGRES_PORT:-5432}:5432" | ||
volumes: | ||
- pgdata:/var/lib/postgresql/data | ||
|
||
pgweb: | ||
container_name: pgweb | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know you grabbed this as-is from the CDRC work, but I realized there's a conflict. If both projects have this
If I remove this line, it comes up just fine. I'll make a ticket to remove it from CDRC as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for noticing this! Removed it in 332fb4a |
||
image: sosedoff/pgweb | ||
ports: | ||
- "${PGWEB_PORT:-8081}:8081" | ||
depends_on: | ||
postgres: | ||
condition: service_healthy | ||
environment: | ||
- PGWEB_DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOSTNAME}:${POSTGRES_PORT}/${POSTGRES_DB}?sslmode=disable | ||
|
||
docs: | ||
image: caltrans/pems:dev | ||
entrypoint: mkdocs | ||
|
@@ -41,3 +76,7 @@ services: | |
- "${STREAMLIT_LOCAL_PORT:-8501}:8501" | ||
volumes: | ||
- ./:/caltrans/app | ||
|
||
volumes: | ||
pgdata: | ||
driver: local |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
Parameters: | ||
App: | ||
Type: String | ||
Description: Your application's name. | ||
Env: | ||
Type: String | ||
Description: The environment name your service, job, or workflow is being deployed to. | ||
Name: | ||
Type: String | ||
Description: Your workload's name. | ||
# Customize your Aurora Serverless cluster by setting the default value of the following parameters. | ||
postgreswebDBName: | ||
thekaveman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Type: String | ||
Description: The name of the initial database to be created in the Aurora Serverless v2 cluster. | ||
Default: django | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the Since the job of our There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, I think copilot automatically creates the So because of how copilot sets up the database, we don't actually use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this might be the root of these issues. It seems like this We definitely do not want Django using the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💯 |
||
# Cannot have special characters | ||
# Naming constraints: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Limits.html#RDS_Limits.Constraints | ||
Mappings: | ||
postgreswebEnvScalingConfigurationMap: | ||
dev: | ||
"DBMinCapacity": 0.5 # AllowedValues: from 0.5 through 128 | ||
"DBMaxCapacity": 8 # AllowedValues: from 0.5 through 128 | ||
|
||
All: | ||
"DBMinCapacity": 0.5 # AllowedValues: from 0.5 through 128 | ||
"DBMaxCapacity": 8 # AllowedValues: from 0.5 through 128 | ||
|
||
Resources: | ||
postgreswebDBSubnetGroup: | ||
Type: 'AWS::RDS::DBSubnetGroup' | ||
Properties: | ||
DBSubnetGroupDescription: Group of Copilot private subnets for Aurora Serverless v2 cluster. | ||
SubnetIds: | ||
!Split [',', { 'Fn::ImportValue': !Sub '${App}-${Env}-PrivateSubnets' }] | ||
postgreswebSecurityGroup: | ||
Metadata: | ||
'aws:copilot:description': 'A security group for your workload to access the Aurora Serverless v2 cluster postgresweb' | ||
Type: 'AWS::EC2::SecurityGroup' | ||
Properties: | ||
GroupDescription: !Sub 'The Security Group for ${Name} to access Aurora Serverless v2 cluster postgresweb.' | ||
VpcId: | ||
Fn::ImportValue: | ||
!Sub '${App}-${Env}-VpcId' | ||
Tags: | ||
- Key: Name | ||
Value: !Sub 'copilot-${App}-${Env}-${Name}-Aurora' | ||
postgreswebDBClusterSecurityGroup: | ||
Metadata: | ||
'aws:copilot:description': 'A security group for your Aurora Serverless v2 cluster postgresweb' | ||
Type: AWS::EC2::SecurityGroup | ||
Properties: | ||
GroupDescription: The Security Group for the Aurora Serverless v2 cluster. | ||
SecurityGroupIngress: | ||
- ToPort: 5432 | ||
FromPort: 5432 | ||
IpProtocol: tcp | ||
Description: !Sub 'From the Aurora Security Group of the workload ${Name}.' | ||
SourceSecurityGroupId: !Ref postgreswebSecurityGroup | ||
VpcId: | ||
Fn::ImportValue: | ||
!Sub '${App}-${Env}-VpcId' | ||
Tags: | ||
- Key: Name | ||
Value: !Sub 'copilot-${App}-${Env}-${Name}-Aurora' | ||
postgreswebAuroraSecret: | ||
Metadata: | ||
'aws:copilot:description': 'A Secrets Manager secret to store your DB credentials' | ||
Type: AWS::SecretsManager::Secret | ||
Properties: | ||
Description: !Sub Aurora main user secret for ${AWS::StackName} | ||
GenerateSecretString: | ||
SecretStringTemplate: '{"username": "postgres"}' | ||
GenerateStringKey: "password" | ||
ExcludePunctuation: true | ||
IncludeSpace: false | ||
PasswordLength: 16 | ||
postgreswebDBClusterParameterGroup: | ||
Metadata: | ||
'aws:copilot:description': 'A DB parameter group for engine configuration values' | ||
Type: 'AWS::RDS::DBClusterParameterGroup' | ||
Properties: | ||
Description: !Ref 'AWS::StackName' | ||
Family: 'aurora-postgresql16' | ||
Parameters: | ||
client_encoding: 'UTF8' | ||
postgreswebDBCluster: | ||
Metadata: | ||
'aws:copilot:description': 'The postgresweb Aurora Serverless v2 database cluster' | ||
Type: 'AWS::RDS::DBCluster' | ||
Properties: | ||
MasterUsername: | ||
!Join [ "", [ '{{resolve:secretsmanager:', !Ref postgreswebAuroraSecret, ":SecretString:username}}" ]] | ||
MasterUserPassword: | ||
!Join [ "", [ '{{resolve:secretsmanager:', !Ref postgreswebAuroraSecret, ":SecretString:password}}" ]] | ||
DatabaseName: !Ref postgreswebDBName | ||
Engine: 'aurora-postgresql' | ||
EngineVersion: '16.2' | ||
DBClusterParameterGroupName: !Ref postgreswebDBClusterParameterGroup | ||
DBSubnetGroupName: !Ref postgreswebDBSubnetGroup | ||
Port: 5432 | ||
VpcSecurityGroupIds: | ||
- !Ref postgreswebDBClusterSecurityGroup | ||
ServerlessV2ScalingConfiguration: | ||
# Replace "All" below with "!Ref Env" to set different autoscaling limits per environment. | ||
MinCapacity: !FindInMap [postgreswebEnvScalingConfigurationMap, All, DBMinCapacity] | ||
MaxCapacity: !FindInMap [postgreswebEnvScalingConfigurationMap, All, DBMaxCapacity] | ||
postgreswebDBWriterInstance: | ||
Metadata: | ||
'aws:copilot:description': 'The postgresweb Aurora Serverless v2 writer instance' | ||
Type: 'AWS::RDS::DBInstance' | ||
Properties: | ||
DBClusterIdentifier: !Ref postgreswebDBCluster | ||
DBInstanceClass: db.serverless | ||
Engine: 'aurora-postgresql' | ||
PromotionTier: 1 | ||
AvailabilityZone: !Select | ||
- 0 | ||
- !GetAZs | ||
Ref: AWS::Region | ||
|
||
postgreswebSecretAuroraClusterAttachment: | ||
Type: AWS::SecretsManager::SecretTargetAttachment | ||
Properties: | ||
SecretId: !Ref postgreswebAuroraSecret | ||
TargetId: !Ref postgreswebDBCluster | ||
TargetType: AWS::RDS::DBCluster | ||
Outputs: | ||
postgreswebSecret: # injected as POSTGRESWEB_SECRET environment variable by Copilot. | ||
Description: "The JSON secret that holds the database username and password. Fields are 'host', 'port', 'dbname', 'username', 'password', 'dbClusterIdentifier' and 'engine'" | ||
Value: !Ref postgreswebAuroraSecret | ||
postgreswebSecurityGroup: | ||
Description: "The security group to attach to the workload." | ||
Value: !Ref postgreswebSecurityGroup |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just noting a small change I made to how the cert bundle is added to the CDRC image:
This ultimately was because of a change related to the Buildkit caching, where I wasn't copying the entire source directory in anymore during Docker build. That caused some cascading issues with the runtime directory being different from e.g.
/cdt/app
, and one of the problems was this cert bundle couldn't be found by Django.This solves it by not making Django have to construct the path, instead it happens at Docker build time and is baked into the image as an env var.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! If it's ok, I'll add this small change to #132 which is about implementing Buildkit caching.