Promeetheus Agent를 사용하여 ECS Fargate 메트릭을 AMP에 전송하고 Grafana에서 모니터링

개시하다


이 글은 AWS Advent Calendar 2021의 다섯째 날의 글이다.
Fargate 노드에 있습니다.js가 응용한 양도Prometheus Agent를 사이드카 컨테이너로 이동하여 Amazon Managed Service for Prometheus (AMP)에 전송Grafana에서 볼 수 있다.
참고로 Promeethus Agent는 아직 실험적 기능 없기 때문에 실제 업무에서 사용하는 것을 추천하지 않습니다.
본 보도의 환경 구축은 AWS CDK을 이용했다.

작업 환경

  • Node.js v16.13.0
  • AWS CDK 2.0.0 (build 4b6ce31)
  • Prometheus 2.32.1
  • 환경 구조


    환경 구축을 즉시 추진하다.AMP는 아직 CDK에서 조작할 수 없기 때문에 AWS 콘솔에서 수동으로 작업공간을 제작한다.(2021/12/06)
    aws-aps AWS CDK를 사용해서도 아마존 Managed Service for Promeetheus를 제작하는 작업공간을 확인했기 때문에 추천합니다..🙇🙇
    lib/prometheus-agent-test-stack.ts의 코드도 수정되어 AWS CDK에서 Amazon Managed Service for Proometheus를 만드는 작업 공간으로 편집되었습니다.(2021/12/18 보충)
    AMP 작업공간을 수동으로 작성하려면
    먼저 작업공간을 만들기 위해 AMP 콘솔 화면로 마이그레이션합니다.
    AMP のコンソール画面からワークスペースを作成する
    1. AMP 콘솔 화면에서 작업공간으로 이동하여 화면 만들기
    2. AMP のワークスペースを作成する
    2. AMP의 작업공간 만들기
    3. AMP のワークスペース作成完了と同時に設定値を控えておく
    3. AMP의 작업공간 제작 완료를 확인하면서 설정 값을 제어합니다.
    AMP 작업공간エンドポイント - リモート書き込み URL은 Promoetheus Agent를 통해 AMP에 데이터를 보낼 때나Grafana에 데이터 원본을 등록할 때 필요하기 때문에 제어가 필요하다.

    AWS CDK로 환경 구축


    CDK로 구축 작업을 추진하다.먼저 다음 명령을 사용하여 CDK 프로젝트를 만듭니다.언어 선택TypeScript을 사용합니다.
    mkdir prometheus-agent-test && cd prometheus-agent-test
    cdk init --language typescript
    
    먼저 CDK가 인프라 시설을 건설하기 전에 수집 테스트의 노드를 측정하는 데 사용한다.js 프로그램을 준비합니다.

    ECS Fargate가 시작되는 노드입니다.js 응용 프로그램 준비


    이용prom-client, 노드.js 도량의 노드를 얻을 수 있습니다.js 프로그램을 준비합니다.prometheus-agent-test 폴더에서 다음 명령을 실행합니다.
    mkdir metrics-app && cd metrics-app
    npm init -y
    npm install --save prom-client
    
    다음metrics-app 폴더에 만들기index.js 다음 내용을 편집합니다.
    metrics-app/index.js
    'use strict';
    
    const http = require('http');
    const server = http.createServer();
    
    const client = require('prom-client');
    const register = new client.Registry()
    
    // 5秒間隔でメトリクスを取得する
    client.collectDefaultMetrics({ register, timeout: 5 * 1000 });
    
    server.on('request', async function(req, res) {
        // /metrics にアクセスしたら、Prometheus のレポートを返す
        if (req.url === '/metrics') {
            res.setHeader('Content-Type', register.contentType)
    
            const metrics = await register.metrics()
            return res.end(metrics)
        } else {
            return res.writeHead(404, {'Content-Type' : 'text/plain'});
        }
    });
    
    server.listen(8080);
    
    node index.js 명령을 실행하고 방문해 보세요http://localhost:8080/metrics.아래의 각종 양도 출력의 상황을 확인할 수 있다면 OK입니다.
    Prometheus のレポートが正常に出力されている様子
    Promeetheus의 보고서가 정상적으로 출력되는 모습
    이번에는 ECS에서 노드를js 응용 프로그램의 동작을 위해 Dockerfile도 제작합니다.
    metrics-app/Dockerfile
    FROM public.ecr.aws/docker/library/node:16-alpine3.12 AS builder
    
    EXPOSE 8080
    WORKDIR /usr/src/app
    
    COPY package*.json ./
    RUN npm install --max-old-space-size=4096
    
    COPY . .
    
    CMD [ "node", "index.js" ]
    
    Dockerfile를 제작한 후 동작을 재검증하기 위해 아래 명령을 실행한 후 방문http://localhost:8080/metrics을 시도한다.
    docker build -t prometheus-agent-test/metrics-app .
    docker run -p 8080:8080 prometheus-agent-test/metrics-app:latest
    
    아까와 같은http://localhost:8080/metrics 방문 시 각종 도량 출력을 확인할 수 있으면 OK.

    Node.js 애플리케이션을 모니터링할 Promeetheus Agent 준비


    먼저 Promaetheus 관련 파일을 구성하는 폴더를 만듭니다.prometheus-agent-test 폴더에서 다음 명령을 실행합니다.
    mkdir prometheus-agent && cd prometheus-agent
    
    Proometheus의 설정 템플릿 파일을 생성합니다.템플릿 파일sed을 이용하여 내용을 다시 쓴다__TASK_ID____REMOTE_WRITE_URL__.
    prometheus-agent/prometheus.tmpl.yml
    global:
      scrape_interval: 5s
      external_labels:
        monitor: 'prometheus'
    
    scrape_configs:
      - job_name: 'prometheus-agent-test'
        static_configs:
          - targets: ['localhost:8080']
            labels:
              # デフォルトの localhost:8080 がインスタンスとして利用されると、
              # メトリクスの判別がしづらくなるため ECS Task の ID を利用する
              instance: '__TASK_ID__'
    
    remote_write:
      # AMP ワークスペース作成時に控えておいた、
      # `エンドポイント - リモート書き込み URL` を設定する箇所
      - url: '__REMOTE_WRITE_URL__'
        sigv4:
          region: ap-northeast-1
        queue_config:
          max_samples_per_send: 1000
          max_shards: 200
          capacity: 2500
    
    
    설정 파일 제작이 완료되면 템플릿 파일을 이용하여 Proometheus의 설정 파일을 만들고 Proometheus Agent를 시작하는 하우징 스크립트를 만듭니다.
    prometheus-agent/docker-entrypoint.sh
    #!/bin/sh
    
    while [ -z "$taskId" ]
    do
      # ECS Fargate で起動したタスク ID を取得する
      taskId=$(curl --silent ${ECS_CONTAINER_METADATA_URI}/task | jq -r '.TaskARN | split("/") | .[-1]')
    
      echo "waiting..."
      sleep 1
    done
    
    echo "taskId: ${taskId}"
    echo "remoteWriteUrl: ${REMOTE_WRITE_URL}"
    
    # タスク ID `taskId` および、環境変数 `REMOTE_WRITE_URL` で、
    # Prometheus のテンプレートファイル `prometheus.tmpl.yml` の内容を書き換え、
    # その結果を `/etc/prometheus/prometheus.yml` に出力する
    cat /etc/prometheus/prometheus.tmpl.yml | \
        sed "s/__TASK_ID__/${taskId}/g" | \
        sed "s>__REMOTE_WRITE_URL__>${REMOTE_WRITE_URL}>g" > /etc/prometheus/prometheus.yml
    
    # --enable-feature=agent で Prometheus を Agent モードで起動する
    # Prometheus のコンフィグファイルには上記で出力した `/etc/prometheus/prometheus.yml` を利用する
    /usr/local/bin/prometheus \
        --enable-feature=agent \
        --config.file=/etc/prometheus/prometheus.yml \
        --web.console.libraries=/etc/prometheus/console_libraries \
        --web.console.templates=/etc/prometheus/consoles
    
    
    이렇게 되면 Promeetheus Agent의 시작 준비가 완료되고 최종 준비가 완료됩니다Dockerfile.참고로 Proometheus Agentv2.32.0는 나중에 사용할 수 있습니다.이 기사는 v2.32.1를 사용합니다.
    prometheus-agent/Dockerfile
    FROM --platform=arm64 alpine:3.15
    
    ADD prometheus.tmpl.yml /etc/prometheus/
    
    RUN apk add --update --no-cache jq sed curl
    
    # ARM64 で動作する Prometheus v2.32.1 を curl でダウンロード展開する
    RUN curl -sL -O https://github.com/prometheus/prometheus/releases/download/v2.32.1/prometheus-2.32.1.linux-arm64.tar.gz
    RUN tar -zxvf prometheus-2.32.1.linux-arm64.tar.gz && rm prometheus-2.32.1.linux-arm64.tar.gz
    
    # `prometheus` コマンドを `/usr/local/bin/prometheus` に移動する
    RUN mv prometheus-2.32.1.linux-arm64/prometheus /usr/local/bin/prometheus
    
    COPY ./docker-entrypoint.sh /
    RUN chmod +x /docker-entrypoint.sh
    CMD ["/docker-entrypoint.sh"]
    
    CDK는 지금까지 인프라 정비 추진을 위한 사전 준비를 마쳤다.

    ECS Fargate 상위 노드js 애플리케이션 및 Promeetheus Agent 실행


    그리고 CDK가 ECS Fargate에서 Node를js 애플리케이션과 Promeetheus Agent,Grafana의 운영 환경을 정비하기 위해
    다시 쓰기lib/prometheus-agent-test-stack.ts의 내용.
    lib/prometheus-agent-test-stack.ts
    import { Construct } from 'constructs';
    import {
      Stack,
      StackProps,
      aws_ecs as ecs,
      aws_logs as logs,
      aws_aps as aps,
      aws_ecs_patterns as ecs_patterns,
      aws_iam as iam,
      aws_elasticloadbalancingv2 as elbv2,
      Duration,
      CfnOutput,
    } from 'aws-cdk-lib';
    
    export class PrometheusAgentTestStack extends Stack {
      constructor(scope: Construct, id: string, props?: StackProps) {
        super(scope, id, props);
    
        // Node.js アプリに ecs_patterns.ApplicationLoadBalancedFargateService を利用して ALB 経由でアクセス可能にする
        const projectName = 'prometheus-agent-test';
        const fargateService = new ecs_patterns.ApplicationLoadBalancedFargateService(this, `${projectName}-fargate-service`, {
          serviceName: `${projectName}-fargate-service`,
          cpu: 256,
          desiredCount: 3,
          listenerPort: 80,
          taskImageOptions: {
            family: `${projectName}-taskdef`,
            image: ecs.ContainerImage.fromAsset('metrics-app'),
            containerPort: 8080,
            logDriver: ecs.LogDrivers.awsLogs({
              streamPrefix: `/${projectName}/metrics-app`,
              logRetention: logs.RetentionDays.ONE_DAY
            })
          },
          cluster: new ecs.Cluster(this, `${projectName}-cluster`, {
            clusterName: `${projectName}-cluster`
          }),
          memoryLimitMiB: 512,
        });
        fargateService.targetGroup.configureHealthCheck({
          path: "/metrics",
          timeout: Duration.seconds(8),
          interval: Duration.seconds(10),
          healthyThresholdCount: 2,
          unhealthyThresholdCount: 4,
          healthyHttpCodes: "200",
        });
    
        // 本質ではないが、Gravition2 で動作させたいために RuntimePlatform のプロパティを上書きしている
        const fargateServiceTaskdef = fargateService.taskDefinition.node.defaultChild as ecs.CfnTaskDefinition
        fargateServiceTaskdef.addPropertyOverride('RuntimePlatform', {
          CpuArchitecture: "ARM64",
          OperatingSystemFamily: "LINUX"
        });
    
        // AMP への書き込み権限を付与する
        fargateService.taskDefinition.taskRole.addManagedPolicy(
          iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonPrometheusRemoteWriteAccess')
        )
    
        // (2021/12/18) Amazon Managed Service for Prometheus のワークスペースを作成して、Prometheus の remote-write URL を取得する
        const apsWorkspace = new aps.CfnWorkspace(this, `${projectName}-prom-workspace`, {
          alias: `${projectName}-prom-workspace`,
        });
        const apsWorkspaceRemoteUrl = `${apsWorkspace.attrPrometheusEndpoint}api/v1/remote_write`;
    
        // (2021/12/18) 本記事で頻出する "エンドポイント - リモート書き込み URL" をコンソールに出力する
        new CfnOutput(this, 'prom-remote-write-url', {
          value: apsWorkspaceRemoteUrl,
          description: 'Prometheus Workspace の remote-write URL',
          exportName: 'PromRemoteWriteURL',
        });
    
        // AMP へメトリクス情報を送信するための Prometheus Agent コンテナを追加する
        const containerName = `${projectName}-prometheus-agent`
        fargateService.taskDefinition.addContainer(containerName, {
          containerName,
          image: ecs.ContainerImage.fromAsset('prometheus-agent'),
          memoryReservationMiB: 128,
          environment: {
            // (2021/12/18) CDK 経由で作成した Prometheus の remote-write URL を設定する
            REMOTE_WRITE_URL: apsWorkspaceRemoteUrl
          },
          logging: new ecs.AwsLogDriver({
            streamPrefix: `/${projectName}/prometheus-agent`,
            logRetention: logs.RetentionDays.ONE_DAY,
          })
        });
    
        // Grafana のタスク定義を作成する
        const grafanaDashboardTaskDefinition = new ecs.FargateTaskDefinition(this, `${projectName}-grafana-taskdef`, {
          family: `${projectName}-grafana-taskdef`
        });
        // Grafana のタスクが Prometheus Query を叩けるように権限付与する
        grafanaDashboardTaskDefinition.taskRole.addManagedPolicy(
          iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonPrometheusQueryAccess')
        )
    
        // Grafana のコンテナを追加する。パスプレフィクスには dashboard を設定する
        const grafanaDashboardContainerName = `${projectName}-grafana-dashboard`
        grafanaDashboardTaskDefinition.addContainer(grafanaDashboardContainerName, {
          containerName: grafanaDashboardContainerName,
          image: ecs.ContainerImage.fromRegistry('public.ecr.aws/ubuntu/grafana'),
          environment: {
            AWS_SDK_LOAD_CONFIG: 'true',
            GF_AUTH_SIGV4_AUTH_ENABLED: 'true',
            GF_SERVER_SERVE_FROM_SUB_PATH: 'true',
            GF_SERVER_ROOT_URL: '%(protocol)s://%(domain)s/dashboard'
          },
          portMappings: [{ containerPort: 3000 }],
          memoryLimitMiB: 512,
          logging: new ecs.AwsLogDriver({
            streamPrefix: `/${projectName}/grafana-dashboard`,
            logRetention: logs.RetentionDays.ONE_DAY,
          })
        });
    
        const grafanaDashboardServiceName = `${projectName}-grafana-dashboard-service`
        const grafanaDashboardService = new ecs.FargateService(this, grafanaDashboardServiceName, {
          serviceName: grafanaDashboardServiceName,
          cluster: fargateService.cluster,
          taskDefinition: grafanaDashboardTaskDefinition,
          desiredCount: 1
        });
    
        // Grafana のタスクを ALB のターゲットグループに紐づける
        fargateService.listener.addTargets(`${projectName}-grafana-dashboard-target`, {
          priority: 1,
          conditions: [
            elbv2.ListenerCondition.pathPatterns(['/dashboard/*']),
          ],
          healthCheck: {
            path: '/dashboard/login',
            interval: Duration.seconds(10),
            timeout: Duration.seconds(8),
            healthyThresholdCount: 2,
            unhealthyThresholdCount: 3,
            healthyHttpCodes: "200"
          },
          port: 3000,
          protocol: elbv2.ApplicationProtocol.HTTP,
          targets: [grafanaDashboardService],
        });
      }
    }
    
    
    이후 cdk deploy 인프라 시설을 건설한다.
    CDK によるインフラ構築が正常に実行された時の様子
    CDK의 인프라 시설 건설이 정상적으로 실시되었을 때의 상황
    depuro가 정상적으로 완료되었음을 확인한 후 Outputs 출력된 PrometheusAgentTestStack.prometheusagenttestfargateserviceServiceURL<識別子>의 URL 끝에 부여/metrics에 접근해 보십시오.출력된 URL 형식은 http://<識別子>.ap-northeast-1.elb.amazonaws.com입니다.
    방문http://<識別子>.ap-northeast-1.elb.amazonaws.com/metrics이라는 것이다.
    ALB 経由で Node.js アプリにアクセス可能なことを確認する
    ALB 노드를 경유합니다.js 응용 프로그램에 접근할 수 있는지 확인
    또한 Outputs에 출력된 PrometheusAgentTestStack.promremotewriteurl는 이후 사용エンドポイント - リモート書き込み URL할 때 사용되므로 제어해 주십시오.
    이로써 AWS CDK의 인프라 구축 작업은 완료됐다.마지막으로 Grafana에서 AMP의 메트릭을 시각화하는 작업을 진행합니다.

    Grafana에서 AMP(Aroometheus)의 메트릭 시각화


    이전 액세스/metrics 경로와 마찬가지로 출력Outputs된 URL의 끝에 액세스/dashboard/login를 추가합니다.Grafana의 초기 사용자 및 비밀번호는 admin입니다.
    즉, 방문을 시도해 본다http://<識別子>.ap-northeast-1.elb.amazonaws.com/dashboard/login.
    ログインを行う
    로그인 정보가 정확하면 새 비밀번호를 설정하는 화면으로 이동하고 새 비밀번호를 입력하여 로그인을 종료합니다.로그인한 후 Promaetheus(AMP)를 데이터 소스로 추가하려면 다음과 같이 하십시오.
    1. 歯車アイコンをクリックして  をクリックする
    1. 톱니바퀴 아이콘Data sources을 클릭
    2.  ボタンをクリックする
    2.Add data source버튼 클릭
    3. データソースとして Prometheus を選択する
    3. Promaetheus를 데이터 소스로 선택
    4. Prometheus をデータソースとして追加する
    4. Prometheus をデータソースとして追加する
    4. Prometheus をデータソースとして追加する
    4. Proometheus를 데이터 소스로 추가
    그래파나로 Promeetheus(AMP)에 보내는 메트릭을 시각화할 준비가 됐기 때문에 실제로 그래파나의 대시보드로 메트릭을 시각화해 보았다.빠른 가시화 양도를 위해 계기판NodeJS Application Dashboard을 사용합니다.
    1. + アイコンをクリックして、 をクリックする
    1.클릭+아이콘, 클릭Import2.  の ID を入力して  ボタンをクリックする
    2. NodeJS Application Dashboard의 ID를 입력하고 Load 버튼을 클릭
    3. 必要な情報を入力して  のインポートを完了する
    3. 필요한 정보를 입력하고 NodeJS Application Dashboard 가져오기 완료
    4. ダッシュボードから Prometheus のメトリクスが確認できる
    4. 대시보드의 Nodejs 프로그램의 양도를 확인할 수 있습니다
    지금까지의 절차는 양도의 가시화를 완성했지만 부하의 실제 양도 변화 상황에 따라 확인해 보았다.사용Vegeta실제 부하.다음 명령을 실행합니다.
    echo 'GET http://<識別子>.ap-northeast-1.elb.amazonaws.com/metrics' | vegeta attack -duration=5s | vegeta report
    
    이후 다시 Grafana의 계기판을 보러 갔다.부하를 가하는 시간대 도표만 달라질 수 있다는 것을 확인할 수 있을 것이다.
    ダッシュボードの CPU 使用率のグラフに変化があったことを確認できる
    대시보드의 CPU 사용률 차트가 변경되었는지 확인할 수 있습니다.

    끝말


    이번에는 Amazon Managed Service for Proometheus(AMP)에 ECS Fargate의 메트릭을 보내고Grafana로 시각화하는 방법을 소개했다.
    ECS의 서비스에서 작업을 수행할 때서비스 할인를 사용할 수 있기 때문에Promoetheus서비스 할인 설정를 실행하면 모든 용기의 도량을 단일 Promoetheus로 처리할 수 있습니다.
    또 노드야.js 프로그램을 제작할 때 사용하는 prom-client에서 제작레이어드 스케일하면 감시하고 싶은 항목을 자유롭게 추가할 수 있습니다.
    이번 보도가 ECS Fargate를 감시할 때 논의 자료 중 하나가 되면 좋겠다.

    참조 링크

  • AWS Fargate(서버 및 클러스터를 관리할 필요가 없는 컨테이너 사용)|AWS
  • Introducing Prometheus Agent Mode, an Efficient and Cloud-Native Way for Metric Forwarding | Prometheus
  • Amazon Managed Service for Promeetheus | 전체 관리 Promeetheus | Amazon 웹 서비스
  • Grafana: The open observability platform | Grafana Labs
  • AWS 클라우드 개발 키트 – 아마존 웹 서비스
  • siimon/prom-client: Prometheus client for node.js
  • tsenart/vegeta: HTTP load testing tool and library. It's over 9000!
  • NodeJS Application Dashboard dashboard for Grafana | Grafana Labs
  • 좋은 웹페이지 즐겨찾기