EKS on Fargateのdatadogへのログ送信

# なぜ書くか/何を書くか
### なぜ？
[Amazon EKS on AWS Fargate](https://docs.datadoghq.com/ja/integrations/eks_fargate/)を参考にdatadogへのログ送信を設定していたのですが、複数のドキュメントを見なければならなかったのでメモとして残します。
同じ状況にある方の参考になれば幸いです。

### 何を？
上記ドキュメント内の「ログの収集」について記載しています。
他の収集については書きません。

# 前提
- 用語の説明はしません
- datadog-agentはサイドカーとして実行します
- Datadog側で以下の[インテグレーション](https://docs.datadoghq.com/ja/integrations/)をインストールする必要があります
    - Kubernetes
    - AWS
    - EKS
- 例で使用する名称は以下のとおりです
    - Namespace: myns
    - Serviceaccount: mysa

# サンプル
## リソースの用意
### RBACの用意
ライフサイクル的にClusterRoleとバインディングは分けていいかもしれません。
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: datadog-agent
rules:
  - apiGroups:
    - ""
    resources:
    - nodes
    - namespaces
    - endpoints
    verbs:
    - get
    - list
  - apiGroups:
      - ""
    resources:
      - nodes/metrics
      - nodes/spec
      - nodes/stats
      - nodes/proxy
      - nodes/pods
      - nodes/healthz
    verbs:
      - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: datadog-agent
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: datadog-agent
subjects:
  - kind: ServiceAccount
    name: mysa
    namespace: myns
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: mysa
  namespace: myns
```

### Agentをサイドカーとして実行
以下のマニフェストが最小設定のようです。
リソースリクエストはドキュメント同様の設定で問題なく動くはずです。
`DD_API_KEY`はちゃんと保護しましょう。

`※kubectl exec`などでagentのコンテナに入り、`curl localhost:8126`を打つと`404 page not found`と出ますが、これは正常です。
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
 name: "<APPLICATION_NAME>"
 namespace: myns
spec:
 selector:
   matchLabels:
     app: "<APPLICATION_NAME>"
 replicas: 1
 template:
   metadata:
     labels:
       app: "<APPLICATION_NAME>"
     name: "<POD_NAME>"
   spec:
     serviceAccountName: mysa
     containers:
     - name: "<APPLICATION_NAME>"
       image: "<APPLICATION_IMAGE>"
     ## Agent をサイドカーとして実行
     - image: datadog/agent
       name: datadog-agent
       env:
       - name: DD_API_KEY
         value: "<YOUR_DATADOG_API_KEY>"
       - name: DD_SITE
         value: "datadoghq.com"
       - name: DD_EKS_FARGATE
         value: "true"
       - name: DD_CLUSTER_NAME
         value: "<CLUSTER_NAME>"
       - name: DD_KUBERNETES_KUBELET_NODENAME
         valueFrom:
           fieldRef:
             apiVersion: v1
             fieldPath: spec.nodeName
      resources:
          requests:
            memory: "256Mi"
            cpu: "200m"
          limits:
            memory: "256Mi"
            cpu: "200m"
```

## ログ送信の設定
ドキュメントに乗っ取り`Cloudwatch logs`と`lambda`による送信をしてみます。

### FluentBitの構成
Cloudwatch logsへ送るための設定です。
`aws-observablity`というNamespaceにConfigMapを置くだけでいいらしい。(EKSがよしなにやってくれるのかな？)
詳しくは[Fargateのログ記録](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/fargate-logging.html)を参考に。
**※aws-observability**のNamespaceが未作成の場合は作成してください。
```yaml
 kind: ConfigMap
 apiVersion: v1
 metadata:
   name: aws-logging
   namespace: aws-observability
 data:
   output.conf: |
     [OUTPUT]
         Name cloudwatch_logs
         Match   *
         region us-east-1
         log_group_name awslogs-https
         log_stream_prefix awslogs-firelens-example
         auto_create_group true
```

### datadog-forwardar
実体はlambdaでCloudwatch logsからDatadogへの送信を担っているみたい。

詳細のドキュメント[Datadog Forwarder](https://docs.datadoghq.com/ja/logs/guide/forwarder/?tab=terraform).
[こちらはGitHubの実装です](https://github.com/DataDog/datadog-serverless-functions/tree/master/aws/logs_monitoring).

```terraform
# DatadogのAPIキー
variable "dd_api_key" {
  type        = string
  description = "Datadog API key"
}
resource "aws_secretsmanager_secret" "dd_api_key" {
  name        = "datadog_api_key"
  description = "Encrypted Datadog API Key"
}
resource "aws_secretsmanager_secret_version" "dd_api_key" {
  secret_id     = aws_secretsmanager_secret.dd_api_key.id
  secret_string = var.dd_api_key
}

# datadog-forwarderのCloudformation
resource "aws_cloudformation_stack" "datadog_forwarder" {
  name         = "datadog-forwarder"
  capabilities = ["CAPABILITY_IAM", "CAPABILITY_NAMED_IAM", "CAPABILITY_AUTO_EXPAND"]
  parameters   = {
    DdApiKeySecretArn  = aws_secretsmanager_secret.dd_api_key.arn,
    DdSite             = "datadoghq.com",
    FunctionName       = "datadog-forwarder"
  }
  template_url = "https://datadog-cloudformation-template.s3.amazonaws.com/aws/forwarder/latest.yaml"
}
```

#### datadog-forwarderのトリガーを設定
自動と手動による方法があるようですが、自動の方法では再現できなかったので手動でセットアップしました。
参考元: [Datadog の Lambda 関数で AWS サービスのログを送信する](https://docs.datadoghq.com/ja/logs/guide/send-aws-services-logs-with-the-datadog-lambda-function/?tab=terraform#set-up-triggers).

##### 自動
コンソールで`Integration`->`AWS`->`Log Collection`タブへ。
datadog-forwarderのlambdaのarnを貼り付けたらできるようです。

##### 手動
[cloudwatch_log_subscription_filter](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_subscription_filter)を使用してトリガーを管理します。
```terraform
resource "aws_cloudwatch_log_subscription_filter" "datadog_log_subscription_filter" {
  name            = "datadog_log_subscription_filter"
  log_group_name  = "awslogs-https"
  destination_arn = arn:aws:lambda:<region>:<account_id>:function:datadog-forwarder
  filter_pattern  = ""
}
```
ここまでの設定でDatadogへ送信がされるはずです。
できない場合、[Fargateのログ記録](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/fargate-logging.html)のFargate Podの実行ロールなど確認してみてください。

### 余談
ドキュメントどおりにCloudwatch logsを使用しましたが、kinesisとかの方が安く済むと思ったり。。

実はagentコンテナの`404 page not found`を知らなくて3日くらい使ってしまった...
Datadogなんもわからん状態だから頑張りたい.

# 参考
- [Amazon EKS on AWS Fargate](https://docs.datadoghq.com/ja/integrations/eks_fargate/)
- [Datadog Forwarder](https://docs.datadoghq.com/ja/logs/guide/forwarder/?tab=terraform)
- [Fargateのログ記録](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/fargate-logging.html)
- [Datadog の Lambda 関数で AWS サービスのログを送信する](https://docs.datadoghq.com/ja/logs/guide/send-aws-services-logs-with-the-datadog-lambda-function/?tab=terraform#set-up-triggers)