Zurück zur Startseite

ClickHouse in Docker: Analysen in 2 Minuten starten

Leitfaden zum Ausführen von ClickHouse in Docker mit vier fertigen Szenarien: einfaches docker run, docker-compose für Entwicklung mit Healthcheck, Cluster mit ZooKeeper für Replikation, vollständiger ClickHouse + Kafka + Redis Stack für Gaming-Analysen. Umgebungsvariablen, Einbindung benutzerdefinierter Konfigurationen, typische Fehler und deren Lösungen werden erklärt.

ClickHouse in Docker: 4 fertige Szenarien mit Compose-Dateien
Advertisement 728x90

ClickHouse in Docker: Wie ich aufhörte, mir Sorgen zu machen und Analysen in 2 Minuten startete

Warum Docker – und alles andere kommt danach

Ich erinnere mich an das erste Mal, als ich ClickHouse in der Produktion eingerichtet habe. Es dauerte vier Stunden, um Berechtigungen, Limits und Konfigurationen manuell zu bearbeiten und systemd neu zu starten. Einen Monat später kam ein neuer Entwickler dazu, und wir versuchten, die Umgebung auf seinem Rechner zu replizieren – die gleichen alten Fallstricke.

Docker hat alles gelöst. Jetzt habe ich einen einzigen Ordner mit docker-compose.yml, den ich zwischen Projekten mitnehme. Ich starte einen Analyse-Cluster in einer Minute, und wenn ich ihn abbauen muss – docker-compose down -v und alles ist sauber. Kein Systemmüll.

Im Folgenden finden Sie drei fertige Szenarien, die ich in echten Projekten verwende (von einem Startup-Seitenprojekt bis hin zu Wettanalysen). Alle Konfigurationen sind mit Docker Engine 24+ getestet.

Google AdInline article slot

Szenario 1. Schnellstart: Ein Befehl, um eine Hypothese zu testen

Für die lokale Entwicklung und schnelles Prototyping reicht eine einzige Zeile. Aber nicht nur docker run clickhouse/clickhouse-server – fügen wir hinzu, was ClickHouse nützlich macht: persistenten Speicher und Portzuordnung.

docker run -d \
  --name clickhouse-dev \
  --restart unless-stopped \
  -p 8123:8123 \
  -p 9000:9000 \
  -v clickhouse-data:/var/lib/clickhouse \
  -v clickhouse-logs:/var/log/clickhouse-server \
  -e CLICKHOUSE_DB=analytics \
  -e CLICKHOUSE_USER=developer \
  -e CLICKHOUSE_PASSWORD=devpass123 \
  -e CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT=1 \
  clickhouse/clickhouse-server:latest

Was hier wichtig ist:

  • -v clickhouse-data – ein benanntes Volume, kein Bind Mount. Der Unterschied: Volumes werden von Docker verwaltet, gehen beim Neustart nicht verloren und sind unter macOS leistungsfähiger (wichtig, wenn Sie auf einem MacBook arbeiten – Bind Mounts sind aufgrund der Synchronisation langsam).
  • CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT=1 – aktiviert die Zugriffskontrolle. Ohne diese Variable wird der Benutzer developer erstellt, kann aber keine neuen Konten anlegen. Das haben wir auf die harte Tour gelernt: In der Produktion mussten wir in den Container gehen und users.xml bearbeiten.
  • Ports 9000 (natives Protokoll) und 8123 (HTTP) – ich öffne immer beide, weil die Hälfte der Clients (DBeaver, TablePlus) über HTTP arbeiten, während Anwendungen den nativen Treiber verwenden.

Überprüfen, ob es läuft:

Google AdInline article slot
# HTTP-Schnittstelle – der einfachste Test
curl "http://localhost:8123/?query=SELECT+version()"
# Ausgabe: 24.8.2.3

Szenario 2. Docker Compose für die Entwicklung (Einzelknoten, Healthcheck)

Wenn das Projekt etwas komplexer wird, wechsle ich sofort zu docker-compose.yml. Diese Datei verwende ich auf meinen Laptops und Entwicklungsservern:

version: '3.8'

