Create deployment docker setup (AWS series #671–675) #219#681
Open
drakeredwind01 wants to merge 8 commits into
Open
Create deployment docker setup (AWS series #671–675) #219#681drakeredwind01 wants to merge 8 commits into
drakeredwind01 wants to merge 8 commits into
Conversation
…and entrypoint-aws.sh #672
Single-stage: 74MB → multi-stage: 60.7MB (18% reduction)
for more information, see https://pre-commit.ci
| @@ -0,0 +1,27 @@ | |||
| from .settings import * # noqa: F401, F403 | |||
fyliu
requested changes
Jun 11, 2026
fyliu
left a comment
Member
There was a problem hiding this comment.
Thanks for working on this. But can you create separate PRs for each issue so that it's easier to review? These points may belong to different issues, but I can't be sure. There might be more issues, but these are the more visible ones.
- Please remove the first commit from the commit chain. That commit is attempting to implement a "not planned" issue.
- Please fix the code quality comment about importing all.
- Please test that the changes work before creating the PR. The MkDocs service is crashing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #219
AWS Deployment Series — Issues #671–675
A complete AWS production deployment setup built across five issues on branch
drake_670_integrate_whitenoise.Summary
requirements-aws.in/txt; correctedpsycopg2-binaryand addedwhitenoisesettings_aws.py,urls_aws.py, updatedDockerfile-awsandentrypoint-aws.shDOCKER_BUILDKIT=1; updatedaws-resources.mdKey discoveries across the series
psycopg2-binarywas incorrectly classified as dev-only in the issue — it's the database driver, required everywhereDJANGO_ALLOWED_HOSTShad no default, crashingcollectstaticat Docker build timedrf_spectacularturned out to be a runtime import dependency (used inviews.pydecorators), not dev-only — had to be added back torequirements-aws.inrequirements-aws.txtcompiled locally resolved packages incompatible with Python 3.10 in the Docker image — always compile with--python-version 3.10Split requirements into dev and AWS #671
Response for HFLA re: requirements classification
psycopg2-binaryis marked as a dev dependency in the issue, but it's the PostgreSQL database driver — the app cannot connect to the database without it in any environment. It should be included inrequirements-aws.in.whitenoisewas not listed in the issue but has already been added torequirements.inon the current branch; it belongs inrequirements-aws.inas well since it serves static files in production.Files created:
Files updated:
Add gunicorn and Whitenoise, and set up Dockerfile-aws and entrypoint-aws.sh #672
Pre-implementation concerns
1. INSTALLED_APPS references dev-only packages not in requirements-aws.txt (serious)
settings.pyincludesdrf_spectacularanddjango_linear_migrationsinINSTALLED_APPS. Neither is installed in the production image, so the container will crash withModuleNotFoundErroron startup.Decision: create
app/peopledepot/settings_aws.pythat imports fromsettings.pyand overridesINSTALLED_APPSto exclude dev-only apps. This is the industry standard approach (used by Cookiecutter Django). SetDJANGO_SETTINGS_MODULE=peopledepot.settings_awsinDockerfile-aws.Resolved:
app/peopledepot/settings_aws.pycreated.Note: uses
from .settings import *— the accepted Django idiom for settings inheritance (settings are a config namespace, not a module; explicit imports would require listing every setting).# noqa: F401, F403silences flake8, which doesn't know this is a settings file.2.
collectstaticduringdocker buildcrashes on missingDJANGO_ALLOWED_HOSTSsettings.py:37:os.environ.get("DJANGO_ALLOWED_HOSTS").split(",")raisesAttributeErrorwhen the env var is unset at build time, preventing Django settings from loading at all.Decision: add a default —
os.environ.get("DJANGO_ALLOWED_HOSTS", "localhost").split(",")— so the build can proceed without that env var.Resolved:
settings.py:37updated with default.3.
drf_spectacularis a runtime import dependency — missed in #672, fixed in #674views.pyimportsdrf_spectacularat the module level for@extend_schemadecorators. Removing it fromINSTALLED_APPSinsettings_aws.pywasn't enough — it also needs to be installed. It was incorrectly classified as dev-only; it's actually a runtime import dependency of the application code.Fix (applied in #674): add
drf-spectacularback torequirements-aws.in; keep it out ofINSTALLED_APPSso schema endpoints and management commands stay inactive in production. Also createdurls_aws.pyto exclude the schema UI routes.4. Dockerfile-aws has graphviz and Roboto font
These were copied from the dev Dockerfile and serve no production purpose. Leaving them in — out of scope for this issue, can be a separate issue if HFLA wants them removed.
Files created:
Files updated:
Optimize Dockerfile-aws with multi-stage build #673
Pre-implementation concerns
1. Must build and measure the single-stage image before refactoring
The acceptance criteria requires a before/after size comparison. Need to build and record the current image size first, then implement the multi-stage build, then measure again. Do not start the refactor until the baseline is captured.
2. Size savings will be modest — I agree
The cache mounts (
--mount=type=cache) added in #672 already keep pip/apk caches out of image layers, which was historically the biggest multi-stage win. Savings here will mainly be removingpipanduvfrom the final image. The issue itself flags this uncertainty; I confirmed the expectation going in.3.
staticfiles/must be explicitly copied from builder to runtime stage (foresight)collectstaticruns in the builder stage and writes tostaticfiles/. This directory must be explicitlyCOPY --from=builder'd into the runtime stage — whitenoise serves from it at runtime. Pre-emptively noted to avoid missing it during implementation.size before
docker build -f app/Dockerfile-aws -t peopledepot-aws:single-stage app/
docker image inspect peopledepot-aws:single-stage --format='{{.Size}}' | numfmt --to=inspect
71M
docker images peopledepot-aws:single-stage
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
peopledepot-aws:single-stage fded4b4e4602 330MB 74MB
reclaim space
docker rmi peopledepot-aws:single-stage
size after
docker build -f app/Dockerfile-aws -t peopledepot-aws:multi-stage app/
docker images peopledepot-aws:multi-stage
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
peopledepot-aws:multi-stage 56eed5b30e55 282MB 60.7MB
reclaim space
docker rmi peopledepot-aws:multi-stage
size diff
18% reduction (74MB → 60.7MB)
Files updated:
Create docker-compose-aws.yml for local testing #674
Pre-implementation concerns (not mentioned in the issue)
1. Must NOT mount the app directory as a volume
docker-compose.yml(dev) mounts./app/:/usr/src/app/so developers can edit code and see changes instantly without rebuilding the image — this is intentional for development workflow.docker-compose-aws.ymlmust NOT do this. The app code is baked into the image during the build (COPY . .in Dockerfile-aws). Mounting the directory would overwrite it with live local code, bypassingcollectstatic, the multi-stage build, andsettings_aws.py— nothing production-like would actually be tested.Proposed change: omit the volume mount entirely from
docker-compose-aws.yml.2. Need a new
.env.docker-awsfile.env.dockerhasDEBUG=True— wrong for production testing..env.prod.samplehasSECURE_SSL_REDIRECT=True— causes an infinite redirect loop locally since there's no SSL certificate. Neither works as-is.Proposed change: create
app/.env.docker-awsandapp/.env.docker-aws-examplebased on.env.prod.samplebut withDEBUG=False, SSL settings off, and local-friendlyDJANGO_ALLOWED_HOSTS.3. Port conflict with dev compose
Dev compose binds host ports
8000(web) and5432(postgres). Running both simultaneously would fail.Proposed change: use
8001:8000and5433:5432indocker-compose-aws.yml. Dev keeps the familiarlocalhost:8000; production is accessible atlocalhost:8001. The compose file handles the mapping — developers don't need to remember the port numbers.Port notation is
host:container. The left side (host port) is where the conflict would happen — dev uses 5432, aws uses 5433, so both can run simultaneously. The right side (5432) is PostgreSQL's internal port inside each container — they're separate containers so that never conflicts.4. Postgres named volume must differ from dev
Dev compose uses named volume
postgres_data. Ifdocker-compose-aws.ymlused the same name, both environments would share the same database on disk — migration conflicts and data bleed between environments.Resolved: use
postgres_data_awsindocker-compose-aws.yml.5.
.env.docker-awsnot covered by.gitignoreThe gitignore lists explicit filenames rather than a wildcard, so
.env.docker-awswould have been committed with secrets.Resolved:
.env.docker-awsadded to.gitignore.Files created:
docker-compose-aws.yml— builds Dockerfile-aws, ports 8001:8000 and 5433:5432, postgres_data_aws volume, no code volume mountapp/.env.docker-aws-example— production-like env: DEBUG=False, SSL settings off, local ALLOWED_HOSTS; committed as templateapp/.env.docker-aws— gitignored developer copy of the abovedocs/contributing/howto/test-aws-setup-locally.md— full guide: setup steps, cleanup commands, comparison table of dev vs aws environmentsdocs/contributing/onboarding/test_aws_locally.md— two commands and a link to the full guideFiles updated:
.gitignore— added.env.docker-awsdocs/contributing/howto/index.md— added link to new guideIssues found during testing and fixes applied
drf_spectacular still imported via views.py
views.pyimportsdrf_spectacularat the module level for@extend_schemadecorators. Removing it fromINSTALLED_APPSwasn't enough —include("core.api.urls")triggersviews.pyimport at startup.Fix: added
drf-spectacularback torequirements-aws.in(it's a runtime import dependency, not dev-only); createdapp/peopledepot/urls_aws.pywithout schema UI routes; addedROOT_URLCONF = "peopledepot.urls_aws"tosettings_aws.py.requirements-aws.txt compiled against wrong Python version
Recompiling locally resolved
rpds-py==2026.5.1which requires Python>=3.11, butDockerfile-awsuses Python 3.10 — build failed.Fix: recompiled with
uv pip compile --python-version 3.10; updatedscripts/update-dependencies.shto always pass--python-version 3.10for the aws compile command.Files created (including fixes):
docker-compose-aws.ymlapp/.env.docker-aws-exampleapp/.env.docker-awsapp/peopledepot/urls_aws.py— production URL config without schema UI routesdocs/contributing/howto/test-aws-setup-locally.mddocs/contributing/onboarding/test_aws_locally.mdFiles updated (including fixes):
.gitignore— added.env.docker-awsapp/requirements-aws.in— addeddrf-spectacularapp/requirements-aws.txt— recompiled targeting Python 3.10app/peopledepot/settings_aws.py— addedROOT_URLCONF = "peopledepot.urls_aws"scripts/update-dependencies.sh— added--python-version 3.10to aws compile commanddocs/contributing/howto/index.md— added link to new guideUpdate deployment workflow #675
Most action items already handled pre-emptively in #671–674
deploy-dev.ymlalready usesdocker build -f Dockerfile-awsrequirements-aws.txtis referenced insideDockerfile-aws— picked up automaticallysettings_aws.pyis set viaENV DJANGO_SETTINGS_MODULEinDockerfile-aws— baked inentrypoint-aws.shis theENTRYPOINTinDockerfile-aws— already correctentrypoint-aws.sh— already in placePre-implementation concerns
1. BuildKit not explicitly enabled — NOT mentioned in the issue
Dockerfile-awsuses--mount=type=cachewhich requires BuildKit. GitHub Actions enables BuildKit by default on recent Docker versions but it is not guaranteed and is not explicitly set in the workflow. If missing, the build fails with a syntax error on the--mountlines.Proposed change: add
DOCKER_BUILDKIT=1to the build step'senvblock indeploy-dev.yml.2. Documentation update — IS mentioned in the issue
docs/contributing/reference/aws-resources.mdalready referencesDockerfile-awsandentrypoint-aws.shand is mostly current. Needs minor additions to mention gunicorn as the WSGI server, whitenoise for static files, andsettings_aws.pyas the production settings module.Files updated:
.github/workflows/deploy-dev.yml— addedDOCKER_BUILDKIT=1to build step env blockdocs/contributing/reference/aws-resources.md— step 5 updated to mention gunicorn and whitenoise;settings_aws.pyadded to Docker & App Startup section