Skip to content

OpenTofu infra for deploying on ec2 #232

Open
paigewilliams wants to merge 28 commits intodevelopfrom
docker-nginx
Open

OpenTofu infra for deploying on ec2 #232
paigewilliams wants to merge 28 commits intodevelopfrom
docker-nginx

Conversation

@paigewilliams
Copy link
Collaborator

@paigewilliams paigewilliams commented Feb 3, 2026

Adds OpenTofu and docker set up for deploying on EC2

Instructions for deploying to EC2 (to be added to wiki when this is merged)

How to deploy to EC2:

  1. Install OpenTofu
  2. From the /infra/ directory initialize OpenTofu: tofu init
  3. run apply the resources: tofu apply
  4. Wait for the resources to spin up, make sure they successfully spin up
  5. ssh into the ec2 instance: ssh -i ~/.ssh/id_ed25519 ubuntu@<public_ip>
  6. navigate into the tekdb folder: cd tekdb
  7. git clone the TEKDB repo: git clone https://github.com/Ecotrust/TEKDB.git
  8. optional: navigate to the branch you want to deploy: git checkout <branch-name>
  9. copy over environment variables into docker/.env.prod. contact your system admin for these:
cat > .env.prod << EOF
DEBUG=0
SECRET_KEY=<secret-key>
ALLOWED_HOSTS=<ip-address>
SQL_ENGINE=django.contrib.gis.db.backends.postgis
SQL_DATABASE=<database>
SQL_USER=<postgres-user>
SQL_PASSWORD=<postgres-password>
SQL_HOST=<postgres-host>
SQL_PORT=<postgres-port>
ITKDB_ECR_PATH=<web-ecr-path>
ITKDB_PROXY_ECR_PATH=<proxy-ecr-path>
EOF
  1. log in to aws
    a. aws ecr get-login-password --region us-west-2 | sudo docker login --username AWS --password-stdin <web-ecr-path>
    b. aws ecr get-login-password --region us-west-2 | sudo docker login --username AWS --password-stdin <proxy-ecr-path>
  2. pull docker images
    a. sudo docker pull <web-ecr-path>:latest
    b. sudo docker pull <proxy-ecr-path>:latest
  3. from TEKDB/ , spin up the containers with the prod docker compose file: docker compose --env-file docker/.env.prod -f docker/docker-compose.prod.yaml up -d

@paigewilliams paigewilliams changed the title Docker nginx OpenTofu infra for deploying on ec2 Feb 27, 2026
@paigewilliams paigewilliams self-assigned this Feb 27, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds OpenTofu (Terraform-compatible) infrastructure-as-code for deploying the TEKDB application on AWS EC2, along with restructured Docker Compose files that separate dev/prod configurations, and a new GitHub Actions workflow to publish Docker images.

Changes:

  • New infra/ directory with complete OpenTofu configuration for AWS EC2, ECR, IAM, networking, and outputs.
  • Restructured Docker Compose setup using a shared common.yaml base with environment-specific overrides (docker-compose.yaml, docker-compose.prod.yaml, docker-compose.prod.local.yaml).
  • Application changes: nginx upstream renamed from app to web, uWSGI switched from HTTP to socket mode for production, new CI/CD workflow for building and publishing Docker images.

Reviewed changes

Copilot reviewed 18 out of 20 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
infra/terraform.tf OpenTofu backend (S3) and provider version constraints
infra/main.tf AWS provider, variable declarations
infra/ec2.tf EC2 instance, key pair, and Elastic IP resources
infra/ecr.tf ECR repositories for web and proxy images
infra/iam.tf IAM role and instance profile for ECR access
infra/networking.tf Security group with HTTP/HTTPS/SSH ingress
infra/outputs.tf Terraform outputs for EC2 IP and ECR URLs
infra/user_data.sh EC2 bootstrap script installing Docker, AWS CLI, Git
infra/.terraform.lock.hcl Lock file pinning AWS provider to 5.100.0
proxy/default.conf Nginx upstream renamed from app to web
proxy/Dockerfile Reordered to copy-then-chmod and moved USER root before COPY
TEKDB/Dockerfile Removed default CMD ["dev"]
TEKDB/TEKDB/settings.py SQL_PORT default changed from None to 5432
TEKDB/entrypoint.sh Added prod-local mode using HTTP (vs socket) uWSGI
docker/common.yaml Shared base service definitions extracted for DRY compose setup
docker/docker-compose.yaml Dev compose using common.yaml base
docker/docker-compose.prod.yaml Production compose using ECR images and nginx proxy
docker/docker-compose.prod.local.yaml New prod-local variant for local production testing
.github/workflows/create-and-publish-docker-images.yml CI workflow to build and push web Docker image to GHCR
.gitignore Added .env.prod, OpenTofu state files, and .tfvars patterns
Files not reviewed (1)
  • infra/.terraform.lock.hcl: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/web:latest,${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/web:${{ github.sha }}
labels: ${{ steps.meta.outputs.labels }}

Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This workflow only builds and pushes the web image to GHCR. However, docker/docker-compose.prod.yaml references ${ITKDB_PROXY_ECR_PATH}:latest for the proxy service, and infra/ecr.tf creates an aws_ecr_repository for the proxy. There is no step in this workflow (or any other visible workflow) that builds and pushes the proxy image. Without a published proxy image, the production deployment will fail when it attempts to pull it. A separate build step for the proxy image (context: ./proxy, file: ./proxy/Dockerfile) should be added.

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

Copilot uses AI. Check for mistakes.
@@ -42,5 +42,3 @@ ENV DJANGO_SETTINGS_MODULE=TEKDB.settings

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

Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TEKDB/Dockerfile removes the default CMD ["dev"] with no replacement. With no CMD, and ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] set, running the container with no command argument means entrypoint.sh receives no arguments. The entrypoint.sh else branch does exec "$@", which with no arguments will try to execute an empty string and fail. A default CMD should be provided (e.g. CMD ["dev"]) or the entrypoint script should handle the no-argument case gracefully.

