Migrate a Kubernetes application from a local Kind cluster to Huawei Cloud CCE. Covers CCE cluster creation, node pool provisioning, public API access via EIP, ELB setup for Ingress, SWR image push, Nginx Ingress Controller installation, application deployment with CCE-specific values, and post-migration validation. Based on a verified end-to-end migration of an nginx-demo Helm chart.
Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
Migrate a Kubernetes application from a local Kind cluster to Huawei Cloud CCE. Covers CCE cluster creation, node pool provisioning, public API access via EIP, ELB setup for Ingress, SWR image push, Nginx Ingress Controller installation, application deployment with CCE-specific values, and post-migration validation. Based on a verified end-to-end migration of an nginx-demo Helm chart.
Migrate a Kubernetes application from a local Kind cluster to Huawei Cloud CCE (Cloud Container Engine). This skill documents the exact steps, pitfalls, and solutions discovered during a verified end-to-end migration.
Rules
ALWAYS create the CCE cluster first, then the node pool — Cluster creation returns an ID needed for all subsequent operations. Poll CCE ShowCluster until status.phase=Available before proceeding.
NEVER use Ubuntu with overlay_l2 — CCE rejects Ubuntu 22.04 on overlay_l2 clusters with "Not support Ubuntu 22.04 in overlay_l2 cluster". Use instead.
EulerOS 2.9
ALWAYS validate flavor availability per AZ — Flavors like c3.large.2 may not exist in all AZs. Use hcloud_hcloud_list_flavors with availability_zone filter before creating the node pool. Prefer small flavors (ac8.large.2 = 2 vCPU / 4 GB) for dev/test.
ALWAYS bind an EIP to the API server ELB — The internal endpoint (172.31.x.x:5443) is unreachable from outside the VPC. Create an EIP first, then bind with CCE UpdateClusterEip --spec.action=bind --spec.spec.id=<eip_id>. Re-generate kubeconfig afterward.
ALWAYS use L4+L7 ELB for nginx-ingress — An L7-only ELB cannot create TCP listeners (ports 80/443). The error: "Loadbalancer has only flavor of type l7 and cannot create listeners of type l4". Create the ELB with both l4_flavor_id and l7_flavor_id.
ALWAYS push images to SWR before deploying — CCE nodes cannot reliably pull from Docker Hub or registry.k8s.io (timeouts). Push all application images to swr.<region>.myhuaweicloud.com/<namespace>. Use SWR CreateAuthorizationToken for temporary credentials.
ALWAYS create an imagePullSecret for private SWR namespaces — CCE nodes can pull from hwofficial (public SWR namespace), but custom namespaces require authentication. Create a docker-registry secret with decoded SWR credentials and patch the service account: kubectl patch serviceaccount default -p '{"imagePullSecrets":[{"name":"swr-secret"}]}'.
NEVER use RWO PVC with multi-node Deployments on CCE — EVS (csi-disk) volumes with ReadWriteOnce cannot be attached to multiple nodes simultaneously (Multi-Attach error). Options: (a) disable PVC if content comes from ConfigMap, (b) use ReadWriteMany with SFS/SFS Turbo, (c) use StatefulSet with volumeClaimTemplates.
ALWAYS disable admission webhooks on ingress — The admission webhook job pulls images from registry.k8s.io which times out on CCE. Set controller.admissionWebhooks.enabled=false.
ALWAYS use SWR images for ingress controller — Set controller.image.registry=swr.<region>.myhuaweicloud.com, controller.image.image=hwofficial/nginx-ingress. Get the compatible tag from the CCE add-on template: CCE ListAddonTemplates --addon_template_name=nginx-ingress, find the version supporting your cluster K8s version.
NEVER trust hcloud CLI for nested addon values — CCE CreateAddonInstance --spec.values only accepts {} or []. For add-ons requiring nested JSON (like nginx-ingress with ELB ID), install via Helm with kubernetes.io/elb.id service annotation instead.
ALWAYS decode SWR auth before creating secrets — SWR CreateAuthorizationToken returns base64-encoded auth field. Decode with echo "$AUTH" | base64 -d, then split into username:password for kubectl create secret docker-registry.
Kubeconfig re-generation may need retries — After binding EIP, CCE CreateKubernetesClusterCert may fail transiently with EOF error. Retry after 15-30 seconds.
ALWAYS verify each step before proceeding — After cluster creation, node pool, EIP bind, ELB create, Helm install, and app deploy — run the corresponding verification command. Never assume success.
Prerequisites
Tool
Purpose
hcloud (KooCLI)
Huawei Cloud API calls
kubectl
Kubernetes CLI
Helm 3.x
Application deployment
Docker
Image tag/push to SWR
Huawei Cloud requirements:
VPC and subnet already exist in the target region
IAM permissions for CCE, EIP, ELB, SWR, ECS
SSH keypair (create via ECS CreateKeypair or import)
docker pull <SOURCE_IMAGE>
docker tag <SOURCE_IMAGE> swr.<REGION>.myhuaweicloud.com/<SWR_NAMESPACE>/<IMAGE_NAME>:<TAG>
docker push swr.<REGION>.myhuaweicloud.com/<SWR_NAMESPACE>/<IMAGE_NAME>:<TAG>
Step 7: Install Nginx Ingress Controller
Get the compatible SWR image tag from CCE add-on templates:
hcloud CCE ListAddonTemplates --cli-region=<REGION> --addon_template_name=nginx-ingress
# Find version supporting your K8s version (e.g., 6.0.2 for v1.30)# Note the tag (e.g., v1.14.3_6.0.2)
Create ingress values file (see templates/ingress-values-cce.yaml):
KUBECONFIG=~/.kube/config-<CLUSTER_NAME> kubectl get pods -n ingress-nginx
KUBECONFIG=~/.kube/config-<CLUSTER_NAME> kubectl get svc -n ingress-nginx
# svc should show EXTERNAL-IP = ELB internal IP
Step 8: Create SWR Image Pull Secret
Required if using a private SWR namespace (not hwofficial):
KUBECONFIG=~/.kube/config-<CLUSTER_NAME> kubectl get pods -l app.kubernetes.io/name=<APP>
KUBECONFIG=~/.kube/config-<CLUSTER_NAME> kubectl get ingress
KUBECONFIG=~/.kube/config-<CLUSTER_NAME> kubectl get hpa
KUBECONFIG=~/.kube/config-<CLUSTER_NAME> kubectl get configmap <APP>-config -o yaml
KUBECONFIG=~/.kube/config-<CLUSTER_NAME> kubectl get secret <APP>-secret -o yaml
# Test via ELB public IP
curl -s -H "Host: <HOSTNAME>" http://<ELB_PUBLIC_IP>/
Verification checklist:
Check
Command
Expected
Pods Running
kubectl get pods
All 1/1 Running
Ingress has address
kubectl get ingress
ADDRESS column populated
HPA configured
kubectl get hpa
Min/Max/Target match source
ConfigMap matches
kubectl get cm -o yaml
Data matches source (or intentionally updated)
Secret matches
kubectl get secret -o yaml
Data matches source
App responds
curl -H "Host: ..." http://<ELB_IP>/
Expected HTML/response
CCE add-ons healthy
CCE ListAddonInstances
coreddns=running, everest=running
CCE Compatibility Mapping
Component
Local (Kind)
CCE
Migration Change
Container images
Docker Hub / registry.k8s.io
SWR registry
docker tag + docker push to SWR
Image pull auth
None (public)
imagePullSecret (private SWR)
Create swr-secret, patch ServiceAccount
Node OS
Kind (Debian-based)
EulerOS 2.9
Automatic (node pool config)
Ingress Controller
Helm from community
Helm with SWR images + ELB annotation
Change image registry, add kubernetes.io/elb.id
Ingress LoadBalancer
NodePort / hostNetwork
ELB (L4+L7)
Create ELB, annotate Service
PVC StorageClass
local-path
csi-disk (EVS)
Change storageClassName in values
PVC accessMode
ReadWriteOnce (single node)
ReadWriteOnce (single node, Multi-Attach error if multi-replica)
Disable PVC or use ReadWriteMany (SFS)
PVC size
1Gi (local)
10Gi (EVS minimum)
Adjust size in values
HPA
autoscaling/v2
Same
No change
ConfigMap/Secret
Same
Same
No change
K8s version
v1.30.0 (Kind)
v1.30.x-rXX (CCE)
Compatible within same minor version
Cost Reference
Resource
Specification
Billing
CCE cluster
cce.s1.small
Free (control plane managed)
Worker nodes
ac8.large.2 (2 vCPU / 4 GB)
Pay-per-use (ECS)
API server EIP
5_bgp, 5 Mbps, traffic
Pay-per-use (EIP + traffic)
Ingress ELB
L4+L7 s1.small, 5 Mbps, traffic
Pay-per-use (ELB + EIP + traffic)
EVS volumes
SAS, 40GB root + 100GB data
Pay-per-use (EVS)
SWR storage
Image storage
Pay-per-use (SWR)
Troubleshooting
Problem
Cause
Solution
"Not support Ubuntu 22.04 in overlay_l2 cluster"
Ubuntu incompatible with overlay_l2 network mode
Use EulerOS 2.9 in node pool config
Flavor not found in AZ
Flavor doesn't exist in the selected availability zone
Use hcloud_hcloud_list_flavors with AZ filter; pick a flavor with status normal
Kubeconfig generation: EOF error
Transient failure after EIP bind
Retry CCE CreateKubernetesClusterCert after 15-30 seconds
kubectl get nodes timeout via internal IP
Kubeconfig uses internal endpoint (172.31.x.x)
Bind EIP to API server, re-generate kubeconfig
ELB: "cannot create listeners of type l4"
ELB created with L7 flavor only
Create ELB with both l4_flavor_id AND l7_flavor_id
ImagePullBackOff from registry.k8s.io
CCE nodes cannot reach registry.k8s.io
Push images to SWR; use SWR image references
ImagePullBackOff from private SWR namespace
CCE nodes lack auth for custom SWR namespace
Create imagePullSecret with decoded SWR credentials; patch ServiceAccount
Multi-Attach error for PVC
RWO EVS volume already attached to another node
Disable PVC, use ReadWriteMany (SFS), or use StatefulSet
Admission webhook BackoffLimitExceeded
Webhook job image from registry.k8s.io unreachable