Ghost is an amazing open-source blogging platform. Managed hosting is available, but if you already have a Kubernetes cluster available, why not use it?
These steps are focused on Azure Kubernetes Services (AKS), but will mostly apply to AWS EKS or Google GKE. Additionally, this assumes that you are using NGINX Ingress Controller. Otherwise, you will have to customize the load balancer or ingress configuration. These instructions will use a SQLite database as opposed to the MySQL option.
Step 1: Create Namespace
apiVersion: v1
kind: Namespace
metadata:
name: ghost
Step 2: Register Azure Files Storage Class
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: azurefile
provisioner: kubernetes.io/azure-file
mountOptions:
- dir_mode=0777
- file_mode=0777
- uid=1000
- gid=1000
- mfsymlinks
- nobrl
- cache=none
parameters:
skuName: Standard_LRS
Step 3: Configure Persistent Volume Claim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ghost-claim
namespace: ghost
spec:
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName: azurefile
resources:
requests:
storage: 50Gi
Note: Azure Files with standard performance is billed per used GB. So you can over-provision the storage without paying extra.
Step 4: Deployment
Replace your URL in the following deployment script:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: ghost-3-2-0
namespace: ghost
labels:
app: ghost
release: 3.2.0
spec:
replicas: 1
selector:
matchLabels:
app: ghost
release: 3.2.0
template:
metadata:
labels:
app: ghost
release: 3.2.0
spec:
volumes:
- name: ghost-content
persistentVolumeClaim:
claimName: ghost-claim
containers:
- name: ghost-3-2-0
image: ghost:3.2.0-alpine
env:
- name: url
value: {{YOUR WEBSITE URL}}
volumeMounts:
- name: ghost-content
mountPath: /var/lib/ghost/content
resources:
limits:
cpu: "1"
memory: 256Mi
requests:
cpu: 100m
memory: 64Mi
ports:
- name: http
containerPort: 2368
protocol: TCP
restartPolicy: Always
Step 5: Service
apiVersion: v1
kind: Service
metadata:
name: ghost
namespace: ghost
spec:
type: ClusterIP
selector:
app: ghost
ports:
- protocol: TCP
port: 80
targetPort: 2368
Step 6: Ingress
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
name: ingress-ghost
namespace: ghost
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/backend-protocol: HTTP
nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: 16m
spec:
tls:
- hosts:
- {{HOST NAME ex. myghostblog.com}}
secretName: {{Kubernetes Secret name with TLS/SSL Certificate}}
rules:
- host: {{HOST NAME ex. myghostblog.com}}
http:
paths:
- path: /
backend:
serviceName: ghost
servicePort: 80
Note: this assumes you want to use TLS / SSL. You can modify the ingress for standard HTTP and skip the TLS Secret.
Step 7: Configure DNS
Update your DNS to point to the public IP address of your Kubernetes load balancer.
Step 8: Test it out
Connect to your site.
Step 9: Login
You can access the admin portal for Ghost at https://{{host name}}/ghost.
Thanks for reading! I'd love to hear your thoughts or questions.