Skip to main content

InvenTree on Google Cloud Run

InvenTree is a free, open-source inventory management system: it tracks parts and components, stock locations and movements, suppliers, bills of materials, and purchase and sales orders, and is used by hardware teams, makerspaces and small manufacturers. This module deploys InvenTree on Cloud Run v2 on top of the App_CloudRun foundation, which provisions and manages the shared Google Cloud infrastructure.

This guide focuses on the cloud services InvenTree uses and how to explore and operate them from the Google Cloud Console and the command line. For the mechanics common to every Cloud Run application — service identity, ingress and load balancing, scaling and concurrency, CI/CD, Cloud Armor, IAP, Binary Authorization, VPC Service Controls, backups, and the deployment lifecycle — refer to the App_CloudRun foundation guide rather than repeating them here.


1. Overview​

InvenTree runs as a Python/Django application served by gunicorn on Cloud Run v2. Each revision runs two containers built from the same image: the web container and a django-q qcluster background-worker sidecar. The deployment wires together a focused set of Google Cloud services:

CapabilityGoogle Cloud serviceNotes
ComputeCloud Run v2Web container (1 vCPU / 2 GiB) plus a qcluster sidecar (1 vCPU / 1 GiB); CPU always allocated; scale-to-zero by default
DatabaseCloud SQL for MySQL 8.0Schema created by Django migrations in a dedicated migrate init job
Shared filesystemNFS (Services_GCP NFS server)Optional (enable_nfs = false by default) — needed to persist InvenTree's data directory
Object storageCloud StorageA data bucket (Foundation default) and a storage bucket (from InvenTree_Common) are created; neither is mounted into the container
SecretsSecret ManagerDatabase password only — the module generates no application secrets
IngressCloud Run URL / Cloud Load BalancingProject-number run.app URL; optional external HTTPS load balancer + custom domain

Sensible defaults worth knowing up front:

  • Use the project-number URL. InvenTree checks every request's host against INVENTREE_SITE_URL, which the Foundation injects from the predicted https://<service>-<project-number>.<region>.run.app URL. The hash-form *.a.run.app URL that Cloud Run also advertises returns HTTP 500 (INVE-E7). The service_url output is the project-number form.
  • The data directory is ephemeral unless you enable NFS. InvenTree keeps config.yaml, its generated secret_key.txt, uploaded media, collected static files and plugins under /home/inventree/data. With the default enable_nfs = false, that is the container's own filesystem and is lost on every cold start. Set enable_nfs = true and nfs_mount_path = "/home/inventree/data" for any deployment you intend to keep.
  • Migrations are a job, not a startup step. INVENTREE_AUTO_UPDATE is "false"; the migrate init job owns the schema.
  • The background worker needs CPU outside requests. cpu_always_allocated = true (instance-based billing) so the qcluster sidecar keeps polling between requests.
  • Scale-to-zero is enabled by default (min_instance_count = 0, max_instance_count = 1). While no instance exists, the worker does not run either; set min_instance_count = 1 if scheduled work matters.
  • No administrator account is provisioned. The module creates no admin user and no admin secret (see §3).

2. Google Cloud Services & How to Explore Them​

All commands assume PROJECT and REGION are set. Service and resource names are reported in the deployment Outputs.

A. Cloud Run — the InvenTree service​

InvenTree runs as a Cloud Run v2 service with two containers per revision: the ingress container (gunicorn on port 8000) and the qcluster sidecar (no HTTP). Each deployment creates an immutable revision; traffic can be split across revisions for safe rollouts.

  • Console: Cloud Run → select the service for revisions, containers, traffic, logs, and metrics.
  • CLI:
    gcloud run services list --project "$PROJECT" --region "$REGION"
    gcloud run services describe <service-name> --project "$PROJECT" --region "$REGION"
    gcloud run revisions list --service <service-name> --project "$PROJECT" --region "$REGION"

See App_CloudRun for scaling, concurrency, execution environment, and traffic splitting.

