2016-06-05 20:52:20 +00:00
# Kubernetes on Openstack with Terraform
Provision a Kubernetes cluster with [Terraform ](https://www.terraform.io ) on
Openstack.
## Status
2017-12-05 12:48:47 +00:00
This will install a Kubernetes cluster on an Openstack Cloud. It should work on
most modern installs of OpenStack that support the basic services.
## Approach
The terraform configuration inspects variables found in
[variables.tf ](variables.tf ) to create resources in your OpenStack cluster.
There is a [python script ](../terraform.py ) that reads the generated`.tfstate`
file to generate a dynamic inventory that is consumed by the main ansible script
to actually install kubernetes and stand up the cluster.
### Networking
The configuration includes creating a private subnet with a router to the
external net. It will allocate floating-ips from a pool and assign them to the
hosts where that makes sense. You have the option of creating bastion hosts
inside the private subnet to access the nodes there.
### Kubernetes Nodes
You can create many different kubernetes topologies by setting the number of
different classes of hosts. For each class there are options for allocating
floating ip addresses or not.
- Master Nodes with etcd
- Master nodes without etcd
- Standalone etcd hosts
- Kubernetes worker nodes
Note that the ansible script will report an invalid configuration if you wind up
with an even number of etcd instances since that is not a valid configuration.
### Gluster FS
The terraform configuration supports provisioning of an optional GlusterFS
shared file system based on a separate set of VMs. To enable this, you need to
specify
- the number of gluster hosts
- Size of the non-ephemeral volumes to be attached to store the GlusterFS bricks
- Other properties related to provisioning the hosts
Even if you are using Container Linux by CoreOS for your cluster, you will still
need the GlusterFS VMs to be based on either Debian or RedHat based images,
Container Linux by CoreOS cannot serve GlusterFS, but can connect to it through
binaries available on hyperkube v1.4.3_coreos.0 or higher.
2016-06-05 20:52:20 +00:00
## Requirements
- [Install Terraform ](https://www.terraform.io/intro/getting-started/install.html )
2017-12-05 12:48:47 +00:00
- [Install Ansible ](http://docs.ansible.com/ansible/latest/intro_installation.html )
- you already have a suitable OS image in glance
- you already have a floating-ip pool created
- you have security-groups enabled
- you have a pair of keys generated that can be used to secure the new hosts
2016-06-05 20:52:20 +00:00
2017-12-05 12:48:47 +00:00
## Module Architecture
The configuration is divided into three modules:
- Network
- IPs
- Compute
2016-06-05 20:52:20 +00:00
2017-12-05 12:48:47 +00:00
The main reason for splitting the configuration up in this way is to easily
accommodate situations where floating IPs are limited by a quota or if you have
any external references to the floating IP (e.g. DNS) that would otherwise have
to be updated.
2016-06-05 20:52:20 +00:00
2017-12-05 12:48:47 +00:00
You can force your existing IPs by modifying the compute variables in
`kubespray.tf` as
2016-06-05 20:52:20 +00:00
```
2017-12-05 12:48:47 +00:00
k8s_master_fips = ["151.101.129.67"]
k8s_node_fips = ["151.101.129.68"]
2016-06-05 20:52:20 +00:00
```
2017-12-05 12:48:47 +00:00
## Terraform
Terraform will be used to provision all of the OpenStack resources. It is also
used to deploy and provision the software requirements.
2016-06-05 20:52:20 +00:00
2017-12-05 12:48:47 +00:00
### Prep
2016-06-05 20:52:20 +00:00
2017-12-05 12:48:47 +00:00
#### OpenStack
2016-06-05 20:52:20 +00:00
2017-12-05 12:48:47 +00:00
Ensure your OpenStack **Identity v2** credentials are loaded in environment
variables. This can be done by downloading a credentials .rc file from your
OpenStack dashboard and sourcing it:
2016-06-05 20:52:20 +00:00
```
2017-12-05 12:48:47 +00:00
$ source ~/.stackrc
2016-06-05 20:52:20 +00:00
```
Ensure that you have your Openstack credentials loaded into Terraform
environment variables. Likely via a command similar to:
```
$ echo Setting up Terraform creds & & \
export TF_VAR_username=${OS_USERNAME} & & \
export TF_VAR_password=${OS_PASSWORD} & & \
export TF_VAR_tenant=${OS_TENANT_NAME} & & \
export TF_VAR_auth_url=${OS_AUTH_URL}
```
2017-12-05 12:48:47 +00:00
### Terraform Variables
The construction of the cluster is driven by values found in
[variables.tf ](variables.tf ).
The best way to set these values is to create a file in the project's root
directory called something like`my-terraform-vars.tfvars`. Many of the
variables are obvious. Here is a summary of some of the more interesting
ones:
2017-09-27 09:59:09 +00:00
2017-12-05 12:48:47 +00:00
|Variable | Description |
|---------|-------------|
|`cluster_name` | All OpenStack resources will use the Terraform variable`cluster_name` (default`example`) in their name to make it easier to track. For example the first compute resource will be named`example-kubernetes-1`. |
|`network_name` | The name to be given to the internal network that will be generated |
|`dns_nameservers`| An array of DNS name server names to be used by hosts in the internal subnet. |
|`floatingip_pool` | Name of the pool from which floating IPs will be allocated |
|`external_net` | UUID of the external network that will be routed to |
|`flavor_k8s_master`,`flavor_k8s_node`,`flavor_etcd`, `flavor_bastion` ,`flavor_gfs_node` | Flavor depends on your openstack installation, you can get available flavor IDs through`nova flavor-list` |
|`image`,`image_gfs` | Name of the image to use in provisioning the compute resources. Should already be loaded into glance. |
|`ssh_user`,`ssh_user_gfs` | The username to ssh into the image with. This usually depends on the image you have selected |
|`public_key_path` | Path on your local workstation to the public key file you wish to use in creating the key pairs |
|`number_of_k8s_masters`, `number_of_k8s_masters_no_floating_ip` | Number of nodes that serve as both master and etcd. These can be provisioned with or without floating IP addresses|
|`number_of_k8s_masters_no_etcd`, `number_of_k8s_masters_no_floating_ip_no_etcd` | Number of nodes that serve as just master with no etcd. These can be provisioned with or without floating IP addresses |
|`number_of_etcd` | Number of pure etcd nodes |
|`number_of_k8s_nodes`, `number_of_k8s_nodes_no_floating_ip` | Kubernetes worker nodes. These can be provisioned with or without floating ip addresses. |
|`number_of_bastions` | Number of bastion hosts to create. Scripts assume this is really just zero or one |
|`number_of_gfs_nodes_no_floating_ip` | Number of gluster servers to provision. |
| `gfs_volume_size_in_gb` | Size of the non-ephemeral volumes to be attached to store the GlusterFS bricks |
2016-10-26 14:56:15 +00:00
2017-12-05 12:48:47 +00:00
## Initializing Terraform
Before Terraform can operate on your cluster you need to install required
plugins. This is accomplished with the command
```bash
$ terraform init contrib/terraform/openstack
2016-10-26 14:56:15 +00:00
```
2017-12-05 12:48:47 +00:00
## Provisioning Cluster with Terraform
You can apply the terraform config to your cluster with the following command
issued from the project's root directory
```bash
$ terraform apply -state=contrib/terraform/openstack/terraform.tfstate -var-file=my-terraform-vars.tfvars contrib/terraform/openstack
2016-10-26 14:56:15 +00:00
```
2017-12-05 12:48:47 +00:00
if you chose to create a bastion host, this script will create
`contrib/terraform/openstack/k8s-cluster.yml` with an ssh command for ansible to
be able to access your machines tunneling through the bastion's ip adress. If
you want to manually handle the ssh tunneling to these machines, please delete
or move that file. If you want to use this, just leave it there, as ansible will
pick it up automatically.
2017-09-27 09:59:09 +00:00
2017-12-05 12:48:47 +00:00
## Destroying Cluster with Terraform
You can destroy a config deployed to your cluster with the following command
issued from the project's root directory
```bash
$ terraform destroy -state=contrib/terraform/openstack/terraform.tfstate -var-file=my-terraform-vars.tfvars contrib/terraform/openstack
2017-09-27 09:59:09 +00:00
```
2017-12-05 12:48:47 +00:00
## Debugging Cluster Provisioning
You can enable debugging output from Terraform by setting
`OS_DEBUG` to 1 and`TF_LOG` to`DEBUG` before runing the terraform command
2017-09-27 09:59:09 +00:00
2017-12-05 12:48:47 +00:00
# Running the Ansible Script
Ensure your local ssh-agent is running and your ssh key has been added. This
step is required by the terraform provisioner:
2017-09-27 09:59:09 +00:00
2017-12-05 12:48:47 +00:00
```
$ eval $(ssh-agent -s)
$ ssh-add ~/.ssh/id_rsa
```
Make sure you can connect to the hosts:
2016-11-11 03:59:46 +00:00
```
2017-12-05 12:48:47 +00:00
$ ansible -i contrib/terraform/openstack/hosts -m ping all
example-k8s_node-1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
example-etcd-1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
example-k8s-master-1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
2016-11-11 03:59:46 +00:00
```
2017-12-05 12:48:47 +00:00
if you are deploying a system that needs bootstrapping, like Container Linux by
CoreOS, these might have a state`FAILED` due to Container Linux by CoreOS not
having python. As long as the state is not`UNREACHABLE`, this is fine.
2016-10-26 14:56:15 +00:00
2017-12-05 12:48:47 +00:00
if it fails try to connect manually via SSH ... it could be something as simple as a stale host key.
2017-10-18 12:26:14 +00:00
2017-12-05 12:48:47 +00:00
## Configure Cluster variables
2017-07-10 15:53:57 +00:00
2017-12-05 12:48:47 +00:00
Edit`inventory/group_vars/all.yml`:
2017-07-10 15:53:57 +00:00
- Set variable **bootstrap_os** according selected image
```
# Valid bootstrap options (required): ubuntu, coreos, centos, none
bootstrap_os: coreos
```
2017-07-11 09:46:19 +00:00
- **bin_dir**
2017-07-10 15:53:57 +00:00
```
# Directory where the binaries will be installed
# Default:
# bin_dir: /usr/local/bin
# For Container Linux by CoreOS:
bin_dir: /opt/bin
```
2017-07-11 09:46:19 +00:00
- and **cloud_provider**
```
cloud_provider: openstack
```
2017-12-05 12:48:47 +00:00
Edit`inventory/group_vars/k8s-cluster.yml`:
2017-07-10 15:53:57 +00:00
- Set variable **kube_network_plugin** according selected networking
```
# Choose network plugin (calico, weave or flannel)
# Can also be set to 'cloud', which lets the cloud provider setup appropriate routing
kube_network_plugin: flannel
```
> flannel works out-of-the-box
> calico requires allowing service's and pod's subnets on according OpenStack Neutron ports
2017-07-11 09:46:19 +00:00
- Set variable **resolvconf_mode**
```
# Can be docker_dns, host_resolvconf or none
# Default:
# resolvconf_mode: docker_dns
# For Container Linux by CoreOS:
resolvconf_mode: host_resolvconf
```
2017-07-10 15:53:57 +00:00
2017-07-11 09:46:19 +00:00
For calico configure OpenStack Neutron ports: [OpenStack ](/docs/openstack.md )
2016-10-26 14:56:15 +00:00
2017-12-05 12:48:47 +00:00
## Deploy kubernetes:
2016-06-05 20:52:20 +00:00
```
$ ansible-playbook --become -i contrib/terraform/openstack/hosts cluster.yml
```
2017-12-05 12:48:47 +00:00
## Set up local kubectl
2017-07-10 15:53:57 +00:00
1. Install kubectl on your workstation:
[Install and Set Up kubectl ](https://kubernetes.io/docs/tasks/tools/install-kubectl/ )
2. Add route to internal IP of master node (if needed):
```
sudo route add [master-internal-ip] gw [router-ip]
```
or
```
sudo route add -net [internal-subnet]/24 gw [router-ip]
```
3. List Kubernetes certs& keys:
```
ssh [os-user]@[master-ip] sudo ls /etc/kubernetes/ssl/
```
4. Get admin's certs& key:
```
ssh [os-user]@[master-ip] sudo cat /etc/kubernetes/ssl/admin-[cluster_name]-k8s-master-1-key.pem > admin-key.pem
ssh [os-user]@[master-ip] sudo cat /etc/kubernetes/ssl/admin-[cluster_name]-k8s-master-1.pem > admin.pem
ssh [os-user]@[master-ip] sudo cat /etc/kubernetes/ssl/ca.pem > ca.pem
```
2017-12-05 12:48:47 +00:00
5. Configure kubectl:
2017-07-10 15:53:57 +00:00
```
kubectl config set-cluster default-cluster --server=https://[master-internal-ip]:6443 \
2017-12-05 12:48:47 +00:00
--certificate-authority=ca.pem
2017-07-10 15:53:57 +00:00
kubectl config set-credentials default-admin \
--certificate-authority=ca.pem \
--client-key=admin-key.pem \
2017-12-05 12:48:47 +00:00
--client-certificate=admin.pem
2017-07-10 15:53:57 +00:00
kubectl config set-context default-system --cluster=default-cluster --user=default-admin
kubectl config use-context default-system
```
7. Check it:
```
kubectl version
```
2017-12-05 12:48:47 +00:00
If you are using floating ip addresses then you may get this error:
```
Unable to connect to the server: x509: certificate is valid for 10.0.0.6, 10.0.0.6, 10.233.0.1, 127.0.0.1, not 132.249.238.25
```
2017-07-10 15:53:57 +00:00
2017-12-05 12:48:47 +00:00
You can tell kubectl to ignore this condition by adding the
`--insecure-skip-tls-verify` option.
2016-06-05 20:52:20 +00:00
2017-12-05 12:48:47 +00:00
## GlusterFS
GlusterFS is not deployed by the standard`cluster.yml` playbook, see the
[glusterfs playbook documentation ](../../network-storage/glusterfs/README.md )
for instructions.
2016-06-05 20:52:20 +00:00
2017-12-05 12:48:47 +00:00
Basically you will install gluster as
```bash
$ ansible-playbook --become -i contrib/terraform/openstack/hosts ./contrib/network-storage/glusterfs/glusterfs.yml
2016-06-05 20:52:20 +00:00
```
2017-12-05 12:48:47 +00:00
# What's next
[Start Hello Kubernetes Service ](https://kubernetes.io/docs/tasks/access-application-cluster/service-access-application-cluster/ )