Tutorial 10 — List and Deploy via Azure Marketplace
> Status note.* The Helm chart at deploy/helm/buttrbase-backend-rust/ is real and committed — you can run it against an AKS cluster right now using tutorial 07. The Azure Marketplace *listing* (the Partner Center offer, the Azure Container/Kubernetes application package, the certification pipeline) is forward-looking: this tutorial is a packaging guide for when you take that chart to market, not a guide to a listing that exists today. Steps that require a Microsoft Partner Center account are marked *[Marketplace listing — forward-looking] so the distinction is never ambiguous.
This tutorial is one layer thin: it explains what Azure Marketplace adds on top of the chart, how to push the image to Azure Container Registry so Azure can reference it, how the Kubernetes application offer wraps the chart, and what a customer sees when they install from the Marketplace. For everything about how Helm install actually works — topology values, secrets, the /health probe — see 07-deploy-with-helm.md. That document is the substrate; this one references it, it does not repeat it.
1. Why Azure Marketplace
Azure Marketplace lets an AKS customer deploy ButtrBase directly into their own Azure subscription* — they find the listing, click *Get It Now, pick a cluster, and the Marketplace UI drives the same Helm values the operator would set by hand. The purchase settles through their existing Azure billing account and can draw down Microsoft Azure Consumption Commitments (MACC) — meaning enterprises with committed Azure spend can apply that commitment to ButtrBase without a separate procurement motion.
This maps exactly to the single-tenant-byoc topology: the customer owns the AKS cluster, the Azure Database for PostgreSQL instance, and the Azure Blob Storage bucket. ButtrBase's Mothership provisions the tenant record and issues the encryption keys; the customer's infrastructure runs the workload. See the deployment matrix in docs/specs/federation-and-deployment-architecture.md for where single-tenant-byoc sits relative to the other topologies and why the marketplace path lands there.
| What Azure Marketplace provides | What you still own |
|---------------------------------|--------------------|
| Kubernetes application offer UI into customer's AKS | The Helm chart logic and values files |
| Azure billing integration and MACC drawdown | Mothership provisioning and entitlement sync |
| ACR hosting for the packaged offer image | The container image (ghcr.io/buttrbase/buttrbase-backend-rust) |
| Marketplace listing search and discoverability | The support, SLA, and upgrade path |
2. Prerequisites
- An Azure subscription with billing enabled and the following services accessible: Azure Container Registry (ACR)*, **Azure Kubernetes Service**, *Azure Database for PostgreSQL (for the customer's Postgres instance).
azCLI authenticated:az login.- An AKS cluster (1.25+) and
kubectlconfigured against it. - Helm 3.12+.
- Marketplace listing — forward-looking]* A Microsoft Partner Center account enrolled in the *Commercial Marketplace program. Partner onboarding is the gating step — Microsoft reviews the publisher application before you can create or submit a listing. See [Microsoft's commercial marketplace documentation for the current enrollment process.
3. Create an Azure Container Registry
The application image must live in ACR so Azure's validation pipeline and AKS pull policy can reach it. If you already have an ACR instance, skip the creation step.
az acr create \
--resource-group YOUR_RESOURCE_GROUP \
--name YOUR_ACR_NAME \
--sku Basic
Authenticate Docker to the registry:
az acr login --name YOUR_ACR_NAME
Replace YOUR_RESOURCE_GROUP and YOUR_ACR_NAME throughout. The login step sets up the Docker credential helper for YOUR_ACR_NAME.azurecr.io.
4. Push the application image to ACR
The chart's default image is ghcr.io/buttrbase/buttrbase-backend-rust. The Marketplace offer must reference an ACR URI. Tag and push a pinned release — never list latest on a marketplace:
Pull the image you want to list (pin a real tag)
docker pull ghcr.io/buttrbase/buttrbase-backend-rust:0.1.0Tag for ACR
docker tag \
ghcr.io/buttrbase/buttrbase-backend-rust:0.1.0 \
YOUR_ACR_NAME.azurecr.io/buttrbase/buttrbase-backend-rust:0.1.0Push
docker push YOUR_ACR_NAME.azurecr.io/buttrbase/buttrbase-backend-rust:0.1.0
After this step the image is accessible to AKS clusters that grant pull access to your ACR, and to Azure's offer validation scanner.
5. Package the chart as an Azure Kubernetes application offer
[Marketplace listing — forward-looking]
Azure Marketplace Kubernetes application offers (also called Container offers with an AKS deployment plan) require a packaging bundle on top of the raw Helm chart. The bundle is a .zip archive you upload via Partner Center:
| Bundle artifact | Purpose |
|-----------------|---------|
| Chart.yaml | Standard Helm chart descriptor — already present in deploy/helm/buttrbase-backend-rust/. |
| values.yaml + overlay files | The topology values files from the chart (values-single-tenant-byoc.yaml drives the customer install plan). |
| createUiDefinition.json | Defines the Azure Portal configuration form the customer fills in: cluster selector, Postgres connection string, storage account, tenant slug, region. Maps form fields to Helm values. |
| mainTemplate.json | An ARM template (or Bicep transpiled to ARM) that wraps the Kubernetes application object. Azure's deployment engine processes this to track the install lifecycle in the customer's subscription. |
The chart at deploy/helm/buttrbase-backend-rust/ slots in as-is. The customer-facing configuration form (createUiDefinition.json) will inject their inputs — Postgres URL, storage account name, tenant slug, region — as values matching the shape of values-single-tenant-byoc.yaml. The secrets (database-url, secret-key, encryption-key) are passed through secure fields in the form and materialized as a Kubernetes Secret in the customer's cluster — the same three keys the chart reads.
Canonical authoring references for createUiDefinition.json and the ARM wrapper are in Microsoft's documentation for creating a Kubernetes application offer.
6. Submit the listing
[Marketplace listing — forward-looking]
Submission happens entirely in the Partner Center web UI at partner.microsoft.com. The steps are:
1. In Partner Center, go to Marketplace offers* and create a new **Azure Container** offer (choose the *Kubernetes application plan type for AKS).
2. Fill in the offer metadata: name, description, categories, support contacts, and legal terms.
3. Configure pricing: Azure Marketplace supports free, flat-rate, per-core, and usage-based billing models. Choose the model that matches how ButtrBase sells the BYOC tier.
4. Under the plan's Technical configuration, upload the chart bundle (the .zip from step 5) and provide the ACR image URI for the application container.
5. Supply the createUiDefinition.json so the Marketplace portal can render the customer configuration form.
6. Trigger Partner Center's automated validation. The validator checks that the bundle is well-formed, the images are pullable from ACR, and the Kubernetes application installs successfully against a test cluster.
7. Submit for Microsoft's review. First-submission review timelines vary; plan for several business days.
Do not attempt to drive these steps from the az CLI — the Partner Center commercial-marketplace workflow is portal-native. There is no stable az marketplace offer ... subcommand surface for publisher-side operations.
7. Customer install experience
Once the listing is live, a customer's path is:
1. Find ButtrBase* in the Azure Marketplace and click *Get It Now.
2. Select the Azure subscription and resource group to deploy into (their own subscription).
3. Fill in the configuration form from createUiDefinition.json: AKS cluster, Postgres connection string (typically Azure Database for PostgreSQL private endpoint), storage account, tenant slug, region.
4. Click Create. Azure's deployment engine applies the ARM wrapper and invokes helm upgrade --install with the customer-supplied values against their AKS cluster.
5. The Portal shows the deployment as Succeeded once the Kubernetes application reports healthy.
The customer never sees a Helm command. Underneath, Azure is running the same chart as 07, with topology values matching values-single-tenant-byoc.yaml.
8. Direct AKS install (without the Marketplace UI)
For operators who need to deploy into a customer's AKS cluster directly — without going through the Marketplace listing — the flow is the same as tutorial 07, but targeted at the customer's cluster. Fetch AKS credentials:
az aks get-credentials \
--resource-group CUSTOMER_RESOURCE_GROUP \
--name CUSTOMER_AKS_CLUSTER \
--overwrite-existing
Then create the namespace, the Secret, and run the Helm install exactly as in tutorial 07:
kubectl create namespace buttrbasekubectl -n buttrbase create secret generic buttrbase-backend-rust \
--from-literal=database-url='postgres://buttrbase:…@customer-pg.postgres.database.azure.com:5432/buttrbase' \
--from-literal=secret-key="$(openssl rand -hex 32)" \
--from-literal=encryption-key="$(openssl rand -hex 32)"
helm upgrade --install buttrbase ./deploy/helm/buttrbase-backend-rust \
-n buttrbase \
-f ./deploy/helm/buttrbase-backend-rust/values-single-tenant-byoc.yaml \
--set app.image.tag=0.1.0
This is the direct operator path — useful for BYOC deployments while the Marketplace listing is still in review, or for customers who prefer to drive the install themselves.
9. Verify the install
Verification is identical to tutorial 07 — the chart is the same chart. Once the deployment is running (whether installed via the Marketplace UI or directly), check readiness and probe the health endpoint:
kubectl -n buttrbase rollout status deploy/buttrbase --timeout=120s
kubectl -n buttrbase port-forward svc/buttrbase 4300:4300 &
curl -fsS http://localhost:4300/health && echo " ✓ healthy"
Confirm the topology round-tripped:
kubectl -n buttrbase exec deploy/buttrbase -- printenv BUTTRBASE_RUST_DEPLOYMENT_MODE
→ single-tenant-byoc
If the pod is not ready, read the logs — the two dominant first-install failures are a database-url the pod's network cannot reach (the AKS node can't hit the Postgres private endpoint) and an encryption-key that is not 32 bytes hex. Both appear in the first ten log lines.
kubectl -n buttrbase logs deploy/buttrbase --tail=50
Done
You have the full Azure Marketplace packaging path: the image is in ACR, the chart is ready for the Kubernetes application bundle, and the customer-facing install flow maps cleanly to single-tenant-byoc. From here:
07-deploy-with-helm.md is the ground truth for chart behavior, values semantics, and secret layout.08-deploy-gcp-marketplace.md covers the same chart packaged as a GKE Marketplace Kubernetes app.09 covers the same chart packaged as an EKS Marketplace listing.