B. Cloud SQL for MySQL 8.0​

InvenTree stores all of its records — parts, stock, orders, users — in a managed Cloud SQL for MySQL 8.0 instance. The service connects over the instance's private IP via TCP (enable_cloudsql_volume = false): the wrapper entrypoint sets INVENTREE_DB_HOST from the Foundation's DB_IP. On first deploy the db-init job creates the database and user, then the migrate job creates the schema.

  • Console: SQL → select the instance for connections, backups, flags, metrics.
  • CLI:
    gcloud sql instances list --project "$PROJECT"
    gcloud sql instances describe <instance-name> --project "$PROJECT"
    gcloud sql connect <instance-name> --user=<db-user> --database=<db-name> --project "$PROJECT"

The instance name, database, user, and password secret are in the Outputs. See App_CloudRun for the connection model, backups, and password rotation.

C. NFS — InvenTree's data directory​

When enable_nfs = true, the Services_GCP NFS share is mounted into the web container and the init jobs at nfs_mount_path, and into the qcluster sidecar at /home/inventree/data. Point nfs_mount_path at /home/inventree/data so all three see the same directory; the default /var/lib/inventree is not a path InvenTree reads or writes.

  • Console: Compute Engine → VM instances (the Services_GCP NFS server).
  • CLI:
    gcloud compute instances list --project "$PROJECT" --filter="name~nfs"

D. Cloud Storage​

Two buckets are provisioned by default: the Foundation's data bucket (from storage_buckets) and a storage bucket contributed by InvenTree_Common. Neither is mounted into the container (gcs_volumes is empty), and InvenTree does not read or write them. The storage bucket is a convenient place to stage files for enable_custom_sql_scripts.

  • Console: Cloud Storage → Buckets.
  • CLI:
    gcloud storage buckets list --project "$PROJECT"

E. Secret Manager​

InvenTree_Common generates no application secrets. The only secret is the database password, managed by the foundation. Any credential-named key you put in environment_variables is moved into Secret Manager automatically while protect_sensitive_environment_variables = true.

  • Console: Security → Secret Manager.
  • CLI:
    gcloud secrets list --project "$PROJECT"

See App_CloudRun for injection and rotation details.

F. Networking & ingress​

The service is reachable at its project-number run.app URL by default. An external HTTPS load balancer with a custom domain, Cloud CDN, and Cloud Armor can be layered on; a custom domain also sidesteps the two-hostname issue above.

  • Console: Cloud Run (service URL); Network services → Load balancing.
  • CLI:
    PROJECT_NUMBER=$(gcloud projects describe "$PROJECT" --format='value(projectNumber)')
    echo "https://<service-name>-${PROJECT_NUMBER}.${REGION}.run.app"
    gcloud compute addresses list --project "$PROJECT"

See App_CloudRun.

G. Cloud Logging & Monitoring​

Logs from both containers flow to Cloud Logging; Cloud Run and Cloud SQL metrics flow to Cloud Monitoring. The uptime check is off by default (uptime_check_config.enabled = false).

  • Console: Logging → Logs Explorer; Monitoring → Dashboards / Alerting.
  • CLI:
    gcloud run services logs read <service-name> --project "$PROJECT" --region "$REGION" --limit 50

