---
title: "Launching a Kubernetes cluster with Ansible"
description: "Learn how to launch a Kubernetes cluster in just a few minutes using Ansible and CoreOS."
date: 2016-05-09
author: "Sebastien Goasguen"
url: https://www.exoscale.com/blog/kubernetes-ansible/
---
# Launching a Kubernetes cluster with Ansible

[Kubernetes](https://kubernetes.io/) gives you a great solution for managing distributed applications at scale. In this guide, I show you how to launch a Kubernetes (or k8s) cluster using Ansible. 

![Launching Kubernetes with Ansible](https://www.exoscale.com/blog/kubernetes-ansible/cover.png)

## Introducing Kubernetes

In case you're not familiar with Kubernetes, here's a quick introduction.

You might already have used [Swarm](https://www.exoscale.com/blog/deploy-docker-swarm/) to create a cluster of Docker hosts. You might even have done so using the [Exoscale Docker machine driver](https://www.exoscale.com/blog/deploy-a-remote-docker-host-and-connect-to-it-using-your-local-docker-client/). But Docker Swarm is not the only solution to orchestrate your containers and more broadly speaking to manage your distributed application in the Cloud.

Originating from Google, Kubernetes is an open re-write of Google's internal application management system [Borg](https://research.google/pubs/pub43438/). You should definitely take some time and read the paper on Borg. It contains lots of knowledge about managing systems at scale and explains some of the thinking behind Kubernetes.

Kubernetes is written in Golang and the source is available on [GitHub](https://github.com/kubernetes/kubernetes). It typically needs a head node and a set of worker nodes. The head node runs an API server, a scheduler and a controller. The workers run an agent called _kubelet_ and a proxy that enables service discovery across the cluster. The state of the cluster is stored in [Etcd](https://github.com/etcd-io/etcd). We will leave a discussion on Kubernetes primitives for another time.

In this blog, we will use Ansible to create a Kubernetes cluster on Exoscale. The head node will also run etcd and we will start as many workers as we want.

## Prerequisites

Before we get started, we need to install a few prerequisites just in case you do not have them on your machine already.

We will be using [Ansible](https://www.ansible.com/), which has a Python package that can be installed via the Python Package installer (i.e Pip).

Exoscale uses the Cloudstack API, so we'll all use the Ansible [core module](https://docs.ansible.com/projects/ansible/latest/index.html) for CloudStack. This module is based on a Python CloudStack API client written by the fine folks at Exoscale. This package, [_cs_](https://github.com/exoscale/cs), is also available via _Pip_.

If you're on Ubuntu, here's how to instal Pip:

    $ sudo apt-get install -y python-pip

On MacOS, you can use Pip to install a recent version of Python and that package includes Pip:

    $ brew install python

Then use Pip to pull down the rest of the prerequesites:

    $ sudo pip install ansible cs sshpubkeys

To use your Kubernetes cluster you will need a client that talks to the k8s API. This client is called _kubectl_. It is extremely powerfull and enjoyable to use.

From Ubuntu, and other Linuxen, you can wget the kubectl binary:

    $ wget https://storage.googleapis.com/kubernetes-release/release/v1.2.0/bin/linux/amd64/kubectl
    $ chmod +x kubectl
    
Similarly, from MacOS you can install it using brew:

    $ brew install kubectl

The last step before diving in the cluster creation is to configure _cs_ to talk to the Exoscale API endpoint.

To do this, create a `~/.cloudstack.ini` file with your credentials and Exoscale endpoint:

```
[cloudstack]
endpoint = https://api.exoscale.ch/compute
key = <your api access key>
secret = <your api secret key>
method = post
```

You should now be all set and ready to get the Ansible playbook that will do all the work for you.

## Creating the cluster

Ansible is used to configure machines. But the Cloud modules also allow us to create cloud resources such as [VM instances](https://www.exoscale.com/compute/), SSH key pairs, security groups and so on.

For example, to create a VM instance in a CloudStack cloud, your Ansible task could look like this:

```
- local_action:
    module: cs_instance
    name: web-vm-1
    iso: Linux Debian 7 64-bit
    hypervisor: VMware
    service_offering: Tiny
    disk_offering: Performance
    disk_size: 20
    ssh_key: john@example.com
```

Hence, we will be using Ansible to create the VM instances that will make our Kubernetes cluster, and we will also automatically create the correct security group rules.

The playbook makes use of CoreOS instances, and passes userdata at the instance creation step to configure them properly and start the Kubernetes services properly.

So let's get started and clone a GitHub repo that contains a playbook to create a Kubernetes cluster on Exoscale from scratch.

```
git clone https://github.com/skippbox/ansible-cloudstack.git
cd ansible-cloudstack
```

The repository contains a main playbook `k8s.yml` as well as one to remove the entire cluster `k8s-remove.yml` this can be handy. Under `roles/k8s/tasks` you can see the list of tasks that Ansible will perform. And in `roles/k8s/templates` you can see the userdata that we will pass to the CoreOS instances. This is where you will see the definition of the systemd units that will run the various k8s components (e.g API server, kubelet)

```
$ tree
.
├── LICENSE
├── README.md
├── ansible.cfg
├── inventory
├── k8s-remove.yml
├── k8s.yml
└── roles
    ├── common
    │   └── tasks
    │       ├── create_sshkey.yml
    │       └── main.yml
    ├── k8s
    │   ├── tasks
    │   │   ├── create_context.yml
    │   │   ├── create_inv.yml
    │   │   ├── create_secgroup.yml
    │   │   ├── create_secgroup_rules.yml
    │   │   ├── create_vm.yml
    │   │   └── main.yml
    │   └── templates
    │       ├── inventory.j2
    │       ├── k8s-master.j2
    │       └── k8s-node.j2
    └── k8s-remove
        └── tasks
            ├── delete_context.yml
            ├── delete_inv.yml
            ├── delete_secgroup.yml
            ├── delete_secgroup_rules.yml
            ├── delete_vm.yml
            └── main.yml
```

Check the main playbook and edit it to meet your needs. The playbook will create an SSH keypair for you, it will create a security group, and will start one head node and as many workers as you want.

```
- hosts: localhost
  connection: local
  vars:
    ssh_key: k8s
    k8s_version: v1.2.0
    k8s_num_nodes: 2
    k8s_security_group_name: k8s
    k8s_node_prefix: foobar
    k8s_template: Linux CoreOS stable 899 64-bit 50G Disk (2016-04-05-d6cdbb)
    k8s_instance_type: Tiny
    k8s_username: foobar
    k8s_password: FdKPSuwQ

  roles:
    - common
    - k8s
```

With the `k8s.yml` file edited to your liking, just launch ansible and watch it do its job. The output below hides some of the steps.

```
$ ansible-playbook k8s.yml
PLAY ***************************************************************************

TASK [setup] *******************************************************************
ok: [localhost]
...
TASK [common : Create SSH Key] *************************************************
ok: [localhost -> localhost]
...
TASK [k8s : Create k8s Security Group] *****************************************
ok: [localhost -> localhost]
...
TASK [k8s : Start k8s head node] ***********************************************
changed: [localhost -> localhost]
...
TASK [k8s : debug] *************************************************************
ok: [localhost] => {
    "msg": "k8s master IP is 185.19.29.73"
}
...
TASK [k8s : Start k8s nodes] ***************************************************
changed: [localhost -> localhost] => (item=1)
changed: [localhost -> localhost] => (item=2)
...
TASK [k8s : Create context] ****************************************************
changed: [localhost]
...
PLAY RECAP *********************************************************************
localhost                  : ok=26   changed=7    unreachable=0    failed=0   
```

Assuming everything went fine as shown above, you should now see the instances in your Exoscale console, plus a _k8s_ key pair and a _k8s_ security group.

At the end of the play you will notice that the last task it did was _Create context_. This is a handy task that configured your local installation of _kubectl_ to point directly to your k8s API endpoint. You can check what it is by running the `kubectl config view` command. You should see an output like below:

```
apiVersion: v1
clusters:
- cluster:
    insecure-skip-tls-verify: true
    server: https://185.19.29.73:443
  name: exo
- context:
    cluster: exo
    user: exo
  name: exo
current-context: exo
kind: Config
preferences: {}
users:
- name: exo
  user:
    password: FdKPSuwQ
    username: foobar
```

The setup currently uses basic auth but we do not setup a proper TLS handshake; pull requests are welcome to improve this.

With your k8s client configured you can check that your nodes have joined your cluster. Note however that it might take a minute or so for the nodes to reach _Ready_ state.

```
$ kubectl get nodes
NAME            STATUS    AGE
185.19.29.115   Ready     11m
185.19.29.96    Ready     12m
```

## Deploying an application

Now that you have a working Kubernetes cluster, it's time to deploy an application. And that will be the subject of my next post!

Keep following this blog, or [Exoscale's Twitter account](https://twitter.com/exoscale), for news of when the next post is available.

