☸️Kubernetes Concepts
The container
Before even presenting Kubernetes, it's better we start from the very basic: the container.
A container is a lightweight, semi-isolated environment that has everything it needs to run a specific process. While it shares the host machine’s Linux kernel, it operates with its own virtual filesystem, network stack, and user space.
This isolation is made possible by two key Linux kernel features:
Namespaces – These isolate resources like process trees, networking, and mount points between containers.
Cgroups – Short for “control groups,” these limit and monitor the amount of CPU, memory, and other system resources each container can use.

A well-known software that combine all of these features is Docker, a container runtime that builds, manages, and runs containers.
Declarative deployment using Docker Compose
Initially, deploying a container looked like this:
But there’s a catch: if you ever need to redeploy the container, you have to remember and rerun the exact same command. And unless it was written down somewhere, it could be lost or inconsistent between environments.
To address this, engineers started using Docker Compose. It wraps those docker commands into a single declarative YAML file: docker-compose.yaml, that you can commit to version control and reuse consistently.
This made container deployment more reproducible. But it didn’t solve everything.
While Docker Compose helps organize and deploy containers, it starts to show its limits in more complex or production-like scenarios:
Scaling is difficult:
You have to manually replicate containers.
Volumes are tightly bound to the host machine.
Load balancing has to be configured separately.
Upgrades are risky:
Replacing a container usually means stopping the running one first.
If the new container fails to start correctly, users experience downtime: healthy traffic is interrupted before the new instance is checked.
No automatic rollback if something goes wrong.
Single Points of Failure:
No native failover: Docker’s data (volumes, images) isn’t replicated.
No container redundancy or high availability.
Network and storage are tightly coupled to a single host.
In short, every layer of a Compose-based stack is a potential failure point. This led to serious challenges for our SaaS offering, and even more so for power users of our Self-Hosted deployments.
Introducing Kubernetes to solve availability
If Docker is the brain behind container deployment on a single machine, then Kubernetes is the brain coordinating deployment across many machines.

Kubernetes isn't very different from Docker and Docker Compose. In fact, Kubernetes is a superset of Docker and Docker Compose. It builds on their ideas but extends them to support scaling, resiliency, and high availability.
Instead of using docker-compose.yaml, Kubernetes introduces the concept of a Pod, which is defined in a YAML file:
Functionally speaking, a Pod offers the same capabilities to a Docker Compose deployment. But, because of the same design, it shares the same core limitations: no built-in replication, no safe upgrades, and no failover mechanisms.
To solve that, Kubernetes wraps Pods in another object: the Deployment.
Deployments immediatly offers:
Safe rollout strategies: Old Pods are only terminated once the new ones are confirmed healthy.
Replication: Easily scale up by running multiple instances (replicas) of the Pod, even across different machines.
But to handle traffic across those replicas, Kubernetes needs a way to distribute incoming connections. Since you can’t bind the same port on multiple containers on the same host, Kubernetes introduces the concept of a Service, which acts as a built-in Layer 4 (TCP/UDP) load balancer.
More precisely, Service simply serves traffic on healthy replicas of the Pod using known Linux technologies: iptables (the linux firewall) and veth (virtual ethernet device).
As you can see, Kubernetes doesn’t reinvent the wheel. It simply builds on top of proven, existing tools, wrapping them into a system that helps you scale out your containers reliably and safely.
And compared to full-blown virtualization platforms like OpenStack or Proxmox, Kubernetes is relatively lightweight and easier to adopt, while solving production-grade problems around upgrades, networking, and high availability.
So the question is: why does it feel harder to use Kubernetes than Docker Compose?
Well, there is actually a cognitive overhead. Kubernetes introduces a lot of concepts, but not all of them are essential to get started.

That’s a lot of YAML just to get a database running... even though all you really want is to set a few configuration values.
In Docker, this reduces to:
Introducing Helm
To reduce the cognitive overhead of managing raw Kubernetes YAML, we use Helm, a templating engine and package manager for Kubernetes.
Helm works by combining:
Template files that generate Kubernetes manifests behind the scenes.
A central
values.yamlfile that defines configurable defaults.An optional override mechanism, using either patched YAML or inline flags.

