Deploying a web application with Scaleway Kubernetes Kapsule using a full isolation pool and Public Gateway
This tutorial walks you through an example of how to deploy a WordPress‑based web application on a Scaleway Kubernetes Kapsule. For the sake of the example, let's suppose that the application requires high security, scalability, and controlled external access. To achieve this, the solution outlined in this document applies:
- a full isolation pool to ensure that worker nodes have only private IP addresses, communicating within a Private Network
- a Public Gateway to manage secure external access to the web application
This setup ensures that internal cluster traffic is isolated from the public internet, while external users can access the application through a controlled entry point.
Objectives
- Security - Isolate all internal cluster communication within a Private Network to prevent exposure to the public internet.
- Scalability - Enable auto-scaling to handle fluctuating traffic.
- Controlled access - Use a Public Gateway to manage and secure external traffic to the web application.
- Resilience - Ensure high availability by deploying across multiple Availability Zones (AZs).
Architecture
The architecture includes the following:
- Kubernetes Kapsule cluster - A managed Kubernetes cluster hosted in the Paris region (
fr-par) of Scaleway. - Full isolation pool - Worker nodes configured with only private IP addresses, communicating within a Scaleway Private Network.
- Public Gateway - A Scaleway Public Gateway with Dynamic NAT enabled to route outgoing traffic from the Private Network to the public internet and allow controlled inbound access.
- Load Balancer - A Scaleway Load Balancer to distribute external traffic to the web application pods.
- Containerized web application - A web application (based on WordPress) deployed as pods, accessible externally via an ingress controller, with a MySQL database for persistence.
Before you start
To complete the actions presented below, you must have:
- A Scaleway account with IAM permissions to create and manage Kubernetes clusters, VPC, Private Networks, and Public Gateways
- Created a VPC in the desired region to deploy
- Scaleway CLI or console access for configuration
- A containerized web application image (WordPress) stored in the Scaleway Container Registry or another registry
- A Scaleway Managed Database for MySQL for data persistence
- Basic knowledge of Kubernetes, Terraform, WordPress, and the Scaleway ecosystem
Create Terraform variables
-
Create a
variables.tffile to define Terraform variables used in the project.variable "region" { type = string default = "fr-par" description = "The Scaleway region to deploy resources in (e.g., fr-par)" } variable "scaleway_access_key" { type = string description = "Scaleway access key for API authentication" sensitive = true } variable "scaleway_secret_key" { type = string description = "Scaleway secret key for API authentication" sensitive = true } variable "project_id" { type = string description = "Scaleway project ID for resource creation" } variable "db_user" { type = string description = "Username for the MySQL database" default = "admin" } variable "db_password" { type = string description = "Password for the MySQL database" sensitive = true } -
Use environment variables to securely provide your Scaleway credentials and sensitive data to Terraform. This avoids hardcoding values in files, reducing the risk of exposure (e.g., in version control). Set the required environment variables before running Terraform commands. Prefix the variable names with
TF_VAR_to make them accessible to Terraform.export TF_VAR_scaleway_access_key="" export TF_VAR_scaleway_secret_key="" export TF_VAR_project_id="" export TF_VAR_db_password="" # Optional: Override defaults if needed export TF_VAR_region="fr-par" export TF_VAR_db_user="admin"Remember to add your actual Scaleway access key, Scaleway secret key, Scaleway Project ID, and MySQL database password.
Create and configure the Private Network and Public Gateway
Before you start, ensure you have created a Virtual Private Cloud (VPC) in the region of deployment. For detailed instructions, see How to create and manage VPCs.
For full details, see the Terraform configuration file (main.tf) in Appendix: Full main.tf file.
-
Create a new Private Network in the
fr-parregion with a /22 IP subnet. For the sake of this tutorial, let's suppose that the solution outlined here will be used by a fictitious company called SiteSecure, so let's name the Private Networksitesecure-private-net.# Creating a private network for cluster isolation resource "scaleway_vpc_private_network" "sitesecure_pn" { name = "sitesecure-private-net" region = var.region } -
Create a Public Gateway in the same region as the cluster.
# Creating a public gateway for external access resource "scaleway_vpc_public_gateway" "sitesecure_gateway" { name = "sitesecure-gateway" type = "VPC-GW-S" -
Attach the Public Gateway to the Private Network.
# Attaching the Public Gateway to the Private Network with Dynamic NAT resource "scaleway_vpc_gateway_network" "sitesecure_gateway_network" { gateway_id = scaleway_vpc_public_gateway.sitesecure_gateway.id private_network_id = scaleway_vpc_private_network.sitesecure_pn.id enable_masquerade = true ipam_config { push_default_route = true } }
Create a Kubernetes Kapsule cluster using Terraform
Create a Kubernetes Kapsule cluster with a node pool using full isolation. Configure the cluster via Terraform using the following characteristics:
- Cluster settings:
- Name:
sitesecure-kapsule-cluster - Region:
fr-par - Kubernetes version: Latest supported version (e.g., 1.36.1)
- CNI: Cilium (recommended for performance and security)
- Private Network: Attach to
sitesecure-private-net
- Name:
- Pool configuration:
-
Pool name:
full-isolation-pool -
Node type:
PRO2-S(4 vCPUs, 16GB RAM, suitable for the workloads of the web application)For more information about Instance types, see Choosing the best Scaleway Instance type for your workload.
-
Enable Full Isolation: Nodes will have only private IPs, relying on the Public Gateway for external communication.
-
Enable Auto-scaling: Set minimum nodes to 2 and maximum to 5 to handle traffic spikes.
-
Enable Autoheal: Ensure unhealthy nodes are replaced automatically.
-
Terraform example:
# Creating a Kubernetes Kapsule cluster
resource "scaleway_k8s_cluster" "sitesecure_cluster" {
name = "sitesecure-kapsule-cluster"
version = "1.36.1"
cni = "cilium"
private_network_id = scaleway_vpc_private_network.sitesecure_pn.id
region = var.region
delete_additional_resources = true
}
# Creating a node pool with full isolation
resource "scaleway_k8s_pool" "full_isolation_pool" {
cluster_id = scaleway_k8s_cluster.sitesecure_cluster.id
name = "full-isolation-pool"
node_type = "PRO2-S"
size = 2
autoscaling = true
autohealing = true
min_size = 2
max_size = 5
public_ip_disabled = true
region = var.region
depends_on = [scaleway_vpc_gateway_network.sitesecure_gateway_network]
}Create and configure a Managed Database for MySQL using Terraform
Create a Managed Database for MySQL for use with WordPress.
Terraform example:
# Creating a managed MySQL database for WordPress
resource "scaleway_rdb_instance" "wordpress_db" {
name = "sitesecure-wordpress-db"
node_type = "db-dev-s"
engine = "MySQL-8"
is_ha_cluster = true
user_name = var.db_user
password = var.db_password
region = var.region
volume_type = "sbs_15k"
volume_size_in_gb = 15
private_network {
pn_id = scaleway_vpc_private_network.sitesecure_pn.id
enable_ipam = true
}
}Deploy the services using Terraform
Before running the following commands, you can check the reference main.tf file in the Appendix to confirm that the upcoming changes match your expectations.
-
Initialize your Terraform configuration.
terraform init -
Plan your deployment.
terraform plan -
Deploy the services.
terraform apply
After deploying the infrastructure for the web application, it is time to create your resources.
Retrieve variable values
-
Display the value of the output variable
db_password_base64by running the following command:terraform output -raw db_password_base64 -
Note down the value returned, you will need it when creating the Kubernetes Secret for database credentials (
wordpress-db-secret.yaml). -
Display the value of the output variable
db_hostby running the following command:terraform output -raw db_host -
Note down the value returned, you will need it when creating the Kubernetes Deployment for WordPress (
wordpress-deployment.yaml).
Create a Kubernetes Secret for the database
Create a Kubernetes Secret for database credentials (wordpress-db-secret.yaml). Remember to replace the value of DB_PASSWORD with your actual value (obtained in section Retrieve variable values).
apiVersion: v1
kind: Secret
metadata:
name: wordpress-db-credentials
namespace: default
type: Opaque
data:
DB_PASSWORD: "<base64-encoded-mysql-password>"
# Ensure the DB_PASSWORD is the same password as set in the terraform.tfvars configurationCreate a Kubernetes Deployment for WordPress
Create a Kubernetes Deployment for WordPress (wordpress-deployment.yaml). Remember to replace the value of WORDPRESS_DB_HOST with your actual value (obtained in section Retrieve variable values).
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: sitesecure-wordpress
template:
metadata:
labels:
app.kubernetes.io/name: sitesecure-wordpress
spec:
containers:
- name: wordpress
image: wordpress:latest
ports:
- containerPort: 80
env:
- name: WORDPRESS_DB_HOST
value: "<wordpress-database-host>"
- name: WORDPRESS_DB_NAME
value: "wordpress"
- name: WORDPRESS_DB_USER
value: "admin"
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: woocommerce-db-credentials
key: DB_PASSWORD
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "1Gi"Create an ingress controller
Deploy an ingress controller (e.g., nginx-ingress) to manage external HTTP traffic to the web application.
Create a configuration file called wordpress-ingress.yaml.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: sitesecure-ingress
namespace: default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
rules:
- host: sitesecure.your-domain.tld
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: sitesecure-wordpress-service
port:
number: 80Configure a Load Balancer
Create a configuration file called wordpress-service.yaml to deploy a Kubernetes Service of type LoadBalancer.
apiVersion: v1
kind: Service
metadata:
name: sitesecure-wordpress-service
namespace: default
spec:
type: LoadBalancer
selector:
app.kubernetes.io/name: sitesecure-wordpress
ports:
- port: 80
targetPort: 80This configuration provisions a Scaleway Load Balancer and integrates it with the Public Gateway to route external traffic.
Test and monitor
-
To interact with the cluster, download and install the
kubeconfigfile of the cluster.scw k8s config install <cluster-id> -
Deploy the web application using the following command.
kubectl apply -f wordpress-db-secret.yaml kubectl apply -f wordpress-deployment.yaml kubectl apply -f wordpress-service.yaml kubectl apply -f wordpress-ingress.yaml -
Use
kubectlto verify the cluster status.kubectl get nodes kubectl get pods -
Test the web application by accessing
sitesecure.your-domain.tldvia a browser and verifying the WordPress setup. -
Enable Scaleway Cockpit to monitor the data plane and audit logs of the cluster.
-
Verify auto-scaling by simulating increased traffic (e.g., using a load testing tool like Vegeta).
Appendix: Full main.tf file
variable "region" {
type = string
default = "fr-par"
description = <<EOT
Region where the infrastructure will be deployed
more details https://www.scaleway.com/en/docs/account/products-availability/
EOT
}
variable "zone" {
type = string
default = "fr-par-1"
description = <<EOT
Availability Zone where the infrastructure will be deployed
more details https://www.scaleway.com/en/docs/account/products-availability/
EOT
}
terraform {
required_providers {
scaleway = {
source = "scaleway/scaleway"
}
}
required_version = ">= 0.13"
}
provider "scaleway" {
zone = var.zone
region = var.region
}
variable "db_user" {
type = string
default = "admin"
description = "database admin username"
}
variable "db_password" {
type = string
sensitive = true
nullable = false
description = "database admin password"
}
# Creating a Private Network for cluster isolation
resource "scaleway_vpc_private_network" "sitesecure_pn" {
name = "sitesecure-private-net"
region = var.region
}
# Creating a Public Gateway for external access
resource "scaleway_vpc_public_gateway" "sitesecure_gateway" {
name = "sitesecure-gateway"
type = "VPC-GW-S"
}
# Attaching the Public Gateway to the Private Network with Dynamic NAT
resource "scaleway_vpc_gateway_network" "sitesecure_gateway_network" {
gateway_id = scaleway_vpc_public_gateway.sitesecure_gateway.id
private_network_id = scaleway_vpc_private_network.sitesecure_pn.id
enable_masquerade = true
ipam_config {
push_default_route = true
}
}
# Creating a Kubernetes Kapsule cluster
resource "scaleway_k8s_cluster" "sitesecure_cluster" {
name = "sitesecure-kapsule-cluster"
version = "1.36.1"
cni = "cilium"
private_network_id = scaleway_vpc_private_network.sitesecure_pn.id
region = var.region
delete_additional_resources = true
}
# Creating a node pool with full isolation
resource "scaleway_k8s_pool" "full_isolation_pool" {
cluster_id = scaleway_k8s_cluster.sitesecure_cluster.id
name = "full-isolation-pool"
node_type = "PRO2-S"
size = 2
autoscaling = true
autohealing = true
min_size = 2
max_size = 5
public_ip_disabled = true
region = var.region
depends_on = [scaleway_vpc_gateway_network.sitesecure_gateway_network]
}
# Creating a managed MySQL database for WordPress
resource "scaleway_rdb_instance" "wordpress_db" {
name = "sitesecure-wordpress-db"
node_type = "db-dev-s"
engine = "MySQL-8"
is_ha_cluster = true
user_name = var.db_user
password = var.db_password
region = var.region
volume_type = "sbs_15k"
volume_size_in_gb = 15
private_network {
pn_id = scaleway_vpc_private_network.sitesecure_pn.id
enable_ipam = true
}
}
resource "scaleway_rdb_database" "database" {
instance_id = scaleway_rdb_instance.wordpress_db.id
name = "wordpress"
}
# Creating output variable for database host
output "db_host" {
value = format("%s:%d", scaleway_rdb_instance.wordpress_db.private_network.0.ip, scaleway_rdb_instance.wordpress_db.private_network.0.port)
}
# Creating output variable for and base64-encoding the database password
output "db_password_base64" {
value = base64encode(var.db_password)
sensitive = true
}Visit our Help Center and find the answers to your most frequent questions.
Visit Help Center