---
title: "Exoscale Kubernetes Cloud Controller Manager"
description: "Thanks to the transparent bridging of k8s functionalities to corresponding Exoscale resources, deploying Kubernetes workloads gets easier than ever."
date: 2020-08-06
author: "Marc Falzon"
tags: ["kubernetes"]
url: https://www.exoscale.com/blog/exoscale-kubernetes-cloud-controller-manager-release/
---
# Exoscale Kubernetes Cloud Controller Manager

> [!NOTE]
> The CCM is natively integrated in [Exoscale Scalable Kubernetes Service](https://www.exoscale.com/sks/)
> to provides the benefits outlined below seamlessly.

As the trend doesn't show any signs of slowing, it is safe to say that
Kubernetes (a.k.a *k8s*) is here to stay: more and more of our customers are
running Kubernetes clusters on their Exoscale infrastructure, granting the
flexibility of today's gold standard of workload orchestration on top of
rock-solid IaaS foundations.

For them and for everyone, we are happy to announce the first release of the [Exoscale Kubernetes Cloud
Controller Manager][exo-ccm], paving the way for better integration of your
Kubernetes clusters on the Exoscale platform.

![Exoscale's Official Kubernetes Cloud Controller Manager](https://www.exoscale.com/blog/exoscale-kubernetes-cloud-controller-manager-release/k8CMM.png)


## First-Class Integration of Your Kubernetes Clusters on Exoscale

A Kubernetes *Cloud Controller Manager* (CCM) is a software component, part of
the control plane, in charge of interacting with the underlying cloud
infrastructure. It features transparent bridging of k8s functionalities to
corresponding provider-side ones, such as mapping a Kubernetes *Service* of
type `LoadBalancer` to an Exoscale [Network Load Balancer][exo-nlb].


## Use Case: Load Balancing a Static Website

To demonstrate the benefits of using the Exoscale CCM in your Kubernetes
cluster running on Exoscale, let's use a simple static website exposed outside
the cluster via a k8s *Service* which will be available on the Internet through
a Network Load Balancer. For the sake of brevity, we'll assume that we have a
Docker image (`hello-corp/website`) of it ready to run.

After [installing the Cloud Controller in your cluster][exo-ccm-install],
we then proceed to deploy the website as a k8s *Deployment*:

```
$ cat <<EOF | kubectl apply --namespace=hello-corp -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: website
spec:
  selector:
    matchLabels:
      app: website
  replicas: 3
  template:
    metadata:
      labels:
        app: website
    spec:
      containers:
      - name: website
        image: hello-corp/website:latest
        ports:
        - containerPort: 80
EOF
deployment.apps/website created
```

We can ensure that our website deployment is effective by looking at the *Pods*
running:

```
$ kubectl get pods --namespace hello-corp --selector app=website
NAME                       READY   STATUS    RESTARTS   AGE
website-5cfbcdbc65-csxk4   1/1     Running   0          18s
website-5cfbcdbc65-d2zvt   1/1     Running   0          18s
website-5cfbcdbc65-fkvd9   1/1     Running   0          18s
```

We can now proceed to the declaration of a k8s *Service* of type
`LoadBalancer`, which will be delegated to the Exoscale CCM for it to handle
the creation and management of a Network Load Balancer instance configured to
forward the ingress traffic to the cluster Nodes that run our website
deployment *Pods*:

```
$ cat <<EOF | kubectl apply --namespace hello-corp -f -
kind: Service
apiVersion: v1
metadata:
  name: website
  annotations:
    service.beta.kubernetes.io/exoscale-loadbalancer-zone: "de-muc-1"
spec:
  selector:
    app: website
  type: LoadBalancer
  ports:
  - port: 80
EOF
service/website created
```

After a short while, we can confirm the availability of our website through a
Network Load Balancer instance:

```
$ kubectl get svc website --namespace hello-corp
NAME      TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
website   LoadBalancer   10.110.181.100   194.182.182.79   80:31476/TCP   37s
```

If we look at the Network Load Balancer resources in our Exoscale account, we
can see the corresponding instance:

```
$ exo nlb list -z de-muc-1
┼──────────────────────────────────────┼──────────────────────────────────────────┼──────────┼────────────────┼
│                  ID                  │                   NAME                   │   ZONE   │   IP ADDRESS   │
┼──────────────────────────────────────┼──────────────────────────────────────────┼──────────┼────────────────┼
│ 7cdd1d43-9514-414b-937f-a9743754ab19 │ k8s-981eddc1-436c-4c0f-a0d2-b24455d1e48e │ de-muc-1 │ 194.182.182.79 │
┼──────────────────────────────────────┼──────────────────────────────────────────┼──────────┼────────────────┼

$ exo nlb show -z de-muc-1 k8s-981eddc1-436c-4c0f-a0d2-b24455d1e48e
┼───────────────────────┼────────────────────────────────────────────────────────────────────────────────┼
│ NETWORK LOAD BALANCER │                                                                                │
┼───────────────────────┼────────────────────────────────────────────────────────────────────────────────┼
│ ID                    │ 7cdd1d43-9514-414b-937f-a9743754ab19                                           │
│ Name                  │ k8s-981eddc1-436c-4c0f-a0d2-b24455d1e48e                                       │
│ Zone                  │ de-muc-1                                                                       │
│ IP Address            │ 194.182.182.79                                                                 │
│ Description           │                                                                                │
│ Services              │ 0c24cb2e-801f-4c30-9b02-dcc5fd79d580 | 981eddc1-436c-4c0f-a0d2-b24455d1e48e-80 │
│ State                 │ running                                                                        │
┼───────────────────────┼────────────────────────────────────────────────────────────────────────────────┼
```

Additionally, a NLB service has been defined to forward traffic towards our
Kubernetes *Service*:

```
$ exo nlb svc show -z de-muc-1 k8s-981eddc1-436c-4c0f-a0d2-b24455d1e48e 981eddc1-436c-4c0f-a0d2-b24455d1e48e-80
┼──────────────────────┼─────────────────────────────────────────┼
│     NLB SERVICE      │                                         │
┼──────────────────────┼─────────────────────────────────────────┼
│ ID                   │ 0c24cb2e-801f-4c30-9b02-dcc5fd79d580    │
│ Name                 │ 981eddc1-436c-4c0f-a0d2-b24455d1e48e-80 │
│ Description          │                                         │
│ Instance Pool ID     │ 3a202310-0bbe-6045-52ea-82506d3b9594    │
│ Protocol             │ tcp                                     │
│ Port                 │ 80                                      │
│ Target Port          │ 31476                                   │
│ Strategy             │ round-robin                             │
│ Healthcheck Mode     │ tcp                                     │
│ Healthcheck Port     │ 31476                                   │
│ Healthcheck Interval │ 10s                                     │
│ Healthcheck Timeout  │ 5s                                      │
│ Healthcheck Retries  │ 1                                       │
│ Healthcheck Status   │ 194.182.181.144 | success               │
│                      │ 194.182.180.94 | success                │
│ State                │ running                                 │
┼──────────────────────┼─────────────────────────────────────────┼
```

If we query the Kubernetes cluster API to retrieve the external IP addresses of
the *Nodes*, we can confirm that they match the NLB service's target IP
addresses:

```
$ kubectl get nodes --selector '!node-role.kubernetes.io/master' \
    -o jsonpath='{.items[*].status.addresses[?(@.type=="ExternalIP")].address}'
194.182.181.144 194.182.180.94
```

Finally, we can reach our website through the Load Balancer IP address:

```
$ curl http://194.182.182.79
Welcome to Hello Corp
```

To illustrate the load balancing across our *Pods*, we've added a custom HTTP
header `X-Served-By` to our website responses to report information about the
server that has handled the request:

```
$ for i in {1..10} ; do curl -iI http://194.182.182.79 | grep "^X-Served-By:" ; done
X-Served-By: 192.168.132.85:80@website-5cfbcdbc65-fkvd9
X-Served-By: 192.168.132.86:80@website-5cfbcdbc65-csxk4
X-Served-By: 192.168.132.86:80@website-5cfbcdbc65-csxk4
X-Served-By: 192.168.132.86:80@website-5cfbcdbc65-csxk4
X-Served-By: 192.168.132.85:80@website-5cfbcdbc65-fkvd9
X-Served-By: 192.168.132.86:80@website-5cfbcdbc65-csxk4
X-Served-By: 192.168.132.86:80@website-5cfbcdbc65-csxk4
X-Served-By: 192.168.194.129:80@website-5cfbcdbc65-d2zvt
X-Served-By: 192.168.132.86:80@website-5cfbcdbc65-csxk4
X-Served-By: 192.168.194.129:80@website-5cfbcdbc65-d2zvt
```


## A Small Step Towards More Kubernetes Announcements

The Exoscale CCM has been designed to be easy to use with minimal
configuration, however it is [highly configurable through Kubernetes manifests
annotations][exo-ccm-lb-guide].

The introduction of the Exoscale Cloud Controller Manager will further increase the viability of our platform to deploy
Kubernetes workloads onto, and we're committed to support this technology with
more upcoming announcements. Stay tuned!


[exo-ccm]: https://github.com/exoscale/exoscale-cloud-controller-manager
[exo-nlb]: https://community.exoscale.com/documentation/compute/network-load-balancer/
[exo-ccm-install]: https://github.com/exoscale/exoscale-cloud-controller-manager/blob/master/docs/getting-started.md
[exo-ccm-lb-guide]: https://github.com/exoscale/exoscale-cloud-controller-manager/blob/master/docs/service-loadbalancer.md
[k8-product-page]: https://www.exoscale.com/kubernetes/

