Skip to content
Deployments

Deploy your first app on Kubernetes

Deployment · Updated Jun 2026

Coming from another cloud?

▸AWS·Amazon EKS Cluster

Amazon EKS Clusterhigh

  • EKS control plane fully AWS-managed, single-tenant, across 3 AZs with auto scale/replace; on Quake AI you run the control plane on Nova instances, provisioned through Magnum or self-managed with OpenTofu, and you operate it.
  • EKS regional API endpoint with SLA; Quake AI exposes the kube API via Neutron LB with floating IP.
  • EKS charges a per-hour cluster platform fee on top of the underlying compute; Quake AI charges only for underlying Nova/Neutron/Cinder resources with no K8s platform fee.
  • EKS managed nodes auto AMI updates, Spot integration; Quake AI self-managed nodes require manual OS image selection and update management.
AWS docs ↗
▸Azure·AKS Cluster

AKS Clusterhigh

  • Azure automatically provisions and manages the control plane at no additional cost (Free tier) or fixed fee (Standard tier with SLA), offloading health monitoring and upgrades; on Quake AI you provision a cluster through Magnum (openstack coe cluster create) or self-managed Kubernetes on Nova instances (OpenTofu plus kubeadm, k3s, or RKE2), and you operate the cluster after creation.
  • No OpenStack integration; uses Azure Resource Manager for cluster lifecycle.
  • Pre-configured with Azure-specific defaults and add-ons like application routing.
  • Managed via Azure Virtual Machine Scale Sets (VMSS) with auto-scaling and upgrades; Quake AI uses Nova instances provisioned via OpenTofu with user-managed scaling and upgrades.
Azure docs ↗
▸DigitalOcean·Doks

This Quake AI feature maps to DigitalOcean’s Doks.

▸Google Cloud·GKE Cluster

GKE Clusterhigh

  • GKE provides Autopilot mode with fully managed node provisioning and scaling by Google; on Quake AI you provision clusters through Magnum or self-managed Kubernetes on Nova instances and manage node scaling yourself.
  • Control plane is fully managed with automatic upgrades through release channels; Quake AI requires user-provisioned and user-managed control plane nodes.
  • Cluster creation uses gcloud CLI vs OpenStack CLI (openstack coe cluster create).
  • Custom machine types, spot VMs, accelerators in node pools; Quake AI K8s nodes use standard Nova flavors.
Google Cloud docs ↗

Deploy your first app on Kubernetes

Stand up a Magnum Kubernetes cluster on Quake AI and deploy an Nginx app reachable from the public internet through a LoadBalancer service. The Kubernetes service (OpenStack Magnum) provisions the control plane, worker nodes, and cluster networking; you drive the cluster with kubectl once it reaches CREATE_COMPLETE.

Monthly cost estimate

Pricing calculator ↗

Sized as a custom package on a mix of shared and dedicated vCPU.

Starting template$238.80/mo

Monthly total for the required template above. Use the configurator below to add optional pieces and see the total update.

What each resource is for

Control plane

m2a.xlarge · 4 dedicated vCPU, 16 GiB RAM, 1 Gbps

$132.00/mo

3× Worker node

s1a.medium · 4 shared vCPU, 4 GiB RAM, 0.5 Gbps

$99.00/mo

Compute shown per role at custom-package rates ($29/dedicated vCPU, $7.25/shared vCPU, $1/GiB RAM). The headline above is the billed total: the cheaper of a named plan and the custom package, plus add-ons.

Included in baseline

m2a.xlarge

4 dedicated vCPU, 16 GiB RAM, 1 Gbps

$132.00

s1a.medium

4 shared vCPU, 4 GiB RAM, 0.5 Gbps

$33.00

s1a.medium

4 shared vCPU, 4 GiB RAM, 0.5 Gbps

$33.00

s1a.medium

4 shared vCPU, 4 GiB RAM, 0.5 Gbps

$33.00

Compute + RAM rate basis

16 vCPU + 28 GiB RAM at $29/dedicated vCPU, $7.25/shared vCPU, $1/GiB RAM (regular). Totals apply the flat −$5/mo package promotion.

—

Block storage (160 GiB)

160 GiB at $0.08/GiB/mo