services:
  clickhouse:
    image: clickhouse/clickhouse-server:latest
    container_name: clickhouse-dev
    hostname: clickhouse
    ports:
      - "8123:8123"
      - "9000:9000"
      - "9009:9009"
    volumes:
      - clickhouse-data:/var/lib/clickhouse
      - clickhouse-logs:/var/log/clickhouse-server
      - ./config/config.d:/etc/clickhouse-server/config.d
      - ./config/users.d:/etc/clickhouse-server/users.d
    environment:
      CLICKHOUSE_DB: betting_analytics
      CLICKHOUSE_USER: analyst
      CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD:-analyst123}
      CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1
    ulimits:
      nofile:
        soft: 262144
        hard: 262144
      nproc:
        soft: 32768
        hard: 32768
    healthcheck:
      test: ["CMD", "wget", "--spider", "-q", "http://localhost:8123/ping"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    restart: unless-stopped
    networks:
      - analytics-net

networks:
  analytics-net:
    driver: bridge

volumes:
  clickhouse-data:
  clickhouse-logs:

Warum ich ulimits hinzugefügt habe: In der Produktion verbraucht ClickHouse bis zu 262144 offene Dateideskriptoren. Ohne dies stürzt es unter hoher Last mit Too many open files ab. Ich habe einmal drei Stunden damit verschwendet, als der Server nach 2 Millionen Zeilen ausfiel.

Healthcheck über /ping: ClickHouse hat einen integrierten /ping-Endpunkt (gibt "Ok." zurück, wenn es läuft). Das ist besser als die Überprüfung über SELECT 1, da es keine Authentifizierung erfordert und keine Logs schreibt.

Google AdInline article slot

Standardvariable: ${CLICKHOUSE_PASSWORD:-analyst123} – wenn nicht in .env gesetzt, lautet das Passwort analyst123. Vergessen Sie nicht die .env-Datei für echte Geheimnisse.

Szenario 3. Produktionsähnliches Setup: ClickHouse + Zookeeper für Replikation

Die Tabellenreplikation von ClickHouse erfordert ZooKeeper (oder ClickHouse Keeper, aber ich beginne mit dem Klassiker). Ich verwende dieses Compose zum Testen der Ausfallsicherheit:

version: '3.8'

services:
  zookeeper:
    image: confluentinc/cp-zookeeper:latest
    container_name: zookeeper
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000
    ports:
      - "2181:2181"
    volumes:
      - zookeeper-data:/var/lib/zookeeper
    networks:
      - ch-cluster

  clickhouse-1:
    image: clickhouse/clickhouse-server:latest
    container_name: clickhouse-1
    hostname: clickhouse-1
    ports:
      - "8123:8123"
      - "9000:9000"
    volumes:
      - ch1-data:/var/lib/clickhouse
      - ./config/replicated.xml:/etc/clickhouse-server/config.d/replicated.xml
    environment:
      CLICKHOUSE_DB: bets
      CLICKHOUSE_USER: replicator
      CLICKHOUSE_PASSWORD: rep_pass
      CLICKHOUSE_SHARD: 1
      CLICKHOUSE_REPLICA: 1
    depends_on:
      - zookeeper
    ulimits:
      nofile:
        soft: 262144
        hard: 262144
    networks:
      - ch-cluster

  clickhouse-2:
    image: clickhouse/clickhouse-server:latest
    container_name: clickhouse-2
    hostname: clickhouse-2
    ports:
      - "8124:8123"  # zweite Instanz auf einem anderen Port
      - "9001:9000"
    volumes:
      - ch2-data:/var/lib/clickhouse
      - ./config/replicated.xml:/etc/clickhouse-server/config.d/replicated.xml
    environment:
      CLICKHOUSE_DB: bets
      CLICKHOUSE_USER: replicator
      CLICKHOUSE_PASSWORD: rep_pass
      CLICKHOUSE_SHARD: 1
      CLICKHOUSE_REPLICA: 2
    depends_on:
      - zookeeper
    ulimits:
      nofile:
        soft: 262144
        hard: 262144
    networks:
      - ch-cluster

networks:
  ch-cluster:
    driver: bridge

volumes:
  zookeeper-data:
  ch1-data:
  ch2-data:

Und hier der Inhalt von config/replicated.xml (in beide Container eingehängt):

<clickhouse>
    <zookeeper>
        <node>
            <host>zookeeper</host>
            <port>2181</port>
        </node>
    </zookeeper>
    <remote_servers>
        <replicated_cluster>
            <shard>
                <replica>
                    <host>clickhouse-1</host>
                    <port>9000</port>
                </replica>
                <replica>
                    <host>clickhouse-2</host>
                    <port>9000</port>
                </replica>
            </shard>
        </replicated_cluster>
    </remote_servers>
    <macros>
        <shard>1</shard>
        <replica>${CLICKHOUSE_REPLICA}</replica>
    </macros>
</clickhouse>

Wann dies wirklich nötig ist: In einem Produktions-Casino-Projekt haben wir Daten verloren, weil wir alles auf einem einzigen Knoten gehalten haben. Danach starte ich immer mindestens zwei replizierte Container zum Testen. Der Preisunterschied sind zwei Container statt einem, aber gut schlafen ist unbezahlbar.

Szenario 4. Vollständiges Glücksspiel-Setup: ClickHouse + Kafka + Redis

Für Echtzeit-Wettanalysen benötige ich Streaming (Kafka) und Caching (Redis). Ich verwende dieses Compose zum lokalen Debuggen der Pipeline:

version: '3.8'

services:
  zookeeper-kafka:
    image: confluentinc/cp-zookeeper:latest
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000
    ports:
      - "2181:2181"

  kafka:
    image: confluentinc/cp-kafka:latest
    depends_on:
      - zookeeper-kafka
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper-kafka:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
    ports:
      - "9092:9092"

  redis:
    image: redis:7-alpine
    container_name: redis-cache
    ports:
      - "6379:6379"
    command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD:-cachepass}
    volumes:
      - redis-data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s

  clickhouse:
    image: clickhouse/clickhouse-server:latest
    container_name: clickhouse-betting
    ports:
      - "8123:8123"
      - "9000:9000"
    volumes:
      - clickhouse-betting-data:/var/lib/clickhouse
      - ./clickhouse-kafka.xml:/etc/clickhouse-server/config.d/kafka.xml
    environment:
      CLICKHOUSE_DB: betting
      CLICKHOUSE_USER: streamer
      CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PW:-stream123}
      CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1
    ulimits:
      nofile:
        soft: 262144
        hard: 262144
    depends_on:
      - kafka
      - redis

  kafka-connector:
    image: clickhouse/clickhouse-kafka-connect:latest
    container_name: kafka-connector
    depends_on:
      - kafka
      - clickhouse
    environment:
      CONNECT_BOOTSTRAP_SERVERS: kafka:9092
      CONNECT_GROUP_ID: clickhouse-group
      CONNECT_CONFIG_STORAGE_TOPIC: connect-configs
      CONNECT_OFFSET_STORAGE_TOPIC: connect-offsets
      CONNECT_STATUS_STORAGE_TOPIC: connect-status
      CONNECT_KEY_CONVERTER: org.apache.kafka.connect.storage.StringConverter
      CONNECT_VALUE_CONVERTER: org.apache.kafka.connect.json.JsonConverter
    ports:
      - "8083:8083"

