Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
27d0ff6
use .env.prod in docker-compose.prod.yaml
paigewilliams Feb 3, 2026
5e5cc5b
add github action to publish docker image to github packages
paigewilliams Feb 3, 2026
e91eb06
point push step to prod dockerfile
paigewilliams Feb 3, 2026
ec83f25
try triggering action on push
paigewilliams Feb 3, 2026
453f95e
try generating slug for repo name
paigewilliams Feb 3, 2026
4d93d8d
try getting slug for repo name as string
paigewilliams Feb 3, 2026
43916a5
try again to use lowercase repo name
paigewilliams Feb 3, 2026
521e750
try setting lowercase IMAGE_NAME env var
paigewilliams Feb 3, 2026
05fcd1b
add prod dockerfile
paigewilliams Feb 3, 2026
76b4ab0
remove cache lines for build and push step
paigewilliams Feb 4, 2026
5fb47f5
try token change
paigewilliams Feb 4, 2026
942ea13
remove push from trigger options
paigewilliams Feb 4, 2026
c83e88c
use common docker compose and use extends
paigewilliams Feb 4, 2026
3e60eaa
wip: add gh action to push to ECR and deploy to app runner
paigewilliams Feb 4, 2026
cddcf48
set 5432 as default db port
paigewilliams Feb 24, 2026
bd97aac
use nginx proxy in prod setup
paigewilliams Feb 24, 2026
fd1ec89
add docker compose for testing prod set up locally
paigewilliams Feb 24, 2026
7f91476
add OpenTofu/terraform to gitignore
paigewilliams Feb 24, 2026
60d0dcc
add tf/opentofu IaC
paigewilliams Feb 26, 2026
e8e2c00
track terraform.lock.hcl
paigewilliams Feb 26, 2026
1d46d36
remove deploy app runner gh action workflow
paigewilliams Feb 26, 2026
476f04b
use commands in docker compose not dockerfiles; remove prod.Dockerfile
paigewilliams Feb 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .github/workflows/create-and-publish-docker-images.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# source: https://docs.github.com/en/actions/tutorials/publish-packages/publish-docker-images#publishing-images-to-docker-hub-and-github-packages
name: Create and publish a Docker image

# manually trigger while testing
on:
workflow_dispatch

# Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds.
env:
REGISTRY: ghcr.io

jobs:
build-and-push-image:
runs-on: ubuntu-latest
# Sets the permissions granted to the `PACKAGE_TOKEN` for the actions in this job.
permissions:
contents: read
packages: write
attestations: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v5
# Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.PACKAGE_TOKEN }}
# This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels.
- name: Set lowercase image name
run: |
IMAGE_NAME=$(echo "${GITHUB_REPOSITORY}" | tr '[:upper:]' '[:lower:]')
echo "IMAGE_NAME=${IMAGE_NAME}" >> $GITHUB_ENV
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Format repo slug
uses: actions/github-script@v8
id: repo_slug
with:
result-encoding: string
script: |
return `ghcr.io/${process.env.GITHUB_REPOSITORY.toLowerCase()}`
# This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages.
# It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see [Usage](https://github.com/docker/build-push-action#usage) in the README of the `docker/build-push-action` repository.
# It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step.