$12.80

Public IP (included)

1 included with the custom package

$0.00

Package promotional discount

Flat −$5.00/mo on the custom package (same promotion as named plans).

$-5.00

Included at no charge

These line items are zero on Quake AI. Many other providers meter them separately.

Data transfer (inbound and outbound)

Unlimited data transfer on every plan; Quake AI does not meter per-GB egress.

AWS, GCP, and Azure meter outbound transfer per GB. DigitalOcean and Hetzner include an allowance on compute plans, then charge overage.

Learn more
$0.00

Private networking

Private networks, subnets, Neutron routers, and security groups are included with the plan.

VPC objects are usually free to create elsewhere, but NAT gateways bill hourly plus per-GB processed. Quake AI uses router SNAT with no separate NAT line item.

$0.00

Control-plane API requests

OpenStack API calls for provisioning and management are included.

Some managed services on other clouds meter API calls or charge for premium control-plane features.

$0.00

Kubernetes control plane

Magnum clusters run on Nova instances; there is no separate K8s platform fee in Quake AI pricing.

Managed Kubernetes on AWS, GCP, and Azure charges a control-plane fee on top of worker nodes.

Learn more
$0.00

Dev/test vs production

Start on shared CPU for dev/test, then promote to dedicated for production with a flavor resize. The network, storage, and template stay the same.

Dev/test on shared CPU

Burstable s1a flavors; suited to prototyping and low or bursty load.

$139.80/mo

Production on the configured CPU

The headline estimate above; predictable steady-load performance.

$238.80/mo

Saves $99.00/mo while you build on shared CPU.

Shared flavors carry less RAM (m2a.xlarge (16 GiB RAM) -> s1a.medium (4 GiB RAM)). A resize reboots the instance; data on attached volumes persists. Size the dedicated flavor for the RAM your production workload needs.

Pricing data last validated: . For current rates, check quake.ai/pricing.

Your laptopPublic IP203.0.113.xQuake AI projectKubernetes clusterMaster nodecontrol planeWorker nodeServicetype LoadBalancerNginx pods HTTP 80
Click to zoom
Kubernetes cluster with a LoadBalancer service: traffic from the internet reaches Nginx pods through the service's public IP

Prerequisites#

You need:

  • A Quake AI account with a Developer tier project
  • An SSH key pair uploaded to your account

Use the Console to create the cluster and download credentials; use your local terminal for kubectl steps.

Step 1: Confirm you have a cluster template#

A cluster template defines the Kubernetes version, the network driver, and the default node flavors that the cluster inherits. You select a template when you create the cluster.

  1. In the Console, go to Kubernetes > Cluster Templates.
  2. Look for a platform-provided template in the list. Platform templates include the Kubernetes version in the name, for example Standard-v2.0-k8s-calico-fc38_v1.24.16.

If the list is empty, create a template before continuing: follow How to create a cluster template, then come back to Step 2. That guide also documents the labels a template needs (including boot_volume_size, which Quake AI requires because every flavor family ships with a zero-size root disk).

Step 2: Create the cluster#

Create a one-master, one-worker cluster from the template. The Console renders the Create Cluster wizard as five numbered steps.

  1. Go to Kubernetes > Clusters and select Create Cluster.
  2. Step 1: Cluster Info. Set Cluster Name to tutorial-k8s. Under Cluster Template, select the platform template you found in Step 1. Select Next: Node Spec.
  3. Step 2: Node Spec. Select your SSH Keypair. Leave Number of Master Nodes at 1 and Number of Nodes at 1 for this walkthrough. Pick master and worker flavors from the families listed in the dropdown (for example, m2a.xlarge for the master and m2a.large for the worker). Available families vary by project; choose any flavor that fits your quota. Select Next: Network Setting.
  4. Step 3: Network Setting. Under Enable Load Balancer, check Enabled Load Balancer for Master Nodes so the cluster API gets a load balancer. Under Enabled Network, leave Create New Network checked so the wizard provisions a dedicated cluster network. Select Next: Management.
  5. Step 4: Management. Leave the defaults. Select Next: Additional Labels.
  6. Step 5: Additional Labels. Confirm the template carries boot_volume_size=40. If the label is missing, add it with + Add Label (key boot_volume_size, value 40). Without it, the cluster fails within about a minute because the flavors have a zero-size root disk.
  7. Select Confirm.

