HUAWEI CLOUD → STACKIT · COMPLETE GUIDE
The complete Huawei Cloud to STACKIT migration guide
Start with the Terraform you already have: run stacktoit assess, read assessment.json and the wave order, settle the decisions the run leaves to you, build the STACKIT network first, then move data, compute and finally the edge. In the example run on this page, nine Huawei Cloud resources become nine units in three waves, eight classed RECONFIGURE and one REPLATFORM. None is written as STACKIT Terraform, so each is a manual step with an owner. This guide follows the order of that run and names the decision behind every step.
The migration in eight steps
1. Gather and pin the Terraform
Collect every root module that uses the huaweicloud/huaweicloud provider and commit .terraform.lock.hcl. Without a lock entry the run reports the provider as unpinned and caps its units at MEDIUM confidence, which is what all nine units of the example show.
2. Assess
Run stacktoit assess ./huawei-terraform. It reads the files and connects to no Huawei Cloud account, so a resource that was created by hand and is in no module is not in the result. Add it to the Terraform first or list it yourself. A sensitive variable without a value, such as db_password in the example, does not stop the run: the console reports it as a missing input and marks the source VARIABLE_UNRESOLVED, and the answer template counts it among the requests that block the draft. Supply it with --var-file or a TF_VAR_ environment variable.
3. Read the output in this order
assessment.json for class, target and reason of each unit. migration/technical-sequencing.md for the waves. migration/data-movement.md for the stateful units. execution/manual/actions.md for the manual steps and their owners. engineering/architect-report.md for the reasoning. index.html shows the same in one workspace.
4. Answer what the run asks
The example run lists six open requests. Two block the draft: the STACKIT region (eu01 or eu02) and the value of db_password. Four are preferences the build records but cannot apply: project, observability, public ingress and egress. Copy inputs-template.yaml out of the run folder, fill the value lines and run again with --inputs; the template does not take db_password, which comes from a variable file or TF_VAR_db_password.
5. Build the landing zone and the network
Lay out organization, folders and projects first; the STACKIT Migration Framework calls the landing zone the secure platform base for migrated workloads. A VPC has no one-to-one counterpart: its subnets become STACKIT networks, and a Network Area connects projects where routing is needed. Security groups follow. STACKIT rules only allow traffic, so every deny rule of the source needs a decision.
6. Move the data
The example has three stateful units: an EVS volume, an OBS bucket and an RDS PostgreSQL instance. The run sets the mechanism of each to UNKNOWN and asks you to choose it. For PostgreSQL the run names pg_dump and pg_restore or logical replication; for a bucket, rclone is a documented route; a volume moves at host level or with the server image.
7. Move compute and the edge
Import or rebuild the image of each server. STACKIT accepts raw, qcow2 and iso images up to 70 GB, and qemu-img can convert other formats to raw. Then bring up the Network Load Balancer and the public IP, and change DNS records and allow lists that name the old address.
8. Cut over, observe, retire
The run states no cutover facts for this estate and performs no cutover. Cut over in the order of the waves where it fits, keep the Huawei Cloud side until your checks pass, and write down how each step is undone: the plan leaves rollback to the person who carries out the step.
A web server, a database and a load balancer, assessed
A small Huawei Cloud estate with nine resources, written for this page and assessed by StackToIT on 4 November 2026. Left: three blocks of the input. Right: the result the run recorded for them, an excerpt of assessment.json with the values as the run wrote them.
resource "huaweicloud_compute_instance" "web" {
name = "shop-web-01"
image_id = "6f3b0e2a-1c4d-4e5f-8a9b-0c1d2e3f4a5b"
flavor_id = "s6.xlarge.2"
availability_zone = "eu-west-101a"
security_group_ids = [huaweicloud_networking_secgroup.app.id]
system_disk_type = "SSD"
system_disk_size = 40
network {
uuid = huaweicloud_vpc_subnet.app.id
}
}
resource "huaweicloud_rds_instance" "orders" {
name = "shop-orders"
flavor = "rds.pg.n1.large.2"
vpc_id = huaweicloud_vpc.main.id
subnet_id = huaweicloud_vpc_subnet.app.id
security_group_id = huaweicloud_networking_secgroup.app.id
availability_zone = ["eu-west-101a"]
db {
type = "PostgreSQL"
version = "16"
password = var.db_password
}
volume {
type = "ULTRAHIGH"
size = 100
}
backup_strategy {
start_time = "02:00-03:00"
keep_days = 7
}
}
resource "huaweicloud_lb_loadbalancer" "front" {
name = "shop-front"
vip_subnet_id = huaweicloud_vpc_subnet.app.ipv4_subnet_id
}[
{
"id": "huaweicloud_compute_instance.web",
"result": {
"class": "RECONFIGURE",
"confidence": "MEDIUM",
"target": {
"service": "STACKIT Compute Engine"
},
"reason": "An ECS instance becomes a STACKIT server. The flavor becomes a STACKIT flavor, the image is rebuilt or imported, and the attached disks and interfaces become volumes and network interfaces."
}
},
{
"id": "huaweicloud_rds_instance.orders",
"result": {
"class": "REPLATFORM",
"confidence": "MEDIUM",
"target": {
"service": "STACKIT PostgreSQL Flex"
},
"reason": "Managed PostgreSQL to managed PostgreSQL: data moves with pg_dump/pg_restore or logical replication, and the flavor becomes a Flex flavor."
}
},
{
"id": "huaweicloud_lb_loadbalancer.front",
"result": {
"class": "RECONFIGURE",
"confidence": "MEDIUM",
"target": {
"service": "STACKIT Network Load Balancer"
},
"reason": "A shared load balancer becomes a STACKIT Network Load Balancer. Listeners and backends are rewritten, and the public address changes."
}
}
]Eight of nine are reconfigured
Network, security group, disk, bucket, public IP, server and load balancer keep their role on STACKIT with different settings. Only the database is classed REPLATFORM, because it becomes a different managed service.
The database keeps its engine
Managed PostgreSQL goes to PostgreSQL Flex. The flavor becomes a Flex flavor and the data moves with pg_dump and pg_restore or logical replication, as the run states.
Every unit has an owner
The run sorts the nine manual steps into seven work packages for the Network, Data, Storage and Platform Architect roles. Each package is done when the STACKIT counterpart is set up and checked.
How the nine resources map
| Huawei Cloud resource | STACKIT target | Class and wave |
|---|---|---|
| VPC | STACKIT network; a Network Area connects projects where routing is needed | RECONFIGURE · wave 1 |
| Security group | STACKIT security group | RECONFIGURE · wave 1 |
| EVS volume | STACKIT Block Storage | RECONFIGURE · wave 1 |
| OBS bucket | STACKIT Object Storage (S3 API) | RECONFIGURE · wave 1 |
| EIP | STACKIT public IP; the address changes | RECONFIGURE · wave 1 |
| VPC subnet | STACKIT network with its own address range | RECONFIGURE · wave 2 |
| ECS instance | STACKIT Compute Engine server | RECONFIGURE · wave 3 |
| Shared load balancer | STACKIT Network Load Balancer | RECONFIGURE · wave 3 |
| RDS PostgreSQL | STACKIT PostgreSQL Flex | REPLATFORM · wave 3 |
Classes and waves as the run decided them. A wave is a dependency order: a unit moves after every unit it depends on. It is not a schedule and not an order for the data.
The wave order and the provider pin the run writes
Left: the dependency order from migration/technical-sequencing.md, lines as written. Right: terraform/terraform.tf, the only Terraform the run writes for this source besides variables.tf and a README.
## Wave 1 — 5 unit(s)
| Unit | Class | Target |
|---|---|---|
| `huaweicloud_evs_volume.uploads` | RECONFIGURE / MEDIUM | STACKIT Block Storage |
| `huaweicloud_networking_secgroup.app` | RECONFIGURE / MEDIUM | STACKIT security groups |
| `huaweicloud_obs_bucket.media` | RECONFIGURE / MEDIUM | STACKIT Object Storage |
| `huaweicloud_vpc.main` | RECONFIGURE / MEDIUM | STACKIT network |
| `huaweicloud_vpc_eip.front` | RECONFIGURE / MEDIUM | STACKIT public IP |
## Wave 2 — 1 unit(s)
| Unit | Class | Target |
|---|---|---|
| `huaweicloud_vpc_subnet.app` | RECONFIGURE / MEDIUM | STACKIT network |
## Wave 3 — 3 unit(s)
| Unit | Class | Target |
|---|---|---|
| `huaweicloud_compute_instance.web` | RECONFIGURE / MEDIUM | STACKIT Compute Engine |
| `huaweicloud_lb_loadbalancer.front` | RECONFIGURE / MEDIUM | STACKIT Network Load Balancer |
| `huaweicloud_rds_instance.orders` | REPLATFORM / MEDIUM | STACKIT PostgreSQL Flex |
## Cutover (decision support — performed by the customer)
No cutover facts: the scan and the draft established no DNS record set whose value the draft re-binds to a generated address, no public address re-binding, no DNS record unit, no certificate unit and no open cutover decision. That is not a statement that nothing has to be cut over: a name, an address or a certificate outside the scanned source is not seen, and a unit that exists only if OpenTofu decides so at plan time is not read here. StackToIT performs no cutover and gives no time estimate.terraform {
# Write-only attributes (e.g. a VPN pre-shared key) need Terraform/OpenTofu 1.11 or later.
required_version = ">= 1.11.0"
required_providers {
stackit = {
source = "stackitcloud/stackit"
version = "0.121.0"
}
}
}
Network first
The VPC and the security group lead, the subnet follows, and only then do server, load balancer and database appear in wave 3.
Data is not a wave
The disk, bucket and database hold state, but the wave table orders resources, not copies of data. Rehearse each data move on its own timeline.
Decisions that stay with your architects
Region
The run asks for eu01 or eu02 before it writes a draft. For PostgreSQL Flex the run records both regions as offered; for the Network Load Balancer it records that region availability is not established, so check it for your region.
Load balancer type
A shared load balancer maps to the Network Load Balancer, which works at layer 4 only and leaves encryption to you. If your listeners terminate TLS or route by path, plan an Application Load Balancer instead.
Deny rules
STACKIT security groups only allow traffic. A deny rule or a rule priority of the source cannot be carried over as written.
Data mechanism, RPO and downtime
Data class, recovery point and tolerated downtime show NOT_PROVIDED in the run until you state them. The mechanism is then your choice per unit.
Public address
The EIP becomes a STACKIT public IP and the address itself changes, so DNS records and partner allow lists change with it.
Landing zone layout
Number of projects, folders and who may create networks are design decisions the run cannot derive from Terraform.
Questions teams ask before they start
Does StackToIT write STACKIT Terraform for a Huawei Cloud estate?
Not for these services yet. The run writes terraform.tf with the pinned STACKIT provider, variables.tf and a README, and lists each of the nine resources as left for the architect. The mapping, the reasons and the order are the result.
Does StackToIT need access to our Huawei Cloud account?
No. It reads Terraform and OpenTofu root modules that use the huaweicloud/huaweicloud provider and connects to no account. Anything that exists only in the console is outside the result.
Are the waves the order in which we cut over?
They are the dependency order of the resources. Cutover, data copies and rollback are separate decisions that the plan leaves to the person who carries out each step.
How long does such a migration take?
The run states no duration. Data size, change rate and tolerated downtime are not in the Terraform, so the data-movement file lists them as not known until you provide them.
Sources
Your next move: STACKIT.
Tell us about your estate. We show you what StackToIT delivers for it: target architecture, Terraform artifacts and a structured migration plan.