Skip to content

feat(clickhouse): add gr-clickhouse EC2 module#57

Merged
BK1031 merged 3 commits into
mainfrom
bk1031/gr-clickhouse-ec2
Jun 5, 2026
Merged

feat(clickhouse): add gr-clickhouse EC2 module#57
BK1031 merged 3 commits into
mainfrom
bk1031/gr-clickhouse-ec2

Conversation

@BK1031

@BK1031 BK1031 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor
  • New `infra/modules/clickhouse-ec2` mirroring the postgres-ec2 / mqtt-ec2 shape: Graviton AL2023, EIP, separate gp3 EBS data volume on `prevent_destroy`, SG ingress on `:8123` (HTTP) + `:9000` (native) from the EKS node SG + admin CIDRs
  • `user-data` formats `/var/lib/clickhouse`, installs Docker, drops a `users.d` admin user (`sha256_hex`-hashed password, `access_management=1` so further users can be created via SQL) and removes the default no-password user, then runs `clickhouse/clickhouse-server:24.12` with `--ulimit nofile=262144` per the official docs requirement
  • Deploys as `gr-clickhouse` in prod on `t4g.xlarge` (16 GiB RAM, 4 vCPU) with a 200 GB data volume — columnar OLAP store for CAN telemetry + Epic Shelter ingest, complementing the transactional gr-postgres
  • Cloudflare A record `gr-clickhouse.gauchoracing.com` → EIP (gray-cloud, since CF free can't proxy TCP)
  • Outputs `clickhouse_admin_password` (sensitive) — read via `terraform output -raw clickhouse_admin_password` → k8s Secret / clickhouse-client config

Why a separate box (not co-locate on gr-postgres or in-cluster)

Postgres just OOM-killed on the t4g.medium under `NUM_WORKERS=4` write pressure. Telemetry is column-store-shaped (high write volume, scan-heavy queries, ~10× compression) — squeezing it onto Postgres always loses. ClickHouse handles the analytics; Postgres keeps users / vehicles / jobs / sessions.

Could also have run ClickHouse in-cluster, but: it's stateful with a big EBS-backed data dir, ulimit/host-network expectations, and 10s of GB of memory at maturity — same reasons we chose EC2 over k8s for Postgres apply here.

Test plan

  • `terraform fmt -check -recursive` on module + prod env
  • `terraform validate` on module + prod env
  • `terraform plan` against prod after merge — confirm only additions for module.clickhouse + cloudflare_dns_record.gr_clickhouse
  • `terraform apply` — instance reaches Running, EBS attached, container `clickhouse-server` up
  • `curl -u admin:$(terraform output -raw clickhouse_admin_password) http://gr-clickhouse.gauchoracing.com:8123/ping\` returns `Ok.`
  • `SELECT version()` via `clickhouse-client --host=gr-clickhouse.gauchoracing.com --user=admin --password=...` returns `24.12.x`
  • Anonymous / `default` user gets `AUTHENTICATION_FAILED` (default user was removed)

- New infra/modules/clickhouse-ec2 mirroring the postgres-ec2 shape:
  Graviton AL2023, EIP, separate gp3 EBS data volume on prevent_destroy,
  SG ingress on 8123 (HTTP) + 9000 (native) from EKS node SG + admin CIDRs
- user-data formats /var/lib/clickhouse, installs Docker, drops a
  users.d admin user (sha256_hex'd password, access_management=1) and
  removes the default no-password user, then runs
  clickhouse/clickhouse-server:24.12 with --ulimit nofile=262144 per
  the official docs requirement
- Deploys as gr-clickhouse in prod on t4g.xlarge (16 GiB RAM) with
  200 GB data volume; columnar OLAP store for CAN telemetry + Epic
  Shelter ingest, complementing the transactional gr-postgres
- Cloudflare A record gr-clickhouse.gauchoracing.com → EIP, gray-cloud
- Outputs clickhouse_admin_password (sensitive) for downstream Secret
  population
@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Terraform plan: prod

step result
fmt success
init success
validate success
plan success
plan output
module.origin_cert.tls_private_key.this: Refreshing state... [id=4c5b5e0a4a4f13723ba2aebe888a7cb50529fcc0]
module.mqtt.random_password.mqtt_tcm26: Refreshing state... [id=none]
module.mqtt.random_password.mqtt: Refreshing state... [id=none]
module.postgres.random_password.postgres: Refreshing state... [id=none]
data.cloudflare_zone.gauchoracing: Reading...
module.origin_cert.tls_cert_request.this: Refreshing state... [id=9398eb1d26e54eb59b18d476ced10810e80172e5]
module.origin_cert.cloudflare_origin_ca_certificate.this: Refreshing state... [id=307819530070461722629184968406649377122389744032]
module.eks.module.eks.module.kms.data.aws_partition.current[0]: Reading...
module.postgres.aws_ebs_volume.data: Refreshing state... [id=vol-0321a5c46c01340f2]
module.vpc.module.vpc.aws_vpc.this[0]: Refreshing state... [id=vpc-06e13a97395396a3b]
module.clickhouse.data.aws_ami.al2023_arm64: Reading...
module.eks.module.eks.data.aws_iam_policy_document.node_assume_role_policy[0]: Reading...
module.eks.module.eks.data.aws_iam_policy_document.assume_role_policy[0]: Reading...
module.eks.module.eks.aws_cloudwatch_log_group.this[0]: Refreshing state... [id=/aws/eks/gr-prod/cluster]
module.eks.module.eks.module.kms.data.aws_partition.current[0]: Read complete after 0s [id=aws]
module.eks.module.eks.data.aws_iam_policy_document.assume_role_policy[0]: Read complete after 0s [id=2830595799]
module.eks.module.eks.data.aws_iam_policy_document.node_assume_role_policy[0]: Read complete after 0s [id=3518401652]
module.eks.module.eks.module.kms.data.aws_caller_identity.current[0]: Reading...
module.postgres.data.aws_ami.al2023_arm64: Reading...
module.eks.module.eks.data.aws_caller_identity.current[0]: Reading...
module.mqtt.data.aws_ami.al2023_arm64: Reading...
module.eks.module.eks.module.kms.data.aws_caller_identity.current[0]: Read complete after 0s [id=211125506628]
module.eks.module.eks.data.aws_partition.current[0]: Reading...
module.eks.module.eks.data.aws_partition.current[0]: Read complete after 0s [id=aws]
module.eks.module.eks.aws_iam_role.this[0]: Refreshing state... [id=gr-prod-cluster-20260601094833481300000002]
module.eks.module.eks.aws_iam_role.eks_auto[0]: Refreshing state... [id=gr-prod-eks-auto-20260601094833482500000004]
data.cloudflare_zone.gauchoracing: Read complete after 0s [id=5ac5ae9c6086e4b55c5e1b21ca963d94]
module.eks.module.eks.data.aws_caller_identity.current[0]: Read complete after 0s [id=211125506628]
module.origin_cert.aws_acm_certificate.this: Refreshing state... [id=arn:aws:acm:us-west-2:211125506628:certificate/d10d5205-6d4b-4798-a152-293c69174660]
cloudflare_ruleset.ssl_overrides: Refreshing state... [id=5a5ed8237d6f48418c172979ffe5da81]
module.eks.module.eks.data.aws_iam_policy_document.custom[0]: Reading...
module.eks.module.eks.data.aws_iam_policy_document.custom[0]: Read complete after 0s [id=513122117]
module.eks.module.eks.data.aws_iam_session_context.current[0]: Reading...
module.eks.module.eks.aws_iam_policy.custom[0]: Refreshing state... [id=arn:aws:iam::211125506628:policy/gr-prod-cluster-20260601094833480900000001]
module.eks.module.eks.data.aws_iam_session_context.current[0]: Read complete after 1s [id=arn:aws:sts::211125506628:assumed-role/github-actions-terraform/GitHubActions]
module.postgres.data.aws_ami.al2023_arm64: Read complete after 1s [id=ami-0a2a049c945b84826]
module.clickhouse.data.aws_ami.al2023_arm64: Read complete after 1s [id=ami-0a2a049c945b84826]
module.mqtt.data.aws_ami.al2023_arm64: Read complete after 1s [id=ami-0a2a049c945b84826]
module.eks.module.eks.aws_iam_role_policy_attachment.this["AmazonEKSClusterPolicy"]: Refreshing state... [id=gr-prod-cluster-20260601094833481300000002/arn:aws:iam::aws:policy/AmazonEKSClusterPolicy]
module.eks.module.eks.aws_iam_role_policy_attachment.this["AmazonEKSBlockStoragePolicy"]: Refreshing state... [id=gr-prod-cluster-20260601094833481300000002/arn:aws:iam::aws:policy/AmazonEKSBlockStoragePolicy]
module.eks.module.eks.aws_iam_role_policy_attachment.this["AmazonEKSComputePolicy"]: Refreshing state... [id=gr-prod-cluster-20260601094833481300000002/arn:aws:iam::aws:policy/AmazonEKSComputePolicy]
module.eks.module.eks.aws_iam_role_policy_attachment.this["AmazonEKSNetworkingPolicy"]: Refreshing state... [id=gr-prod-cluster-20260601094833481300000002/arn:aws:iam::aws:policy/AmazonEKSNetworkingPolicy]
module.eks.module.eks.aws_iam_role_policy_attachment.this["AmazonEKSLoadBalancingPolicy"]: Refreshing state... [id=gr-prod-cluster-20260601094833481300000002/arn:aws:iam::aws:policy/AmazonEKSLoadBalancingPolicy]
module.eks.module.eks.module.kms.data.aws_iam_policy_document.this[0]: Reading...
module.eks.module.eks.module.kms.data.aws_iam_policy_document.this[0]: Read complete after 0s [id=922405470]
module.eks.module.eks.module.kms.aws_kms_key.this[0]: Refreshing state... [id=7768801a-b38a-4c26-8bc3-7bf6fe2aac86]
module.eks.module.eks.aws_iam_role_policy_attachment.custom[0]: Refreshing state... [id=gr-prod-cluster-20260601094833481300000002/arn:aws:iam::211125506628:policy/gr-prod-cluster-20260601094833480900000001]
module.eks.module.eks.aws_iam_role_policy_attachment.eks_auto["AmazonEC2ContainerRegistryPullOnly"]: Refreshing state... [id=gr-prod-eks-auto-20260601094833482500000004/arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPullOnly]
module.eks.module.eks.aws_iam_role_policy_attachment.eks_auto["AmazonEKSWorkerNodeMinimalPolicy"]: Refreshing state... [id=gr-prod-eks-auto-20260601094833482500000004/arn:aws:iam::aws:policy/AmazonEKSWorkerNodeMinimalPolicy]
module.vpc.module.vpc.aws_default_security_group.this[0]: Refreshing state... [id=sg-0a592b2169fd42df8]
module.vpc.module.vpc.aws_default_route_table.default[0]: Refreshing state... [id=rtb-08f817bde5f65eb92]
module.vpc.module.vpc.aws_default_network_acl.this[0]: Refreshing state... [id=acl-0fd92b5b8eb95b2f9]
module.vpc.module.vpc.aws_subnet.private[0]: Refreshing state... [id=subnet-09fbaccd0b3aaab85]
module.vpc.module.vpc.aws_internet_gateway.this[0]: Refreshing state... [id=igw-0ace83040de106603]
module.vpc.module.vpc.aws_subnet.private[2]: Refreshing state... [id=subnet-06540460bfd7d06a2]
module.vpc.module.vpc.aws_subnet.private[1]: Refreshing state... [id=subnet-022e58c410c24d794]
module.vpc.module.vpc.aws_route_table.public[0]: Refreshing state... [id=rtb-0815845194166b58b]
module.vpc.module.vpc.aws_route_table.private[0]: Refreshing state... [id=rtb-0c18db918f54ad033]
module.vpc.module.vpc.aws_subnet.public[0]: Refreshing state... [id=subnet-0264aaaa19faa70f5]
module.vpc.module.vpc.aws_subnet.public[1]: Refreshing state... [id=subnet-0182a0562244a6fac]
module.vpc.module.vpc.aws_subnet.public[2]: Refreshing state... [id=subnet-0a5a8299f6da9bc59]
module.mqtt.aws_security_group.this: Refreshing state... [id=sg-0f5a2dc492283dafe]
module.postgres.aws_security_group.this: Refreshing state... [id=sg-08a5b2e02e0540520]
module.eks.module.eks.aws_security_group.node[0]: Refreshing state... [id=sg-0b19db83dbe18cbf1]
module.eks.module.eks.aws_security_group.cluster[0]: Refreshing state... [id=sg-0cac44db03a686436]
module.eks.module.eks.module.kms.aws_kms_alias.this["cluster"]: Refreshing state... [id=alias/eks/gr-prod]
module.vpc.module.vpc.aws_eip.nat[0]: Refreshing state... [id=eipalloc-015b9b6ae09534761]
module.vpc.module.vpc.aws_route.public_internet_gateway[0]: Refreshing state... [id=r-rtb-0815845194166b58b1080289494]
module.eks.module.eks.aws_iam_policy.cluster_encryption[0]: Refreshing state... [id=arn:aws:iam::211125506628:policy/gr-prod-cluster-ClusterEncryption20260601094855072000000006]
module.vpc.module.vpc.aws_route_table_association.private[0]: Refreshing state... [id=rtbassoc-0c836864d0eccc7fc]
module.vpc.module.vpc.aws_route_table_association.private[1]: Refreshing state... [id=rtbassoc-07ea61af9805b07cb]
module.vpc.module.vpc.aws_route_table_association.private[2]: Refreshing state... [id=rtbassoc-0b736817e30c38444]
module.vpc.module.vpc.aws_route_table_association.public[2]: Refreshing state... [id=rtbassoc-01d455080d37c3108]
module.vpc.module.vpc.aws_route_table_association.public[0]: Refreshing state... [id=rtbassoc-09913d53f1ff40442]
module.vpc.module.vpc.aws_route_table_association.public[1]: Refreshing state... [id=rtbassoc-041ffe3137ec2ff7a]
module.postgres.aws_security_group_rule.ingress_cidr[0]: Refreshing state... [id=sgrule-3721507580]
module.mqtt.aws_security_group_rule.ingress_cidr[0]: Refreshing state... [id=sgrule-1294033340]
module.eks.module.eks.aws_security_group_rule.node["egress_all"]: Refreshing state... [id=sgrule-4004824215]
module.eks.module.eks.aws_security_group_rule.node["ingress_cluster_kubelet"]: Refreshing state... [id=sgrule-2079615841]
module.eks.module.eks.aws_security_group_rule.node["ingress_cluster_10251_webhook"]: Refreshing state... [id=sgrule-1337801498]
module.eks.module.eks.aws_security_group_rule.node["ingress_nodes_ephemeral"]: Refreshing state... [id=sgrule-504933240]
module.eks.module.eks.aws_security_group_rule.node["ingress_self_coredns_tcp"]: Refreshing state... [id=sgrule-1577514230]
module.eks.module.eks.aws_security_group_rule.node["ingress_cluster_4443_webhook"]: Refreshing state... [id=sgrule-118149494]
module.eks.module.eks.aws_security_group_rule.node["ingress_cluster_443"]: Refreshing state... [id=sgrule-500562133]
module.eks.module.eks.aws_security_group_rule.node["ingress_cluster_9443_webhook"]: Refreshing state... [id=sgrule-3115694346]
module.eks.module.eks.aws_security_group_rule.node["ingress_cluster_6443_webhook"]: Refreshing state... [id=sgrule-3460871904]
module.eks.module.eks.aws_security_group_rule.node["ingress_self_coredns_udp"]: Refreshing state... [id=sgrule-4200159001]
module.eks.module.eks.aws_security_group_rule.node["ingress_cluster_8443_webhook"]: Refreshing state... [id=sgrule-3709110977]
module.postgres.aws_instance.this: Refreshing state... [id=i-03ff02aaa4a8c8da3]
module.mqtt.aws_instance.this: Refreshing state... [id=i-0bf98528bc8e9dab0]
module.eks.module.eks.aws_security_group_rule.cluster["ingress_nodes_443"]: Refreshing state... [id=sgrule-535925259]
module.eks.module.eks.aws_iam_role_policy_attachment.cluster_encryption[0]: Refreshing state... [id=gr-prod-cluster-20260601094833481300000002/arn:aws:iam::211125506628:policy/gr-prod-cluster-ClusterEncryption20260601094855072000000006]
module.vpc.module.vpc.aws_nat_gateway.this[0]: Refreshing state... [id=nat-019992cce709b8681]
module.mqtt.aws_security_group_rule.ingress_sg["sg-0b19db83dbe18cbf1"]: Refreshing state... [id=sgrule-1062873908]
module.postgres.aws_security_group_rule.ingress_sg["sg-0b19db83dbe18cbf1"]: Refreshing state... [id=sgrule-1130224857]
module.vpc.module.vpc.aws_route.private_nat_gateway[0]: Refreshing state... [id=r-rtb-0c18db918f54ad0331080289494]
module.eks.module.eks.aws_eks_cluster.this[0]: Refreshing state... [id=gr-prod]
module.eks.module.eks.data.tls_certificate.this[0]: Reading...
module.eks.module.eks.aws_eks_access_entry.this["arn-aws-iam--211125506628-role-github-actions-terraform"]: Refreshing state... [id=gr-prod:arn:aws:iam::211125506628:role/github-actions-terraform]
module.eks.module.eks.aws_eks_access_entry.this["arn-aws-iam--211125506628-user-admin-cli"]: Refreshing state... [id=gr-prod:arn:aws:iam::211125506628:user/admin-cli]
module.eks.module.eks.time_sleep.this[0]: Refreshing state... [id=2026-06-01T10:46:10Z]
module.eks.module.eks.data.tls_certificate.this[0]: Read complete after 0s [id=f97f646c2cd14cc0db0f757f0fccc96abbbe2af5]
module.eks.module.eks.aws_iam_openid_connect_provider.oidc_provider[0]: Refreshing state... [id=arn:aws:iam::211125506628:oidc-provider/oidc.eks.us-west-2.amazonaws.com/id/21512EE80634956C7C9D0B9647C70224]
module.eks.module.eks.aws_eks_access_policy_association.this["arn-aws-iam--211125506628-user-admin-cli_admin"]: Refreshing state... [id=gr-prod#arn:aws:iam::211125506628:user/admin-cli#arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy]
module.eks.module.eks.aws_eks_access_policy_association.this["arn-aws-iam--211125506628-role-github-actions-terraform_admin"]: Refreshing state... [id=gr-prod#arn:aws:iam::211125506628:role/github-actions-terraform#arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy]
module.argocd.helm_release.argocd: Refreshing state... [id=argocd]
module.mqtt.aws_eip.this[0]: Refreshing state... [id=eipalloc-000796d397533c6d8]
cloudflare_dns_record.gr_mqtt: Refreshing state... [id=53badd7d1ab83280dc57c671ee486f90]
module.postgres.aws_volume_attachment.data: Refreshing state... [id=vai-2257873426]
module.postgres.aws_eip.this[0]: Refreshing state... [id=eipalloc-06d6c59b1e0a49482]
cloudflare_dns_record.gr_postgres: Refreshing state... [id=a69d68353c27a536e84d7448af48e3f0]

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # cloudflare_dns_record.gr_clickhouse will be created
  + resource "cloudflare_dns_record" "gr_clickhouse" {
      + content          = (known after apply)
      + created_on       = (known after apply)
      + id               = (known after apply)
      + meta             = (known after apply)
      + modified_on      = (known after apply)
      + name             = "gr-clickhouse"
      + proxiable        = (known after apply)
      + proxied          = false
      + settings         = (known after apply)
      + tags             = (known after apply)
      + tags_modified_on = (known after apply)
      + ttl              = 300
      + type             = "A"
      + zone_id          = "5ac5ae9c6086e4b55c5e1b21ca963d94"
    }

  # module.clickhouse.aws_ebs_volume.data will be created
  + resource "aws_ebs_volume" "data" {
      + arn               = (known after apply)
      + availability_zone = "us-west-2a"
      + create_time       = (known after apply)
      + encrypted         = true
      + final_snapshot    = false
      + id                = (known after apply)
      + iops              = (known after apply)
      + kms_key_id        = (known after apply)
      + region            = "us-west-2"
      + size              = 200
      + snapshot_id       = (known after apply)
      + tags              = {
          + "Name" = "gr-clickhouse-data"
        }
      + tags_all          = {
          + "Environment" = "prod"
          + "ManagedBy"   = "terraform"
          + "Name"        = "gr-clickhouse-data"
          + "Repo"        = "gaucho-racing/infrastructure"
        }
      + throughput        = (known after apply)
      + type              = "gp3"
    }

  # module.clickhouse.aws_eip.this[0] will be created
  + resource "aws_eip" "this" {
      + allocation_id        = (known after apply)
      + arn                  = (known after apply)
      + association_id       = (known after apply)
      + carrier_ip           = (known after apply)
      + customer_owned_ip    = (known after apply)
      + domain               = "vpc"
      + id                   = (known after apply)
      + instance             = (known after apply)
      + ipam_pool_id         = (known after apply)
      + network_border_group = (known after apply)
      + network_interface    = (known after apply)
      + private_dns          = (known after apply)
      + private_ip           = (known after apply)
      + ptr_record           = (known after apply)
      + public_dns           = (known after apply)
      + public_ip            = (known after apply)
      + public_ipv4_pool     = (known after apply)
      + region               = "us-west-2"
      + tags                 = {
          + "Name" = "gr-clickhouse"
        }
      + tags_all             = {
          + "Environment" = "prod"
          + "ManagedBy"   = "terraform"
          + "Name"        = "gr-clickhouse"
          + "Repo"        = "gaucho-racing/infrastructure"
        }
    }

  # module.clickhouse.aws_instance.this will be created
  + resource "aws_instance" "this" {
      + ami                                  = "ami-0a2a049c945b84826"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = true
      + availability_zone                    = "us-west-2a"
      + disable_api_stop                     = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + enable_primary_ipv6                  = (known after apply)
      + force_destroy                        = false
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + host_resource_group_arn              = (known after apply)
      + iam_instance_profile                 = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_lifecycle                   = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "r8g.xlarge"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = (known after apply)
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + placement_group_id                   = (known after apply)
      + placement_partition_number           = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + region                               = "us-west-2"
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + spot_instance_request_id             = (known after apply)
      + subnet_id                            = "subnet-0264aaaa19faa70f5"
      + tags                                 = {
          + "Name" = "gr-clickhouse"
          + "Role" = "clickhouse"
        }
      + tags_all                             = {
          + "Environment" = "prod"
          + "ManagedBy"   = "terraform"
          + "Name"        = "gr-clickhouse"
          + "Repo"        = "gaucho-racing/infrastructure"
          + "Role"        = "clickhouse"
        }
      + tenancy                              = (known after apply)
      + user_data                            = (sensitive value)
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_change          = false
      + vpc_security_group_ids               = (known after apply)

      + capacity_reservation_specification (known after apply)

      + cpu_options (known after apply)

      + ebs_block_device (known after apply)

      + enclave_options (known after apply)

      + ephemeral_block_device (known after apply)

      + instance_market_options (known after apply)

      + maintenance_options (known after apply)

      + metadata_options (known after apply)

      + network_interface (known after apply)

      + primary_network_interface (known after apply)

      + private_dns_name_options (known after apply)

      + root_block_device {
          + delete_on_termination = true
          + device_name           = (known after apply)
          + encrypted             = true
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + tags_all              = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = 20
          + volume_type           = "gp3"
        }

      + secondary_network_interface (known after apply)
    }

  # module.clickhouse.aws_security_group.this will be created
  + resource "aws_security_group" "this" {
      + arn                    = (known after apply)
      + description            = "ClickHouse for gr-clickhouse"
      + egress                 = [
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + from_port        = 0
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "-1"
              + security_groups  = []
              + self             = false
              + to_port          = 0
                # (1 unchanged attribute hidden)
            },
        ]
      + id                     = (known after apply)
      + ingress                = (known after apply)
      + name                   = "gr-clickhouse"
      + name_prefix            = (known after apply)
      + owner_id               = (known after apply)
      + region                 = "us-west-2"
      + revoke_rules_on_delete = false
      + tags                   = {
          + "Name" = "gr-clickhouse"
        }
      + tags_all               = {
          + "Environment" = "prod"
          + "ManagedBy"   = "terraform"
          + "Name"        = "gr-clickhouse"
          + "Repo"        = "gaucho-racing/infrastructure"
        }
      + vpc_id                 = "vpc-06e13a97395396a3b"
    }

  # module.clickhouse.aws_security_group_rule.ingress_cidr["8123"] will be created
  + resource "aws_security_group_rule" "ingress_cidr" {
      + cidr_blocks              = [
          + "0.0.0.0/0",
        ]
      + description              = "ClickHouse :8123 from admin CIDRs"
      + from_port                = 8123
      + id                       = (known after apply)
      + protocol                 = "tcp"
      + region                   = "us-west-2"
      + security_group_id        = (known after apply)
      + security_group_rule_id   = (known after apply)
      + self                     = false
      + source_security_group_id = (known after apply)
      + to_port                  = 8123
      + type                     = "ingress"
    }

  # module.clickhouse.aws_security_group_rule.ingress_cidr["9000"] will be created
  + resource "aws_security_group_rule" "ingress_cidr" {
      + cidr_blocks              = [
          + "0.0.0.0/0",
        ]
      + description              = "ClickHouse :9000 from admin CIDRs"
      + from_port                = 9000
      + id                       = (known after apply)
      + protocol                 = "tcp"
      + region                   = "us-west-2"
      + security_group_id        = (known after apply)
      + security_group_rule_id   = (known after apply)
      + self                     = false
      + source_security_group_id = (known after apply)
      + to_port                  = 9000
      + type                     = "ingress"
    }

  # module.clickhouse.aws_security_group_rule.ingress_sg["sg-0b19db83dbe18cbf1-8123"] will be created
  + resource "aws_security_group_rule" "ingress_sg" {
      + description              = "ClickHouse :8123 from sg-0b19db83dbe18cbf1"
      + from_port                = 8123
      + id                       = (known after apply)
      + protocol                 = "tcp"
      + region                   = "us-west-2"
      + security_group_id        = (known after apply)
      + security_group_rule_id   = (known after apply)
      + self                     = false
      + source_security_group_id = "sg-0b19db83dbe18cbf1"
      + to_port                  = 8123
      + type                     = "ingress"
    }

  # module.clickhouse.aws_security_group_rule.ingress_sg["sg-0b19db83dbe18cbf1-9000"] will be created
  + resource "aws_security_group_rule" "ingress_sg" {
      + description              = "ClickHouse :9000 from sg-0b19db83dbe18cbf1"
      + from_port                = 9000
      + id                       = (known after apply)
      + protocol                 = "tcp"
      + region                   = "us-west-2"
      + security_group_id        = (known after apply)
      + security_group_rule_id   = (known after apply)
      + self                     = false
      + source_security_group_id = "sg-0b19db83dbe18cbf1"
      + to_port                  = 9000
      + type                     = "ingress"
    }

  # module.clickhouse.aws_volume_attachment.data will be created
  + resource "aws_volume_attachment" "data" {
      + device_name = "/dev/sdf"
      + id          = (known after apply)
      + instance_id = (known after apply)
      + region      = "us-west-2"
      + volume_id   = (known after apply)
    }

  # module.clickhouse.random_password.admin will be created
  + resource "random_password" "admin" {
      + bcrypt_hash = (sensitive value)
      + id          = (known after apply)
      + length      = 32
      + lower       = true
      + min_lower   = 0
      + min_numeric = 0
      + min_special = 0
      + min_upper   = 0
      + number      = true
      + numeric     = true
      + result      = (sensitive value)
      + special     = false
      + upper       = true
    }

Plan: 11 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + clickhouse_admin_password = (sensitive value)
  + clickhouse_private_ip     = (known after apply)
  + clickhouse_public_ip      = (known after apply)

─────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't
guarantee to take exactly these actions if you run "terraform apply" now.

BK1031 added 2 commits June 4, 2026 22:48
Graviton4 RAM-optimized: 4 vCPU / 32 GiB (vs t4g.xlarge's 16 GiB) and
dedicated CPU instead of t-series credit-burstable. ClickHouse query
memory + mark cache get the bigger pool, and big aggregations don't
risk throttling. ~$55/mo more on-demand.
- instance_type: t4g.large → r8g.xlarge (Graviton4 RAM-optimized)
- clickhouse_version: 24.12 → 26.3-alpine

Module default == what prod actually runs. Future callers can still
opt back to smaller/cheaper by overriding.
@BK1031 BK1031 merged commit 7437c9a into main Jun 5, 2026
1 check passed
@BK1031 BK1031 deleted the bk1031/gr-clickhouse-ec2 branch June 5, 2026 06:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant