Install on Google Cloud¶
infra-gcp/gcp.sh installs Axium in a Google Cloud project from Cloud Shell:
a Cloud SQL (PostgreSQL 17) instance, and the core and the ui as two Cloud Run
services. It is meant to be pasted and waited on, and it is idempotent: you
can re-run it to upgrade versions without losing the database or the master
key.
Run it¶
Open Cloud Shell in the target project and run:
wget https://raw.githubusercontent.com/axium-lab/infrastructure-documentation/refs/heads/main/infra-gcp/gcp.sh \
&& chmod +x gcp.sh \
&& TAG=v0.1.0 ./gcp.sh
The script asks for two things it cannot find on its own:
- Your Axium license (40 hexadecimal characters). It is checked against the Axium Lab license API before anything is created, so a mistyped or expired license fails in seconds rather than after ten minutes of Cloud SQL provisioning. If the license API cannot be reached the script warns and continues: the core validates the license again at startup.
- Your Quay user and token, unless a session already exists.
Plan for 10 to 15 minutes, most of it waiting for Cloud SQL.
Options¶
All options are environment variables:
| Variable | Default | Effect |
|---|---|---|
TAG |
latest |
Image tag to deploy. Pin a version in production: TAG=v0.1.0. |
REGION |
europe-west1 |
Region for Cloud SQL, Artifact Registry and Cloud Run. |
PROJECT_ID |
current gcloud project |
Target project. |
AXIUM_LICENSE |
asked interactively | License key. Pass it in pipelines; an invalid value aborts instead of prompting. |
VERTEX_PROJECT |
PROJECT_ID |
Project where Vertex AI lives, if different. The IAM role is granted there. |
DB_INSTANCE / DB_NAME / DB_USER |
axium-db / axium-api / axium |
Cloud SQL names. |
AR_REPO |
axium |
Artifact Registry repository. |
CORE_SERVICE / UI_SERVICE |
axium-core / axium-ui |
Cloud Run service names. |
DEBUG |
unset | 1 prints registry connectivity diagnostics and runs crane in verbose mode. |
AXIUM_NO_CRANE |
unset | 1 forces the Docker daemon for image copies instead of crane. |
What it creates¶
flowchart LR
B[Browser] -->|HTTPS| UI[Cloud Run<br/>axium-ui]
B -->|HTTPS · API_URL| CORE[Cloud Run<br/>axium-core]
CORE -->|Unix socket /cloudsql| SQL[(Cloud SQL<br/>PostgreSQL 17)]
CORE -->|OAuth2 · roles/aiplatform.user| VX[Vertex AI]
CORE -->|roles/storage.objectUser| GCS[(Cloud Storage)]
Q[quay.io/axiumlab] -->|crane copy| AR[Artifact Registry<br/>REGION-docker.pkg.dev]
AR --> UI
AR --> CORE
Step by step:
- License check against
https://meta.axium-lab.com/v1/license/check/<license>. - APIs:
sqladmin,run,artifactregistry,storagein the project, andaiplatforminVERTEX_PROJECT(a failure there only warns). - Artifact Registry repository
axium. Cloud Run can only deploy from Artifact Registry, so the images are copied from Quay withcrane(falls back to the Docker daemon). Downloads ofcraneare cached in~/.axium/bin. - Cloud SQL: the cheapest configuration that exists, intended for a
pilot.
db-f1-micro, 10 GB HDD, single zone, no automatic backups. For production remove--no-backupand pick a bigger tier. - Secrets:
MASTER_ENCRYPTION_KEYandDATABASE_URLare read back from the deployed core if it exists and generated otherwise. The master key is never regenerated once it exists. The DSN uses the Cloud SQL Unix socket:postgresql://axium:<pass>@localhost/axium-api?host=/cloudsql/<connectionName>. -
IAM on the runtime service account (the project's default compute SA unless the service already uses another):
Role Project Why roles/cloudsql.clientdeploy Connect through the /cloudsqlsocket.roles/storage.objectUserdeploy Read, write and delete objects in buckets. roles/storage.bucketViewerdeploy List buckets and read metadata; objectUseralone makesbucket.exists()return 403.roles/aiplatform.userVERTEX_PROJECTCall Google models through Vertex AI. Publisher models do not accept per-resource IAM, so the binding is project-wide. -
Core on Cloud Run:
--allow-unauthenticated, 1 GiB RAM, 1 vCPU, concurrency 20, 0 to 4 instances, withDATABASE_URL,MASTER_ENCRYPTION_KEY,TRUST_PROXY=trueandAXIUM_LICENSE. Memory and concurrency follow from the 50 MB upload ceiling, which is held in RAM per request. - Ui on Cloud Run: 512 MiB, concurrency 80,
API_URL=<core URL>/v1. - Verification: waits for
/v1/health, then requires/v1/install/statusto answerinstalled.
The script ends with the console URL, the API URL, the initial credentials and the master key in clear text. Save it before closing the shell.
After installing¶
- Change the admin password (First login).
- Move the secrets to Secret Manager. The master key and the database
password are in clear text in the Cloud Run service configuration, visible to
anyone with read access to the project. Replace
--set-env-varswith--set-secretsin the script to harden it. -
Renewing the license does not require reinstalling:
-
Vertex AI in another project. The core calls Vertex with the
project_idconfigured in the provider inside Axium. If that is not the deploy project, re-run withVERTEX_PROJECT=<that project> bash gcp.shor grantroles/aiplatform.userthere by hand, otherwise generation fails with403 PERMISSION_DENIED. - Public services. If the deploy fails mentioning IAM or
allUsers, your organization's domain-restricted-sharing policy forbids public Cloud Run services. Deploy with--no-allow-unauthenticatedand put a load balancer or IAP in front.
Several environments in one project¶
infra-gcp/gcp-environments.sh is the same installer with an environment
prefix. It asks for a name (dev, test, pre, …) and creates
<env>-axium-core, <env>-axium-ui and a database <env>-axium-api inside
the same Cloud SQL instance, which is the only piece that costs money to
duplicate.
AXIUM_ENV=dev TAG=v0.1.0 bash gcp-environments.sh # non-interactive
AXIUM_ENV= bash gcp-environments.sh # empty = no prefix, same as gcp.sh
Each environment gets its own master key and its own database user password, read back from its own Cloud Run service on re-runs.
Upgrading¶
Use infra-gcp/update.sh. It is covered in Upgrading.
Cost notes¶
With the defaults, idle cost is dominated by the Cloud SQL instance
(db-f1-micro, always on). Both Cloud Run services scale to zero. The first
request after a scale-to-zero pays a cold start of a few seconds; on the core
that cold start also runs the schema check.