1"use strict";(globalThis.webpackChunkdocs=globalThis.webpackChunkdocs||[]).push([[4400],{3818(e,n,s){s.r(n),s.d(n,{assets:()=>o,contentTitle:()=>d,default:()=>h,frontMatter:()=>c,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"supported-technologies/clickhouse","title":"ClickHouse","description":"How to configure the NeverBlink Agent for monitoring self-managed ClickHouse clusters, including node discovery, polling modes, and connection tuning.","source":"@site/docs/03-supported-technologies/clickhouse.md","sourceDirName":"03-supported-technologies","slug":"/supported-technologies/clickhouse","permalink":"/docs/supported-technologies/clickhouse","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":9,"frontMatter":{"title":"ClickHouse","sidebar_position":9,"slug":"/supported-technologies/clickhouse","description":"How to configure the NeverBlink Agent for monitoring self-managed ClickHouse clusters, including node discovery, polling modes, and connection tuning."},"sidebar":"docsSidebar","previous":{"title":"Logstash","permalink":"/docs/supported-technologies/logstash"},"next":{"title":"ClickHouse Cloud","permalink":"/docs/supported-technologies/clickhouse-cloud"}}');var r=s(4848),t=s(8453);const c={title:"ClickHouse",sidebar_position:9,slug:"/supported-technologies/clickhouse",description:"How to configure the NeverBlink Agent for monitoring self-managed ClickHouse clusters, including node discovery, polling modes, and connection tuning."},d="ClickHouse",o={},l=[{value:"Agent Configuration",id:"agent-configuration",level:2},{value:"Configuration file",id:"configuration-file",level:3},{value:"Configuration reference",id:"configuration-reference",level:3},{value:"Using HTTPS",id:"using-https",level:2},{value:"Polling modes",id:"polling-modes",level:2},{value:"Node discovery",id:"node-discovery",level:2},{value:"Setting Up a Dedicated Monitoring User",id:"setting-up-a-dedicated-monitoring-user",level:2},{value:"1. Create the user",id:"1-create-the-user",level:3},{value:"2. Grant read access to system tables",id:"2-grant-read-access-to-system-tables",level:3},{value:"3. Grant metadata visibility",id:"3-grant-metadata-visibility",level:3},{value:"4. Grant access metadata visibility",id:"4-grant-access-metadata-visibility",level:3},{value:"5. Grant REMOTE",id:"5-grant-remote",level:3},{value:"6. Verify",id:"6-verify",level:3},{value:"Deploy the Agent",id:"deploy-the-agent",level:2}];function a(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",mdxAdmonitionTitle:"mdxAdmonitionTitle",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,t.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"clickhouse",children:"ClickHouse"})}),"\n",(0,r.jsxs)(n.p,{children:["NeverBlink provides monitoring for self-managed ClickHouse clusters running anywhere \u2014 on-premises, in any cloud provider, or in Kubernetes. The agent collects node metrics, async metrics, system events, disk stats, error logs, and query logs over the ClickHouse HTTP interface (default port ",(0,r.jsx)(n.code,{children:"8123"}),")."]}),"\n",(0,r.jsxs)(n.p,{children:["NeverBlink also supports fully-managed ",(0,r.jsx)(n.a,{href:"/docs/supported-technologies/clickhouse-cloud",children:"ClickHouse Cloud"})," services \u2014 see that page for the Cloud-specific setup."]}),"\n",(0,r.jsx)(n.h2,{id:"agent-configuration",children:"Agent Configuration"}),"\n",(0,r.jsxs)(n.p,{children:["See ",(0,r.jsx)(n.a,{href:"/docs/get-started/connecting-a-cluster#ingest-keys-and-container-pull-token",children:"Ingest Keys and Container Pull Token"})," for where to find both credentials."]}),"\n",(0,r.jsx)(n.admonition,{title:"One cluster per agent",type:"note",children:(0,r.jsx)(n.p,{children:"A single agent instance monitors one ClickHouse cluster. Monitoring multiple clusters requires a separate agent deployment per cluster."})}),"\n",(0,r.jsx)(n.p,{children:"Configure the agent via environment variables:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"export NB_INGEST_KEY=<INGEST_KEY>\nexport CLICKHOUSE_HOSTS=http://clickhouse1:8123,http://clickhouse2
1:8123\nexport CLICKHOUSE_USERNAME=default\nexport CLICKHOUSE_PASSWORD=secret\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Only ",(0,r.jsx)(n.code,{children:"CLICKHOUSE_HOSTS"})," is required; all other fields have defaults that work for typical deployments. The full list of variables is in the ",(0,r.jsx)(n.a,{href:"#configuration-reference",children:"Configuration reference"})," below."]}),"\n",(0,r.jsx)(n.h3,{id:"configuration-file",children:"Configuration file"}),"\n",(0,r.jsx)(n.p,{children:"A configuration file is needed only when monitoring multiple clusters of different technologies from a single agent. When set, env vars take precedence for the same field. Example:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'clusters:\n - type: clickhouse\n hosts: http://clickhouse1:8123,http://clickhouse2:8123\n username: default\n password: ""\n port: 8123\n auto_discovery: true\n max_connections: 5\n keep_alive_timeout: 30\n socket_keep_alive: true\n connect_timeout: 5000\n socket_timeout: 10000\n'})}),"\n",(0,r.jsx)(n.h3,{id:"configuration-reference",children:"Configuration reference"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Config file key"}),(0,r.jsx)(n.th,{children:"Environment variable"}),(0,r.jsx)(n.th,{children:"Description"}),(0,r.jsx)(n.th,{children:"Default"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"hosts"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"CLICKHOUSE_HOSTS"})}),(0,r.jsx)(n.td,{children:"Comma-separated list of ClickHouse HTTP URLs"}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.em,{children:"(required)"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"username"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"CLICKHOUSE_USERNAME"})}),(0,r.jsx)(n.td,{children:"ClickHouse username"}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"default"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"password"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"CLICKHOUSE_PASSWORD"})}),(0,r.jsx)(n.td,{children:"ClickHouse password"}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:'""'})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"port"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"CLICKHOUSE_PORT"})}),(0,r.jsx)(n.td,{children:"Default HTTP port for discovered nodes"}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"8123"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"auto_discovery"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"CLICKHOUSE_AUTO_DISCOVERY"})}),(0,r.jsxs)(n.td,{children:["Enable automatic cluster node discovery via ",(0,r.jsx)(n.code,{children:"system.clusters"})]}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"true"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"polling_mode"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"CLICKHOUSE_POLLING_MODE"})}),(0,r.jsx)(n.td,{children:"Polling strategy \u2014 see below"}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"NODE_BY_NODE"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"cluster_name"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"CLUSTER_NAME"})}),(0,r.jsxs)(n.td,{children:["Cluster name used by ",(0,r.jsx)(n.code,{children:"DISTRIBUTED"})," polling mode. This is the agent-wide variable, with no technology prefix."]}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.em,{children:"(auto-detected)"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"stale_node_max_retries"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"CLICKHOUSE_STALE_NODE_MAX_RETRIES"})}),(0,r.jsx)(n.td,{children:"Discovery cycles before a missing node is removed"}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"3"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"max_connections"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"CLICKHOUSE_MAX_CONNECTIONS"})}),(0,r.jsx)(n.td,{children:"Max connections per node in the connection pool"}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"5"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"keep_alive_timeout"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"CLICKHOUSE_KEEP_ALIVE_TIMEOUT"})}),(0,r.jsx)(n.td,{children:"Keep-alive timeout in seconds"}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"30"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"socket_keep_alive"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"CLICKHOUSE_SOCKET_KEEP_ALIVE"})}),(0,r.jsx)(n.td,{children:"Enable TCP socket keep-alive"}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"true"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"connect_timeout"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"CLICKHOUSE_CONNECT_TIMEOUT"})}),(0,r.jsx)(n.td,{children:"Connection timeout in milliseconds"}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"5000"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"socket_timeout"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"CLICKHOUSE_SOCKET_TIMEOUT"})}),(0,r.jsx)(n.td,{children:"Socket read timeout in milliseconds"}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"10000"})})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"ssl.verification_mode"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"CLICKHOUSE_SSL_VERIFICATION_MODE"})}),(0,r.jsxs)(n.td,{children:["SSL certificate verification mode for HTTPS endpoints \u2014 see ",(0,r.jsx)(n.a,{href:"/docs/integration/configuration#ssl-configuration",children:"SSL Configuration"}),". Set to ",(0,r.jsx)(n.code,{children:"none"}
1)," to trust self-signed / internal-CA certs."]}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"full"})})]})]})]}),"\n",(0,r.jsx)(n.h2,{id:"using-https",children:"Using HTTPS"}),"\n",(0,r.jsxs)(n.p,{children:["Put ",(0,r.jsx)(n.code,{children:"https://"})," URLs in ",(0,r.jsx)(n.code,{children:"CLICKHOUSE_HOSTS"})," and set ",(0,r.jsx)(n.code,{children:"CLICKHOUSE_PORT"})," to the matching TLS port (typically ",(0,r.jsx)(n.code,{children:"8443"}),") to connect over TLS. No separate ",(0,r.jsx)(n.code,{children:"_SSL_ENABLED"})," flag is needed \u2014 the scheme drives it."]}),"\n",(0,r.jsx)(n.p,{children:"For self-signed or internal-CA certificates, either:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Skip verification"})," by setting ",(0,r.jsx)(n.code,{children:"CLICKHOUSE_SSL_VERIFICATION_MODE=none"})," (also disables hostname checks \u2014 fine for internal monitoring traffic, not for public endpoints), or"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Trust your CA"})," by mounting a CA bundle and setting ",(0,r.jsx)(n.code,{children:"SSL_CERTIFICATE_AUTHORITIES"})," (or ",(0,r.jsx)(n.code,{children:"SSL_TRUSTSTORE_PATH"})," + ",(0,r.jsx)(n.code,{children:"SSL_TRUSTSTORE_SECURE_PASSWORD"}),"). See ",(0,r.jsx)(n.a,{href:"/docs/integration/configuration#ssl-configuration",children:"Advanced Configuration \u2192 SSL"})," for the full reference."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"polling-modes",children:"Polling modes"}),"\n",(0,r.jsxs)(n.p,{children:["Three polling strategies are available via ",(0,r.jsx)(n.code,{children:"polling_mode"})," / ",(0,r.jsx)(n.code,{children:"CLICKHOUSE_POLLING_MODE"}),":"]}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Mode"}),(0,r.jsx)(n.th,{children:"Description"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"NODE_BY_NODE"})}),(0,r.jsxs)(n.td,{children:["Each discovered node is polled with its own dedicated HTTP client. Enables per-node metrics and is the default when ",(0,r.jsx)(n.code,{children:"auto_discovery"})," is on. List all your hosts in ",(0,r.jsx)(n.code,{children:"CLICKHOUSE_HOSTS"}),", or enable ",(0,r.jsx)(n.code,{children:"auto_discovery"})," and list some of them."]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"DISTRIBUTED"})}),(0,r.jsxs)(n.td,{children:["A single seed client queries all nodes at once using ",(0,r.jsx)(n.code,{children:"clusterAllReplicas()"}),". Lower connection count, but requires a reachable cluster name (either auto-detected or set via ",(0,r.jsx)(n.code,{children:"cluster_name"}),") and an inter-server ",(0,r.jsx)(n.code,{children:"<secret>"})," in the ",(0,r.jsx)(n.code,{children:"<remote_servers>"})," cluster config block \u2014 see the ",(0,r.jsx)(n.a,{href:"#5-grant-remote",children:"caution note below"}),"."]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"ROUND_ROBIN_DNS"})}),(0,r.jsx)(n.td,{children:"Each seed URL is polled sequentially. Intended for setups where a load balancer rotates connections across nodes."})]})]})]}),"\n",(0,r.jsx)(n.h2,{id:"node-discovery",children:"Node discovery"}),"\n",(0,r.jsxs)(n.p,{children:["When ",(0,r.jsx)(n.code,{children:"auto_discovery"})," is ",(0,r.jsx)(n.code,{children:"true"})," (default), the agent connects to the seed ",(0,r.jsx)(n.code,{children:"hosts"})," and queries ",(0,r.jsx)(n.code,{children:"system.clusters"})," at startup and on every periodic refresh to discover the full node list. Discovered nodes are reached using the scheme and port from the seed URL (or the configured ",(0,r.jsx)(n.code,{children:"port"}),")."]}),"\n",(0,r.jsxs)(n.p,{children:["When ",(0,r.jsx)(n.code,{children:"auto_discovery"})," is ",(0,r.jsx)(n.code,{children:"false"}),", only the explicitly configured ",(0,r.jsx)(n.code,{children:"hosts"})," are polled."]}),"\n",(0,r.jsxs)(n.p,{children:["A node missing from ",(0,r.jsx)(n.code,{children:"system.clusters"})," for ",(0,r.jsx)(n.code,{children:"stale_node_max_retries"})," consecutive discovery cycles is removed from the agent's view. Seed hosts (the explicit entries in ",(0,r.jsx)(n.code,{children:"hosts"}),") are never evicted, so the agent retains connectivity even if ",(0,r.jsx)(n.code,{children:"system.clusters"})," returns unexpected output."]}),"\n",(0,r.jsx)(n.h2,{id:"setting-up-a-dedicated-monitoring-user",children:"Setting Up a Dedicated Monitoring User"}),"\n",(0,r.jsxs)(n.p,{children:["For optimal security, create a dedicated read-only user for the NeverBlink Agent instead of using the ",(0,r.jsx)(n.code,{children:"default"})," user. Run the following SQL in ",(0,r.jsx)(n.code,{children:"clickhouse-client"})," or any SQL interface connected to your cluster."]}),"\n",(0,r.jsxs)(n.admonition,{type:"note",children:[(0,r.jsxs)(n.mdxAdmonitionTitle,{children:["When to use ",(0,r.jsx)(n.code,{children:"ON CLUSTER"})]}),(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"ON CLUSTER '{cluster}'"})," variants below fan the DDL out to every node. Use them only when users are stored locally on each node. Single-node deployments, and clusters that use a shared/replicated user directory, only need the plain form run once."]})]}),"\n",(0,r.jsx)(n.h3,{id:"1-create-the-user",children:"1. Create the user"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsxs)(n.strong,{children:["Without ",(0,r.jsx)(n.code,{children:"ON CLUSTER"}),":"]})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"CREATE USER IF NOT EXISTS neverblink_monitoring_collector\nIDENTIFIED WITH sha256_password BY 'PASSWORD'\nSETTINGS\n readonly = 1,\n log_queries = 0,\n max_execution_time = 30,\n max_result_rows = 100000,\n max_memory_usage = 1000000000;\n"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsxs)(n.strong,{children:["With ",(0,r.jsx)(n.code,{children:"ON CLUSTER"})]})," (replace ",(0,r.jsx)(n.code,{children:"'{cluster}'"})," with your cluster name or keep the macro as-is):"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"CREATE USER IF NOT EXISTS neverblink_monitoring_collector ON CLUSTER '{cluster}'\nIDENTIFIED WITH sha256_password BY 'PASSWORD'\nSETTINGS\n readonly = 1,\n log_queries = 0,\n max_execution_time = 30,\n max_result_rows = 100000,\n max_memory_usage = 1000000000;\n"})}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"readonly = 1"})," blocks every write \u2014 INSERT, UPDATE, DELETE, and DDL \u2014 regardless of which grants are added later. ",(0,r.jsx)(n.code,{children:"PASSWORD"})," is the plaintext value; ClickHouse hashes it server-side with SHA-256 and stores only the hash."]}),"\n",(0,r.jsxs)(n.admonition,{title:"Pre-hashing the password",type:"tip",children:[(0,r.jsxs)(n.p,{children:["If you prefer not to send the plaintext to the server, swap the clause for ",(0,r.jsx)(n.code,{children:"IDENTIFIED WITH sha256_hash BY '<hex>'"})," and pass a precomputed hash:"]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"echo -n 'your_password' | sha256sum | awk '{print $1}'\n"})})]}),"\n",(0,r.jsxs)(n.admonition,{type:"note",children:[(0,r.jsxs)(n.mdxAdmonitionTitle,{children:["Interactive clients and ",(0,r.jsx)(n.code,{children:"readonly = 1"})]}),(0,r.jsxs)(n.p,{children:["Some SQL clients (",(0,r.jsx)(n.code,{children:"clickhouse-client"}),", DBeaver, JetBrains DataGrip) apply session settings on connect, which ",(0,r.jsx)(n.code,{children:"readonly = 1"})," rejects with ",(0,r.jsx)(n.code,{children:"Cannot modify ... setting in readonly mode"}),". If you need to smoke-test the monitoring user from such a client, swap ",(0,r.jsx)(n.code,{children:"readonly = 1"})," for ",(0,r.jsx)(n.code,{children:"readonly = 2"})," \u2014 it still blocks INSERT/UPDATE/DELETE/DDL but allows session-setting changes. The NeverBlink Agent itself works fine with ",(0,r.jsx)(n.code,{children:"readonly = 1"}),"; this only matters for interactive client compatibility."]})]}),"\n",(0,r.jsx)(n.h3,{id:"2-grant-read-access-to-system-tables",children:"2. Grant read access to system tables"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsxs)(n.strong,{children:["Without ",(0,r.jsx)(n.code,{children:"ON CLUSTER"}),":"]})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"GRANT SELECT ON system.* TO neverblink_monitoring_collector;\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsxs)(n.strong,{children:["With ",(0,r.jsx)(n.code,{children:"ON CLUSTER"}),":"]})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"GRANT ON CLUSTER '{cluster}' SELECT ON system.* TO neverblink_monitoring_collector;\n"})}),"\n",(0,r.jsx)(n.h3,{id:"3-grant-metadata-visibility",children:"3. Grant metadata visibility"}),"\n",(0,r.jsx)(n.p,{children:"Required for viewing table schemas and structures:"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsxs)(n.strong,{children:["Without ",(0,r.jsx)(n.code,{children:"ON CLUSTER"}),":"]})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"GRANT SHOW ON *.* TO neverblink_monitoring_collector;\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsxs)(n.strong,{children:["With ",(0,r.jsx)(n.code,{children:"ON CLUSTER"}),":"]})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"GRANT ON CLUSTER '{cluster}' SHOW ON *.* TO neverblink_monitoring_collector;\n"})}),"\n",(0,r.jsx)(n.h3,{id:"4-grant-access-metadata-visibility",children:"4. Grant access metadata visibility"}),"\n",(0,r.jsxs)(n.p,{children:["Required for viewing grants and access control (the agent reads ",(0,r.jsx)(n.code,{children:"system.grants"}),", ",(0,r.jsx)(n.code,{children:"system.users"}),", and related access tables):"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsxs)(n.strong,{children:["Without ",(0,r.jsx)(n.code,{children:"ON CLUSTER"}),":"]})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"GRANT SHOW ACCESS ON *.* TO neverblink_monitoring_collector;\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsxs)(n.strong,{children:["With ",(0,r.jsx)(n.code,{children:"ON CLUSTER"}),":"]})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"GRANT ON CLUSTER '{cluster}' SHOW ACCESS ON *.* TO neverblink_monitoring_collector;\n"})}),"\n",(0,r.jsx)(n.h3,{id:"5-grant-remote",children:"5. Grant REMOTE"}),"\n",(0,r.jsxs)(n.p,{children:["Required when using ",(0,r.jsx)(n.code,{children:"CLICKHOUSE_POLLING_MODE=DISTRIBUTED"}),", which polls all nodes via ",(0,r.jsx)(n.code,{children:"clusterAllReplicas()"})," from a single seed client. ",(0,r.jsx)(n.code,{children:"NODE_BY_NODE"})," (the default) and ",(0,r.jsx)(n.code,{children:"ROUND_ROBIN_DNS"})," do not strictly need it, but granting it now keeps the user usable across all polling modes if you switch later."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsxs)(n.strong,{children:["Without ",(0,r.jsx)(n.code,{children:"ON CLUSTER"}),":"]})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"GRANT REMOTE ON *.* TO neverblink_monitoring_collector;\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsxs)(n.strong,{children:["With ",(0,r.jsx)(n.code,{children:"ON CLUSTER"}),":"]})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"GRANT ON CLUSTER '{cluster}' REMOTE ON *.* TO neverblink_monitoring_collector;\n"})}),"\n",(0,r.jsxs)(n.admonition,{type:"caution",children:[(0,r.jsxs)(n.mdxAdmonitionTitle,{children:[(0,r.jsx)(n.code,{children:"DISTRIBUTED"})," mode also needs an inter-server ",(0,r.jsx)(n.code,{children:"<secret>"})]}),(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"clusterAllReplicas()"})," requires the ClickHouse cluster definition to include an inter-server ",(0,r.jsx)(n.code,{children:"<secret>"})," before it will forward authenticated queries between nodes. Without it, the seed node refuses to pass credentials to the replicas and you'll see auth failures from the replicas even with ",(0,r.jsx)(n.code,{children:"REMOTE"})," granted on every node. Add a ",(0,r.jsx)(n.code,{children:"<secret>"})," inside the ",(0,r.jsx)(n.code,{children:"<cluster>"})," block in your ClickHouse server config:"]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-xml",children:"<remote_servers>\n <your_cluster_name>\n <secret>some-shared-secret</secret>\n \x3c!-- shards / replicas ... --\x3e\n </your_cluster_name>\n</remote_servers>\n"})}),(0,r.jsxs)(n.p,{children:["If you can't change the cluster config, stay on ",(0,r.jsx)(n.code,{children:"NODE_BY_NODE"})," (default) or ",(0,r.jsx)(n.code,{children:"ROUND_ROBIN_DNS"})," instead \u2014 neither uses ",(0,r.jsx)(n.code,{children:"clusterAllReplicas()"}),"."]})]}),"\n",(0,r.jsx)(n.h3,{id:"6-verify",children:"6. Verify"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"SHOW GRANTS FOR neverblink_monitoring_collector;\n"})}),"\n",(0,r.jsx)(n.p,{children:"Smoke test \u2014 run as the monitoring user:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"SELECT * FROM system.metrics LIMIT 5;\n"})}),"\n",(0,r.jsx)(n.p,{children:"Negative tests \u2014 all must fail:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"-- Should fail: no access to application data\nSELECT * FROM default.some_table LIMIT 1;\n\n-- Should fail: writes blocked by readonly = 1\nINSERT INTO default.some_table VALUES (1);\n\n-- Should fail: DDL blocked by readonly = 1\nCREATE TABLE default.x (a UInt8) ENGINE
1= MergeTree ORDER BY a;\n"})}),"\n",(0,r.jsx)(n.p,{children:"Then update your agent configuration:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"export CLICKHOUSE_USERNAME=neverblink_monitoring_collector\nexport CLICKHOUSE_PASSWORD=your_strong_password\n"})}),"\n",(0,r.jsx)(n.admonition,{title:"Deprecated naming",type:"note",children:(0,r.jsxs)(n.p,{children:["A user whose name starts with ",(0,r.jsx)(n.code,{children:"pulse_"})," (e.g. ",(0,r.jsx)(n.code,{children:"pulse_monitoring_collector"}),") is leftover from the agent's former name. It's deprecated and can be safely removed from clusters set up before this rename \u2014 ",(0,r.jsx)(n.code,{children:"neverblink_monitoring_collector"})," fully replaces it."]})}),"\n",(0,r.jsx)(n.h2,{id:"deploy-the-agent",children:"Deploy the Agent"}),"\n",(0,r.jsx)(n.p,{children:"With the env vars above set, the quickest way to run the NeverBlink Agent is Docker:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"docker run \\\n --env NB_INGEST_KEY \\\n --env CLICKHOUSE_HOSTS \\\n --env CLICKHOUSE_USERNAME \\\n --env CLICKHOUSE_PASSWORD \\\n -m 2G \\\n --restart=always \\\n r.neverbl.ink/<CONTAINER_PULL_TOKEN>/agent\n"})}),"\n",(0,r.jsx)(n.p,{children:"For production or non-Docker environments, follow the dedicated guide for your platform:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/docs/integration/docker",children:"Running with Docker"})}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"/docs/integration/kubernetes",children:"Kubernetes (manifests)"})," \xb7 ",(0,r.jsx)(n.a,{href:"/docs/integration/helm",children:"Kubernetes (Helm chart)"})]}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/docs/integration/ecs",children:"Amazon ECS on Fargate"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/docs/integration/nomad",children:"HashiCorp Nomad"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"/docs/integration/cloud-run",children:"Google Cloud Run"})}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["For SSL, proxy, heap tuning, Prometheus, and other tuning, see ",(0,r.jsx)(n.a,{href:"/docs/integration/configuration",children:"Advanced Configuration"}),"."]}),"\n",(0,r.jsx)(n.admonition,{type:"note",children:(0,r.jsxs)(n.p,{children:["ClickHouse support is a newer integration. If you need guidance for a specific topology or authentication setup, ",(0,r.jsx)(n.a,{href:"https://app.neverblink.ai/support",children:"contact our support team"}),"."]})})]})}function h(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(a,{...e})}):a(e)}},8453(e,n,s){s.d(n,{R:()=>c,x:()=>d});var i=s(6540);const r={},t=i.createContext(r);function c(e){const n=i.useContext(t);return i.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:c(e.components),i.createElement(t.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.