Build phpPgAdmin on unified PHP base
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
.git
|
||||
.gitea
|
||||
*.md
|
||||
*.sh
|
||||
*.yaml
|
||||
@@ -5,6 +5,7 @@ on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
IMAGE: registry.brunner.ninja/feedc0de/phppgadmin
|
||||
KUBECONFORM_VERSION: v0.7.0
|
||||
KUBECTL_VERSION: v1.36.3
|
||||
KUBERNETES_API: https://host.containers.internal:6443
|
||||
@@ -12,6 +13,74 @@ env:
|
||||
NAMESPACE: default
|
||||
|
||||
jobs:
|
||||
image:
|
||||
name: Build, test and publish image
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Check out source
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Log in to Quay
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: registry.brunner.ninja
|
||||
username: ${{ secrets.QUAY_USERNAME }}
|
||||
password: ${{ secrets.QUAY_TOKEN }}
|
||||
|
||||
- name: Build image
|
||||
env:
|
||||
COMMIT_SHA: ${{ gitea.sha }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
docker build \
|
||||
--pull \
|
||||
--load \
|
||||
--label "org.opencontainers.image.base.name=registry.brunner.ninja/feedc0de/php-apache:f76304f1014f15354ec05bba7eaca376993afe72" \
|
||||
--label "org.opencontainers.image.revision=${COMMIT_SHA}" \
|
||||
--label "org.opencontainers.image.source=https://code.brunner.ninja/feedc0de/phppgadmin-docker" \
|
||||
--tag "${IMAGE}:${COMMIT_SHA}" \
|
||||
.
|
||||
|
||||
- name: Smoke-test image
|
||||
env:
|
||||
COMMIT_SHA: ${{ gitea.sha }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
docker run --rm --entrypoint httpd "${IMAGE}:${COMMIT_SHA}" -t
|
||||
docker run --rm --entrypoint php "${IMAGE}:${COMMIT_SHA}" -r '
|
||||
foreach (["pgsql", "pdo_pgsql", "mbstring", "Zend OPcache"] as $extension) {
|
||||
if (!extension_loaded($extension)) {
|
||||
fwrite(STDERR, "Missing PHP extension: {$extension}\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
'
|
||||
container_id="$(docker run --detach --publish 127.0.0.1::80 "${IMAGE}:${COMMIT_SHA}")"
|
||||
trap 'docker rm --force "${container_id}" >/dev/null 2>&1 || true' EXIT
|
||||
port="$(docker inspect --format '{{ (index (index .NetworkSettings.Ports "80/tcp") 0).HostPort }}' "${container_id}")"
|
||||
for attempt in {1..30}; do
|
||||
if curl --fail --silent --show-error \
|
||||
--output "${RUNNER_TEMP}/phppgadmin.html" \
|
||||
"http://127.0.0.1:${port}/phppgadmin/" \
|
||||
&& grep -Fq 'phpPgAdmin' "${RUNNER_TEMP}/phppgadmin.html"; then
|
||||
exit 0
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
docker logs "${container_id}"
|
||||
exit 1
|
||||
|
||||
- name: Push image
|
||||
if: gitea.ref == 'refs/heads/main'
|
||||
env:
|
||||
COMMIT_SHA: ${{ gitea.sha }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
docker push "${IMAGE}:${COMMIT_SHA}"
|
||||
docker tag "${IMAGE}:${COMMIT_SHA}" "${IMAGE}:latest"
|
||||
docker push "${IMAGE}:latest"
|
||||
|
||||
validate:
|
||||
name: Validate manifests
|
||||
runs-on: ubuntu-latest
|
||||
@@ -34,7 +103,9 @@ jobs:
|
||||
deploy:
|
||||
name: Deploy to Kubernetes
|
||||
if: gitea.ref == 'refs/heads/main'
|
||||
needs: validate
|
||||
needs:
|
||||
- image
|
||||
- validate
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out source
|
||||
@@ -70,9 +141,14 @@ jobs:
|
||||
export KUBECONFIG="${RUNNER_TEMP}/kubeconfig"
|
||||
sed \
|
||||
"s|deployment.brunner.ninja/revision: manual|deployment.brunner.ninja/revision: ${COMMIT_SHA}|" \
|
||||
phppgadmin.yaml > "${RUNNER_TEMP}/phppgadmin.yaml"
|
||||
phppgadmin.yaml \
|
||||
| sed \
|
||||
"s|registry.brunner.ninja/feedc0de/phppgadmin:latest|${IMAGE}:${COMMIT_SHA}|" \
|
||||
> "${RUNNER_TEMP}/phppgadmin.yaml"
|
||||
grep -Fq "deployment.brunner.ninja/revision: ${COMMIT_SHA}" \
|
||||
"${RUNNER_TEMP}/phppgadmin.yaml"
|
||||
grep -Fq "image: ${IMAGE}:${COMMIT_SHA}" \
|
||||
"${RUNNER_TEMP}/phppgadmin.yaml"
|
||||
"${RUNNER_TEMP}/kubectl" apply \
|
||||
--dry-run=server \
|
||||
--validate=false \
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
ARG PHP_APACHE_TAG=f76304f1014f15354ec05bba7eaca376993afe72
|
||||
FROM registry.brunner.ninja/feedc0de/php-apache:${PHP_APACHE_TAG}
|
||||
|
||||
ARG PHPPGADMIN_VERSION=7.14.7
|
||||
ARG PHPPGADMIN_SHA256=7c0e89922abcf88fd81a52590930f3b5121032d1d37234a54a8f6415152dc292
|
||||
|
||||
RUN curl --fail --show-error --location \
|
||||
--output /tmp/phppgadmin.tar.gz \
|
||||
"https://github.com/ReimuHakurei/phpPgAdmin/archive/refs/tags/v${PHPPGADMIN_VERSION}-mod.tar.gz" \
|
||||
&& printf '%s %s\n' "${PHPPGADMIN_SHA256}" /tmp/phppgadmin.tar.gz | sha256sum --check \
|
||||
&& install -d /usr/share/webapps/phppgadmin /etc/phppgadmin \
|
||||
&& tar --extract --gzip --file /tmp/phppgadmin.tar.gz \
|
||||
--strip-components=1 --directory /usr/share/webapps/phppgadmin \
|
||||
&& cp /usr/share/webapps/phppgadmin/conf/config.inc.php-dist \
|
||||
/etc/phppgadmin/config.inc.php \
|
||||
&& rm -f /usr/share/webapps/phppgadmin/conf/config.inc.php \
|
||||
&& ln -s /etc/phppgadmin/config.inc.php \
|
||||
/usr/share/webapps/phppgadmin/conf/config.inc.php \
|
||||
&& rm /tmp/phppgadmin.tar.gz
|
||||
|
||||
COPY phppgadmin.conf /etc/httpd/conf/extra/phppgadmin.conf
|
||||
|
||||
RUN printf '%s\n' 'Include conf/extra/phppgadmin.conf' >> /etc/httpd/conf/httpd.conf
|
||||
@@ -1,15 +1,15 @@
|
||||
# phpPgAdmin on Kubernetes
|
||||
|
||||
Production deployment for the brunner.ninja phpPgAdmin service. The repository
|
||||
uses a maintained public container image, a single plain Kubernetes manifest,
|
||||
Traefik ingress, health probes, zero-unavailable rolling updates, and restricted
|
||||
Gitea Actions deployment credentials.
|
||||
uses a small private image derived from the shared PHP/Apache base, a single
|
||||
plain Kubernetes manifest, Traefik ingress, health probes, zero-unavailable
|
||||
rolling updates, and restricted Gitea Actions deployment credentials.
|
||||
|
||||
## Architecture
|
||||
|
||||
- `tozd/phppgadmin` supplies phpPgAdmin, Nginx, PHP, and PostgreSQL client tools.
|
||||
- The image is pinned to an immutable multi-platform manifest digest rather
|
||||
than a mutable tag.
|
||||
- The repository image adds phpPgAdmin to the same Apache/PHP layer used by the
|
||||
homepage deployments.
|
||||
- CI deploys the image by its immutable Git commit tag rather than `latest`.
|
||||
- `default/phppgadmin-config` mounts the complete multi-server configuration at
|
||||
`/etc/phppgadmin/config.inc.php`.
|
||||
- A ClusterIP Service exposes TCP port 80 to Traefik.
|
||||
@@ -27,29 +27,19 @@ The deployment is stateless. phpPgAdmin does not store database passwords or
|
||||
sessions on a PVC; users authenticate directly to the selected PostgreSQL
|
||||
server. The ConfigMap lists server addresses but contains no credentials.
|
||||
|
||||
## Why there is no Dockerfile
|
||||
## Container image
|
||||
|
||||
This repository previously built phpPgAdmin from the Arch User Repository on
|
||||
top of a private base image and pushed the result to the private Quay registry.
|
||||
That duplicated public image storage and made every repository commit rebuild
|
||||
an otherwise unchanged application.
|
||||
The Dockerfile installs the verified phpPgAdmin 7.14.7 release directly on
|
||||
`registry.brunner.ninja/feedc0de/php-apache`. The common image already provides
|
||||
Apache, PHP, PostgreSQL/PDO PostgreSQL, and OPcache, so Kubernetes nodes share
|
||||
those layers with the PHP homepage deployments. The phpPgAdmin layer contains
|
||||
only the application and its Apache alias configuration. Its base tag is the
|
||||
same immutable php-apache Git commit used by the homepage values files.
|
||||
|
||||
The current deployment instead uses the actively maintained public
|
||||
[`tozd/phppgadmin`](https://gitlab.com/tozd/docker/phppgadmin) image. It supports
|
||||
the same configuration-file mount used here. The pinned image contains
|
||||
phpPgAdmin 7.14.7, which is also the current AUR package version at the time of
|
||||
this repository conversion.
|
||||
|
||||
The committed image is:
|
||||
|
||||
```text
|
||||
tozd/phppgadmin@sha256:4ee690768d54b0c057dbc4ed5c1baa152c1a5ef0ebd6eb12f1e310e545eb4489
|
||||
```
|
||||
|
||||
It was inspected and smoke-tested before deployment. Pinning prevents an
|
||||
upstream rebuild from silently changing the running software. To upgrade,
|
||||
inspect and test the new upstream digest, replace the image line in
|
||||
`phppgadmin.yaml`, and merge the change through the normal deployment workflow.
|
||||
The release archive is checked against the SHA-256 published by the Arch User
|
||||
Repository package before extraction. phpPgAdmin is exposed at
|
||||
`/phppgadmin/`, and the existing ConfigMap is mounted at
|
||||
`/etc/phppgadmin/config.inc.php`.
|
||||
|
||||
## Repository contents
|
||||
|
||||
@@ -60,16 +50,20 @@ inspect and test the new upstream digest, replace the image line in
|
||||
- `ci-deployer.yaml`: restricted Gitea Actions ServiceAccount, Role, binding,
|
||||
and revocable token.
|
||||
- `create-ci-kubeconfig.sh`: one-time CI identity bootstrap.
|
||||
- `.gitea/workflows/deploy.yml`: validation on every push and pull request;
|
||||
deployment after successful validation of `main`.
|
||||
- `Dockerfile` and `phppgadmin.conf`: small phpPgAdmin layer and Apache alias
|
||||
on the shared php-apache image.
|
||||
- `.gitea/workflows/deploy.yml`: image build and validation on every push and
|
||||
pull request; image publishing and deployment after a successful `main` run.
|
||||
|
||||
There is no Helm chart, Kustomize overlay, Argo CD application, private image,
|
||||
or container build pipeline.
|
||||
phpPgAdmin is intentionally not deployed through the generic PHP homepage Helm
|
||||
chart. It is stateless, has no CephFS web root, and needs its own ConfigMap and
|
||||
Traefik redirect Middleware.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Kubernetes and kubectl.
|
||||
- An amd64 worker node. The pinned upstream image currently publishes amd64.
|
||||
- The unified `registry.brunner.ninja/feedc0de/php-apache` image in Quay.
|
||||
- The `quay-pull-secret` image pull secret in the `default` namespace.
|
||||
- Traefik with the `traefik.io/v1alpha1` Middleware CRD and ingress class
|
||||
`traefik`.
|
||||
- The existing Traefik `websecure` entrypoint and default
|
||||
@@ -133,9 +127,13 @@ The workflow validates every push and pull request. A successful push to
|
||||
Service, Ingress, and Middleware, then polls the Deployment for up to ten
|
||||
minutes.
|
||||
|
||||
No image is built or pushed. The workflow requires only one Gitea Actions
|
||||
secret:
|
||||
The workflow builds and smoke-tests the image for every push and pull request.
|
||||
On `main` it pushes the immutable Git commit tag plus `latest`, substitutes the
|
||||
immutable tag in the deployment manifest, and deploys it. It requires these
|
||||
Gitea Actions secrets:
|
||||
|
||||
- `QUAY_USERNAME`: Quay robot-account username with read/write access.
|
||||
- `QUAY_TOKEN`: token for that robot account.
|
||||
- `KUBE_CONFIG_BASE64`: the restricted phpPgAdmin deployment kubeconfig,
|
||||
base64-encoded on one line.
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
Alias /phppgadmin "/usr/share/webapps/phppgadmin"
|
||||
|
||||
<Directory "/usr/share/webapps/phppgadmin">
|
||||
DirectoryIndex index.php
|
||||
AllowOverride All
|
||||
Options FollowSymLinks
|
||||
Require all granted
|
||||
</Directory>
|
||||
+5
-4
@@ -241,10 +241,9 @@ spec:
|
||||
terminationGracePeriodSeconds: 30
|
||||
containers:
|
||||
- name: phppgadmin
|
||||
# Public, maintained image pinned to the verified multi-platform
|
||||
# manifest digest published on 2026-08-08.
|
||||
image: tozd/phppgadmin@sha256:4ee690768d54b0c057dbc4ed5c1baa152c1a5ef0ebd6eb12f1e310e545eb4489
|
||||
imagePullPolicy: IfNotPresent
|
||||
# CI replaces latest with the immutable source commit tag on main.
|
||||
image: registry.brunner.ninja/feedc0de/phppgadmin:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 80
|
||||
@@ -278,6 +277,8 @@ spec:
|
||||
- name: phppgadmin-config
|
||||
configMap:
|
||||
name: phppgadmin-config
|
||||
imagePullSecrets:
|
||||
- name: quay-pull-secret
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
|
||||
Reference in New Issue
Block a user