Skip to main content

Stirling-PDF on GKE Autopilot

Stirling-PDF on GKE Autopilot

Stirling-PDF is an open-source (MIT-licensed core), locally-hosted web PDF toolkit — merge, split, convert, OCR, compress, watermark, sign, redact, and 50+ other PDF operations, all processed on your own infrastructure so documents never touch a third-party service. This module deploys Stirling-PDF on GKE Autopilot on top of the App_GKE foundation, which provisions and manages the shared Google Cloud and Kubernetes infrastructure.

This guide focuses on the cloud services Stirling-PDF uses and how to explore and operate them from the Google Cloud Console and the command line. For the mechanics that are common to every GKE application — Workload Identity, ingress, autoscaling, CI/CD, Cloud Armor, IAP, Binary Authorization, VPC Service Controls, and the deployment lifecycle — refer to the App_GKE foundation guide rather than repeating them here.


1. Overview

Stirling-PDF runs as a Java / Spring Boot web workload (with a bundled LibreOffice for document conversions). The deployment wires together a deliberately small set of Google Cloud services — Stirling-PDF is stateless, so there is no database, no persistent storage, and no secrets to manage:

CapabilityGoogle Cloud serviceNotes
ComputeGKE AutopilotJava pods, 1 vCPU / 2 GiB by default, horizontally autoscaled
Container imageArtifact RegistryOfficial stirlingtools/stirling-pdf image, mirrored in by default
IngressCloud Load BalancingExternal LoadBalancer, optional custom domain + managed certificate
Rate limiting (optional)RedisOff by default; enable only to throttle abuse on a public instance
ObservabilityCloud Logging / Cloud MonitoringPod logs, metrics, optional uptime check and alerts

Sensible defaults worth knowing up front:

  • Stateless — no database, no storage, no secrets. database_type = "NONE", no GCS buckets, no NFS, workload_type = Deployment, and an empty secret map. Every PDF operation runs in a per-request ephemeral working directory discarded on completion.
  • Prebuilt image. container_image_source = "prebuilt" deploys the official stirlingtools/stirling-pdf image directly; enable_image_mirroring = true mirrors it into Artifact Registry to avoid Docker Hub rate limits.
  • Login is disabled by default. enable_login = false (SECURITY_ENABLELOGIN=false) ships an open instance. Enable it and front the workload with IAP or Cloud Armor for a private deployment.
  • Minimum 1 replica. GKE does not support scale-to-zero; min_instance_count = 1 keeps the toolkit reachable. Because there is no shared state, scaling out is safe without Redis.
  • 2 GiB memory floor. The JVM plus LibreOffice needs at least 2Gi; raise container_resources.memory_limit for heavy OCR / conversion workloads.
  • External LoadBalancer with a stable IP. service_type = "LoadBalancer", reserve_static_ip = true, and enable_custom_domain = true by default.
  • Health probes hit /api/v1/info/status — a public, unauthenticated endpoint returning 200 once the JVM and LibreOffice have initialised. The full image can take 2–4 minutes to bind its port on a cold-provisioned Autopilot node, so the startup probe allows a ~5 minute window (20s initial delay, 30 × 10s failures).

2. Google Cloud Services & How to Explore Them

All commands assume you have run gcloud container clusters get-credentials <cluster> --region <region> --project <project> and that PROJECT, REGION, and NAMESPACE are set. The namespace and other identifiers are reported in the deployment Outputs.

A. GKE Autopilot — the Stirling-PDF workload

Stirling-PDF pods are scheduled on Autopilot, which bills for the CPU/memory the pods actually request. Horizontal Pod Autoscaling sizes the deployment between the minimum and maximum replica counts.

  • Console: Kubernetes Engine → Workloads → select the Stirling-PDF workload to see pods and events. Kubernetes Engine → Services & Ingress shows the external IP.
  • CLI:
    kubectl get pods,svc,hpa -n "$NAMESPACE"
    kubectl logs -n "$NAMESPACE" deploy/<service-name> --tail=100
    kubectl describe hpa -n "$NAMESPACE"

See App_GKE for how Autopilot, scaling, and the workload type (Deployment vs StatefulSet) are managed.

B. Artifact Registry — the container image

The official stirlingtools/stirling-pdf image is mirrored into Artifact Registry (enable_image_mirroring = true) and the cluster pulls it from there. No Cloud Build step runs — the image is prebuilt upstream.

  • Console: Artifact Registry → Repositories.
  • CLI:
    gcloud artifacts repositories list --project "$PROJECT" --location "$REGION"

