Skip to navigationSkip to main contentSkip to footerScaleway Docs HomepageAsk our AI
Ask our AI

Deploying a web application with Scaleway Kubernetes Kapsule using a full isolation pool and Public Gateway

Terraform
OpenTofu
Kubernetes
Kapsule
Instances

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

  1. Create a variables.tf file 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
    }
  2. 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.

    Tip

    Best practices:

    • For persistent use on your local machine, add the previously mentioned export commands to your shell profile (e.g., ~/.bashrc or ~/.zshrc).
    • In CI/CD environments, inject environment variables as secure secrets.
    • Never commit environment variable scripts or files containing credentials to version control.
    • Verify that variables are set (e.g., echo $TF_VAR_scaleway_access_key on Linux/macOS) before running Terraform.

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.

  1. Create a new Private Network in the fr-par region 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 Network sitesecure-private-net.

    # Creating a private network for cluster isolation
    resource "scaleway_vpc_private_network" "sitesecure_pn" {
    	name = "sitesecure-private-net"
    	region = var.region
    }
  2. 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"
  3. 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
  • 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.

  1. Initialize your Terraform configuration.

    terraform init
  2. Plan your deployment.

    terraform plan
  3. Deploy the services.

    terraform apply

After deploying the infrastructure for the web application, it is time to create your resources.

Retrieve variable values

  1. Display the value of the output variable db_password_base64 by running the following command:

    terraform output -raw db_password_base64
  2. Note down the value returned, you will need it when creating the Kubernetes Secret for database credentials (wordpress-db-secret.yaml).

  3. Display the value of the output variable db_host by running the following command:

    terraform output -raw db_host
  4. 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 configuration

Create 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: 80

Configure 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: 80

This configuration provisions a Scaleway Load Balancer and integrates it with the Public Gateway to route external traffic.

Test and monitor

  1. To interact with the cluster, download and install the kubeconfig file of the cluster.

    scw k8s config install <cluster-id>
  2. 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
  3. Use kubectl to verify the cluster status.

    kubectl get nodes
    kubectl get pods
  4. Test the web application by accessing sitesecure.your-domain.tld via a browser and verifying the WordPress setup.

  5. Enable Scaleway Cockpit to monitor the data plane and audit logs of the cluster.

  6. Verify auto-scaling by simulating increased traffic (e.g., using a load testing tool like Vegeta).

Tip

Once you have completed your tests, you can delete your deployment using the terraform destroy command.

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
}
Questions?

Visit our Help Center and find the answers to your most frequent questions.

Visit Help Center
No Results