Deploy a WordPress blog as a Kubernetes cluster using a WordPress Helm chart that can be versioned.
Requirements
Docker
Git
Lens
K3d/K3s, Helm, Kubectl
Clone WordPress-Helm Repo
Clone the hardened Ansible-based wordpress-helm repository from open.greenhost.net
cd /Users/derungsm/_git && \
git clone https://open.greenhost.net/openappstack/wordpress-helm.git && \
cd wordpress-helm
A lot of work went into this helm chart to make deployments easy. Open the repo in code editor and view the README. There are a lot of options for deployment. Not all options will apply. Also see notes on the Bitnami MariaDB helm chart.
Download and store the repo's WordPress and WordPress CLI Docker images from the wordpress-helm container registry.
docker pull open.greenhost.net:4567/openappstack/wordpress-helm/wordpress:0.3.1 && \
docker pull open.greenhost.net:4567/openappstack/wordpress-helm/wordpress-cli-ansible:0.3.1
Pull a specific tag. The "latest" is not always found in manifest.
Customize Deploy
Copy values.local.yaml.example => values-local.yaml and make edits.
set wordpress.config.adm.usid
=> blog-admin
set wordpress.config.adm.pssw
=> blog-admin_password
add wordpress.config.adm.email
=> blog-admin@domain.extension
set wordpress.site.url
=> ????????
set wordpress.site.title
=> blog-title
add wordpress.site.version
=> 5.8.1
set database.auth.database
=> blog
set database.auth.username
=> wordpress-admin
set database.auth.password
=> wordpress-admin-password
set database.auth.rootPassword
=> wordpress-admin-password
set database.auth.replicationPassword
=> wordpress-admin-password
set themes_install
=> bloggist, twentytwentyone
set theme_active
=> bloggist
set theme_fallback
=> twentytwentyone
Copy install.sh.example => install.sh and make the script executable
chmod +x install.sh
Create Cluster
Create a three-node cluster called "k3s-wordpress" and expose Kubernetes API on a port that does not conflict with any other clusters already running (though the API port is not strictly necessary)
k3d cluster create k3s-wordpress --api-port 6551 --agents 2
If you get the error "Unable to connect to the server: x509: certificate signed by unknown authority" (typically in a secondary tab on Mac when trying to run kubectl commands like
kubectl get pods
), then set the API context withexport KUBECONFIG=$(k3d kubeconfig write k3s-wordpress)
. It could also mean you need to clear the K3d.kube/cache
folders.
Deploy WordPress
Set the API context
export KUBECONFIG=$(k3d kubeconfig write k3s-wordpress)
expected output
/Users/derungsm/.k3d/kubeconfig-k3s-wordpress.yamlAdd the Bitnami charts repository to Helm
helm repo add bitnami https://charts.bitnami.com/bitnami
Get all helm dependencies from the Git working directory
helm dependency update
This avoids the error "found in Chart.yaml, but missing in charts/ directory: mariadb, redis)"
expected output
Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "rancher-stable" chart repository ...Successfully got an update from the "rancher-latest" chart repository ...Successfully got an update from the "bitnami" chart repository Update Complete. ⎈Happy Helming!⎈ Saving 2 charts Downloading mariadb from repo https://charts.bitnami.com/bitnami Downloading redis from repo https://charts.bitnami.com/bitnami Deleting outdated chartsRun the install script
./install.sh
expected output
Release "wordpress-production" does not exist. Installing it now. NAME: wordpress-production LAST DEPLOYED: Tue Oct 5 12:33:24 2021 NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: NoneMonitor progress with Watch utility (brew install watch
)
watch kubectl get all
It can take about 5 minutes for pod/wordpress-production0 to enter a running state and 5.5 min for statefulset/apps/wordpress-production to enter ready state.
Check status
kubectl -n default rollout status statefulset wordpress-production kubectl get all
View Setup in Lens
Open Lens and view performance. May need to save the context first:
k3d kubeconfig write k3s-wordpress -o ``pwd``/kubeconfig-k3d-dev
Import Existing WordPress Database
Get a dump of the current WordPress database from existing server to Mac
scp -r user@server:/home/backup/mysqldump/blog.sql .
Upload dump file to K3d PV
kubectl exec -i wordpress-production-database-primary-0 \
-- mysql \
-uwordpress \
-ppassword \
--database=blog < ./data/blog.sql
Moving WordPress to a different URL/environment means changing the site and home urls in the database. For example, to work with the database on locally (localhost):
Connect to the database running in K3s
kubectl exec -it \
wordpress-production-database-primary-0 \
--namespace=default \
-- /bin/bash
-it
means the same as--stdin --tty
or-i -t
Access/review the database/settings
mysql -u root -p
use wp_database_name;
show tables;
SELECT option_name, option_value
FROM blog.wp_option
WHERE option_name
LIKE 'siteurl'
OR option_name
LIKE 'home';
Update the URLs
UPDATE database_name.wp_options
SET option_value = replace(option_value, 'https://somedomain/blog', 'http://localhost');
In my case, I also needed to change the URLs for an SSO Plugin For Azure AD to allow a "http://localhost/wp-admin" login with "http://localhost/?sso_for_azure_ad=callback" callback:
SELECT *
FROM wp_database_name.wp_options
WHERE option_name
LIKE 'sso%';
UPDATE wp_database_name.wp_options
SET option_value = '12345abc-b723-2229-aa00-03b0ece6eac5'
WHERE option_name
LIKE 'sso_for_azure_ad_client_id';
UPDATE wp_database_name.wp_options
SET option_value = 'aHgO.0_rU5NFGCtufooe0-AY_~Obuzz3nc'
WHERE option_name
LIKE 'sso_for_azure_ad_client_secret';
The ids and secrets are fake, but you get the idea.
Extras
Connect to the primary or secondary database PV
kubectl exec -it \
wordpress-production-database-primary-0 \
--namespace=default \
-- /bin/bash
kubectl exec -it \
wordpress-production-database-secondary-0 \
--namespace=default
-- /bin/bash
File structure of database PVs
/bitnami/mariadb/data/mysql
/opt/bitnami/mariadb/bin/mysql
/opt/bitnami/mariadb/include/mysql
/opt/bitnami/mariadb/include/mysql/mysql
/opt/bitnami/mariadb/include/ysql/server/mysql
Import Existing WordPress Admin Content
Copy files from server to Mac
scp -r user@server:/var/www/html/blog/wp-content .
Copy files from Mac to K3d WordPress pod
kubectl cp ./data/wp-content/plugins wordpress-production-0:/var/www/wp-content-mount && \
kubectl cp ./data/wp-content/themes wordpress-production-0:/var/www/wp-content-mount && \
kubectl cp ./data/wp-content/uploads wordpress-production-0:/var/www/wp-content-mount
Change ownership of the files to UID 33 (the www-data
user in the WordPress container):
kubectl exec -it wordpress-production-0 -- chown -R 33:33 /var/www/wp-content-mount
This may say
chown: changing ownership of '/var/www/wp-uploads-mount/.htaccess': Read-only file system
, which is the mounted.htaccess
file. Ownership of all the other files will have changed.
Check uploads
kubectl exec -it \
wordpress-production-0 \
--namespace=default \
-- /bin/bash
ls -la /var/www/html
ls -la /var/www/wp-content-mount
ls -la /var/www/wp-uploads-mount
Remove the default plugins (Classic Editor) from inside the pod
rm -rf /var/www/wp-content-mount/plugins/classic-editor
Remove the default plugins (Classic Editor) from outside the pod
kubectl delete wordpress-production-0:/var/www/wp-content-mount/plugins/classic-editor
Browse the Site
Forward the k3s-wordpress port to Mac - make sure that this URL doesn't go through the proxy
export KUBECONFIG=$(k3d kubeconfig write k3s-wordpress) && \
sudo -E kubectl port-forward service/wordpress-production 80:8080
Port 80 is generally reserved, so use
sudo
with the-E
flag to pass the KUBECONFIG environment to kubectl
Backout
Delete pods, services and statefulsets
./delete.sh
Modify release name in variables.sh if not using git repo
Stop the cluster
k3d cluster stop k3s-wordpress
(or restart the Docker Engine)
If the init container fails rebuilding WordPress, see workaround
Stop and remove the cluster
k3d cluster stop k3s-wordpress && \ k3d cluster delete k3s-wordpress
To Do
- Get a version of the wordpress-helm images from Azure Container Registry using authentication.
- Get an outside dump file from inside the K3s pod directly.
- Get outside wp-content from inside the K3s pod directly.
- Automate WordPress content and database backups to external host.
References
Install WordPress in Kubernetes
- https://habd.as/post/deadsimple-wordpress-kubernetes/
- https://habd.as/post/k3s-wordpress-redis-helm-macos/
Simple Nginx web server
Wordpress Helm
- https://kubernetes.io/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/
- https://github.com/helm/charts/tree/master/stable/wordpress
- https://github.com/bitnami/bitnami-docker-wordpress
- https://hub.docker.com/r/bitnami/wordpress-nginx/tags/?page=1&ordering=last_updated
- https://www.bogotobogo.com/DevOps/Docker/Docker_Helm_Chart_WordPress_MariaDB_Minikube_with_Ingress.php
- https://github.com/bitnami/charts/tree/master/bitnami/wordpress
Persistent Volumes and Claims
- https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes
- https://kubernetes.io/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/
Lens