| title | Google Artifact Registry |
|---|---|
| description | Provision and operate the required user-owned image registry. |
Techulus Cloud requires a user-owned Google Artifact Registry (GAR) Docker repository for images built from GitHub sources. Techulus does not provision or own the repository. Agents use one repository-scoped Writer credential to push and pull images. User-supplied images can still use credentials configured under Settings → Registries.
Each source-backed service has one GAR package:
<location>-docker.pkg.dev/<gcp-project>/<repository>/<techulus-project-id>/<service-id>:revision-<revision-id>
Create the repository and Writer service account in Google Cloud Console. Use a billing-enabled project and enable the Artifact Registry and IAM APIs if prompted.
The operator needs permission to enable APIs, administer Artifact Registry repositories and their IAM policies, create service accounts, and create service-account keys. The predefined roles that supply these permissions are Service Usage Admin, Artifact Registry Administrator, Service Account Admin, and Service Account Key Admin, or custom roles with equivalent permissions.
Open Artifact Registry → Repositories → Create repository:
| Setting | Value |
|---|---|
| Name | techulus-images |
| Format | Docker |
| Mode | Standard, not remote or virtual |
| Location | A region close to your deployment agents |
| Immutable tags | Disabled so cleanup can delete tagged versions |
| Encryption | Google-managed key unless you require CMEK |
| Cleanup policy mode | Dry run, not Delete artifacts yet |
Keep the repository private. Configure the cleanup policy before activating deletion.
Alternatively, use Google Cloud Shell or an authenticated gcloud CLI:
export GAR_PROJECT_ID=google-project-id
export GAR_LOCATION=us-central1
export GAR_REPOSITORY_ID=techulus-images
gcloud services enable artifactregistry.googleapis.com iam.googleapis.com \
--project="$GAR_PROJECT_ID"
gcloud artifacts repositories create "$GAR_REPOSITORY_ID" \
--project="$GAR_PROJECT_ID" \
--location="$GAR_LOCATION" \
--repository-format=docker \
--description="Techulus Cloud source images"Open IAM & Admin → Service Accounts and create techulus-agent without granting a project-wide role. In the repository's Permissions panel, grant it Artifact Registry Writer (roles/artifactregistry.writer) on that repository only. The account pushes and pulls images; Techulus does not need repository administration access.
For the equivalent gcloud setup:
export GAR_AGENT_SA="techulus-agent@${GAR_PROJECT_ID}.iam.gserviceaccount.com"
gcloud iam service-accounts create techulus-agent \
--project="$GAR_PROJECT_ID" \
--display-name="Techulus agents"
gcloud artifacts repositories add-iam-policy-binding "$GAR_REPOSITORY_ID" \
--project="$GAR_PROJECT_ID" \
--location="$GAR_LOCATION" \
--member="serviceAccount:${GAR_AGENT_SA}" \
--role="roles/artifactregistry.writer"For the Writer account, open Keys → Add key → Create new key → JSON and download the key to a trusted workstation as agent-key.json. Service-account key creation can be prohibited by the iam.disableServiceAccountKeyCreation organization policy. If blocked, ask your organization administrator to approve an exemption. Google does not allow an existing private key to be downloaded again.
With gcloud, create the key using:
umask 077
gcloud iam service-accounts keys create agent-key.json \
--iam-account="$GAR_AGENT_SA" --project="$GAR_PROJECT_ID"Encode the complete JSON document as one line. These commands work on macOS and Linux; use a new output filename if gar-credentials.env already exists:
umask 077
printf 'GAR_AGENT_KEY_BASE64=%s\n' \
"$(base64 < agent-key.json | tr -d '\r\n')" > gar-credentials.env
chmod 600 gar-credentials.envumask 077 makes newly created files private to your user; chmod 600 explicitly restricts the output to owner read/write access. Base64 is not encryption. Treat both files as private keys: never commit them or paste them into chat.
Securely copy the encoded value into the deployment .env or installer and add the repository path:
GAR_REPOSITORY=us-central1-docker.pkg.dev/google-project-id/techulus-images
GAR_AGENT_KEY_BASE64=<base64 Writer service-account JSON>GAR_REPOSITORY must not include a scheme, image path, tag, or digest. The health endpoint returns 503 when a mandatory GAR value is missing or malformed. After securely transferring the credential, delete temporary files:
rm agent-key.json gar-credentials.envThe control plane includes this credential in each agent's encrypted registry bundle. BuildKit uses it to push images and Podman uses it to pull deployments. TLS verification is always enabled. Static repository-scoped keys are intentional because builds can outlast GAR OAuth access tokens.
The tracked deployment/gar-cleanup-policy.json defines exactly two repository-wide rules:
- keep the 10 most recent versions of every package, with no package-prefix filter;
- delete versions in any tag state once they are older than 30 days.
Keep policies take precedence over delete policies. A version outside the newest 10 remains available until it is older than 30 days. GAR evaluates age from version creation time.
This policy is intentionally independent of deployments. An active or rollback image can disappear when it falls outside a package's newest 10 versions and becomes older than 30 days. Failed and undeployed builds count toward version history. Multi-platform images create multiple registry versions, so 10 versions does not mean 10 builds or rollouts. The newest versions of deleted services remain, and a seven-day service/data restore does not guarantee that its image is still available.In the repository's cleanup settings, use Dry run and configure:
| Name | Action | Condition |
|---|---|---|
keep-most-recent-ten-versions |
Keep most recent versions | Keep count 10, no package prefixes |
delete-versions-after-thirty-days |
Delete | Tag state Any, older than 30 days |
The operator applying policies needs Artifact Registry Administrator permissions. From a Techulus checkout, the equivalent gcloud command is:
gcloud artifacts repositories set-cleanup-policies "$GAR_REPOSITORY_ID" \
--project="$GAR_PROJECT_ID" \
--location="$GAR_LOCATION" \
--policy=deployment/gar-cleanup-policy.json \
--dry-runGAR evaluates cleanup asynchronously, generally within one day. Enable Artifact Registry Data Write audit logs, wait for a dry-run cycle, and inspect proposed BatchDeleteVersions operations. When correct, switch to Delete artifacts in Console or run the same command with --no-dry-run.
After deploying the code that no longer manages GAR tags, replace the old protected-tag Keep rule with the tracked policy; Techulus does not update cloud policies automatically. Then remove GAR_ADMIN_KEY_BASE64 from the deployment environment and revoke/delete the unused Repository Administrator service-account key. Remove the account or its repository role if it has no other purpose. There is no compatibility or migration automation.
This is a clean beta cutover. Techulus does not copy old images or rewrite persisted image references. Configure GAR and the Writer key before upgrading. Existing source-built revisions then point to an unavailable old registry and every source-backed service must be rebuilt before it can deploy from GAR.
The upgrade removes the old registry container but leaves its Docker volume. After verifying the upgrade and deciding rollback data is no longer needed, inspect and explicitly remove the orphaned volume:
docker volume ls --filter name=registry-data
docker volume rm <exact-volume-name>Volume deletion is irreversible and is never performed automatically.
Administrators can add credentials for user-supplied private images under Settings → Registries. A host, including an explicit port when needed, is globally unique and cannot include a scheme or path. The GAR system host is reserved.
Changes are queued for every registered agent, including offline agents. Entries cannot be edited; delete and recreate one to change its username, password, or TLS setting. Use pull-only robot or service-account credentials where possible. Passwords are write-only in the UI, and an actual agent pull remains the authoritative availability check.