Deploying a Stateless Application to k3s with Manifests
Take a container image and turn it into a running workload on k3s using Deployment and Service manifests, then verify it end to end.
Netbay Infrastructure Team
Netbay Engineering
On this page
Once your k3s cluster is up, the first real task is moving a container from "I have an image" to "a running, reachable workload." For a stateless app this is refreshingly simple: a Deployment describes the desired pods, a Service exposes them, and you apply two small YAML files. This walkthrough deploys an nginx webserver, but the pattern is identical for any stateless service — an API, a frontend, or a worker process.
Stateless means the app keeps no required local state; its pods can be deleted, recreated, and scaled freely. That is what makes the Deployment abstraction so clean here.
The Deployment manifest
Declare the desired state: three replicas of an nginx image, with a label the Service can match.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 80
resources:
requests:
cpu: 100m
memory: 64MiThe Service manifest
A ClusterIP Service gives the pods a stable name and balances traffic across all replicas.
apiVersion: v1
kind: Service
metadata:
name: web
spec:
selector:
app: web
ports:
- port: 80
targetPort: 80Applying and verifying
Now apply both files and inspect the result. Everything here uses the standard kubectl workflow.
kubectl apply -f deploy.yaml -f service.yaml
kubectl get pods -o wide
kubectl get svc web
kubectl rollout status deployment/webWhen the Deployment reaches the Ready state, you should see three running pods and a Service with three endpoints.
The request path
Once the Service exists, traffic flows through it to whichever pods match its selector.
Exposing it outside the cluster
ClusterIP is only reachable inside the cluster. For quick external testing on a single node, you can use a NodePort Service, which exposes the app on a high port of every node.
apiVersion: v1
kind: Service
metadata:
name: web-nodeport
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 80
nodePort: 30080Then reach it at http://NODE_IP:30080. In later posts we will replace NodePort with a proper Ingress, but this is the fastest way to confirm the deployment works.
Takeaway
Deploying a stateless app is two manifests plus apply: a Deployment for the pods and a Service for routing. Because the app holds no state, scaling and replacing pods is trivial and safe. To practice hands-on, spin up a Linux VPS on Netbay, install k3s, and run through this exact workflow — netbayhosts.in.
Keep reading
Follow along on a real VPS
Deploy Linux in under 60 seconds
These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.
Deploy an instance