This abstraction allows you to deploy complex apps without drowning in dozens of YAML files. It also lets maintainers expose only the necessary knobs. No need to manually wire every port, label, or secret.
For example, to deploy PostgreSQL, you can simply run:
It's that simple! And if you want to customize the PostgreSQL password. Just create a values.yaml file:
Then apply it like this:
Or, if you're in a hurry:
Helm drastically reduces boilerplate and repetition. It gives us, at Toucan, a way to offer clear, focused customization instructions while still allowing you the freedom to tailor the deployment to your environment and needs.
Helm makes deploying and configuring Kubernetes applications much easier, and that’s exactly how we’ll deploy Toucan!
But before we do that, it’s worth taking a moment to get familiar with a few essential Kubernetes concepts: the stuff you’ll actually touch or maintain when running Toucan in production.
Exposing your workload with Kubernetes
One major difference between Docker and Kubernetes is how you expose your application to the outside world.
We've talked earlier about Service, the L4 load balancer used to keep track of the pods IPs and expose them to the Kubernetes internal network.
To expose to the external network, you have two solutions:
Open the
Serviceto the outside world by setting thetypetoLoadBalancer.Or place a reverse proxy in front of the
Service, in which its ownServiceis aLoadBalancer.
Most of the time, you'll use the second solution. But we'll talk about the first option as well to understand how the traffic is routed.
Exposing using a LoadBalancer
First of all, what is technically a Service of type LoadBalancer? How is Kubernetes able to accept external traffic? It has two things:
Using a external router, the external IP is announced to the world. Incoming traffic is routed directly on the Kubernetes nodes.
Using
iptables, Linux internal router, Kubernetes is able to redirect the incoming traffic from the network interface to the container IP.
It is very important to remember that a LoadBalancer doesn't work alone. In the cloud, a literal load balancer is deployed on top of the Kubernetes.
TODO: Add a diagram
And in bare-metal, most people use MetalLB to announce the IP to the external network with ARP, or route to the IP directly using BGP.
TODO: Add a diagram.
Exposing using an Ingress or HTTPRoute
We know that a LoadBalancer is the most common way to expose your application. The issue is that you might have multiple web applications, so can't afford to occupy the only available port.
The solution is to use a reverse proxy, which will be used as a L7 router, i.e, a router with knowledge of the HTTP protocol.
Common routing rules in a reverse proxy involve routing based on the hostname.
TODO: Add a diagram.
We define the actors as follows:
The routing rules are called
IngressorHTTPRoute.The reverse proxy is called an Ingress Controller (a contraction of Kubernetes Controller handling
Ingressresources), orGateway, which handlesHTTPRoute.
When deploying a Ingress Controller, or a Gateway, a new Service of type LoadBalancer is created. This is how applications are exposed.
In Kubernetes, you have two types of routing "protocol": the Ingress API and the Gateway API. The recommendation is to use the Gateway API.
About Ingress routing
The setup for Ingress is quite simple:
The infrastructure administrator deploys the Ingress Controller.
The ingress controller opens ports via the
Serviceof typeLoadBalancer.The ingress controller reads the
Ingressresources and routes the traffic accordingly. It can additionally handle TLS certificates.
It is that simple.
About Gateway routing
Due to complex scenarios, the Kubernetes team decided to give more power to Kubernetes about HTTP routing. The setup is now the following:
The infrastructure administrator deploys a "Gateway Class". It's just a common configuration. For example, this includes the pricing plan of the cloud load balancer, or the IP pool used when deploying a
Service.The Kubernetes cluster operator deploys a
Gateway, which describes the open ports (also known as "listeners"), the allowed protocols, and the allowed hostnames. TLS certificates are also configured here. By deploying aGateway, you are creating aServiceof typeLoadBalancer.The gateway reads the
HTTPRouteresources and routes the traffic accordingly. No certificates are handled by the HTTPRoute.
Other than the fact that Gateway can now be easily created on-demand, the main difference between the Ingress and the Gateway API is the separation of responsibility: application developpers that used to deploy Ingresses are now unable to handle TLS certificates. (This is a good thing, technically speaking. It's still possible to give this power back to the application using ListenerSet. But you shouldn't.)
Another difference is that HTTPRoute has many HTTP features, such as adding new headers.
What you actually need to know about Kubernetes
The Kubernetes' official documentation offers in-depth explanations of its architecture and components. However, a full understanding of Kubernetes internals is not required to self-host Toucan.
As with Docker Compose, it is not necessary to understand the underlying networking stack to deploy a working setup. What matters is knowing how to configure the relevant components.
Common Concepts
If you're comfortable with Docker Compose, you're already 90% of the way to understanding how to use a Kubernetes Pod. And, since we are abstracting the configuration with Helm, you shouldn't need to go too far in depth.
However, if you ever need to learn more, here are the common concepts:
Pod: Basic execution unit in Kubernetes. Represents one or more containers with shared storage and network. Equivalent to Docker Compose.
Deployment: Manages stateless Pods, including rolling updates and replica scaling.
StatefulSet: Manages stateful Pods with persistent identity and stable storage.
Service: Provides a stable network endpoint and load balances traffic to a set of Pods.
Persistent Volume (PV): Represents storage resources in the cluster. Usually provisioned dynamically, so you don't actually need to worry about it.
Persistent Volume Claim (PVC): A request for storage by a Pod; typically used to bind to a PV.
If you ever need help to visualize the deployment, feel free to check Headlamp. The postgres diagram from above is provided by Headlamp.
Maintenance Overview
Unless Kubernetes is installed manually using tools like kubeadm, most distributions handle system-level maintenance tasks such as certificate rotation, updates, and basic network configuration.
Distributions such as k3s, k0s, Rancher, and Talos Linux provide automation around cluster management and have proven to be suitable for production deployments.
The only maintenance that has to be set up manually are backups. Thankfully, Kubernetes stores all cluster state in a single backend, making it straightforward to back up and restore.
If you opt for a single node control plane, simply look for the SQLite database which holds the whole Kubernetes state. For example, with k3s, simply export the directory /var/lib/rancher/k3s/server/db/ and the /var/lib/rancher/k3s/server/token.
If you opt for multi nodes control plane, the "brain" is distributed accross the nodes using ETCD, a distributed, strongly consistent, key-value database. Thanks to that "strongly consistent" design, the backup also take form of copying the data directory. ETCD also offer a simple tool: etcdctl snapshot save snapshot.db.
Kubernetes only has a single source of truth! So moving/restoring these backups will proceed into restoring the whole infrastructure!
Single-Node Kubernetes
Tools like k3s, a lightweight Kubernetes distribution, demonstrate that Kubernetes can be efficient and manageable on a single node. With k3s, you can deploy a production-grade Kubernetes cluster on a modest machine, like a Raspberry Pi.
In such cases, SQLite is used as the backing store, reducing operational complexity while retaining the benefits of Kubernetes features such as declarative configuration, self-healing workloads, and Helm-based deployment.

For development, Minikube enables running a full-featured local Kubernetes cluster using Docker as both the container runtime and virtualization driver. This allows developers to replicate production-like environments with minimal effort.
What's next
Now that you've learned about the benefits of Kubernetes and Helm, you're ready to deploy Toucan on your Kubernetes cluster!
But before that, let's check if you have the prerequisites.
✅PrerequisitesLast updated
Was this helpful?