Skip to main content
With the infrastructure and platform components in place, deploy a workspace. Run this part once per workspace, in order: namespace → TLS → service accounts and RBAC → NamespaceConfig → NVMe init (optional) → QueryRouter → AccessToken (optional) → DNS.

Step 0: Set workspace variables

These commands re-derive the Part 1 values, so this works in a fresh shell. Set PREFIX, RESOURCE_GROUP, and WORKSPACE_NAME to the same values you used in Part 1.
NAMESPACE must stay equal to WORKSPACE_NAME - the federated identity credentials from Part 1 Step 8 are bound to service accounts in exactly that namespace. If you change it, Workload Identity authentication fails.

Step 1: Create the namespace

Step 2: Create the TLS certificate

The workspace endpoint is served over HTTPS by Envoy, which terminates TLS in-cluster using a Kubernetes secret named envoy-tls. Unlike AWS - where the NLB can terminate TLS with an ACM cert - the Azure load balancer is L4 and passes through, so the certificate always lives in the cluster. Every option below produces the same envoy-tls secret covering ${CONSOLE_HOSTNAME}. Choose one.

Option A: e6data-provided wildcard certificate

If your workspace endpoint is on an e6data domain (for example *.e6.run), e6data provides a CA-signed wildcard certificate. Load it into the secret:

Option B: Customer-procured certificate

A certificate from your own CA (DigiCert, Namecheap, Sectigo, or a corporate CA). Works with any domain. Make sure fullchain.pem includes the full chain (leaf plus intermediates):
If your certificate is stored in Azure Key Vault, download it first, split it into tls.crt and tls.key, then create the secret the same way.

Option C: Let’s Encrypt via cert-manager

cert-manager obtains and auto-renews a free Let’s Encrypt certificate using a DNS01 challenge through Azure DNS. This requires the letsencrypt-prod ClusterIssuer (a public domain in an Azure DNS zone you control, plus a cert-manager identity with DNS Zone Contributor):

Option D: Azure Key Vault + Secrets Store CSI

The closest Azure analog to AWS ACM: Key Vault owns and auto-rotates the certificate, and the Secrets Store CSI driver syncs it into the cluster as the envoy-tls secret. Best for teams already standardized on Key Vault for certificate lifecycle. Enable the azure-keyvault-secrets-provider addon, then create a SecretProviderClass that targets your certificate and sets secretObjects to sync a kubernetes.io/tls secret named envoy-tls. The exact SecretProviderClass is environment-specific - ask your e6data onboarding engineer for a template.

Step 3: Create service accounts and RBAC

Create the core service accounts (engine, monitoring, console, query-router) - each annotated with the Workload Identity client ID from Part 1 - plus their Roles and Bindings. Save as rbac.yaml and apply with envsubst < rbac.yaml | kubectl apply -f -.
This creates the core service accounts. When you enable add-ons (Laminar, Copilot, Metriq), add their service accounts (and Laminar’s Role) here, and add a federated credential for each against the workspace identity (Part 1 Step 8).

Step 4: Apply the NamespaceConfig

The NamespaceConfig is the workspace’s root custom resource. Once applied, the e6-operator creates the console, the compaction job, and (on demand) the MetadataServices:
storageBackend uses the wasbs://<container>@<account>.dfs.core.windows.net URI from Part 1 Step 7. The serviceAccounts block lists the core components; add laminar, copilot, and metriq keys when you enable those add-ons.

Step 5: Engine NodeClass and NodePool

Already created in Part 1 Step 6C.5 (Karpenter). If you chose a static pool or NAP instead, make sure its nodes carry the label and taint workspace-name=${WORKSPACE_NAME} so the NamespaceConfig’s nodeSelector and tolerations match.

Step 6: NVMe init DaemonSet (only for NVMe VM families)

If your engine NodePool includes the L family (Lsv3/Lasv3, local NVMe), this DaemonSet formats and RAIDs the NVMe drives and mounts them at /app/tmp:

Step 7: Deploy the QueryRouter

The QueryRouter deploys Envoy (data path, TLS termination, JWT enforcement) and the xDS control plane. The external load balancer is L4, so JWT auth in the QueryRouter is required - Envoy authenticates every request. The merged-single-port mode fronts gRPC, HTTP, and PostgreSQL on port 443 behind one load balancer.
Public by default. With no azure-load-balancer-internal annotation, Azure gives the load balancer a public IP (JWT auth still protects every request). Point your DNS A-record at that public IP.To instead restrict it to a private endpoint reachable only inside your VNet, add service.beta.kubernetes.io/azure-load-balancer-internal: "true" to mergedService.annotations, and reach it through the VNet (jumpbox, VPN, or peering). The DNS record then points at the private IP.

Step 8: Create an AccessToken (optional)

Static tokens for HTTP/JDBC query authentication:

Step 9: Configure DNS

Point the workspace hostname at the load balancer’s IP address:
Use the EXTERNAL-IP (.status.loadBalancer.ingress[0].ip), not the ClusterIP. With the public default this is a real public address - not a 172.20.x (cluster-internal ClusterIP). A 10.x private VNet IP appears only if you kept the load balancer internal.
For a private/internal load balancer, put the A-record in a Private DNS zone (or an internal resolver), since a public record pointing at a 10.x address only resolves usefully from inside the VNet.

Verify the deployment

Expected pods once active: console-*, ${WORKSPACE_NAME}-qr-envoy-*, ${WORKSPACE_NAME}-qr-xds-*, and mds-schema-* / mds-storage-* (after the first MetadataServices is created). Metadata pods may take 1–2 minutes to appear.

Next

If something doesn’t come up cleanly, see Troubleshooting.
Last modified on September 29, 2026