The cluster appears in the Clusters list with status CREATE_IN_PROGRESS. Provisioning a small cluster takes 5 to 15 minutes. Wait until the status reads CREATE_COMPLETE before continuing.

Step 3: Connect with kubectl#

Download the cluster's kubeconfig from the Console and point kubectl at it.

  1. Go to Kubernetes > Clusters.
  2. On the tutorial-k8s row, open the Settings gear icon and select Get kube.config. The browser downloads a plain-text YAML file immediately.
  3. Move the file to a known location and export it as KUBECONFIG in your terminal:
bash
export KUBECONFIG=/path/to/downloaded/kube.config
  1. Confirm kubectl reaches the cluster:
bash
kubectl get nodes

Expected output for a one-master, one-worker cluster:

NAME                                   STATUS   ROLES    AGE   VERSION
tutorial-k8s-<token>-master-0          Ready    master   9m    v1.24.16
tutorial-k8s-<token>-node-0            Ready    <none>   7m    v1.24.16

Both nodes show Ready. The Kubernetes service injects a random token into the node names to keep them unique across cluster re-creates, so your exact names differ.

Step 4: Deploy the app#

Define an Nginx Deployment and apply it with kubectl. Save the following manifest as app.yaml on your local machine:

YAML
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello-nginx
  template:
    metadata:
      labels:
        app: hello-nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.27
          ports:
            - containerPort: 80

Apply it:

bash
kubectl apply -f app.yaml

Expected output:

deployment.apps/hello-nginx created

Watch the pods until both reach Running:

bash
kubectl get pods

Expected output:

NAME                           READY   STATUS    RESTARTS   AGE
hello-nginx-7c8b5d9f4b-5n2hq   1/1     Running   0          40s
hello-nginx-7c8b5d9f4b-pq7xz   1/1     Running   0          40s

The first run pulls the nginx:1.27 image, so the pods may sit in ContainerCreating for a few seconds before they reach Running.

Step 5: Expose the app to the internet#

A LoadBalancer service tells the cluster to publish the selected pods through a public IP. Add the service to app.yaml below the Deployment, separated by a --- document break:

YAML
---
apiVersion: v1
kind: Service
metadata:
  name: hello-nginx
spec:
  type: LoadBalancer
  selector:
    app: hello-nginx
  ports:
    - port: 80
      targetPort: 80

Apply the file again. kubectl creates the service and leaves the Deployment unchanged:

bash
kubectl apply -f app.yaml

Expected output:

deployment.apps/hello-nginx unchanged
service/hello-nginx created

Watch the service until the EXTERNAL-IP column changes from <pending> to an address:

bash
kubectl get service hello-nginx --watch

Expected output once the public service finishes provisioning:

NAME          TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
hello-nginx   LoadBalancer   10.254.12.118   203.0.113.42    80:31840/TCP   2m

The address in EXTERNAL-IP is the public IP the cluster allocated for the service. Provisioning the service and assigning the IP takes 2 to 4 minutes. Press Ctrl+C to stop watching once the IP appears.

Step 6: Reach the app#

Send a request to the public IP from your local machine. Replace 203.0.113.42 with the EXTERNAL-IP from Step 5:

bash
curl http://203.0.113.42

Expected output (the start of the default Nginx welcome page):

HTML
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>

The request travels from your machine to the service's public IP and then to one of the two Nginx pods on the worker node.

Next steps#

Clean up#

To stop using project resources, delete the app and the cluster.

  1. Delete the app. Remove the Deployment and the LoadBalancer service, which releases its public IP:
bash
kubectl delete -f app.yaml
  1. Delete the cluster. Go to Kubernetes > Clusters, open the Settings gear icon on the tutorial-k8s row, and select Delete. Confirm in the dialog. Read the cluster name in the dialog body first; the Console deletes on a single confirmation without asking you to type the name.

Deleting the cluster removes its VMs, network, router, and cluster networking resources. The cluster leaves the list once deletion finishes.

Quick answers

Was this page helpful?