volumes:
  redis-data:
  clickhouse-betting-data:

So verwenden Sie dies im Anwendungscode:

# Beispiel in Python: Wette aus Redis lesen (Cache), in ClickHouse schreiben
import redis
from kafka import KafkaProducer
import json

r = redis.Redis(host='localhost', port=6379, password='cachepass', decode_responses=True)
producer = KafkaProducer(bootstrap_servers='localhost:9092', value_serializer=lambda v: json.dumps(v).encode())

# Duplikatsprüfung (Betrugserkennung)
bet_id = "bet_12345"
if r.setnx(bet_id, "processed"):
    bet_event = {"user_id": 101, "amount": 500, "odds": 2.1}
    producer.send('bets-stream', bet_event)
else:
    print(f"Doppelte Wette {bet_id} blockiert")

So hängen Sie Ihre eigene config.xml ein, ohne alles zu zerstören

Ein Fehler, den ich fünfmal gemacht habe: Eine vollständige config.xml einzuhängen, nur um festzustellen, dass eine neue ClickHouse-Version obligatorische Abschnitte hinzugefügt hat. Der Container stürzte mit Config has no <logger> ab.

Der richtige Ansatz: Nur Überschreibungen in config.d/ ablegen. Hier ist eine Struktur, die funktioniert:

docker-clickhouse/
├── docker-compose.yml
├── .env
├── config/
│   ├── config.d/
│   │   ├── memory.xml
│   │   ├── networks.xml
│   │   └── query-log.xml
│   └── users.d/
│       └── profiles.xml

Beispiel config/config.d/memory.xml:

<clickhouse>
    <max_server_memory_usage>0.75</max_server_memory_usage>
    <max_memory_usage_for_all_queries>0</max_memory_usage_for_all_queries>
    <background_pool_size>16</background_pool_size>
</clickhouse>

Beispiel config/users.d/profiles.xml:

