Build Platforms Daily

Part 3: Deploy WordPress via Score and Humanitec with a Managed MySQL Database

By Victor Ikeme on Jun 20, 2025
Deploying WordPress with Humanitec and Score

In Part 1 and Part 2, the WordPress workload was deployed using Score with Docker Compose and Kubernetes, respectively. These flows were fast, local, and environment-aware — but they still required container orchestration, YAML generation, and platform ownership.

In this final part, the focus shifts toward a more mature platform engineering model: Deploying same Score-defined workload to a Kubernetes-based Internal Developer Platform (IDP) powered by Humanitec.

This model allows platform engineers to fully abstract operational complexity while delivering secure, scalable infrastructure as a service to developers — automatically.

The outcome:

  • Developers write a score.yaml, deploy it with a single command, and get running apps.
  • Platform Engineers define reusable infrastructure, not runtime YAMLs.
  • Humanitec provisions infrastructure dynamically
  • The platform delivers configuration, secrets, and network routing
  • No Compose. No Helm. No kubectl. No handoffs.

What You Will Learn.

  • How to deploy workloads to Humanitec using humctl score deploy
  • How Score and Humanitec together enable platform-as-a-product workflows
  • How developers declare intent, while platform engineers define provisioning contracts
  • How to define a reusable, managed MySQL resource in Humanitec
  • How Score supports self-service environments across all deployment targets
  • How developers consume infrastructure via Score — without needing credentials or kubectl
  • How graph-based IDPs turn Kubernetes into a true developer-first experience

Table of Contents.

Prerequisites.

Before deploying to Humanitec, ensure the following:

  • A valid Humanitec organization and personal access token
  • humctl installed and authenticated against the org
  • Score CLI installed locally
  • A Humanitec environment (e.g. 5min-local) is available
  • A Kubernetes cluster is connected to Humanitec (via Pocket IDP or cloud integration)

To get the example project:

$ git clone https://github.com/victor-ikeme/awesome-score-spec-examples
$ cd awesome-score-spec-examples/examples/wordpress-mysql

To quickly deploy using the Makefile:

$ make score-deploy

After deployment:

$ open http://localhost:8080

To clean up:

$ make score-down

1. Define the WordPress Workload with Score.

This step is unchanged from previous parts of the series.

From the developer’s perspective, the workload remains completely declarative. The score.yaml defines the container, service ports, and required resources — with no knowledge of the underlying platform.

apiVersion: score.dev/v1b1
metadata:
  name: wordpress
containers:
  wordpress:
    image: wordpress:latest
    variables:
      WORDPRESS_DB_HOST: ${resources.db.host}
      WORDPRESS_DB_USER: ${resources.db.username}
      WORDPRESS_DB_PASSWORD: ${resources.db.password}
      WORDPRESS_DB_NAME: ${resources.db.name}
service:
  ports:
    tcp:
      port: 8080
      targetPort: 80
resources:
  db:
    type: mysql

This single spec works across Docker Compose, Kubernetes, and Humanitec. It focuses solely on what the application needs — without dictating how that infrastructure gets delivered.

2. As a Platform Engineer: Add a Managed MySQL Resource to the Platform with Class wp.

Platform Engineers build golden paths by exposing reusable, abstracted infrastructure — not by giving developers YAML or shell scripts. In Humanitec, this means defining resource classes and matching criteria that allow workloads to consume infrastructure safely and predictably.

In this step, simulate the Platform Engineer experience by making a managed MySQL resource available under a custom class called wp.

We will walk through:

  • Creating an application and environment in Humanitec
  • Defining a new mysql resource class (wp)
  • Installing a MySQL resource definition using Terraform
  • Linking the class and environment via matching criteria
  • Confirming visibility from the developer’s side

🧠 This pattern allows developers to say “I need a mysql” — while the platform decides how to provision it.

2.1. Onboard the Application and Environment to Humanitec.

First, initialize the Humanitec application and environment.

This guide assumes you’re using 5min IDP, a Kubernetes-based platform setup provided by Humanitec. It also works the same way with other cloud-connected Kubernetes clusters (AWS, GCP, Azure, OpenShift, etc.).

