Hi, I'm Daisy

Here is a place for my random musings!

Exploring Kubernetes and Helm

As more developers work within distributed environments, tools like Kubernetes have become central to keeping application components standardized across dynamic build and production environments. While Kubernetes lets developers orchestrate large numbers of containers at scale, tools like Helm have become important when managing resources within Kubernetes clusters.

When you are working with many resources and a sizable stack on Kubernetes, managing thousands of lines of YAML become difficult. This is where Helm comes in. Helm is a package manager for Kubernetes that collects sets of templatized Kubernetes manifest files into a unified bundle called a chart, which is organized and versioned. Once the Helm client deploys the chart into the Kubernetes cluster, it can manage the upgrade and rollback of these bundles.

In this post, we are going to explore Helm by setting up WordPress with an external MySQL database on Kubernetes using the Helm package manager. We will begin by configuring some permissions with Helm’s server side component (Tiller) as well as our MySQL installation, inspect some Helm charts, and then install WordPress onto the Kubernetes cluster using the Helm client and connect to an external MySQL database. To conclude, we will visit our deployed WordPress application and check the status of our deployment.


To follow along, you will need to install the following command line tools and services. These could be installed on your local development machine, or on a server that you’ve set up as your development environment:

  • A Kubernetes 1.10+ cluster with role-based access control (RBAC) enabled.
  • The kubectl command-line tool installed on your local machine or development server and configured to connect to your cluster.
  • Helm installed on your local machine or server, and Tiller installed on your cluster.
  • MySQL installed on a server.

Once you have these components set up, you’re ready to begin.

Changing Account Permissions

Helm Permissions

The Helm permission model requires us to adjust its default setup so that it can work with the new permission structure in Kubernetes 1.6+, which has RBAC turned on by default. As a result, the service account for each namespace does not have cluster-wide access out of the box and so Tiller (running as a pod in the system-wide kube-system namespace) does not have the permission to install and manage cluster resources. To work around this issue, we can elevate permissions for the default service account in the kube-system namespace to be cluster-wide:

kubectl create clusterrolebinding add-on-cluster-admin --clusterrole=cluster-admin --serviceaccount=kube-system:default

This creates a ClusterRoleBinding with cluster-admin access levels for our specified service account and also grants the cluster-admin role to it, which permits resource installation across all namespaces.

Note: On large scale production-level deployments, you might consider creating different service accounts, roles, and role bindings for different users/teams, but defining the exact roles and permissions on your cluster is out of the scope of this tutorial. You can learn more about Kubernetes’ RBAC model in the official documentation. The above command suffices for exploring Helm or for development clusters.

You should now be able to successfully use Helm to install your packages now that Tiller has broadened permissions.

MySQL Permissions

You should have MySQL installed on a server independent of your Kubernetes cluster. It is generally a good idea to keep your database independent of your cluster because Kubernetes’ architecture supports a very ephemeral environment where pods and containers are dynamically created and destroyed all the time, which isn’t ideal for keeping state.

Before we can move forward with our WordPress installation, we need to make sure that our MySQL server and database can be accessed remotely.

Create a database for our installation:


Create a user with a password and give the user all privileges to the database we just created, as well as allowing access if the user connects from anywhere. You can also fine-tune these privileges as necessary later on.

GRANT ALL ON wpdb.* TO 'sammy'@'%' IDENTIFIED BY 'password';

Note: The following instructions are based on a MySQL installation on Ubuntu 18.04.

To allow for outside connections to your database, edit your MySQL config file by commenting out the bind address that points to localhost. You can alternatively change it to bind-address

[label /etc/mysql/mysql.conf.d/mysqld.cnf]
# bind-address 

Restart the MySQL service:

sudo systemctl restart mysql.service

If there is a firewall, open up the default port for MySQL (:3306) and then restart the service.

sudo ufw allow 3306/tcp
sudo systemctl restart ufw

Your MySQL server and database should allow for outside connections now.

Understanding Charts in Helm

A Helm chart is an archive of container definitions and configurations tailored for an application. By default, Helm installs from a repository called stable, which contains many charts for many different types of workloads curated and created by the community. You can also create and install a chart locally or create your own repository.

If we go to the stable/wordpress repository, we can see all the YAML files that make up the bundle. When a chart is installed by Helm, the values in values.yaml are replaced inside the templates, and the manifests are created, which define resources in Kubernetes. Helm will be able to manage the maintenance of this application once the chart is deployed in your cluster.

We can search for a WordPress chart using Helm’s CLI tool:

helm search wordpress
[secondary_label Output]
NAME              CHART VERSION   APP VERSION   DESCRIPTION                                             
stable/wordpress  5.1.3           5.0.3      	Web publishing platform for building blogs and websites.

The output indicates that there is currently one chart in the default repository that contain the keyword “wordpress”.

To learn about the details of this chart and about its configuration options, you can read the information on their GitHub repo or use the inspect command:

helm inspect stable/wordpress
[secondary_label Output]
appVersion: 5.0.3
description: Web publishing platform for building blogs and websites.
engine: gotpl
home: http://www.wordpress.com/

## Configuration

The following table lists the configurable parameters of the WordPress chart and their default values.