<clickhouse>
    <profiles>
        <default>
            <max_memory_usage>10000000000</max_memory_usage>
            <timeout_before_checking_execution_speed>0</timeout_before_checking_execution_speed>
        </default>
        <analyst>
            <readonly>1</readonly>
            <max_execution_time>300</max_execution_time>
        </analyst>
    </profiles>
</clickhouse>

Arbeiten mit clickhouse-client in einem Container

In einen Container springen, um schnelle Abfragen durchzuführen, ist normal. Aber nicht über docker exec -it bash – machen Sie es direkt:

# Eine Abfrage ausführen
docker exec -it clickhouse-dev clickhouse-client --query "SELECT count() FROM system.tables"

# Interaktiver Modus
docker exec -it clickhouse-dev clickhouse-client

# Mit Passwort
docker exec -it clickhouse-dev clickhouse-client --password devpass123

Mein Lifehack: Fügen Sie einen Alias zu ~/.bashrc hinzu:

alias ch-cli='docker exec -it clickhouse-dev clickhouse-client'

Danach einfach ch-cli eingeben und arbeiten, als wäre es eine lokale Datenbank.

Umgebungsvariablen: Was wirklich funktioniert

Das offizielle Image unterstützt nicht alle Variablen, die in Foren versprochen werden. Hier sind die getesteten:

Variable Zweck Beispiel
CLICKHOUSE_DB Standard-Datenbankname analytics
CLICKHOUSE_USER Admin-Benutzer prod_user
CLICKHOUSE_PASSWORD Passwort strongpass
CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT RBAC aktivieren (1/0) 1

Was NICHT funktioniert: CLICKHOUSE_HTTP_PORT, CLICKHOUSE_TCP_PORT – der Entrypoint ignoriert sie. Ändern Sie Ports über ports: in Compose oder durch Einhängen einer Konfiguration.

Health Check: Meine vollständige Checkliste

Nach dem Starten eines Compose führe ich Folgendes aus:

# 1. HTTP-Ping (sollte "Ok." zurückgeben)
curl http://localhost:8123/ping

# 2. Version über HTTP
curl "http://localhost:8123/?query=SELECT+version()"

# 3. Testtabelle erstellen
docker exec -it clickhouse-dev clickhouse-client --query "CREATE TABLE test.t (id UInt64) ENGINE = MergeTree ORDER BY id"

# 4. Einfügen und auswählen
docker exec -it clickhouse-dev clickhouse-client --query "INSERT INTO test.t SELECT number FROM numbers(1000)"
docker exec -it clickhouse-dev clickhouse-client --query "SELECT count() FROM test.t"

# 5. HTTP mit Authentifizierung (falls Passwort gesetzt)
curl -u developer:devpass123 "http://localhost:8123/?query=SELECT+user()"

Was tun, wenn es nicht funktioniert – Häufige Docker-Fehler

Fehler: Code: 210. DB::NetException: Connection refused Lösung: Der Container wurde noch nicht gestartet. Fügen Sie depends_on und healthcheck hinzu oder verwenden Sie sleep 5 in Skripten.

Fehler: Cannot create directory /var/lib/clickhouse: Permission denied Lösung: Fügen Sie auf einem Host mit SELinux :Z zum Volume hinzu: -v ./data:/var/lib/clickhouse:Z. Oder verwenden Sie benannte Volumes.

Fehler: Max connections limit reached Lösung: In der Konfiguration erhöhen: <max_connections>4096</max_connections> und neu starten.

Container-Speicher frisst den Host auf Lösung: Über Docker begrenzen:

docker update --memory=4g --memory-swap=4g clickhouse-dev

Oder in Compose:

deploy:
  resources:
    limits:
      memory: 4G

Fazit: Wann Docker verwenden und wann nicht

Docker ist ideal für ClickHouse in Entwicklung, Staging und kleinen Produktionsumgebungen. Aber wenn Sie einen Cluster mit 10+ Knoten und 100 TB Daten haben – native Pakete ohne zusätzliche Schichten sind besser.

Nehmen Sie vorerst mein Glücksspiel-Setup-Compose, ändern Sie die Passwörter und beginnen Sie, Wetten in Echtzeit zu zählen.

Alle Konfigurationen stammen aus echten Projekten. Namen geändert, Fallstricke bleiben.


Vorherige:
Nächste: ClickHouse-Client: Wie ich mich mit der Konsole und der HTTP-API in einem Glücksspielprojekt anfreundete

— Editorial Team

Advertisement 728x90

Weiterlesen