Kubernetes is a container orchestration platform and has been described as “the OS of the cloud”. It builds on container-based services by providing many features such as volumes for stateful services, resilience and scaling, monitoring, automated zero-downtime upgrades. It runs on a cluster of nodes (VMs) and allocates services to nodes based on either hard limits (eg. my service must run on linux) and prioritised preferences (eg. put these two services on the same VM). If you are running your services in containers, Kubernetes will likely make your life easier.
The first important step is to ensure your software is running in a container. A container is a way of packaging your service, along with any dependencies, removing the reliance of specific libraries, etc existing on the OS. I’m mostly assuming you know what a container is, what the benefits are and how to run one in this blog post.
Assuming you have a container already (and if you haven’t you can just use one of mine to follow along), the first step is to create your cluster. Sorry, that part is up to you. Come back here when you’re done. You can take a look at this page for assistance with Azure.
Pods are the basic building blocks of a Kubernetes system and it’s probably fair to say everything else supports Pods in keeping their services running and available. A Pod runs one or more containers and defines ports, volumes, config settings, etc to expose a container service.
To create a pod, you will need a yaml file that defines its structure. If you’re not sure what yaml is, it’s like a json file with way fewer characters. It uses file layout to express relationships between properties, so take care of those spaces! Anyway, here’s our first yaml file:
--- apiVersion: v1 kind: Pod metadata: name: basiccore-pod labels: app: basiccore spec: containers: - name: basiccore image: isonaj/basiccore ports: - containerPort: 80 nodeSelector: beta.kubernetes.io/os: linux
Alright, that is not terribly clear because it’s got ‘basiccore’ all over it. This yaml file has 4 parts to it: apiVersion, kind, metadata and spec. We are asking for a
Pod kind of component, from
v1 of the API. The metadata says that the name of the pod should be
basiccore-pod and it should have one label called
app with the value
basiccore. Inside this pod, I want a single container running image
isonaj/basiccore (with port
80 exposed) and the container should be called
basiccore. The nodeSelector part is just to ensure that the linux container runs on a Linux node. (with AKS supporting windows nodepools, it helps to be sure)
Now, run that on the cluster using
kubectl apply -f pod.yaml. You can check what is happening by running
kubectl get pods. If it shows an error, use
kubectl describe pod basiccore-pod to find out more.
Once you’re finished, there’s nothing more to see. We won’t actually be using this to go further. Nobody expects the spanish inquision and nobody starts a pod on its own. Delete your pod with
kubectl delete pod basiccore-pod.
So let’s start over. Nobody starts a pod by itself, because there’s a much better construct for running pods and that is a Deployment. A deployment will provide zero downtime by managing all sorts of things for you. It can be used to automatically rollout new image versions or pod configs (basically anything that could put your uptime at risk). We’ll take a closer look in a later post.
Let’s jump into the yaml:
--- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: basiccore-deployment spec: replicas: 2 template: metadata: name: basiccore-pod labels: app: basiccore spec: containers: - name: basiccore image: isonaj/basiccore ports: - containerPort: 80 nodeSelector: beta.kubernetes.io/os: linux
It’s a bit bigger than the Pod yaml. Let’s work through from the top. Deployments weren’t available in v1. It was added in
extensions/v1beta1. Next, we’re creating a
Deployment, not a
Pod and giving it a name of
spec for a deployment consists of the number of replicas and the template. We are starting 2 Pods with this one and the template is the yaml we used to create the Pod earlier.
Let’s take a look:
$ kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE basiccore-deployment 2/2 2 2 33s $ kubectl get pods NAME READY STATUS RESTARTS AGE basiccore-deployment-c46759d6d-5qw96 1/1 Running 0 7s basiccore-deployment-c46759d6d-f94lk 1/1 Running 0 7s
We’ve just spent all of this time starting and stopping pods, but we haven’t actually connected to it yet. We need a way to get in, and get directed to the pod. For this, we use a Service component.
A Kubernetes Service is an abstraction layer which defines a logical set of Pods and enables external traffic exposure, load balancing and service discovery for those Pods. - kubernetes.io
What’s that mean? A service component is basically a load balancer that sits across some pods and directs the incoming requests where they are supposed to go.
--- apiVersion: v1 kind: Service metadata: name: basiccore-service spec: type: LoadBalancer selector: app: basiccore ports: - protocol: TCP port: 80 targetPort: 80
This service will open up a port in our cluster and load balance any traffic across the pods in the selector. In this case, we’re creating a service with a
LoadBalancer targetting any pod with the metadata
basiccore (which we applied in the deployment template).
kubectl apply -f basiccore-service.yaml to apply the service and then
kubectl get services to see the current state.
$ kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE basiccore-service LoadBalancer 10.0.55.65 <pending> 80:30376/TCP 5m52s $ kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE basiccore-service LoadBalancer 10.0.55.65 188.8.131.52 80:30376/TCP 8m12s
Once the External IP is displayed, put that into your browser, and there it is. A container, in a pod, accessible from the outside world.