
Huawei Cloud Cci Instance Management
- 94 installs
- 19 repo stars
- Updated July 31, 2026
- huaweicloud/huaweicloud-skills
Manage Huawei Cloud CCI serverless container lifecycle via hcloud CLI: namespaces, networks, deployments, statefulsets, pods, and EIPPools.
About
Manages the full lifecycle of Huawei Cloud CCI serverless containers (namespace, network, deployment, statefulset, pod, EIPPool, logs, metrics) through the hcloud CLI. A developer uses it to run serverless workloads without cluster management, with two-step confirmation on destructive operations.
- Serverless: create namespace, network, then deploy workloads
- Two-step confirmation; namespace deletion cascades all resources
Huawei Cloud Cci Instance Management by the numbers
- 94 all-time installs (skills.sh)
- +17 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #572 of 1,042 Cloud & Infrastructure skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/huaweicloud/huaweicloud-skills --skill huawei-cloud-cci-instance-managementAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 94 |
|---|---|
| repo stars | ★ 19 |
| Last updated | July 31, 2026 |
| Repository | huaweicloud/huaweicloud-skills ↗ |
What it does
Manage Huawei Cloud CCI serverless container lifecycle via hcloud CLI: namespaces, networks, deployments, statefulsets, pods, and EIPPools.
Files
Huawei Cloud CCI Container Instance Lifecycle Management
Overview
Manage Huawei Cloud CCI (Cloud Container Instance) full lifecycle using hcloud CLI (KooCLI). CCI is a serverless container service — no cluster management needed, just create a Namespace, define a Network, then deploy workloads directly.
Architecture: hcloud CLI → CCI OpenAPI → Namespace / Network / Deployment / StatefulSet / Pod / EIPPool / Service / Ingress
Constraints and Rules
Security Rules
- Two-step confirmation: All destructive operations (delete Namespace/Network/Deployment/StatefulSet/Pod/EIPPool) require explicit user confirmation — preview command, resource details, and risk warning first; execute only after user confirms.
- Credential security: Never expose AK/SK values in conversation, commands, or output. Only use
hcloud configure listto check credential status (presence only). Prefer profile mode or environment variables over explicit AK/SK parameters.
Resource Constraints
- Namespace flavor annotation is mandatory: Every namespace must carry
namespace-kubernetes-io/flavorannotation (value:general-computingorgpu-accelerated). Without it, creation fails. - limits must equal requests: CCI enforces
resources.limits == resources.requests. Mismatch causes "limit and request doesn't equal" error. Set both to the same values (e.g.,500m/1Gi). - Network must precede workloads: Pod/Deployment/StatefulSet creation fails or stays Pending if no Network exists in the namespace. Always create Network before deploying workloads.
- VPC CIDR restriction: VPC subnet CIDR must NOT be
10.247.0.0/16— CCI reserves this range for Service networking. Using it causes IP conflicts and workload creation failures. - Deletion order: Pod → Deployment/StatefulSet → EIPPool → Network → Namespace. Deleting a Namespace cascades all resources under it.
hcloud CLI Constraints
- Network creation must use Python helper script: hcloud CLI cannot pass annotation keys containing dots (
network.alpha.kubernetes.io/default-security-group). Neither dot notation nor--cli-jsonInputworks. Usescripts/cci_network_helper.py. - Namespace annotation uses hyphen replacement: Keys like
namespace.kubernetes.io/flavorcan use hyphens (namespace-kubernetes-io/flavor) and CCI auto-normalizes. This workaround only works for Namespace, NOT for Network. - Always verify parameters with `--help`: CCI has hundreds of parameters. Run
hcloud CCI <Operation> --helpbefore constructing any command. The help output is the authoritative source.
Detailed breakdowns of these rules are in Security Constraints, hcloud CLI Limitations, and Precautions.
Standard Workflow
1. Create Namespace (with flavor annotation)
2. Create Network (requires Python helper script for annotation — see hcloud CLI Limitations)
3. Create Deployment / StatefulSet / Pod (run workloads)
4. Query status, view logs
5. (Optional) Create EIPPool for Pod public IP access
6. Cleanup: delete workload → delete Network → delete NamespacePrerequisites
1. hcloud CLI Requirements (MANDATORY)
- hcloud CLI installed (version >= 7.2.2)
- Run
hcloud versionto verify installation - First-time usage:
printf "y\n" | hcloud versionto accept privacy statement
2. Credential Configuration
hcloud CLI supports two credential modes. See references/credential-configuration.md for full details.
Quick setup (choose one):
# Mode A — Long-term AK/SK
export HUAWEI_CLOUD_AK=<your-ak>
export HUAWEI_CLOUD_SK=<your-sk>
export HUAWEI_CLOUD_REGION=cn-north-4
# Mode B — Temporary AK/SK + SecurityToken
export HUAWEI_CLOUD_AK=<your-temp-ak>
export HUAWEI_CLOUD_SK=<your-temp-sk>
export HUAWEI_CLOUD_SECURITY_TOKEN=<your-security-token>
export HUAWEI_CLOUD_REGION=cn-north-4- Security rules: Never expose AK/SK/SecurityToken values. Use
hcloud configure listto check presence only.
⚠️ Known limitation — Python helper script credentials are independent of hcloud CLI: The Python helper script (scripts/cci_network_helper.py) usesHW_ACCESS_KEY/HW_SECRET_KEY(and optionallyHW_SECURITY_TOKEN) environment variables for authentication, which are separate from hcloud CLI's credential source (profile orHUAWEI_CLOUD_AK/HUAWEI_CLOUD_SK). If the credentials inHW_ACCESS_KEY/HW_SECRET_KEYlack the necessary IAM permissions for CCI Network creation, the script will fail with a 403 error. Ensure these variables contain credentials with sufficient CCI permissions (e.g.,CCI FullAccess). The hcloud CLI continues using its own credential source independently — running the helper script does not affect subsequent hcloud CLI commands.
3. Validation Check
hcloud version
hcloud configure listSecurity Constraints
Dangerous Operation Confirmation Mechanism
This skill strictly enforces a two-step confirmation mechanism for all destructive operations.
All destructive operations require explicit user confirmation before execution. The process:
Step 1: Preview — Show the command, resource details, and risk warning
Step 2: Confirm & Execute — Only after user explicitly confirms
Operations Requiring Confirmation
| Operation | Risk Level | Description |
|---|---|---|
| Delete Namespace | 🔴 Critical | Cascades — deletes ALL resources under this namespace (Network, Pods, Deployments, etc.) |
| Delete Network | 🟠 High | Disconnects namespace from VPC; running pods lose network |
| Delete Deployment | 🟠 High | Terminates all replicas of the workload |
| Delete StatefulSet | 🟠 High | Terminates all replicas; PVC data may be lost |
| Delete Pod | 🟠 High | Terminates the container instance |
| Delete EIPPool | 🟡 Medium | Releases public IPs allocated to pods |
Credential Security
- Never expose AK/SK/SecurityToken values in conversation, commands, or output
- Never ask user to input AK/SK/SecurityToken directly in conversation
- Only use
hcloud configure listto check credential status (presence only, not values) - Prefer profile mode or environment variables over explicit AK/SK parameters
Command Format Standard
CCI follows the standard hcloud format with Kubernetes-style nested parameters:
hcloud CCI <Operation> --param=value --cli-region=<region> --cli-output=jsonCCI-Specific Parameter Rules
CCI parameters follow Kubernetes API conventions — deeply nested objects with dot notation:
1. *Annotations use `{} format**: --metadata.annotations.namespace-kubernetes-io/flavor=general-computing 2. **Labels use {}` format: `--metadata.labels.app=my-app` 3. Containers array (1-based): `--spec.template.spec.containers.1.name=main --spec.template.spec.containers.1.image=nginx` 4. Resources use `{} format**: --spec.template.spec.containers.1.resources.limits.cpu=500m 5. **Selector matchLabels use {}` format: `--spec.selector.matchLabels.app=my-app` 6. Namespaced operations require `--namespace`*: all workload operations must specify namespace
⚠️ Critical: Before constructing any CCI command, always run hcloud CCI <Operation> --help to verify exact parameter names. CCI has hundreds of parameters; the help output is the authoritative source.Parameter Format Details
See references/parameter-format.md for complete CCI parameter format rules and examples.
Scenario Routing
| User Intent | Reference Document |
|---|---|
| Create/query/delete Namespace | references/task-namespace-management.md |
| Create/query/delete Network | references/task-network-management.md |
| Create/query/update/delete/scale Deployment | references/task-deployment-management.md |
| Create/query/update/delete StatefulSet | references/task-statefulset-management.md |
| Create/query/delete Pod | references/task-pod-management.md |
| Create/query/delete EIPPool | references/task-eippool-management.md |
| Query status, view logs, events | references/task-logs-and-status.md |
| Full workflow (create→run→cleanup) | references/common-workflows.md |
| All CCI operations quick reference | references/cci-operation-catalog.md |
| Troubleshooting | references/troubleshooting.md |
| IAM permissions | references/iam-policies.md |
| Verification steps | references/verification-method.md |
| Correct/error pattern comparison | references/acceptance-criteria.md |
Core Commands
Namespace
# Create namespace (general-computing flavor)
hcloud CCI createCoreV1Namespace \
--metadata.name=<ns-name> \
--metadata.annotations.namespace-kubernetes-io/flavor=general-computing \
--cli-region=<region \
--cli-output=json
# List namespaces
hcloud CCI listCoreV1Namespace --cli-region=<region> --cli-output=json
# Read namespace details
hcloud CCI readCoreV1Namespace --name=<ns-name> --cli-region=<region> --cli-output=json
# Delete namespace (TWO-STEP CONFIRMATION REQUIRED)
hcloud CCI deleteCoreV1Namespace --name=<ns-name> --cli-region=<region>Network
⚠️ hcloud CLI limitation: Network creation requires a Python helper script because hcloud CLI cannot pass the annotation keynetwork.alpha.kubernetes.io/default-security-group(contains dots that hcloud treats as nested levels). The--cli-jsonInputapproach also doesn't work due to an hcloud bug where annotations show in--dryrunbut aren't transmitted in actual requests. See hcloud CLI Limitations below.
>
⚠️ Credential requirement: The Python helper script usesHW_ACCESS_KEY/HW_SECRET_KEY(and optionallyHW_SECURITY_TOKEN) environment variables for authentication. This is independent from hcloud CLI's credential source (which reads fromHUAWEI_CLOUD_AK/HUAWEI_CLOUD_SKor its profile). If the credentials inHW_ACCESS_KEY/HW_SECRET_KEYlack CCI Network creation permissions, the script will fail with 403. Ensure they have sufficient IAM permissions (e.g.,CCI FullAccess). After the script runs, hcloud CLI commands continue using their own credential source unaffected.
# Step 1: Get VPC subnet details (including neutron_network_id)
hcloud VPC ShowSubnet --vpc_id=<vpc-id> --subnet_id=<subnet-id> --cli-region=<region> --cli-output=json
# Step 2: Create network via Python helper script
python scripts/cci_network_helper.py create \
--namespace=<ns-name> \
--name=<network-name> \
--vpc-id=<vpc-id> \
--subnet-id=<subnet-id> \
--network-id=<neutron-network-id> \
--security-group-id=<sg-id> \
--region=<region>
# Step 3: Check network status until Active
hcloud CCI readNetworkingCciIoV1beta1NamespacedNetworkStatus \
--name=<network-name> \
--namespace=<ns-name> \
--cli-region=<region> \
--cli-output=json
# List networks
hcloud CCI listNetworkingCciIoV1beta1NamespacedNetwork \
--namespace=<ns-name> \
--cli-region=<region> \
--cli-output=jsonRequired Network spec fields: Network creation requires attachedVPC, subnetID, networkType, AND networkID (neutron network ID). The networkID field is REQUIRED — it is the neutron network ID obtained from hcloud VPC ShowSubnet.
Required Network annotation: network.alpha.kubernetes.io/default-security-group (the correct annotation key for CCI Network security group, NOT security-group-id). This annotation must be set to the security group ID.
Deployment
# Create deployment
hcloud CCI createAppsV1NamespacedDeployment \
--namespace=<ns-name> \
--metadata.name=<deploy-name> \
--spec.replicas=1 \
--spec.selector.matchLabels.app=<deploy-name> \
--spec.template.metadata.labels.app=<deploy-name> \
--spec.template.spec.containers.1.name=<container-name> \
--spec.template.spec.containers.1.image=<image> \
--spec.template.spec.containers.1.resources.limits.cpu=500m \
--spec.template.spec.containers.1.resources.limits.memory=1Gi \
--spec.template.spec.containers.1.resources.requests.cpu=500m \
--spec.template.spec.containers.1.resources.requests.memory=1Gi \
--cli-region=<region> \
--cli-output=json
# Scale deployment
hcloud CCI patchAppsV1NamespacedDeploymentScale \
--name=<deploy-name> \
--namespace=<ns-name> \
--spec.replicas=<new-replicas> \
--cli-region=<region>
# Read deployment status
hcloud CCI readAppsV1NamespacedDeploymentStatus \
--name=<deploy-name> \
--namespace=<ns-name> \
--cli-region=<region> \
--cli-output=jsonStatefulSet
# Create statefulset
hcloud CCI createAppsV1NamespacedStatefulSet \
--namespace=<ns-name> \
--metadata.name=<sts-name> \
--spec.replicas=1 \
--spec.selector.matchLabels.app=<sts-name> \
--spec.template.metadata.labels.app=<sts-name> \
--spec.template.spec.containers.1.name=<container-name> \
--spec.template.spec.containers.1.image=<image> \
--spec.template.spec.containers.1.resources.limits.cpu=500m \
--spec.template.spec.containers.1.resources.limits.memory=1Gi \
--cli-region=<region> \
--cli-output=json
# Read statefulset status
hcloud CCI readAppsV1NamespacedStatefulSetStatus \
--name=<sts-name> \
--namespace=<ns-name> \
--cli-region=<region> \
--cli-output=jsonPod
# Create pod (single container instance)
hcloud CCI createCoreV1NamespacedPod \
--namespace=<ns-name> \
--metadata.name=<pod-name> \
--spec.containers.1.name=<container-name> \
--spec.containers.1.image=<image> \
--spec.containers.1.resources.limits.cpu=500m \
--spec.containers.1.resources.limits.memory=1Gi \
--cli-region=<region> \
--cli-output=json
# Read pod status
hcloud CCI readCoreV1NamespacedPodStatus \
--name=<pod-name> \
--namespace=<ns-name> \
--cli-region=<region> \
--cli-output=json
# Read pod logs
hcloud CCI readCoreV1NamespacedPodLog \
--name=<pod-name> \
--namespace=<ns-name> \
--container=<container-name> \
--cli-region=<region>EIPPool
# Create EIPPool (for pod public IP access — auto-create EIPs)
hcloud CCI createCrdYangtseCniV1NamespacedEIPPool \
--namespace=<ns-name> \
--apiVersion=crd.yangtse.cni/v1 \
--kind=EIPPool \
--metadata.name=<eippool-name> \
--spec.amount=1 \
--spec.eipAttributes.networkType=5_bgp \
--spec.eipAttributes.ipVersion=4 \
--spec.eipAttributes.bandwidth.shareType=PER \
--spec.eipAttributes.bandwidth.size=5 \
--spec.eipAttributes.bandwidth.chargeMode=bandwidth \
--spec.eipAttributes.bandwidth.name=<bw-name> \
--cli-region=<region> \
--cli-output=json
# Read EIPPool status
hcloud CCI readCrdYangtseCniV1NamespacedEIPPoolStatus \
--name=<eippool-name> \
--namespace=<ns-name> \
--cli-region=<region> \
--cli-output=jsonEIPPool required fields: --apiVersion=crd.yangtse.cni/v1 and --kind=EIPPool are mandatory. spec.eipAttributes.networkType is required (values: 5_bgp for dynamic BGP, 5_gray for dedicated load balancing). spec.eipAttributes.bandwidth.chargeMode and name are required when auto-creating EIPs.
Pod EIP binding: To assign an EIPPool to a Pod, add annotation yangtse.io/eippool=<eippool-name> (use hyphen workaround: --metadata.annotations.yangtse-io/eippool=<eippool-name>).
VPC/Subnet Prerequisites
CCI workloads run inside a Network that maps to an existing VPC subnet. Before creating a Network, query available VPCs and subnets, and obtain the neutron network ID (required for Network creation):
# List VPCs
hcloud VPC ListVpcs --cli-region=<region> --cli-output=json
# List subnets
hcloud VPC ListSubnets --cli-region=<region> --cli-output=json
# Get subnet details (including neutron_network_id — REQUIRED for Network creation)
hcloud VPC ShowSubnet --vpc_id=<vpc-id> --subnet_id=<subnet-id> --cli-region=<region> --cli-output=json⚠️ VPC subnet CIDR restriction: The VPC and subnet CIDR must NOT be 10.247.0.0/16 — this range is reserved by CCI for Service networking. Using it causes IP conflicts and workload creation failures.⚠️ neutron_network_id is required: Theneutron_network_idfromVPC ShowSubnetoutput is the value for thenetworkIDfield in Network spec. This field is REQUIRED for Network creation.
Namespace Flavor Types
| Flavor Value | Description | Use Case |
|---|---|---|
general-computing | General computing type | Standard workloads, web services, microservices |
gpu-accelerated | GPU accelerated type | AI, ML, high-performance computing |
Resource Quota and Limits
CCI enforces resource quotas per namespace. Common defaults:
| Resource | Default Limit |
|---|---|
| Pods | varies by region |
| CPU per Pod | 0.25 - 8 cores |
| Memory per Pod | 0.5Gi - 32Gi |
| PVCs | varies |
Query current quotas:
hcloud CCI listCoreV1NamespacedResourceQuota --namespace=<ns-name> --cli-region=<region> --cli-output=jsonOutput Format
JSON (recommended)
hcloud CCI <Operation> --cli-region=<region> --cli-output=jsonTable (for manual viewing)
hcloud CCI <Operation> --cli-region=<region> --cli-output=tableJMESPath Filtering
# Filter deployment status
hcloud CCI readAppsV1NamespacedDeploymentStatus --name=<deploy> --namespace=<ns> --cli-region=<region> --cli-output=json --cli-query="{replicas:status.replicas,ready:status.readyReplicas,available:status.availableReplicas}"
# Filter pod phase
hcloud CCI readCoreV1NamespacedPodStatus --name=<pod> --namespace=<ns> --cli-region=<region> --cli-output=json --cli-query="status.phase"--cli-region=<region> --cli-output=json \ --cli-query="status.phase"
## Debugging
Add `--cli-debug=true` to any command for detailed request/response information:
hcloud CCI <Operation> --cli-debug=true --cli-region=<region>
## Parameter Confirmation
Before executing any CCI operation, confirm these parameters:
| Parameter | Required | Description | Source |
|---|---|---|---|
| `--namespace` | Yes | CCI namespace name | Existing or newly created |
| `--cli-region` | Yes | Huawei Cloud region ID | `HUAWEI_CLOUD_REGION` or config |
| `--metadata.name` | Yes | Resource name | User specified |
| Flavor annotation | Yes (Namespace) | `general-computing` or `gpu-accelerated` | User choice |
| VPC/Subnet ID | Yes (Network) | From `VPC ListVpcs` / `VPC ShowSubnet` | Query existing resources |
| neutron_network_id | Yes (Network) | From `VPC ShowSubnet` response | Query result |
> Run `hcloud CCI <Operation> --help` before any CCI command to verify parameter names, then cross-reference the table above.
## Precautions
See [references/troubleshooting.md](references/troubleshooting.md) for detailed troubleshooting.
**Quick reference**:
| Issue | Cause | Quick Fix |
|---|---|---|
| Namespace creation fails | Missing flavor annotation | Add `--metadata.annotations.namespace-kubernetes-io/flavor=general-computing` |
| Network creation fails (400/403) | Missing VPC/subnet/annotation/networkID, or credential scope insufficient | Verify subnet/neutron IDs, security group; use Python helper; use **long-term AK/SK** (Mode A) |
| Pod stays Pending | No Network in namespace | Create Network first |
| 403 permission error | Insufficient IAM | Check [references/iam-policies.md](references/iam-policies.md) |
| Deep nested param errors | Wrong dot notation | Use `--help` to verify exact parameter path |
| Annotation with dots not passed | hcloud CLI limitation | Use Python helper script for Network creation |
| EIPPool creation fails (400/422) | Missing apiVersion/kind/networkType | Add all required fields (see EIPPool section) |
| limit/request mismatch | CCI requires limits == requests | Set requests same as limits (e.g., both `500m/1Gi`) |
## Verification Method
See [references/verification-method.md](references/verification-method.md) for complete verification steps.
**Quick checklist**:
| Step | Command | Expected Result |
|---|---|---|
| Namespace | `hcloud CCI readCoreV1Namespace --name=<ns> --cli-region=<region>` | status.phase=Active |
| Network | `hcloud CCI readNetworkingCciIoV1beta1NamespacedNetworkStatus --name=<net> --namespace=<ns>` | status.phase=Active |
| Deployment | `hcloud CCI readAppsV1NamespacedDeploymentStatus --name=<deploy> --namespace=<ns>` | readyReplicas >= 1 |
| Pod | `hcloud CCI readCoreV1NamespacedPodStatus --name=<pod> --namespace=<ns>` | status.phase=Running |
## Best Practices
1. **Namespace isolation**: Use different namespaces for different teams/projects to avoid resource conflicts
2. **EIPPool on-demand**: Only create EIPPool when Pod public IP access is needed
## hcloud CLI Limitations
> **⚠️ Critical**: hcloud CLI has known limitations that affect CCI operations. Understanding these is essential for successful Network creation.
| Limitation | Impact | Workaround |
|---|---|---|
| **Cannot pass annotation keys containing dots (.) via CLI parameters** | hcloud treats dots in parameter names as nested object levels, so `--metadata.annotations.network.alpha.kubernetes.io/default-security-group` creates a deeply nested structure instead of a single annotation key | Use Python helper script (`scripts/cci_network_helper.py`) for Network creation |
| **`--cli-jsonInput` doesn't properly transmit annotations** | hcloud bug: annotations appear in `--dryrun` output but are not transmitted in actual API requests | Use Python helper script instead |
| **`--cli-jsonInput` requires ASCII encoding** | UTF-8 BOM causes JSON parsing failure | Ensure JSON input files are saved as plain ASCII (no BOM) |
| **Namespace annotation works with hyphen replacement** | Keys like `namespace.kubernetes.io/flavor` can use hyphens (`namespace-kubernetes-io/flavor`) and CCI auto-normalizes them back | This workaround only works for Namespace, NOT for Network |
**Why Network needs a Python helper**: The Network annotation key `network.alpha.kubernetes.io/default-security-group` cannot be passed via hcloud CLI (neither dot notation nor `--cli-jsonInput`). Unlike Namespace annotations, CCI does NOT normalize hyphen-replaced keys for Network resources. The Python helper script (`scripts/cci_network_helper.py`) constructs the correct API request body directly.
## References
| Document | Description |
|---|---|
| [task-namespace-management.md](references/task-namespace-management.md) | Namespace lifecycle operations |
| [task-network-management.md](references/task-network-management.md) | Network lifecycle operations |
| [task-deployment-management.md](references/task-deployment-management.md) | Deployment lifecycle operations |
| [task-statefulset-management.md](references/task-statefulset-management.md) | StatefulSet lifecycle operations |
| [task-pod-management.md](references/task-pod-management.md) | Pod lifecycle operations |
| [task-eippool-management.md](references/task-eippool-management.md) | EIPPool operations |
| [task-logs-and-status.md](references/task-logs-and-status.md) | Status queries and log viewing |
| [cci-operation-catalog.md](references/cci-operation-catalog.md) | Full CCI operation quick reference |
| [parameter-format.md](references/parameter-format.md) | CCI parameter format rules and examples |
| [common-workflows.md](references/common-workflows.md) | Complete workflow sequences |
| [credential-configuration.md](references/credential-configuration.md) | Credential setup (long-term AK/SK & temporary AK/SK+SecurityToken) |
| [iam-policies.md](references/iam-policies.md) | IAM permission policies |
| [troubleshooting.md](references/troubleshooting.md) | Error troubleshooting |
| [verification-method.md](references/verification-method.md) | Verification steps |
| [acceptance-criteria.md](references/acceptance-criteria.md) | Correct/error pattern comparison |
| [scripts/cci_network_helper.py](scripts/cci_network_helper.py) | Python helper script for Network creation (bypasses hcloud CLI annotation limitations) |Acceptance Criteria: Correct vs Error Patterns for CCI Operations
Namespace Creation
| Correct Pattern | Error Pattern |
|---|---|
--metadata.annotations.namespace-kubernetes-io/flavor=general-computing included | Missing flavor annotation — creation request rejected |
--metadata.name=my-namespace specified | Missing metadata.name — parameter error |
Network Creation
| Correct Pattern | Error Pattern |
|---|---|
Valid subnet ID and VPC ID from hcloud VPC ListSubnets | Invalid or non-existent subnet/VPC ID — creation fails |
--namespace=<ns-name> specified | Missing namespace — operation targets wrong context |
CIDR != 10.247.0.0/16 (e.g., 10.0.0.0/24) | CIDR overlaps 10.247.0.0/16 — reserved for CCI internal routing |
Deployment Creation
| Correct Pattern | Error Pattern |
|---|---|
spec.selector.matchLabels matches spec.template.metadata.labels | Selector mismatch — pods not managed by Deployment |
spec.template.spec.containers.1.resources.limits.cpu and memory specified | Missing resource limits — pod may fail scheduling or exceed quota |
limits == requests (e.g., both 500m/1Gi) | limits != requests — CCI rejects with "limit and request doesn't equal" error |
--namespace=<ns-name> specified | Missing namespace — Deployment created in wrong/default namespace |
Pod Creation
| Correct Pattern | Error Pattern |
|---|---|
spec.containers.1.resources.limits.cpu and memory specified | Bare pod without resources — may fail scheduling |
--namespace=<ns-name> specified | Missing namespace — Pod created in wrong context |
EIPPool Creation
| Correct Pattern | Error Pattern |
|---|---|
--apiVersion=crd.yangtse.cni/v1 and --kind=EIPPool included | Missing apiVersion or kind — 400 error "Object 'Kind' is missing" |
--spec.eipAttributes.networkType=5_bgp specified | Missing networkType — 422 validation error |
--spec.eipAttributes.bandwidth.chargeMode=bandwidth and name=<bw-name> specified | Missing chargeMode or name — 403 validation error |
--namespace=<ns-name> specified | Missing namespace — EIPPool created in wrong context |
Parameter Format Patterns
| Correct Pattern | Error Pattern | Explanation |
|---|---|---|
--spec.template.spec.containers.1.image=nginx | --spec.template.spec.containers={"image":"nginx"} | hcloud CLI uses dotted path with {*} indexing, not JSON objects |
--spec.template.spec.containers.1.image=nginx (1-based index) | --spec.template.spec.containers.0.image=nginx (0-based index) | hcloud CLI uses 1-based indexing for arrays |
--metadata.name=my-ns | --metadata.name my-ns (space separation) | hcloud CLI requires = between key and value |
--cli-region=cn-north-4 | --region=cn-north-4 | CLI region flag is --cli-region, not --region |
--spec.template.spec.containers.1.resources.limits.cpu=500m | --spec.containers.1.resources.limits.cpu=500m (shallow path) | Must use full deep nested path as shown in --help output |
--metadata.annotations.namespace-kubernetes-io/flavor=general-computing | --metadata.annotations.flavor=general-computing (abbreviated key) | Annotation keys must be the exact full key name, not abbreviated |
CCI Operation Catalog
Complete quick reference of all hcloud CCI operations organized by category.
Namespace (Core)
| Operation | Description |
|---|---|
createCoreV1Namespace | Create namespace |
listCoreV1Namespace | List namespaces |
readCoreV1Namespace | Read namespace details |
deleteCoreV1Namespace | Delete namespace |
Network (CCI-specific CRD)
| Operation | Description |
|---|---|
createNetworkingCciIoV1beta1NamespacedNetwork | Create Network |
listNetworkingCciIoV1beta1NamespacedNetwork | List Networks |
readNetworkingCciIoV1beta1NamespacedNetwork | Read Network |
readNetworkingCciIoV1beta1NamespacedNetworkStatus | Read Network status |
deleteNetworkingCciIoV1beta1NamespacedNetwork | Delete Network |
deleteNetworkingCciIoV1beta1CollectionNamespacedNetwork | Delete all Networks in namespace |
Deployment (Apps)
| Operation | Description |
|---|---|
createAppsV1NamespacedDeployment | Create Deployment |
listAppsV1NamespacedDeployment | List Deployments in namespace |
listAppsV1DeploymentForAllNamespaces | List Deployments across namespaces |
readAppsV1NamespacedDeployment | Read Deployment |
readAppsV1NamespacedDeploymentStatus | Read Deployment status |
readAppsV1NamespacedDeploymentScale | Read Deployment scale |
patchAppsV1NamespacedDeployment | Update Deployment (patch) |
patchAppsV1NamespacedDeploymentScale | Scale Deployment |
replaceAppsV1NamespacedDeployment | Replace Deployment |
replaceAppsV1NamespacedDeploymentScale | Replace Deployment scale |
deleteAppsV1NamespacedDeployment | Delete Deployment |
deleteAppsV1CollectionNamespacedDeployment | Delete all Deployments in namespace |
StatefulSet (Apps)
| Operation | Description |
|---|---|
createAppsV1NamespacedStatefulSet | Create StatefulSet |
listAppsV1NamespacedStatefulSet | List StatefulSets |
listAppsV1StatefulSetForAllNamespaces | List StatefulSets across namespaces |
readAppsV1NamespacedStatefulSet | Read StatefulSet |
readAppsV1NamespacedStatefulSetStatus | Read StatefulSet status |
patchAppsV1NamespacedStatefulSet | Update StatefulSet |
replaceAppsV1NamespacedStatefulSet | Replace StatefulSet |
deleteAppsV1NamespacedStatefulSet | Delete StatefulSet |
deleteAppsV1CollectionNamespacedStatefulSet | Delete all StatefulSets in namespace |
Pod (Core)
| Operation | Description |
|---|---|
createCoreV1NamespacedPod | Create Pod |
listCoreV1NamespacedPod | List Pods in namespace |
listCoreV1PodForAllNamespaces | List Pods across namespaces |
readCoreV1NamespacedPod | Read Pod details |
readCoreV1NamespacedPodStatus | Read Pod status |
readCoreV1NamespacedPodLog | Read Pod logs |
patchCoreV1NamespacedPod | Update Pod |
replaceCoreV1NamespacedPod | Replace Pod |
deleteCoreV1NamespacedPod | Delete Pod |
deleteCoreV1CollectionNamespacedPod | Delete all Pods in namespace |
connectCoreV1GetNamespacedPodExec | Exec into Pod (GET) |
connectCoreV1PostNamespacedPodExec | Exec into Pod (POST) |
EIPPool (CCI-specific CRD)
| Operation | Description |
|---|---|
createCrdYangtseCniV1NamespacedEIPPool | Create EIPPool |
listCrdYangtseCniV1NamespacedEIPPool | List EIPPools |
readCrdYangtseCniV1NamespacedEIPPool | Read EIPPool |
readCrdYangtseCniV1NamespacedEIPPoolStatus | Read EIPPool status |
patchCrdYangtseCniV1NamespacedEIPPool | Update EIPPool |
replaceCrdYangtseCniV1NamespacedEIPPool | Replace EIPPool |
deleteCrdYangtseCniV1NamespacedEIPPool | Delete EIPPool |
Service (Core)
| Operation | Description |
|---|---|
createCoreV1NamespacedService | Create Service |
listCoreV1NamespacedService | List Services |
readCoreV1NamespacedService | Read Service |
readCoreV1NamespacedServiceStatus | Read Service status |
patchCoreV1NamespacedService | Update Service |
replaceCoreV1NamespacedService | Replace Service |
deleteCoreV1NamespacedService | Delete Service |
Ingress (Extensions)
| Operation | Description |
|---|---|
createExtensionsV1beta1NamespacedIngress | Create Ingress |
listExtensionsV1beta1NamespacedIngress | List Ingresses |
readExtensionsV1beta1NamespacedIngress | Read Ingress |
readExtensionsV1beta1NamespacedIngressStatus | Read Ingress status |
patchExtensionsV1beta1NamespacedIngress | Update Ingress |
replaceExtensionsV1beta1NamespacedIngress | Replace Ingress |
deleteExtensionsV1beta1NamespacedIngress | Delete Ingress |
deleteExtensionsV1beta1CollectionNamespacedIngress | Delete all Ingresses |
ConfigMap
| Operation | Description |
|---|---|
createCoreV1NamespacedConfigMap | Create ConfigMap |
listCoreV1NamespacedConfigMap | List ConfigMaps |
readCoreV1NamespacedConfigMap | Read ConfigMap |
patchCoreV1NamespacedConfigMap | Update ConfigMap |
replaceCoreV1NamespacedConfigMap | Replace ConfigMap |
deleteCoreV1NamespacedConfigMap | Delete ConfigMap |
deleteCoreV1CollectionNamespacedConfigMap | Delete all ConfigMaps |
Secret
| Operation | Description |
|---|---|
createCoreV1NamespacedSecret | Create Secret |
listCoreV1NamespacedSecret | List Secrets |
readCoreV1NamespacedSecret | Read Secret |
patchCoreV1NamespacedSecret | Update Secret |
replaceCoreV1NamespacedSecret | Replace Secret |
deleteCoreV1NamespacedSecret | Delete Secret |
deleteCoreV1CollectionNamespacedSecret | Delete all Secrets |
PersistentVolumeClaim
| Operation | Description |
|---|---|
createCoreV1NamespacedPersistentVolumeClaim | Create PVC |
listCoreV1NamespacedPersistentVolumeClaim | List PVCs |
readCoreV1NamespacedPersistentVolumeClaim | Read PVC |
replaceCoreV1NamespacedPersistentVolumeClaim | Replace PVC |
deleteCoreV1NamespacedPersistentVolumeClaim | Delete PVC |
Job (Batch v1)
| Operation | Description |
|---|---|
createBatchV1NamespacedJob | Create Job |
listBatchV1NamespacedJob | List Jobs |
readBatchV1NamespacedJob | Read Job |
readBatchV1NamespacedJobStatus | Read Job status |
patchBatchV1NamespacedJob | Update Job |
replaceBatchV1NamespacedJob | Replace Job |
deleteBatchV1NamespacedJob | Delete Job |
deleteBatchV1CollectionNamespacedJob | Delete all Jobs |
Job (Volcano)
| Operation | Description |
|---|---|
createBatchVolcanoShV1alpha1NamespacedJob | Create Volcano Job |
listBatchVolcanoShV1alpha1NamespacedJob | List Volcano Jobs |
readBatchVolcanoShV1alpha1NamespacedJob | Read Volcano Job |
patchBatchVolcanoShV1alpha1NamespacedJob | Update Volcano Job |
replaceBatchVolcanoShV1alpha1NamespacedJob | Replace Volcano Job |
deleteBatchVolcanoShV1alpha1NamespacedJob | Delete Volcano Job |
deleteBatchVolcanoShV1alpha1CollectionNamespacedJob | Delete all Volcano Jobs |
RBAC
| Operation | Description |
|---|---|
createRbacAuthorizationV1NamespacedRoleBinding | Create RoleBinding |
listRbacAuthorizationV1NamespacedRoleBinding | List RoleBindings |
listRbacAuthorizationV1RoleBindingForAllNamespaces | List RoleBindings across namespaces |
readRbacAuthorizationV1NamespacedRoleBinding | Read RoleBinding |
listRbacAuthorizationV1ClusterRole | List ClusterRoles |
readRbacAuthorizationV1ClusterRole | Read ClusterRole |
patchRbacAuthorizationV1NamespacedRoleBinding | Update RoleBinding |
replaceRbacAuthorizationV1NamespacedRoleBinding | Replace RoleBinding |
deleteRbacAuthorizationV1NamespacedRoleBinding | Delete RoleBinding |
Events / ResourceQuota / Metrics
| Operation | Description |
|---|---|
listCoreV1NamespacedEvent | List Events |
readCoreV1NamespacedEvent | Read Event |
listCoreV1NamespacedResourceQuota | List ResourceQuotas |
listMetricsV1beta1NamespacedPodMetrics | List Pod metrics |
readMetricsV1beta1NamespacedPodMetrics | Read Pod metrics |
StorageClass
| Operation | Description |
|---|---|
listStorageV1StorageClass | List StorageClasses |
readStorageV1StorageClass | Read StorageClass |
ReplicaSet
| Operation | Description |
|---|---|
listAppsV1NamespacedReplicaSet | List ReplicaSets |
readAppsV1NamespacedReplicaSet | Read ReplicaSet |
Endpoints
| Operation | Description |
|---|---|
createCoreV1NamespacedEndpoints | Create Endpoints |
listCoreV1NamespacedEndpoints | List Endpoints |
readCoreV1NamespacedEndpoints | Read Endpoints |
patchCoreV1NamespacedEndpoints | Update Endpoints |
replaceCoreV1NamespacedEndpoints | Replace Endpoints |
deleteCoreV1NamespacedEndpoints | Delete Endpoints |
API Discovery
| Operation | Description |
|---|---|
GetOpenAPIv2 | Get OpenAPI v2 schema |
getAPIVersions | Get API versions |
getCoreAPIVersions | Get core API versions |
getCoreV1APIResources | Get core v1 API resources |
getAppsAPIGroup | Get apps API group |
getAppsV1APIResources | Get apps v1 API resources |
getBatchAPIGroup | Get batch API group |
getBatchV1APIResources | Get batch v1 API resources |
getBatchV1beta1APIResources | Get batch v1beta1 API resources |
getBatchVolcanoShAPIGroup | Get Volcano API group |
getBatchVolcanoShV1alpha1APIResources | Get Volcano v1alpha1 API resources |
getCrdYangtseCniAPIGroup | Get Yangtse CNI CRD API group |
getCrdYangtseCniV1APIResources | Get Yangtse CNI v1 API resources |
getExtensionsAPIGroup | Get extensions API group |
getExtensionsV1beta1APIResources | Get extensions v1beta1 API resources |
getMetricsAPIGroup | Get metrics API group |
getMetricsV1beta1APIResources | Get metrics v1beta1 API resources |
getNetworkingCciIoAPIGroup | Get networking CCI API group |
getNetworkingCciIoV1beta1APIResources | Get networking v1beta1 API resources |
getRbacAuthorizationAPIGroup | Get RBAC API group |
getRbacAuthorizationV1APIResources | Get RBAC v1 API resources |
---
All operations use the format:
hcloud CCI <Operation> --param=value --cli-region=<region> --cli-output=jsonNamespaced operations require --namespace=<ns-name>.
CCI Common Workflows
Complete end-to-end workflow sequences with actual hcloud commands. Default region: cn-north-4.
Critical Notes
- Network creation requires a Python helper script: The annotation key
network.alpha.kubernetes.io/default-security-groupcontains dots thathcloudCLI cannot pass as parameter names. Usecci_network_helper.pyfrom thescripts/directory for Network creation. - Namespace creation: Use hyphens instead of dots in annotation keys, e.g.
--metadata.annotations.namespace-kubernetes-io/flavor=general-computing(CCI auto-normalizes hyphenated keys back to canonical dotted form for Namespace resources). - Deployment/Pod/StatefulSet: CCI requires limits == requests for container resources. If limits != requests, creation fails with "limit and request doesn't equal" error. Always set requests to the same values as limits.
- EIPPool creation: Requires
--apiVersion=crd.yangtse.cni/v1and--kind=EIPPool(mandatory). Also requires--spec.eipAttributes.networkTypeand all bandwidth fields (shareType,size,chargeMode,name). - Annotation keys containing dots: Keys like
yangtse.io/eippoolmust use hyphen replacement (yangtse-io/eippool) when passed via hcloud CLI.
---
Workflow 1: Create and Run a Deployment
Step 1: Create Namespace
hcloud CCI createCoreV1Namespace \
--metadata.name=my-ns \
--metadata.annotations.namespace-kubernetes-io/flavor=general-computing \
--cli-region=cn-north-4Step 2: Create Network (requires VPC/subnet — use Python helper)
The Network spec requires these fields: attachedVPC, subnetID, networkType, and `networkID` (the neutron network ID of the VPC subnet). Because annotation keys with dots cannot be passed via hcloud CLI, use the helper script.
Step 2a: Get VPC subnet details (including neutron_network_id)
hcloud VPC ShowSubnet \
--vpc_id=vpc-def456 \
--subnet_id=subnet-abc123 \
--cli-region=cn-north-4 \
--cli-output=jsonExtract neutron_network_id from the response.
Step 2b: Create Network via Python helper script
python scripts/cci_network_helper.py create \
--namespace=my-ns \
--name=my-network \
--vpc-id=vpc-def456 \
--subnet-id=subnet-abc123 \
--network-id=<neutron-network-id> \
--security-group-id=<sg-id> \
--region=cn-north-4Step 2c: Check Network status until Active
hcloud CCI readNetworkingCciIoV1beta1NamespacedNetworkStatus \
--name=my-network \
--namespace=my-ns \
--cli-region=cn-north-4 \
--cli-output=jsonRepeat until status.phase is Active.
Step 3: Create Deployment
hcloud CCI createAppsV1NamespacedDeployment \
--namespace=my-ns \
--metadata.name=my-deploy \
--metadata.annotations.network-alpha-kubernetes-io/default-network=my-network \
--spec.replicas=2 \
--spec.selector.matchLabels.app=my-deploy \
--spec.template.metadata.labels.app=my-deploy \
--spec.template.spec.containers.1.name=nginx \
--spec.template.spec.containers.1.image=nginx:latest \
--spec.template.spec.containers.1.resources.limits.cpu=500m \
--spec.template.spec.containers.1.resources.limits.memory=1Gi \
--spec.template.spec.containers.1.resources.requests.cpu=500m \
--spec.template.spec.containers.1.resources.requests.memory=1Gi \
--spec.template.spec.containers.1.ports.1.containerPort=80 \
--cli-region=cn-north-4Step 4: Verify Deployment Status (poll until readyReplicas > 0)
hcloud CCI readAppsV1NamespacedDeploymentStatus \
--namespace=my-ns \
--name=my-deploy \
--cli-region=cn-north-4 \
--cli-output=jsonRepeat until status.readyReplicas equals spec.replicas.
Step 5: View Pod Logs
hcloud CCI listCoreV1NamespacedPod \
--namespace=my-ns \
--cli-region=cn-north-4 \
--cli-output=jsonhcloud CCI readCoreV1NamespacedPodLog \
--namespace=my-ns \
--name=<pod-name> \
--cli-region=cn-north-4---
Workflow 2: Create a Pod with Public IP (EIPPool)
Step 1: Create Namespace
hcloud CCI createCoreV1Namespace \
--metadata.name=eip-ns \
--metadata.annotations.namespace-kubernetes-io/flavor=general-computing \
--cli-region=cn-north-4Step 2: Create Network (use Python helper)
Step 2a: Get VPC subnet details
hcloud VPC ShowSubnet \
--vpc_id=vpc-def456 \
--subnet_id=subnet-abc123 \
--cli-region=cn-north-4 \
--cli-output=jsonStep 2b: Create Network via Python helper script
python scripts/cci_network_helper.py create \
--namespace=eip-ns \
--name=eip-network \
--vpc-id=vpc-def456 \
--subnet-id=subnet-abc123 \
--network-id=<neutron-network-id> \
--security-group-id=<sg-id> \
--region=cn-north-4Step 2c: Check Network status until Active
hcloud CCI readNetworkingCciIoV1beta1NamespacedNetworkStatus \
--name=eip-network \
--namespace=eip-ns \
--cli-region=cn-north-4 \
--cli-output=jsonRepeat until status.phase is Active.
Step 3: Create EIPPool
hcloud CCI createCrdYangtseCniV1NamespacedEIPPool \
--namespace=eip-ns \
--apiVersion=crd.yangtse.cni/v1 \
--kind=EIPPool \
--metadata.name=my-eippool \
--spec.amount=1 \
--spec.eipAttributes.networkType=5_bgp \
--spec.eipAttributes.ipVersion=4 \
--spec.eipAttributes.bandwidth.shareType=PER \
--spec.eipAttributes.bandwidth.size=5 \
--spec.eipAttributes.bandwidth.chargeMode=bandwidth \
--spec.eipAttributes.bandwidth.name=eip-bw \
--cli-region=cn-north-4Step 4: Create Pod with EIPPool Annotation
hcloud CCI createCoreV1NamespacedPod \
--namespace=eip-ns \
--metadata.name=eip-pod \
--metadata.annotations.network-alpha-kubernetes-io/default-network=eip-network \
--metadata.annotations.yangtse-io/eippool=my-eippool \
--spec.containers.1.name=nginx \
--spec.containers.1.image=nginx:latest \
--spec.containers.1.resources.limits.cpu=500m \
--spec.containers.1.resources.limits.memory=1Gi \
--spec.containers.1.ports.1.containerPort=80 \
--cli-region=cn-north-4Step 5: Verify Pod Status and EIP Allocation
hcloud CCI readCoreV1NamespacedPodStatus \
--namespace=eip-ns \
--name=eip-pod \
--cli-region=cn-north-4 \
--cli-output=jsonhcloud CCI readCrdYangtseCniV1NamespacedEIPPoolStatus \
--namespace=eip-ns \
--name=my-eippool \
--cli-region=cn-north-4 \
--cli-output=jsonCheck status.eips for the allocated public IP address.
---
Workflow 3: Scale a Deployment
Step 1: Read Current Deployment Scale
hcloud CCI readAppsV1NamespacedDeploymentScale \
--namespace=my-ns \
--name=my-deploy \
--cli-region=cn-north-4 \
--cli-output=jsonStep 2: Patch Scale to New Replica Count
hcloud CCI patchAppsV1NamespacedDeploymentScale \
--namespace=my-ns \
--name=my-deploy \
--spec.replicas=5 \
--cli-region=cn-north-4Step 3: Verify New Replicas Are Ready
hcloud CCI readAppsV1NamespacedDeploymentStatus \
--namespace=my-ns \
--name=my-deploy \
--cli-region=cn-north-4 \
--cli-output=jsonRepeat until status.readyReplicas >= 5.
---
Workflow 4: Update Deployment Image (Rolling Update)
Step 1: Read Current Deployment
hcloud CCI readAppsV1NamespacedDeployment \
--namespace=my-ns \
--name=my-deploy \
--cli-region=cn-north-4 \
--cli-output=jsonStep 2: Patch Container Image
hcloud CCI patchAppsV1NamespacedDeployment \
--namespace=my-ns \
--name=my-deploy \
--spec.template.spec.containers.1.image=nginx:1.25 \
--cli-region=cn-north-4Step 3: Monitor Rolling Update Status
hcloud CCI readAppsV1NamespacedDeploymentStatus \
--namespace=my-ns \
--name=my-deploy \
--cli-region=cn-north-4 \
--cli-output=jsonMonitor until:
status.updatedReplicas == spec.replicasstatus.readyReplicas == spec.replicasstatus.oldReplicas == 0(if present)
---
Workflow 5: Full Cleanup (Delete All Resources)
Step 1: Delete All Deployments/StatefulSets/Pods
hcloud CCI deleteAppsV1CollectionNamespacedDeployment \
--namespace=my-ns \
--cli-region=cn-north-4
hcloud CCI deleteAppsV1CollectionNamespacedStatefulSet \
--namespace=my-ns \
--cli-region=cn-north-4
hcloud CCI deleteCoreV1CollectionNamespacedPod \
--namespace=my-ns \
--cli-region=cn-north-4Step 2: Delete All EIPPools
hcloud CCI listCrdYangtseCniV1NamespacedEIPPool \
--namespace=my-ns \
--cli-region=cn-north-4 \
--cli-output=json
hcloud CCI deleteCrdYangtseCniV1NamespacedEIPPool \
--namespace=my-ns \
--name=<eippool-name> \
--cli-region=cn-north-4Step 3: Delete Network
Network deletion works via hcloud CLI with two-step confirmation:
hcloud CCI deleteNetworkingCciIoV1beta1NamespacedNetwork \
--name=my-network \
--namespace=my-ns \
--cli-region=cn-north-4Step 4: Delete Namespace
hcloud CCI deleteCoreV1Namespace \
--name=my-ns \
--cli-region=cn-north-4Important: Deleting a namespace cascades deletion of ALL resources within it (Deployments, Pods, Networks, EIPPools, etc.). The simplest cleanup approach is to delete the namespace directly:
hcloud CCI deleteCoreV1Namespace \
--name=my-ns \
--cli-region=cn-north-4This is equivalent to Steps 1-4 combined, but the namespace and all its contents must be fully deleted before the namespace name can be reused.
---
Workflow 6: Create StatefulSet with PVC
Step 1: Create Namespace + Network
hcloud CCI createCoreV1Namespace \
--metadata.name=ss-ns \
--metadata.annotations.namespace-kubernetes-io/flavor=general-computing \
--cli-region=cn-north-4Create Network via Python helper script:
hcloud VPC ShowSubnet \
--vpc_id=vpc-def456 \
--subnet_id=subnet-abc123 \
--cli-region=cn-north-4 \
--cli-output=jsonExtract neutron_network_id from the response.
python scripts/cci_network_helper.py create \
--namespace=ss-ns \
--name=ss-network \
--vpc-id=vpc-def456 \
--subnet-id=subnet-abc123 \
--network-id=<neutron-network-id> \
--security-group-id=<sg-id> \
--region=cn-north-4Check Network status until Active:
hcloud CCI readNetworkingCciIoV1beta1NamespacedNetworkStatus \
--name=ss-network \
--namespace=ss-ns \
--cli-region=cn-north-4 \
--cli-output=jsonStep 2: Create StatefulSet with volumeClaimTemplates
hcloud CCI createAppsV1NamespacedStatefulSet \
--namespace=ss-ns \
--metadata.name=my-statefulset \
--metadata.annotations.network-alpha-kubernetes-io/default-network=ss-network \
--spec.replicas=3 \
--spec.selector.matchLabels.app=my-statefulset \
--spec.serviceName=my-statefulset \
--spec.template.metadata.labels.app=my-statefulset \
--spec.template.spec.containers.1.name=mysql \
--spec.template.spec.containers.1.image=mysql:5.7 \
--spec.template.spec.containers.1.resources.limits.cpu=1 \
--spec.template.spec.containers.1.resources.limits.memory=2Gi \
--spec.template.spec.containers.1.resources.requests.cpu=1 \
--spec.template.spec.containers.1.resources.requests.memory=2Gi \
--spec.template.spec.containers.1.ports.1.containerPort=3306 \
--spec.template.spec.containers.1.volumeMounts.1.name=data \
--spec.template.spec.containers.1.volumeMounts.1.mountPath=/var/lib/mysql \
--spec.volumeClaimTemplates.1.metadata.name=data \
--spec.volumeClaimTemplates.1.spec.accessModes.1=ReadWriteOnce \
--spec.volumeClaimTemplates.1.spec.resources.requests.storage=10Gi \
--cli-region=cn-north-4Step 3: Verify PVC Creation
hcloud CCI listCoreV1NamespacedPersistentVolumeClaim \
--namespace=ss-ns \
--cli-region=cn-north-4 \
--cli-output=jsonEach replica creates a PVC named data-my-statefulset-0, data-my-statefulset-1, data-my-statefulset-2.
Step 4: Read Pod Status
hcloud CCI readAppsV1NamespacedStatefulSetStatus \
--namespace=ss-ns \
--name=my-statefulset \
--cli-region=cn-north-4 \
--cli-output=jsonRepeat until status.readyReplicas >= 3.
Credential Configuration for hcloud CLI
hcloud CLI (KooCLI) supports two credential modes via environment variables, automatically detected at runtime.
Security Rules:
- 🚫 Never expose AK/SK/SecurityToken values in conversation, commands, or output
- 🚫 Never useecho $HUAWEI_CLOUD_AKorecho $HUAWEI_CLOUD_SKto check credentials
- ✅ Prefer environment variables or hcloud CLI profile mode
- ✅ Use hcloud configure list to check credential status (presence only, not values)Mode A — Long-term AK/SK
Suitable for permanent access, CI/CD pipelines, and long-running automation.
export HUAWEI_CLOUD_AK=<your-ak>
export HUAWEI_CLOUD_SK=<your-sk>
export HUAWEI_CLOUD_REGION=cn-north-4Characteristics:
- Credentials are valid until manually revoked in IAM console
- Recommended for service accounts, CI/CD pipelines, and automation scripts
- Rotate regularly following security best practices
Mode B — Temporary AK/SK + SecurityToken
Recommended for temporary, delegated, or fine-grained access scenarios.
export HUAWEI_CLOUD_AK=<your-temp-ak>
export HUAWEI_CLOUD_SK=<your-temp-sk>
export HUAWEI_CLOUD_SECURITY_TOKEN=<your-security-token>
export HUAWEI_CLOUD_REGION=cn-north-4Characteristics:
- Credentials expire after a configured duration (typically 15 minutes to 24 hours)
- Obtained via IAM
CreateTemporaryAccessKeyByTokenorCreateTemporaryAccessKeyByAgencyAPIs - Supports scoped permissions via agency delegation
- When
HUAWEI_CLOUD_SECURITY_TOKENis present, hcloud CLI automatically uses temporary credential authentication - When only AK/SK are set, it uses long-term credential authentication
Validation
After configuring credentials, verify they work:
# Check credential presence (shows profile name, NOT credential values)
hcloud configure list
# Verify connectivity with a simple query
hcloud CCI listCoreV1Namespace --cli-region=cn-north-4 --cli-output=jsonImportant Notes
- Never commit credentials to version control
- Use IAM users with minimal required permissions (least privilege principle)
- Enable MFA for sensitive operations
- Rotate long-term AK/SK regularly
- For temporary credentials, use appropriate expiration duration — too short causes frequent re-authentication, too long increases risk
Known Limitation — Python Helper Script Uses Independent Credentials
The CCI Network creation helper script (scripts/cci_network_helper.py) authenticates via HW_ACCESS_KEY / HW_SECRET_KEY (and optionally HW_SECURITY_TOKEN) environment variables. This is independent from hcloud CLI's credential source:
| Component | Credential Source | Scope |
|---|---|---|
| hcloud CLI commands | HUAWEI_CLOUD_AK/HUAWEI_CLOUD_SK/HUAWEI_CLOUD_SECURITY_TOKEN env vars, or hcloud profile | Used for all hcloud CCI ... commands |
| Python helper script | HW_ACCESS_KEY/HW_SECRET_KEY/HW_SECURITY_TOKEN env vars | Used only for Network creation via cci_network_helper.py |
If the credentials in HW_ACCESS_KEY/HW_SECRET_KEY lack the necessary IAM permissions for CCI Network creation (e.g., missing CCI FullAccess), the script will fail with a 403 Forbidden error. Running the helper script does not affect hcloud CLI's credential state — hcloud CLI commands continue using their own credential source afterward.
IAM Permission Policies for CCI Operations
Minimum Required Permissions
| Permission | Description |
|---|---|
cci:namespace:create | Create namespace |
cci:namespace:get | Read namespace |
cci:namespace:list | List namespaces |
cci:namespace:delete | Delete namespace |
cci:network:create | Create Network |
cci:network:get | Read Network |
cci:network:list | List Networks |
cci:network:delete | Delete Network |
cci:pod:create | Create Pod |
cci:pod:get | Read Pod |
cci:pod:list | List Pods |
cci:pod:delete | Delete Pod |
cci:deployment:create | Create Deployment |
cci:deployment:get | Read Deployment |
cci:deployment:list | List Deployments |
cci:deployment:update | Update/scale Deployment |
cci:deployment:delete | Delete Deployment |
cci:statefulset:create | Create StatefulSet |
cci:statefulset:get | Read StatefulSet |
cci:statefulset:list | List StatefulSets |
cci:statefulset:update | Update StatefulSet |
cci:statefulset:delete | Delete StatefulSet |
vpc:vpcs:list | List VPCs (for Network creation) |
vpc:subnets:get | Read subnet details (for Network creation) |
Minimum Required Policy JSON
{
"Version": "5.0",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cci:namespace:create",
"cci:namespace:get",
"cci:namespace:list",
"cci:namespace:delete",
"cci:network:create",
"cci:network:get",
"cci:network:list",
"cci:network:delete",
"cci:pod:create",
"cci:pod:get",
"cci:pod:list",
"cci:pod:delete",
"cci:deployment:create",
"cci:deployment:get",
"cci:deployment:list",
"cci:deployment:update",
"cci:deployment:delete",
"cci:statefulset:create",
"cci:statefulset:get",
"cci:statefulset:list",
"cci:statefulset:update",
"cci:statefulset:delete",
"vpc:vpcs:list",
"vpc:subnets:get"
],
"Resource": [
"CCI:*:*:namespace:*",
"CCI:*:*:network:*",
"CCI:*:*:pod:*",
"CCI:*:*:deployment:*",
"CCI:*:*:statefulset:*"
]
}
]
}System Policies
| System Policy | Applicable Scenario |
|---|---|
CCI Administrator | Full CCI management permissions |
CCI Viewer | Read-only, view all CCI resources |
VPC Viewer | Read-only VPC access (for Network creation) |
EIPPool Additional Permissions
If using EIPPool, add these permissions to the policy:
| Permission | Description |
|---|---|
cci:eippool:create | Create EIPPool |
cci:eippool:get | Read EIPPool |
cci:eippool:list | List EIPPools |
cci:eippool:delete | Delete EIPPool |
vpc:publicIps:list | List available EIPs |
Permission Failure Handling Process
When any command fails due to permission errors:
1. Read this iam-policies.md file 2. Show required permission list and policy JSON to user 3. Guide user to create custom policy in IAM console 4. Pause execution and wait for user confirmation
CCI Parameter Format Rules
CCI uses deeply nested Kubernetes-style objects via the hcloud CLI. Understanding the parameter format is critical.
1. Dot Notation for Nested Objects
Nested fields are accessed via dot-separated paths:
--metadata.name=my-ns
--metadata.annotations.namespace-kubernetes-io/flavor=general-computing
--metadata.labels.app=my-deploy
--spec.template.spec.containers.1.image=nginx:latest
--spec.networkId=subnet-xxx
--spec.routerId=vpc-xxx2. {*} Format for Maps (Annotations, Labels, Resources)
Maps are expressed as individual key=value entries using dot notation, NOT as JSON objects:
# Annotations
--metadata.annotations.namespace-kubernetes-io/flavor=general-computing
--metadata.annotations.key1=value1
# Labels
--metadata.labels.app=my-app
--metadata.labels.environment=production
# Resource limits/requests
--spec.template.spec.containers.1.resources.limits.cpu=500m
--spec.template.spec.containers.1.resources.limits.memory=1Gi
--spec.template.spec.containers.1.resources.requests.cpu=250m
--spec.template.spec.containers.1.resources.requests.memory=512Mi
# Selector matchLabels
--spec.selector.matchLabels.app=my-deploy3. 1-Based Array Indexing
Arrays use 1-based indexing (NOT 0-based):
# First container is .1, second is .2
--spec.template.spec.containers.1.name=main
--spec.template.spec.containers.2.name=sidecar
--spec.template.spec.containers.1.ports.1.containerPort=80
--spec.template.spec.containers.1.ports.2.containerPort=443
--spec.template.spec.volumes.1.name=data-vol
--spec.template.spec.volumes.2.name=config-vol4. Resource Quantity Format
| Type | Format | Examples |
|---|---|---|
| CPU | millicores or cores | 500m (0.5 core), 1 (1 core), 2 (2 cores) |
| Memory | Mi or Gi suffix | 512Mi, 1Gi, 2Gi |
CPU values: 100m = 0.1 core, 500m = 0.5 core, 1 = 1 core, 4 = 4 cores. Memory values: 256Mi, 512Mi, 1Gi, 2Gi, 4Gi.
5. CCI Annotation Key Limitations
5.1 The Dot Parsing Problem
Annotation keys in Kubernetes often contain dots (e.g., namespace.kubernetes.io/flavor, network.alpha.kubernetes.io/default-security-group). When passed via hcloud CLI dot notation, hcloud treats dots in the key name as nested object delimiters, the same as dots in the field path.
This means:
# INTENDED: annotation key = "network.alpha.kubernetes.io/default-security-group"
# ACTUAL: hcloud parses as nested object path:
# metadata.annotations.network.alpha.kubernetes.io.default-security-group
# → {network: {alpha: {kubernetes: {io: {default-security-group: value}}}}}
# This is NOT a valid annotation key-value pair.
--metadata.annotations.network.alpha.kubernetes.io/default-security-group=sg-xxxThere is no escaping mechanism (quotes, backslashes, etc.) that prevents hcloud from parsing dots as nested delimiters.
5.2 Namespace Annotation Workaround (Hyphen Replacement)
For Namespace, the annotation key namespace.kubernetes.io/flavor can be passed via hcloud CLI by replacing dots with hyphens in the key portion:
# hcloud CLI parameter (dots replaced with hyphens in the key):
--metadata.annotations.namespace-kubernetes-io/flavor=general-computing
# CCI service auto-adds the canonical dotted version:
# namespace.kubernetes.io/flavor=general-computingThis workaround works because the key only contains dots (no additional slashes beyond the single / separating domain from name), and CCI recognizes the hyphenated form.
5.3 Network Annotation Cannot Use hcloud CLI
The Network resource requires the annotation key network.alpha.kubernetes.io/default-security-group (confirmed by official CCI API docs: https://support.huaweicloud.com/api-cci/createNetworkingCciIoV1beta1NamespacedNetwork.html).
This key contains dots AND a slash, making it impossible to pass via hcloud CLI:
- Dots are parsed as nested delimiters (no workaround)
- The hyphen replacement trick does not work for Network annotations
- Use the Python helper script to create Network resources with this annotation
5.4 --cli-jsonInput Does Not Solve This
The --cli-jsonInput feature allows passing the entire request body as a JSON file. However, it has a critical limitation for CCI:
- Even though
--dryrunshows annotations correctly in the JSON input, the actual API request does not include annotations in the request body when using--cli-jsonInput. This is a hcloud bug/limitation. --cli-jsonInputfile encoding must be ASCII (UTF-8 with BOM causes parsing failure).
Do not rely on `--cli-jsonInput` for setting annotations on CCI resources.
5.5 When to Use hcloud CLI vs Python Helper Script
| Resource | Annotation Key | hcloud CLI | Python Script |
|---|---|---|---|
| Namespace | namespace.kubernetes.io/flavor | Use hyphen workaround | Optional |
| Network | network.alpha.kubernetes.io/default-security-group | Cannot use | Required |
| Pod / Deployment | Simple keys (no dots) | Works normally | Optional |
| Pod / Deployment | Keys with dots | Cannot pass directly | Required |
5.6 Network Required Spec Fields
Network resources require ALL of the following spec fields:
spec:
attachedVPC: <vpc-id> # VPC ID
subnetID: <subnet-id> # Subnet ID
networkType: <type> # Network type (e.g., "underlay-neutron")
networkID: <neutron-network-id> # Neutron network ID of the VPC subnet (REQUIRED)The networkID field is REQUIRED — it is the neutron network ID associated with the VPC subnet, not the same as subnetID.
6. Common Format Errors
| Wrong | Correct | Issue |
|---|---|---|
--metadata.annotations={"namespace.kubernetes.io/flavor":"general-computing"} | --metadata.annotations.namespace-kubernetes-io/flavor=general-computing | Map uses {*} dot format, not JSON; use hyphens for Namespace annotation key |
--metadata.annotations.network.alpha.kubernetes.io/default-security-group=sg-xxx | Use Python helper script for Network | Dots in annotation key are parsed as nested delimiters; no hcloud CLI workaround exists |
--spec.containers.0.name=main | --spec.template.spec.containers.1.name=main | Array index starts from 1, not 0; also need full path through template.spec |
--spec.selector.matchLabels={"app":"my-app"} | --spec.selector.matchLabels.app=my-app | Map uses {*} format |
--spec.resources.limits={"cpu":"500m"} | --spec.template.spec.containers.1.resources.limits.cpu=500m | Full nested path + {*} format |
--region=cn-north-4 | --cli-region=cn-north-4 | Region uses cli prefix |
--name my-pod | --name=my-pod | Equals sign required |
7. Parameter Path Depth Reference
Namespace (Shallow)
metadata.name
metadata.annotations.*
metadata.labels.*Example:
hcloud CCI createCoreV1Namespace \
--metadata.name=my-ns \
--metadata.annotations.namespace-kubernetes-io/flavor=general-computing \
--cli-region=cn-north-4Network (Shallow but Requires Python Script)
metadata.name
metadata.annotations.network.alpha.kubernetes.io/default-security-group
spec.attachedVPC
spec.subnetID
spec.networkType
spec.networkIDExample (Python helper script — hcloud CLI cannot set this annotation):
# Use the Python helper script for Network creation
# hcloud CLI cannot pass the required annotation keyPod (Deep)
metadata.name
metadata.annotations.*
metadata.labels.*
spec.containers.1.name
spec.containers.1.image
spec.containers.1.resources.limits.*
spec.containers.1.resources.requests.*
spec.containers.1.ports.1.containerPort
spec.volumes.1.*Deployment (Very Deep)
metadata.name
metadata.annotations.*
metadata.labels.*
spec.replicas
spec.selector.matchLabels.*
spec.template.metadata.labels.*
spec.template.spec.containers.1.name
spec.template.spec.containers.1.image
spec.template.spec.containers.1.resources.limits.*
spec.template.spec.containers.1.resources.requests.*
spec.template.spec.containers.1.ports.1.containerPort
spec.template.spec.volumes.1.*Nesting hierarchy (Deployment):
spec # Deployment spec
replicas # Number of replicas
selector # Pod selector
matchLabels.* # Label match rules
template # Pod template
metadata # Pod metadata
labels.* # Pod labels
spec # Pod spec
containers.1 # First container (1-based)
name
image
ports.1 # First port (1-based)
containerPort
resources
limits.* # Resource limits map
requests.* # Resource requests map
env.1 # First env var (1-based)
name
value
volumes.1 # First volume (1-based)
name
configMap # Volume source
name8. DryRun for Validation
Validate parameters without creating resources:
hcloud CCI createCoreV1Namespace \
--dryRun=All \
--metadata.name=test-ns \
--metadata.annotations.namespace-kubernetes-io/flavor=general-computing \
--cli-region=cn-north-4hcloud CCI createAppsV1NamespacedDeployment \
--dryRun=All \
--namespace=test-ns \
--metadata.name=my-deploy \
--spec.replicas=2 \
--spec.selector.matchLabels.app=my-deploy \
--spec.template.metadata.labels.app=my-deploy \
--spec.template.spec.containers.1.name=main \
--spec.template.spec.containers.1.image=nginx:latest \
--spec.template.spec.containers.1.resources.limits.cpu=500m \
--spec.template.spec.containers.1.resources.limits.memory=1Gi \
--cli-region=cn-north-4Deployment Lifecycle Management
Deployments in CCI are serverless — no node management is needed. CCI automatically provisions compute resources based on container specifications.
Prerequisites
Before creating a Deployment, the following must already exist:
1. Namespace — created via createCoreV1Namespace 2. Network — created via createNetworkingCciIoV1beta1NamespacedNetwork and in Active state
Create Deployment
Single Container
hcloud CCI createAppsV1NamespacedDeployment \
--namespace=<ns-name> \
--metadata.name=<deploy-name> \
--spec.replicas=1 \
--spec.selector.matchLabels.app=<deploy-name> \
--spec.template.metadata.labels.app=<deploy-name> \
--spec.template.spec.containers.1.name=<container-name> \
--spec.template.spec.containers.1.image=<image> \
--spec.template.spec.containers.1.resources.limits.cpu=500m \
--spec.template.spec.containers.1.resources.limits.memory=1Gi \
--spec.template.spec.containers.1.resources.requests.cpu=250m \
--spec.template.spec.containers.1.resources.requests.memory=512Mi \
--cli-region=<region> \
--cli-output=jsonKey constraints:
--spec.selector.matchLabelsMUST match--spec.template.metadata.labels— mismatched labels prevent the Deployment from managing its Pods- Resource limits and requests are MANDATORY for CCI — omitting them causes creation failure
- Array indices are 1-based:
containers.1is the first container,containers.2is the second
Multi-Container Example
hcloud CCI createAppsV1NamespacedDeployment \
--namespace=<ns-name> \
--metadata.name=<deploy-name> \
--spec.replicas=1 \
--spec.selector.matchLabels.app=<deploy-name> \
--spec.template.metadata.labels.app=<deploy-name> \
--spec.template.spec.containers.1.name=main \
--spec.template.spec.containers.1.image=nginx \
--spec.template.spec.containers.1.resources.limits.cpu=500m \
--spec.template.spec.containers.1.resources.limits.memory=1Gi \
--spec.template.spec.containers.1.resources.requests.cpu=250m \
--spec.template.spec.containers.1.resources.requests.memory=512Mi \
--spec.template.spec.containers.2.name=sidecar \
--spec.template.spec.containers.2.image=busybox \
--spec.template.spec.containers.2.resources.limits.cpu=100m \
--spec.template.spec.containers.2.resources.limits.memory=256Mi \
--spec.template.spec.containers.2.resources.requests.cpu=50m \
--spec.template.spec.containers.2.resources.requests.memory=128Mi \
--cli-region=<region> \
--cli-output=jsonPort Specification Example
hcloud CCI createAppsV1NamespacedDeployment \
--namespace=<ns-name> \
--metadata.name=<deploy-name> \
--spec.replicas=1 \
--spec.selector.matchLabels.app=<deploy-name> \
--spec.template.metadata.labels.app=<deploy-name> \
--spec.template.spec.containers.1.name=<container-name> \
--spec.template.spec.containers.1.image=<image> \
--spec.template.spec.containers.1.ports.1.containerPort=80 \
--spec.template.spec.containers.1.resources.limits.cpu=500m \
--spec.template.spec.containers.1.resources.limits.memory=1Gi \
--spec.template.spec.containers.1.resources.requests.cpu=250m \
--spec.template.spec.containers.1.resources.requests.memory=512Mi \
--cli-region=<region> \
--cli-output=jsonList Deployments
Within a namespace
hcloud CCI listAppsV1NamespacedDeployment \
--namespace=<ns-name> \
--cli-region=<region> --cli-output=jsonAcross all namespaces
hcloud CCI listAppsV1DeploymentForAllNamespaces \
--cli-region=<region> --cli-output=jsonRead Deployment
hcloud CCI readAppsV1NamespacedDeployment \
--name=<deploy-name> --namespace=<ns-name> \
--cli-region=<region> --cli-output=jsonRead Deployment Status
hcloud CCI readAppsV1NamespacedDeploymentStatus \
--name=<deploy-name> --namespace=<ns-name> \
--cli-region=<region> --cli-output=jsonCheck readyReplicas vs replicas to determine rollout progress.
Scale Deployment
hcloud CCI patchAppsV1NamespacedDeploymentScale \
--name=<deploy-name> --namespace=<ns-name> \
--spec.replicas=<new-count> \
--cli-region=<region>Update Deployment (Patch)
Update container image
hcloud CCI patchAppsV1NamespacedDeployment \
--name=<deploy-name> --namespace=<ns-name> \
--spec.template.spec.containers.1.image=<new-image> \
--cli-region=<region>This triggers a rolling update — Pods are replaced incrementally.
Delete Deployment
TWO-STEP CONFIRMATION REQUIRED.
Step 1: Warn the user
WARNING: Deleting a Deployment terminates all Pod replicas managed by it. This is irreversible.
Step 2: Execute (only after explicit user confirmation)
hcloud CCI deleteAppsV1NamespacedDeployment \
--name=<deploy-name> --namespace=<ns-name> \
--cli-region=<region>EIPPool Management
EIPPool is a CCI-specific CRD (crd.yangtse.cni/v1) for allocating public IPs (EIPs) to Pods automatically.
---
1. Create EIPPool
Option A — Auto-create EIPs (amount-based):
hcloud CCI createCrdYangtseCniV1NamespacedEIPPool \
--namespace=<ns-name> \
--apiVersion=crd.yangtse.cni/v1 \
--kind=EIPPool \
--metadata.name=<eippool-name> \
--spec.amount=<number-of-eips> \
--spec.eipAttributes.networkType=5_bgp \
--spec.eipAttributes.ipVersion=4 \
--spec.eipAttributes.bandwidth.shareType=PER \
--spec.eipAttributes.bandwidth.size=5 \
--spec.eipAttributes.bandwidth.chargeMode=bandwidth \
--spec.eipAttributes.bandwidth.name=<bandwidth-name> \
--cli-region=<region> \
--cli-output=jsonOption B — Use pre-created EIP IDs:
hcloud CCI createCrdYangtseCniV1NamespacedEIPPool \
--namespace=<ns-name> \
--apiVersion=crd.yangtse.cni/v1 \
--kind=EIPPool \
--metadata.name=<eippool-name> \
--spec.eips.1=<eip-id-1> \
--spec.eips.2=<eip-id-2> \
--cli-region=<region> \
--cli-output=jsonRequired fields for Option A (auto-create):
| Field | Value | Description |
|---|---|---|
--apiVersion | crd.yangtse.cni/v1 | API version (required) |
--kind | EIPPool | Resource kind (required) |
--spec.amount | integer | Number of EIPs to create |
--spec.eipAttributes.networkType | 5_bgp or 5_gray | EIP network type (required) |
--spec.eipAttributes.bandwidth.shareType | PER or WHOLE | Bandwidth share type |
--spec.eipAttributes.bandwidth.size | integer | Bandwidth size in Mbit/s |
--spec.eipAttributes.bandwidth.chargeMode | bandwidth or traffic | Bandwidth billing mode |
--spec.eipAttributes.bandwidth.name | string | Bandwidth name (required for PER share type) |
Constraints:
--apiVersion=crd.yangtse.cni/v1and--kind=EIPPoolare required (missing these causes 400 error)spec.eipAttributes.networkTypeis required (missing causes 422 validation error)spec.eipAttributes.bandwidth.chargeModeandnameare required when auto-creating EIPs (missing causes 403 validation error)- EIPPool must be in the same namespace as the Pod that uses it
- Array items are 1-based:
--spec.eips.1=<eip-id>(not0) 5_bgp= Dynamic BGP EIP;5_gray= Dedicated load balancing (internal use)
---
2. List / Read / Status
# List EIPPools in namespace
hcloud CCI listCrdYangtseCniV1NamespacedEIPPool --namespace=<ns-name> --cli-region=<region> --cli-output=json
# Read a specific EIPPool
hcloud CCI readCrdYangtseCniV1NamespacedEIPPool --name=<eippool-name> --namespace=<ns-name> --cli-region=<region>
# Read EIPPool status (allocated IPs, available count)
hcloud CCI readCrdYangtseCniV1NamespacedEIPPoolStatus --name=<eippool-name> --namespace=<ns-name> --cli-region=<region> --cli-output=jsonStatus response includes:
status.eips— array of allocated EIP objects (each withipv4,id,status,bandwidthSize)status.usage— usage string (e.g.,0/1means 0 of 1 EIPs bound to Pods)
---
3. Delete EIPPool — TWO-STEP CONFIRMATION
hcloud CCI deleteCrdYangtseCniV1NamespacedEIPPool --name=<eippool-name> --namespace=<ns-name> --cli-region=<region>WARNING: Pods currently using this EIPPool will lose their public IP access immediately. Always confirm with the user and check for active Pods referencing this EIPPool before deletion.
After deletion, the EIPPool enters Terminating state with finalizer yangtse.io/eip-pool. The EIPs created by the pool are released automatically.
---
4. Pod Usage — Assign EIP via Annotation
To associate a Pod with an EIPPool, add the annotation at Pod creation:
Note: The annotation key yangtse.io/eippool contains dots and a slash. This may encounter the same hcloud CLI dot-parsing limitation as other annotation keys. If hcloud CLI cannot pass this annotation, consider:
- Using the hyphen replacement:
--metadata.annotations.yangtse-io/eippool=<eippool-name>(may or may not work for Pod annotations — needs testing) - Using
--cli-jsonInput(but note this has known issues transmitting annotations for CCI resources)
hcloud CCI createCoreV1NamespacedPod \
--namespace=<ns-name> \
--metadata.name=<pod-name> \
--metadata.annotations.yangtse-io/eippool=<eippool-name> \
--spec.containers.1.name=<container-name> \
--spec.containers.1.image=<image> \
--spec.containers.1.resources.limits.cpu=500m \
--spec.containers.1.resources.limits.memory=1Gi \
--cli-region=<region> \
--cli-output=jsonFor Deployment or StatefulSet, add the annotation in the Pod template:
# Deployment with EIP (hyphen workaround for annotation key)
--spec.template.metadata.annotations.yangtse-io/eippool=<eippool-name>
# StatefulSet with EIP (hyphen workaround for annotation key)
--spec.template.metadata.annotations.yangtse-io/eippool=<eippool-name>---
5. EIPPool vs Manual EIP
| Criteria | EIPPool (CCI-native) | Manual EIP binding |
|---|---|---|
| Allocation | Automatic — Pod gets EIP on creation | Manual — create EIP then bind to resource |
| Scope | Namespace-level, pod-specific | VPC-level, resource-specific |
| Lifecycle | EIP follows Pod lifecycle (released when Pod deleted) | EIP is independent, persists until manually deleted |
| Use case | Container workloads needing public IP | VMs, load balancers, NAT gateways |
| Management | CCI CRD, managed via k8s-style API | ECS/VPC API, managed via Huawei Cloud console/CLI |
| Dynamic scaling | Yes — pool auto-assigns as pods scale | No — each EIP must be manually bound |
Use EIPPool for CCI workloads that need direct public IP on Pods. Use manual EIP for non-container resources or when you need persistent IPs independent of Pod lifecycle.
Logs and Status Queries
Status reading and log viewing across all CCI resources.
---
1. Pod Status
hcloud CCI readCoreV1NamespacedPodStatus \
--name=<pod-name> --namespace=<ns-name> \
--cli-region=<region> --cli-output=jsonPhase values: Pending, Running, Succeeded, Failed, Unknown
JMESPath quick query:
--cli-query="status.phase"---
2. Pod Logs
hcloud CCI readCoreV1NamespacedPodLog \
--name=<pod-name> --namespace=<ns-name> \
--container=<container-name> \
--cli-region=<region>Optional parameters:
--sinceSeconds=3600— show logs from last hour (3600 seconds)--limitBytes=10000— limit output to 10000 bytes--previous=true— show logs from previous (crashed) container instance--tailLines=100— show last 100 lines
Multi-container pods: --container=<container-name> is REQUIRED when the Pod has more than one container.
---
3. Deployment Status
hcloud CCI readAppsV1NamespacedDeploymentStatus \
--name=<deploy-name> --namespace=<ns-name> \
--cli-region=<region> --cli-output=jsonKey status fields:
replicas— desired replica countreadyReplicas— pods passing readiness checksavailableReplicas— pods available for serviceupdatedReplicas— pods on the current template version
---
4. StatefulSet Status
hcloud CCI readAppsV1NamespacedStatefulSetStatus \
--name=<sts-name> --namespace=<ns-name> \
--cli-region=<region> --cli-output=jsonKey status fields: same as Deployment plus currentReplicas and currentRevision.
---
5. Network Status
hcloud CCI readNetworkingCciIoV1beta1NamespacedNetworkStatus \
--name=<network-name> --namespace=<ns-name> \
--cli-region=<region> --cli-output=json---
6. EIPPool Status
hcloud CCI readCrdYangtseCniV1NamespacedEIPPoolStatus \
--name=<eippool-name> --namespace=<ns-name> \
--cli-region=<region> --cli-output=jsonShows allocated EIP count, available EIP count, and specific IP assignments.
---
7. Events (Diagnose Issues)
# List all events in namespace
hcloud CCI listCoreV1NamespacedEvent --namespace=<ns-name> --cli-region=<region> --cli-output=json
# Read a specific event
hcloud CCI readCoreV1NamespacedEvent --name=<event-name> --namespace=<ns-name> --cli-region=<region>Events record pod scheduling failures, image pull errors, crash loops, etc.
---
8. ResourceQuota
hcloud CCI listCoreV1NamespacedResourceQuota --namespace=<ns-name> --cli-region=<region> --cli-output=jsonShows CPU, memory, and pod count limits for the namespace.
---
9. Pod Metrics
hcloud CCI listMetricsV1beta1NamespacedPodMetrics --namespace=<ns-name> --cli-region=<region> --cli-output=jsonReturns current CPU and memory usage per Pod.
---
10. Service Status
hcloud CCI readCoreV1NamespacedServiceStatus \
--name=<svc-name> --namespace=<ns-name> \
--cli-region=<region> --cli-output=json---
11. Wait for Pod Running Pattern
Poll Pod status until phase=Running:
# Check status repeatedly until Running
$phase = ""
while ($phase -ne "Running") {
$result = hcloud CCI readCoreV1NamespacedPodStatus `
--name=<pod-name> --namespace=<ns-name> `
--cli-region=<region> --cli-output=json `
--cli-query="status.phase"
$phase = $result.Trim()
if ($phase -ne "Running") {
Start-Sleep -Seconds 5
}
}
Write-Output "Pod is Running"Alternative phases to wait for:
Succeeded— for batch/job podsFailed— indicates error; stop waiting and inspect events
Timeout pattern: add a max iteration count to prevent infinite loops (e.g., 60 iterations × 5s = 5 minutes max).
Namespace Lifecycle Management
Namespaces are the foundational isolation boundary in CCI. All workload operations (Deployments, Pods, Networks) require a namespace.
Create Namespace
hcloud CCI createCoreV1Namespace \
--metadata.name=<ns-name> \
--metadata.annotations.namespace-kubernetes-io/flavor=general-computing \
--cli-region=<region> \
--cli-output=jsonThe flavor annotation is MANDATORY. Accepted values:
| Flavor | Description |
|---|---|
general-computing | Standard compute instances |
gpu-accelerated | GPU instances — requires additional GPU quota approval |
GPU-accelerated namespaces require GPU quota to be approved before workloads can be created.
List Namespaces
hcloud CCI listCoreV1Namespace --cli-region=<region> --cli-output=jsonFilter output with JMESPath:
hcloud CCI listCoreV1Namespace --cli-region=<region> --cli-output=json \
--cli-query="items[].{Name:metadata.name,Status:status.phase,Flavor:metadata.annotations.namespace\.kubernetes\.io/flavor}"Read Namespace
hcloud CCI readCoreV1Namespace --name=<ns-name> --cli-region=<region> --cli-output=jsonDelete Namespace
TWO-STEP CONFIRMATION REQUIRED — this operation is irreversible and cascading.
Step 1: Preview
Show namespace details and warn the user:
hcloud CCI readCoreV1Namespace --name=<ns-name> --cli-region=<region> --cli-output=jsonWARNING: Deleting a namespace cascades to ALL resources under it — Networks, Deployments, Pods, ConfigMaps, Secrets, etc. This cannot be undone.
Step 2: Execute (only after explicit user confirmation)
hcloud CCI deleteCoreV1Namespace --name=<ns-name> --cli-region=<region>- This is irreversible — no undo, no recovery
- This is cascading — all child resources are destroyed
- Always run
readCoreV1Namespacefirst so the user can review what will be lost
Namespace Naming Rules
- Must follow DNS_LABEL format: lowercase alphanumeric and hyphens only
- Must start with a lowercase letter or digit
- Maximum 63 characters
- Examples:
my-app,test-ns-01,production
Namespace Status Phases
| Phase | Meaning |
|---|---|
Active | Namespace is ready for use |
Terminating | Namespace is being deleted — all resources are being cleaned up |
Network Lifecycle Management
A Network maps a VPC subnet into a CCI namespace. A Network must exist before any workload (Deployment, Pod) can be created in the namespace.
VPC/Subnet Query Prerequisite
Before creating a Network, you must identify the VPC, subnet, and neutron network ID.
List VPCs
hcloud VPC ListVpcs --cli-region=<region> --cli-output=jsonList Subnets for a VPC
hcloud VPC ListSubnets --vpc_id=<vpc-id> --cli-region=<region> --cli-output=jsonRecord the following from the output:
vpc_id→ used as--spec.attachedVPC(or--attached-vpcin the helper script)subnet_id→ used as--spec.subnetID(or--subnet-idin the helper script)- The subnet's neutron network ID → used as
--spec.networkID(or--network-idin the helper script)
IMPORTANT: The subnet CIDR MUST NOT be 10.247.0.0/16 — this range is reserved for the CCI Service network and will cause conflicts.Create Network
Required Spec Fields
The Network spec requires three mandatory fields:
| Spec Field | hcloud CLI Parameter | Helper Script Parameter | Source |
|---|---|---|---|
networkID | --spec.networkID | --network-id | Neutron network ID from subnet query |
attachedVPC | --spec.attachedVPC | --attached-vpc | VPC ID from hcloud VPC ListVpcs |
subnetID | --spec.subnetID | --subnet-id | Subnet ID from hcloud VPC ListSubnets |
OmittingnetworkIDcauses the error:spec[networkID]: Required value
Security Group Annotation
CCI Network creation requires the annotation network.alpha.kubernetes.io/default-security-group to specify the default security group:
metadata.annotations:
network.alpha.kubernetes.io/default-security-group: <security-group-id>- CCI auto-normalizes this annotation key (the canonical dotted version is preserved alongside any hyphenated variants when applicable)
hcloud CLI Limitation
hcloud CLI cannot pass annotation keys containing dots (`.`) as CLI parameters — hcloud treats dots as nested object delimiters rather than literal annotation key names. The --cli-jsonInput approach also fails because hcloud does not properly transmit annotations from JSON input files as part of the request body.
Additionally, --cli-jsonInput files must use ASCII encoding (not UTF-8 with BOM). UTF-8 with BOM causes the error: Failed to parse cli-jsonInput parameter file.
Primary Method: Python Helper Script
Use the cci_network_helper.py script from the skill's scripts/ directory. It calls the CCI API directly using huaweicloudsdkcore.signer.signer.Signer and requests, bypassing hcloud's annotation limitation:
python scripts/cci_network_helper.py create \
--namespace=<ns-name> \
--name=<network-name> \
--network-id=<neutron-network-id> \
--attached-vpc=<vpc-id> \
--subnet-id=<subnet-id> \
--security-group=<security-group-id> \
--region=<region>--namespace= CCI namespace (must already exist)--name= Network resource name--network-id= neutron network ID (required)--attached-vpc= VPC ID--subnet-id= subnet ID--security-group= default security group ID (set via thenetwork.alpha.kubernetes.io/default-security-groupannotation)--region= Huawei Cloud region
Fallback: hcloud CLI (Without Security Group Annotation)
If the security group annotation is not needed, hcloud CLI can create a Network without it:
hcloud CCI createNetworkingCciIoV1beta1NamespacedNetwork \
--namespace=<ns-name> \
--metadata.name=<network-name> \
--spec.networkID=<neutron-network-id> \
--spec.attachedVPC=<vpc-id> \
--spec.subnetID=<subnet-id> \
--cli-region=<region> \
--cli-output=jsonNote: This omits the network.alpha.kubernetes.io/default-security-group annotation. Use the Python helper script for complete Network creation with the security group annotation.Network Creation Status Lifecycle
Network creation returns status.state=Initializing. The Network transitions to Active once ready.
| State | Meaning | Action |
|---|---|---|
Initializing | Network is being created | Wait — do not create workloads yet |
Active | Network is ready | You can now create workloads in the namespace |
You must verify the Network reaches `Active` before creating workloads. See "Read Network Status" below.
- One Network per namespace is the typical and recommended pattern
- The namespace must already exist before creating a Network in it
List Networks
hcloud CCI listNetworkingCciIoV1beta1NamespacedNetwork \
--namespace=<ns-name> \
--cli-region=<region> \
--cli-output=jsonRead Network
hcloud CCI readNetworkingCciIoV1beta1NamespacedNetwork \
--name=<network-name> --namespace=<ns-name> \
--cli-region=<region> --cli-output=jsonRead Network Status
Check whether the Network has become Active (required before creating workloads):
hcloud CCI readNetworkingCciIoV1beta1NamespacedNetworkStatus \
--name=<network-name> --namespace=<ns-name> \
--cli-region=<region> --cli-output=json- Network must reach
Activestate before workloads can be created in the namespace - If status is
Initializing, wait and re-check
Delete Network
TWO-STEP CONFIRMATION REQUIRED.
Step 1: Warn the user
WARNING: Deleting the Network will cause all pods in this namespace to lose network connectivity. This is irreversible.
Step 2: Execute (only after explicit user confirmation)
hcloud CCI deleteNetworkingCciIoV1beta1NamespacedNetwork \
--name=<network-name> --namespace=<ns-name> \
--cli-region=<region>Annotation Key Reference
| Annotation Key | Value | Purpose | hcloud CLI Support |
|---|---|---|---|
network.alpha.kubernetes.io/default-security-group | Security group ID (e.g., sg-xxxx) | Default security group for Network | Cannot pass via hcloud CLI — dots treated as nested delimiters; use Python helper script |
namespace.kubernetes.io/flavor | general-computing or gpu-accelerated | Namespace flavor type | Works via --metadata.annotations.namespace-kubernetes-io/flavor (hyphen workaround) |
Pod Management
Pod lifecycle operations — bare pods (single container instance, no replica management).
---
1. Create Pod (Bare Pod)
hcloud CCI createCoreV1NamespacedPod \
--namespace=<ns-name> \
--metadata.name=<pod-name> \
--spec.containers.1.name=<container-name> \
--spec.containers.1.image=<image> \
--spec.containers.1.resources.limits.cpu=500m \
--spec.containers.1.resources.limits.memory=1Gi \
--spec.containers.1.resources.requests.cpu=250m \
--spec.containers.1.resources.requests.memory=512Mi \
--cli-region=<region> \
--cli-output=jsonPrerequisites:
- Namespace must exist before creating a Pod
- Network resource must exist in the namespace
CCI-specific requirements:
resources.limitsandresources.requestsare MANDATORY — CCI rejects pods without resource specifications- Array items are 1-based:
--spec.containers.1.name(not0)
NOT recommended for production — bare pods are not self-healing. Use Deployment or StatefulSet for replica management and restart policies.
---
2. List Pods
# List pods in a specific namespace
hcloud CCI listCoreV1NamespacedPod --namespace=<ns-name> --cli-region=<region> --cli-output=json
# List pods across all namespaces
hcloud CCI listCoreV1PodForAllNamespaces --cli-region=<region> --cli-output=jsonJMESPath filter example:
hcloud CCI listCoreV1NamespacedPod \
--namespace=<ns-name> \
--cli-region=<region> \
--cli-output=json \
--cli-query="items[].{Name:metadata.name,Phase:status.phase,IP:status.podIP}"---
3. Read Pod / Pod Status
# Read full Pod definition
hcloud CCI readCoreV1NamespacedPod --name=<pod-name> --namespace=<ns-name> --cli-region=<region>
# Read Pod status only
hcloud CCI readCoreV1NamespacedPodStatus --name=<pod-name> --namespace=<ns-name> --cli-region=<region> --cli-output=json---
4. Delete Pod — TWO-STEP CONFIRMATION
hcloud CCI deleteCoreV1NamespacedPod --name=<pod-name> --namespace=<ns-name> --cli-region=<region>Always confirm with the user before deleting a Pod. Check if the pod is managed by a Deployment/StatefulSet first — deleting a replica pod will cause the controller to recreate it.
---
5. Pod Phases
| Phase | Meaning |
|---|---|
Pending | Pod accepted but containers not yet running (waiting for scheduling, image pull, etc.) |
Running | Pod bound to a node and at least one container is running |
Succeeded | All containers terminated successfully (won't restart) |
Failed | At least one container terminated with non-zero exit code |
Unknown | Pod state could not be determined (typically node communication failure) |
---
6. Pod with EIP Annotation (Public IP)
To assign a public IP to a Pod via EIPPool:
hcloud CCI createCoreV1NamespacedPod \
--namespace=<ns-name> \
--metadata.name=<pod-name> \
--metadata.annotations.yangtse.io/eippool=<eippool-name> \
--spec.containers.1.name=<container-name> \
--spec.containers.1.image=<image> \
--spec.containers.1.resources.limits.cpu=500m \
--spec.containers.1.resources.limits.memory=1Gi \
--spec.containers.1.resources.requests.cpu=250m \
--spec.containers.1.resources.requests.memory=512Mi \
--cli-region=<region> \
--cli-output=jsonThe annotation yangtse.io/eippool=<eippool-name> tells CCI to allocate an EIP from the specified EIPPool to this Pod.
StatefulSet Management
StatefulSet lifecycle operations for stateful workloads (databases, message queues, etc.).
---
1. Create StatefulSet
hcloud CCI createAppsV1NamespacedStatefulSet \
--namespace=<ns-name> \
--metadata.name=<sts-name> \
--spec.replicas=1 \
--spec.selector.matchLabels.app=<sts-name> \
--spec.template.metadata.labels.app=<sts-name> \
--spec.template.spec.containers.1.name=<container-name> \
--spec.template.spec.containers.1.image=<image> \
--spec.template.spec.containers.1.resources.limits.cpu=500m \
--spec.template.spec.containers.1.resources.limits.memory=1Gi \
--spec.serviceName=<sts-name> \
--cli-region=<region> \
--cli-output=jsonRequired fields:
spec.serviceName— headless Service name for network identity (REQUIRED for StatefulSet)spec.selector.matchLabels— must matchspec.template.metadata.labels- Resources (
limits) are MANDATORY on CCI
PVC volumeClaimTemplates example (persistent storage):
hcloud CCI createAppsV1NamespacedStatefulSet \
--namespace=<ns-name> \
--metadata.name=<sts-name> \
--spec.replicas=1 \
--spec.selector.matchLabels.app=<sts-name> \
--spec.template.metadata.labels.app=<sts-name> \
--spec.template.spec.containers.1.name=<container-name> \
--spec.template.spec.containers.1.image=<image> \
--spec.template.spec.containers.1.resources.limits.cpu=500m \
--spec.template.spec.containers.1.resources.limits.memory=1Gi \
--spec.template.spec.containers.1.volumeMounts.1.name=data \
--spec.template.spec.containers.1.volumeMounts.1.mountPath=/data \
--spec.volumeClaimTemplates.1.metadata.name=data \
--spec.volumeClaimTemplates.1.spec.accessModes.1=ReadWriteOnce \
--spec.volumeClaimTemplates.1.spec.resources.requests.storage=10Gi \
--spec.volumeClaimTemplates.1.spec.storageClassName=<sc-name> \
--spec.serviceName=<sts-name> \
--cli-region=<region> \
--cli-output=json---
2. List / Read / Status
# List all StatefulSets in namespace
hcloud CCI listAppsV1NamespacedStatefulSet --namespace=<ns-name> --cli-region=<region> --cli-output=json
# Read a specific StatefulSet
hcloud CCI readAppsV1NamespacedStatefulSet --name=<sts-name> --namespace=<ns-name> --cli-region=<region>
# Read StatefulSet status only
hcloud CCI readAppsV1NamespacedStatefulSetStatus --name=<sts-name> --namespace=<ns-name> --cli-region=<region> --cli-output=json---
3. Update StatefulSet (Patch)
hcloud CCI patchAppsV1NamespacedStatefulSet \
--name=<sts-name> --namespace=<ns-name> \
--spec.template.spec.containers.1.image=<new-image> \
--cli-region=<region>Common patch operations:
- Image update:
--spec.template.spec.containers.1.image=<new-image> - Replica scaling:
--spec.replicas=<new-count>
---
4. Delete StatefulSet — TWO-STEP CONFIRMATION
hcloud CCI deleteAppsV1NamespacedStatefulSet --name=<sts-name> --namespace=<ns-name> --cli-region=<region>WARNING: PVCs created by volumeClaimTemplates are NOT automatically deleted when the StatefulSet is deleted. Manual cleanup is required:
hcloud CCI deleteCoreV1NamespacedPersistentVolumeClaim --name=<pvc-name> --namespace=<ns-name> --cli-region=<region>Always confirm with the user before deleting a StatefulSet. List PVCs first to show what will remain.
---
5. StatefulSet vs Deployment — When to Use Each
| Criteria | StatefulSet | Deployment |
|---|---|---|
| Workload type | Databases, message queues, distributed storage | Web servers, APIs, microservices |
| Pod identity | Stable hostname (<sts-name>-0, -1, ...) | Random generated names |
| Pod ordering | Ordered create/delete (0→1→2) | Parallel, no ordering |
| Storage | volumeClaimTemplates per pod | Shared or no persistent storage |
| Network | Stable DNS per pod via headless Service | Single Service endpoint |
| Updates | RollingUpdate with partition support or OnDelete | RollingUpdate by default |
Use StatefulSet when you need: stable network identity, ordered deployment, or per-pod persistent storage. Use Deployment for all other stateless workloads.
---
6. PVC Handling Notes
- volumeClaimTemplates auto-creates one PVC per replica:
<pvc-name>-<sts-name>-<ordinal> - PVC naming:
<volumeClaimTemplateName>-<sts-name>-0,-1, etc. - StorageClass: specify
--spec.volumeClaimTemplates.1.spec.storageClassName=<sc-name>; CCI provides default if omitted - PVC lifecycle is independent — deleting the StatefulSet does NOT delete PVCs
- To clean up: manually delete each PVC after the StatefulSet is removed
- Reclaim policy: follows StorageClass settings (Retain or Delete)
Troubleshooting Guide for CCI hcloud CLI Issues
1. Namespace Creation Fails
Cause: Missing namespace.kubernetes.io/flavor annotation.
Fix: Add the flavor annotation:
--metadata.annotations.namespace-kubernetes-io/flavor=general-computingWithout this annotation, CCI rejects namespace creation requests.
2. Network Creation Fails
Cause: Invalid subnet ID, VPC ID, or CIDR conflict.
Fix:
- Verify subnet ID with
hcloud VPC ListSubnets --vpc-id=<vpc-id> - Verify VPC ID with
hcloud VPC ShowVpc - Ensure Network CIDR does not overlap with
10.247.0.0/16(reserved for CCI internal routing) - Use a different CIDR range such as
10.0.0.0/24or172.16.0.0/24
3. Pod Stays in Pending State
Cause: No Network in namespace, insufficient resources, or image pull failure.
Fix:
- Check events:
hcloud CCI listCoreV1NamespacedEvent --namespace=<ns-name> - Verify Network exists in the namespace
- Verify image name and credentials
- Check resource availability in the namespace
4. Deployment Pods Not Becoming Ready
Cause: Container crash, image pull error, or resource limits exceeded.
Fix:
- Read Pod status:
hcloud CCI readCoreV1NamespacedPodStatus --name=<pod> --namespace=<ns> - Check events:
hcloud CCI listCoreV1NamespacedEvent --namespace=<ns-name> - Read Pod logs:
hcloud CCI readCoreV1NamespacedPodLog --name=<pod> --namespace=<ns> --container=<container> - Check resource limits vs available namespace resources
5. Permission Denied (403)
Cause: IAM permissions insufficient for the requested operation.
Fix: Refer to iam-policies.md, identify the missing permission, and add it to the IAM policy.
6. Parameter Format Errors
Common mistakes:
- Using JSON objects instead of
{*}format for nested parameters - Using 0-based indexing instead of 1-based indexing
- Missing equals sign in
--key=valueformat - Using wrong parameter names
Fix: Refer to parameter-format.md for correct hcloud CLI parameter syntax.
7. EIPPool Creation Fails
Cause: No available EIPs in the project, or CIDR format error.
Fix:
- Verify EIP availability:
hcloud VPC ListPublicIps - Check CIDR format (must be valid IPv4 CIDR, e.g.,
10.0.0.0/24) - Ensure sufficient EIPs exist for the pool size
8. Deep Nested Parameter Construction Is Complex
Fix:
- Always use
hcloud CCI <Operation> --helpfirst to see parameter structure - Build parameters incrementally, adding one nested level at a time
- Use
--dryRun=Allto validate parameters before execution - Refer to parameter-format.md for nested parameter syntax rules
9. hcloud CLI General Errors
| Error Type | Description | Resolution |
|---|---|---|
[NETWORK_ERROR] | Network connectivity issue | Check network connection and proxy settings |
[USE_ERROR] | Parameter format error | Check parameter format, refer to parameter-format.md |
[OPENAPI_ERROR] | API version compatibility issue | Check API version, update hcloud CLI |
| Debug flag | --cli-debug=true | Add this flag to any command for detailed debug output |
10. Pod Exec Operations
The connectCoreV1GetNamespacedPodExec and connectCoreV1PostNamespacedPodExec operations are interactive WebSocket operations. They may not work well in hcloud CLI batch mode.
Alternative: Use Pod logs for diagnostics instead of exec:
hcloud CCI readCoreV1NamespacedPodLog --name=<pod> --namespace=<ns> --container=<container>11. CCI Network "securitygroup can not be empty" Error
Cause: The annotation key network.alpha.kubernetes.io/default-security-group is not correctly passed.
Common root causes:
- Wrong annotation key used (e.g.,
security-group-idinstead ofdefault-security-group) - hcloud CLI cannot pass annotation keys containing dots - it treats dots as nested levels
- hcloud
--cli-jsonInputdoesn't properly transmit annotations (see Section 13)
Fix: Use the Python helper script for Network creation instead of hcloud CLI. The Python SDK correctly handles annotation keys with dots.
12. hcloud CLI "Incorrect parameter" Error for Annotation Keys with Dots
Cause: When using --metadata.annotations.network.alpha.kubernetes.io/key=value, hcloud treats each dot as a nested object level delimiter. No escaping mechanism (backslash, quotes, etc.) works.
Fix: This is an hcloud CLI limitation. Use the Python helper script for any CCI resource creation that requires annotation keys with dots (especially Network). hcloud CLI is usable only for annotation keys without dots (e.g., hyphenated keys on Namespace).
13. hcloud --cli-jsonInput "Failed to parse cli-jsonInput parameter file" Error
Cause: Multiple possible causes for this JSON input parsing failure.
Root causes and fixes:
- UTF-8 with BOM encoding: hcloud cannot parse files with BOM. Use ASCII encoding (or UTF-8 without BOM) for the JSON input file.
- Annotations with dots not transmitted: This is a confirmed hcloud bug. Annotations with dots appear in
--dryrunoutput but are not included in the actual API request body. Use the Python helper script instead. - Incorrect JSON structure: The JSON structure must exactly match the skeleton format shown by
hcloud CCI <Operation> --help. Verify field names, nesting, and required fields.
14. Network Creation "spec[networkID]: Required value" Error
Cause: The networkID field (neutron network ID) is missing from the Network spec. This field is required alongside attachedVPC, subnetID, and networkType.
Fix: Obtain the neutron network ID from hcloud VPC ShowSubnet output and include it in the Network spec as the networkID field.
15. CCI Annotation Key Auto-Normalization
Behavior: For Namespace resources, CCI automatically adds the canonical dotted annotation key (namespace.kubernetes.io/flavor) alongside the hyphenated version (namespace-kubernetes-io/flavor) when you provide only the hyphenated form. This auto-normalization only works for Namespace.
Important: This normalization does NOT apply to Network resources. For Network, you must provide the exact dotted annotation keys (network.alpha.kubernetes.io/default-security-group, etc.) yourself. Since hcloud CLI cannot handle dotted keys, use the Python helper script for Network creation.
16. Deployment "limit and request doesn't equal" Error
Cause: CCI requires container resource limits to equal requests. If limits != requests, CCI rejects the Deployment/Pod creation.
Fix: Set requests to the same values as limits:
--spec.template.spec.containers.1.resources.limits.cpu=500m
--spec.template.spec.containers.1.resources.limits.memory=1Gi
--spec.template.spec.containers.1.resources.requests.cpu=500m
--spec.template.spec.containers.1.resources.requests.memory=1Gi17. EIPPool Creation Fails with "Object 'Kind' is missing"
Cause: Missing --apiVersion=crd.yangtse.cni/v1 and --kind=EIPPool parameters.
Fix: Include both required fields:
--apiVersion=crd.yangtse.cni/v1 --kind=EIPPool18. EIPPool Creation Fails with 422 "spec.eipAttributes.networkType: Required value"
Cause: Missing the required --spec.eipAttributes.networkType parameter.
Fix: Add --spec.eipAttributes.networkType=5_bgp (dynamic BGP) or 5_gray (dedicated load balancing).
19. EIPPool Creation Fails with 403 "name, size, shareType and chargeMode are required"
Cause: Missing required bandwidth fields when auto-creating EIPs.
Fix: Include all bandwidth fields:
--spec.eipAttributes.bandwidth.shareType=PER
--spec.eipAttributes.bandwidth.size=5
--spec.eipAttributes.bandwidth.chargeMode=bandwidth
--spec.eipAttributes.bandwidth.name=<bandwidth-name>Step-by-Step Verification Process for CCI Skill Functionality
1. Environment Verification
hcloud version # >= 7.2.2
hcloud configure list # valid profile exists2. Namespace Verification
hcloud CCI listCoreV1Namespace --cli-region=cn-north-4 --cli-output=jsonExpected: list of namespaces with metadata.name and status.phase.
3. Network Verification
hcloud CCI readNetworkingCciIoV1beta1NamespacedNetworkStatus \
--name=<network-name> --namespace=<ns-name> \
--cli-region=cn-north-4 --cli-output=jsonExpected: status.state=Active.
4. Deployment Verification
hcloud CCI readAppsV1NamespacedDeploymentStatus \
--name=<deploy-name> --namespace=<ns-name> \
--cli-region=cn-north-4 --cli-output=jsonExpected: status.readyReplicas > 0, status.availableReplicas > 0.
5. Pod Verification
hcloud CCI readCoreV1NamespacedPodStatus \
--name=<pod-name> --namespace=<ns-name> \
--cli-region=cn-north-4 --cli-output=jsonExpected: status.phase=Running.
6. Log Verification
hcloud CCI readCoreV1NamespacedPodLog \
--name=<pod-name> --namespace=<ns-name> \
--container=<container-name> \
--cli-region=cn-north-4Expected: application log output.
7. Delete Operation Verification
Two-step confirmation process:
1. Test without confirmation: show preview and warning only, do not execute deletion. 2. Test with confirmation: verify the resource is actually deleted by attempting to read it (should return 404 or empty result).
8. Complete Verification Checklist
| Step | Verification Item | Expected Result | Verification Command |
|---|---|---|---|
| 1 | hcloud CLI installed | version >= 7.2.2 | hcloud version |
| 2 | CLI profile configured | valid profile listed | hcloud configure list |
| 3 | Namespace created | status.phase=Active | listCoreV1Namespace |
| 4 | Network created | status.state=Active | readNetworkingCciIoV1beta1NamespacedNetworkStatus |
| 5 | Deployment created | readyReplicas > 0 | readAppsV1NamespacedDeploymentStatus |
| 6 | Pod running | status.phase=Running | readCoreV1NamespacedPodStatus |
| 7 | Logs accessible | application log output | readCoreV1NamespacedPodLog |
| 8 | Delete requires confirmation | preview shown, no deletion | test delete without confirm |
| 9 | Delete with confirmation | resource removed | test delete with confirm, then read returns 404 |
| 10 | Permission errors handled | policy shown, execution paused | test with insufficient permissions |
#!/usr/bin/env python3
"""
CCI Network Creation Helper Script
This script creates a CCI Network by directly calling the CCI OpenAPI,
bypassing hcloud CLI's limitation with annotation keys containing dots.
hcloud CLI treats dots in annotation keys as nested object delimiters,
making it impossible to pass 'network.alpha.kubernetes.io/default-security-group'
via CLI parameters or --cli-jsonInput (which also doesn't properly transmit
annotations in actual API requests, despite showing them in --dryrun).
Usage:
python cci_network_helper.py create \
--namespace <ns-name> \
--name <network-name> \
--vpc-id <vpc-id> \
--subnet-id <neutron-subnet-id> \
--network-id <neutron-network-id> \
--security-group-id <sg-id> \
--region <region>
python cci_network_helper.py delete \
--namespace <ns-name> \
--name <network-name> \
--region <region>
python cci_network_helper.py status \
--namespace <ns-name> \
--name <network-name> \
--region <region>
Required Python packages:
pip install requests huaweicloudsdkcore
Environment variables (required):
HW_ACCESS_KEY - Huawei Cloud AK
HW_SECRET_KEY - Huawei Cloud SK
Environment variables (optional for temporary credential mode):
HW_SECURITY_TOKEN - Huawei Cloud SecurityToken (temporary credential mode)
Falls back to HUAWEI_CLOUD_SECURITY_TOKEN if HW_SECURITY_TOKEN not set.
When set, the script uses temporary STS credential authentication.
Note: subnet-id must be the neutron_subnet_id (not the VPC subnet ID).
network-id must be the neutron_network_id (not the VPC subnet ID).
Both can be obtained from: hcloud VPC ShowSubnet --subnet_id=<id> --cli-region=<region>
"""
import argparse
import json
import os
import sys
import requests
try:
from huaweicloudsdkcore.auth.credentials import BasicCredentials
from huaweicloudsdkcore.signer.signer import Signer
from huaweicloudsdkcore.sdk_request import SdkRequest
except ImportError:
print("ERROR: huaweicloudsdkcore not installed. Run: pip install huaweicloudsdkcore")
sys.exit(1)
def get_credentials():
ak = os.environ.get("HW_ACCESS_KEY")
sk = os.environ.get("HW_SECRET_KEY")
if not ak or not sk:
print("ERROR: HW_ACCESS_KEY and HW_SECRET_KEY environment variables must be set")
sys.exit(1)
# Support SecurityToken for temporary credential mode
# Check HW_SECURITY_TOKEN first, then fall back to HUAWEI_CLOUD_SECURITY_TOKEN
security_token = os.environ.get("HW_SECURITY_TOKEN") or os.environ.get("HUAWEI_CLOUD_SECURITY_TOKEN")
return ak, sk, security_token
def get_project_id(region):
import subprocess
try:
cmd = f"hcloud IAM KeystoneListProjects --cli-region={region} --cli-output=json"
result = subprocess.run(
cmd, capture_output=True, timeout=15,
encoding="utf-8", errors="replace", shell=True,
)
if result.returncode == 0 and result.stdout.strip().startswith("{"):
data = json.loads(result.stdout)
for p in data.get("projects", []):
if p.get("name") == region:
return p["id"]
except Exception:
pass
print(f"ERROR: Cannot auto-detect project ID for region {region}")
print(f" Please provide --project-id explicitly")
print(f" Or run: hcloud IAM KeystoneListProjects --cli-region={region} --cli-output=json")
sys.exit(1)
def sign_request(method, host, resource_path, body, ak, sk, security_token, project_id):
creds = BasicCredentials(ak=ak, sk=sk, project_id=project_id)
if security_token:
creds = creds.with_security_token(security_token)
signer = Signer(creds)
req = SdkRequest(
method=method,
schema="https",
host=host,
resource_path=resource_path,
uri=resource_path,
body=body,
header_params={"Content-Type": "application/json", "Host": host},
query_params=[],
)
signed_req = signer.sign(req)
headers = signed_req.header_params
headers["X-Project-Id"] = project_id
return headers
def create_network(namespace, name, vpc_id, subnet_id, network_id, security_group_id, region, project_id=None):
ak, sk, security_token = get_credentials()
if not project_id:
project_id = get_project_id(region)
body_dict = {
"apiVersion": "networking.cci.io/v1beta1",
"kind": "Network",
"metadata": {
"name": name,
"annotations": {
"network.alpha.kubernetes.io/default-security-group": security_group_id
},
},
"spec": {
"attachedVPC": vpc_id,
"networkID": network_id,
"subnetID": subnet_id,
"networkType": "underlay_neutron",
},
}
body = json.dumps(body_dict)
host = f"cci.{region}.myhuaweicloud.com"
resource_path = (
f"/apis/networking.cci.io/v1beta1/namespaces/{namespace}/networks"
)
url = f"https://{host}{resource_path}"
headers = sign_request("POST", host, resource_path, body, ak, sk, security_token, project_id)
resp = requests.post(url, data=body.encode("utf-8"), headers=headers)
result = json.loads(resp.text)
if resp.status_code == 201:
state = result.get("status", {}).get("state", "Unknown")
print(f"SUCCESS: Network '{name}' created in namespace '{namespace}'")
print(f" State: {state}")
print(f" UID: {result.get('metadata', {}).get('uid', 'N/A')}")
else:
print(f"ERROR: Network creation failed. Status: {resp.status_code}")
msg = result.get("message", resp.text)
print(f" Message: {msg}")
return resp.status_code
def delete_network(namespace, name, region, project_id=None):
ak, sk, security_token = get_credentials()
if not project_id:
project_id = get_project_id(region)
host = f"cci.{region}.myhuaweicloud.com"
resource_path = (
f"/apis/networking.cci.io/v1beta1/namespaces/{namespace}/networks/{name}"
)
url = f"https://{host}{resource_path}"
headers = sign_request("DELETE", host, resource_path, "", ak, sk, security_token, project_id)
resp = requests.delete(url, headers=headers)
if resp.status_code in (200, 204):
print(f"SUCCESS: Network '{name}' deleted from namespace '{namespace}'")
else:
try:
result = json.loads(resp.text)
print(f"ERROR: Network deletion failed. Status: {resp.status_code}")
print(f" Message: {result.get('message', resp.text)}")
except json.JSONDecodeError:
print(f"ERROR: Network deletion failed. Status: {resp.status_code}")
return resp.status_code
def check_status(namespace, name, region, project_id=None):
ak, sk, security_token = get_credentials()
if not project_id:
project_id = get_project_id(region)
host = f"cci.{region}.myhuaweicloud.com"
resource_path = (
f"/apis/networking.cci.io/v1beta1/namespaces/{namespace}/networks/{name}"
)
url = f"https://{host}{resource_path}"
headers = sign_request("GET", host, resource_path, "", ak, sk, security_token, project_id)
resp = requests.get(url, headers=headers)
result = json.loads(resp.text)
if resp.status_code == 200:
state = result.get("status", {}).get("state", "Unknown")
cidr = result.get("spec", {}).get("cidr", "N/A")
print(f"Network '{name}' in namespace '{namespace}'")
print(f" State: {state}")
print(f" CIDR: {cidr}")
else:
print(f"ERROR: Failed to get network status. Status: {resp.status_code}")
print(f" Message: {result.get('message', resp.text)}")
return resp.status_code
def main():
parser = argparse.ArgumentParser(
description="CCI Network helper (bypasses hcloud CLI annotation key limitation)"
)
subparsers = parser.add_subparsers(dest="action", required=True)
create_parser = subparsers.add_parser("create", help="Create a CCI Network")
create_parser.add_argument("--namespace", required=True, help="CCI namespace name")
create_parser.add_argument("--name", required=True, help="Network name")
create_parser.add_argument("--vpc-id", required=True, help="VPC ID (attachedVPC)")
create_parser.add_argument(
"--subnet-id",
required=True,
help="Neutron subnet ID (not VPC subnet ID). Get from: hcloud VPC ShowSubnet",
)
create_parser.add_argument(
"--network-id",
required=True,
help="Neutron network ID. Get from: hcloud VPC ShowSubnet",
)
create_parser.add_argument(
"--security-group-id",
required=True,
help="Security group ID for the network",
)
create_parser.add_argument("--region", required=True, help="Region (e.g., cn-north-4)")
create_parser.add_argument("--project-id", default=None, help="Project ID (auto-detected if omitted)")
delete_parser = subparsers.add_parser("delete", help="Delete a CCI Network")
delete_parser.add_argument("--namespace", required=True, help="CCI namespace name")
delete_parser.add_argument("--name", required=True, help="Network name")
delete_parser.add_argument("--region", required=True, help="Region")
delete_parser.add_argument("--project-id", default=None, help="Project ID (auto-detected if omitted)")
status_parser = subparsers.add_parser("status", help="Check CCI Network status")
status_parser.add_argument("--namespace", required=True, help="CCI namespace name")
status_parser.add_argument("--name", required=True, help="Network name")
status_parser.add_argument("--region", required=True, help="Region")
status_parser.add_argument("--project-id", default=None, help="Project ID (auto-detected if omitted)")
args = parser.parse_args()
if args.action == "create":
create_network(
args.namespace,
args.name,
args.vpc_id,
args.subnet_id,
args.network_id,
args.security_group_id,
args.region,
args.project_id,
)
elif args.action == "delete":
delete_network(args.namespace, args.name, args.region, args.project_id)
elif args.action == "status":
check_status(args.namespace, args.name, args.region, args.project_id)
if __name__ == "__main__":
main()