Featured image of post 快速安装 ClickHouse

快速安装 ClickHouse

概述我们使用 docker compose 来安装 ClickHouse但我们不是裸装 ClickHouse,

概述

我们使用 docker compose 来安装 ClickHouse

但我们不是裸装 ClickHouse,实际上我们安装的是 ClickStack。有点儿像 elastic-stack 与 elastic search 的关系 ,但并不完全一样。

ClickStack 是基于 ClickHouse 构建的完整观察性平台,集成了日志、指标、追踪和会话回放功能,提供统一的用户界面和查询能力。因此,ClickStack 是在 ClickHouse 的基础上,结合 HyperDX 提供的前端界面和 OpenTelemetry Collector 实现的完整解决方案。它不仅仅是一个数据库,而是一个集成的观察性平台。

安装步骤参考官方文档:https://clickhouse.com/docs/zh/use-cases/observability/clickstack/getting-started?loc=use-case-observability

安装

克隆 HyperDX 仓库

1git clone https://github.com/hyperdxio/hyperdx.git
2
3cd hyperdx
4
5# switch to the v2 branch
6git checkout v2

根据自身情况修改配置文件 .env

我将 HDX_IMAGE_REPO=docker.hyperdx.io 修改为 HDX_IMAGE_REPO=docker.io 不然镜像拉不下来

 1# Used by docker-compose.yml
 2HDX_IMAGE_REPO=docker.hyperdx.io
 3IMAGE_NAME=ghcr.io/hyperdxio/hyperdx
 4IMAGE_NAME_DOCKERHUB=hyperdx/hyperdx
 5LOCAL_IMAGE_NAME=ghcr.io/hyperdxio/hyperdx-local
 6LOCAL_IMAGE_NAME_DOCKERHUB=hyperdx/hyperdx-local
 7ALL_IN_ONE_IMAGE_NAME=ghcr.io/hyperdxio/hyperdx-all-in-one
 8ALL_IN_ONE_IMAGE_NAME_DOCKERHUB=hyperdx/hyperdx-all-in-one
 9OTEL_COLLECTOR_IMAGE_NAME=ghcr.io/hyperdxio/hyperdx-otel-collector
10OTEL_COLLECTOR_IMAGE_NAME_DOCKERHUB=hyperdx/hyperdx-otel-collector
11CODE_VERSION=2.0.5
12IMAGE_VERSION_SUB_TAG=.0.5
13IMAGE_VERSION=2
14IMAGE_NIGHTLY_TAG=2-nightly
15IMAGE_LATEST_TAG=latest
16
17# Set up domain URLs
18HYPERDX_API_PORT=8000 #optional (should not be taken by other services)
19HYPERDX_APP_PORT=8080
20HYPERDX_APP_URL=http://localhost
21HYPERDX_LOG_LEVEL=debug
22HYPERDX_OPAMP_PORT=4320
23
24# Otel/Clickhouse config
25HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE=default

docker compose 启动

1docker-compose up -d

Docker-compose 文件如下:

 1name: hdx-oss
 2services:
 3  # ONLY USED FOR DEMO SSL SETUP
 4  # nginx:
 5  #   image: nginx:1.27.3
 6  #   volumes:
 7  #     - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
 8  #     - ./docker/nginx/ssl:/etc/nginx/ssl
 9  #     - .volumes/nginx_logs:/var/log/nginx