See App_GKE for the mirroring mechanism and image retention.

C. Networking & ingress

By default the workload is exposed through an external Cloud Load Balancing IP. A custom domain with a Google-managed certificate can be enabled, and a static IP is reserved by default so the address survives redeploys.

  • Console: Network services → Load balancing; VPC network → IP addresses.
  • CLI:
    kubectl get ingress,svc -n "$NAMESPACE"
    gcloud compute addresses list --project "$PROJECT"

See App_GKE for custom domains, Cloud CDN, and static IP details.

D. Redis (optional rate limiting)

Redis is disabled by default. Stirling-PDF uses it only for rate limiting and bot detection on public-facing instances (enable_redis = true). When redis_host is left empty and enable_nfs is true, the NFS server VM's IP is used as the endpoint.

  • Console: Memorystore → Redis (if using a managed instance).
  • CLI:
    redis-cli -h <redis-host> ping
    kubectl exec -n "$NAMESPACE" deploy/<service-name> -- env | grep -i redis

E. Identity-Aware Proxy (optional)

Because Stirling-PDF processes potentially sensitive documents, a private deployment should gate the Ingress with IAP. Enabling enable_iap requires an authenticated, authorized Google identity before any request reaches the workload.

  • Console: Security → Identity-Aware Proxy.
  • CLI:
    gcloud iap web get-iam-policy --resource-type=backend-services --project "$PROJECT"

See App_GKE for the IAP OAuth wiring.

F. Cloud Logging & Monitoring

Pod stdout/stderr flow to Cloud Logging; GKE metrics flow to Cloud Monitoring. Optional uptime checks and alert policies are available.

  • Console: Logging → Logs Explorer; Monitoring → Dashboards / Alerting.
  • CLI:
    gcloud logging read 'resource.type="k8s_container" AND resource.labels.namespace_name="'"$NAMESPACE"'"' \
    --project "$PROJECT" --limit 50

3. Stirling-PDF Application Behaviour

  • Nothing is persisted. Uploads are written to a per-request ephemeral working directory and deleted when the response is returned. There is no database, no PVC, and no bucket — a rolling update or pod reschedule loses nothing.
  • Slow first boot. The full image bundles LibreOffice + OCR and can take 2–4 minutes to bind its port on a cold-provisioned Autopilot node. The startup probe targets /api/v1/info/status with a 20s initial delay and 30 failures at 10s intervals (~5 minutes total) before a pod is marked unhealthy; the liveness probe waits a 120s initial delay so it doesn't race the startup probe mid-warmup.
  • Login is optional and off by default. enable_login = false ships an open instance. Set enable_login = true to require Stirling-PDF's built-in authentication; combine with IAP for defence in depth.
  • Safe to scale out. With no shared state, max_instance_count > 1 needs no Redis for correctness — Redis is only for rate limiting. The HPA scales replicas by CPU/memory load.
  • Version upgrades are image-tag bumps. Changing application_version triggers a rolling update with no migration step; the default RollingUpdate strategy is fine because the app is stateless.
  • Confirm the running configuration:
    kubectl exec -n "$NAMESPACE" deploy/<service-name> -- env | grep -iE 'SECURITY_|SYSTEM_'

4. Configuration Variables

Variables are grouped exactly as they appear on the deployment platform. Only settings specific to or notable for Stirling-PDF are listed; every other input is inherited from App_GKE with its standard behaviour and defaults.

Group 1 — Project & Identity

VariableDefaultDescription
project_id(required)Target Google Cloud project.
regionus-central1Region for the workload and regional resources.

Group 2 — Deployment Environment

VariableDefaultDescription
tenant_deployment_iddemoShort suffix that makes resource names unique per environment.
support_users[]Emails granted project access and monitoring alerts.
resource_labels{}Labels applied to all resources.

Group 3 — Application Identity

VariableDefaultDescription
application_namestirlingpdfBase name for resources. Do not change after first deploy.
application_display_nameStirling-PDFHuman-readable name shown in the Console.
application_versionlatestStirling-PDF image tag; pin to a specific release in production.
enable_loginfalseEnable Stirling-PDF's built-in auth (SECURITY_ENABLELOGIN).
default_localeen-USDefault UI locale (SYSTEM_DEFAULTLOCALE).

Group 4 — Runtime & Scaling

