Strapi, a popular open-source headless CMS built on Node.js, streamlines content management for developers of all skill levels. It offers flexibility by allowing connection to preferred databases, frameworks, and static site generators, while also enabling content creation from any device. However, when working with Strapi in a Kubernetes environment, schema changes made through the admin panel can lead to data loss during pod restarts. This blog explores the challenges and proposes a solution for persistent storage of Strapi schema changes.
The challenge
Strapi primarily utilizes four directories - config, database, public, and src. While it's ideal to package all these directories within a Docker image, some schema changes made through the admin panel are stored locally on the pod's file system, specifically in the /opt/app/src directory.
Deploying Strapi on Kubernetes presents two significant challenges:
- Data loss: If a pod restarts due to errors or maintenance, any unsaved schema changes in the /opt/app/src directory are lost.
- Manual overhead: Rebuilding Docker images and redeploying the application after every schema change is time-consuming and inefficient.
The solution
One potential solution to this problem is to manually back up the /opt/app/src directory after making schema changes, rebuild the Docker image, and redeploy it. This approach ensures that the schema changes are preserved even if the pod restarts. However, this is a time-consuming and error-prone process, especially if pod restarts occur frequently.
Recently, we encountered a scenario where a pod restarted immediately after a schema change, preventing us from taking a backup and rebuilding the image. As a result, we lost the schema changes and had to manually delete the corresponding database entries and redo the changes.
Implementation steps
Step 1: Create a persistent volume claim (PVC) - Define a PVC to allocate storage for the /opt/app/src directory.
kind: PersistentVolumeClaim apiVersion: v1 metadata: name: strapi-src-claim spec: storageClassName: "gp2" accessModes: - "ReadWriteOnce" resources: requests: storage: "1G"
Step 2: Mount the PVC in deployment - Mount the PVC to the /opt/app/src directory in your Strapi deployment.
volumes: - name: strapi-src persistentVolumeClaim: claimName: strapi-src-claim volumeMounts: - name: strapi-src mountPath: /opt/app/src
Step 3: Initial data transfer - By adding these, you will have persistent storage for your schema changes. But this leads to another issue where the mounted PVC on /opt/app/src will be empty. It will not have the data present in the Docker image. To fix this issue you must run the initContainer the very first time when you mount the PVC.
initContainers: - name: copy-strapi-src image: "strapi:4.20.5" command: ["/bin/sh", "-c", "cp -r /opt/app/src/* /mnt/app-src/ || true"] volumeMounts: - name: strapi-src mountPath: /mnt/app-src
To ensure that the data within the Docker image is copied to the newly created Persistent Volume Claim (PVC), use an initContainer. This container will run before the main container, transferring the necessary data from the image to the PVC. Once the initial data transfer is complete, the initContainer can be removed.
Benefits of using PVCs
• Data persistence: Ensures that schema changes are preserved even after pod restarts.
• Simplified deployment: Reduces the need for frequent Docker image rebuilds and redeployments.
• Improved reliability: Mitigates risks associated with data loss and downtime.
By implementing PVCs, you can significantly enhance the reliability and efficiency of your Strapi deployment on Kubernetes. This solution provides a robust approach to managing schema changes, saving time and effort.