|
| 1 | +--- |
| 2 | +slug: use-app-platform-to-deploy-wordpress |
| 3 | +title: "Use App Platform to Deploy WordPress with Persistent Volumes on LKE" |
| 4 | +description: "Two to three sentences describing your guide." |
| 5 | +authors: ["Akamai"] |
| 6 | +contributors: ["Akamai"] |
| 7 | +published: 2025-04-25 |
| 8 | +keywords: ['app platform','app platform for lke','lke','linode kubernetes engine','kubernetes','persistent volumes','mysql'] |
| 9 | +license: '[CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0)' |
| 10 | +external_resources: |
| 11 | +- '[Akamai App Platform for LKE](https://techdocs.akamai.com/cloud-computing/docs/application-platform)' |
| 12 | +- '[Akamai App Platform Documentation](https://apl-docs.net/docs/akamai-app-platform/introduction)' |
| 13 | +--- |
| 14 | + |
| 15 | +{{< note title="Beta Notice" type="warning" >}} |
| 16 | +The Akamai App Platform is now available as a limited beta. It is not recommended for production workloads. To register for the beta, visit the [Betas](https://cloud.linode.com/betas) page in the Cloud Manager and click the Sign Up button next to the Akamai App Platform Beta. |
| 17 | +{{< /note >}} |
| 18 | + |
| 19 | +This guide includes steps for deploying a WordPress site and persistent MySQL database using App Platform for Linode Kubernetes Engine (LKE). In this architecture, both WordPress and MySQL use PersistentVolumes (PV) and PersistentVolumeClaims (PVC) to store data. |
| 20 | + |
| 21 | +To add the WordPress and MySQL Helm charts to the App Platform Catalog, the **Add Helm Chart** feature of Akamai App Platform for LKE is used. |
| 22 | + |
| 23 | +## Prerequisites |
| 24 | + |
| 25 | +- A [Cloud Manager](https://cloud.linode.com/) account is required to use Akamai's cloud computing services, including LKE. |
| 26 | + |
| 27 | +- Enrollment into the Akamai App Platform's [beta program](https://cloud.linode.com/betas). |
| 28 | + |
| 29 | +- An provisioned and configured LKE cluster with App Platform enabled and [auto-scaling](https://techdocs.akamai.com/cloud-computing/docs/manage-nodes-and-node-pools#autoscale-automatically-resize-node-pools) turned on. A Kubernetes cluster consisting of 3 [Dedicated CPU Compute Instances](https://techdocs.akamai.com/cloud-computing/docs/dedicated-cpu-compute-instances) is sufficient for the deployment in this guide to run, but additional resources may be required during the configuration of your App Platform architecture. |
| 30 | + |
| 31 | + To ensure sufficient resources are available, it is recommended that node pool auto-scaling for your LKE cluster is enabled after deployment. Make sure to set the max number of nodes higher than your minimum. This may result in higher billing costs. |
| 32 | + |
| 33 | + To learn more about provisioning a LKE cluster with App Platform, see our [Getting Started with App Platform for LKE](https://techdocs.akamai.com/cloud-computing/docs/getting-started-with-akamai-application-platform) guide. |
| 34 | + |
| 35 | +## Components |
| 36 | + |
| 37 | +### Infrastructure |
| 38 | + |
| 39 | +- **Linode Kubernetes Engine (LKE)**: LKE is Akamai’s managed Kubernetes service, enabling you to deploy containerized applications without needing to build out and maintain your own Kubernetes cluster. |
| 40 | + |
| 41 | +- **App Platform for LKE**: A Kubernetes-based platform that combines developer and operations-centric tools, automation, self-service, and management of containerized application workloads. App Platform for LKE streamlines the application lifecycle from development to delivery and connects numerous CNCF (Cloud Native Computing Foundation) technologies in a single environment, allowing you to construct a bespoke Kubernetes architecture. |
| 42 | + |
| 43 | +### Software |
| 44 | + |
| 45 | +- [**MySQL**](https://www.mysql.com/): An open source database management system that uses a relational database and SQL (Structured Query Language) to manage its data. |
| 46 | + |
| 47 | +- [**WordPress**](https://wordpress.com/): The WordPress application is an industry standard, open source CMS (content management system) often used for creating and publishing websites. |
| 48 | + |
| 49 | +- [**Ingress NGINX Controller**](https://github.com/kubernetes/ingress-nginx): When creating a Service in App Platform, an `ingress` is created using NGINX's Ingress Controller to allow public access to internal services. |
| 50 | + |
| 51 | +## Set Up Infrastructure |
| 52 | + |
| 53 | +Once your LKE cluster is provisioned and the App Platform web UI is available, complete the following steps to continue setting up your infrastructure. |
| 54 | + |
| 55 | +Sign into the App Platform web UI using the `platform-admin` account, or another account that uses the `platform-admin` role. Instructions for signing into App Platform for the first time can be found in our [Getting Started with Akamai App Platform](https://techdocs.akamai.com/cloud-computing/docs/getting-started-with-akamai-application-platform) guide. |
| 56 | + |
| 57 | +### Create a New Team |
| 58 | + |
| 59 | +[Teams](https://apl-docs.net/docs/for-ops/console/teams) are isolated tenants on the platform to support Development/DevOps teams, projects, and methodologies, like [DTAP](https://en.wikipedia.org/wiki/Development,_testing,_acceptance_and_production). A Team gets access to the Console, which provides access to self-service features and the shared apps available on the platform. |
| 60 | + |
| 61 | +When working in the context of an admin-level Team, users can create and access resources in any namespace. When working in the context of a non-admin Team, users can only create and access resources used in that Team’s namespace. |
| 62 | + |
| 63 | +1. Select **view** > **platform** in the top bar. |
| 64 | + |
| 65 | +1. Click **Teams** in the left menu. |
| 66 | + |
| 67 | +1. Click **Create Team**. |
| 68 | + |
| 69 | +1. Provide a **Name** for the Team. Keep all other default values, and click **Create Team**. This guide uses the Team name `demo`. |
| 70 | + |
| 71 | +### Add the WordPress Helm Chart to the Catalog |
| 72 | + |
| 73 | +[Helm charts](https://helm.sh/) provide information for defining, installing, and managing resources on a Kubernetes cluster. Custom Helm charts can be added to App Platform Catalog using the **Add Helm Chart** feature. |
| 74 | + |
| 75 | +To install WordPress on your cluster, add the WordPress Helm chart using the Git Repository URL. |
| 76 | + |
| 77 | +1. Select **view** > **team** and **team** > **admin** in the top bar. |
| 78 | + |
| 79 | +1. Once using the `admin` team view, click on **Catalog** in the left menu. |
| 80 | + |
| 81 | +1. Select **Add Helm Chart**. |
| 82 | + |
| 83 | +1. Under **Git Repository URL**, add the URL to the `wordpress` Helm chart .yaml file: |
| 84 | + |
| 85 | + ```command |
| 86 | + https://github.com/bitnami/charts/blob/wordpress/24.1.18/bitnami/wordpress/Chart.yaml |
| 87 | + ``` |
| 88 | + |
| 89 | +1. Click **Get Details** to populate the `wordpress` Helm chart details. |
| 90 | + |
| 91 | +1. Leave **Allow teams to use this chart** selected (default). This allows teams other than `admin` to use the Helm chart. |
| 92 | + |
| 93 | +1. Click **Add Chart**. It may take a few minutes for the Helm chart to be added to the Catalog. |
| 94 | + |
| 95 | +### Add the MySQL Helm Chart to the Catalog |
| 96 | + |
| 97 | +Repeat the same steps for installing the MySQL service on your cluster. |
| 98 | + |
| 99 | +1. While still using the `admin` team view, click **Catalog** in the left menu. |
| 100 | + |
| 101 | +1. Select **Add Helm Chart**. |
| 102 | + |
| 103 | +1. Under **Git Repository URL**, add the URL to the `mysql` Helm chart .yaml file: |
| 104 | + |
| 105 | + ```command |
| 106 | + https://github.com/bitnami/charts/blob/mysql/12.3.1/bitnami/mysql/Chart.yaml |
| 107 | + ``` |
| 108 | + |
| 109 | +1. Click **Get Details** to populate the `mysql` Helm chart details. If necessary, change the **Target Directory Name** field to read "MySQL". This is used to differentiate Helm charts within the Catalog. |
| 110 | + |
| 111 | +1. Leave **Allow teams to use this chart** selected. |
| 112 | + |
| 113 | +1. Click **Add Chart**. |
| 114 | + |
| 115 | +## Deploy a MySQL Database and WordPress Site |
| 116 | + |
| 117 | +Separate Workloads are created for MySQL and WordPress in order to deploy a persistent database and site, respectively. Both Workloads require passwords, so to prevent the passwords from being stored unencrypted, Sealed Secrets are created for each first. |
| 118 | + |
| 119 | +[Sealed Secrets](https://apl-docs.net/docs/for-devs/console/secrets) are encrypted Kubernetes Secrets stored in the Values Git repository. When a Sealed Secret is created in the Console, the Kubernetes Secret will appear in the Team's namespace. |
| 120 | +
|
| 121 | +### Create a Sealed Secret to Store MySQL Passwords |
| 122 | +
|
| 123 | +1. Select **view** > **team** and **team** > **demo** in the top bar. |
| 124 | +
|
| 125 | +1. Click **Sealed Secrets** in the left menu. |
| 126 | +
|
| 127 | +1. Click **Create SealedSecret**. |
| 128 | +
|
| 129 | +1. Add a name for your Sealed Secret. This name is also used when creating the MySQL Workload. This guide uses the name `mysql-credentials`. |
| 130 | +
|
| 131 | +1. Select type _[kubernetes.io/opaque](kubernetes.io/opaque)_ from the **type** dropdown menu. |
| 132 | +
|
| 133 | +1. Add the following **Key** and **Value** pairs, replacing `{{< placeholder "YOUR_PASSWORD" >}}` and `{{< placeholder "YOUR_ROOT_PASSWORD" >}}` with your own secure passwords. To add a second Key and Value combination, select **Add Item** after entering the first pair below: |
| 134 | +
|
| 135 | + - Key=`mysql-password`, Value=`{{< placeholder "YOUR_PASSWORD" >}}` |
| 136 | + - Key=`mysql-root-password`, Value=`{{< placeholder "YOUR_ROOT_PASSWORD" >}}` |
| 137 | +
|
| 138 | +1. Click **Submit**. The Sealed Secret may take a few minutes to become ready. |
| 139 | +
|
| 140 | +### Create a Sealed Secret to Store WordPress Credentials |
| 141 | +
|
| 142 | +1. Select **view** > **team** and **team** > **demo** in the top bar. |
| 143 | +
|
| 144 | +1. Click **Sealed Secrets** in the left menu. |
| 145 | +
|
| 146 | +1. Click **Create SealedSecret**. |
| 147 | +
|
| 148 | +1. Add a name for your Sealed Secret. This name is also used when creating the WordPress Workload. This guide uses the name `wordpress-credentials`. |
| 149 | +
|
| 150 | +1. Select type _[kubernetes.io/opaque](kubernetes.io/opaque)_ from the **type** dropdown menu. |
| 151 | +
|
| 152 | +1. Add the following **Key** and **Value** pairs. |
| 153 | +
|
| 154 | + Replace `{{< placeholder "YOUR_MYSQL_PASSWORD" >}}` with the same password you used for your `mysql-password` when creating the `mysql-credentials` Sealed Secret above. Replace `{{< placeholder "YOUR_WORDPRESS_PASSWORD" >}}` with your own secure password: |
| 155 | +
|
| 156 | + - Key=`mariadb-password`, Value=`{{< placeholder "YOUR_MYSQL_PASSWORD" >}}` |
| 157 | + - Key=`wordpress-password`, Value=`{{< placeholder "YOUR_WORDPRESS_PASSWORD" >}}` |
| 158 | +
|
| 159 | +1. Click **Submit**. The Sealed Secret may take a few minutes to become ready. |
| 160 | +
|
| 161 | +### Create the MySQL Workload |
| 162 | +
|
| 163 | +1. Select **view** > **team** and **team** > **demo** in the top bar. |
| 164 | +
|
| 165 | +1. Select **Workloads** in the left menu. |
| 166 | +
|
| 167 | +1. Click on **Create Workload**. |
| 168 | +
|
| 169 | +1. Select the _MySQL_ Helm chart from the Catalog. |
| 170 | +
|
| 171 | +1. Click on **Values**. |
| 172 | +
|
| 173 | +1. Provide a name for the Workload. This guide uses the Workload name `wordpress-mysql`. |
| 174 | +
|
| 175 | +1. Set the following chart values: |
| 176 | +
|
| 177 | + ``` |
| 178 | + auth: |
| 179 | + database: "{{< placeholder "wordpress" >}}" |
| 180 | + username: "{{< placeholder "wordpress" >}}" |
| 181 | + existingSecret: "{{< placeholder "mysql-credentials" >}}" # Change when using a different name |
| 182 | + networkPolicy: |
| 183 | + enabled: {{< placeholder "false" >}} |
| 184 | + ``` |
| 185 | +
|
| 186 | + {{< note title="Managing Network Policies" >}} |
| 187 | + The `networkPolicy` is disabled since all traffic is allowed by default. Rather than configuring `networkPolicy` values directly in the Workload config, this guide centrally manages all network policies using App Platform's [**Network Policies**](https://apl-docs.net/docs/for-ops/console/netpols) function. |
| 188 | + {{< /note >}} |
| 189 | + |
| 190 | +1. Click **Submit**. The Workload may take a few minutes to become ready. |
| 191 | + |
| 192 | +### Create the WordPress Workload |
| 193 | + |
| 194 | +1. Select **view** > **team** and **team** > **demo** in the top bar. |
| 195 | + |
| 196 | +1. Click **Workloads** in the left menu. |
| 197 | + |
| 198 | +1. Click on **Create Workload**. |
| 199 | + |
| 200 | +1. Select the _WordPress_ Helm chart from the Catalog. |
| 201 | + |
| 202 | +1. Click on **Values**. |
| 203 | + |
| 204 | +1. Provide a name for the Workload. This guide uses the Workload name `wordpress`. |
| 205 | + |
| 206 | +1. Set the following chart values. Replace {{< placeholder "YOUR_USERNAME" >}} with the username you wish to use for logging into WordPress: |
| 207 | + |
| 208 | + ``` |
| 209 | + mariadb: |
| 210 | + enabled: {{< placeholder "false" >}} |
| 211 | + externalDatabase: |
| 212 | + host: {{< placeholder "wordpress-mysql.team-demo.svc.cluster.local" >}} |
| 213 | + user: {{< placeholder "wordpress" >}} |
| 214 | + database: {{< placeholder "wordpress" >}} |
| 215 | + existingSecret: "{{< placeholder "wordpress-credentials" >}}" |
| 216 | + service: |
| 217 | + type: {{< placeholder "ClusterIP" >}} |
| 218 | + networkPolicy: |
| 219 | + enabled: {{< placeholder "false" >}} |
| 220 | + existingSecret: "{{< placeholder "wordpress-credentials" >}}" |
| 221 | + wordpressUsername: "{{< placeholder "YOUR_USERNAME" >}}" |
| 222 | + ``` |
| 223 | + |
| 224 | +1. Click **Submit**. The Workload may take a few minutes to become ready. |
| 225 | + |
| 226 | +### Create Network Policies |
| 227 | + |
| 228 | +Create a Network Policy allowing only the WordPress Pod to connect to the MySQL database. |
| 229 | + |
| 230 | +1. Select **view** > **team** and **team** > **demo** in the top bar. |
| 231 | + |
| 232 | +1. Click **Network Policies** in the left menu. |
| 233 | + |
| 234 | +1. Click **Create Netpol**. |
| 235 | + |
| 236 | +1. Add a name for the Network Policy. This guide uses the name `wordpress-mysql`. |
| 237 | + |
| 238 | +1. Select **Rule type** `ingress` using the following values: |
| 239 | + |
| 240 | + - **Selector label name**: [`app.kubernetes.io/instance`](http://app.kubernetes.io/instance) |
| 241 | + |
| 242 | + - **Selector label value**: `wordpress-mysql` |
| 243 | + |
| 244 | +1. Select **AllowOnly**, and enter the following values. This allows only the WordPress Pod to connect to the database: |
| 245 | + |
| 246 | + - **Namespace name**: `team-demo` |
| 247 | + |
| 248 | + - **Selector label name**: [`app.kubernetes.io/instance`](http://app.kubernetes.io/instance) |
| 249 | + |
| 250 | + - **Selector label value**: `wordpress` |
| 251 | + |
| 252 | +1. Click **Submit**. |
| 253 | + |
| 254 | +#### Check the Pod Status |
| 255 | + |
| 256 | +Using the App Platform **Shell** feature, you can check to see if the WordPress Pod has started and connected to the MySQL database. |
| 257 | + |
| 258 | +1. Select **view** > **team** and **team** > **demo** in the top bar. |
| 259 | + |
| 260 | +1. Click **Shell** in the left menu. |
| 261 | + |
| 262 | +1. Enter the following command to launch the k9s interface once the Shell session has loaded. [k9s](https://k9scli.io/) is an open source, terminal-based Kubernetes user interface pre-installed with Akamai App Platform: |
| 263 | + |
| 264 | + ```command |
| 265 | + k9s |
| 266 | + ``` |
| 267 | + |
| 268 | +1. A `CrashLoopBackOff` status signifies that WordPress has not successfully connected to the database. If this is the case, check to see if label values are correct in your Network Policy. |
| 269 | + |
| 270 | +  |
| 271 | + |
| 272 | + In order to force a restart, click on the WordPress Pod, and type <kbd>Ctrl</kbd> + <kbd>D</kbd>. This kills the current Pod and starts a new one. |
| 273 | + |
| 274 | +  |
| 275 | + |
| 276 | +## Create a Service to Expose the WordPress Site |
| 277 | + |
| 278 | +Creating a [Service](https://apl-docs.net/docs/for-devs/console/services) in App Platform configures NGINX’s Ingress Controller. This allows you to enable public access to services running internally on your cluster. |
| 279 | + |
| 280 | +1. Select **view** > **team** and **team** > **demo** in the top bar. |
| 281 | + |
| 282 | +1. Click **Services** in the left menu. |
| 283 | + |
| 284 | +1. Click **Create Service**. |
| 285 | + |
| 286 | +1. In the **Service Name** dropdown menu, select the `wordpress` service. |
| 287 | + |
| 288 | +1. Under **Exposure (ingress)**, select **External**. |
| 289 | + |
| 290 | +1. Click **Create Service**. |
| 291 | + |
| 292 | +1. Once the Service is ready, click the URL of the `wordpress` service to navigate to the live WordPress site: |
| 293 | + |
| 294 | +  |
| 295 | + |
| 296 | +### Setting Up DNS |
| 297 | + |
| 298 | +When creating a Service, DNS for your site can be configure using a CNAME rather than using an external IP address. To do this, configure a CNAME entry with your domain name provider, and follow the steps in our [Using a CNAME](https://apl-docs.net/docs/for-devs/console/services#using-a-cname) App Platform documentation. |
| 299 | + |
| 300 | +See our guide on [CNAME records](https://techdocs.akamai.com/cloud-computing/docs/cname-records) for more information on how CNAME records work. |
| 301 | + |
| 302 | +### Access the WordPress UI |
| 303 | + |
| 304 | +1. While viewing the WordPress site in your browser, add `/wp-admin` to the end of the URL, where {{< placeholder "MY_WORDPRESS_URL" >}} is your site URL: |
| 305 | + |
| 306 | + ``` |
| 307 | + http://{{< placeholder "MY_WORDPRESS_URL" >}}/wp-admin |
| 308 | + ``` |
| 309 | + |
| 310 | + This should bring you to the WordPress admin panel login screen: |
| 311 | + |
| 312 | +  |
| 313 | + |
| 314 | +1. To access the WordPress UI, sign in with your WordPress username and password. |
| 315 | + |
| 316 | + Your username is the value used for `wordpressUsername` when creating the [WordPress Workload](#create-the-wordpress-workload). Your password is the value used for `wordpress-password` when making your `wordpress-credentials` [Sealed Secret](#create-a-sealed-secret-to-store-wordpress-credentials). |
| 317 | + |
| 318 | +## Going Further |
| 319 | + |
| 320 | +Once you've accessed the WordPress UI, you can begin modifying your site using WordPress templates, themes, and plugins. For more information, see WordPress's resources below: |
| 321 | + |
| 322 | +- [WordPress Support](https://wordpress.org/support/): Learn the basic workflows for using WordPress. |
| 323 | + |
| 324 | +- [Securing WordPress](https://www.linode.com/docs/guides/how-to-secure-wordpress/): Advice on securing WordPress through HTTPS, using a secure password, changing the admin username, and more. |
| 325 | + |
| 326 | +- [WordPress Themes](https://wordpress.org/themes/#): A collection of thousands of available WordPress themes. |
0 commit comments