Skip to main content

LubeLogger on GKE Autopilot

LubeLogger on GKE Autopilot

LubeLogger is a free, open-source vehicle maintenance and fuel-mileage tracker built on ASP.NET Core (.NET), shipped as a single container image with an embedded LiteDB database. This module deploys LubeLogger 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 LubeLogger 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, backups, and the deployment lifecycle — refer to the App_GKE foundation guide rather than repeating them here.


1. Overview

LubeLogger runs as a single ASP.NET Core pod, recommended as a StatefulSet with a real block-storage PVC. The deployment wires together a minimal set of Google Cloud services — there is no managed database in the default configuration:

CapabilityGoogle Cloud serviceNotes
ComputeGKE AutopilotASP.NET Core pod, 1 vCPU / 1 GiB by default, fixed at a single replica
DatabaseNone (default)LubeLogger's default mode uses an internal embedded LiteDB database file — no Cloud SQL instance is created
Object storage / block storageCloud Storage + Persistent DiskA block PVC (recommended, stateful_pvc_enabled = true) at /App/data, plus a small dpkeys GCS bucket for ASP.NET Core Data Protection keys (always GCS-backed)
Cache & queueNoneLubeLogger has no Redis usage and no background worker/queue
SecretsNoneNo secrets are generated — the first account is created via self-service registration
IngressCloud Load BalancingExternal LoadBalancer by default; optional custom domain + managed certificate

Sensible defaults worth knowing up front:

  • No external database by default. database_type = "NONE" — LubeLogger's own embedded LiteDB database file is the source of truth. LubeLogger also supports an optional external Postgres backend via a single POSTGRES_CONNECTION DSN environment variable, but this module does not wire Cloud SQL for it.
  • Block-storage PVC is the recommended layout. stateful_pvc_enabled = true (default) runs LubeLogger as a StatefulSet with a per-pod PVC mounted at /App/data — a real block device gives reliable file locking for the embedded LiteDB database, unlike GCS FUSE.
  • Single instance only. min_instance_count = 1 and max_instance_count = 1 — LubeLogger's default mode serves one shared database file from one volume; running multiple replicas against the same file corrupts it.
  • Runs as root; no fsGroup needed. Confirmed directly against the running image — LubeLogger's official image has no USER directive, so stateful_fs_group defaults to 0 (unset).
  • Secure by default. EnableAuth = "true" overrides LubeLogger's own appsettings.json default of fully open access. There is no seeded admin account — the first person to complete the Register form on /Login gains access.
  • Prebuilt image, no build step. The module deploys the official ghcr.io/hargata/lubelogger image directly (mirrored into Artifact Registry by default) — there is no Dockerfile or Cloud Build involved.
  • Externally reachable by default. service_type = "LoadBalancer" — LubeLogger is a public-facing web application, not an internal-only workload.

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 LubeLogger workload

LubeLogger runs as a single pod (StatefulSet by default), which Autopilot bills for based on requested CPU/memory.

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

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

B. Persistent storage — block PVC and Cloud Storage

The default layout (stateful_pvc_enabled = true) provisions a per-pod Persistent Disk-backed PVC mounted at /App/data — this holds the embedded LiteDB database file and uploaded photos/receipts/documents. A separate, small Cloud Storage bucket (dpkeys) is always mounted via GCS FUSE at the fixed path /root/.aspnet/DataProtection-Keys, independent of the PVC.

  • Console: Kubernetes Engine → Storage (PVCs); Cloud Storage → Buckets.
  • CLI:
    kubectl get pvc -n "$NAMESPACE"
    gcloud storage buckets list --project "$PROJECT" --filter="name~lubelogger"

