Skip to main content

Install Pagifier

This is the platform-engineer side: cluster, persistence, registry, identity, and the public API. Developers can stay over in the developer guide unless they are running a laptop sandbox.

Two ways inβ€”pick your adventure:

  • On your laptop πŸ§ͺ β€” the whole platform on a kind cluster, images built from source, ~15 minutes, nothing needed but Docker. The best way to kick the tires.
  • For real ☁️ β€” a proper cluster, proper storage, proper registry. EKS, GKE, AKS, or anything that runs Kubernetes.

Local quickstart (laptop)​

Prerequisites: Docker, kind, kubectl, Helm, and the AWS CLI (only used to talk to local MinIO). Clone the repo first:

git clone https://github.com/kcloudev/pagifier-dev.git && cd pagifier-dev

1. Cluster + local registry​

./hack/quickstart/kind-with-registry.sh

This creates a kind cluster named pagifier and a local Docker registry at localhost:5001 that's reachable from inside the cluster too β€” that's where your built platform images and the app images built by Pagifier will live.

Install an ingress controller:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
kubectl -n ingress-nginx wait --for=condition=Ready pod -l app.kubernetes.io/component=controller --timeout=180s

2. Dependencies: MinIO + PostgreSQL​

kubectl apply -f hack/quickstart/minio.yaml -f hack/quickstart/postgres.yaml
kubectl -n pagifier-deps wait --for=condition=Available deploy --all --timeout=180s

MinIO gives you both S3 buckets (pagifier-artifacts, pagifier-platform β€” a Job creates them); Postgres holds deploy history. Both are throwaway dev instances.

Seed the platform configuration (templates, profiles, runtime images) and the database schema:

# platform config β†’ MinIO
kubectl -n pagifier-deps port-forward svc/minio 9000:9000 >/dev/null 2>&1 &
AWS_ACCESS_KEY_ID=pagifier AWS_SECRET_ACCESS_KEY=pagifier-dev-secret \
aws --endpoint-url http://localhost:9000 s3 sync examples/platform-config/ s3://pagifier-platform/

# schema β†’ Postgres
kubectl -n pagifier-deps exec deploy/postgres -- psql -U pagifier -d pagifier \
< docs/db/schema.sql

3. Build your own images​

make images REGISTRY=localhost:5001/pagifier VERSION=dev
docker push localhost:5001/pagifier/api:dev
docker push localhost:5001/pagifier/operator:dev
docker push localhost:5001/pagifier/builder:dev

Three images from source: the API server, the operator, and the builder (which carries buildctl and cosign into build pods).

4. Install Pagifier​

kubectl create namespace pagifier-system
kubectl -n pagifier-system create secret generic pagifier-api-tokens \
--from-literal=tokens='dev-token:acme'

helm install pagifier charts/pagifier -n pagifier-system \
--set image.api=localhost:5001/pagifier/api:dev \
--set image.operator=localhost:5001/pagifier/operator:dev \
--set image.builder=localhost:5001/pagifier/builder:dev \
--set registry.url=pagifier-registry:5000/apps \
--set registry.insecure=true \
--set storage.endpoint=http://minio.pagifier-deps.svc:9000 \
--set storage.artifactBucket=pagifier-artifacts \
--set storage.configBucket=pagifier-platform \
--set api.databaseURL=postgres://pagifier:pagifier-dev-secret@postgres.pagifier-deps.svc:5432/pagifier

kubectl -n pagifier-system set env deploy/pagifier-api deploy/pagifier-operator \
AWS_ACCESS_KEY_ID=pagifier AWS_SECRET_ACCESS_KEY=pagifier-dev-secret
kubectl -n pagifier-system wait --for=condition=Available deploy --all --timeout=180s

Two values matter for local: registry.url points app-image pushes at the in-cluster name of your local registry, and registry.insecure=true lets BuildKit push over plain HTTP (never use it beyond a laptop).

5. Deploy something​

kubectl -n pagifier-system port-forward svc/pagifier-api 8443:80 >/dev/null 2>&1 &

cd examples/minimal
sed -i '' 's/environment = "prod"/environment = "dev"/; s/my-app.company.com/my-app.localtest.me:8080/' pagifier.toml
zip -q app.zip pagifier.toml # any static content works; the template builds real apps

curl -H "Authorization: Bearer dev-token" \
-F config=@pagifier.toml -F archive=@app.zip \
"http://localhost:8443/v1/applications/my-app/environments/dev/deployments?wait=true"

Watch the build stream, then open http://my-app.localtest.me:8080 (localtest.me resolves to 127.0.0.1; port 8080 is the kind ingress mapping). The console is at http://localhost:8443/console β€” paste dev-token.

Tear it all down with kind delete cluster --name pagifier.

Production install​

You provide: Kubernetes β‰₯ 1.29 with an nginx ingress controller, object storage, PostgreSQL, and an OCI registry. Optional integrations β€” External Secrets Operator, KEDA, Prometheus, external-dns, a Gateway β€” each enables the matching feature.