Begin by exporting the following variables:

$ export APP_ID=wordpress-demo
$ export ENV_ID=5min-local

Now, create the application and environment:

$ humctl api post /orgs/${HUMANITEC_ORG}/apps \
  -d '{
    "id": "'${APP_ID}'",
    "name": "'${APP_ID}'",
    "env": {
      "id": "'${ENV_ID}'",
      "name": "'${ENV_ID}'",
      "type": "5min-local"
    }
  }'

If successful, this call registers wordpress-demo with a 5min-local environment in your org.

You can also confirm this in the Humanitec Developer Portal:

  • The application and environment will appear in the Apps view
  • The environment type will be listed as 5min-local

2.2. Create the wp Resource Class.

To offer multiple flavors of a resource type (e.g., local MySQL vs. cloud-managed MySQL), define a resource class.

Run the following to create a wp class for mysql:

$ humctl api post "/orgs/${HUMANITEC_ORG}/resources/types/mysql/classes" \
  -d '{
    "id": "wp",
    "description": "MySQL database settings for WordPress workloads"
  }'

This adds wp as a valid resource class for MySQL — enabling developers to request it explicitly in Score specs.

The response will confirm the creation:

{
  "id": "wp",
  "description": "MySQL database settings for WordPress workloads",
  ...
}

2.3. Create the MySQL Resource Definition.

Now, define how to provision MySQL for the wp class — in this case, using an in-cluster Deployment.

Clone the resource pack repository:

$ git clone https://github.com/humanitec-architecture/resource-packs-in-cluster
$ cd resource-packs-in-cluster/examples/mysql

Initialize and apply the Terraform configuration to create the resource definition:

$ terraform init
$ terraform plan
$ terraform apply

This registers a new resource definition in Humanitec (e.g., hum-rp-mysql-ex-mysql) that provisions MySQL using native Kubernetes manifests.

🔧 Make sure humctl login has already been run before applying Terraform.

Once applied, verify in the Humanitec Portal under Resource Definitions:

2.4. Apply Matching Criteria for the wp Class.

Now associate the resource definition with the wp class in the 5min-local environment.

First, identify your resource definition ID (e.g., hum-rp-mysql-ex-mysql), then run:

$ humctl api PUT \
  /orgs/${HUMANITEC_ORG}/resources/defs/hum-rp-mysql-ex-mysql/criteria \
  --data '[{"env_type": "5min-local", "class": "wp"}]'

This ensures that any Score workload requesting:

resources:
  db:
    type: mysql
    class: wp

…will be resolved using this specific resource definition.

The output should confirm the criteria were set:

[
  {
    "class": "wp",
    "env_type": "5min-local",
    "id": "..."
  }
]

2.5. Validate as a Developer: Check Available Resource Types.

From a developer’s perspective, it’s now possible to check which resource types (and classes) are available for the current app and environment.

Navigate back to the workload directory:

$ cd ~/awesome-score-spec-examples/examples/wordpress-mysql

Then run:

$ humctl score available-resource-types

This returns a list like:

MySQL            	mysql      	datastore	wp       	MySQL database settings for WordPress workloads

This confirms that the mysql resource with class wp is now available for use — cleanly abstracted, reusable, and platform-aligned.

3. As a Developer: Update the Score Spec to Use the wp MySQL Class and Add DNS + Route Resources for URL Access.

With the wp MySQL resource and class now available on the platform, the developer’s role is simply to express their intent: “I need a database, and I want this app to be accessible at a predictable URL.”

This step introduces two new Score resource types: dns and route.

Why are dns and route needed?

In our earlier deployments (Docker Compose and Kubernetes), WordPress was accessed via localhost and static ports. But in a cloud-native IDP like Humanitec, services typically receive ingress URLs dynamically — and those need to be declared explicitly.

  • The dns resource requests a DNS host to represent the application.
  • The route resource defines how traffic should flow from that DNS to the container (port, path, etc.).