3. InvenTree Application Behaviour​

  • Two-stage init chain. db-init (mysql:8.0-debian, 3 retries, 600 s) creates the MySQL user and database and verifies the user can connect. migrate (the app image, 2 vCPU / 2 GiB, 1800 s, depends on db-init) runs python3 manage.py migrate --noinput and then counts the tables; it fails if fewer than 10 exist, because migrate can exit 0 having applied nothing.
  • Why not INVENTREE_AUTO_UPDATE. Upstream's in-process migration runs in the gunicorn master before the port binds (so the startup probe kills the revision mid-migration), its empty-database branch is unreachable, and the web and worker containers would race on the same schema. Both containers run with INVENTREE_AUTO_UPDATE = "false".
  • Required environment. The wrapper entrypoint refuses to start without INVENTREE_SITE_URL (or CLOUDRUN_SERVICE_URL as a fallback) and the Foundation's DB_IP, DB_NAME, DB_USER and DB_PASSWORD. The module also sets INVENTREE_USE_X_FORWARDED_PROTO = "true" and INVENTREE_SESSION_COOKIE_SECURE = "true", so absolute links are https:// and cookies are secure behind Cloud Run's TLS termination.
  • Static files. The web container runs collectstatic on every start (the vendor init.sh does not). A failure there is logged as a warning and the container still starts — the UI may then render unstyled.
  • Background worker. The qcluster sidecar runs /cloud-entrypoint.sh invoke worker with the app's infrastructure env and secrets (inherit_app_env = true), and with INVENTREE_AUTO_UPDATE and INVENTREE_COLLECTSTATIC set to false. Turning off enable_background_worker removes it: the UI and API still work, but no scheduled tasks, notifications or label generation run.
  • Health checks. Startup and liveness probes are HTTP GET / on port 8000. The root path answers with a redirect to the web UI.
    curl -s -o /dev/null -w "%{http_code}\n" "$SERVICE_URL/"   # expect 302
  • First administrator. The module creates no InvenTree user, and the admin_email input is not used. Create the first superuser yourself — for example with InvenTree's own INVENTREE_ADMIN_USER, INVENTREE_ADMIN_EMAIL and INVENTREE_ADMIN_PASSWORD settings (see the InvenTree documentation), supplied through environment_variables / secret_environment_variables.
  • Inspect job execution:
    gcloud run jobs list --project "$PROJECT" --region "$REGION"
    gcloud run jobs executions list --job <job-name> --project "$PROJECT" --region "$REGION"

4. Configuration Variables​

Variables are grouped exactly as they appear on the deployment platform. Only settings specific to or notable for InvenTree are listed; every other input is inherited from App_CloudRun with its standard behaviour.

Group 1 — Project & Identity​

VariableDefaultDescription
project_id(required)Target Google Cloud project.
tenant_iddemoShort suffix that makes resource names unique per environment.
regionus-central1Region for the service and regional resources.

Group 2 — Deployment Environment​

VariableDefaultDescription
support_users[]Emails granted project access and monitoring alerts.
resource_labels{}Labels applied to all resources.

Group 3 — Application Identity​

VariableDefaultDescription
application_nameinventreeBase name for resources. Do not change after first deploy.
display_nameInvenTreeHuman-readable name shown in the Console.
application_version1.5.4inventree/inventree tag, passed as the INVENTREE_VERSION build ARG. Pin an exact version — this variant's value is the one that takes effect.
php_memory_limit512MNot used — InvenTree is a Python application.
admin_emailadmin@example.comNot used — no administrator account is created.
enable_gcs_storage_volumetrueNot used — no bucket is mounted by this setting.

Group 4 — Runtime & Scaling​

VariableDefaultDescription
deploy_applicationtrueSet false to provision infrastructure only.
container_image_sourcecustomBuilds the wrapper image via Cloud Build. "prebuilt" skips the wrapper entrypoint and its DB_* → INVENTREE_DB_* mapping.
cpu_limit1000mCPU for the web container.
memory_limit2GiMemory for the web container.
min_instance_count00 enables scale-to-zero.
max_instance_count1Autoscaling upper bound.
container_port8000gunicorn's port.
execution_environmentgen2Cloud Run execution environment.
timeout_seconds300Maximum request duration.
enable_cloudsql_volumefalseConnect over private-IP TCP instead of the Auth Proxy socket.
container_protocolhttp1HTTP/1.1.
cpu_always_allocatedtrueRequired for the qcluster sidecar.
enable_background_workertrueRun the qcluster sidecar.
worker_cpu_limit / worker_memory_limit1000m / 1GiSidecar resources.

Group 5 — Access & Ingress Control​

VariableDefaultDescription
ingress_settingsallPublic ingress by default.
vpc_egress_settingPRIVATE_RANGES_ONLYRoute only RFC 1918 traffic via VPC.
enable_iapfalseRequire Google sign-in.
iap_authorized_users / iap_authorized_groups[]Who may access through IAP.

Group 6 — Environment Variables & Secrets​

VariableDefaultDescription
environment_variables{}Extra InvenTree settings (INVENTREE_*). Merged over the module's defaults, so a key here wins — do not override INVENTREE_AUTO_UPDATE, INVENTREE_DATA_DIR or INVENTREE_DB_ENGINE.
secret_environment_variables{}Map of env var → Secret Manager secret name.
protect_sensitive_environment_variablestrueMoves credential-named keys from environment_variables into Secret Manager.
secret_propagation_delay30Seconds to wait after secret creation before proceeding.
secret_rotation_period2592000sSecret Manager rotation notification frequency.

Group 7 — Backup & Restore​

VariableDefaultDescription
backup_schedule0 2 * * *Automated backup cron (UTC).
backup_retention_days7Retention; raise for production.
enable_backup_import / backup_source / backup_uri / backup_formatrestore optionsRestore from a backup on deploy.

Group 8 — CI/CD & Binary Authorization​

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

Group 9 — Custom SQL Scripts & NFS Naming​

enable_custom_sql_scripts, custom_sql_scripts_bucket, custom_sql_scripts_path, custom_sql_scripts_use_root — run SQL from a GCS bucket after provisioning (verified end to end on this module, executed as the application user). nfs_instance_name / nfs_instance_base_name select the NFS server; leave them at their defaults to use the Services_GCP server. See App_CloudRun.

Group 10 — Load Balancer, CDN & Image Retention​

VariableDefaultDescription
enable_cloud_armorfalseProvision Global HTTPS LB + Cloud Armor WAF.
application_domains[]Custom domain names for the HTTPS LB.
enable_cdnfalseEnable Cloud CDN on the HTTPS LB backend (requires Cloud Armor).
max_images_to_retain7Revision/image pruning.
delete_untagged_images / image_retention_daystrue / 30No effect in a Services_GCP deployment — the shared registry's own policy applies.

Group 11 — Storage & Filesystem​

VariableDefaultDescription
create_cloud_storagetrueCreate the buckets in storage_buckets.
storage_buckets[{ name_suffix = "data" }]Setting this replaces the list — adding a bucket destroys the default data bucket.
enable_nfsfalseMount NFS into the service, jobs and sidecar. Set true to persist the data directory.
nfs_mount_path/var/lib/inventreeSet to /home/inventree/data when enable_nfs = true.
gcs_volumes[]GCS Fuse volume mounts (requires gen2).
manage_storage_kms_iam / enable_artifact_registry_cmekfalseCMEK options.

Group 12 — Database Backend​

VariableDefaultDescription
database_typeMYSQL_8_0InvenTree is configured for MySQL.
db_name / db_userinventreeTenant-prefixed at deploy time. Immutable after first deploy.
database_password_length32Generated password length (16–64). Do not change on a running deployment.
enable_auto_password_rotationfalseAutomated password rotation.
db_host_env_var_nameDB_IPExtra name for the DB private IP; redundant, since DB_IP is always injected.

Group 13 — Jobs & Scheduled Tasks​

VariableDefaultDescription
initialization_jobs[]Leave empty to use the built-in db-init → migrate chain. A non-empty list replaces it entirely.
cron_jobs[]No platform-scheduled recurring tasks by default — InvenTree's own scheduling runs in the qcluster sidecar.

Group 14 — Observability & Health​

VariableDefaultDescription
startup_probeHTTP GET /, 30 s delay, 15 s period, 60 retriesA long window for a cold first start.
liveness_probeHTTP GET /, 60 s delay, 30 s period, 3 retriesMatches the vendor image's health check (the document root).
uptime_check_config{ enabled = false, path = "/" }Cloud Monitoring uptime check — off by default.
alert_policies[]Metric alert policies.

