@@ -34,329 +34,314 @@ Documentation for other releases can be found at
...
@@ -34,329 +34,314 @@ Documentation for other releases can be found at
# Persistent Installation of MySQL and WordPress on Kubernetes
# Persistent Installation of MySQL and WordPress on Kubernetes
This example describes how to run a persistent installation of [Wordpress](https://wordpress.org/) using the [volumes](../../docs/user-guide/volumes.md) feature of Kubernetes, and [Google Compute Engine](https://cloud.google.com/compute/docs/disks)[persistent disks](../../docs/user-guide/volumes.md#gcepersistentdisk).
This example describes how to run a persistent installation of
[WordPress](https://wordpress.org/) and
We'll use the [mysql](https://registry.hub.docker.com/_/mysql/) and [wordpress](https://registry.hub.docker.com/_/wordpress/) official [Docker](https://www.docker.com/) images for this installation. (The wordpress image includes an Apache server).
[MySQL](https://www.mysql.com/) on Kubernetes. We'll use the
[mysql](https://registry.hub.docker.com/_/mysql/) and
We'll create two Kubernetes [pods](../../docs/user-guide/pods.md) to run mysql and wordpress, both with associated persistent disks, then set up a Kubernetes [service](../../docs/user-guide/services.md) to front each pod.
[wordpress](https://registry.hub.docker.com/_/wordpress/) official
[Docker](https://www.docker.com/) images for this installation. (The
This example demonstrates several useful things, including: how to set up and use persistent disks with Kubernetes pods; how to define Kubernetes services to leverage docker-links-compatible service environment variables; and use of an external load balancer to expose the wordpress service externally and make it transparent to the user if the wordpress pod moves to a different cluster node.
WordPress image includes an Apache server).
## Get started on Google Compute Engine (GCE)
Demonstrated Kubernetes Concepts:
*[Persistent Volumes](http://kubernetes.io/docs/user-guide/persistent-volumes/) to
define persistent disks (disk lifecycle not tied to the Pods).
*[Services](http://kubernetes.io/docs/user-guide/services/) to enable Pods to
Because we're using the `GCEPersistentDisk` type of volume for persistent storage, this example is only applicable to [Google Compute Engine](https://cloud.google.com/compute/). Take a look at the [volumes documentation](../../docs/user-guide/volumes.md) for other options.
## Table of Contents
<!-- BEGIN MUNGE: GENERATED_TOC -->
-[Persistent Installation of MySQL and WordPress on Kubernetes](#persistent-installation-of-mysql-and-wordpress-on-kubernetes)
-[tl;dr Quickstart](#tldr-quickstart)
-[Table of Contents](#table-of-contents)
-[Cluster Requirements](#cluster-requirements)
-[Decide where you will store your data](#decide-where-you-will-store-your-data)
-[Host Path](#host-path)
-[GCE Persistent Disk](#gce-persistent-disk)
-[Create the MySQL Password Secret](#create-the-mysql-password-secret)
-[Deploy MySQL](#deploy-mysql)
-[Deploy WordPress](#deploy-wordpress)
-[Visit your new WordPress blog](#visit-your-new-wordpress-blog)
-[Take down and restart your blog](#take-down-and-restart-your-blog)
-[Next Steps](#next-steps)
<!-- END MUNGE: GENERATED_TOC -->
## Cluster Requirements
Kubernetes runs in a variety of environments and is inherently
modular. Not all clusters are the same. These are the requirements for
this example.
* Kubernetes version 1.2 is required due to using newer features, such
at PV Claims and Deployments. Run `kubectl version` to see your
cluster version.
*[Cluster DNS](../../cluster/addons/dns/) will be used for service discovery.
* An [external load balancer](http://kubernetes.io/docs/user-guide/services/#type-loadbalancer)
Please see the [GCE getting started guide](../../docs/getting-started-guides/gce.md) for full details and other options for starting a cluster.
## Create the MySQL Password Secret
## Create two persistent disks
Use a [Secret](http://kubernetes.io/docs/user-guide/secrets/) object
to store the MySQL password. First create a temporary file called
`password.txt` and save your password in it. Make sure to not have a
trailing newline at the end of the password. The first `tr` command
will remove the newline if your editor added one. Then, create the
Secret object.
For this WordPress installation, we're going to configure our Kubernetes [pods](../../docs/user-guide/pods.md) to use [persistent disks](https://cloud.google.com/compute/docs/disks). This means that we can preserve installation state across pod shutdown and re-startup.
You will need to create the disks in the same [GCE zone](https://cloud.google.com/compute/docs/zones) as the Kubernetes cluster. The default setup script will create the cluster in the `us-central1-b` zone, as seen in the [config-default.sh](../../cluster/gce/config-default.sh) file. Replace `$ZONE` below with the appropriate zone.
This secret is referenced by the MySQL and WordPress pod configuration
so that those pods will have access to it. The MySQL pod will set the
database password, and the WordPress pod will use the password to
access the database.
We will create two disks: one for the mysql pod, and one for the wordpress pod. In this example, we create 20GB disks, which will be sufficient for this demo. Feel free to change the size to align with your needs, as wordpress requirements can vary. Also, keep in mind that [disk performance scales with size](https://cloud.google.com/compute/docs/disks/#comparison_of_disk_types).
## Deploy MySQL
First create the mysql disk.
Now that the persistent disks and secrets are defined, the Kubernetes
claim is satisfied by any volume that meets the requirements, in our
case one of the volumes we created above.
Also look at the `env` section and see that we specified the password
by referencing the secret `mysql-pass` that we created above. Secrets
can have multiple key:value pairs. Ours has only one key
`password.txt` which was the name of the file we used to create the
secret. The [MySQL image](https://hub.docker.com/_/mysql/) sets the
database password using the `MYSQL_ROOT_PASSWORD` environment
variable.
It may take a short period before the new pod reaches the `Running`
state. List all pods to see the status of this new pod.
```shell
kubectl get pods
```
```
## Start the Mysql Pod and Service
Now that the persistent disks are defined, the Kubernetes pods can be launched. We'll start with the mysql pod.
### Start the Mysql pod
First, **edit [`mysql.yaml`](mysql.yaml)**, the mysql pod definition, to use a database password that you specify.
`mysql.yaml` looks like this:
<!-- BEGIN MUNGE: EXAMPLE mysql.yaml -->
```yaml
apiVersion:v1
kind:Pod
metadata:
name:mysql
labels:
name:mysql
spec:
containers:
-resources:
limits :
cpu:0.5
image:mysql:5.6
name:mysql
env:
-name:MYSQL_ROOT_PASSWORD
# change this
value:yourpassword
ports:
-containerPort:3306
name:mysql
volumeMounts:
# name must match the volume name below
-name:mysql-persistent-storage
# mount path within the container
mountPath:/var/lib/mysql
volumes:
-name:mysql-persistent-storage
gcePersistentDisk:
# This GCE PD must already exist.
pdName:mysql-disk
fsType:ext4
```
```
NAME READY STATUS RESTARTS AGE
[Download example](mysql.yaml?raw=true)
wordpress-mysql-cqcf4-9q8lo 1/1 Running 0 1m
<!-- END MUNGE: EXAMPLE mysql.yaml -->
Note that we've defined a volume mount for `/var/lib/mysql`, and specified a volume that uses the persistent disk (`mysql-disk`) that you created.
Once you've edited the file to set your database password, create the pod as follows, where `<kubernetes>` is the path to your Kubernetes installation:
It may take a short period before the new pod reaches the `Running` state.
Kubernetes logs the stderr and stdout for each pod. Take a look at the
List all pods to see the status of this new pod and the cluster node that it is running on:
logs for a pod by using `kubectl log`. Copy the pod name from the
`get pods` command, and then:
```sh
```shell
$ kubectl get pods
kubectl logs <pod-name>
```
```
#### Check the running pod on the Compute instance
You can take a look at the logs for a pod by using `kubectl.sh log`. For example:
```sh
$ kubectl logs mysql
```
```
...
If you want to do deeper troubleshooting, e.g. if it seems a container is not staying up, you can also ssh in to the node that a pod is running on. There, you can run `sudo -s`, then `docker ps -a` to see all the containers. You can then inspect the logs of containers that have exited, via `docker logs <container_id>`. (You can also find some relevant logs under `/var/log`, e.g. `docker.log` and `kubelet.log`).
2016-02-19 16:58:05 1 [Note] InnoDB: 128 rollback segment(s) are active.
2016-02-19 16:58:05 1 [Note] InnoDB: Waiting for purge to start
2016-02-19 16:58:05 1 [Note] Server hostname (bind-address): '*'; port: 3306
We'll define and start a [service](../../docs/user-guide/services.md) that lets other pods access the mysql database on a known port and host.
2016-02-19 16:58:05 1 [Note] IPv6 is available.
We will specifically name the service `mysql`. This will let us leverage the support for [Docker-links-compatible](../../docs/user-guide/services.md#how-do-they-work) service environment variables when we set up the wordpress pod. The wordpress Docker image expects to be linked to a mysql container named `mysql`, as you can see in the "How to use this image" section on the wordpress docker hub [page](https://registry.hub.docker.com/_/wordpress/).
2016-02-19 16:58:05 1 [Note] - '::' resolves to '::';
2016-02-19 16:58:05 1 [Note] Server socket created on IP: '::'.
So if we label our Kubernetes mysql service `mysql`, the wordpress pod will be able to use the Docker-links-compatible environment variables, defined by Kubernetes, to connect to the database.
Here we are using many of the same features, such as a volume claim
for persistent storage and a secret for the password.
## Start the WordPress Pod and Service
The [WordPress image](https://hub.docker.com/_/wordpress/) accepts the
database hostname through the environment variable
Once the mysql service is up, start the wordpress pod, specified in
`WORDPRESS_DB_HOST`. We set the env value to the name of the MySQL
[`wordpress.yaml`](wordpress.yaml). Before you start it, **edit `wordpress.yaml`** and **set the database password to be the same as you used in `mysql.yaml`**.
service we created: `wordpress-mysql`.
Note that this config file also defines a volume, this one using the `wordpress-disk` persistent disk that you created.
<!-- BEGIN MUNGE: EXAMPLE wordpress.yaml -->
```yaml
apiVersion:v1
kind:Pod
metadata:
name:wordpress
labels:
name:wordpress
spec:
containers:
-image:wordpress
name:wordpress
env:
-name:WORDPRESS_DB_PASSWORD
# change this - must match mysql.yaml password
value:yourpassword
ports:
-containerPort:80
name:wordpress
volumeMounts:
# name must match the volume name below
-name:wordpress-persistent-storage
# mount path within the container
mountPath:/var/www/html
volumes:
-name:wordpress-persistent-storage
gcePersistentDisk:
# This GCE PD must already exist.
pdName:wordpress-disk
fsType:ext4
```
[Download example](wordpress.yaml?raw=true)
The WordPress service has the setting `type: LoadBalancer`. This will
<!-- END MUNGE: EXAMPLE wordpress.yaml -->
set up the wordpress service behind an external IP.
Create the pod:
Find the external IP for your WordPress service. **It may take a minute
to have an external IP assigned to the service, depending on your
or by listing the forwarding rules for your project:
> Warning: Do not leave your WordPress installation on this page. If
> it is found by another user, they can set up a website on your
> instance and use it to serve potentially malicious content. You
> should either continue with the installation past the point at which
> you create your username and password, delete your instance, or set
> up a firewall to restrict access.
```sh
## Take down and restart your blog
$ gcloud compute forwarding-rules list
```
Look for the rule called `wpfrontend`, which is what we named the wordpress service, and note its IP address.
Set up your WordPress blog and play around with it a bit. Then, take
down its pods and bring them back up again. Because you used
persistent disks, your blog state will be preserved.
## Visit your new WordPress blog
All of the resources are labeled with `app=wordpress`, so you can
easily bring them down using a label selector:
To access your new installation, you first may need to open up port 80 (the port specified in the wordpress service config) in the firewall for your cluster. You can do this, e.g. via:
This will define a firewall rule called `sample-http` that opens port 80 in the default network for your project.
Later, re-creating the resources with the original commands will pick
up the original disks with all your data intact. Because we did not
delete the PV Claims, no other pods in the cluster could claim them
after we deleted our pods. Keeping the PV Claims also ensured
recreating the Pods did not cause the PD to switch Pods.
Now, we can visit the running WordPress app.
If you are ready to release your persistent volumes and the data on them, run:
Use the external IP that you obtained above, and visit it on port 80:
```
```shell
http://<external-ip>
kubectl delete pvc -lapp=wordpress
```
```
You should see the familiar WordPress init page.
And then delete the volume objects themselves:
## Take down and restart your blog
Set up your WordPress blog and play around with it a bit. Then, take down its pods and bring them back up again. Because you used persistent disks, your blog state will be preserved.
```shell
kubectl delete pv local-pv-1 local-pv-2
If you are just experimenting, you can take down and bring up only the pods: