ghost-on-kubernetes

Ghost on Kubernetes by SREDevOps.org - Deploy Ghost v6 on Kubernetes (k8s, k3s, etc) with our hardened distroless non root custom image.

View on GitHub

Ghost on Kubernetes by SREDevOps.Org

SREDevOps.org

SREDevOps.org: SRE, DevOps, Linux, Ethical Hacking, AI, ML, Open Source, Cloud Native, Platform Engineering en Español, Portugués (Brasil) and English

Build Multiarch Image Size OpenSSF Scorecard Fork this repository Star this repository OpenSSF Best Practices Artifact Hub

Introduction

This repository implements Ghost CMS v6.xx.x from @TryGhost (Official) on Kubernetes, with our custom image, which has significant improvements intended to be used on Kubernetes (Dockerfile). See this whole README for more information.

Features

Recent updates and changes

We’ve made some significant updates to improve the security and efficiency of our Ghost implementation on Kubernetes:

Installation Instructions

0. Clone the repository or fork it

  ## Clone the repository
  git clone https://github.com/sredevopsorg/ghost-on-kubernetes.git --depth 1 --branch main --single-branch --no-tags
  ## Change directory
  cd ghost-on-kubernetes
  ## Create a new branch for your changes (optional but   recommended).
  git checkout -b my-branch --no-track --detach

1. Check the example configurations

2. Edit the default values and make changes as needed

Remember to edit the values according to your needs, the details for every files are provided on each manifest file inside the deploy folder and the following steps.

Understanding the Ghost Deployment Architecture on Kubernetes

Deploying a sophisticated application like Ghost on Kubernetes involves orchestrating several components. Let’s break down the essential Kubernetes resources we’ll use:

Namespaces: Isolating Our Ghost Instance

Namespaces in Kubernetes provide a logical separation of resources. We’ll use the ghost-on-kubernetes namespace to contain all resources related to our Ghost deployment. This approach enhances organization and prevents resource conflicts with other applications running on the same cluster.

*Note*: You can even host multiple Ghost instances on the same cluster by replacing the Namespace specification in each manifest file.

Full file: deploy/00-namespace.yaml

# Source code example excerpt:
apiVersion: v1
kind: Namespace
metadata:
  name: ghost-on-kubernetes
  labels:
    app: ghost-on-kubernetes
    # ... other labels

Secrets: Securely Storing your Ghost Configuration

Secrets in Kubernetes allow us to store and manage sensitive data, such as database credentials and TLS certificates, securely. We’ll use the following Secrets:

Full file: deploy/01-mysql-config.yaml

Full file: deploy/04-ghost-config.yaml

Full file: deploy/01-tls.yaml

# Source code example excerpt:
apiVersion: v1
kind: Secret
metadata:
  name: ghost-config-prod
  namespace: ghost-on-kubernetes
  # ... other metadata
type: Opaque
stringData:
  config.production.json: |-
    {
      # ... Ghost configuration
    }

PersistentVolumeClaims: Persistent Storage for Our Blog

PersistentVolumeClaims (PVCs) in Kubernetes enable us to request persistent storage volumes. We’ll use two PVCs:

Full file: deploy/02-pvc.yaml

# Source code example excerpt:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: k8s-ghost-content
  namespace: ghost-on-kubernetes
  # ... other metadata
spec:
  # ... PVC specification

Services: Exposing Ghost and MySQL Within the Cluster

Services in Kubernetes provide a way to expose our applications running on a set of pods as a network service. We’ll define two services:

Full file: deploy/03-service.yaml

# Source code example excerpt:
apiVersion: v1
kind: Service
metadata:
  name: ghost-on-kubernetes-service
  namespace: ghost-on-kubernetes
  # ... other metadata
spec:
  # ... Service specification

StatefulSet: Managing the MySQL Database

A StatefulSet in Kubernetes is designed to manage stateful applications, such as databases, that require persistent storage and stable network identities. We’ll use a StatefulSet to deploy a single replica of the MySQL database.

Full file: deploy/05-mysql.yaml

# Source code example excerpt:
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: ghost-on-kubernetes-mysql
  namespace: ghost-on-kubernetes
  # ... other metadata
spec:
  # ... StatefulSet specification

Deployment: Managing the Ghost Application

Deployments in Kubernetes manage the deployment and scaling of stateless applications. We’ll use a Deployment to deploy a single replica of the Ghost application.

Full file: deploy/06-ghost-deployment.yaml

# Source code example excerpt:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ghost-on-kubernetes
  namespace: ghost-on-kubernetes
  # ... other metadata
spec:
  # ... Deployment specification

Ingress: Exposing Ghost to the Outside World

An Ingress resource in Kubernetes acts as a reverse proxy, routing external traffic to services within the cluster. We’ll use an Ingress to expose our Ghost blog to the internet using a domain name.

File: deploy/07-ingress.yaml

# Source code example excerpt:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ghost-on-kubernetes-ingress
  namespace: ghost-on-kubernetes
  # ... other metadata
spec:
  # ... Ingress specification

Bringing It All Together: Deploying Ghost on Kubernetes

With our Kubernetes resources defined, we can now deploy Ghost on our cluster. Follow these general steps:

IMPORTANT NOTE: You need to apply those commands or deploy files in order, or you could face inconsistences on your MySQL StatefulSet and/or other components.

  1. Create the Namespace:

    kubectl apply -f deploy/00-namespace.yaml
    
  2. Create the Secrets:

    kubectl apply -f deploy/01-mysql-config.yaml
    kubectl apply -f deploy/04-ghost-config.yaml
    kubectl apply -f deploy/01-tls.yaml
    
  3. Create the PersistentVolumeClaims:

    kubectl apply -f deploy/02-pvc.yaml
    
  4. Create the Services:

    kubectl apply -f deploy/03-service.yaml
    
  5. Deploy the MySQL Database:

    kubectl apply -f deploy/05-mysql.yaml
    
  6. Deploy the Ghost Application:

    kubectl apply -f deploy/06-ghost-deployment.yaml
    
  7. Expose Ghost with Ingress (Optional):

    kubectl apply -f deploy/07-ingress.yaml
    

Your Ghost Blog is deployed! 🎉

Congratulations! You’ve successfully deployed Ghost on a Kubernetes cluster. This setup provides a robust and scalable foundation for your blogging platform. Remember to customize the configurations, such as storage class, resource limits, and domain name, to suit your specific requirements.

A final trick: Access Ghost on Kubernetes without a domain name

If you want to use a port forwarding to preview the website, be sure to configure both url and admin URLs in the config file as http://localhost:2368/, resttart the pod and then run the kubectl port-forwarding like:

  kubectl port-forward -n ghost-on-kubernetes services ghost-on-kubernetes-service 2368:2368

Contributing

We welcome contributions from the community! Please check the CONTRIBUTING.md file for more information on how to contribute to this project.

License and Credits

Star History

Star History Chart