See App_GKE for StorageClass, CMEK, and GCS Fuse mount options.

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 can be reserved 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. 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. LubeLogger Application Behaviour

  • No first-deploy database setup. There is no db-init job — LubeLogger initialises its own LiteDB database file and directory structure (config/, documents/, images/, temp/, themes/, translations/ under /App/data) on first boot.
  • No fixed admin credential. Open the service, go to /Login, and submit the Register form — that becomes the usable account. Complete this immediately after first deploy: EnableAuth = "true" restricts the rest of the app, but registration itself is open to anyone who can reach the URL until a first account exists.
  • Health path. Startup and liveness probes target /Login — LubeLogger's public, unauthenticated page. The app root / is [Authorize]-gated and would fail an unauthenticated probe even on a healthy container.
  • Optional external Postgres. LubeLogger supports a single POSTGRES_CONNECTION DSN environment variable (Host=<host>;Port=5432;Username=<user>;Password=<pass>;Database=<db>;) to use an external Postgres database instead of the embedded LiteDB file. This module does not provision Cloud SQL for this path.
  • Single instance, always. max_instance_count is fixed at 1 — LubeLogger's default mode has no distributed-locking or multi-writer support for its embedded database.
  • Runs as root. Confirmed via docker inspect/docker exec against the actual image — no USER directive, process runs as uid 0. Relevant if you ever add a restricted securityContext — the default configuration needs none.

4. Configuration Variables

Variables are grouped exactly as they appear on the deployment platform. Only settings specific to or notable for LubeLogger 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 for cost/ownership tracking.

Group 3 — Application Identity

VariableDefaultDescription
application_namelubeloggerBase name for resources. Do not change after first deploy.
application_versionlatestImage tag on ghcr.io/hargata/lubelogger. Since the image is prebuilt (not custom-built), this directly selects the released version.

Group 4 — Runtime & Scaling

VariableDefaultDescription
deploy_applicationtrueSet false to provision infrastructure only.
min_instance_count1Kept at 1 to avoid cold starts.
max_instance_count1Must stay at 1 — LubeLogger's default mode serves one shared database file.
cpu_limit1000mCPU per pod.
memory_limit1GiMemory per pod.
timeout_seconds300Maximum request duration (0–3600 seconds).
enable_cloudsql_volumefalseLubeLogger's default mode has no Cloud SQL.
enable_image_mirroringtrueMirror the LubeLogger image into Artifact Registry before deployment.

Group 5 — Environment Variables & Secrets

VariableDefaultDescription
environment_variables{}Extra non-secret settings, merged with the module's default EnableAuth = "true".
secret_environment_variables{}Map of env var → Secret Manager secret name. Use this for POSTGRES_CONNECTION if wiring the optional external Postgres backend.
secret_propagation_delay30Seconds to wait after secret creation before proceeding.
secret_rotation_period2592000sSecret Manager rotation notification frequency.

Group 6 — GKE Backend & Cluster

VariableDefaultDescription
service_typeLoadBalancerLubeLogger is a public-facing web application, so it defaults to external access.
workload_typenull (auto → StatefulSet)Auto-resolves to StatefulSet when stateful_pvc_enabled = true.
session_affinityNoneNo sticky routing needed — single replica.
network_tags["nfsserver"]Node/pod network tags; only relevant if enable_nfs = true.
termination_grace_period_seconds60Seconds to wait after SIGTERM before SIGKILL (lets LubeLogger flush writes).
enable_network_segmentationfalseCreate Kubernetes NetworkPolicy resources.

Group 7 — StatefulSet

VariableDefaultDescription
stateful_pvc_enabledtrueRecommended for LubeLogger — a real block PVC gives reliable file locking for the embedded LiteDB database.
stateful_pvc_size20GiPer-pod PVC storage size — sized for the LiteDB database, uploaded documents/receipts, and overhead.
stateful_pvc_mount_path/App/dataContainer mount path for the PVC — must match LubeLogger's data directory.
stateful_pvc_storage_classstandard-rwoKubernetes StorageClass for PVCs; use premium-rwo for higher IOPS.
stateful_headless_servicenullCreate a headless Service for stable pod DNS names.
stateful_pod_management_policynullPod creation order: OrderedReady or Parallel.
stateful_update_strategynullUpdate strategy: RollingUpdate or OnDelete.
stateful_fs_group0Left unset — LubeLogger's official image runs as root and needs no fsGroup to write to the PVC.

Group 8 — Resource Quota

VariableDefaultDescription
enable_resource_quotafalseCreate a Kubernetes ResourceQuota in the application namespace.
quota_memory_requests / quota_memory_limits""Requires a binary suffix (e.g. 4Gi, 8192Mi) per convention when set.

Group 9 — Reliability Policies

