Deploying a Ghost Blog on Kubernetes: A Step-by-Step Guide
In this post, I'll show you how I set up my blog using Ghost on Kubernetes. Ghost is a sleek, powerful blogging platform built for simplicity and speed, making it a favorite among bloggers and digital publications.
In this post, I'm excited to show you how I rolled out my blog using the sleek Ghost platform on Kubernetes. It's the very setup powering this post!
What is Ghost?
Ghost is a powerful blogging platform built on modern technology stack. It is designed for simplicity and speed, with a focus on content-first blogging. Its minimalistic design and powerful features make it a favorite among bloggers, journalists, and digital publications.
Preparing Your Kubernetes Secrets
In our blog deployment, we utilize Kubernetes Secrets to securely store MySQL and SMTP passwords. Secrets are pivotal for protecting sensitive information like passwords, OAuth tokens, and SSH keys. They help keep this data secure and separate from your application's codebase, offering both security enhancements and easier data management. Below, we’ll show you how to set up and manage these Secrets using console commands:
Step 1: Create the Secret
You can create a secret using the kubectl create secret
command directly. For instance, to store your database and SMTP credentials:
kubectl create secret generic ghost-app-secrets \
--from-literal=mysql-password=your_database_password \
--from-literal=smtp-password=your_smtp_password
This command creates a secret named ghost-app-secrets
with two entries: password
and smtp-password
.
Preparing Your Kubernetes Manifest
The Kubernetes manifest file defines how your Ghost application will run and be managed within a Kubernetes cluster. Here’s a breakdown of the key components of the manifest file you will need:
Deployment Configuration
apiVersion: apps/v1
kind: Deployment
metadata:
name: ghost-app
labels:
app: ghost-app
spec:
replicas: 1
selector:
matchLabels:
app: ghost-app
template:
metadata:
labels:
app: ghost-app
spec:
containers:
- name: ghost-app
image: ghost:5.72.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 2368
This configuration sets up a deployment named ghost-app
. It specifies a single replica of the Ghost container using the image ghost:5.72.0
and exposes it on port 2368.
Persistent Storage
volumeMounts:
- name: nfs-ghost-app-content
mountPath: /var/lib/ghost/content
Persistent volumes are essential for a stateful application like Ghost to ensure that your data is saved across pod restarts. In this example, an NFS server is used to mount the content directory of Ghost.
Environment Configuration
env:
- name: database__client
value: mysql
- name: database__connection__host
value: 192.168.1.8
- name: database__connection__user
value: user
- name: database__connection__password
valueFrom:
secretKeyRef:
name: ghost-app-secrets
key: mysql-password
- name: database__connection__database
value: ghost
- name: useNullAsDefault
value: "true"
- name: debug
value: "false"
- name: url
value: https://myblog.com/
- name: mail__transport
value: SMTP
- name: mail__from
value: [email protected]
- name: mail__options__service
value: SMTP
- name: mail__options__host
value: smtp.sendgrid.net
- name: mail__options__port
value: "587"
- name: mail__options__auth__user
value: apikey
- name: mail__options__auth__pass
valueFrom:
secretKeyRef:
name: ghost-app-secrets
key: smtp-password
Environment variables are used to configure the Ghost instance, specifying database settings and the URL where the blog will be hosted. The mail__transport
configuration allows Ghost to send emails through SMTP, crucial for blog notifications and user interactions.
Once you have your manifest prepared:
- Apply the manifest: Use
kubectl apply -f your-manifest.yaml
to create the resources on your Kubernetes cluster. - Verify deployment: Ensure that the pod is up and running without errors using
kubectl get pods
. - Access your blog: Once everything is set up, you can access your Ghost blog via the URL defined in the environment variables.
Handling External Traffic with MetalLB in a LAN Environment
Here’s how MetalLB is configured to facilitate access to your Ghost deployment:
Configuring the Load Balancer
apiVersion: v1
kind: Service
metadata:
name: ghost-app-lb
spec:
selector:
app: ghost-app
ports:
- port: 80
targetPort: 2368
name: http
protocol: TCP
type: LoadBalancer
loadBalancerIP: 192.168.1.9
Key Features of the Load Balancer:
- Selector: This specifies which pods receive traffic by matching the labels. Here, it's set to target pods with the label
app: ghost-app
. - Ports: Defines the port mapping. External traffic on port 80 is routed to port 2368 on the pod running Ghost.
- Load Balancer IP: This is the specific IP address assigned to the load balancer. In this case,
192.168.1.9
is used, which would typically be an internally routable IP in a private cloud or on-premise data center.
Deploying the Load Balancer
Just like deploying the Ghost app, you deploy the load balancer service using kubectl
:
kubectl apply -f your-load-balancer-manifest.yaml
Final Manifest File
apiVersion: apps/v1
kind: Deployment
metadata:
name: ghost-app
labels:
app: ghost-app
spec:
replicas: 1
selector:
matchLabels:
app: ghost-app
template:
metadata:
labels:
app: ghost-app
spec:
containers:
- name: ghost-app
image: ghost:5.72.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 2368
volumeMounts:
- name: nfs-ghost-app-content
mountPath: /var/lib/ghost/content
env:
- name: database__client
value: mysql
- name: database__connection__host
value: 192.168.1.8
- name: database__connection__user
value: tim
- name: database__connection__password
valueFrom:
secretKeyRef:
name: ghost-app-secrets
key: mysql-password
- name: database__connection__database
value: ghost
- name: useNullAsDefault
value: "true"
- name: debug
value: "false"
- name: url
value: https://myblog.com/
- name: mail__transport
value: SMTP
- name: mail__from
value: [email protected]
- name: mail__options__service
value: SMTP
- name: mail__options__host
value: smtp.sendgrid.net
- name: mail__options__port
value: "587"
- name: mail__options__auth__user
value: apikey
- name: mail__options__auth__pass
valueFrom:
secretKeyRef:
name: ghost-app-secrets
key: smtp-password
volumes:
- name: nfs-ghost-app-content
nfs:
server: 192.168.1.10
path: /mnt/ext1/docker/ghost-app-content
readOnly: no
Conclusion
Deploying Ghost on Kubernetes not only leverages the strengths of a containerized environment but also ensures that your blog can scale and recover from failures more effectively. With Kubernetes, you can focus more on creating content and less on managing servers.