This blog is running the NodeJS based software called Ghost. It's hosted on a Digital Ocean droplet with Rancher's k3s. My goal with the setup was to remove all state from the container running Ghost and allow it to scale up if needed.

Out of the box Ghost will store all its configuration and data under /var/lib/ghost/content. You can mount a persistent volume in Kubernetes under this path however the backup story is much easier by removing state altogether.

This blog post will demonstrate how to achieve setting up a stateless container by moving images to a CDN (this blog uses Azure CDN) and a MySQL database.  


  • Kubernetes environment (k3s or K8s is fine)
  • MySQL host and database.
  • Azure Blob Storage Account with Azure CDN setup.
  • Docker and kubectl installed locally

Deploying Ghost

You'll need the following YAML to create the deployment, service, ingress and configmap in K8s.

To get started, download the below Gist:

In your editor, you will need to edit the configmap YAML with your database credentials and CDN address.

The deployment and ingress YAML needs updating with your blog's domain.

You will need to create a secret with your Azure Blob Storage connection string. Run the following kubectl command to create it.

kubectl create secret generic azure --from-literal=AZURE_STORAGE_CONNECTION_STRING="changeme"

This secret is referenced in the deployment YAML and will inject the environment variable AZURE_STORAGE_CONNECTION_STRING for the Azure ghost storage plugin.

Make sure your terminal is in the YAML directory and apply the updated YAML with

kubectl apply -f . 

Your blog should be available at your domain, browse to /ghost to run the admin setup guide.

Adding your own theme

To add your theme to ghost, you will need to create your own container image and upload your image.

Upload the theme (zipped) normally through the ghost admin portal

Fork the repository:

Update the script to copy your (uncompressed) theme into /var/lib/ghost/content/themes/. I'm using git to copy it in but you can also use the COPY command inside the Dockerfile.

If you do use the Dockerfile method, you will need to copy it to an interim location and copy to the themes directory using the entrypoint script. The themes/content directory doesn't exist at the time the Dockerfile is executes.

Build and push your new Docker image with

 docker build . -t docker-hub-username/ghostblog && docker push docker-hub-username/ghostblog

Once you have the theme in your docker image, update the deployment YAML image with your docker-hub-username/ghostblog and apply it with

kubectl apply -f ghost_deploy.yml

You can test that your theme stays applied by restarting your containers

kubectl rollout restart deploy ghost

Known Issues

  • If running multiple replicas, new posts show 404 when hitting the pods not aware of the new post.