Datadog Agent กับ Integration
ไอเดียหลักในหนึ่งประโยค
หัวข้อที่มีชื่อว่า “ไอเดียหลักในหนึ่งประโยค”“Agent” ไม่ได้เป็น process เดียว แต่เป็นกลุ่ม process เล็ก ๆ — core Agent, Trace Agent, Process Agent, Security Agent และบน Kubernetes จะมี process ที่ห้าระดับ cluster คือ Cluster Agent — แต่ละตัวเก็บ telemetry คนละแบบ โดยมี checks และ Autodiscovery เป็นตัวตัดสินว่าจะเก็บอะไรจากที่ไหน บทนี้รัน datadog/agent:7 container จริง (tag 7 resolve ไปเป็น Agent v7.83.3 — พิสูจน์ด้านล่าง) เพื่อพิสูจน์ทุก claim แทนที่จะแค่บรรยาย
process ทั้งห้าตัวของ Agent
หัวข้อที่มีชื่อว่า “process ทั้งห้าตัวของ Agent”เวลาคนพูดว่า “ติดตั้ง Datadog Agent” จริง ๆ แล้วหมายถึง package ที่ยกกลุ่ม process ที่ทำงานร่วมกันขึ้นมา แต่ละตัวมีหน้าที่แคบ ๆ
- Core Agent — เก็บ metric ระดับ host/system (CPU, memory, disk, network) และรัน checks กับ integration ที่ตั้งค่าไว้ นี่คือ process ที่อ่าน config ใน
conf.d/ - Trace Agent — ฟัง span ที่ tracing library ของแอปส่งมาในเครื่อง batch แล้วส่งต่อไปที่ APM intake ของ Datadog แอปของคุณไม่เคยคุยกับ Datadog โดยตรงสำหรับ trace — แต่คุยกับ Trace Agent
- Process Agent — component เชิงตรรกะ ที่เก็บข้อมูลระดับ process แบบ live (อะไรกำลังรันอยู่, ใช้ resource เท่าไหร่) สำหรับ view Live Processes ใน Agent 7 ปัจจุบัน (7.83.3, พิสูจน์ด้านล่าง) check ของมันรัน อยู่ใน process ของ core Agent โดย default จึงไม่มี PID
process-agentแยก ดู Agent Architecture สำหรับหลักฐานเต็ม - Security Agent (optional) — รันงาน Cloud Security: posture/misconfiguration scanning กับ runtime threat detection ปัจจุบันทำตลาดในชื่อ Cloud Security Management (CSM) ดราฟต์เก่าของคอร์สนี้เรียกว่า “Cloud Security Posture Management” — คำนั้นครอบแค่ครึ่งเดียว (posture/misconfiguration) ของสิ่งที่ Security Agent ทำตอนนี้ CSM คือชื่อ umbrella product ปัจจุบัน
- Cluster Agent (Kubernetes เท่านั้น, process ที่ห้า) — deploy แค่ตัวเดียวต่อ cluster (ไม่ใช่ต่อ node) รันงานระดับ cluster ที่ Agent ต่อ node ไม่ควรทำซ้ำ — Kubernetes State Metrics core check, External Metrics Provider ที่ขับเคลื่อน Horizontal Pod Autoscaler, Admission Controller, และการประสานงาน cluster checks Agent ทุกตัวใน node คุยกับ Cluster Agent แทนที่จะยิง Kubernetes API server ตรง ๆ นี่คือสิ่งที่ทำให้ load บน API server คงที่แม้ cluster จะขยายไปหลายร้อย node
process เหล่านี้ถูกติดตั้งเป็นชุดเดียว ส่วนใหญ่ข้างใต้เป็น OS process แยกกัน (core, Trace, Security) นี่คือเหตุผลที่คำสั่ง status (ด้านล่าง) รายงานแต่ละตัวแยกกัน ยกเว้น Process Agent ใน 7.83.3 ที่เป็น component ภายใน process ของ core Agent
flowchart TB
subgraph Node["Host / Node"]
Core["Core Agent
(metrics + checks)"]
Trace["Trace Agent
(receives spans)"]
Proc["Process Agent
(live processes, runs inside core by default)"]
Sec["Security Agent
(optional)"]
end
subgraph Cluster["Kubernetes cluster (one per cluster)"]
CA["Cluster Agent
(cluster checks, HPA metrics, Admission Controller)"]
end
App["Instrumented app"] -->|spans| Trace
Core -->|runs process checks in-process| Proc
Core -->|checks read| ConfD["conf.d/*.d/conf.yaml"]
Core -->|node-local queries| CA
CA -->|cluster-scoped queries| K8sAPI["Kubernetes API server"]
Core --> Backend["Datadog Backend"]
Trace --> Backend
Proc --> Backend
Sec --> Backend
CA --> Backend
พิสูจน์: เดิน agent status จริงทีละส่วน
หัวข้อที่มีชื่อว่า “พิสูจน์: เดิน agent status จริงทีละส่วน”datadog/agent:7 container ที่รันค้างไว้ (DD_API_KEY ปลอม 32 เลข 0, DD_DD_URL=http://127.0.0.1:1 เพื่อให้แน่ใจว่าไม่มีอะไรหลุดออกจากเครื่องนี้แม้จะพลาด) ให้ agent status จริง ตัดมาเฉพาะส่วนที่สำคัญ:
$ docker run -d --name dd-fnd \ -e DD_API_KEY=00000000000000000000000000000000 \ -e DD_DD_URL=http://127.0.0.1:1 \ -e DD_HOSTNAME=lesson-fnd-host \ -v /var/run/docker.sock:/var/run/docker.sock:ro \ datadog/agent:7$ docker exec dd-fnd agent status===============Agent (v7.83.3)=============== ... Build arch: arm64$ docker exec dd-fnd agent versionAgent 7.83.3 - Commit: 8c639c92581 - Serialization version: v5.0.207 - Go version: go1.26.7docker exec dd-fnd ps aux จริง โชว์กลุ่ม process ตรง ๆ — s6-supervise (process supervisor ของ container) มีหนึ่ง entry ต่อ component พิสูจน์ claim “process ที่ทำงานร่วมกันหลายตัว” ที่ระดับ OS ไม่ใช่แค่ใน prose:
root 424 s6-supervise agentroot 425 s6-supervise traceroot 426 s6-supervise processroot 427 s6-supervise sysproberoot 429 s6-supervise securityroot 430 agent runroot 431 trace-loader /etc/datadog-agent/datadog.yaml /opt/datadog-agent/embedded/bin//trace-agent --config=...root 433 system-probe-lite run --socket ...root 578 agent-data-plane --config ... runagent status เองก็ยืนยันว่ามีสอง component process ที่ยังทำงานอยู่จริงและรายงานตัวแยกกันผ่าน gRPC bus ภายในของ Agent:
2 remote agent(s) registered: Name: Agent Data Plane Flavor: agent_data_plane Last seen: 25.619486636s ago
Name: Security Agent Flavor: security_agent Last seen: 24.788567469s agoส่วน APM (Trace) Agent กับ Process Agent รายงาน Not running or unreachable ใน container ขั้นต่ำนี้ — เป็น output จริง ไม่ใช่ bug (สองตัวนี้สาเหตุต่างกัน อธิบายหลัง block):
=========APM Agent========= Status: Not running or unreachable on localhost:5012. Error: Get "https://localhost:5012/debug/vars": dial tcp [::1]:5012: connect: connection refusedentry s6-supervise ของทั้งสองตัวมีอยู่จริง (พิสูจน์ว่ากลุ่ม process ถูก provision) แต่ debug/status endpoint ของมันยังไม่ตอบสนองในจังหวะที่ agent status ไป poll ใน container ที่ idle ไม่มี trace ไม่มี process collection มากนี้ — เตือนว่า “process มีอยู่จริง” กับ “process รายงานตัวครบแล้ว” เป็นคนละเรื่องที่ agent status แยกให้เห็นชัด
บรรทัด Process Agent มีสาเหตุต่างออกไป เมื่อตั้ง DD_PROCESS_AGENT_ENABLED=true บน container แบบ --network none (Agent 7.83.3) ps ไม่เจอ binary process-agent เลย agent status ยังพิมพ์ Process Agent → Status: Not running or unreachable และด้านล่างทันทีมี section Process Component แสดง Enabled Checks: [process rtprocess] พร้อม check process ใน collector ของ core Agent check รันอยู่ภายใน core Agent ส่วน s6 service process แยกออกด้วย exit code 0 ทั้งสองบรรทัดจริงพร้อมกัน ดังนั้น “Not running” ตรงนี้ไม่ได้แปลว่าการเก็บ Live Processes ปิดอยู่ หลักฐานเต็มใน Agent Architecture
Checks กับ integration
หัวข้อที่มีชื่อว่า “Checks กับ integration”check คือโค้ดชิ้นเล็ก ๆ (Python ที่มากับ Agent) ที่รู้วิธีคุยกับ service หนึ่งตัวโดยเฉพาะ — Postgres, Redis, NGINX, Kafka และอีกหลายร้อยตัว — แล้วแปลง state ข้างในของตัวเองเป็น metric ของ Datadog แต่ละ check ถูกตั้งค่าผ่านไฟล์ YAML ใต้ directory conf.d/ ของ Agent ในโฟลเดอร์ที่ตั้งชื่อตาม integration นั้น
init_config:
instances: - host: localhost port: 5432 username: datadog password: "<PASSWORD>" tags: - "env:prod" - "service:orders-db"init_config:
instances: - host: localhost port: 6379 tags: - "env:prod" - "service:orders-cache"พอไฟล์นั้นมีอยู่แล้ว Agent restart (หรือ pick up การเปลี่ยนแปลง) จะเริ่มรัน check postgres หรือ redis ตามตารางเวลา และส่ง metric อย่าง postgresql.connections หรือ redis.mem.used — ที่ถูก tag ตามที่ใส่ไว้ใต้ tags บวกกับ host tag ของ Agent เอง
configcheck error จริง: เขียน instances: เป็น dict ไม่ใช่ list
หัวข้อที่มีชื่อว่า “configcheck error จริง: เขียน instances: เป็น dict ไม่ใช่ list”YAML ใต้ conf.d/ ที่ AI generate ชอบยุบ instances: จาก list ของหนึ่ง item ให้เหลือ mapping เปล่า ๆ — มัน ดู เหมือนเทียบเท่ากัน และสำหรับ instance เดียวมันยิ่งอ่านเป็นธรรมชาติกว่าด้วยซ้ำ มันไม่เทียบเท่ากัน และ Agent จริงปฏิเสธมันตอน config-load ด้วย Go type error จริง:
# @expect-error conf.d/broken.d/conf.yaml -- instances: is a mapping, not a []mapinit_config:
instances: host: localhost port: 6379$ docker exec dd-fnd-broken agent configcheck=== Configuration errors ===
broken: yaml: unmarshal errors: line 4: cannot unmarshal !!map into []integration.RawMapinstances เป็น list เสมอของ instance map — แม้จะมี instance เดียวเป๊ะ ๆ - ที่นำหน้าก็มีความหมาย นี่คือ error จริงที่ reproduce ได้จาก container พังตัวจริงของบทนี้เอง ไม่ใช่การถอดความ
Autodiscovery: checks กับ container logs
หัวข้อที่มีชื่อว่า “Autodiscovery: checks กับ container logs”ไฟล์ conf.d/ แบบ static ใช้ได้ดีกับ host ที่รัน service เดิมตลอดไป แต่พังทันทีที่ service เป็น container ที่ start, stop และ reschedule ตลอดเวลา — คุณเขียน config file มือให้ Postgres pod ที่อาจจะไม่มีอยู่แล้วในอีกห้านาทีไม่ได้ Autodiscovery แก้ปัญหานี้ — Agent เฝ้าดู container/pod แล้วจับคู่กับ config template ที่แปะเป็น annotation (Kubernetes) หรือ label (Docker ธรรมดา) สร้าง (และรื้อ) check config ให้เองอัตโนมัติตามที่ container ที่ match เข้ามาหรือหายไป
format annotation แบบปัจจุบัน (v2) ของ Kubernetes ใช้หนึ่ง annotation ต่อ container ต่อจุดประสงค์ นี่คือสิ่งที่ annotation block แบบนี้กำลังทำอยู่บน Pod template หน้า NGINX — สำหรับ checks:
apiVersion: v1kind: Servicemetadata: name: nginx annotations: ad.datadoghq.com/nginx.checks: | { "nginx": { "init_config": {}, "instances": [ { "nginx_status_url": "http://%%host%%:81/nginx_status/" } ] } }spec: selector: app: nginx ports: - port: 81และ annotation คู่กันสำหรับ container logs คือ ad.datadoghq.com/<CONTAINER_NAME>.logs บน Pod template:
apiVersion: apps/v1kind: Deploymentmetadata: name: orders-api # WRONG PLACE: an annotation here, on the Deployment's own metadata, # is invisible to Autodiscovery -- see the Callout below.spec: selector: matchLabels: app: orders-api template: metadata: labels: app: orders-api annotations: ad.datadoghq.com/orders-api.logs: | [{"source": "nodejs", "service": "orders-api"}] spec: containers: - name: orders-api image: orders-api:latestAgent อ่าน ad.datadoghq.com/<container-name>.checks กับ ad.datadoghq.com/<container-name>.logs แทนที่ template variable อย่าง %%host%% ด้วย pod IP จริงตอน runtime แล้วเริ่มรัน check หรือ log source ที่ match กับ pod ตัวไหนก็ตามที่ match อยู่ตอนนั้น — ไม่ต้องแก้ conf.d/ มือ ไม่ต้อง restart ทีละ pod
พิสูจน์การ discover ด้วย Docker label — ไม่ต้องมี cluster
หัวข้อที่มีชื่อว่า “พิสูจน์การ discover ด้วย Docker label — ไม่ต้องมี cluster”Kubernetes annotation กับ Docker label เป็นกลไก Autodiscovery เดียวกัน แค่จุดแปะต่างกัน รูปแบบของ Docker คือ com.datadoghq.ad.checks หนึ่ง label ที่เก็บ check config เต็มเป็น JSON (ยืนยันจาก docs.datadoghq.com/containers/docker/integrations/?tab=dockerlabels) container จริงสามตัว, Agent ตัวเดียว (dd-fnd ที่ restart พร้อม mount /var/run/docker.sock เพื่อให้เห็น container label) พิสูจน์ผลลัพธ์ที่แตกต่างกันสามแบบ:
# 1. label key ถูก, ชื่อ check ถูก "redisdb"$ docker run -d --name ad-redis-correct \ --label 'com.datadoghq.ad.checks={"redisdb":{"instances":[{"host":"%%host%%","port":6379}]}}' \ redis:7-alpine
# 2. label key ถูก, ชื่อ check ผิด "redis" (คำเดาที่ AI มีโอกาสเดาสูงมาก --# package Python กับ Docker image ชื่อ "redis" ทั้งคู่; integration ของ Datadog# ชื่อจริงคือ "redisdb")$ docker run -d --name ad-redis-good \ --label 'com.datadoghq.ad.checks={"redis":{"instances":[{"host":"%%host%%","port":6379}]}}' \ redis:7-alpine
# 3. label key ผิด ("check" เอกพจน์ -- ความผิดพลาด "ผิดที่ object" เทียบเท่า# ของ Docker กับการแปะ annotation บน Deployment แทน Pod template)$ docker run -d --name ad-redis-bad \ --label 'com.datadoghq.ad.check={"redisdb":{"instances":[{"host":"%%host%%","port":6379}]}}' \ redis:7-alpineagent configcheck หลัง container ทั้งสามรันอยู่:
$ docker exec dd-fnd agent configcheck=== redisdb check ===Configuration provider: kubernetes-container-allinoneConfiguration source: container:docker://bac373c7ed70e24c64dd646113a99696947388f1e310acababa4ce54a779f33cConfig for instance ID: redisdb:533fb300e611a572host: 172.17.0.5port: 6379Auto-discovery IDs:* docker://bac373c7ed70e24c64dd646113a99696947388f1e310acababa4ce54a779f33c===
=== redis check ===Configuration provider: kubernetes-container-allinoneConfiguration source: container:docker://5bf7d03f5930c062d23327d960d51d39082cc1968c8d41a5e948ae4a3708bc96Config for instance ID: redis:2461dfba582d49echost: 172.17.0.3port: 6379Auto-discovery IDs:* docker://5bf7d03f5930c062d23327d960d51d39082cc1968c8d41a5e948ae4a3708bc96===Container 1 (ad-redis-correct, id bac373c7...) ถูก discover เป็น redisdb check ที่ทำงานได้จริง Container 2 (ad-redis-good, id 5bf7d03f...) ก็ถูก discover เหมือนกัน — Autodiscovery match label ได้ปกติ — แต่เป็น check ที่ชื่อ redis ตรงตัว และ agent status โชว์ว่ามันไม่เคยรันจริงเลย:
Loading Errors ============== redis ----- Core Check Loader: Check redis not found in Catalog
Python Check Loader: unable to load check redis: unable to load python module datadog_checks.redis: unable to import module 'datadog_checks.redis': No module named 'datadog_checks.redis'Container 3 (ad-redis-bad, id f4db23d2...) ไม่ปรากฏที่ไหนเลยใน output ของ configcheck — ไม่ใช่ check ที่ทำงาน ไม่ใช่ loading error ไม่มีอะไรเลย Docker listener ของ Agent ไม่เคย match com.datadoghq.ad.check (เอกพจน์) กับอะไรเลย เป็นความผิดพลาดแบบ “มองไม่เห็นแบบเงียบ ๆ” ประเภทเดียวกับความผิดพลาด Deployment-metadata ของ Kubernetes เป๊ะ เพียงแต่ไม่ต้องมี cluster ก็พิสูจน์ได้
Kubernetes: Helm chart เทียบกับ Datadog Operator + DatadogAgent CRD
หัวข้อที่มีชื่อว่า “Kubernetes: Helm chart เทียบกับ Datadog Operator + DatadogAgent CRD”ปัจจุบันมีสองวิธีที่ support การรันกลุ่ม Agent บน Kubernetes และ manifest ที่ AI generate มักผสมรูปแบบทั้งสองตลอด เพราะทั้งคู่ถูกต้องและมีเอกสารรองรับ:
Helm (chart datadog/datadog, เวอร์ชันจริงที่ pin ไว้ 3.250.2, appVersion: "7") ติดตั้ง resource DaemonSet/Deployment ตรงจาก chart template คีย์จริงจาก values.yaml ของ chart ตัวนี้เป๊ะ — ไม่ได้เดา:
datadog: apiKey: "<DATADOG_API_KEY>" site: datadoghq.com logs: enabled: true containerCollectAll: false
clusterAgent: enabled: true image: name: cluster-agent tag: 7.82.3 # the chart pins an exact patch by default -- see "image tags" below
agents: image: name: agentclusterAgent.enabled: true คือคีย์ตรงตัวที่เปิด component ที่ห้าที่อธิบายไว้ด้านบน Helm มองว่ามันเป็น deployment หนึ่งตัวใน chart install เดียวกัน ไม่ใช่ product แยก
Datadog Operator (DataDog/datadog-operator, release ล่าสุดจริง v1.30.0) คือทางเลือกที่ Datadog แนะนำสำหรับ cluster ที่ใหญ่/ซับซ้อนกว่า: ติดตั้ง Operator ครั้งเดียว แล้วจัดการ Agent แบบ declarative ผ่าน custom resource DatadogAgent แทนการ helm upgrade บทนี้ดึง OpenAPI schema จริงของ Operator ชื่อ datadoghq.com_datadogagents_v2alpha1.json ตรงจาก github.com/DataDog/datadog-operator ที่ tag v1.30.0 แล้ว validate manifest จริงแบบ offline ด้วย kubeconform (ดึงไว้แล้ว, ghcr.io/yannh/kubeconform, -schema-location ชี้ไปที่ schema ที่แกะออกมา — ไม่มี cluster ไม่มี API server ไม่มีอะไรถูกส่งไปไหนเลย):
apiVersion: datadoghq.com/v2alpha1kind: DatadogAgentmetadata: name: datadog namespace: datadog-agentspec: global: site: datadoghq.com credentials: apiSecret: secretName: datadog-secret keyName: api-key features: apm: enabled: true logCollection: enabled: true containerCollectAll: true override: nodeAgent: image: name: agent tag: "7"$ docker run --rm -v "$PWD":/work ghcr.io/yannh/kubeconform \ -schema-location '/work/k8s-schema/{{.Group}}/{{.ResourceAPIVersion}}/{{.ResourceKind}}.json' \ -summary -verbose /work/datadog-agent-cr.yaml/work/datadog-agent-cr.yaml - DatadogAgent datadog is validSummary: 1 resource found in 1 file - Valid: 1, Invalid: 0, Errors: 0, Skipped: 0CRD v2alpha1 เข้มงวด ("additionalProperties": false) — manifest ที่มีรูปร่างแบบ v1alpha1 เก่าของ CRD (block spec.agent: ระดับบนสุด รูปแบบที่ training data ของ AI ยังมีเยอะ) จะ fail การ validate schema จริงแบบ offline ทันที:
$ docker run --rm -v "$PWD":/work ghcr.io/yannh/kubeconform \ -schema-location '/work/k8s-schema/{{.Group}}/{{.ResourceAPIVersion}}/{{.ResourceKind}}.json' \ -summary -verbose /work/datadog-agent-cr-broken.yaml/work/datadog-agent-cr-broken.yaml - DatadogAgent datadog is invalid: problem validating schema.Check JSON formatting: jsonschema validation failed with '...#' - at '/spec': additional properties 'agent' not allowedSummary: 1 resource found in 1 file - Valid: 0, Invalid: 1, Errors: 0, Skipped: 0รูปร่างปัจจุบันใช้ spec.global (site, credentials), spec.features (toggle ต่อ product อย่าง apm, logCollection) และ spec.override (override ต่อ component อย่าง nodeAgent.image.tag) — ไม่ใช่ spec.agent/spec.clusterAgent แบบแยกแบนของ API version เก่า
Agent 5, 6 และ 7: legacy pattern ที่อาจเจอในโค้ดที่ AI generate
หัวข้อที่มีชื่อว่า “Agent 5, 6 และ 7: legacy pattern ที่อาจเจอในโค้ดที่ AI generate”คอร์สนี้สอนแค่ Agent 7 — ถูกต้องสำหรับของที่ ship วันนี้ — แต่ training data ของ AI ครอบคลุมเอกสาร/บล็อกของ Datadog หลายปี ดังนั้น snippet ที่ hallucinate หรือ outdated ที่อ้างถึง Agent generation เก่ากว่าก็โผล่มาในโค้ดที่ generate ได้ การเปลี่ยนแปลงจริงสองอย่างที่เอกสารยืนยัน และมันเกิดขึ้นตอนไหนจริง ๆ (นี่แก้กรอบ “Agent 6 เทียบ 7” ที่หลวมเกินไปจากรอบก่อนของคอร์สนี้ — การเปลี่ยน config file ด้านล่างเกิดที่ 5→6 ไม่ใช่ 6→7):
- Agent 5 → 6: format config เปลี่ยนจาก INI
datadog.confเป็น YAMLdatadog.yaml(ตามdocs.datadoghq.com/agent/faq/agent_v6_changes/: “Agent v5datadog.conf–> Agent v6datadog.yaml”); directory config ย้ายจาก/etc/dd-agentเป็น/etc/datadog-agent; binary/command เปลี่ยนชื่อจากdd-agentเป็นdatadog-agent; สาม process แยก (Forwarder, Collector, DogStatsD) รวมเป็น Agent process เดียว; log file แยกต่อ process (collector.log,forwarder.log,dogstatsd.log) รวมเป็นagent.logเดียว - Agent 6 → 7: เลิก support Python 2 สำหรับ checks ตาม upgrade guide อย่างเป็นทางการ (
docs.datadoghq.com/agent/versions/upgrade_to_agent_v7/): “Agent 7 only supports Python 3 custom checks” — และสำคัญมาก “The upgrade process does not automatically move custom Agent checks” ดังนั้น custom check ที่เขียนมือแบบ Python 2 ต้อง port ไม่ใช่แค่ deploy ใหม่ ถ้าโค้ดที่ AI generate สื่อ syntax Python 2 ใน custom check (printstatement ไม่มีวงเล็บ, เรียกunicode()) แปลว่า check นั้นมาจากก่อน Agent 7 และจะไม่ถูก load
# ของ Agent 5 ถ้าเจอรูปแบบนี้ในโค้ดที่ AI generate แปลว่ามัน generate ให้ Agent# generation ที่ end-of-life มาหลายปีแล้ว[Main]api_key: <API_KEY>hostname: my-hostวิธีติดตั้ง, image tag และการ troubleshoot
หัวข้อที่มีชื่อว่า “วิธีติดตั้ง, image tag และการ troubleshoot”Agent มีให้ติดตั้งหลายทาง เลือกตามที่ที่ต้องรัน
# Host package install (Debian/Ubuntu, one-line installer)DD_API_KEY=<API_KEY> DD_SITE="datadoghq.com" bash -c \ "$(curl -L https://install.datadoghq.com/scripts/install_script_agent7.sh)"
# Docker Agent containerdocker run -d --name datadog-agent \ -e DD_API_KEY=<API_KEY> -e DD_SITE="datadoghq.com" \ -v /var/run/docker.sock:/var/run/docker.sock:ro \ gcr.io/datadoghq/agent:7
# Kubernetes, via the official Helm charthelm repo add datadog https://helm.datadoghq.comhelm install datadog-agent datadog/datadog \ --set datadog.apiKey=<API_KEY> --set datadog.site="datadoghq.com"ตัวอย่างทั้งหมดด้านบน pin image tag เป็น 7 ไม่ใช่ latest พิสูจน์จริงว่าทำไมความต่างนี้สำคัญแม้ตอนนี้มันจะตรงกัน:
$ docker inspect datadog/agent:7 --format '{{.Id}}'sha256:da43d3ecfad79906df4d32c21c3dcee8c681ba8f0afa9a59f6663d8f5489d70c$ docker inspect datadog/agent:latest --format '{{.Id}}'sha256:da43d3ecfad79906df4d32c21c3dcee8c681ba8f0afa9a59f6663d8f5489d70c$ docker inspect datadog/agent:7.83.3 --format '{{.Id}}'sha256:da43d3ecfad79906df4d32c21c3dcee8c681ba8f0afa9a59f6663d8f5489d70cตอนนี้ 7, latest และ 7.83.3 resolve ไปที่ image เดียวกันเป๊ะ แต่มันจะไม่เป็นแบบนี้ตลอด: latest จะขยับไปที่ tag ใหม่สุดข้าม ทุก major version (รวมถึง Agent 8 ในอนาคตที่มี breaking change ของตัวเอง แบบเดียวกับที่บทนี้เพิ่งบันทึกไว้สำหรับการเปลี่ยน 5→6 กับ 6→7) ในขณะที่ 7 ขยับแค่ภายในสาย 7.x — เป็นแนวกันจริงและตั้งใจไม่ให้กระโดดข้าม major version แบบไม่ประกาศ แลกกับ docker pull ที่อาจได้ minor/patch ใหม่ทุกครั้งที่ restart แทนที่จะได้ image เดิมเป๊ะ ถ้าต้องการ image เดิมเป๊ะข้าม restart ให้ pin 7.83.3 เต็ม ๆ แทน
พอ Agent รันอยู่แล้ว มีสองคำสั่งที่ตอบคำถาม “Agent ทำงานอยู่หรือเปล่า” ได้เกือบทุกครั้ง
# Full status: which checks ran, when, any errors, each component process's healthsudo datadog-agent status
# Run one check once, in the foreground, with verbose output — the fastest# way to see exactly what a specific integration is doing (or failing to do)sudo datadog-agent check postgresstatus คือคำสั่งแรกที่ควรรันเมื่อ metric ดูเหมือนหายไป — พิสูจน์ด้านบน มันโชว์เวลารันล่าสุดของทุก check, loading error (เคส redis เทียบ redisdb ด้านบน) และสถานะ reachability ของแต่ละ component process check <name> คือเครื่องมือสำหรับวน iterate config ของ integration ตัวเดียวโดยไม่ต้องรอรอบถัดไป
Reading AI-generated code
หัวข้อที่มีชื่อว่า “Reading AI-generated code”🐛 หา bug ในโค้ดนี้
# AI comment: "Autodiscovery config for the orders Redis cache"apiVersion: v1kind: Podmetadata:name: orders-cacheannotations: ad.datadoghq.com/orders-cache.checks: | { "redis": { "init_config": {}, "instances": [ { "host": "%%host%%", "port": 6379 } ] } }spec:containers: - name: orders-cache image: redis:7-alpineเฉลย
ดูสมเหตุสมผลมาก — annotation รูปแบบปัจจุบันจริง (.checks) วางถูกที่บน Pod ด้วยชื่อ check ที่ดูน่าเชื่อ bug ที่พิสูจน์ด้วย container จริงด้านบนคือ: integration ของ Datadog สำหรับ Redis ชื่อ redisdb ไม่ใช่ redis — redis คือชื่อ Python package กับ Docker image ซึ่งเป็นเหตุผลที่ AI model สับสนสองอย่างนี้เข้าด้วยกันพอดี agent configcheck จริงยังโชว์ container นี้เป็น “redis check” ที่ถูก discover (Autodiscovery match annotation ได้ปกติ) แต่ agent status จริงโชว์ว่ามัน load ไม่สำเร็จ: Check redis not found in Catalog / unable to load python module datadog_checks.redis check นี้ตายแบบเงียบ ๆ — ไม่มี metric ไม่มี error โผล่ที่ไหนเลยนอกจากส่วน Loading Errors ของ agent status ซึ่งไม่มีอะไร alert ให้โดย default วิธีแก้: "redis" → "redisdb" ทั้งใน annotation JSON key และถ้า migrate จาก static config ก็ชื่อโฟลเดอร์ conf.d/ ด้วย (redisdb.d/)
Mental Model
หัวข้อที่มีชื่อว่า “Mental Model”ลองนึกภาพการติดตั้ง Agent เป็น บ้านที่มีผู้เชี่ยวชาญหลายคนอยู่ที่อยู่เดียวกัน ไม่ใช่คนงานคนเดียวทำทุกอย่าง Core Agent คือคนที่อ่านจดหมาย (conf.d/) แล้ววิ่งธุระ (checks) ตามตารางเวลา Trace Agent รับแขกแค่เรื่อง span อย่างเดียว Process Agent เฝ้าดูแค่ว่าอะไรกำลังรันอยู่ (ใน 7.83.3 ทำงานอยู่ในบ้านของ core Agent เอง) Security Agent จัดการแค่ security scanning ส่วน Cluster Agent ไม่ได้อยู่บ้านเดียวกันด้วยซ้ำ — มันคือออฟฟิศเดียวที่ให้บริการทั้งย่าน (cluster) เพื่อไม่ให้แต่ละบ้านต้องแยกกันไปกวน city record office (Kubernetes API server) เพื่อข้อมูลระดับ cluster เดียวกัน Autodiscovery คือกฎการคัดแยกจดหมายของบ้าน — label/annotation คือซองจดหมาย ถ้าส่งผิดประตู (key ผิด) หรือวางผิดตึก (metadata ของ Deployment แทน Pod template) มันไม่ถูกตีกลับหาผู้ส่ง — มันแค่ไม่มาถึงเลย และไม่มีอะไรบอกคุณ
Trade-offs
หัวข้อที่มีชื่อว่า “Trade-offs”- Helm เทียบกับ Datadog Operator — Helm คือคำสั่งเดียว คนที่ใช้ Helm อยู่แล้วเข้าใจทันที และ upgrade ก็แค่
helm upgrade; Operator เพิ่ม CRD กับ controller ให้ต้องจัดการ แต่ให้kubectl get datadogagentรายงานสถานะ, แก้ drift, และเรื่อง declarative ที่สะอาดกว่าสำหรับ GitOps — แลกกับชิ้นส่วนที่เคลื่อนไหวอีกหนึ่งตัว (ตัว Operator เอง) ที่ต้อง upgrade ด้วยเหมือนกัน - image tag
7เทียบกับ patch ที่ pin (7.83.3) เทียบกับlatest— พิสูจน์ด้านบน ทั้งสามเหมือนกันวันนี้;7update ตัวเองภายใน major version (สะดวก มีความเสี่ยง supply-chain เล็กน้อยที่ minor bump ที่ไม่ได้ review จะมาตอน restart) ส่วน patch ที่ pin reproducible เต็มที่แต่ต้อง bump มือถึงจะได้ fix;latestให้คำเตือนเป็นศูนย์ก่อน Agent 8 ที่มี breaking change จะ ship เข้ามาผ่านการ restart ธรรมดา conf.d/แบบ static เทียบกับ Autodiscovery — ไฟล์ static อ่านง่ายกว่าและ diff ใน version control ได้ และ fail แบบเสียงดัง (ไฟล์ไม่มี สังเกตง่าย); Autodiscovery จำเป็นสำหรับอะไรก็ตามที่เป็น container และ reschedule ได้ แต่ failure mode ของมัน — พิสูจน์ด้านบนสามครั้ง — คือความเงียบ ไม่ใช่ error ซึ่งทำให้ typo แพงกว่ามากในการหา
Common Misconceptions
หัวข้อที่มีชื่อว่า “Common Misconceptions”- “Datadog Agent เป็น process เดียว” ผิด — พิสูจน์ด้านบน:
ps auxใน container จริงโชว์ entrys6-superviseแยกกันสำหรับagent,trace,processและsecurityบวกกับสองตัว (Agent Data Plane,Security Agent) ที่ลงทะเบียนเป็น “remote agent” กับ core Agent แยกกันผ่าน gRPC bus ภายใน - “Autodiscovery annotation บน Deployment ตั้งค่าให้ทุก Pod ที่มันสร้าง” ผิด — เอกสาร ยกคำพูดด้านบน: annotation ต้องอยู่บน
.spec.template.metadataไม่ใช่metadataของ Deployment เอง พิสูจน์ด้านบนด้วย Docker-label ที่เทียบเท่ากัน label key พิมพ์ผิดทำให้ container ไม่ปรากฏที่ไหนเลยใน output ของconfigcheck - “ถ้า
agent configcheckโชว์ check ของฉัน แปลว่ามันทำงาน” ผิดบางส่วน — พิสูจน์ด้านบน: check ที่ชื่อ integration ผิด (redisแทนredisdb) ถูก discover และ list โดยconfigcheckแต่agent statusจริงโชว์ว่ามัน load ไม่สำเร็จเลย ไม่มี metric ถูกส่งเลย - “Datadog Operator มาแทน Helm chart” ผิด — ทั้งคู่ current, Datadog support และ maintain อยู่จริง (Helm chart
3.250.2, Operatorv1.30.0ทั้งคู่ release ภายในไม่กี่สัปดาห์ก่อนเขียนบทนี้) ใช้ manifest shape ต่างกันสำหรับ Agent ตัวเดียวกัน manifest ที่เขียนให้ตัวหนึ่งไม่ valid สำหรับอีกตัว พิสูจน์ด้านบนด้วยkubeconformreject จริงแบบเข้มงวด - “
docker pull datadog/agent:7ได้ image เดิมเสมอ” ผิด — พิสูจน์โดยนิยามด้านบน: tag7ลอยไปที่ release 7.x ล่าสุดทุกครั้งที่ pull ตอนที่เขียนบทนี้มันตรงกับ7.83.3แต่จะไม่ตรงตลอดไป ต่างจาก patch tag ที่ pin ไว้