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
27 changes: 27 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
version: 2

updates:
# Dependabot's docker file fetcher matches any filename containing "dockerfile" or
# "containerfile", case-insensitively (DOCKER_REGEXP in dependabot-core), so Dockerfile-17
# is picked up without renaming it.
#
# Each PR here is a PostgreSQL minor release. Read the Dockerfile header before merging:
# a bump below the minor version a live data directory runs is a downgrade PostgreSQL does
# not support, and merging publishes a new image rather than deploying it.
- package-ecosystem: docker
directory: /
schedule:
interval: weekly
commit-message:
prefix: docker
labels:
- dependencies

- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
commit-message:
prefix: ci
labels:
- dependencies
66 changes: 66 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: build

# Publishes ghcr.io/fountain-bio/postgres so Railway can consume it as a SOURCE IMAGE.
#
# The source type matters. A Railway service that builds from this repo loses its database
# recognition: no Data tab, and `railway connect` answers "No supported database found in
# service". A service pointed at a pre-built image keeps it. So this workflow publishes the
# image and each Railway service stays image-sourced, with Source Image set to
# ghcr.io/fountain-bio/postgres:17.
#
# The package has to be pullable by Railway. Make it public under the org's package settings,
# or add registry credentials on each service.

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

# A queued build for an older commit has nothing useful to publish once a newer one lands.
concurrency:
group: build-${{ github.ref }}
cancel-in-progress: true

jobs:
postgres-17:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v7.0.1

- uses: docker/setup-buildx-action@v4.2.0

# Pull requests build without publishing, so a broken Dockerfile fails review rather
# than overwriting the tag Railway pulls from.
- uses: docker/login-action@v4.6.0
if: github.event_name != 'pull_request'
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- id: meta
uses: docker/metadata-action@v6.2.0
with:
images: ghcr.io/fountain-bio/postgres
# `17` is the moving tag Railway points at. The sha tag gives every build a stable
# identity, so a bad rollout can be pinned back to a known-good digest.
tags: |
type=raw,value=17
type=raw,value=17-${{ github.sha }}

- uses: docker/build-push-action@v7.3.0
with:
context: .
file: ./Dockerfile-17
# Railway runs amd64. Building arm64 as well would double build time for an image
# nothing pulls on that architecture.
platforms: linux/amd64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
27 changes: 25 additions & 2 deletions Dockerfile-17
Original file line number Diff line number Diff line change
@@ -1,2 +1,25 @@
FROM ghcr.io/railwayapp-templates/postgres-ssl:17.6
RUN apt-get update && apt-get install -y --no-install-recommends postgresql-17-cron && rm -rf /var/lib/apt/lists/*
# Railway's Postgres image with pg_cron added.
#
# Railway's stock Postgres ships no extensions, so pg_cron used to be apt-installed by hand
# inside the running container. That splits the install across two lifetimes: the
# `shared_preload_libraries = pg_stat_statements,pg_cron` setting lives in postgresql.conf
# inside PGDATA, which is on the volume, while pg_cron.so lives only in the container
# filesystem. Replace the container and Postgres refuses to start with
# `FATAL: could not access file "pg_cron"`. Baking the extension into the image is what
# makes a redeploy, an image change, or a platform restart survivable.
#
# pg_cron drives the Inngest run/trace retention job (`ops/inngest-prune.sql` in the
# fountain-bio monorepo), which is the only thing keeping those trace stores bounded.
#
# The base tag is PINNED rather than floating on `:17` so Dependabot raises a visible PR for
# each Postgres minor release. Two rules when that PR arrives:
# 1. Never merge a bump that moves BELOW the minor version a live data directory runs.
# PostgreSQL guarantees minor upgrades, not minor downgrades.
# 2. Merging does not deploy. Railway pulls the new image on the next redeploy of each
# service, so prod moves when you move it.
FROM ghcr.io/railwayapp-templates/postgres-ssl:17.10

# The package major version has to track the base image's major version.
RUN apt-get update \
&& apt-get install -y --no-install-recommends postgresql-17-cron \
&& rm -rf /var/lib/apt/lists/*
Loading