Our Community is getting an upgrade! To get everything ready for the relaunch, we’ll be placing the site in read-only mode starting September 21st.
We really appreciate your understanding while we get things set up behind the scenes. Catch up on all the exciting details about the move here.
Need help or have questions? Drop us a line at [email protected]
Created on 08-05-2026 08:26 AM
Cloudera has a lot of ways to get a cluster. Almost none of them are “one command on your laptop.” cloudera-labs/cloudera-ce-aws is the exception: a Terraform + Ansible bundle that stands up a full Cloudera Private Cloud Community Edition cluster on AWS — Cloudera Manager, Kerberos, Auto-TLS, a real storage/compute topology — from a single ansible-navigator run. This post is me taking my freshly-released fork from zero to a running Ozone cluster, and the handful of real snags between the README and a green Cloudera Manager.
Everything here is field-run against cloudera-ce-aws v1.0.0, deploying Cloudera Manager 7.13.2 / Runtime 7.3.2, from an Apple-Silicon Mac into AWS account AWS SE in us-east-2.
A ring-fenced cluster — ~11 EC2 nodes — with everything a real Cloudera deployment has and a laptop demo usually fakes:
The whole thing is idempotent: re-running produces no unintended changes. The node roles and default sizing (t3a for most, one r5a.xlarge for CMS):
Role Count Instance
| gateway | 1 | t3a.medium |
| services | 1 | t3a.large |
| masters | 3 | t3a.xlarge |
| workers | 4 | t3a.xlarge |
| cms | 1 | r5a.xlarge |
| sdx | 1 | t3a.xlarge |
At on-demand rates that’s roughly ~$2/hr / ~$45/day — worth a pause.yml between sessions (stops EC2, keeps EBS) if you’re leaving it up.
Every dependency — Terraform, Ansible, all the collections — is baked into an Ansible execution-environment container image. Locally you need almost nothing:
git clone https://github.com/cloudera-labs/cloudera-ce-aws.git
cd cloudera-ce-aws
python -m venv ~/cdp-navigator && source ~/cdp-navigator/bin/activate
pip install ansible-core ansible-navigatorPlus a container runtime (Docker or Podman) and two credentials: AWS SSO and a Cloudera license .txt.
# AWS SSO — the config uses your SSO profile to mint short-lived creds
aws sso login --profile YOUR_PROFILE
# Cloudera Private Cloud license — the text file, NOT the .zip
export CDP_LICENSE_FILE=/path/to/license.txtThen a three-line config.yml:
name_prefix: "steven-ce"
infra_region: "us-east-2"
common_password: "<min 8 chars, 1 number>"
owner_email: "[email protected]"
And the one command that does everything:
ansible-navigator run playbooks/infrastructure.yml playbooks/services.yml \
playbooks/cms.yml playbooks/ozone-cluster.yml -e @config.yml -m stdoutFour playbooks, four stages: Terraform provisions the AWS infra → Ansible configures DNS/Kerberos/DB/TLS → Cloudera Manager comes up → the Ozone cluster deploys.
The quickstart is clean, but seven things cost me time — exactly the stuff a reveal post should call out. The first four are one-time setup friction; the last three are genuine traps in the v1.0.0 release.
ansible-navigator.yml points the execution environment at ghcr.io/cloudera-labs/cloudera-ce-aws:latest. That tag doesn’t exist — the registry only publishes 1.0.0-amd64:
Error response from daemon: failed to resolve reference
"ghcr.io/cloudera-labs/cloudera-ce-aws:latest": not foundFix — pin the real tag in ansible-navigator.yml:
image: ghcr.io/cloudera-labs/cloudera-ce-aws:1.0.0-amd64
The only published arch is -amd64. On an M-series Mac the image runs under emulation; make it explicit so Docker doesn’t guess:
container-options:
- "--network=host"
- "--platform=linux/amd64"
The EE is an orchestration controller — it drives Terraform and SSHes to the nodes; it isn’t doing heavy local compute — so emulation is a non-issue for throughput here.
I was logged into the AWS access portal in the browser, but the CLI had no profile, no cached token, nothing — NoCredentials. The fix is aws configure sso, but the trap is subtler: after setup my default profile carried the sso_session but was missing sso_account_id and sso_role_name, so it still couldn’t resolve credentials. A complete profile:
[sso-session Cloudera-Main-SSO]
sso_start_url = https://d-xxxxxxxxxx.awsapps.com/start#/
sso_region = us-east-1
sso_registration_scopes = sso:account:access
[profile cldr-se]
sso_session = Cloudera-Main-SSO
sso_account_id = 007856030109
sso_role_name = cldr_poweruser
region = us-east-2
aws sts get-caller-identity --profile cldr-se should return your assumed-role ARN. That token is cached on disk, so it survives across shells — which matters because the deploy consumes the creds via aws configure export-credentials.
config.yml holds a plaintext password and your fork is public. It’s in .gitignore (alongside *.pem and *.tfstate) — confirm that before you commit anything, because a leaked common_password there unlocks every service in the cluster.
Hint — this one cost me a full teardown. Make common_password letters and digits only. Cloudera’s automation sets service admin passwords through basic-auth API calls shaped like https://admin:PASSWORD@host/..., so an @ or # inside the password corrupts the URL’s userinfo section and enrollment fails — and the task is no_log, so the error is censored and you can’t see why. Alphanumeric still satisfies the “min 8 chars, 1 number” rule; you lose nothing.
My first run had common_password full of special characters (#, @). The deploy sailed through Terraform and most of the services stage, then died on:
TASK [cloudera.exe.grafana : Set Grafana admin password if API login fails]
fatal: [<services-node>]: FAILED! => {"censored": "... 'no_log: true' ..."}The result is censored (no_log), but the cause is the password: common_password feeds service admin passwords that get set via basic-auth API calls (https://admin:PASSWORD@host/...). An @ inside the password breaks URL userinfo parsing, so the API login/set fails. The same password later feeds CM, Ranger, Knox, Hue, and SMM — so this isn’t a Grafana quirk, it’s a landmine for every API-set credential downstream.
Fix: keep common_password alphanumeric (letters + digits, meets the “min 8, 1 number” rule without @ # $ / :). Because the password is baked into FreeIPA/DB/services as they’re provisioned, the clean fix is a teardown + redeploy with the safe password, not an in-place change.
config-template.yml implies Prometheus/Grafana is off by default (# enable_prometheus: false). But group_vars/all.yml defines the key twice — false, then true further down — and last-wins in YAML, so the effective default is true. That’s why the Grafana tasks ran (and hit gotcha #5) even though I never enabled them. If you don’t want the monitoring stack, set enable_prometheus: false explicitly in your config.yml so it overrides the duplicate.
The EE launches with --tty, so piping the run through tee sends output to the container’s PTY (the pipe stays empty) and reports the pipeline’s exit code (tee’s 0) rather than ansible’s. A run that actually failed looked like it succeeded. Watch the run with docker logs -f <ansible_runner_container> instead, and trust the PLAY RECAP failed= counts, not the shell exit code.
One ansible-navigator run chains four playbooks. On my run — Apple-Silicon Mac, amd64 EE under emulation, default instance sizes — the full stand-up took about 2.5 hours end to end. The long poles are parcel distribution and bringing 14 Kerberized services up, not the Terraform infra (which was ~10 min); native amd64 and larger nodes would cut this down.
Stage Playbook What happens
| 1 | infrastructure.yml | Terraform: VPC, security groups, 11 EC2 nodes, generated SSH key |
| 2 | services.yml | FreeIPA (DNS + Kerberos), PostgreSQL, Caddy/TLS, Node Exporter, Prometheus/Grafana |
| 3 | cms.yml | Cloudera Manager install + license, CM agents, AutoTLS, CM Kerberos |
| 4 | ozone-cluster.yml | CM builds the cluster: distribute/activate parcels, assign roles, start services |
Every stage ended failed=0. The final recap across all 11 hosts:
PLAY RECAP
steven-ce-base-master-01.cldr.internal : ok=197 changed=75 unreachable=0 failed=0
steven-ce-base-master-02.cldr.internal : ok=197 changed=75 unreachable=0 failed=0
steven-ce-base-master-03.cldr.internal : ok=197 changed=75 unreachable=0 failed=0
steven-ce-base-worker-01.cldr.internal : ok=197 changed=75 unreachable=0 failed=0
... workers 02–04 identical ...
steven-ce-gateway-01.cldr.internal : ok=93 changed=55 unreachable=0 failed=0
steven-ce-manager-01.cldr.internal : ok=182 changed=79 unreachable=0 failed=0
steven-ce-sdx-01.cldr.internal : ok=196 changed=75 unreachable=0 failed=0
steven-ce-services-01.cldr.internal : ok=205 changed=121 unreachable=0 failed=0One thing worth knowing: right after the Ozone stage completes, the CM cluster can briefly show BAD_HEALTH while ZooKeeper’s startup canary settles — it flips to GOOD on its own within a couple minutes. Don’t panic-restart it.
A GOOD_HEALTH ozone-base-cluster on Cloudera Runtime 7.3.2, reachable through the Caddy reverse proxy on the single public node (the gateway) via a nip.io hostname:
The cluster bills ~$2/hr while it runs, so know the exits up front. All three are the same one-command shape:
# Pause — stop the EC2 instances, keep the EBS volumes + cluster state (cheapest way to keep it around)
ansible-navigator run playbooks/pause.yml -e @config.yml -m stdout
# Resume — start the instances back up
ansible-navigator run playbooks/resume.yml -e @config.yml -m stdout
# Tear down — Terraform destroys everything: instances, volumes, VPC
ansible-navigator run playbooks/infrastructure-teardown.yml -e @config.yml -m stdoutTeardown is a terraform destroy under the hood and finishes in a few minutes with a clean recap:
PLAY RECAP
localhost : ok=3 changed=1 unreachable=0 failed=0Then confirm nothing is left billing before you walk away — Terraform state should be empty and AWS should report zero instances:
aws ec2 describe-instances --profile <your-profile> --region us-east-2 \
--filters "Name=tag:deployment,Values=<name_prefix>" \
"Name=instance-state-name,Values=running,pending,stopping,stopped" \
--query 'length(Reservations[].Instances[])' --output text
# -> 0
If you would like a deeper dive, hands on experience, demos, or are interested in speaking with me further about Cloudera Community Edition on AWS in One Command please reach out to schedule a discussion.