diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..defce791 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,42 @@ +name: Build Metro2 Docker images + +on: + pull_request: + push: + branches: + - update/dockerfiles + # - main + merge_group: + +jobs: + build-front-end-image: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: cfpb/actions/docker-build-push@5cff5ed85fa5dacdbcdc7512421d835f74fdc252 + with: + image-name: metro2-frontend-builder + context: ./front-end + target: builder + token: ${{ secrets.GITHUB_TOKEN }} + + build-back-end-image: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: cfpb/actions/docker-build-push@5cff5ed85fa5dacdbcdc7512421d835f74fdc252 + with: + image-name: metro2-backend-base + context: ./django + target: base + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/django/Dockerfile b/django/Dockerfile index 965223ff..019d6214 100644 --- a/django/Dockerfile +++ b/django/Dockerfile @@ -1,22 +1,20 @@ +############################################################################# +## Stage: base python/django image FROM python:3.13-alpine AS base # Ensure that the environment uses UTF-8 encoding by default ENV LANG=en_US.UTF-8 ENV ENV=/etc/profile -ENV PIP_NO_CACHE_DIR=true ENV PYTHONUNBUFFERED=1 +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PIP_NO_CACHE_DIR=true +ENV PIP_ROOT_USER_ACTION=ignore -ENV APP_HOME=/src/metro2/django -WORKDIR ${APP_HOME} - -ARG USERNAME=default-user -ARG USER_UID=1002 - -RUN adduser -u $USER_UID -D $USERNAME +ENV APP_HOME=/src/metro2 +WORKDIR ${APP_HOME}/django -# Add Zscaler Root CA certificate, rebuild CA certificates, and both the root -# cert and the rebuilt ca-certificates cert to APP_HOME for reuse. -ADD https://raw.githubusercontent.com/cfpb/zscaler-cert/refs/heads/main/zscaler_root_ca.pem /usr/local/share/ca-certificates/zscaler_root_ca.crt +# Add Zscaler Root CA certificate and rebuild CA certificates +ADD https://raw.githubusercontent.com/cfpb/zscaler-cert/3982ebd9edf9de9267df8d1732ff5a6f88e38375/zscaler_root_ca.pem /usr/local/share/ca-certificates/zscaler_root_ca.crt RUN apk add --no-cache --no-check-certificate ca-certificates && update-ca-certificates # upgrade apk and pip, add build dependencies to .build-deps virtual to be @@ -25,13 +23,11 @@ RUN apk update --no-cache && \ apk upgrade --no-cache && \ apk add libpq && \ apk add --virtual .build-deps gcc python3-dev musl-dev && \ - apk add --no-cache bash && \ + apk add --no-cache aws-cli bash && \ apk add libffi-dev && \ pip install --upgrade pip -# Add `$HOME/.local/bin` to PATH -RUN echo 'export PATH=$HOME/.local/bin:$PATH' >> /etc/profile - +# Copy the django application into the WORKDIR COPY . . RUN pip install -r ./requirements.txt @@ -39,15 +35,19 @@ RUN pip install -r ./requirements.txt # Delete build dependencies RUN apk del .build-deps -# Write the VERSION arg to a file in the parent of APP_HOME +############################################################################# +### Stage: development application +FROM base AS dev + +# Write the VERSION arg to a file in APP_HOME ARG VERSION=unknown -RUN echo "$VERSION" > $APP_HOME/../version.txt +RUN echo "$VERSION" > $APP_HOME/version.txt +# Run as a non-root user +ARG USERNAME=default +ARG USER_UID=1000 +RUN adduser -u $USER_UID -D $USERNAME RUN chown -R $USERNAME:$USERNAME $APP_HOME - -# Create the user USER $USERNAME -EXPOSE 8000 - CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"] diff --git a/docker-compose.yml b/docker-compose.yml index 3b23ae1c..e634128f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,23 +15,25 @@ services: ports: - 127.0.0.1:5432:5432 healthcheck: - test: [ "CMD-SHELL", "pg_isready" ] + test: ["CMD-SHELL", "pg_isready"] interval: 3s timeout: 3s retries: 10 - shm_size: '256mb' + shm_size: "256mb" + frontend: container_name: frontend build: context: ./front-end + target: dev ports: - 127.0.0.1:3000:3000 depends_on: postgres: condition: service_healthy - command: yarn dev volumes: - ./front-end/src:/src/frontend/src + django: image: django-m2:local build: @@ -39,6 +41,7 @@ services: args: # Set the VERSION env var and run compose build to set this VERSION: ${VERSION:-unknown} + target: dev depends_on: postgres: condition: service_healthy diff --git a/front-end/Dockerfile b/front-end/Dockerfile index ebcc2fd3..fc04eaeb 100644 --- a/front-end/Dockerfile +++ b/front-end/Dockerfile @@ -1,3 +1,5 @@ +############################################################################# +## Stage: base front-end image image FROM node:24-alpine AS base # Ensure that the environment uses UTF-8 encoding by default @@ -6,32 +8,38 @@ ENV ENV=/etc/profile ENV PIP_NO_CACHE_DIR=true ENV APP_HOME=/src/frontend - -ARG USERNAME=default-user -ARG USER_UID=1001 -RUN adduser -u $USER_UID -D $USERNAME - WORKDIR ${APP_HOME} -# Add `$HOME/.local/bin` to PATH -RUN echo 'export PATH=$HOME/.local/bin:$PATH' >> /etc/profile - -COPY . . - # Add Zscaler Root CA certificate, rebuild CA certificates, and both the root # cert and the rebuilt ca-certificates cert to APP_HOME for reuse. ADD https://raw.githubusercontent.com/cfpb/zscaler-cert/refs/heads/main/zscaler_root_ca.pem /usr/local/share/ca-certificates/zscaler_root_ca.crt RUN apk add --no-cache --no-check-certificate ca-certificates && update-ca-certificates ENV NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt -# Enabled Corepack -RUN corepack enable +# Make sure everything is up to date +RUN apk update --no-cache && apk upgrade --no-cache -# Fetch the Yarn version specified in package.json -RUN corepack prepare --activate +COPY . ${APP_HOME} -RUN yarn && \ - chown -R $USERNAME:$USERNAME $APP_HOME +# Prepare yarn +RUN corepack enable && \ + corepack prepare --activate && \ + yarn -# Create the user +############################################################################# +### Stage: dev to run `yarn dev` as a non-root user +FROM base AS dev + +# Run as a non-root user +ARG USERNAME=default +ARG USER_UID=1001 +RUN adduser -u $USER_UID -D $USERNAME +RUN chown -R $USERNAME:$USERNAME $APP_HOME USER $USERNAME + +CMD ["yarn", "dev"] + +############################################################################# +### Stage: builder to run `yarn build` and build the frontend +FROM base AS builder +RUN yarn build