VariableDefaultDescription
enable_pod_disruption_budgettrueProtect availability during node upgrades.
pdb_min_available1Minimum pods available during voluntary disruptions.

Group 10 — Observability & Health

VariableDefaultDescription
startup_probeHTTP /Login 15s delayStartup probe.
liveness_probeHTTP /Login 30s delayLiveness probe.
startup_probe_configHTTP /LoginApp_GKE-level infrastructure probe.
health_check_configHTTP /LoginApp_GKE-level liveness probe.
uptime_check_configdisabledOptional Cloud Monitoring uptime check.
alert_policies[]Optional metric alert policies.

Group 11 — Jobs & Scheduled Tasks

VariableDefaultDescription
initialization_jobs[]LubeLogger's default mode needs no init job.
cron_jobs[]No platform-scheduled recurring tasks by default.
additional_services[]Sidecar or helper services deployed alongside LubeLogger.

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 14 — Cloud Storage & Artifact Registry

VariableDefaultDescription
create_cloud_storagetrueCreate the storage and dpkeys GCS buckets.
storage_buckets[]Additional buckets to provision.
gcs_volumes[]Additional GCS Fuse volume mounts via the CSI driver.
max_images_to_retain7Maximum recent Artifact Registry images to keep.
delete_untagged_imagestrueAutomatically delete untagged images.
image_retention_days30Days after which images are eligible for deletion.

Group 15 — Redis

VariableDefaultDescription
enable_redistrue (foundation default)Forwarded for compatibility; LubeLogger_GKE forces it false — LubeLogger needs no Redis.

Group 16 — Database Backend

VariableDefaultDescription
database_typeNONEFixed — LubeLogger's default mode has no Cloud SQL database.

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 22 — VPC Service Controls & Audit Logging

VariableDefaultDescription
enable_vpc_scfalseEnforce a VPC-SC perimeter (requires organization_id).
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 LubeLogger.
storage_bucketsCreated Cloud Storage buckets (storage, dpkeys).
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.
initialization_jobsNames of setup jobs (none by default).
statefulset_nameName of the StatefulSet.
deployment_id / tenant_id / resource_prefixNaming identifiers.
project_id / project_numberProject identifiers.
cicd_enabled / cicd_configurationCI/CD status and details.
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. 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
max_instance_count1CriticalLubeLogger's default mode serves one shared embedded database file from one volume; more than one replica risks database corruption from concurrent writers. Enforced by a plan-time validation guard.
stateful_pvc_enabledtrueHighA real block PVC gives reliable file locking; falling back to GCS FUSE for /App/data (by setting this false) risks lock contention under concurrent writes.
stateful_pvc_mount_path/App/dataCriticalMust match LubeLogger's actual data directory — a wrong path means the database and uploads are written to ephemeral pod storage and lost on every restart.
storage/dpkeys buckets, or the PVCNever deleteCriticalLosing /App/data (PVC or storage bucket) loses every vehicle record; losing dpkeys invalidates all existing login sessions (recoverable — forces re-login only).
EnableAuthtrue (default)CriticalSetting it to false reverts to LubeLogger's fully open-access mode — anyone with the URL can view/edit all data with no login at all.
First-run registrationComplete immediately after deployHighUntil a first account is registered, the Register form is reachable by anyone who can reach the URL.
startup_probe/liveness_probe path/LoginCriticalPointing probes at / (or any [Authorize]-gated path) fails the probe on an otherwise-healthy pod — it never becomes Ready.
workload_typeleave null (auto)HighSetting workload_type = "Deployment" alongside stateful_pvc_enabled = true fails at plan time — a PVC template requires a StatefulSet.
database_typeNONE (default)HighLubeLogger's default mode ignores this setting entirely; changing it does not connect LubeLogger to a Cloud SQL instance — use POSTGRES_CONNECTION instead for the optional external Postgres path.
quota_memory_requests / _limitsbinary units (4Gi, 8192Mi)CriticalBare integers are bytes and block all pod scheduling in the namespace.
enable_pod_disruption_budgettrueMediumDisabling allows GKE to evict the pod during maintenance with no protection.
service_typeLoadBalancer (default)MediumSetting to ClusterIP makes the public web UI unreachable from outside the cluster.

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