Deploying a single monolithic application to Kubernetes might seem like overkill, but it’s a fantastic way to get a feel for the platform’s power and how it manages even the simplest workloads.

Let’s get this monolith, "MyAwesomeMonolith," running. We’ll use a basic Nginx image as our stand-in.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-awesome-monolith-deployment
  labels:
    app: my-awesome-monolith
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-awesome-monolith
  template:
    metadata:
      labels:
        app: my-awesome-monolith
    spec:
      containers:
      - name: monolith-container
        image: nginx:1.25.3
        ports:
        - containerPort: 80

This Deployment tells Kubernetes: "I want 3 copies (replicas) of my application running, and they should all be based on the nginx:1.25.3 image. Each container will listen on port 80." Kubernetes will then ensure that 3 pods matching this description are always running. If a pod dies, Kubernetes automatically starts a new one.

Now, how do we actually talk to our monolith? We need a Service.

apiVersion: v1
kind: Service
metadata:
  name: my-awesome-monolith-service
spec:
  selector:
    app: my-awesome-monolith
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: LoadBalancer

This Service acts as a stable network endpoint for our pods. The selector app: my-awesome-monolith ensures it only directs traffic to pods with that label. port: 80 is the port the service will expose, and targetPort: 80 is the port on the pods that traffic will be sent to. The type: LoadBalancer is crucial here; it tells Kubernetes to provision an external load balancer (provided by your cloud provider or a local tool like MetalLB) that will give your monolith a public IP address.

Apply these:

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

After a minute or two, check the service:

kubectl get service my-awesome-monolith-service

You should see an EXTERNAL-IP listed. Hit that IP in your browser, and you’ll see the default Nginx welcome page. Congratulations, your monolith is now running on Kubernetes and accessible externally!

The real magic happens when you scale. Want 10 replicas? Just kubectl scale deployment my-awesome-monolith-deployment --replicas=10. Kubernetes handles the rest, ensuring all 10 pods are up and running and distributing traffic across them via the service.

The Deployment object is the workhorse for managing stateless applications. It defines the desired state for your pods (how many, what image, what configuration) and continuously works to maintain that state. It also handles rolling updates and rollbacks gracefully.

The Service object, on the other hand, provides a persistent, abstract network layer. It decouples your application’s consumers from the dynamic lifecycle of individual pods. Pods can come and go, get rescheduled, or be replaced, but the Service’s IP address and port remain constant, always routing traffic to healthy instances.

If you were to update the Nginx image to nginx:1.26.0, you’d edit your deployment.yaml, change the image field, and run kubectl apply -f deployment.yaml again. Kubernetes would perform a rolling update, gradually replacing old pods with new ones running the updated image, minimizing downtime.

What most people don’t realize is how deeply the Service abstracts away the underlying network. It’s not just a load balancer; it’s a DNS entry within the cluster (e.g., my-awesome-monolith-service.your-namespace.svc.cluster.local) and an IP address that other pods inside the cluster can reliably use to communicate with your monolith, regardless of which specific pod instance they’re talking to.

The next natural step is to explore how to configure your monolith, perhaps by mounting configuration files into the pods.

Want structured learning?

Take the full Monolith course →