VariableDefaultDescription
deploy_applicationtrueSet false to provision infrastructure only.
container_image_sourceprebuiltDeploy the official image (prebuilt) or build a custom one.
container_resources{ cpu_limit="1000m", memory_limit="2Gi" }CPU/memory limits; 2Gi floor for JVM + LibreOffice.
min_instance_count1Minimum replicas; GKE requires ≥ 1.
max_instance_count3Maximum replicas. Safe to raise — no shared state.
container_port8080Stirling-PDF listens on port 8080.
enable_image_mirroringtrueMirror the image into Artifact Registry.
timeout_seconds60Maximum request duration; raise for large conversions.

Group 5 — Environment Variables & Secrets

VariableDefaultDescription
environment_variables{}Extra Stirling-PDF settings (e.g. SYSTEM_MAXFILESIZE). Login and locale are set via enable_login / default_locale.
secret_environment_variables{}Secret Manager references. Stirling-PDF needs none by default.
secret_propagation_delay30Seconds to wait after secret creation before proceeding.
secret_rotation_period2592000sSecret Manager rotation notification frequency.

Group 6 — GKE Backend & Cluster

VariableDefaultDescription
service_typeLoadBalancerHow the Kubernetes Service is exposed.
workload_typenullAuto-resolves to a stateless Deployment. StatefulSet is unnecessary.
session_affinityNoneStirling-PDF is stateless — no sticky routing required.
network_tags["nfsserver"]Node/pod network tags.
termination_grace_period_seconds30Seconds to wait after SIGTERM before SIGKILL.
enable_network_segmentationfalseCreate Kubernetes NetworkPolicy resources.
enable_cloudsql_volumefalseNot used — Stirling-PDF has no database.

Group 7 — StatefulSet

VariableDefaultDescription
stateful_pvc_enablednullLeave off — Stirling-PDF stores no state.
stateful_pvc_size / stateful_pvc_mount_path / stateful_pvc_storage_class10Gi / /data / standard-rwoOnly relevant if a StatefulSet is forced.

Group 9 — Reliability Policies

VariableDefaultDescription
enable_pod_disruption_budgettrueProtect availability during node upgrades.
pdb_min_available1Minimum pods available during voluntary disruptions.
enable_resource_quotafalseEnforce a namespace ResourceQuota.
quota_memory_requests / quota_memory_limits""Must use binary units (4Gi) — bare integers are bytes and block scheduling.

Group 10 — Observability & Health

VariableDefaultDescription
startup_probeHTTP /api/v1/info/status, 20s delay, 30 × 10s retriesStartup probe. ~5 minute first-boot window for JVM + LibreOffice.
liveness_probeHTTP /api/v1/info/status, 120s delayLiveness probe; delayed to clear the slow first boot.
uptime_check_configdisabledOptional Cloud Monitoring uptime check.
alert_policies[]Optional metric alert policies.

Group 11 — Jobs & Scheduled Tasks

VariableDefaultDescription
initialization_jobs[]None required — Stirling-PDF is stateless.
cron_jobs[]Scheduled Kubernetes CronJobs.
additional_services[]Sidecar or helper services.

Group 12 — CI/CD & GitHub Integration

Standard App_GKE Cloud Build / Cloud Deploy integration — see App_GKE. Key inputs: enable_cicd_trigger, github_repository_url, github_token, enable_cloud_deploy.

Group 13 — Filesystem (NFS)

VariableDefaultDescription
enable_nfsfalseNFS is off by default. Enable only if co-locating Redis on the NFS server VM.
nfs_mount_path/mnt/nfsMount path inside the container.

Group 14 — Cloud Storage & Artifact Registry

VariableDefaultDescription
create_cloud_storagefalseStirling-PDF is stateless — no bucket by default.
storage_buckets[]Optional additional buckets.
gcs_volumes[]GCS Fuse volume mounts via the CSI driver.
max_images_to_retain7Maximum recent Artifact Registry images to keep.
manage_storage_kms_iam / enable_artifact_registry_cmekfalseCMEK options.

Group 15 — Redis (optional rate limiting)

VariableDefaultDescription
enable_redisfalseEnable Redis-backed rate limiting / bot detection for public instances.
redis_host""Redis endpoint. Leave empty to use the NFS server IP (requires enable_nfs = true).
redis_port6379Redis port.
redis_auth""Optional Redis auth password (sensitive).

Group 16 — Database Backend

VariableDefaultDescription
database_typeNONEFixed — Stirling-PDF uses no database.
database_password_length32Not used.

Group 19 — Custom Domain, Static IP & Networking

VariableDefaultDescription
enable_custom_domaintrueProvision Ingress for custom hostnames + managed certificate.
application_domains[]Hostnames to serve.
reserve_static_iptrueStable external IP across redeploys.

