-cluster account, with its PASSWORDCluster create and delete run ONLY as {{TENANT_SHORT_NAME}}-cluster, signed in with its password. The platform's cluster machinery cannot operate through an application credential -- a cluster create attempted with the -svc credential fails every time, no matter how it is phrased. This is a platform constraint, not a configuration you (or the operator) can change. Do not "simplify" cluster automation to the application credential; it will never work.
Sign in (prompt the human for the password -- never read it from a file into your context, never store it in CI):
export OS_AUTH_TYPE=password
export OS_AUTH_URL={{AUTH_URL}}
export OS_IDENTITY_API_VERSION=3
export OS_CACERT=<path to the delivered CA bundle>
export OS_USERNAME={{TENANT_SHORT_NAME}}-cluster
export OS_USER_DOMAIN_NAME={{TENANT_SHORT_NAME}}
export OS_PROJECT_NAME={{TENANT_SHORT_NAME}}-prod
export OS_PROJECT_DOMAIN_NAME={{TENANT_SHORT_NAME}}
read -rs -p "password for {{TENANT_SHORT_NAME}}-cluster: " OS_PASSWORD && export OS_PASSWORD
openstack token issue # smoke test
The SSH keypair {{TENANT_SHORT_NAME}}-key is OWNED by the -cluster account, and the platform validates keypair ownership in the cluster creator's context. Consequences:
{{TENANT_SHORT_NAME}}-key or recreate it under another account. A key with the same name owned by -svc or a team user will make every cluster create fail.OS_USERNAME before anything else.The standard onboarding delivers a cluster template at handover:
openstack coe cluster template show {{TENANT_SHORT_NAME}}-k8s
If that template is missing, or you need a variant, create your own -- see "Creating your own cluster template" below.
Create (node counts are limited by your quota; builds take TENS OF MINUTES -- poll slowly or just wait):
openstack coe cluster create <cluster-name> \
--cluster-template {{TENANT_SHORT_NAME}}-k8s \
--keypair {{TENANT_SHORT_NAME}}-key \
--master-count 1 --node-count <N>
openstack coe cluster show <cluster-name> # poll >=10s apart
# done when status = CREATE_COMPLETE
Fetch the kubeconfig (treat it as a credential -- never print its contents; store it like any other secret):
openstack coe cluster config <cluster-name> --dir <secure-dir> export KUBECONFIG=<secure-dir>/config kubectl get nodes
Delete (confirm with the human first, by name):
openstack coe cluster delete <cluster-name>
Templates are PROJECT-SCOPED: everyone in your project can already use them. The one hard rule: NEVER set the Public or Hidden flag (the two checkboxes in the dashboard's Create Cluster Template dialog, or --public / --hidden on the CLI). Publishing a template cloud-wide is an operator-only action, and the platform refuses the whole create with:
Not authorized to set public or hidden flag for cluster template (HTTP 403)
In the dashboard this surfaces only as the generic "Error: Unable to create cluster template." -- if you see that toast, the Public/Hidden checkboxes are the FIRST thing to check. You lose nothing by leaving them unchecked.
The second hard rule: use --network-driver calico. This platform supports calico. Do NOT choose flannel -- a flannel cluster never finishes coming up: the create sits IN_PROGRESS and eventually fails, with the nodes never going Ready. A cluster stuck in CREATE_IN_PROGRESS far past the normal build time is almost always this. Rebuild the template with calico.
A known-good CLI starting point, mirroring the platform-delivered template (works signed in as -svc or -cluster):
openstack coe cluster template create <template-name> \
--coe kubernetes \
--image <public kube image name or UUID> \
--external-network provider-ext \
--master-flavor <flavor> --flavor <flavor> \
--network-driver calico --docker-storage-driver overlay2 \
--master-lb-enabled --floating-ip-enabled \
--fixed-network {{TENANT_SHORT_NAME}}-net \
--fixed-subnet {{TENANT_SHORT_NAME}}-subnet
Pick the two machine sizes from openstack flavor list; if you have the delivered template, openstack coe cluster template show {{TENANT_SHORT_NAME}}-k8s shows the platform's known-good choices.
Do NOT bake --keypair into the template: the keypair is owned by the -cluster account (see the trap above), so it is passed at cluster create time instead, exactly as the lifecycle section shows.
The cluster gets its own load balancer for the Kubernetes API, and it can publish Service objects of type: LoadBalancer through the same platform mechanism -- no extra setup needed:
kubectl expose deployment <app> --type=LoadBalancer --port=80
The Service's external address is allocated from the platform. Each such Service consumes a load balancer (and typically a floating IP) from YOUR quota -- prefer a single ingress controller of type LoadBalancer fronting many Services over one LoadBalancer per app.
-cluster, OUTSIDE CI.-cluster password into CI so pipelines can create clusters. If your workflow genuinely needs cluster-per-run, raise it with {{ACCOUNT_CONTACT}} first -- there are capacity and quota implications.Day-2 cloud work around the cluster (networks, floating IPs, volumes, extra load balancers) still runs as -svc per references/day2-operations.md; only cluster create/delete needs the -cluster password login.