With a healthy cluster confirmed, deploy a sample application to it and open it in your browser through a Hetzner Load Balancer. Most of the wait is the load balancer coming up. ## Prerequisites - A healthy workload cluster with `KUBECONFIG` still pointed at it. Complete [Explore your cluster](/docs/hetzner/apalla/getting-started/explore-your-cluster) to confirm it is ready. ## Deploy the application You create two Kubernetes objects. A **Deployment** keeps a set of identical pods running and replaces any that fail. A **Service** gives those pods one stable address; with `type: LoadBalancer`, that address is a public IP on a Hetzner Load Balancer. Create a file named `app.yaml`: ```yaml # app.yaml apiVersion: apps/v1 kind: Deployment metadata: name: hello spec: replicas: 2 selector: matchLabels: app: hello template: metadata: labels: app: hello spec: containers: - name: hello image: nginx:stable-alpine ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: hello spec: type: LoadBalancer selector: app: hello ports: - port: 80 targetPort: 80 ``` Apply it: ```console $ kubectl apply -f app.yaml deployment.apps/hello created service/hello created ``` Both pods start within a few seconds. Confirm they are running: ```console $ kubectl get pods -l app=hello NAME READY STATUS RESTARTS AGE hello-6d4b9c8f7d-8kx2p 1/1 Running 0 20s hello-6d4b9c8f7d-v5qtm 1/1 Running 0 20s ``` Both pods show `1/1 Running`. The random suffixes in your pod names differ. ## Watch the load balancer appear A Service with `type: LoadBalancer` tells Syself Autopilot to create a Hetzner Load Balancer in the Hetzner Cloud project that holds your cluster. This takes about a minute. Once it exists, every request follows the same path: ```mermaid flowchart LR I["Internet
the external IP"] --> LB["Hetzner Load Balancer"] --> S["Service
hello"] --> P["Pods
your app replicas"] ``` Watch the Service until an external IP appears: ```console $ kubectl get service hello --watch NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE hello LoadBalancer 100.96.45.12 80:31820/TCP 15s hello LoadBalancer 100.96.45.12 167.235.10.20 80:31820/TCP 70s ``` When the `EXTERNAL-IP` column changes from `` to an IP address, the load balancer is ready. Press to stop watching. Your IP and ports differ from the example. You can also see the new load balancer in the [Hetzner Cloud Console](https://console.hetzner.cloud/) under **Load Balancers**. ## Access the application Open `http://` in your browser, or test it with curl: ```console $ curl http:// ``` You should see the nginx welcome page, an HTML response starting with `Welcome to nginx!`. Your app is live on the internet. Both pods serve traffic through the same load balancer, so if one fails, the other keeps answering. ## Clean up Delete the Deployment and Service when you are done: ```console $ kubectl delete -f app.yaml deployment.apps "hello" deleted service "hello" deleted ``` The Hetzner Load Balancer is deleted automatically when the Service is removed, so it stops billing right away. ## Beyond a single load balancer This example uses a plain LoadBalancer Service, one load balancer per application. For production workloads you typically want: - An **ingress controller**. This is a component that routes requests for several applications through one load balancer, based on the hostname or URL path. Syself Autopilot does not include a built-in ingress controller; choose one that fits your needs. - **TLS termination** at the ingress level. See [Expose an application](/docs/hetzner/apalla/network/expose/choose-how-to-expose) for a complete guide covering ingress and TLS options. ## Get the most out of Syself You now have a running cluster and a working deploy loop. That is the demo. The platform's depth shows up in what comes next: - **Run a production-ready workload.** Syself Autopilot drains and replaces nodes during upgrades and self-healing. A bare Deployment like the one above takes a traffic hit on every such event. [Run a production-ready workload](/docs/hetzner/apalla/workloads/production/run-a-production-ready-workload) adds the probes, disruption budgets, and resource requests that keep an app serving through all of it. - **Harden your workloads.** The node this app ran on is hardened by default. The pod you deployed is not. [Next steps](/docs/hetzner/apalla/getting-started/next-steps) covers the security checklist to work through before production. - **Set up observability.** Every component in the cluster exports Prometheus metrics, but nothing collects them yet. [Set up Prometheus and Grafana](/docs/hetzner/apalla/observability/metrics/set-up-prometheus) turns them into dashboards and alerts. - **Bring in your team.** So far you have used a single kubeconfig file. [Configure OIDC](/docs/hetzner/apalla/clusters/configure/configure-oidc) connects your identity provider so teammates log in with short-lived tokens instead of shared credentials. > [!TIP] > GitOps is a natural next step. You can keep every manifest in a Git repository and use Argo CD or Flux to apply changes automatically. See [GitOps with Argo CD](/docs/hetzner/apalla/clusters/gitops/set-up-argo-cd). ## Next step You have a running app and a working deploy loop. Continue with [Next steps](/docs/hetzner/apalla/getting-started/next-steps) to see where to go from here: understanding the platform, upgrades, security, and running real services. ## Related - [Next steps](/docs/hetzner/apalla/getting-started/next-steps) - [How to: expose an application](/docs/hetzner/apalla/network/expose/choose-how-to-expose) - [How to: configure a load balancer](/docs/hetzner/apalla/network/load-balancing/configure-a-load-balancer) - [How to: GitOps with Argo CD](/docs/hetzner/apalla/clusters/gitops/set-up-argo-cd) - [Explore your cluster](/docs/hetzner/apalla/getting-started/explore-your-cluster)