Application Demo: Ghost Blog
This tutorial explains how to run Ghost on APPUiO Cloud.
If you aren’t familiar with issuing commands on a terminal session, we recommend familiarizing yourself with it before continuing this tutorial.
Requirements
To follow this guide, please make sure that you have the following tools installed:
oc
-
You can download the OpenShift command directly from APPUiO Cloud, selecting the help menu (marked as a question mark) and selecting the "Command line tools" entry
About the Application
Ghost is a powerful app for new-media creators to publish, share, and grow a business around their content. It comes with modern tools to build a website, publish content, send newsletters & offer paid subscriptions to members.
Step 1: Create a Project
All the following steps are currently only working on the Exoscale APPUiO Zone because of the Application Catalog service availability. |
Follow these steps to login to APPUiO Cloud on your terminal:
-
Login to the APPUiO Cloud console:
oc login --server=https://api.${zone}.appuio.cloud:6443
You can find the exact URL of your chosen zone in the APPUiO Cloud Portal.
This command displays a URL on your terminal:
You must obtain an API token by visiting https://oauth-openshift.apps.${zone}.appuio.cloud/oauth/token/request
-
Click on the link above and open it in your browser.
-
Click "Display token" and copy the login command shown as "Log in with this token"
-
Paste the
oc login
command on the terminal:oc login --token=sha256~_xxxxxx_xxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxx-X \ --server=https://api.${zone}.appuio.cloud:6443
-
Create a new project called "[YOUR_USERNAME]-application-demo"
oc new-project "[YOUR_USERNAME]-application-demo"
Step 2: Deploy the application
To deploy the application we will use standard Kubernetes objects.
Save the example YAML Kubernetes resources into a file and apply it with oc apply -f <myfile.yaml>
.
-
First, we need a database:
Database ordering from the VSHN Application CatalogapiVersion: exoscale.appcat.vshn.io/v1 kind: ExoscaleMySQL metadata: name: example-app spec: writeConnectionSecretToRef: name: mysql-creds
This will create a MySQL DBaaS instance with default settings. See the AppCat docs for more information.
-
Then we deploy the application:
Application deployment with all other needed resourcesapiVersion: apps/v1 kind: Deployment metadata: name: ghost labels: app.kubernetes.io/name: demo-app spec: selector: matchLabels: app.kubernetes.io/name: demo-app replicas: 1 strategy: type: Recreate template: metadata: labels: app.kubernetes.io/name: demo-app spec: containers: - name: ghost image: docker.io/bitnami/ghost:latest imagePullPolicy: Always env: - name: GHOST_DATABASE_HOST valueFrom: secretKeyRef: name: mysql-creds key: MYSQL_HOST - name: GHOST_DATABASE_PORT_NUMBER valueFrom: secretKeyRef: name: mysql-creds key: MYSQL_PORT - name: GHOST_DATABASE_NAME valueFrom: secretKeyRef: name: mysql-creds key: MYSQL_DB - name: GHOST_DATABASE_USER valueFrom: secretKeyRef: name: mysql-creds key: MYSQL_USER - name: GHOST_DATABASE_PASSWORD valueFrom: secretKeyRef: name: mysql-creds key: MYSQL_PASSWORD - name: GHOST_DATABASE_ENABLE_SSL value: "yes" - name: GHOST_DATABASE_SSL_CA_FILE value: /srv/db-ca/ca.crt - name: GHOST_BLOG_TITLE value: "APPUiO Cloud Demo" - name: GHOST_ENABLE_HTTPS value: "yes" ports: - name: web containerPort: 2368 protocol: TCP resources: limits: {} requests: {} volumeMounts: - name: app-data mountPath: /bitnami/ghost - name: db-ca mountPath: /srv/db-ca volumes: - name: app-data persistentVolumeClaim: claimName: app-data - name: db-ca secret: secretName: mysql-creds optional: false items: - key: ca.crt path: ca.crt --- apiVersion: v1 kind: Service metadata: name: example-app labels: app.kubernetes.io/name: demo-app spec: type: ClusterIP sessionAffinity: None ports: - name: web port: 443 protocol: TCP targetPort: web selector: app.kubernetes.io/name: demo-app --- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: app-data labels: app.kubernetes.io/name: demo-app spec: accessModes: - ReadWriteOnce resources: requests: storage: "1Gi" --- apiVersion: route.openshift.io/v1 kind: Route metadata: name: example-app spec: port: targetPort: web to: kind: Service name: example-app weight: 100 wildcardPolicy: None tls: termination: edge insecureEdgeTerminationPolicy: Redirect
-
Now wait until your pod appears with the status "Running":
oc get pods --watch
-
Last but not least retrieve the URL of your Ghost blog:
oc get route example-app -o jsonpath='{.spec.host}'
You can now login to your Ghost instance on /ghost
with the default credentials by the image:
-
Username: user@example.com
-
Password: bitnami123
This example configuration isn’t meant for a production ready service. |
What’s next?
For a production ready service, we recommend the following parts to be implemented and configured:
-
While the database is already being backed up because it’s a managed service, you should still backup your persistent volume with K8up.
-
Add some monitoring for your application:
-
Use your own URL with Let’s Encrypt.
-
Choose appropriate sizing:
-
Persistent storage volume size
-
-
Maybe you want to use an
RWX
storage class which allows you to scale your application by running multiple Pods. -
Configure proper requests and limits for your Pod.
-
Use a pinned image version and set the
imagePullPolicy
toIfNotPresent
. -
Keep your app up-to-date! Install patches and upgrades as they get available. One way to achieve that, is to use a GitOps style deployment, either push or pull, and leverage the mighty Renovate Bot to keep your image references clean.
-
Using a Helm Chart for production deployments or Kustomize setup for different stages can be an advantage.
Especially for this example application:
-
Change the default username and password immediately.
-
Review the documentation of the used image to learn more about the configuration and possibilities.
-
Ghost needs a proper mail sending configuration in production, we recommend using a managed mail sending service for that, for example Mailgun.
Once you’re done evaluating this example application, cleanup again to not cause any unwanted costs:
oc delete project [YOUR_USERNAME]-application-demo
We’re happy to help you running your application. Contact us and let us know how we can help. |