|          Parameter          |              Description             |                    Default                     |
| `mariadb.enabled`           | Deploy MariaDB container(s)          | `true`                                         |
| `mariadb.rootUser.password` | MariaDB admin password               | `nil`                                          |
| `mariadb.db.name`           | Database name to create              | `bitnami_wordpress`                            |
| `mariadb.db.user`           | Database user to create              | `bn_wordpress`                                 |
| `mariadb.db.password`       | Password for the database            | _random 10 character long alphanumeric string_ |
| `externalDatabase.host`     | Host of the external database        | `localhost`                                    |
| `externalDatabase.user`     | Existing username in the external db | `bn_wordpress`                                 |
| `externalDatabase.password` | Password for the above username      | `nil`                                          |
| `externalDatabase.database` | Name of the existing database        | `bitnami_wordpress`                            |
| `externalDatabase.port`     | Database port number                 | `3306`                                         |

There is a wealth of information here, but for our goal, the main items we want to note is that the WordPress chart uses MariaDB by default (which we want to change) and that there are configurable options to connect to an external database (which is exactly what we want to do).

Installing WordPress Chart that Connects to External MySQL Server

We are going to create a namespace in Kubernetes for our WordPress application to keep things organized. Otherwise it will go into the default namespace. We will also give our installation release a name to avoid being assigned a randomly generated one by Helm. Then we will disable MariaDB and supply the information to our external MySQL database.

The following command will install and run WordPress in a container in a Kubernetes pod with our specified requirements and configurations:

$ helm install stable/wordpress \
    --set mariadb.enabled=false \
    --set externalDatabase.host=<^>your_server_ip<^> \
    --set externalDatabase.user=<^>sammy<^> \
    --set externalDatabase.password=<^>password<^> \
    --set externalDatabase.database=<^>wpdb<^> \
    --set externalDatabase.port=3306 \
    --name wordpress \
    --namespace wordpress
[secondary_label Output]
NAME:   wordpress
LAST DEPLOYED: Fri Feb  8 10:25:35 2019
NAMESPACE: wordpress

==> v1/Secret
NAME                   TYPE      DATA  AGE
wordpress-externaldb   Opaque    1     1s
wordpress-wordpress    Opaque    1     1s

==> v1/PersistentVolumeClaim
wordpress-wordpress  Pending  do-block-storage  1s

==> v1/Service
NAME                 TYPE          CLUSTER-IP     EXTERNAL-IP     PORT(S)                     AGE
wordpress-wordpress  LoadBalancer   <pending>       80:30139/TCP,443:30901/TCP  1s

==> v1beta1/Deployment
wordpress-wordpress  1        1        1           0          1s

==> v1/Pod(related)
NAME                                  READY  STATUS   RESTARTS  AGE
wordpress-wordpress-75c6c8b68f-5256q  0/1    Pending  0         1s

1. Get the WordPress URL:

  NOTE: It may take a few minutes for the LoadBalancer IP to be available.
        Watch the status with: 'kubectl get svc --namespace wordpress -w wordpress-wordpress'
  export SERVICE_IP=$(kubectl get svc --namespace wordpress wordpress-wordpress --template "{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}")
  echo "WordPress URL: http://$SERVICE_IP/"
  echo "WordPress Admin URL: http://$SERVICE_IP/admin"

2. Login with the following credentials to see your blog

  echo Username: user
  echo Password: $(kubectl get secret --namespace wordpress wordpress-wordpress -o jsonpath="{.data.wordpress-password}" | base64 --decode)

We receive a lot of status back from Helm, which tells us what it has done and created. Namely, it created a service and a deployment and from the deployment it created a pod. The NOTES section provides us with useful information about how to access our WordPress site. Run the specified commands to obtain the IP address to your application as well as the login credentials.

Note that you can also set the login password with the --set wordpressPassword=password option upon installation.

It will take a few minutes for WordPress to finish provisioning. In the meantime, list the applications that have been installed by Helm onto your cluster:

helm list
[secondary_label Output]
NAME        REVISION   UPDATED       	         STATUS     CHART          	    APP VERSION	   NAMESPACE
wordpress   1          Fri Feb  8 10:25:35 2019	 DEPLOYED   wordpress-5.1.3     5.0.3      	   wordpress

When you install a chart with Helm, it is called a release and gets assigned a version (REVISION). If you release it again, it will increment the version and only update the resources that has changed.

List the pods in our application’s namespace:

kubectl get pods --namespace wordpress
[secondary_label Output]
NAME                                   READY   STATUS    RESTARTS   AGE
wordpress-wordpress-75c6c8b68f-5256q   1/1     Running   3          22m

Check the status of our deployment:

kubectl get deployments --namespace wordpress
[secondary_label Output]
NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
wordpress-wordpress   1/1     1            1           23m

Now that everything looks to be up and running, you can navigate to your WordPress site, log into the control panel and start customizing your site that is now running on a Kubernetes cluster.

In sum, we have demonstrated how to install WordPress onto a Kubernetes cluster using the Helm package manager. We have connected an external MySQL database to our WordPress application by setting the appropriate configuration options upon issuing helm install. With our WordPress running on Kubernetes, we can now host a highly available and scalable application. :)