Group 20 — Identity-Aware Proxy (IAP)

Note: Enabling IAP requires Google identity authentication for all inbound requests. Recommended for private instances handling sensitive documents.

VariableDefaultDescription
enable_iapfalseRequire Google sign-in in front of Stirling-PDF.
iap_authorized_users / iap_authorized_groups[]Who may access.
iap_oauth_client_id / iap_oauth_client_secret""Required when IAP is enabled (sensitive).

Group 21 — Cloud Armor

VariableDefaultDescription
enable_cloud_armorfalseAttach a Cloud Armor (WAF) policy to the Ingress backend. Recommended for public instances.
admin_ip_ranges[]CIDRs allowed privileged access.
enable_cdnfalseEnable Cloud CDN on the GKE Ingress backend.

Group 22 — VPC Service Controls & Audit Logging

VariableDefaultDescription
enable_vpc_scfalseEnforce a VPC-SC perimeter (requires organization_id).
vpc_cidr_ranges / vpc_sc_dry_run(set)Access level CIDRs / dry-run mode.
enable_audit_loggingfalseDetailed Cloud Audit Logs.

5. Outputs

These values are returned on a successful deployment and are the quickest way to locate and explore the running resources.

OutputDescription
service_nameKubernetes Service name.
namespaceNamespace the workload runs in.
service_cluster_ipIn-cluster ClusterIP.
service_external_ipExternal LoadBalancer IP (when a static IP is reserved).
service_urlURL to reach Stirling-PDF.
storage_bucketsCreated Cloud Storage buckets (empty — Stirling-PDF is stateless).
network_name / network_exists / regionsVPC network, presence, available regions.
container_image / container_registryDeployed image and Artifact Registry repo.
monitoring_enabled / monitoring_notification_channelsMonitoring status and channels.
deployment_id / tenant_id / resource_prefixNaming identifiers.
project_id / project_numberProject identifiers.
cicd_enabled / cicd_configurationCI/CD status and details.
github_repository_url / github_repository_owner / github_repository_nameCI/CD GitHub details.
artifact_registry_repository / cloudbuild_trigger_name / cloudbuild_trigger_idRegistry and build trigger.
kubernetes_readyWhether the cluster/workload is ready.
vpc_sc_enabled / vpc_sc_perimeter_name / vpc_sc_dry_run_modeVPC-SC status.
audit_logging_enabled / artifact_registry_cmek_enabledAudit logging and CMEK status.

6. Configuration Pitfalls & Sensible Defaults

Risk: Critical (data loss / outage / security) — High (service degraded) — Medium (cost or partial degradation) — Low (minor).

Inherited plan-time validation. This module passes its configuration through the App_GKE foundation engine, which validates values and combinations at plan time — IAP with no authorized identities, a StatefulSet forced with a Deployment workload type, quota_memory_* in non-binary units, an out-of-range redis_port/timeout_seconds. Invalid configuration fails the plan with a clear, named error before any resource is created, so most mistakes below are caught up front rather than at apply or runtime.

SettingSensible valueRiskConsequence if wrong
enable_login + ingressenable_login = true or IAP for private useHighDefault enable_login = false + external LoadBalancer leaves an open PDF toolkit anyone with the IP can use.
enable_iapEnable for sensitive-document instancesHighWithout IAP (and with login off) the workload is unauthenticated; users can upload confidential documents to an open endpoint.
container_resources.memory_limit2GiHighBelow ~2Gi the JVM + LibreOffice OOM-kills during conversions.
quota_memory_requests / _limitsbinary units (4Gi, 8192Mi)CriticalBare integers are bytes and block all pod scheduling in the namespace.
timeout_seconds60, raise for big filesHighLarge OCR/conversion jobs exceeding the timeout return 504 mid-operation.
min_instance_count1HighGKE requires min ≥ 1; the validation guard rejects 0.
startup_probe windowKeep the ~5 minute defaultMediumShortening it marks pods unhealthy before LibreOffice finishes warming up, wedging the rollout.
enable_cloud_armorEnable for public instancesMediumA public toolkit without a WAF is exposed to abuse and scanning.
enable_pod_disruption_budgettrueMediumDisabling allows GKE to evict all pods simultaneously during maintenance.

For the foundation behaviour referenced throughout — IAM and Workload Identity, autoscaling, ingress and certificates, CI/CD, Cloud Armor, IAP, Binary Authorization, VPC-SC, and image mirroring — see App_GKE. Stirling-PDF-specific application configuration shared with the Cloud Run variant is described in StirlingPDF_Common.