Cloud user? Pick yours πŸ‘‡β€‹

Ready-made values presets live in examples/values/ β€” each one has the exact IAM incantations written down so you don't have to spelunk cloud docs:

ClusterStorageRegistryIdentityPreset
EKSS3 (storage.provider: s3)ECRIRSA role annotationvalues-eks.yaml
GKEGCS (storage.provider: gcs)Artifact RegistryWorkload Identity annotationvalues-gke.yaml
AKSAzure Blob (storage.provider: azure + azureAccountURL)ACRAzure Workload Identity annotationvalues-aks.yaml
Anywhere elseMinIO / any S3-compatible (storage.endpoint)Harbor/GHCR + registry.pushSecretmounted credentialsthe quickstart flow above

Credentials are always ambient β€” Pagifier never stores cloud keys. The per-component access matrix (API reads config + writes artifacts; build jobs read artifacts only; the operator touches no storage) is identical on every cloud; see S3 configuration.

DNS on every cloud works through external-dns: install it with a service-account identity scoped to your zone (Route53 / Cloud DNS / Azure DNS per the preset comments) and records for every ingress host appear and disappear automatically. Projects tune records with the dns block (ttl, target).

CDN per cloud is a platform document: publish cdn/<provider>.yaml (seed examples for CloudFront, Cloud CDN, Front Door, and Cloudflare ship in examples/platform-config/cdn/) and projects opt in with one line β€” cdn = "cloudfront". The definitions pair with dns.target so the hostname resolves to the edge, and with origin-protection headers so only the CDN reaches the cluster.

1. Images​

Use published images, or build and push your own:

make push REGISTRY=ghcr.io/yourorg/pagifier VERSION=1.0.0

2. Storage and database​

aws s3 mb s3://pagifier-artifacts && aws s3 mb s3://pagifier-platform
make sync-platform-config CONFIG_BUCKET=pagifier-platform # then customize!
psql "$DATABASE_URL" -f docs/db/schema.sql

Review examples/platform-config/ before syncing β€” the environment profiles and templates in it become your platform's behavior. See S3 configuration for what every document does.

3. Install​

kubectl create namespace pagifier-system
kubectl -n pagifier-system create secret generic pagifier-api-tokens \
--from-literal=tokens='TEAM_A_TOKEN:team-a,TEAM_B_TOKEN:team-b'

helm install pagifier charts/pagifier -n pagifier-system \
--set image.api=ghcr.io/yourorg/pagifier/api:1.0.0 \
--set image.operator=ghcr.io/yourorg/pagifier/operator:1.0.0 \
--set image.builder=ghcr.io/yourorg/pagifier/builder:1.0.0 \
--set registry.url=123456789.dkr.ecr.us-east-1.amazonaws.com/pagifier \
--set storage.artifactBucket=pagifier-artifacts \
--set storage.configBucket=pagifier-platform \
--set storage.region=us-east-1 \
--set api.databaseURL="$DATABASE_URL" \
--set gitObserver.publicURL=https://pagifier.company.com \
--set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"=arn:aws:iam::123456789:role/pagifier

On EKS, grant S3/ECR through IRSA (the annotation above); elsewhere use registry.pushSecret and mounted credentials. The exact IAM policies per component are in S3 configuration.

ValueRecommendation
buildkitPool.enabled=trueShared layer cache β€” dramatically faster builds
operator.maxConcurrentBuilds=10Protects the pool and registry from herds
prometheusURL=…Enables metric-gated canaries
notifyWebhook=…Slack/Teams deploy notifications
preview.domain=preview.company.comPer-PR preview URLs (wildcard DNS + TLS)
signingSecret=pagifier-cosignImage signing + SLSA provenance
api.tokensSecretRotate tokens by updating the secret
gitObserver.publicURLEnables automatic GitHub/GitLab webhook installation
gitObserver.secretNameRetain and back up this credential-encryption Secret

5. Verify​

kubectl -n pagifier-system get pods
curl https://pagifier.company.com/healthz # ok
curl -H "Authorization: Bearer $TOKEN" --data-binary @pagifier.toml \
https://pagifier.company.com/v1/validate

Next, connect Git, replace everyday use of bootstrap admin tokens with scoped tokens, and publish your templates and profiles. Then hand developers the developer guide, the connection IDs they may use, and a narrow token.

Upgrades and rollback (of Pagifier itself)​

The API and operator are stateless when PostgreSQL is configured: helm upgrade / helm rollback. Leader election keeps operator upgrades non-disruptive; in-flight builds survive restarts (Jobs are owned by Releases). Because releases embed their resolved configuration, upgrading Pagifier never changes running applications. Apply the latest docs/db/schema.sql before upgrading the API. The Helm-managed Git credential encryption key is annotated helm.sh/resource-policy: keep; do not delete it while encrypted connections exist.