K3S: Deploying Applications

Writing and Managing YAML Manifests

Ah, YAML—the universal language of Kubernetes and the source of many developer headaches. Forget JSON; this is how Kubernetes likes to communicate, and we just have to deal with it.

Understanding Kubernetes YAML Syntax

YAML in Kubernetes defines how resources should behave. Indentation matters. One extra space, and Kubernetes will pretend it has no idea what you’re talking about.

Components of a Basic YAML Manifest

  • apiVersion: Defines which API version to use. Get this wrong, and Kubernetes will mock you.
  • kind: The type of resource (Pod, Deployment, Service, etc.).
  • metadata: Names and labels—think of it as Kubernetes’ way of keeping things organized.
  • spec: The blueprint of your resource. Where the real magic happens.

Example: Creating a Simple Pod Definition

apiVersion: v1
kind: Pod
metadata:
  name: myapp
spec:
  containers:
    - name: myapp-container
      image: nginx

Apply it using:

kubectl apply -f myapp.yaml
kubectl get pods

Creating and Managing Deployments and ReplicaSets

Kubernetes gives us Deployments and ReplicaSets so we don’t have to manually keep Pods alive like some sort of server babysitter.

Creating a Deployment YAML File

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp-container
          image: nginx

Scaling Applications

kubectl scale deployment myapp-deployment --replicas=5

Rolling Updates and Rollbacks

kubectl rollout status deployment myapp-deployment
kubectl rollout undo deployment myapp-deployment

If your update breaks everything (which it inevitably will), roll it back with that last command. You’re welcome.

Managing Services (ClusterIP, NodePort, LoadBalancer)

Deployments are great, but they’re useless if nobody can access them. That’s where Services come in.

Exposing a Deployment Using a ClusterIP Service

apiVersion: v1
kind: Service
metadata:
  name: myapp-service
spec:
  selector:
    app: myapp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

Creating a NodePort Service for External Access

apiVersion: v1
kind: Service
metadata:
  name: myapp-nodeport
spec:
  type: NodePort
  selector:
    app: myapp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
      nodePort: 30007

Listing Services and Accessing an Application

kubectl get services
curl http://<node-ip>:30007

If this doesn’t work, check your firewall settings—or sacrifice a rubber chicken to the Kubernetes gods.

Configuring Ingress for HTTP Routing

You don’t want to expose everything with NodePort; that’s messy. Instead, let’s use Ingress to route traffic properly.

Deploying Traefik as an Ingress Controller

K3s comes with Traefik pre-installed, so you’re already ahead of the game.

Creating an Ingress Resource

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-ingress
spec:
  rules:
    - host: myapp.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: myapp-service
                port:
                  number: 80

Applying and Verifying Ingress

kubectl apply -f myapp-ingress.yaml
kubectl get ingress

Hands-On Exercise

Time to put all this knowledge to work:

  • Deploy a sample web application using Deployments and ReplicaSets.
  • Expose the application using a NodePort and ClusterIP Service.
  • Configure and test Ingress for HTTP routing in K3s.

Congratulations! You’ve just deployed a real application in K3s. Now go break it and debug it—because that’s the real Kubernetes experience. 🚀