Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
62 changes: 44 additions & 18 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,11 @@ on:
required: true

env:
IMAGE_REF: us-west1-docker.pkg.dev/${{ secrets.GCP_PROJECT_SLUG }}/firetower-docker/firetower:${{ github.sha }}
BACKEND_IMAGE_REF: us-west1-docker.pkg.dev/${{ secrets.GCP_PROJECT_SLUG }}/firetower-docker/firetower:${{ github.sha }}
STATIC_IMAGE_REF: us-west1-docker.pkg.dev/${{ secrets.GCP_PROJECT_SLUG }}/firetower-docker/nginx:${{ github.sha }}

jobs:
ci:
uses: ./.github/workflows/ci.yml
deploy:
needs: [ci]
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
Expand All @@ -35,44 +33,72 @@ jobs:
run: gcloud auth configure-docker us-west1-docker.pkg.dev
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
- name: Build and push (backend)
uses: docker/build-push-action@v6
with:
push: true
tags: ${{ env.BACKEND_IMAGE_REF }}
file: docker/backend.Dockerfile
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build and push (static assets)
uses: docker/build-push-action@v6
with:
push: true
tags: ${{ env.IMAGE_REF }}
tags: ${{ env.STATIC_IMAGE_REF }}
file: docker/static.Dockerfile
cache-from: type=gha
cache-to: type=gha,mode=max

deploy:
needs: [build]
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Authenticate with GCP
uses: 'google-github-actions/auth@v3'
with:
project_id: ${{ secrets.GCP_PROJECT_SLUG }}
workload_identity_provider: projects/${{ secrets.GCP_PROJECT_NUM }}/locations/global/workloadIdentityPools/github/providers/github-prvdr
- name: deploy-test-db-migration
if: ${{ inputs.environment == 'test' }}
uses: "google-github-actions/deploy-cloudrun@v3"
with:
job: firetower-test-db-migration
project_id: ${{ secrets.GCP_PROJECT_SLUG }}
region: us-west1
image: ${{ env.IMAGE_REF }}
image: ${{ env.BACKEND_IMAGE_REF }}
wait: true
- name: deploy-prod-db-migration
if: ${{ (github.ref == 'refs/heads/main' && !inputs.environment ) || inputs.environment == 'prod' }}
- name: deploy-test
if: ${{ inputs.environment == 'test' }}
uses: "google-github-actions/deploy-cloudrun@v3"
with:
job: firetower-prod-db-migration
service: firetower-test
project_id: ${{ secrets.GCP_PROJECT_SLUG }}
region: us-west1
image: ${{ env.IMAGE_REF }}
wait: true
- name: deploy-test
if: ${{ inputs.environment == 'test' }}
# NOTE: we use flags here because the action does not natively support updating multiple containers.
flags: >
--container nginx --image "${{ env.STATIC_IMAGE_REF }}" --port 80
Comment thread
keeakita marked this conversation as resolved.
Resolved
--container firetower-backend --image "${{ env.BACKEND_IMAGE_REF }}"

- name: deploy-prod-db-migration
if: ${{ (github.ref == 'refs/heads/main' && !inputs.environment ) || inputs.environment == 'prod' }}
uses: "google-github-actions/deploy-cloudrun@v3"
with:
service: firetower-test
job: firetower-prod-db-migration
project_id: ${{ secrets.GCP_PROJECT_SLUG }}
region: us-west1
image: ${{ env.IMAGE_REF }}
image: ${{ env.BACKEND_IMAGE_REF }}
wait: true
- name: deploy-prod
if: ${{ (github.ref == 'refs/heads/main' && !inputs.environment ) || inputs.environment == 'prod' }}
uses: "google-github-actions/deploy-cloudrun@v3"
with:
service: firetower
project_id: ${{ secrets.GCP_PROJECT_SLUG }}
region: us-west1
image: ${{ env.IMAGE_REF }}
# NOTE: we use flags here because the action does not natively support updating multiple containers.
flags: >
--container nginx --image "${{ env.STATIC_IMAGE_REF }}" --port 80
--container firetower-backend --image "${{ env.BACKEND_IMAGE_REF }}"
34 changes: 34 additions & 0 deletions docker/backend.Dockerfile
Comment thread
keeakita marked this conversation as resolved.
Resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
FROM python:3.12.11-alpine3.22 AS build_backend
COPY --from=ghcr.io/astral-sh/uv:0.8.18 /uv /uvx /bin/

WORKDIR /app

