VKEのPodのログをS3に保存してみた

ログが保存されているS3バケットの画面

このブログも含めていくつかVKE (Vultr Kubernetes Engine)で動いているものがあり、それらのログについてちゃんと保存しておかないとなとずっと思っていたのですが、ようやくS3に保存し始めたので簡単に紹介します。

今回はFluentd Daemonset for KubernetesをDaemonSetとして動かし、S3へログの送信を行います。

まずはじめに保存先のS3バケットとVKEから当該S3バケットへアクセスするためのアクセスキーを作成する必要があります。これはうまいこと作成してください。S3はライフサイクルルールを設定するなどしても良いですね。またIAMのポリシーについてはfluentdのS3プラグインのドキュメントと同様に以下を適用しています(バケット名は例となります)。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:ListBucket"
      ],
      "Resource": "arn:aws:s3:::k8s-logs-xxxxxxxx"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject"
      ],
      "Resource": "arn:aws:s3:::k8s-logs-xxxxxxxx/*"
    }
  ]
}

次にVKEで動かすFluentd Daemonset for Kubernetesでログを読み込んでS3に送信するためのConfigMapを作成します。調べたところVKEでのコンテナログは/var/log/pods/の中に、NamespaceやDeploymentごとにディレクトリ分けされて保存されているようですので、そちらを読み込むように設定します。また今回保存しようとしているログがこのブログのApacheログなのですが、行頭に文字列が追加されており既定の形式として読み込めなかったのでパターンを指定していたり、S3に保存したあとにAthenaで検索する考えでしたので、それで使用しやすいようにフィールドと追加したりパスを指定したりしています。他にもいろいろ変数的なものがありますが、NamespaceやDeploymentの名前などで指定しました。

apiVersion: v1
kind: ConfigMap
metadata:
  name: fluentd-s3-config
data:
  fluent.conf: |
    <source>
      @type tail
      path /var/log/pods/default_atgw-blog-*/atgw-blog/*.log
      pos_file /var/log/td-agent/default_atgw-blog.log.pos
      tag default_atgw-blog
      <parse>
        @type regexp
        expression /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d+Z \S+ \S+ (?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>(?:[^\"]|\\.)*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>(?:[^\"]|\\.)*)" "(?<agent>(?:[^\"]|\\.)*)")?$/
        time_format %d/%b/%Y:%H:%M:%S %z
        keep_time_key true
      </parse>
    </source>
    
    <filter default_atgw-blog>
      @type record_transformer
      enable_ruby
      <record>
        unixtime ${Time.strptime(record["time"], "%d/%b/%Y:%H:%M:%S %z").to_i}
      </record>
    </filter>
    
    <match default_atgw-blog>
      @type s3
      aws_key_id xxxxxxxx
      aws_sec_key xxxxxxxx
      s3_bucket k8s-logs-xxxxxxxx
      s3_region ap-northeast-1
      path "default_atgw-blog/"
      time_slice_format year=%Y/month=%m/day=%d/%H_%M
      <format>
        @type json
      </format>
    </match>

ConfigMapができたらあとはDaemonSetを作成するだけです。先ほど作成したConfigMapに加え、ログが保存されいるパスをHostPathでマウントし、Podから使用できるようにします。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-s3
spec:
  selector:
    matchLabels:
      app: fluentd-s3
  template:
    metadata:
      labels:
        app: fluentd-s3
    spec:
      containers:
      - name: fluentd-s3
        image: fluent/fluentd-kubernetes-daemonset:v1.17-debian-s3-amd64-1
        volumeMounts:
        - name: fluentd-s3-config
          mountPath: /fluentd/etc
        - name: fluentd-s3-tdagent
          mountPath: /var/log/td-agent
        - name: fluentd-s3-podlogs
          mountPath: /var/log/pods
          readOnly: true
      volumes:
      - name: fluentd-s3-config
        configMap:
          name: fluentd-s3-config
      - name: fluentd-s3-tdagent
        hostPath:
          path: /var/log/td-agent
      - name: fluentd-s3-podlogs
        hostPath:
          path: /var/log/pods

これですべてのNodeでログの読み込みとS3への送信を行うPodが動き、一番最初の画像のようにS3にログが保存されていきます。ちなみに該当するログが存在しない場合(対象のPodがそのNodeで動いていない場合)でも特にエラーなどは出ていないようです。一方で、エラーという観点ですと、今回はApacheのアクセスログのパターンしか指定してないため、Apacheのエラーログについてはパターンが一致しないということでエラーになっています。Apacheのエラーログも保存したい場合には適切な設定を追加する必要がありますね。

ということで無事にS3にログが保存されるようになって良かったです。なお現時点ではこれによる費用増加はほとんどなさそうな感じです。次はこの保存したログをAthenaで検索するところを紹介できればと思っていますが、そのために使っているGlueの方が個人レベルでは若干気になる費用という感じですかね。

皆さんも是非PodのログをS3に保存してみてください!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です