- name: Build and push Docker image
id: push
uses: docker/build-push-action@v6
with:
context: ./TEKDB
file: ./TEKDB/Dockerfile
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/web:latest,${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/web:${{ github.sha }}
labels: ${{ steps.meta.outputs.labels }}

# This step generates an artifact attestation for the image, which is an unforgeable statement about where and how it was built. It increases supply chain security for people who consume the image. For more information, see [Using artifact attestations to establish provenance for builds](/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds).
- name: Generate artifact attestation
uses: actions/attest-build-provenance@v3
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: true

9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ celerybeat-schedule

# dotenv
.env
.env.prod

# virtualenv
venv/
Expand All @@ -98,4 +99,10 @@ ENV/
.ropeproject

#vscode settings
.vscode/
.vscode/

# OpenTofu/Terraform
.terraform/
terraform.tfstate
terraform.tfstate.backup
*.tfvars
2 changes: 0 additions & 2 deletions TEKDB/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,3 @@ ENV DJANGO_SETTINGS_MODULE=TEKDB.settings

ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

# use development server by default
CMD ["dev"]
2 changes: 1 addition & 1 deletion TEKDB/TEKDB/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@
"USER": os.environ.get("SQL_USER", "postgres"),
"PASSWORD": os.environ.get("SQL_PASSWORD", None),
"HOST": os.environ.get("SQL_HOST", "db"),
"PORT": os.environ.get("SQL_PORT", None),
"PORT": os.environ.get("SQL_PORT", 5432),
}
}

Expand Down
7 changes: 5 additions & 2 deletions TEKDB/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@ if [ "$(python manage.py shell -c 'from TEKDB.models import LookupPlanningUnit;
fi

if [ "$1" = "prod" ]; then
echo "Starting uWSGI (HTTP) on :8000"
uwsgi --http :8000 --master --enable-threads --module TEKDB.wsgi
echo "Starting uWSGI (socket) on :8000"
uwsgi --socket :8000 --master --enable-threads --module TEKDB.wsgi
elif [ "$1" = "prod-local" ]; then
echo "Starting uWSGI (http) on :8000 with local settings"
uwsgi --http :8000 --master --enable-threads --module TEKDB.wsgi
elif [ "$1" = "dev" ]; then
echo "Starting python development server on :8000"
python manage.py runserver 0.0.0.0:8000
Expand Down
19 changes: 2 additions & 17 deletions docker/docker-compose.yml → docker/common.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ services:
interval: 10s
timeout: 5s
retries: 5

web:
build:
context: ../TEKDB/
Expand All @@ -26,20 +26,5 @@ services:
- db
env_file:
- .env.dev
environment:
ALLOWED_HOSTS: ${ALLOWED_HOSTS}
DEBUG: ${DEBUG}
SQL_ENGINE: ${SQL_ENGINE}
SQL_HOST: ${SQL_HOST}
SQL_PORT: ${SQL_PORT}
SQL_DATABASE: ${SQL_DATABASE}
SQL_USER: ${SQL_USER}
SQL_PASSWORD: ${SQL_PASSWORD}
SECRET_KEY: ${SECRET_KEY}
ports:
- "8000:8000"
volumes:
- ../TEKDB:/usr/src/app

volumes:
tekdb_db_data:
- "8000:8000"
34 changes: 34 additions & 0 deletions docker/docker-compose.prod.local.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
services:
db:
extends:
file: common.yaml
service: db

web:
extends:
file: common.yaml
service: web
command: ["prod-local"]
env_file:
- .env.dev
ports: []
volumes:
- static_volume:/usr/src/app/static
- media_volume:/usr/src/app/media
proxy:
build:
context: ../proxy/
dockerfile: ../proxy/Dockerfile
restart: unless-stopped
depends_on:
- web
ports:
- "8080:8080"
volumes:
- static_volume:/vol/static/static:ro
- media_volume:/vol/static/media:ro

volumes:
tekdb_db_data:
static_volume:
media_volume:
55 changes: 21 additions & 34 deletions docker/docker-compose.prod.yaml
Original file line number Diff line number Diff line change
@@ -1,46 +1,33 @@
services:
db:
image: postgis/postgis:15-3.4
restart: always
platform: linux/amd64
environment:
POSTGRES_DB: ${SQL_DATABASE}
POSTGRES_USER: ${SQL_USER}
POSTGRES_PASSWORD: ${SQL_PASSWORD}
volumes:
- tekdb_db_data:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${SQL_USER} -d ${SQL_DATABASE} -h localhost -p ${SQL_PORT}"]
interval: 10s
timeout: 5s
retries: 5
extends:
file: common.yaml
service: db

web:
build:
context: ../TEKDB/
dockerfile: ../TEKDB/Dockerfile
extends:
file: common.yaml
service: web
image: ${ITKDB_ECR_PATH}:latest
command: ["prod"]
env_file:
- .env.prod
ports: []
volumes:
- static_volume:/usr/src/app/static
- media_volume:/usr/src/app/media
proxy:
image: ${ITKDB_PROXY_ECR_PATH}:latest
restart: unless-stopped
depends_on:
- db
env_file:
- .env.dev
environment:
ALLOWED_HOSTS: ${ALLOWED_HOSTS}
DEBUG: ${DEBUG}
SQL_ENGINE: ${SQL_ENGINE}
SQL_HOST: ${SQL_HOST}
SQL_PORT: ${SQL_PORT}
SQL_DATABASE: ${SQL_DATABASE}
SQL_USER: ${SQL_USER}
SQL_PASSWORD: ${SQL_PASSWORD}
SECRET_KEY: ${SECRET_KEY}
- web
ports:
- "8000:8000"
- "80:8080"
volumes:
- ../TEKDB:/usr/src/app
- static_volume:/vol/static/static:ro
- media_volume:/vol/static/media:ro

volumes:
tekdb_db_data:
static_volume:
media_volume:
26 changes: 26 additions & 0 deletions docker/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
services:
db:
extends:
file: common.yaml
service: db

web:
extends:
file: common.yaml
service: web
command: ["dev"]
volumes:
- ../TEKDB:/usr/src/app
environment:
ALLOWED_HOSTS: ${ALLOWED_HOSTS}
DEBUG: ${DEBUG}
SQL_ENGINE: ${SQL_ENGINE}
SQL_HOST: ${SQL_HOST}
SQL_PORT: ${SQL_PORT}
SQL_DATABASE: ${SQL_DATABASE}
SQL_USER: ${SQL_USER}
SQL_PASSWORD: ${SQL_PASSWORD}
SECRET_KEY: ${SECRET_KEY}

volumes:
tekdb_db_data:
20 changes: 20 additions & 0 deletions infra/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

55 changes: 55 additions & 0 deletions infra/ec2.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
resource "aws_key_pair" "itkdb" {
key_name = "${var.project_name}-key"
public_key = var.ssh_public_key

tags = {
Project = "${var.project_name}-staging"
}
}

resource "aws_instance" "itkdb" {
ami = var.ec2_ami
instance_type = var.ec2_instance_type
key_name = aws_key_pair.itkdb.key_name
vpc_security_group_ids = [aws_security_group.itkdb.id]
iam_instance_profile = aws_iam_instance_profile.ec2_profile.name
subnet_id = tolist(data.aws_subnets.default.ids)[0]
user_data_replace_on_change = true

# TODO: fix this! currently does not work
# Install Docker and AWS CLI v2 on first boot
user_data = <<-EOF
#!/bin/bash
set -e
sudo apt update
sudo apt install -y docker
systemctl start docker
systemctl enable docker
usermod -aG docker ubuntu
sudo snap install aws-cli --classic
unzip awscliv2.zip
sudo ./aws/install
EOF

root_block_device {
volume_size = 20
volume_type = "gp3"
encrypted = true
}

tags = {
Name = "${var.project_name}-staging-server"
Project = var.project_name
}
}

# Elastic IP so the address never changes across stop/start
resource "aws_eip" "itkdb" {
instance = aws_instance.itkdb.id
domain = "vpc"

tags = {
Name = "${var.project_name}-staging-eip"
Project = var.project_name
}
}
17 changes: 17 additions & 0 deletions infra/ecr.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
resource "aws_ecr_repository" "web" {
name = "ecotrust/${var.project_name}"
image_tag_mutability = "MUTABLE"

tags = {
Project = var.project_name
}
}

resource "aws_ecr_repository" "proxy" {
name = "ecotrust/${var.project_name}-proxy"
image_tag_mutability = "MUTABLE"

tags = {
Project = var.project_name
}
}
Loading