Conversation
There was a problem hiding this comment.
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.yamlbase with environment-specific overrides (docker-compose.yaml,docker-compose.prod.yaml,docker-compose.prod.local.yaml). - Application changes: nginx upstream renamed from
apptoweb, 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 }} | ||
|
|
There was a problem hiding this comment.
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.
| - 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 }} | |
| @@ -42,5 +42,3 @@ ENV DJANGO_SETTINGS_MODULE=TEKDB.settings | |||
|
|
|||
| ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] | |||
|
|
|||
There was a problem hiding this comment.
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.
| CMD ["dev"] |
| env_file: | ||
| - .env.prod |
There was a problem hiding this comment.
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.
| sudo snap install aws-cli --classic # install aws cli to pull images from ECR | ||
| sudo apt-get update && sudo apt-get upgrade -y |
There was a problem hiding this comment.
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.
| 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 |
| extends: | ||
| file: common.yaml | ||
| service: web | ||
| image: ${ITKDB_ECR_PATH}:latest |
There was a problem hiding this comment.
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.
|
|
||
| # create directory for docker-compose files | ||
| echo "Creating directory for docker-compose files..." | ||
| mkdir -p ~/tekdb/docker No newline at end of file |
There was a problem hiding this comment.
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.
| 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." |
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:
/infra/directory initialize OpenTofu:tofu inittofu applyssh -i ~/.ssh/id_ed25519 ubuntu@<public_ip>cd tekdbgit clone https://github.com/Ecotrust/TEKDB.gitgit checkout <branch-name>docker/.env.prod. contact your system admin for these: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>a.
sudo docker pull <web-ecr-path>:latestb.
sudo docker pull <proxy-ecr-path>:latestTEKDB/, 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