Production Rollout Checklist
The idea in one sentence
Section titled “The idea in one sentence”Going to production with Datadog is a checklist, not a single switch, and every item on it traces back to a decision this course already taught you how to make — from Foundations tagging, through Infrastructure & Metrics, Log Management, APM & Distributed Tracing, Monitors/Alerting/SLOs, and Correlating Signals.
Tagging and ownership, first because everything else depends on it
Section titled “Tagging and ownership, first because everything else depends on it”- Unified service tagging is consistent everywhere.
env,service, andversionare applied the same way across Agent configuration, APM tracer setup, and everylogs:source — this is the Foundations-module tagging model that lets a log line, a trace, and a metric correlate back to one deployable unit. Fixing this after go-live means every dashboard and monitor built in the meantime silently missed some of your telemetry. - Service Catalog entries exist and are accurate. Every service that will page someone has a Service Catalog entry with real ownership: which team, which escalation path, which links to runbooks. This is what the Correlating Signals module set up, and it’s the difference between an alert reaching the on-call engineer and an alert reaching a stale mailing list.
The unified tagging checklist, item by item
Section titled “The unified tagging checklist, item by item”From https://docs.datadoghq.com/getting_started/tagging/unified_service_tagging/:
- The three reserved tags are
env,serviceandversion, mapped toDD_ENV,DD_SERVICEandDD_VERSION. - “In containerized environments,
env,service, andversionare set through the service’s environment variables or labels (for example, Kubernetes deployment and pod labels, Docker container labels). The Datadog Agent detects this tagging configuration and applies it to the data it collects from containers.” - On Kubernetes, “To get the full range of unified service tagging in Kubernetes, add the following labels to both the parent workload and the pod template”:
tags.datadoghq.com/env,tags.datadoghq.com/service,tags.datadoghq.com/version. The pod-level-metrics variant says to add the labels “to the pod spec, as well as optionally to the parent workload”. DD_ENV/DD_SERVICE/DD_VERSIONon the application are “only required if you are using APM in your applications”.- With Docker, “make sure the Agent can access your container’s Docker socket”.
- “On ECS Fargate, you must add these tags to your application container, not the Datadog Agent container.”
version“is expected to change with each new application deployment”.- A global
envtag on the Agent plus a differentenvon a pod means “that pod’s data contains bothenvtags” (same page). Pick one owner forenv.
Point 2 is the one that can be proven without a cluster. I started an Agent with the Docker socket mounted read-only (-e DD_ENV=prod -e DD_TAGS=team:checkout on the Agent itself) and two throwaway containers, one with all three variables and one where DD_SERVICE was misspelled DD_SERVCE:
$ docker exec dd-production agent status | grep -A3 "host tags" host tags: env:prod team:checkout
$ docker exec dd-production agent tagger-list # container_id shortenedTags: [container_id:<id> container_name:dd-production-good docker_image:busybox env:prod image_name:busybox service:checkout-api short_image:busybox version:1.4.2]Tags: [container_id:<id> container_name:dd-production-partial docker_image:busybox env:prod image_name:busybox short_image:busybox]Two facts fall out. First, the Agent turned DD_ENV/DD_SERVICE/DD_VERSION inside the container into env:/service:/version: tags without any tracer being involved. Second, the misspelled DD_SERVCE produced no error, no warning and no service: tag at all; the container just shows up half-tagged. The Agent’s own DD_ENV became a host-level tag, but there is no equivalent Agent-level DD_SERVICE host tag in agent status — service and version belong to the workload, not the host.
On Kubernetes the same information arrives through pod labels and the container env. A Deployment that satisfies the docs’ “full configuration” (this validates against the upstream Kubernetes schema):
apiVersion: apps/v1kind: Deploymentmetadata: name: checkout-api labels: tags.datadoghq.com/env: "prod" tags.datadoghq.com/service: "checkout-api" tags.datadoghq.com/version: "1.4.2"spec: replicas: 2 selector: matchLabels: app: checkout-api template: metadata: labels: app: checkout-api tags.datadoghq.com/env: "prod" tags.datadoghq.com/service: "checkout-api" tags.datadoghq.com/version: "1.4.2" spec: containers: - name: checkout-api image: registry.example.com/checkout-api:1.4.2 env: - name: DD_ENV valueFrom: fieldRef: fieldPath: metadata.labels['tags.datadoghq.com/env'] - name: DD_SERVICE valueFrom: fieldRef: fieldPath: metadata.labels['tags.datadoghq.com/service'] - name: DD_VERSION valueFrom: fieldRef: fieldPath: metadata.labels['tags.datadoghq.com/version']The fieldRef env vars read from the pod’s own labels, so there is one place to change a value. This is the docs’ own pattern; the pod-level reading of those labels by the Agent needs a live cluster and was not run here.
Kubernetes install: Datadog Operator or Helm
Section titled “Kubernetes install: Datadog Operator or Helm”The install page (https://docs.datadoghq.com/containers/kubernetes/installation/) lists three methods and marks one: “Datadog Operator (recommended): a Kubernetes operator that you can use to deploy the Datadog Agent on Kubernetes and OpenShift. It reports deployment status, health, and errors in its Custom Resource status, and it limits the risk of misconfiguration thanks to higher-level configuration options.” The other two are Helm and manual DaemonSet installation. Note that the Operator’s own install commands use Helm (helm install datadog-operator datadog/datadog-operator) — the choice is between managing the Agent with a DatadogAgent resource and managing it with the datadog/datadog chart’s values, not between “Helm” and “no Helm”. The docs give no feature-parity table between the two and this lesson does not invent one.
Same intent, both ways. The Operator form (a DatadogAgent, collected as a k8s fence):
apiVersion: datadoghq.com/v2alpha1kind: DatadogAgentmetadata: name: datadogspec: global: clusterName: checkout-prod site: datadoghq.com credentials: apiSecret: secretName: datadog-secret keyName: api-key tags: - "env:prod" podLabelsAsTags: app.kubernetes.io/team: team features: apm: enabled: true logCollection: enabled: true containerCollectAll: trueThe Helm form (values for the datadog/datadog chart, not a Kubernetes object, so it is deliberately not a collected k8s/ fence):
# helm values for datadog/datadog (not collected by the k8s harness)datadog: apiKeyExistingSecret: datadog-secret clusterName: checkout-prod site: datadoghq.com tags: - "env:prod" podLabelsAsTags: app.kubernetes.io/team: team apm: portEnabled: true logs: enabled: true containerCollectAll: truehelm template datadog datadog/datadog --version 3.250.3 -f values.yaml exits 0 and the rendered Agent DaemonSet carries DD_CLUSTER_NAME=checkout-prod, DD_TAGS=["env:prod"], DD_KUBERNETES_POD_LABELS_AS_TAGS={"app.kubernetes.io/team":"team"}, DD_APM_ENABLED=true and DD_LOGS_CONFIG_CONTAINER_COLLECT_ALL=true. The DatadogAgent fence validates against the v2alpha1 schema from the Operator repo at v1.30.0 (the schema sets additionalProperties: false, so unknown keys are rejected).
Now the difference that matters for review. Misspell two keys in each (clusterName to cluster_name, containerCollectAll to collectAll):
# DatadogAgent, validated against the v2alpha1 schemaERR spec/features/logCollection - Additional properties are not allowed ('collectAll' was unexpected)ERR spec/global - Additional properties are not allowed ('cluster_name' was unexpected)
# Helm values, helm template datadog/datadog 3.250.3exit code 0DD_CLUSTER_NAME occurrences in rendered output: 0DD_LOGS_CONFIG_CONTAINER_COLLECT_ALL: "false"The Operator side rejects both typos. The Helm side accepted both, dropped the cluster name entirely, and left container log collection at the chart default "false" while logs.enabled stayed true — an Agent that looks like it is collecting logs and collects none. This is a property of these two artifacts at these versions (the chart’s values.schema.json did not reject unknown keys), not a general verdict, but it is exactly the kind of bug an AI-written values file carries.
Trade-off summary: the Operator gives a typed, status-reporting resource and rejects unknown fields at admission; Helm has the larger install base and plain-values workflow that most existing GitOps repos already use. Whichever you pick, run the rendered or applied manifest through a schema check in CI. The docs also note that as of Operator chart version 2.19.0 the Agent Helm chart’s registryMigrationMode applies to Agent images managed by the Operator, so image-registry settings can flow between the two.
Log and metric cost, decided deliberately, not by default
Section titled “Log and metric cost, decided deliberately, not by default”- Log indexes are sized on purpose. Retention and daily quota per index reflect the actual value of that log stream, not “index everything and figure it out later” — the Log Management module’s whole point.
- Exclusion filters exist for high-volume, low-value logs before volume scales up in production, not retrofitted after the first surprising invoice.
- Log-based metrics are set up for anything you plan to exclude. If you still need counts or trends from a log stream you’re about to filter out, configure log-based metrics first — excluding the raw logs should never silently blind you to a trend you cared about.
- Custom metric tags are reviewed with cardinality in mind. High-cardinality tags like
pod_namecan still be submitted; Metrics without Limits controls which ones are actually indexed and queryable, and that choice should be deliberate before go-live, not discovered from a cost spike.
APM sampling and retention reviewed as two separate layers
Section titled “APM sampling and retention reviewed as two separate layers”- Ingestion sampling is set intentionally. This is the layer that decides how much of total trace volume reaches Datadog at all — it should be a deliberate rate, not whatever the default happened to be.
- Retention filters are reviewed separately from sampling. Confirm which traces get retained long-term regardless of sampling — for example, everything with an error, or everything above a latency threshold — and that nobody on the team is conflating “we sample less” with “we retain less.” They are two different knobs from the APM & Distributed Tracing module, and go-live is the time to check both, not just one.
Alerting wired to what actually matters
Section titled “Alerting wired to what actually matters”- SLOs are defined for the handful of services the business actually depends on — not a vanity metric copied onto every service just because it was easy to add.
- Burn-rate alerts are wired to those SLOs, so a team gets notified while there’s still error budget left to react, not after it’s already gone. This is the Monitors, Alerting, and SLOs module’s core mechanism, and it only works if it’s actually connected before go-live.
- Every monitor’s notification target is checked against the Service Catalog owner from the tagging step above, so a page reaches the team that can actually act on it.
Manage it all as code, review it like code
Section titled “Manage it all as code, review it like code”- Monitors, dashboards, and SLOs are expressed as Terraform resources —
datadog_monitor,datadog_dashboard,datadog_service_level_objective— rather than clicked together by hand, as covered earlier in this module. Validate every HCL block withterraform validateon the pinned provider in CI. terraform planruns with query validation on, as part of ordinary pull request review, before any monitor or dashboard change reaches production — the same review bar as any other infrastructure change.- RBAC is checked — see the previous lesson:
logs_modify_indexesis global, can delegateLogs Read Index DataandLogs Write Exclusion Filters, and is held by the managed Standard role by default, so “only the platform team” is something you have to make true with custom roles. - A Cloud Cost Management cost alert monitor exists for the services or accounts this rollout affects, so a cost spike gets the same alerting treatment as a latency spike, not a surprise at the end of the month.
Where Bits AI fits (docs-quoted, nothing was run)
Section titled “Where Bits AI fits (docs-quoted, nothing was run)”Everything in this section is from the docs; no Bits AI feature was used, and Datadog’s pricing and rollout status can change, so read the linked pages at go-live time.
- What it is: “Bits AI is your agentic teammate in Datadog, built to automate development, security, and operational workflows. You can chat and collaborate with Bits in real time, or delegate full tasks—like alert investigations, code fixes, or security triage—and let it take care of the details.” (
https://docs.datadoghq.com/bits_ai/) - The docs list seven features there: Bits Investigation, Bits Code, Bits Security Analyst, Bits Chat, Bits Data Analysis, Bits Detection and Bits Remediation. The page for Bits Investigation lives at the older path
bits_ai/bits_ai_sreand the blog links still say “Bits AI SRE” — a naming trap when you read older posts. - Bits Investigation: “an autonomous AI agent that investigates production issues end to end. It iteratively forms hypotheses, gathers relevant telemetry, and uses data-based reasoning to help on-call engineers pinpoint root causes.” (
https://docs.datadoghq.com/bits_ai/bits_ai_sre/) - Availability: the docs show a warning that “This product is not supported for your selected Datadog site” for
app.ddog-gov.comandus2.ddog-gov.com. - Cost: “Learn about Bits AI pricing on AI Credits” (
https://docs.datadoghq.com/account_management/billing/ai_credits/). No price is quoted here. - Wiring: its integrations page says it integrates with GitHub, Grafana, Dynatrace, Splunk, Sentry and ServiceNow, that GitHub setup includes “Tag your APM telemetry with Git information”, and that for monitor alerts, if the monitor already has
@slack,@caseor@oncallnotifications, “Bits automatically posts its findings to those destinations” (https://docs.datadoghq.com/bits_ai/bits_investigation/configure/). Microsoft Teams support is labelled Preview there.
What this means for the checklist: Bits AI reads the telemetry you already send, so it is downstream of every item above. Do not put it on the critical path for go-live; decide, per feature, whether the AI Credits cost and its access to your code and telemetry fit your data policy, and only after tagging, ownership and monitor routing are correct — those are what an investigation has to work with.
Go-Live Checklist1. Unified tagging (env/service/version) verified across Agent, APM, logs; pod template labels present2. Service Catalog ownership accurate for every paging service3. Kubernetes install method chosen (Operator or Helm) and the manifest/values schema-checked in CI4. Log indexes and exclusion filters sized deliberately; log-based metrics set up first5. Custom metric tag cardinality reviewed via Metrics without Limits6. APM ingestion sampling and retention filters reviewed as two separate layers7. SLOs and burn-rate alerts wired to business-critical services only8. Monitor notification targets checked against Service Catalog owners9. Monitors/dashboards/SLOs as Terraform code, reviewed via PR with query validation on10. RBAC checked: logs_modify_indexes and exclusion/archive rights on custom roles, read access broad11. Cloud Cost Management cost alert in place for the affected services/accounts12. Optional: Bits AI features evaluated against cost (AI Credits) and data policyflowchart LR A[Tagging and ownership] --> K["Kubernetes install: Operator or Helm"] K --> B[Log and metric cost decisions] B --> C[APM sampling and retention review] C --> D[SLOs and burn-rate alerting] D --> E[Infrastructure as code review] E --> F[Go-live] F -.optional.-> I["Bits AI evaluation"] A -.Service Catalog owner.-> D B -.cost alert monitor.-> E
Reading AI-generated code
Section titled “Reading AI-generated code”🐛 Spot the bug
# AI comment: "Unified service tagging for checkout-api"apiVersion: apps/v1kind: Deploymentmetadata:name: checkout-apilabels: tags.datadoghq.com/env: "prod" tags.datadoghq.com/service: "checkout-api" tags.datadoghq.com/version: "1.4.2"spec:replicas: 2selector: matchLabels: app: checkout-apitemplate: metadata: labels: app: checkout-api spec: containers: - name: checkout-api image: registry.example.com/checkout-api:1.4.2Show the answer
This is a valid Deployment — it passes the Kubernetes schema — and it looks tagged. The labels are only on the Deployment’s own metadata. The Datadog docs ask for them “on both the parent workload and the pod template” for full configuration, and for the pod-level path they are required on the pod spec while the parent workload is optional. Labels on metadata.labels of a Deployment are not copied onto its pods, so the pods that the Agent actually sees carry no tags.datadoghq.com/* labels (this is standard Kubernetes behaviour, not something this lesson ran against a cluster). The fix is the manifest shown earlier in this lesson: the same three labels under spec.template.metadata.labels, plus DD_ENV/DD_SERVICE/DD_VERSION from fieldRef if the app uses APM.
apiVersion: apps/v1kind: Deploymentmetadata: name: checkout-api labels: tags.datadoghq.com/env: "prod" tags.datadoghq.com/service: "checkout-api" tags.datadoghq.com/version: "1.4.2"spec: replicas: 2 selector: matchLabels: app: checkout-api template: metadata: labels: app: checkout-api tags.datadoghq.com/env: "prod" tags.datadoghq.com/service: "checkout-api" tags.datadoghq.com/version: "1.4.2" spec: containers: - name: checkout-api image: registry.example.com/checkout-api:1.4.2Mental Model
Section titled “Mental Model”A go-live checklist is a dependency graph, not a to-do list. Tags are the join key for logs, traces and metrics, so they come first; ownership is the join key for alerts and people; the install method decides how the Agent gets those tags; cost and sampling decide what you keep; SLOs and alerts decide who is woken; Terraform and RBAC decide who can change any of it. Bits AI sits on top: it consumes what the lower layers produce, so it inherits their quality and their gaps.
Trade-offs
Section titled “Trade-offs”- Operator vs Helm — the docs recommend the Operator and it rejected unknown fields in the check above; Helm is the more common existing workflow and, at chart
3.250.3, silently ignored unknown keys. Switching costs an install-path migration, so pick before go-live, not after. - Labels on both workload and pod template vs pod template only — both is the docs’ “full configuration”; pod-only is the docs’ minimum for pod-level metrics. Extra labels cost a few lines and keep the Deployment queryable by the same tags.
- Adopting Bits AI early vs later — earlier gives on-call help sooner but adds an AI Credits cost line and grants access to code and telemetry (per its integration docs); later lets you fix tagging and routing first. The docs quote no price, so the cost side is unknown until you check your account.
- Schema-checking manifests in CI vs trusting the install command — a schema check costs a pipeline step and catches the silent-typo class that both the Helm run and the misspelled
DD_SERVCEcontainer demonstrated.
Common Misconceptions
Section titled “Common Misconceptions”- “If the Deployment has the labels, the pods are tagged.” Docs require the pod template; a Deployment’s own labels are not pod labels.
- “Helm will complain if I mistype a values key.” At chart
3.250.3helm templateexited 0 and dropped the mistyped keys; the Operator’s schema rejected them. - “The Operator replaces Helm.” The documented Operator install itself runs
helm install datadog-operator datadog/datadog-operator; it replaces thedatadog/datadogchart’s values with aDatadogAgentresource. - “Setting
DD_ENVon the Agent tags everything correctly.” It becomes a host-level tag (agent statusshowsenv:prod), and the docs warn that a differentenvon a pod yields both tags on that pod’s data. - “Bits AI SRE is a separate product from Bits Investigation.” The docs page titled Bits Investigation sits at the
bits_ai_srepath; older posts use the earlier name.