Make sure that you've taken a look at the following tutorial(s) before you continue:
- - First steps
- $300 free trial. How to use it wisely ?
- Let's get MySQL up and running on Kubernetes
Persistent storage for WordPress should be created by now. Persistent disk should be formatted and detached from the instance. GitLab account should be created and you should have an existing GitLab project.
In this tutorial example.com will be used for project's domain name and example for project name and some prefixes. Commands presented in this tutorial should be executed from the root of tutorial's git repository.
You are going to learn
- how to build your own docker image
- how to push this image to a remote container registry
- how to use remote container registry with Kubernetes
- how to create a Config Map
- WordPress on Kubernetes
- 1Build a custom WordPress docker image
- 2Configure GitLab container registry and push WordPress docker image
- 3Create GitLab container registry Secret
- 4Create Secrets and Config Maps
- 5Create Persistent Volume and Claim
- 6Create Deployment with GitLab hosted docker image
- 7Examine the Pod
- 8WordPress data on persistent drive
- 9Create MySQL database for WordPress
- 10Create Load Balancer Service for WordPress
WordPress on Kubernetes
With this tutorial you are going to dive a little deeper into containers. You are going to build a custom image and then run it on Kubernetes. You could potentially use official WordPress image just like you did with MySQL in the previous part of the tutorial. What would be the fun in that ? Am I right ?
By building, pushing and then pulling a custom container image you gain the knowledge needed to do the same for any other type of the project. Let’s not waste anymore of your time for theory.
VOLUME /var/www/example.com WORKDIR /var/www/example.com
Build WordPress docker image based on the
Dockerfile you've just modified. Modify
PROJECT_NAME to fit your data. Image will be named
wordpress and it will be tagged with version number
Container registry is where you place the docker images that have been built successfully. The most known container registry is Docker Hub. Both Google Cloud Platform and GitLab have their own container registries as well. The reasons why in this tutorial we use GitLab container registry is because it is more cloud platform supplier independent approach. GitLab has much more to offer than just that. You will learn all about it in next part of this tutorial series.
Login to your container registry
Push docker image to GitLab container registry
Kubernetes needs to login to our container registry of choice. For that it requires
.docker/config.json file. All you need to know for now is that files and other data are passed to Kubernetes using resources such as or .
.docker/config.json file needs to be wrapped in a Secret.
First you need to encode this file with
base64 and then put the resulting string inside the
k8s/other/registry-gitlab-secret.yaml file. Newlines are not valid within base64 string. Kubernetes will use created Secret to authorize itself when pulling an image is required. The name of this Secret is used later inside a declaration in
Create Secret that will hold the file
The Secret should be created inside your namespace. Verify it by checking the
metadata.creationTimestamp section of the Secret
are just like but they are not ... secret. Edit
k8s/wordpress/configmap.yaml and adjust it to fit your needs before creating it. First find and replace example.com with your domain name and then find and replace example with your project name. Set all the values just as if you were defining WordPress constants in
Choose username and password for MySQL database user that will be used by WordPress. Do not use the same name for user and database (WP CLI has problems if you do). Encode both values using
WordPress requires randomized key and salt values retrieved from the API. Use bash script I've created to generate a file containing Secret with those values in base64 encoded form. Script needs
curl, sed and
base64 to work.
Paste contents of the resulting file inside
k8s/wordpress/secret.yaml. Don't forget to modify the name of the Secret to match the pattern
PROJECT_NAME-wp-secret. Deployment assumes that the name of this Secret will match this pattern. Finally create the Secret.
Following steps are somewhat similar to what was done for MySQL in the previous part of this tutorial series. You need to let your know which persistent disk should be used. Modify
k8s/wordpress/volume.yaml by replacing example with your project's name and paste your WordPress disk's name into
pdName. If you've used another name than main for your namespace then do not forget to modify it accordingly inside
k8s/wordpress/volume.yaml as well.
gcePersistentDisk: pdName: WORDPRESS_DISK_NAME fsType: ext4
Create Persistent Volume and have a look at it.
Create a Persistent Volume Claim that was referenced inside our Persistent Volume declaration
At the top you'll find
metadata.labels section. Notice the three labels. They will be used by the Service to select this Deployment.
The Deployment declaration has a single container ( in
spec.containers ) which is using an image pulled from your GitLab container registry. Change the image property to reflect your docker image URL.
There are a lot of environmet variables defined there. Some of them are based on the Config Map others on those two Secrets that have just been created.
wp-config.php file processes only those environment variables that are prefixed with
wp-config.php declares WordPress constants using the name of the environment variable without the prefix.
At the bottom of the file you will find
volumes section. This is where you tell the Deployment which Persistent Volume Claim should be mounted. Now find a related section
volumeMounts. This is where you tell the Deployment where to mount that volume. All important WordPress data (
wp-content/ directory) is going to be kept on this volume which in fact is a persistent disk.
Create WordPress Deployment. It might take some time. After the image is pulled, Kubernetes will try to run it. If everything is fine then the Deployment becomes available.
First learn how to run a command on your Pod by printing it's environment variables.
Let's connect to the Pod that the Deployment has created and run bash. Notice that we use options
-it which I read as interactive to remember it easily but it really means:
-i - pass stdin to the container -t - stdin is a TTY
bash login shell is started (
-l option). Starting a login shell will cause
/etc/profile to be executed which then runs
/etc/bash.bashrc. Those files are copied to your docker image when you build it.
When using login shell you will get customized command prompt and some file listing command aliases you might already know and cherish like:
Have you ever looked in the mirror wondering who you are, where you are and what is your name ? Three simple commands will give you the answers you've been looking for
Copy the source WordPress
wp-content/ directory to your mounted persistent drive. This is where nginx and WordPress are expecting it to be.
Connect to MySQL database from the Pod.
Create database and user for WordPress. Grant all privileges on that database to the user. Substitute
example with your values.
Create a Load Balancer Service for WordPress deployment. This Service exposes port 80 and points to Pods matching the selector
app: example and
tier: frontend. When a Load Balancer is created additional charges start applying. Google charges you for something called Network Load Balancing: Forwarding Rule Minimum Service Charge. Monthly cost of this is about the same as the cost of one g1-small instance ( approx. $20). Check Useful links for pricing details link.
In the next part of the tutorial series you will configure your own nginx based Load Balancer so in the end you will only need one forwarding rule to service multiple domains from your cluster.
It takes some time for your Service to get an external IP.
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE wordpress-lb 10.99.255.100 <pending> 80:31999/TCP 9s wordpress-mysql None <none> 3306/TCP 1d
... and after a while
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE wordpress-lb 10.99.255.100 22.214.171.124 80:31999/TCP 2m wordpress-mysql None <none> 3306/TCP 1d
Do not start WordPress installation process just yet. You should see WordPress installation page when you visit http://EXTERNAL-IP
For the data above it would be: http://126.96.36.199
Have a look at the Service you've just created. It has the type set to LoadBalancer. That means that during the creation process Google Compute Engine Load Balancer has been provisioned for this Service.
Look at the forwarding rule that has been created in the process
You can also use UI to view your Load Balancers. Google Cloud Platform ConsoleNetwork ServicesLoad balancing
This Service is not going to be used in the next part of the tutorial series so go ahead and delete it.
Forwarding rules - a word of caution
Please take notice of the following. Deleting your Google Compute Engine Load Balancer Service does not remove the forwarding rule.
You can at the same time have no Services present and be charged for load balancing. Once the Service is deleted you can remove the forwarding rule using
Do not remove forwarding rule if your Service is up and you are still using the corresponding Load Balancer.
Think of forwarding rule as a kind of the connection between your Load Balancer and the outside world (eg. DNS). When you destroy a Load Balancer and re-create it then it will probably get different IP but it will be connected to the same forwarding rule. This way you do not need to change your DNS A record and point your domain to another IP address every time you make changes inside your cluster.