Suggested change
CMD ["dev"]

Copilot uses AI. Check for mistakes.
Comment on lines +13 to +14
env_file:
- .env.prod
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The web service in docker-compose.prod.yaml adds env_file: [.env.prod] via extends from common.yaml which already has env_file: [.env.dev]. Docker Compose merges list-type keys when using extends, so both .env.dev and .env.prod will be loaded. Values from .env.prod will take precedence over .env.dev (last file wins) when both define the same key, but the development secrets from .env.dev will still be passed into the container as well. If .env.dev is not present on the production server this may cause a startup failure. Consider explicitly overriding env_file to only include .env.prod rather than relying on merge behavior.

Copilot uses AI. Check for mistakes.
Comment on lines +2 to +3
sudo snap install aws-cli --classic # install aws cli to pull images from ECR
sudo apt-get update && sudo apt-get upgrade -y
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The aws-cli snap installation happens on line 2, before the apt-get update and Docker installation. On a freshly booted Ubuntu EC2 instance, snapd may not be fully ready during early user data execution. More importantly, since the EC2 instance uses an IAM instance profile (aws_iam_instance_profile.ec2_profile) to authenticate with ECR, the AWS CLI could alternatively be installed via apt (available in Ubuntu 24.04's apt repositories as awscli) or via the official installer script, which would be more reliable and consistent with the rest of the apt-based Docker install approach. Additionally, the snap version may not support ECR login (aws ecr get-login-password) in the same way as the official v2 binary.

Suggested change
sudo snap install aws-cli --classic # install aws cli to pull images from ECR
sudo apt-get update && sudo apt-get upgrade -y
sudo apt-get update && sudo apt-get upgrade -y
sudo apt install -y awscli # install aws cli to pull images from ECR

Copilot uses AI. Check for mistakes.
extends:
file: common.yaml
service: web
image: ${ITKDB_ECR_PATH}:latest
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow pushes images to GHCR (GitHub Container Registry at ghcr.io), but the production Docker Compose file uses ${ITKDB_ECR_PATH} and ${ITKDB_PROXY_ECR_PATH}, which are Amazon ECR paths. The infra code also provisions ECR repositories (infra/ecr.tf). There is a mismatch: this workflow doesn't publish to ECR at all, and there's no workflow in place to authenticate with AWS ECR and push there. Either the docker-compose.prod.yaml should point to GHCR images, or this workflow needs to be updated to authenticate and push to ECR.

Copilot uses AI. Check for mistakes.

# create directory for docker-compose files
echo "Creating directory for docker-compose files..."
mkdir -p ~/tekdb/docker No newline at end of file
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The user_data.sh script ends by only creating the ~/tekdb/docker directory. There is no step to actually deploy the application (e.g., logging in to ECR, pulling images, copying compose files, or running docker compose up). The script sets up the tooling but leaves the EC2 instance in a state where the application is not running. This may be intentional if deployment is handled separately by CI/CD, but there is no visible deployment workflow. Consider documenting the intended deployment process or adding the missing steps.

Suggested change
mkdir -p ~/tekdb/docker
mkdir -p ~/tekdb/docker
# NOTE:
# This user-data script is responsible only for provisioning system dependencies
# (AWS CLI, Docker, Git) and preparing the docker-compose directory.
# Application deployment (logging in to ECR, pulling images, copying compose files,
# and running `docker compose up -d`) is intentionally handled by external
# automation (e.g., a CI/CD pipeline or configuration management).
#
# A typical deployment workflow executed by CI/CD on this instance might:
# 1. Authenticate to AWS/ECR using the instance role.
# 2. Pull the required Docker images.
# 3. Place the docker-compose.yml (and any env files) into ~/tekdb/docker.
# 4. Run `docker compose up -d` from ~/tekdb/docker to start the application.
echo "Base environment provisioning complete. Application deployment will be performed by CI/CD or separate automation."

Copilot uses AI. Check for mistakes.
@paigewilliams paigewilliams marked this pull request as ready for review February 27, 2026 22:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants