ข้ามไปยังเนื้อหา

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 แทนที่จะแค่บรรยาย

เวลาคนพูดว่า “ติดตั้ง 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
กลุ่ม process ของ Agent

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 version
Agent 7.83.3 - Commit: 8c639c92581 - Serialization version: v5.0.207 - Go version: go1.26.7

docker exec dd-fnd ps aux จริง โชว์กลุ่ม process ตรง ๆ — s6-supervise (process supervisor ของ container) มีหนึ่ง entry ต่อ component พิสูจน์ claim “process ที่ทำงานร่วมกันหลายตัว” ที่ระดับ OS ไม่ใช่แค่ใน prose:

root 424 s6-supervise agent
root 425 s6-supervise trace
root 426 s6-supervise process
root 427 s6-supervise sysprobe
root 429 s6-supervise security
root 430 agent run
root 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 ... run

agent 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 refused

entry 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

check คือโค้ดชิ้นเล็ก ๆ (Python ที่มากับ Agent) ที่รู้วิธีคุยกับ service หนึ่งตัวโดยเฉพาะ — Postgres, Redis, NGINX, Kafka และอีกหลายร้อยตัว — แล้วแปลง state ข้างในของตัวเองเป็น metric ของ Datadog แต่ละ check ถูกตั้งค่าผ่านไฟล์ YAML ใต้ directory conf.d/ ของ Agent ในโฟลเดอร์ที่ตั้งชื่อตาม integration นั้น

conf.d/postgres.d/conf.yaml
init_config:
instances:
- host: localhost
port: 5432
username: datadog
password: "<PASSWORD>"
tags:
- "env:prod"
- "service:orders-db"
conf.d/redis.d/conf.yaml
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 เอง

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 []map
init_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.RawMap

instances เป็น list เสมอของ instance map — แม้จะมี instance เดียวเป๊ะ ๆ - ที่นำหน้าก็มีความหมาย นี่คือ error จริงที่ reproduce ได้จาก container พังตัวจริงของบทนี้เอง ไม่ใช่การถอดความ

ไฟล์ 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:

k8s/nginx-checks-service.yaml
apiVersion: v1
kind: Service
metadata:
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:

k8s/orders-deployment-logs.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
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:latest

Agent อ่าน 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

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-alpine

agent configcheck หลัง container ทั้งสามรันอยู่:

$ docker exec dd-fnd agent configcheck
=== redisdb check ===
Configuration provider: kubernetes-container-allinone
Configuration source: container:docker://bac373c7ed70e24c64dd646113a99696947388f1e310acababa4ce54a779f33c
Config for instance ID: redisdb:533fb300e611a572
host: 172.17.0.5
port: 6379
Auto-discovery IDs:
* docker://bac373c7ed70e24c64dd646113a99696947388f1e310acababa4ce54a779f33c
===
=== redis check ===
Configuration provider: kubernetes-container-allinone
Configuration source: container:docker://5bf7d03f5930c062d23327d960d51d39082cc1968c8d41a5e948ae4a3708bc96
Config for instance ID: redis:2461dfba582d49ec
host: 172.17.0.3
port: 6379
Auto-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 ก็พิสูจน์ได้

ปัจจุบันมีสองวิธีที่ 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-values.yaml
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: agent

clusterAgent.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 ไม่มีอะไรถูกส่งไปไหนเลย):

k8s/datadog-agent.yaml
apiVersion: datadoghq.com/v2alpha1
kind: DatadogAgent
metadata:
name: datadog
namespace: datadog-agent
spec:
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 valid
Summary: 1 resource found in 1 file - Valid: 1, Invalid: 0, Errors: 0, Skipped: 0

