ClickHouse at HungryHub is deployed using ClickStack Helm Chart (v3.0.1) inside an EKS cluster. This stack includes ClickHouse Server, ClickHouse Keeper (ZooKeeper replacement), and HyperDX (observability dashboard).
Main file: hungryhub-terraform/helm-releases/clickhouse.tf
┌─────────────────────────────────────────────────────────────┐
│ EKS Cluster │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌───────────────────┐ │
│ │ ClickHouse │ │ ClickHouse │ │ HyperDX │ │
│ │ Server │ │ Keeper │ │ (UI Dashboard) │ │
│ │ (port 8123 │ │ (port 9000 │ │ (port 3000) │ │
│ │ native:9000)│ │ internal) │ │ │ │
│ └──────┬───────┘ └──────────────┘ └───────────────────┘ │
│ │ │
│ ┌──────┴───────────────────────────────────┐ │
│ │ Kubernetes Services │ │
│ │ clickhouse (ClusterIP) │ │
│ │ clickhouse-headless (ClusterIP=None) │ │
│ └──────────────────────────────────────────┘ │
│ │ │
│ ┌──────┴───────────────────────────────────┐ │
│ │ NetworkPolicy (restricted ingress) │ │
│ │ - clickstack pods │ │
│ │ - hyperdx pods │ │
│ │ - additional workloads via variable │ │
│ └──────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
┌─────────┴─────────┐
│ │
┌─────▼─────┐ ┌──────▼──────┐
│ ALB │ │ Cloudflare │
│ (dev only)│ │ (prod) │
│ HTTPS:8123 │ │ Tunnel │
└────────────┘ └─────────────┘
Parameter Dev Prod
Replicas 1 (configurable) 3
Shards 1 (configurable) 2
Storage Class gp3 gp3
Storage Size 100Gi (configurable) 200Gi
CPU 2000m 2000m
Memory 6Gi 6Gi
ClickHouse Version 24.12.6-alpine 24.12.6-alpine
Chart Version 3.0.1 3.0.1
Resource Name Purpose
Namespace clickhouseClickHouse workload isolation
Secret clickhouse-credentialsAdmin credentials (username: admin)
Secret clickhouse-default-passwordDefault user password (SHA256)
Service clickhouseClusterIP — HTTP (8123) + Native (9000)
Service clickhouse-headlessHeadless — replica discovery
NetworkPolicy clickhouse-restricted-ingressRestrict access to approved workloads
Resource Purpose
Security Group clickhouse-alb Restrict inbound to VPN CIDRs
ALB Ingress HTTPS termination at ALB, port 8123
ALB Access Logs Logs to S3 bucket alb_logs_s3_bucket
ClickHouse credentials are managed through AWS Secrets Manager + Kubernetes Secrets :
AWS Secrets Manager (/hungryhub/{env})
├── CLICKSTACK_MONGO_URI_{DEV|PROD} → HyperDX MongoDB Atlas
└── SENDGRID_API_KEY → HyperDX SMTP
Random Generation (Terraform)
├── clickhouse_password (admin) → K8s Secret: clickhouse-credentials
└── clickhouse_default_password → K8s Secret: clickhouse-default-password
Admin password: Auto-generated (32 chars, special). Rotated when namespace or storage_class changes.
Default password: Auto-generated (32 chars, special). Overridden via var.clickhouse_default_password from CI pipeline.
Both passwords are not stored in Terraform state or git in plaintext.
Only the following pods may access ClickHouse:
clickstack-clickhouse-clickhouse pods (namespace: clickhouse)
hyperdx pods (namespace: clickhouse)
Additional workloads via var.clickhouse_allowed_ingress_workloads
Host: clickhouse.hhstaging.dev
TLS: ACM cert (*.hhstaging.dev) from route53 remote state
Security Group: Inbound only from clickhouse_ingress_allowed_cidrs (default: WireGuard VPN)
Access Logs: S3 bucket from s3 remote state
Prod uses Cloudflare Tunnel + Zero Trust , not ALB.
# helm-releases/provider.tf
terraform_remote_state:
vpc:
key: vpc/vpc-state.tfstate
outputs: vpc_id, private_subnets, private_subnets_cidr, db_subnets_cidr, eks_cluster_name
eks:
key: eks/eks-state.tfstate
outputs: eks_cluster_id
route53:
key: route53/route53-state.tfstate
outputs: cloudflare_acm (ACM cert ARN)
s3:
key: s3/s3-state.tfstate
outputs: alb_logs_s3_bucket
File: helm-releases/values/clickhouse.yaml.tft
Section Config
clickhouse.cluster.specreplicas, shards, image tag, resources, storage
clickhouse.cluster.spec.settings.defaultUserPassword.secretK8s Secret ref for default user
clickhouse.cluster.spec.settings.extraUsersConfigdefault user grants: GRANT ALL ON *.* WITH GRANT OPTION
clickhouse.keeper.specKeeper replicas + storage
clickhouse.prometheusPort 9363
mongodb.enabledfalse — using MongoDB Atlas
hyperdx.enabledtrue — UI dashboard
hyperdx.configFRONTEND_URL, MONGO_URI, SMTP settings
otel-collector.enabledfalse
File: helm-releases/clickhouse-monitoring.tf
Scrapes ClickHouse native Prometheus endpoint (port 9363)
Interval: 15s, timeout: 10s
Target: clickstack-clickhouse-clickhouse-headless Service
Alert Condition Severity
ClickHouseMemoryUsage container_memory_working_set_bytes > 800MB for 5mwarning
ClickHouseMemoryCritical container_memory_working_set_bytes > 950MB for 1mcritical
ClickHouseUnreachable up == 0 for 1mcritical
clickhouse_http_endpoint = "http://clickstack-clickhouse.clickhouse.svc.cluster.local:8123"
clickhouse_native_endpoint = "clickstack-clickhouse.clickhouse.svc.cluster.local:9000"
hyperdx_ui_endpoint = "http://clickstack-hyperdx.clickhouse.svc.cluster.local:3000"
clickhouse_alb_dns_name = "" # (dev only, populated after ALB provisioned)
clickhouse_alb_zone_id = "" # (dev only)
clickhouse_alb_security_group_id = "" # (dev only)
Variable Default Description
namespaceclickhouseK8s namespace
clickhouse_chart_version3.0.1ClickStack chart version
clickhouse_version24.12.6-alpineClickHouse image tag
clickhouse_replicas1Replicas (dev)
clickhouse_shards1Shards (dev)
clickhouse_cpu2000mCPU request
clickhouse_memory6GiMemory request
clickhouse_storage_size100GiPV size (dev)
clickhouse_storage_classgp3StorageClass
clickhouse_password""Admin password override
clickhouse_default_password""Default user password override
clickhouse_ingress_enabledtrueEnable ALB ingress
clickhouse_ingress_hostclickhouse.hhstaging.devIngress hostname
clickhouse_ingress_allowed_cidrs["5.223.47.105/32"]Allowed CIDRs
DMS is used for two pipelines:
MySQL → Aurora MySQL (CDC replication)
MySQL → S3 Parquet (dev only — data pipeline)
Main file: hungryhub-terraform/dms/main.tf, dms_s3_pipeline.tf
┌──────────────────────────────────────────────────────┐
│ DMS Pipeline │
│ │
│ ┌──────────┐ ┌──────────────┐ ┌──────────┐ │
│ │ MySQL │────▶│ Replication │────▶│ Target │ │
│ │ Source │ │ Instance │ │ │ │
│ │ (RDS) │ │ dms.t3.large│ │ │ │
│ └──────────┘ └──────────────┘ └──────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌──────────────┐│
│ │ │ Aurora MySQL ││
│ │ │ (prod target) ││
│ │ └──────────────┘│
│ │ │
│ │ ┌──────────────┐ │
│ └─────────────▶│ S3 Bucket │ (dev only) │
│ │ dms-target │ │
│ │ (Parquet) │ │
│ └──────────────┘ │
└──────────────────────────────────────────────────────┘
Parameter Value
Class dms.t3.large
Engine 3.5.4
AZ ap-southeast-1c
Multi-AZ false
Storage 50 GB
Public Access true
Maintenance sun:10:30-sun:14:30
Parameter Value
Engine MySQL
Host hh-production-db-master.cgfqflgzmmxy.ap-southeast-1.rds.amazonaws.com
Port 3306
Database booking_production
SSL none
Username root (via variable)
Parameter Value
Engine Aurora
Host data.terraform_remote_state.rds.outputs.mysql_rds_cluster_endpoint
Port 3306
Database booking_production
SSL none
Task Schema Migration Type
{env}-dms-replication-taskbooking_production.%full-load-and-cdc
{env}-dms-replication-task-menuhh_menu_production.%full-load-and-cdc
start_replication_task = false (manual start)
Task settings: task_settings.json
Categories: failure, state change, deletion, configuration change, creation
SNS Topic: {env}-hungryhub-dms
Gated: var.environment == "dev"
Parameter Value
Engine MySQL
Host hungryhub-dev-mysql-proxy.proxy-c2i8lks3rhzq.ap-southeast-1.rds.amazonaws.com
Port 3306
Database booking_production
Parameter Value
Engine S3
Bucket dms-target-hungryhub-dev-s3
Folder bronze/
Format Parquet (v2.0)
Encoding RLE Dictionary
Encryption SSE-S3
Timestamp Column dms_timestamp
Row group length: 10,000
Data page size: 1 MB
Dict page size limit: 1 MB
Max file size: 1 MB
CDC batch interval: 180s
CDC min file size: 32 KB
104 selection rules
4 column-type transformations (date → string(50)):
vouchers.expiry_date
updated_inventories.start_date
updated_inventories.end_date
reservations.date
File: table_mappings_s3_pipeline.json
Bucket: dms-target-hungryhub-{env}-s3
Config Value
Versioning Enabled
Public Access Blocked (all 4)
Lifecycle (bronze/) 30d → STANDARD_IA, 90d → GLACIER, 365d → expire
Non-current 30d → STANDARD_IA, 90d → expire
Role Purpose
dms-access-{env}-endpointDMS service assume role
dms-cloudwatch-{env}-logs-roleCloudWatch Logs for DMS
dms-vpc-{env}-roleVPC management for DMS
dms-s3-{env}-roleS3 access for DMS pipeline
{
"s3:PutObject", "s3:GetObject", "s3:DeleteObject",
"s3:AbortMultipartUpload", "s3:ListMultipartUploadParts",
"s3:ListBucketMultipartUploads", "s3:PutObjectTagging"
}
# Resource: dms-target bucket/*
Inbound: MySQL 3306 from private + db subnets
Egress: All (0.0.0.0/0)
Inbound: HTTPS 8123 from clickhouse_ingress_allowed_cidrs
Egress: All (0.0.0.0/0)
Host: hh-production-db-master.cgfqflgzmmxy.ap-southeast-1.rds.amazonaws.com
Port: 3306
Engine: MySQL
Host: hungryhub-dev-mysql-proxy.proxy-c2i8lks3rhzq.ap-southeast-1.rds.amazonaws.com
Port: 3306
Engine: MySQL
Endpoint: data.terraform_remote_state.rds.outputs.mysql_rds_cluster_endpoint
User: data.terraform_remote_state.rds.outputs.mysql_rds_user_name
Password: data.terraform_remote_state.rds.outputs.mysql_rds_password
dms_security_group_id # ID of DMS security group
dms_s3_target_bucket_name # dms-target-hungryhub-{env}-s3
dms_s3_pipeline_replication_instance_arn # Replication instance ARN
dms_mysql_to_s3_task_arn # MySQL→S3 task ARN (dev only)
┌─────────────┐
│ ClickHouse │
│ (EKS) │
└──────┬──────┘
│
┌────────────┼────────────┐
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ MongoDB │ │ HyperDX │ │ Metrics │
│ Atlas │ │ (UI) │ │Prometheus│
└──────────┘ └──────────┘ └──────────┘
┌─────────────┐
│ DMS │
└──────┬──────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ MySQL │ │ Aurora │ │ S3 │
│ Source │ │ Target │ │ (Parquet)│
│ (RDS) │ │ (RDS) │ │ │
└──────────┘ └──────────┘ └──────────┘
Notes:
ClickHouse and DMS are not directly connected. They are separate infrastructure.
ClickHouse receives data from APM agents (OpenTelemetry) and queries from HyperDX/BI tools.
DMS moves data MySQL → Aurora (CDC) and MySQL → S3 (analytics pipeline).
DMS S3 bucket can be used as a data source for ClickHouse (via S3 table function or materialized view), but no direct connection is defined in Terraform currently.