我是一個人
我們最近上線了一個新應用,想引入外部監控。我們一直在糾結是使用 N 公司的服務還是完全在 AWS 內部部署,最後我們決定使用Datadog 。
即使在網上搜尋之後,我仍然找不到太多關於如何使用Next.js + ECS Fargate配置安裝 Datadog 的訊息,所以我將記錄我實際採取的步驟。
我想將我的應用程式日誌和APM 資料都傳送到 Datadog。
由於現有的基礎設施是使用CDK進行管理的,我們希望使用CDK來建立合適的架構。
從 ECS 連線時,您需要設定一個金鑰,但您可以從 Datadog 的「組織設定」→「API 金鑰」取得和更新金鑰。
當您第一次連線到 ECS 時,API 金鑰也會顯示在待機畫面上的設定檔中。
部署 Secrets Manager 後,新增您獲得的金鑰。
// Datadog API キー用シークレットの作成
const datadogSecret = new secretsmanager.Secret(this, 'DatadogSecret', {
secretName: `${props.envName}-${props.projectName}-datadog-api-key`,
description: 'Datadog API Key - Update manually after deployment',
secretStringValue: cdk.SecretValue.unsafePlainText('placeholder-update-manually'),
});
datadogSecret.applyRemovalPolicy(cdk.RemovalPolicy.RETAIN);
// タスク実行ロールにDatadogシークレットへのアクセス権限を付与
datadogSecret.grantRead(executionRole);
我們使用 FireLens,因為將 ECS 日誌直接傳送到 Datadog 比透過 CloudWatch 更便宜。
const clientContainer = serviceTaskDefinition
.addContainer('client', {
image: appImage,
logging: ecs.LogDrivers.firelens({
options: {
Name: 'datadog',
Host: 'http-intake.logs.ap1.datadoghq.com',
TLS: 'on',
dd_service: 'service_name',
dd_source: 'nodejs',
dd_tags: `env:${props.envName}`,
provider: 'ecs',
},
secretOptions: {
apikey: ecs.Secret.fromSecretsManager(datadogSecret),
},
}),
environment: {
// ... 他の環境変数
DD_ENV: props.envName,
DD_SERVICE: 'service_name',
DD_VERSION: props.imageTag,
DD_LOGS_INJECTION: 'true',
DD_AGENT_HOST: '127.0.0.1',
OTEL_TRACES_EXPORTER: 'otlp',
OTEL_EXPORTER_OTLP_PROTOCOL: 'http/protobuf',
OTEL_EXPORTER_OTLP_ENDPOINT: 'http://127.0.0.1:4318',
OTEL_SERVICE_NAME: 'service_name',
OTEL_RESOURCE_ATTRIBUTES: `deployment.environment=${props.envName},service.version=${props.imageTag}`,
},
// ...
});
DD_SITE
必須設定為您正在使用的 Datadog 的區域。
請注意,如果設定不正確,則不會發送日誌。
對於東京地區,該地址為ap1.datadoghq.com
。
const datadogLogGroup = new logs.LogGroup(this, 'DatadogLogGroup', {
logGroupName: `/aws/ecs/datadog/${props.envName}`,
retention: logs.RetentionDays.THREE_MONTHS,
removalPolicy: props.envName === 'prd' ? cdk.RemovalPolicy.RETAIN : cdk.RemovalPolicy.DESTROY,
});
const datadogContainer = serviceTaskDefinition.addContainer('datadog-agent', {
image: ecs.ContainerImage.fromRegistry('public.ecr.aws/datadog/agent:latest'),
memoryLimitMiB: 512,
containerName: 'datadog',
essential: false,
logging: ecs.LogDriver.awsLogs({
streamPrefix: 'datadog',
logGroup: datadogLogGroup,
}),
secrets: {
DD_API_KEY: ecs.Secret.fromSecretsManager(datadogSecret),
},
environment: {
ECS_FARGATE: 'true',
DD_APM_ENABLED: 'true',
DD_APM_NON_LOCAL_TRAFFIC: 'true',
DD_SITE: 'ap1.datadoghq.com',
DD_LOGS_ENABLED: 'true',
DD_LOGS_CONFIG_CONTAINER_COLLECT_ALL: 'true',
},
});
datadogContainer.addEnvironment(
'DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_HTTP_ENDPOINT',
'0.0.0.0:4318',
);
// APM用ポートマッピング追加
datadogContainer.addPortMappings({
containerPort: 4318,
protocol: ecs.Protocol.TCP,
});
serviceTaskDefinition.addFirelensLogRouter('FirelensLogRouter', {
image: ecs.ContainerImage.fromRegistry('amazon/aws-for-fluent-bit:stable'),
essential: false,
memoryReservationMiB: 50,
firelensConfig: {
type: ecs.FirelensLogRouterType.FLUENTBIT,
options: {
enableECSLogMetadata: true,
configFileType: ecs.FirelensConfigFileType.FILE,
configFileValue: '/fluent-bit/configs/parse-json.conf',
},
},
logging: ecs.LogDriver.awsLogs({
streamPrefix: 'firelens',
logGroup: logGroup,
}),
});
加入dd-trace
。由於本專案使用 Bun,因此新增方式如下:
順便說一句,Bun 用途廣泛,強烈推薦。
% bun add dd-trace
由於我們使用了 App Router,因此在src/
下建立 tracer.ts 並寫入以下程式碼。
import tracer from 'dd-trace';
tracer.init({
logInjection: true,
version: process.env.DD_VERSION,
env: process.env.DD_ENV,
service: process.env.DD_SERVICE,
});
export default tracer;
在與建立的檔案同級建立 instrumentation.ts 並從其中匯入。 instrumentation.ts 是在 Next.js 應用程式啟動時僅執行一次的文件,通常用於初始化測量和監控。
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
await import('./tracer');
}
}
透過這些設置,我能夠將日誌和 APM 從我的 Next.js 應用程式轉發到 Datadog。