Group 21 — Redis​

VariableDefaultDescription
enable_redisfalseInvenTree is not wired to Redis by this module.
redis_host / redis_port"" / 6379Redis endpoint.

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​

Returned on a successful deployment — the quickest way to locate and explore the running resources.

OutputDescription
service_nameCloud Run service name.
service_urlProject-number run.app URL of the service — the one InvenTree accepts.
service_locationRegion the service runs in.
load_balancer_ip / load_balancer_urlExternal HTTPS load balancer IP / URL (when enabled).
database_instance_nameCloud SQL instance name.
database_name / database_userApplication database name / user.
database_password_secretSecret Manager secret holding the DB password.
database_host / database_portDB endpoint (sensitive) / port.
storage_bucketsCreated Cloud Storage buckets.
network_name / network_exists / regionsVPC network, presence, regions.
container_image / container_registryDeployed image and Artifact Registry repo.
monitoring_enabled / monitoring_notification_channels / uptime_check_namesMonitoring status, channels, uptime checks.
initialization_jobsNames of the setup jobs (db-init, migrate).
deployment_id / tenant_id / resource_prefixNaming identifiers.
project_id / project_numberProject identifiers.
cicd_enabled / github_repository_url / cicd_configurationCI/CD status and details.
artifact_registry_repository / cloudbuild_trigger_name / cloudbuild_trigger_idRegistry and build trigger.
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_CloudRun 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
enable_nfs / nfs_mount_pathtrue / /home/inventree/dataCriticalWith the defaults (false / /var/lib/inventree) the data directory is ephemeral: uploaded media, plugins, config.yaml and the generated secret key are lost on every cold start, and a new secret key invalidates all sessions and password-reset tokens. Enabling NFS at the default path mounts a directory InvenTree never uses.
Service URL used by peoplethe project-number URL (service_url output) or a custom domainHighThe hash-form *.a.run.app URL returns HTTP 500 (INVE-E7), because the host does not match INVENTREE_SITE_URL.
db_name / db_userSet onceCriticalImmutable after first deploy; renaming recreates the DB/user and loses all inventory data.
storage_bucketsleave at default unless you mean to replace itHighThe list replaces the default — adding one bucket destroys the data bucket and anything in it.
environment_variablesdo not set INVENTREE_AUTO_UPDATE=trueCriticalRe-enables in-process migrations in both containers: a race on one schema and a probe kill mid-migration. A half-migrated database cannot be repaired by re-running migrate (it fails with Duplicate column name) — it has to be dropped and recreated.
initialization_jobs[]HighAny non-empty list replaces db-init → migrate; without them the schema is never created and the app exits on start.
container_image_sourcecustomCriticalprebuilt deploys the stock image without the wrapper entrypoint — no INVENTREE_DB_* mapping, so InvenTree cannot reach MySQL.
application_versionan exact tagMediumPin it on this variant; a pin set only in InvenTree_Common is overridden.
cpu_always_allocated / enable_background_workertrue / trueMediumWith request-based CPU the worker is frozen between requests; without the sidecar no background tasks run. Both fail silently.
min_instance_count1 for productionMediumAt 0 there is no instance, and so no background worker, while idle; the first request after idle waits for a cold start.
database_password_lengthSet onceHighChanging it on a running deployment rotates the password without updating the database user; every connection then fails until db-init is re-run.
enable_cloud_armorenable for productionMediumThe service is publicly reachable without WAF protection by default.

For the foundation behaviour referenced throughout — service identity, scaling and concurrency, ingress and load balancing, CI/CD, Cloud Armor, IAP, Binary Authorization, VPC-SC, backups, and image mirroring — see App_CloudRun. InvenTree-specific application configuration is described in InvenTree_Common.

Need RAD to do something it does not do yet? Request it on the roadmap, or vote on what is already there.