# Install dependencies
COPY uv.lock .
COPY pyproject.toml .
RUN uv sync --no-dev --frozen --compile-bytecode --no-install-project

COPY src/firetower .

# Install the backend itself
COPY pyproject.toml .
COPY manage.py .
COPY README.md .
COPY src/ src/
RUN uv sync --group prod --no-dev --frozen --compile-bytecode --no-editable

FROM python:3.12.11-alpine3.22

RUN adduser app -h /app -u 1100 -D && chown -R 1100 /app

# Copy the environment, but not the source code
COPY --from=build_backend --chown=1100 /app/.venv /app/.venv

WORKDIR /app
USER 1100

ENV PORT=8080
EXPOSE $PORT

ENV DJANGO_ENV="prod"
ENTRYPOINT [ "sh", "-c", "/app/.venv/bin/granian --interface wsgi --host 0.0.0.0 --port $PORT firetower.wsgi:application"]
22 changes: 7 additions & 15 deletions Dockerfile → docker/static.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,13 @@ ENV VITE_API_URL="/api"

RUN bun run build

FROM python:3.12.11-alpine3.22
FROM nginx:1.29.3-alpine3.22

RUN adduser app -h /app -u 1100 -D && chown -R 1100 /app
RUN chown 101:101 -R /var/cache/nginx/ /var/log/nginx/
RUN touch /run/nginx.pid && chown 101:101 /run/nginx.pid
USER 101

# Copy the environment, but not the source code
COPY --from=build_backend --chown=1100 /app/.venv /app/.venv
COPY --from=build_frontend --chown=1100 /app/dist /app/static
COPY --from=build_backend --chown=1100 /app/static/backend /app/static/backend
COPY --from=build_frontend --chown=101 /app/dist /app/static
COPY --from=build_backend --chown=101 /app/static/backend /app/static/backend

WORKDIR /app
USER 1100

ENV PORT=8080
EXPOSE $PORT

ENV GRANIAN_STATIC_PATH_MOUNT="static/"
ENV DJANGO_ENV="prod"
ENTRYPOINT [ "sh", "-c", "/app/.venv/bin/granian --interface wsgi --host 0.0.0.0 --port $PORT firetower.wsgi:application"]
COPY ./nginx.conf /etc/nginx/nginx.conf
60 changes: 60 additions & 0 deletions nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# user nginx;
worker_processes auto;

error_log /var/log/nginx/error.log notice;
pid /run/nginx.pid;


events {
worker_connections 1024;
}


http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

sendfile on;
tcp_nopush on;
tcp_nodelay on;

keepalive_timeout 65;

#gzip on;

#include /etc/nginx/conf.d/*.conf;

server {
listen 80;
server_name localhost .firetower.getsentry.net;

access_log /var/log/nginx/host.access.log main;

location / {
root /app/static/;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}

location /api {
proxy_pass http://127.0.0.1:8080;
}
location /admin {
proxy_pass http://127.0.0.1:8080;
}
Comment thread
keeakita marked this conversation as resolved.
Resolved

#error_page 404 /404.html;

# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ dependencies = [
"cryptography>=46.0.3",
"django>=5.2.5",
"django-cors-headers>=4.9.0",
"django-kubernetes>=1.1.0",
"djangorestframework>=3.15.2",
"google-auth>=2.37.0",
"google-cloud-logging>=3.11.4",
Expand Down
9 changes: 8 additions & 1 deletion src/firetower/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,14 @@ def dev_default(key: str, default: str = "") -> str:
"django.contrib.staticfiles",
"rest_framework",
"corsheaders",
"djk8s",
"firetower.auth",
"firetower.incidents",
"firetower.integrations",
]

MIDDLEWARE = [
"djk8s.middleware.ProbeMiddleware",
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"corsheaders.middleware.CorsMiddleware",
Expand Down Expand Up @@ -172,7 +174,7 @@ def dev_default(key: str, default: str = "") -> str:
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.2/howto/static-files/

STATIC_URL = "static/backend/"
STATIC_URL = "backend/"
STATIC_ROOT = "static/backend/"

# Default primary key field type
Expand Down Expand Up @@ -223,3 +225,8 @@ def dev_default(key: str, default: str = "") -> str:

client = google.cloud.logging.Client()
client.setup_logging()

# django-k8s proreadiness probes
DJK8S_READINESS_PROBES = [
"djk8s.probes.DatabaseProbe",
]
16 changes: 15 additions & 1 deletion uv.lock

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