Skip to content

Commit d919353

Browse files
authored
chore: install docker built extensions on AMI (#539)
* chore: build arm64 docker in gha * chore: setup docker extension task * chore: extract arm64 build config * fix: install extensions from shell command * fix: hold postgres version from apt upgrade * chore: build pg15 from source * chore: build pg15 with docker * chore: bump release version * chore: bump release version * chore: use explicit build args * chore: create contributing guide for adding new extensions
1 parent 0a1e88b commit d919353

11 files changed

+309
-175
lines changed

.github/workflows/ami-release.yml

+64-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,14 @@ on:
1111

1212
jobs:
1313
build:
14-
runs-on: [self-hosted, X64]
14+
strategy:
15+
matrix:
16+
include:
17+
- runner: arm-runner
18+
arch: arm64
19+
ubuntu: focal
20+
mcpu: neoverse-n1
21+
runs-on: ${{ matrix.runner }}
1522
timeout-minutes: 150
1623
permissions:
1724
contents: write
@@ -20,7 +27,60 @@ jobs:
2027

2128
steps:
2229
- name: Checkout Repo
23-
uses: actions/checkout@v2
30+
uses: actions/checkout@v3
31+
32+
- id: args
33+
uses: mikefarah/yq@master
34+
with:
35+
cmd: yq 'to_entries | map(select(.value|type == "!!str")) | map(.key + "=" + .value) | join("\n")' 'ansible/vars.yml'
36+
- run: docker context create builders
37+
- uses: docker/setup-buildx-action@v2
38+
with:
39+
endpoint: builders
40+
- uses: docker/build-push-action@v3
41+
with:
42+
push: false
43+
load: true
44+
build-args: |
45+
${{ steps.args.outputs.result }}
46+
target: extensions
47+
tags: supabase/postgres:extensions
48+
platforms: linux/${{ matrix.arch }}
49+
cache-from: type=gha
50+
cache-to: type=gha,mode=max
51+
- name: Extract built packages
52+
run: |
53+
mkdir -p /tmp/extensions ansible/files/extensions
54+
docker save supabase/postgres:extensions | tar xv -C /tmp/extensions
55+
for layer in /tmp/extensions/*/layer.tar; do
56+
tar xvf "$layer" -C ansible/files/extensions --strip-components 1
57+
done
58+
59+
- id: version
60+
run: echo "${{ steps.args.outputs.result }}" | grep "postgresql" >> "$GITHUB_OUTPUT"
61+
- name: Build Postgres deb
62+
uses: docker/build-push-action@v3
63+
with:
64+
push: false
65+
load: true
66+
file: docker/Dockerfile
67+
target: pg-deb
68+
build-args: |
69+
ubuntu_release="${{ matrix.ubuntu }}"
70+
postgresql_major="${{ steps.version.outputs.postgresql_major }}"
71+
postgresql_release="${{ steps.version.outputs.postgresql_release }}"
72+
CPPFLAGS="-mcpu=${{ matrix.mcpu }}"
73+
tags: supabase/postgres:deb
74+
platforms: linux/${{ matrix.arch }}
75+
cache-from: type=gha
76+
cache-to: type=gha,mode=max
77+
- name: Extract Postgres deb
78+
run: |
79+
mkdir -p /tmp/build ansible/files/postgres
80+
docker save supabase/postgres:deb | tar xv -C /tmp/build
81+
for layer in /tmp/build/*/layer.tar; do
82+
tar xvf "$layer" -C ansible/files/postgres --strip-components 1
83+
done
2484
2585
- name: Build AMI
2686
run: |
@@ -50,7 +110,7 @@ jobs:
50110
- name: Upload pg binaries to s3 staging
51111
run: |
52112
aws s3 cp /tmp/pg_binaries.tar.gz s3://${{ secrets.ARTIFACTS_BUCKET }}/upgrades/postgres/supabase-postgres-${{ steps.process_release_version.outputs.version }}/20.04.tar.gz
53-
113+
54114
- name: configure aws credentials - prod
55115
uses: aws-actions/configure-aws-credentials@v1
56116
with:
@@ -68,7 +128,7 @@ jobs:
68128
- name: Upload pg binaries to s3 prod
69129
run: |
70130
aws s3 cp /tmp/pg_binaries.tar.gz s3://${{ secrets.PROD_ARTIFACTS_BUCKET }}/upgrades/postgres/supabase-postgres-${{ steps.process_release_version.outputs.version }}/20.04.tar.gz
71-
131+
72132
- name: Create release
73133
uses: softprops/action-gh-release@v1
74134
with:

CONTRIBUTING.md

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Welcome to Supabase Postgres contributing guide
2+
3+
## Adding a new extension
4+
5+
Extensions can either be built from source or installed through a debian package. In general, you want to add the installation commands for your extension to the [Dockerfile](Dockerfile) following the steps below.
6+
7+
1. Create a [build stage](Dockerfile#L777) named after your extension.
8+
2. Add build args that specify the extension's [release version](Dockerfile#L37).
9+
3. If your extension is published as a package, download it to `/tmp/<name>.deb` using the [ADD command](Dockerfile#L705).
10+
4. If you need to build the extensions from source, use [checkinstall](Dockerfile#L791) to create a `/tmp/<name>.deb` package.
11+
5. Copy your extension's package from build stage to [extensions stage](Dockerfile#L851).
12+
13+
Here's a minimal example:
14+
15+
```dockerfile
16+
ARG pg_graphql_release=1.1.0
17+
18+
####################
19+
# 19-pg_graphql.yml
20+
####################
21+
FROM base as pg_graphql
22+
# Download package archive
23+
ARG pg_graphql_release
24+
ADD "https://github.com/supabase/pg_graphql/releases/download/v${pg_graphql_release}/pg_graphql-v${pg_graphql_release}-pg${postgresql_major}-${TARGETARCH}-linux-gnu.deb" \
25+
/tmp/pg_graphql.deb
26+
27+
####################
28+
# Collect extension packages
29+
####################
30+
FROM scratch as extensions
31+
COPY --from=pg_graphql /tmp/*.deb /tmp/
32+
```
33+
34+
Using this process maximises the effectiveness of Docker layer caching, which significantly speeds up our CI builds.
35+
36+
## Testing an extension
37+
38+
Extensions can be tested automatically using pgTAP. Start by creating a new file in [migrations/tests/extensions](migrations/tests/extensions). For example:
39+
40+
```sql
41+
BEGIN;
42+
create extension if not exists wrappers with schema "extensions";
43+
ROLLBACK;
44+
```
45+
46+
This test will be run as part of CI to check that your extension can be enabled successfully from the final Docker image.

ansible/playbook.yml

+3-17
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,6 @@
3030
- name: Install Postgres from source
3131
import_tasks: tasks/setup-postgres.yml
3232

33-
- name: Install Postgres extensions
34-
import_tasks: tasks/setup-extensions.yml
35-
3633
- name: Install PgBouncer
3734
import_tasks: tasks/setup-pgbouncer.yml
3835
tags:
@@ -79,7 +76,7 @@
7976
become: yes
8077
become_user: postgres
8178
shell:
82-
cmd: /usr/bin/pg_ctl -D /var/lib/postgresql/data start
79+
cmd: /usr/lib/postgresql/bin/pg_ctl -D /var/lib/postgresql/data start
8380
when: ebssurrogate_mode
8481

8582
- name: Adjust APT update intervals
@@ -138,25 +135,14 @@
138135
update_cache: yes
139136
cache_valid_time: 3600
140137

141-
# Put PG binaries in a directory under $PATH
142-
- name: Find all files in /usr/lib/postgresql/bin
143-
find:
144-
paths: /usr/lib/postgresql/bin
145-
register: postgresql_bin
146-
147138
- name: Clean out build dependencies
148139
import_tasks: tasks/clean-build-dependencies.yml
149140

150-
- name: Create symbolic links for Postgres binaries to /usr/bin/
151-
become: yes
152-
shell:
153-
cmd: "for fl in /usr/lib/postgresql/bin/* ; do ln -sf $fl /usr/bin/$(basename $fl) ; done"
154-
155141
- name: Restart Postgres Database without Systemd
156142
become: yes
157143
become_user: postgres
158144
shell:
159-
cmd: /usr/bin/pg_ctl -D /var/lib/postgresql/data restart "-o -c shared_preload_libraries='pg_tle'"
145+
cmd: /usr/lib/postgresql/bin/pg_ctl -D /var/lib/postgresql/data restart -o "-c shared_preload_libraries='pg_tle'"
160146
when: ebssurrogate_mode
161147

162148
- name: Run migrations
@@ -168,7 +154,7 @@
168154
become: yes
169155
become_user: postgres
170156
shell:
171-
cmd: /usr/bin/pg_ctl -D /var/lib/postgresql/data stop
157+
cmd: /usr/lib/postgresql/bin/pg_ctl -D /var/lib/postgresql/data stop
172158
when: ebssurrogate_mode
173159

174160
- name: Run unit tests

ansible/tasks/setup-docker.yml

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
- name: Copy extension packages
2+
copy:
3+
src: files/extensions/
4+
dest: /tmp/extensions/
5+
6+
# Builtin apt module does not support wildcard for deb paths
7+
- name: Install extensions
8+
shell: |
9+
set -e
10+
apt-get update
11+
apt-get install -y --no-install-recommends /tmp/extensions/*.deb
12+
13+
- name: pg_cron - set cron.database_name
14+
become: yes
15+
lineinfile:
16+
path: /etc/postgresql/postgresql.conf
17+
state: present
18+
line: cron.database_name = 'postgres'
19+
20+
- name: pgsodium - determine postgres bin directory
21+
shell: pg_config --bindir
22+
register: pg_bindir_output
23+
- set_fact:
24+
pg_bindir: "{{ pg_bindir_output.stdout }}"
25+
26+
- name: pgsodium - set pgsodium.getkey_script
27+
become: yes
28+
lineinfile:
29+
path: /etc/postgresql/postgresql.conf
30+
state: present
31+
# script is expected to be placed by finalization tasks for different target platforms
32+
line: pgsodium.getkey_script= '{{ pg_bindir }}/pgsodium_getkey.sh'
33+
34+
- name: auto_explain - set auto_explain.log_min_duration
35+
become: yes
36+
lineinfile:
37+
path: /etc/postgresql/postgresql.conf
38+
state: present
39+
line: auto_explain.log_min_duration = 10s
40+
41+
# supautils
42+
- name: supautils - add supautils to session_preload_libraries
43+
become: yes
44+
replace:
45+
path: /etc/postgresql/postgresql.conf
46+
regexp: "#session_preload_libraries = ''"
47+
replace: session_preload_libraries = 'supautils'
48+
49+
- name: supautils - write custom supautils.conf
50+
template:
51+
src: "files/postgresql_config/supautils.conf.j2"
52+
dest: /etc/postgresql-custom/supautils.conf
53+
mode: 0664
54+
owner: postgres
55+
group: postgres
56+
57+
- name: supautils - copy extension custom scripts
58+
copy:
59+
src: files/postgresql_extension_custom_scripts/
60+
dest: /etc/postgresql-custom/extension-custom-scripts
61+
become: yes
62+
63+
- name: supautils - chown extension custom scripts
64+
file:
65+
mode: 0775
66+
owner: postgres
67+
group: postgres
68+
path: /etc/postgresql-custom/extension-custom-scripts
69+
recurse: yes
70+
become: yes
71+
72+
- name: supautils - include /etc/postgresql-custom/supautils.conf in postgresql.conf
73+
become: yes
74+
replace:
75+
path: /etc/postgresql/postgresql.conf
76+
regexp: "#include = '/etc/postgresql-custom/supautils.conf'"
77+
replace: "include = '/etc/postgresql-custom/supautils.conf'"
78+
79+
- name: Cleanup - extension packages
80+
file:
81+
path: /tmp/extensions
82+
state: absent

0 commit comments

Comments
 (0)