10  #   ports:
11  #     - 80:80
12  #     - 443:443
13  #   networks:
14  #     - internal
15  #   depends_on:
16  #     - app
17  db:
18    image: mongo:5.0.14-focal
19    volumes:
20      - .volumes/db:/data/db
21    # WARNING: Exposing the database port will make it accessible from outside the container,
22    # potentially allowing unauthorized access. If you uncomment the ports below,
23    # ensure to secure your database (e.g., with strong authentication, proper network rules, and firewalls).
24    # ports:
25    #   - 27017:27017
26    networks:
27      - internal
28  otel-collector:
29    image: ${HDX_IMAGE_REPO}/${OTEL_COLLECTOR_IMAGE_NAME_DOCKERHUB}:${IMAGE_VERSION}
30    environment:
31      CLICKHOUSE_ENDPOINT: 'tcp://ch-server:9000?dial_timeout=10s'
32      HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE: ${HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE}
33      HYPERDX_LOG_LEVEL: ${HYPERDX_LOG_LEVEL}
34      OPAMP_SERVER_URL: 'http://app:${HYPERDX_OPAMP_PORT}'
35    ports:
36      - '13133:13133' # health_check extension
37      - '24225:24225' # fluentd receiver
38      - '4317:4317' # OTLP gRPC receiver
39      - '4318:4318' # OTLP http receiver
40      - '8888:8888' # metrics extension
41    restart: always
42    networks:
43      - internal
44    depends_on:
45      - ch-server
46  app:
47    image: ${HDX_IMAGE_REPO}/${IMAGE_NAME_DOCKERHUB}:${IMAGE_VERSION}
48    ports:
49      - ${HYPERDX_API_PORT}:${HYPERDX_API_PORT}
50      - ${HYPERDX_APP_PORT}:${HYPERDX_APP_PORT}
51    environment:
52      FRONTEND_URL: ${HYPERDX_APP_URL}:${HYPERDX_APP_PORT}
53      HYPERDX_API_KEY: ${HYPERDX_API_KEY}
54      HYPERDX_API_PORT: ${HYPERDX_API_PORT}
55      HYPERDX_APP_PORT: ${HYPERDX_APP_PORT}
56      HYPERDX_APP_URL: ${HYPERDX_APP_URL}
57      HYPERDX_LOG_LEVEL: ${HYPERDX_LOG_LEVEL}
58      MINER_API_URL: 'http://miner:5123'
59      MONGO_URI: 'mongodb://db:27017/hyperdx'
60      NEXT_PUBLIC_SERVER_URL: http://127.0.0.1:${HYPERDX_API_PORT}
61      OPAMP_PORT: ${HYPERDX_OPAMP_PORT}
62      OTEL_SERVICE_NAME: 'hdx-oss-api'
63      USAGE_STATS_ENABLED: ${USAGE_STATS_ENABLED:-true}
64      DEFAULT_CONNECTIONS:
65        '[{"name":"Local
66        ClickHouse","host":"http://ch-server:8123","username":"default","password":""}]'
67      DEFAULT_SOURCES:
68        '[{"from":{"databaseName":"default","tableName":"otel_logs"},"kind":"log","timestampValueExpression":"TimestampTime","name":"Logs","displayedTimestampValueExpression":"Timestamp","implicitColumnExpression":"Body","serviceNameExpression":"ServiceName","bodyExpression":"Body","eventAttributesExpression":"LogAttributes","resourceAttributesExpression":"ResourceAttributes","defaultTableSelectExpression":"Timestamp,ServiceName,SeverityText,Body","severityTextExpression":"SeverityText","traceIdExpression":"TraceId","spanIdExpression":"SpanId","connection":"Local
69        ClickHouse","traceSourceId":"Traces","sessionSourceId":"Sessions","metricSourceId":"Metrics"},{"from":{"databaseName":"default","tableName":"otel_traces"},"kind":"trace","timestampValueExpression":"Timestamp","name":"Traces","displayedTimestampValueExpression":"Timestamp","implicitColumnExpression":"SpanName","serviceNameExpression":"ServiceName","bodyExpression":"SpanName","eventAttributesExpression":"SpanAttributes","resourceAttributesExpression":"ResourceAttributes","defaultTableSelectExpression":"Timestamp,ServiceName,StatusCode,round(Duration/1e6),SpanName","traceIdExpression":"TraceId","spanIdExpression":"SpanId","durationExpression":"Duration","durationPrecision":9,"parentSpanIdExpression":"ParentSpanId","spanNameExpression":"SpanName","spanKindExpression":"SpanKind","statusCodeExpression":"StatusCode","statusMessageExpression":"StatusMessage","connection":"Local
70        ClickHouse","logSourceId":"Logs","sessionSourceId":"Sessions","metricSourceId":"Metrics"},{"from":{"databaseName":"default","tableName":""},"kind":"metric","timestampValueExpression":"TimeUnix","name":"Metrics","resourceAttributesExpression":"ResourceAttributes","metricTables":{"gauge":"otel_metrics_gauge","histogram":"otel_metrics_histogram","sum":"otel_metrics_sum","_id":"682586a8b1f81924e628e808","id":"682586a8b1f81924e628e808"},"connection":"Local
71        ClickHouse","logSourceId":"Logs","traceSourceId":"Traces","sessionSourceId":"Sessions"},{"from":{"databaseName":"default","tableName":"hyperdx_sessions"},"kind":"session","timestampValueExpression":"TimestampTime","name":"Sessions","displayedTimestampValueExpression":"Timestamp","implicitColumnExpression":"Body","serviceNameExpression":"ServiceName","bodyExpression":"Body","eventAttributesExpression":"LogAttributes","resourceAttributesExpression":"ResourceAttributes","defaultTableSelectExpression":"Timestamp,ServiceName,SeverityText,Body","severityTextExpression":"SeverityText","traceIdExpression":"TraceId","spanIdExpression":"SpanId","connection":"Local
72        ClickHouse","logSourceId":"Logs","traceSourceId":"Traces","metricSourceId":"Metrics"}]'
73    networks:
74      - internal
75    depends_on:
76      - ch-server
77      - db
78  ch-server:
79    image: clickhouse/clickhouse-server:24-alpine
80    # WARNING: Exposing the database port will make it accessible from outside the container,
81    # potentially allowing unauthorized access. If you uncomment the ports below,
82    # ensure to secure your database (e.g., with strong authentication, proper network rules, and firewalls).
83    ports:
84      - 8123:8123 # http api
85      - 9050:9000 # native
86    # environment:
87      # default settings
88      # CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1
89    volumes:
90      - ./docker/clickhouse/local/config.xml:/etc/clickhouse-server/config.xml
91      - ./docker/clickhouse/local/users.xml:/etc/clickhouse-server/users.xml
92      - ./empty.xml:/etc/clickhouse-server/users.d/default-password.xml
93      - .volumes/ch_data:/var/lib/clickhouse
94      - .volumes/ch_logs:/var/log/clickhouse-server
95    restart: on-failure
96    networks:
97      - internal
98networks:
99  internal:

注意:environment 部分我注释掉了,另外 加了一行:./empty.xml:/etc/clickhouse-server/users.d/default-password.xml 作用是解决 clickhouse 连接异常的问题。

通过 /data/clickhouse/hyperdx/docker/clickhouse/local/users.xml 可以看到 clickhouse 的账户信息:

 1<?xml version="1.0"?>
 2<clickhouse>
 3    <profiles>
 4        <default>
 5            <max_memory_usage>10000000000</max_memory_usage>
 6            <use_uncompressed_cache>0</use_uncompressed_cache>
 7            <load_balancing>in_order</load_balancing>
 8            <log_queries>1</log_queries>
 9        </default>
10    </profiles>
11
12    <users>
13        <default>
14            <password_sha256_hex>2d964690ad5ac2d2f78bebadc30895bc519969ffcef4d3c9e7ff04ee1c765d96</password_sha256_hex>
15            <profile>default</profile>
16            <networks>
17                <ip>::/0</ip>
18            </networks>
19            <quota>default</quota>
20        </default>
21        <api>
22            <password>api</password>
23            <profile>default</profile>
24            <networks>
25                <ip>::/0</ip>
26            </networks>
27            <quota>default</quota>
28        </api>
29        <worker>
30            <password>worker</password>
31            <profile>default</profile>
32            <networks>
33                <ip>::/0</ip>
34            </networks>
35            <quota>default</quota>
36        </worker>
37    </users>
38
39    <quotas>
40        <default>
41            <interval>
42                <duration>3600</duration>
43                <queries>0</queries>
44                <errors>0</errors>
45                <result_rows>0</result_rows>
46                <read_rows>0</read_rows>
47                <execution_time>0</execution_time>
48            </interval>
49        </default>
50    </quotas>
51</clickhouse>

密码用 sha256sum 处理过

可以这样生成:

1echo -n '你的密码' | sha256sum

运行

Image点击登录跳转至首页

Image

客户端连接

  • 用户名:default
  • 密码: 你的密码
  • 端口:8123

Image

数据库初始化

初始化 sql 脚本

 1/* 1. 创建数据库(如已存在可先 DROP DATABASE IF EXISTS testdb) */
 2CREATE DATABASE IF NOT EXISTS testdb;
 3
 4/* 2. 维度表:用户 */
 5CREATE TABLE IF NOT EXISTS testdb.users (
 6    user_id     UInt32,
 7    user_name   String,
 8    signup_date Date
 9) ENGINE = MergeTree
10ORDER BY user_id;
11
12/* 3. 维度表:页面 */
13CREATE TABLE IF NOT EXISTS testdb.pages (
14    page_id   UInt32,
15    page_url  String,
16    category  String
17) ENGINE = MergeTree
18ORDER BY page_id;
19
20/* 4. 事实表:页面访问日志 */
21CREATE TABLE IF NOT EXISTS testdb.pageviews (
22    event_date Date,
23    event_time DateTime,
24    user_id    UInt32,
25    page_id    UInt32,
26    duration   UInt32   -- 停留秒数
27) ENGINE = MergeTree
28PARTITION BY toYYYYMM(event_date)
29ORDER BY (event_date, user_id, page_id);
30
31/* 5. 物化视图:每日 PV / UV 聚合 */
32CREATE MATERIALIZED VIEW IF NOT EXISTS testdb.pv_uv_daily
33ENGINE = SummingMergeTree
34PARTITION BY toYYYYMM(event_date)
35ORDER BY event_date
36AS
37SELECT
38    event_date,
39    count()               AS pv,
40    uniqExact(user_id)    AS uv
41FROM testdb.pageviews
42GROUP BY event_date;
43
44/* 6. 演示数据插入 ---------------------------------------- */
45
46/* 用户维度 */
47INSERT INTO testdb.users (user_id, user_name, signup_date) VALUES
48    (1, 'Alice', '2024-06-01'),
49    (2, 'Bob',   '2024-07-15'),
50    (3, 'Cathy', '2024-11-30');
51
52/* 页面维度 */
53INSERT INTO testdb.pages (page_id, page_url, category) VALUES
54    (10, '/home',    'landing'),
55    (11, '/pricing', 'info'),
56    (12, '/blog',    'content');
57
58/* 页面访问日志 */
59INSERT INTO testdb.pageviews (event_date, event_time, user_id, page_id, duration) VALUES
60    ('2025-07-13', '2025-07-13 09:17:00', 1, 10, 35),
61    ('2025-07-13', '2025-07-13 09:18:07', 1, 11, 50),
62    ('2025-07-13', '2025-07-13 09:19:02', 2, 10, 15),
63    ('2025-07-14', '2025-07-14 10:03:45', 3, 12, 120),
64    ('2025-07-14', '2025-07-14 10:05:22', 1, 12, 90);
65
66/* 7. 快速验证 --------------------------------------------- */
67
68/* 查看当前数据库已创建的表 */
69SHOW TABLES FROM testdb;
70
71/* 查询物化视图结果 */
72SELECT * FROM testdb.pv_uv_daily ORDER BY event_date;
73
74/* 联表查询示例 */
75SELECT
76    u.user_name,
77    p.page_url,
78    v.event_time,
79    v.duration
80FROM testdb.pageviews AS v
81LEFT JOIN testdb.users  AS u ON v.user_id = u.user_id
82LEFT JOIN testdb.pages  AS p ON v.page_id = p.page_id
83ORDER BY v.event_time DESC;
位旅人路过 次翻阅 初次见面