CRD 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 allowed
Summary: 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 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 เป็น YAML datadog.yaml (ตาม docs.datadoghq.com/agent/faq/agent_v6_changes/: “Agent v5 datadog.conf –> Agent v6 datadog.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 (print statement ไม่มีวงเล็บ, เรียก unicode()) แปลว่า check นั้นมาจากก่อน Agent 7 และจะไม่ถูก load
datadog.conf
# ของ Agent 5 ถ้าเจอรูปแบบนี้ในโค้ดที่ AI generate แปลว่ามัน generate ให้ Agent
# generation ที่ end-of-life มาหลายปีแล้ว
[Main]
api_key: <API_KEY>
hostname: my-host

Agent มีให้ติดตั้งหลายทาง เลือกตามที่ที่ต้องรัน

Terminal window
# 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 container
docker 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 chart
helm repo add datadog https://helm.datadoghq.com
helm 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 ทำงานอยู่หรือเปล่า” ได้เกือบทุกครั้ง

Terminal window
# Full status: which checks ran, when, any errors, each component process's health
sudo 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 postgres

status คือคำสั่งแรกที่ควรรันเมื่อ metric ดูเหมือนหายไป — พิสูจน์ด้านบน มันโชว์เวลารันล่าสุดของทุก check, loading error (เคส redis เทียบ redisdb ด้านบน) และสถานะ reachability ของแต่ละ component process check <name> คือเครื่องมือสำหรับวน iterate config ของ integration ตัวเดียวโดยไม่ต้องรอรอบถัดไป

🐛 หา bug ในโค้ดนี้

# AI comment: "Autodiscovery config for the orders Redis cache"
apiVersion: v1
kind: Pod
metadata:
name: orders-cache
annotations:
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/)

ลองนึกภาพการติดตั้ง 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) มันไม่ถูกตีกลับหาผู้ส่ง — มันแค่ไม่มาถึงเลย และไม่มีอะไรบอกคุณ

  • 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 — พิสูจน์ด้านบน ทั้งสามเหมือนกันวันนี้; 7 update ตัวเองภายใน 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 แพงกว่ามากในการหา
  • “Datadog Agent เป็น process เดียว” ผิด — พิสูจน์ด้านบน: ps aux ใน container จริงโชว์ entry s6-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, Operator v1.30.0 ทั้งคู่ release ภายในไม่กี่สัปดาห์ก่อนเขียนบทนี้) ใช้ manifest shape ต่างกันสำหรับ Agent ตัวเดียวกัน manifest ที่เขียนให้ตัวหนึ่งไม่ valid สำหรับอีกตัว พิสูจน์ด้านบนด้วย kubeconform reject จริงแบบเข้มงวด
  • “docker pull datadog/agent:7 ได้ image เดิมเสมอ” ผิด — พิสูจน์โดยนิยามด้านบน: tag 7 ลอยไปที่ release 7.x ล่าสุดทุกครั้งที่ pull ตอนที่เขียนบทนี้มันตรงกับ 7.83.3 แต่จะไม่ตรงตลอดไป ต่างจาก patch tag ที่ pin ไว้
process ที่ทำงานร่วมกันแยกกันของ "Datadog Agent" บน Kubernetes cluster มีกี่ตัว และตัวไหนที่เป็นระดับ cluster ไม่ใช่ต่อ node
fence conf.d/*.d/conf.yaml ที่พังจริงเขียน instances: เป็น mapping เปล่า ๆ แทนที่จะเป็น list agent configcheck จริงรายงานอะไร
พิสูจน์ด้านบนด้วย container ที่ใส่ label จริงสามตัว เกิดอะไรขึ้นกับ container ที่ label key เป็น com.datadoghq.ad.check (เอกพจน์) แทนที่จะเป็น com.datadoghq.ad.checks
container ถูกแปะ label ด้วยชื่อ check JSON "redis" (ไม่ใช่ "redisdb") โดยใช้ key com.datadoghq.ad.checks ที่ถูกต้อง container จริงของบทนี้พิสูจน์ว่าอะไรเกิดขึ้น
พิสูจน์ด้านบนด้วยการรัน kubeconform จริงกับ CRD schema v2alpha1 จริงของ Datadog Operator เกิดอะไรขึ้นกับ manifest DatadogAgent ที่ใช้ shape เก่า spec.agent:
ข้อเท็จจริงที่เอกสารยืนยันจริงข้อไหนที่แก้การลดรูปเกินไปของ "Agent 6 เทียบ 7" legacy pattern ทั่วไป