Together, these resources enable URL-based access to the app, managed and provisioned by the platform.

Updated Score Spec

The updated score.yaml reflects the new MySQL class and ingress configuration:

apiVersion: score.dev/v1b1
metadata:
  name: wordpress
containers:
  wordpress:
    image: wordpress:latest
    variables:
      WORDPRESS_DB_HOST: ${resources.db.host}
      WORDPRESS_DB_USER: ${resources.db.username}
      WORDPRESS_DB_PASSWORD: ${resources.db.password}
      WORDPRESS_DB_NAME: ${resources.db.name}
service:
  ports:
    tcp:
      port: 80
      targetPort: 80
resources:
  db:
    type: mysql
    class: wp
  dns:
    type: dns
  route:
    type: route
    host: ${resources.dns.host}
    path: /
    port: 80

What This Configuration Does:

  • type: mysql with class: wp ensures the app uses the MySQL resource provisioned earlier.
  • dns and route request platform-managed ingress, allowing access via an external URL.
  • No hardcoded addresses, no manual kubectl port-forward, and no ingress.yaml.

💡 This is a key moment in our platform-as-a-product journey: developers remain focused on what the app needs — not how the platform satisfies those needs.

Deploy to Humanitec

To deploy the updated spec, we first define our environment variables for standardization:

$ export HUMANITEC_ENVIRONMENT=5min-local
$ export HUMANITEC_APPLICATION=wordpress-demo

Then we runt the followijg command to deploy our app to our Kubernetes-based IDP powered by Humanitec:

$ humctl score deploy \
	 -f score/score.yaml \
	 --app ${HUMANITEC_APPLICATION} \
	 --env ${HUMANITEC_ENVIRONMENT} \
	 --wait

This single command triggers the entire orchestration:

  • Resolves resource definitions for MySQL, DNS, and routing
  • Provisions and binds those resources dynamically
  • Injects environment variables into the container
  • Deploys the application into the platform-managed Kubernetes cluster

No YAML handoffs. No Helm charts. No manual ingress setups.

The infrastructure is fully self-service, declarative, and repeatable — powered by Score and Humanitec.

4. Verify the Deployment in the Humanitec Developer Portal.

The final deployment can be inspected from the Humanitec Developer Portal.

The portal provides:

  • A visual resource graph connecting the app to its backing services:

  • Deployment logs and pod status
  • A list of resolved outputs from provisioned resources
  • The external route to access the WordPress application

Example output may resemble:

📦 App: wordpress-demo
	Environment: 5min-local
🌐 URL: https://wordpress-demo-qax4.localhost

No YAML editing. No Helm charts. No secrets injection logic. Everything flows through Score and Humanitec — seamlessly.

Now, we can go to browser and see our deployed wordpress app using the dns url provisioned bt the humanitec platform:

Summary.

This final step in the series demonstrates how Score and Humanitec deliver a complete Internal Developer Platform experience:

  • Developers work from a single declarative spec.
  • Platform teams define infrastructure contracts once, then reuse them everywhere.
  • Humanitec dynamically provisions, connects, and deploys — with no handoffs.

This approach treats platforms as products, shifting platform engineering from writing automation to designing reliable developer experiences.

Whether deploying locally, to Kubernetes, or across environments with Humanitec, Score enables platform-consistent developer workflows — making self-service infrastructure real.

💡 Platform Engineering Insight

What began as a WordPress demo now reveals a deeper lesson: A platform is not a set of scripts. It’s a product.

Score allows developers to express intent clearly. Humanitec ensures infrastructure is provisioned reliably. Together, they reduce friction, encourage best practices, and help organizations scale platform maturity — one abstraction at a time.

Contribute to the Awesome Score Spec.

This tutorial is part of the open-source Awesome Score Spec Examples project.

⭐️ Star the repo to explore more platform-ready workload examples — or contribute your own.

Listen to my Podcasts

Join me as I talk shop about internal developer platforms, products, tools, tips and everything in between—new episodes every week!

© Copyright 2025 by Build Platforms Daily. Built with ♥ by Victor Ikeme.