Setup ClickHouse In Local Using Docker Desktop
ClickHouse is a high-performance column-oriented database management system designed for online analytical processing (OLAP) workloads. While a single ClickHouse instance is sufficient for learning SQL and basic administration, many real-world deployments use clusters consisting of multiple ClickHouse servers and ClickHouse Keeper nodes.
In this tutorial, we will set up a local ClickHouse cluster using Docker Desktop. The cluster will simulate a production-like environment with multiple shards, replicas, and a dedicated ClickHouse Keeper ensemble. Running the cluster locally allows developers and administrators to learn distributed ClickHouse concepts such as replication, sharding, distributed queries, fault tolerance, and Keeper-based coordination without requiring physical servers.
The setup described in this tutorial uses ClickHouse version 24.9.2.42 and runs entirely on a local machine using Docker Desktop.
Cluster Architecture
The cluster consists of six ClickHouse server nodes and three ClickHouse Keeper participants.
ClickHouse Server Nodes
- ch1
- ch2
- ch3
- ch4
- ch5
- ch6
Keeper Participants
- ch1 (embedded Keeper participant)
- ch2 (embedded Keeper participant)
- keeper3 (dedicated Keeper node)
Shard and Replica Layout
The cluster is organized into three shards.
Shard 1
- Replica 1: ch1
- Replica 2: ch4
Shard 2
- Replica 1: ch2
- Replica 2: ch5
Shard 3
- Replica 1: ch3
- Replica 2: ch6
This arrangement provides:
- Three independent shards
- Two replicas per shard
- High availability through replication
- Fault tolerance through ClickHouse Keeper quorum
Why Three Keeper Nodes?
ClickHouse Keeper uses the Raft consensus algorithm. A single Keeper node creates a single point of failure. If that node becomes unavailable, replication metadata becomes inaccessible. A three-node Keeper ensemble provides fault tolerance because quorum requires a majority of nodes.
For three Keeper participants:
- Quorum size = 2
- One node can fail without affecting cluster operation
- Two node failures result in quorum loss
This is the minimum recommended production-style Keeper topology.
clickhouse-lab/
│
├── docker-compose.yml
│
├── ch1/
│ ├── config.d/
│ │ ├── cluster.xml
│ │ ├── keeper.xml
│ │ ├── listen.xml
│ │ ├── macros.xml
│ │ └── zookeeper.xml
│ └── data/
│
├── ch2/
│ ├── config.d/
│ │ ├── cluster.xml
│ │ ├── keeper.xml
│ │ ├── listen.xml
│ │ ├── macros.xml
│ │ └── zookeeper.xml
│ └── data/
│
├── ch3/
│ ├── config.d/
│ │ ├── cluster.xml
│ │ ├── listen.xml
│ │ ├── macros.xml
│ │ └── zookeeper.xml
│ └── data/
│
├── ch4/
│ ├── config.d/
│ │ ├── cluster.xml
│ │ ├── listen.xml
│ │ ├── macros.xml
│ │ └── zookeeper.xml
│ └── data/
│
├── ch5/
│ ├── config.d/
│ │ ├── cluster.xml
│ │ ├── listen.xml
│ │ ├── macros.xml
│ │ └── zookeeper.xml
│ └── data/
│
├── ch6/
│ ├── config.d/
│ │ ├── cluster.xml
│ │ ├── listen.xml
│ │ ├── macros.xml
│ │ └── zookeeper.xml
│ └── data/
│
└── keeper3/
├── config.d/
└── data/
Source Code
services:
ch1:
image: clickhouse/clickhouse-server:24.9.2.42
container_name: ch1
hostname: ch1
ports:
- "8123:8123"
- "9000:9000"
- "9181:9181"
- "9234:9234"
volumes:
- ./ch1/data:/var/lib/clickhouse
- ./ch1/config.d:/etc/clickhouse-server/config.d
networks:
- clickhouse-net
ch2:
image: clickhouse/clickhouse-server:24.9.2.42
container_name: ch2
hostname: ch2
ports:
- "8124:8123"
- "9001:9000"
- "9182:9181"
- "9235:9234"
volumes:
- ./ch2/data:/var/lib/clickhouse
- ./ch2/config.d:/etc/clickhouse-server/config.d
networks:
- clickhouse-net
ch3:
image: clickhouse/clickhouse-server:24.9.2.42
container_name: ch3
hostname: ch3
ports:
- "8125:8123"
- "9002:9000"
volumes:
- ./ch3/data:/var/lib/clickhouse
- ./ch3/config.d:/etc/clickhouse-server/config.d
networks:
- clickhouse-net
ch4:
image: clickhouse/clickhouse-server:24.9.2.42
container_name: ch4
hostname: ch4
ports:
- "8126:8123"
- "9003:9000"
volumes:
- ./ch4/data:/var/lib/clickhouse
- ./ch4/config.d:/etc/clickhouse-server/config.d
networks:
- clickhouse-net
ch5:
image: clickhouse/clickhouse-server:24.9.2.42
container_name: ch5
hostname: ch5
ports:
- "8127:8123"
- "9004:9000"
volumes:
- ./ch5/data:/var/lib/clickhouse
- ./ch5/config.d:/etc/clickhouse-server/config.d
networks:
- clickhouse-net
ch6:
image: clickhouse/clickhouse-server:24.9.2.42
container_name: ch6
hostname: ch6
ports:
- "8128:8123"
- "9005:9000"
volumes:
- ./ch6/data:/var/lib/clickhouse
- ./ch6/config.d:/etc/clickhouse-server/config.d
networks:
- clickhouse-net
keeper3:
image: clickhouse/clickhouse-keeper:24.9.2.42
container_name: keeper3
hostname: keeper3
ports:
- "9183:9181"
- "9236:9234"
volumes:
- ./keeper3/data:/var/lib/clickhouse
- ./keeper3/config.d:/etc/clickhouse-keeper
networks:
- clickhouse-net
networks:
clickhouse-net:
driver: bridge
<clickhouse>
<remote_servers>
<company_cluster>
<!-- Shard 1 -->
<shard>
<replica>
<host>ch1</host>
<port>9000</port>
</replica>
<replica>
<host>ch4</host>
<port>9000</port>
</replica>
</shard>
<!-- Shard 2 -->
<shard>
<replica>
<host>ch2</host>
<port>9000</port>
</replica>
<replica>
<host>ch5</host>
<port>9000</port>
</replica>
</shard>
<!-- Shard 3 -->
<shard>
<replica>
<host>ch3</host>
<port>9000</port>
</replica>
<replica>
<host>ch6</host>
<port>9000</port>
</replica>
</shard>
</company_cluster>
</remote_servers>
</clickhouse>
<clickhouse>
<keeper_server>
<tcp_port>9181</tcp_port>
<listen_host>0.0.0.0</listen_host>
<server_id>1</server_id>
<log_storage_path>/var/lib/clickhouse/coordination/log</log_storage_path>
<snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>
<raft_configuration>
<server>
<id>1</id>
<hostname>ch1</hostname>
<port>9234</port>
</server>
<server>
<id>2</id>
<hostname>ch2</hostname>
<port>9234</port>
</server>
<server>
<id>3</id>
<hostname>keeper3</hostname>
<port>9234</port>
</server>
</raft_configuration>
</keeper_server>
</clickhouse>
<clickhouse>
<macros>
<shard>01</shard>
<replica>replica1</replica>
</macros>
</clickhouse>
<clickhouse>
<zookeeper>
<node>
<host>ch1</host>
<port>9181</port>
</node>
<node>
<host>ch2</host>
<port>9181</port>
</node>
<node>
<host>keeper3</host>
<port>9181</port>
</node>
</zookeeper>
</clickhouse>
<clickhouse>
<remote_servers>
<company_cluster>
<!-- Shard 1 -->
<shard>
<replica>
<host>ch1</host>
<port>9000</port>
</replica>
<replica>
<host>ch4</host>
<port>9000</port>
</replica>
</shard>
<!-- Shard 2 -->
<shard>
<replica>
<host>ch2</host>
<port>9000</port>
</replica>
<replica>
<host>ch5</host>
<port>9000</port>
</replica>
</shard>
<!-- Shard 3 -->
<shard>
<replica>
<host>ch3</host>
<port>9000</port>
</replica>
<replica>
<host>ch6</host>
<port>9000</port>
</replica>
</shard>
</company_cluster>
</remote_servers>
</clickhouse>
<clickhouse>
<keeper_server>
<tcp_port>9181</tcp_port>
<listen_host>0.0.0.0</listen_host>
<server_id>2</server_id>
<log_storage_path>/var/lib/clickhouse/coordination/log</log_storage_path>
<snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>
<raft_configuration>
<server>
<id>1</id>
<hostname>ch1</hostname>
<port>9234</port>
</server>
<server>
<id>2</id>
<hostname>ch2</hostname>
<port>9234</port>
</server>
<server>
<id>3</id>
<hostname>keeper3</hostname>
<port>9234</port>
</server>
</raft_configuration>
</keeper_server>
</clickhouse>
<clickhouse>
<macros>
<shard>02</shard>
<replica>replica1</replica>
</macros>
</clickhouse>
<clickhouse>
<zookeeper>
<node>
<host>ch1</host>
<port>9181</port>
</node>
<node>
<host>ch2</host>
<port>9181</port>
</node>
<node>
<host>keeper3</host>
<port>9181</port>
</node>
</zookeeper>
</clickhouse>
<clickhouse>
<remote_servers>
<company_cluster>
<!-- Shard 1 -->
<shard>
<replica>
<host>ch1</host>
<port>9000</port>
</replica>
<replica>
<host>ch4</host>
<port>9000</port>
</replica>
</shard>
<!-- Shard 2 -->
<shard>
<replica>
<host>ch2</host>
<port>9000</port>
</replica>
<replica>
<host>ch5</host>
<port>9000</port>
</replica>
</shard>
<!-- Shard 3 -->
<shard>
<replica>
<host>ch3</host>
<port>9000</port>
</replica>
<replica>
<host>ch6</host>
<port>9000</port>
</replica>
</shard>
</company_cluster>
</remote_servers>
</clickhouse>
<clickhouse>
<macros>
<shard>03</shard>
<replica>replica1</replica>
</macros>
</clickhouse>
<clickhouse>
<zookeeper>
<node>
<host>ch1</host>
<port>9181</port>
</node>
<node>
<host>ch2</host>
<port>9181</port>
</node>
<node>
<host>keeper3</host>
<port>9181</port>
</node>
</zookeeper>
</clickhouse>
<clickhouse>
<remote_servers>
<company_cluster>
<!-- Shard 1 -->
<shard>
<replica>
<host>ch1</host>
<port>9000</port>
</replica>
<replica>
<host>ch4</host>
<port>9000</port>
</replica>
</shard>
<!-- Shard 2 -->
<shard>
<replica>
<host>ch2</host>
<port>9000</port>
</replica>
<replica>
<host>ch5</host>
<port>9000</port>
</replica>
</shard>
<!-- Shard 3 -->
<shard>
<replica>
<host>ch3</host>
<port>9000</port>
</replica>
<replica>
<host>ch6</host>
<port>9000</port>
</replica>
</shard>
</company_cluster>
</remote_servers>
</clickhouse>
<clickhouse>
<macros>
<shard>01</shard>
<replica>replica2</replica>
</macros>
</clickhouse>
<clickhouse>
<zookeeper>
<node>
<host>ch1</host>
<port>9181</port>
</node>
<node>
<host>ch2</host>
<port>9181</port>
</node>
<node>
<host>keeper3</host>
<port>9181</port>
</node>
</zookeeper>
</clickhouse>
<clickhouse>
<remote_servers>
<company_cluster>
<!-- Shard 1 -->
<shard>
<replica>
<host>ch1</host>
<port>9000</port>
</replica>
<replica>
<host>ch4</host>
<port>9000</port>
</replica>
</shard>
<!-- Shard 2 -->
<shard>
<replica>
<host>ch2</host>
<port>9000</port>
</replica>
<replica>
<host>ch5</host>
<port>9000</port>
</replica>
</shard>
<!-- Shard 3 -->
<shard>
<replica>
<host>ch3</host>
<port>9000</port>
</replica>
<replica>
<host>ch6</host>
<port>9000</port>
</replica>
</shard>
</company_cluster>
</remote_servers>
</clickhouse>
<clickhouse>
<macros>
<shard>02</shard>
<replica>replica2</replica>
</macros>
</clickhouse>
<clickhouse>
<zookeeper>
<node>
<host>ch1</host>
<port>9181</port>
</node>
<node>
<host>ch2</host>
<port>9181</port>
</node>
<node>
<host>keeper3</host>
<port>9181</port>
</node>
</zookeeper>
</clickhouse>
<clickhouse>
<remote_servers>
<company_cluster>
<!-- Shard 1 -->
<shard>
<replica>
<host>ch1</host>
<port>9000</port>
</replica>
<replica>
<host>ch4</host>
<port>9000</port>
</replica>
</shard>
<!-- Shard 2 -->
<shard>
<replica>
<host>ch2</host>
<port>9000</port>
</replica>
<replica>
<host>ch5</host>
<port>9000</port>
</replica>
</shard>
<!-- Shard 3 -->
<shard>
<replica>
<host>ch3</host>
<port>9000</port>
</replica>
<replica>
<host>ch6</host>
<port>9000</port>
</replica>
</shard>
</company_cluster>
</remote_servers>
</clickhouse>
<clickhouse>
<macros>
<shard>03</shard>
<replica>replica2</replica>
</macros>
</clickhouse>
<clickhouse>
<zookeeper>
<node>
<host>ch1</host>
<port>9181</port>
</node>
<node>
<host>ch2</host>
<port>9181</port>
</node>
<node>
<host>keeper3</host>
<port>9181</port>
</node>
</zookeeper>
</clickhouse>
<clickhouse>
<keeper_server>
<tcp_port>9181</tcp_port>
<listen_host>0.0.0.0</listen_host>
<server_id>3</server_id>
<log_storage_path>/var/lib/clickhouse/coordination/log</log_storage_path>
<snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>
<raft_configuration>
<server>
<id>1</id>
<hostname>ch1</hostname>
<port>9234</port>
</server>
<server>
<id>2</id>
<hostname>ch2</hostname>
<port>9234</port>
</server>
<server>
<id>3</id>
<hostname>keeper3</hostname>
<port>9234</port>
</server>
</raft_configuration>
</keeper_server>
</clickhouse>
The code of listen.xml is same
<clickhouse>
<listen_host>0.0.0.0</listen_host>
</clickhouse>