Skip to main content
In this tutorial you’ll deploy the Example Voting App onto a Kubernetes cluster. We’ll create Pod manifests for each service, then add Services so the components can communicate and the UIs can be accessed from your browser. Prerequisites:
  • A running Kubernetes cluster (minikube, kind, or a cloud cluster)
  • kubectl configured to talk to your cluster
  • A directory containing the YAML manifests you’ll create
Start by creating a working folder and the individual YAML files described below.
A dark-themed Visual Studio Code window with the Explorer sidebar open showing a folder named "voting-apps-demo" and a file being created called "voting-app". The main area shows the large VS Code logo and quick command hints in the center.

1. Pod manifests

Pod manifests share the same top-level structure: apiVersion, kind, metadata (including name and labels), and spec (which defines containers). Create one YAML file per component:
  • voting-app-pod.yaml — voting UI
  • result-app-pod.yaml — results UI
  • redis-pod.yaml — Redis data store
  • db-pod.yaml — Postgres database
  • worker-pod.yaml — background worker
Below are the Pod manifests to create. Save each into its respective filename. voting UI (voting-app-pod.yaml):
results UI (result-app-pod.yaml):
Redis (redis-pod.yaml):
Postgres (db-pod.yaml):
For Postgres, POSTGRES_USER and POSTGRES_PASSWORD initialize the default database user. In production, supply secrets using Kubernetes Secrets rather than plain env values.
Worker (worker-pod.yaml) — the worker only needs to run and communicate internally, so no ports are required:

Quick manifest summary

2. Service manifests

To enable network communication between components and to expose UIs, create Services for Redis, Postgres (db), vote, and result.
  • Use ClusterIP for internal services (Redis and Postgres).
  • Use NodePort for the vote and result UIs so you can open them in a browser for this demo.
Redis Service (redis-service.yaml):
Postgres Service (db-service.yaml):
Vote UI Service (vote-service.yaml) — NodePort exposes the UI externally on node port 31000, mapping the Service port 8080 to container port 80:
Result UI Service (result-service.yaml) — exposed on node port 31001 mapping Service port 8081 to container port 80:

Service summary

NodePort exposes ports on each cluster node and is suitable for demos. For production, consider using Ingress, a LoadBalancer Service, or a cloud LB rather than NodePort.

3. Apply manifests to the cluster

From the directory containing all YAML files, apply them in one command:
You should see resource creation messages similar to:

4. Verify Pods and Services

Check that Pods are running:
Expected output (example):
List Services to confirm types and port mappings:
Example output:
The NodePort mapping is shown as <service-port>:<nodePort>/TCP, for example 8080:31000/TCP.

5. Access the UIs

Find a node IP to access NodePort services:
Use the node’s INTERNAL-IP and the nodePort to open the UIs in your browser. For example, if the node’s IP is 192.168.97.2: Open the Vote UI, cast a vote (for example, select Cats), then open the Result UI to confirm the service mesh and database updates. You should see the updated poll results (example below).
A simple blue screen showing a small centered poll results box that reads "CATS 100.0%" and "DOGS 0.0%." A browser window frame is visible around the screen and "1 vote" is shown in the bottom-right.

Conclusion

You have completed an end-to-end deployment of the Example Voting App on Kubernetes:
  • Pods for each component (vote, result, redis, db, worker)
  • ClusterIP Services for internal-only components (Redis, Postgres)
  • NodePort Services to expose vote and result UIs for demonstration
For production deployments, replace Pod manifests with Deployments (for replica management), move secrets into Secret objects, and use Ingress or LoadBalancer Services to expose public endpoints.

Watch Video