AWS

AWSでsyslogやmessagesに出力されるdhclientについて. 出力されるログ syslogは通常運用時はなるべく出力させたくないと思っておりサーバを整備していました。 dhclientはdhcpでAWSからIPアドレスを割り当てるのに使われているようです。 結論から言うと対応はでき… 2017.11.16 AWS Kou … 続きを読む

カテゴリー 未分類 | タグ

新しいCloudWatch AgentでEC2インスタンスのメモリ使用率を監視する

この記事は OpsJAWS Advent Calendar 2017 19日目の記事です。

はじめに

先日、新しいCloudWatch Agentが登場しました。
https://aws.amazon.com/jp/about-aws/whats-new/2017/12/amazon-cloudwatch-introduces-a-new-cloudwatch-agent-with-aws-systems-manager-integration-for-unified-metrics-and-logs-collection/

これまでディスク使用量やメモリ使用率といった仮想マシン上のメトリックについては
CloudWatch Monitoring Scripts 等 を設定してCloudWatchにデータを送信する必要がありました。
新しい Agent ではこれらのゲストOS上のメトリックについても収集できるようになっています。

収集可能なメトリックの一覧については以下のドキュメントを参照ください。
稼働対象(EC2 or On-premises)、OS、ログ取得レベルによっても取得出来る内容が異なります。
http://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CW_Support_For_AWS.html#metrics-collected-by-CloudWatch-agent

やってみる

実際にAmazon Linuxサーバのメモリ使用率の監視設定を行ってみます。

IAMロールの作成

CloudWatch Agent を実行する EC2 インスタンスにアタッチする IAM ロールを事前に作成しておきます。

まず、以下の内容でポリシーを作成します。ポリシー名は任意に設定します。

CloudWatchAgentAdminPolicy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "CloudWatchAgentAdminPolicy",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "cloudwatch:PutMetricData",
                "ec2:DescribeTags",
                "logs:DescribeLogStreams",
                "logs:CreateLogGroup",
                "logs:PutLogEvents",
                "ssm:GetParameter",
                "ssm:PutParameter"
            ],
            "Resource": "*"
        }
    ]
}

新規のEC2用のIAMロールを作成し、上記のポリシーをアタッチします。
Agent の設定は AWS Systems Manager のパラメータストアに格納し、他サーバに展開させることが可能です。
上記例ではパラメータストアへの書き込みのため、ssm:PutParameter権限を付与しています。
通常、全てのインスタンスがパラメータストアへの書き込み権限を持つ必要はありませんので、
上記とは別に ssm:PutParameter を除いた一般用のIAMロールを別途作成することが望ましいです。

image.png

CloudWactch Agent のインストール

先ほど作成したIAMロールを、インストール対象のEC2インスタンスにアタッチします。

Agent のインストール方法は以下の2通りです。

  • AWS Systems Manager(ssm)によるインストール
  • CLI によるインストール

運用を考えると ssm でインストールを行うほうが楽ですが、
今回はAgentの基本的な操作を覚えるために、EC2インスタンスにログインし、CLIでインストールを行いました。

$ wget https://s3.amazonaws.com/amazoncloudwatch-agent/linux/amd64/latest/AmazonCloudWatchAgent.zip
$ unzip AmazonCloudWatchAgent.zip
$ sudo ./install.sh

プロキシを設定する必要がある環境の場合は、
/opt/aws/amazon-cloudwatch-agent/etc/common-config.tomlに設定します。

common-config.tml
[proxy]
http_proxy = "{http_url}"
https_proxy = "{https_url}"
no_proxy = "{domain}"

Agent 設定

Agent 設定ファイルの作成

Agent の設定ファイルは、収集するメトリックやログファイルを指定したファイルです。
JSONで作成されたファイルをAgent 起動時にTOMLに変換する形になります。
手動で作成することもできますが、ここではウィザードを使用して作成します。

$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard

ウィザードでは以下を設定します。カッコ内は今回選択した内容です。
収集間隔は最短で1秒を指定できるようになっていますが、今回は60秒を選択しました。

  • インストール先のOS(Linux)
  • インストール先がEC2かオンプレミスか(EC2)
  • ホストのメトリクスを収集するか(yes)
  • CPUコア毎のメトリクスを収集するか(yes)
  • EC2ディメンションを全てのメトリクスに追加するか(yes)
  • メトリクスを収集する間隔(60s)
  • メトリクスの収集レベル(Standard)

ログファイル監視対象の設定

既にCloudWatch Logs を使用している環境の場合は、引き続きこのウィザードで設定を移行できます。
移行を行わない場合も監視対象のログファイルのパスを指定し、追加することができます。
ここでは デフォルト選択の syslog(/var/log/messages) を対象に指定し、ログの監視設定を完了します。

設定ファイルは /opt/aws/amazon-cloudwatch-agent/bin/config.json に保存されます。
今回、最終的な設定内容は以下のようになります。

config.json
{
    "logs": {
        "logs_collected": {
            "files": {
                "collect_list": [
                    {
                        "file_path": "/var/log/messages",
                        "log_group_name": "messages"
                    }
                ]
             }
         }
    },
    "metrics": {
        "append_dimensions": {
            "AutoScalingGroupName": "${aws:AutoScalingGroupName}",
            "ImageId": "${aws:ImageId}",
            "InstanceId": "${aws:InstanceId}",
            "InstanceType": "${aws:InstanceType}"
        },
        "metrics_collected": {
            "cpu": {
                "measurement": [
                    "cpu_usage_idle",
                    "cpu_usage_iowait",
                    "cpu_usage_user",
                    "cpu_usage_system"
                ],
                "metrics_collection_interval": 60,
                "resources": [
                    "*"
                ],
                "totalcpu": false
             },
            "disk": {
                "measurement": [
                    "used_percent",
                    "inodes_free"
                ],
                "metrics_collection_interval": 60,
                "resources": [
                    "*"
                ]
            },
            "diskio": {
                "measurement": [
                    "io_time"
                ],
                "metrics_collection_interval": 60,
                "resources": [
                    "*"
                ]
            },
            "mem": {
                "measurement": [
                    "mem_used_percent"
                ],
                "metrics_collection_interval": 60
            },
            "swap": {
                "measurement": [
                    "swap_used_percent"
                ],
                "metrics_collection_interval": 60
            }
        }
    }
}

パラメータストアへの保存

ウィザードの最後に設定ファイルをSSM パラメータストアに保存するかの確認があります。
選択肢は全てデフォルトで問題ありません。

  • 設定ファイルを SSM パラメータストアに保存するか(yes)
  • パラメータストア名(agent-config-linux)
  • 保存先リージョン(ap-northeast-1)
  • AWSクレデンシャルの選択(From SDK)

aws cliで手動アップロードすることも可能です。

$ cd /opt/aws/amazon-cloudwatch-agent/bin/
$ aws ssm put-parameter --name "agent-config-linux" --type "String" --value file://config.json

AWS Systems Manger のコンソールを確認すると、パラメータストアが保存されていることが確認できます。

image.png

Agentの起動

SSMパラメータストアに保存した設定ファイルでAgentを起動してみます。

$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c ssm:agent-config-linux -s
/opt/aws/amazon-cloudwatch-agent/bin/config-downloader --output-file /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json --download-source ssm:agent-config-linux --mode ec2 --config /opt/aws/amazon-cloudwatch-agent/etc/common-config.toml
Successfully fetched the config from parameter store ssm:agent-config-linux and saved in /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json
Start configuration validation...
/opt/aws/amazon-cloudwatch-agent/bin/config-translator --input /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json --output /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml --mode ec2 --config /opt/aws/amazon-cloudwatch-agent/etc/common-config.toml
Valid Json input schema.
Configuration validation first phase succeeded
/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent -schematest -config /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml
Configuration validation second phase succeeded
Configuration validation succeeded
amazon-cloudwatch-agent start/running, process 2811

メッセージの内容から、JSONの設定ファイルが
/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.toml として保存されていることがわかります。

ログファイルは /opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log に出力されています。
またAgentインストール時にサービス登録が行われていますが、

  • common-config.toml
  • amazon-cloudwatch-agent.toml

の2ファイルが存在しないと、OS起動時にAgentが正常に起動できないようです。

ステータス確認、および終了コマンドは以下のように行うことができます。
また amazon-cloudwatch-agent.toml が作成されている状態であれば、2回目以降の起動では
設定ファイルのフェッチは不要です。

# ステータス確認
$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -m ec2 -a status
{
  "status": "running",
  "starttime": "2017-12-19T01:43:56+0000",
  "version": "1.73.9"
}

# 停止
$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -m ec2 -a stop
amazon-cloudwatch-agent stop/waiting

# 起動
$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -m ec2 -a start
amazon-cloudwatch-agent start/running, process 3044

監視設定

コンソール上で取得したメトリックの確認および、アラームの設定を行います。

メトリックの確認

カスタム名前空間の CWAgent を選択します。
少しわかりにくいですが、それぞれのメトリックを確認できます。

  • ImageId, InstanceId, InstanceType, device, fstype, path: Disk
  • ImageId, InstanceId, InstanceType, cpu: CPU
  • ImageId, InstanceId, InstanceType, name: Disk I/O
  • ImageId, InstanceId, InstanceType: Memory

image.png

ImageId, InstanceId, InstanceType を選択すると、mem_user_percent および swap_user_percent の値を確認することができました。

image.png

アラームの設定

特に変わった手順はありません。
グラフ化したメトリクスからアクションのアラームの作成を選択します。
image.png

アラーム名、閾値、間隔、通知先等を任意に設定し、アラームの作成を押下します。
image.png

以上でメモリ使用率の監視設定が完了しました。
参考になれば幸いです。

続きを読む

Kubernetes上のアプリケーションログを自動収集する

image.png

TL;DR;

新サービスや既存サービスをKubernetesに移行するたびに、ログの収集設定のためインフラエンジニア待ちになってしまうのは面倒ですよね。
そこで、アプリのログをFluentdとDatadog LogsやStackdriver Loggingで自動的に収集する方法を紹介します。

主に以下のOSSを利用します。

今回はDatadog Logsを使いますが、Stackdriver Loggingを使う場合でもUIやAPIクレデンシャル等の設定以外は同じです。

お急ぎの方へ: アプリ側の設定手順

標準出力・標準エラーログを出力するだけでOKです。

参考: The Twelve-Factor App (日本語訳)

詳しくは、この記事の「サンプルアプリからログを出力する」以降を読んでください。

あとはクラスタ側に用意しておいたFluentdの仕事ですが、Kubernetesがノード上に特定のフォーマットで保存するため、アプリ毎の特別な設定は不要です。

まえおき1: なぜDatadogやStackdriver Loggingなのか

分散ロギングのインフラを準備・運用するのがつらい

分散ロギングと一口にいっても、実現したいことは様々です。例えば、多数のサービス、サーバ、プロセス、コンテナから出力されたログを

  1. 分析などの用途で使いやすいようにETLしてRedshiftのようなデータウェアハウスに投入しておきたい
  2. S3などのオブジェクトストレージに低コストでアーカイブしたい
  3. ほぼリアルタイムでストリーミングしたり、絞込検索したい
    • Web UI、CLIなど

1.はtd-agent + TreasureData or BigQuery、2.はfluentd (+ Kinesis Streams) + S3、3.はfilebeat or Logstash + Elasticsearch + Kibana、Graylog2、専用のSaaSなど、ざっとあげられるだけでも多数の選択肢があります。

方法はともかく、できるだけ運用保守の手間を省いて、コアな開発に集中したいですよね。

メトリクス、トレース、ログを一つのサービスで一元管理したい・運用工数を節約したい

「Kubernetesにデプロイしたアプリケーションのメトリクスを自動収集する – Qiita」でも書きましたが、例えばKubernetesの分散ロギング、分散トレーシング、モニタリングをOSSで実現すると以下のような構成が定番だと思います。

  • 基本的なグラフ作成とメトリクス収集、アラート設定はPrometheus
  • 分散ログはEKF(Elasticsearch + Kibana Fluentd)
  • 分散トレースはZipkinやJaeger

もちろん、ソフトウェアライセンス費用・サポート費用、将来の拡張性などの意味では良い判断だと思います。

一方で、

  • アラートを受けたときに、その原因調査のために3つもサービスを行ったり来たりするのは面倒
  • 人が少ない場合に、セルフホストしてるサービスの運用保守に手間をかけたくない
    • アカウント管理を個別にやるだけでも面倒・・最低限、SSO対応してる?

などの理由で

  • 個別のシステムではなく3つの役割を兼ねられる単一のシステム

がほしいと思うことがあると思います。

fluentd + Datadog Logs/Stackdriver Logging

StackdriverとDatadogはSaaSで、かつ(それぞれサブサービスで、サブサービス間連携の度合いはそれぞれではありますが、)3つの役割を兼ねられます。

SaaSへログを転送する目的でfluentdを利用しますが、Kubernetesのログを収集するエージェントとしてfluentdがよく使われている関係で、Kubernetes界隈でよく使われるfluentdプラグインに関しては、よくある「メンテされていない、forkしないと動かない」という問題に遭遇しづらいというのも利点です。

まえおき2: なぜDatadogなのか

もともとStackdriver Loggingを利用していたのですが、以下の理由で乗り換えたので、この記事ではDatadog Logsの例を紹介することにします。

  • メトリクスやAPMで既にDatadogを採用していた
  • UI面で使いやすさを感じた

UI面に関して今のところ感じている使いやすさは以下の2点です。

  • ログメッセージの検索ボックスでメタデータの補完が可能

    • hostで絞込をしようとすると、hostの値が補完される
    • あとで説明します
  • 柔軟なFaceting
    • Datadog LogsもStackdriver Loggingもログにメタデータを付与できるが、Datadog Logsは任意のメタデータキーで絞り込むためのショートカットを簡単に追加できる
    • あとで説明します

Stackdriver Loggingを利用する場合でも、この記事で紹介する手順はほぼ同じです。Kubernetesの分散ロギングをSaaSで実現したい場合は、せっかくなので両方試してみることをおすすめします。

Fluentdのセットアップ手順

DatadogのAPIキー取得

Datadog > Integratinos > APIsの「New API Key」から作成できます。

image.png

以下では、ここで取得したAPIキーをDD_API_KEYという環境変数に入れた前提で説明を続けます。

fluentdのインストール

今回はkube-fluentdを使います。

$ git clone git@github.com:mumoshu/kube-fluentd.git
$ cd kube-fluentd

# 取得したAPIキーをsecretに入れる
$ kubectl create secret generic datadog --from-literal=api-key=$DD_API_KEY

# FluentdにK8Sへのアクセス権を与えるためのRBAC関連のリソース(RoleやBinding)を作成
$ kubectl create -f fluentd.rbac.yaml

# 上記で作成したsecretとRBAC関連リソースを利用するfluentd daemonsetの作成
$ kubectl create -f fluentd.datadog.daemonset.yaml

設定内容の説明

今回デプロイするfluentdのmanifestを上から順に読んでみましょう。

kind: DaemonSet

Kubernetes上のアプリケーションログ(=Podの標準出力・標準エラー)は各ノードの/var/log/containers以下(より正確には、そこからsymlinkされているファイル)に出力されます。それをfluentdで集約しようとすると、必然的に各ノードにいるfluentdがそのディレクトリ以下のログファイルをtailする構成になります。fluentdに限らず、何らかのコンテナをデプロイしたいとき、KubernetesではPodをつくります。Podを各ノードに一つずつPodをスケジュールするためにはDaemonSetを使います。

  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1

DaemonSetをアップデートするとき(例えばDockerイメージを最新版にするためにタグの指定を変える)、Podを1つずつローリングアップデートします。アップデートによってfluentdが動かなくなった場合の影響を抑えることが目的ですが、気にしない場合はこの設定は記述は不要です。

serviceAccountName: fluentd-cloud-logging

kubectl -f fluent.rbac.yamlで作成されたサービスアカウントを利用する設定です。これがないとデフォルトのサービスアカウントが使われてしまいますが、ほとんどのツールでつくられたKubernetesクラスタではデフォルトのサービスアカウントに与えられる権限が絞られているので、デフォルトのサービスアカウントではkube-fluentdが動作しない可能性があります。

      tolerations:
      - operator: Exists
        effect: NoSchedule
      - operator: Exists
        effect: NoExecute
      - operator: Exists

KubernetesのMasterノードや、その他taintが付与された特定のワークロード専用のWorkerノード含めて、すべてのノードにfluentd podをスケジュールための記述です。何らかの理由でfluentdを動作させたくないノードがある場合は、tolerationをもう少し絞り込む必要があります。

env:
        - name: DD_API_KEY
          valueFrom:
            secretKeyRef:
              name: datadog
              key: api-key
        - name: DD_TAGS
          value: |
            ["env:test", "kube_cluster:k8s1"]

一つめは、secretに保存したDatadog APIキーを環境変数DD_API_KEYにセットする、二つめはfluentdが収集したすべてのログに二つのタグをつける、という設定です。タグはDatadogの他のサブサービスでもよく見られる形式で、”key:value”形式になっています。

Datadogタグのenvは、Datadogで環境名を表すために慣習的に利用されています。もしDatadogでメトリクスやトレースを既に収集していて、それにenvタグをつけているのであれば、それと同じような環境名をログにも付与するとよいでしょう。

kube_clusterは個人的におすすめしたいタグです。Kubernetesクラスタは複数同時に運用する可能性があります。このタグがあると、メトリクスやトレース、ログをクラスタ毎に絞り込むことができ、何か障害が発生したときにその原因が特定のクラスタだけで起きているのかどうか切り分ける、などの用途で役立ちます。

        ports:
        - containerPort: 24231
          name: prometheus-metrics

「Kubernetesにデプロイしたアプリケーションのメトリクスを自動収集する」で紹介した方法でdd-agentにfluentdのPrometheusメトリクスをスクレイプさせるために必要なポートです。

サンプルアプリからログを出力する

適当なPodを作成して、testmessage1というメッセージを出力します。

$ kubectl run -it --image ruby:2.4.2-slim-stretch distlogtest-$(date +%s) -- ruby -e 'puts %q| mtestmessage1|; sleep 60'

ログの確認

何度か同じコマンドを実行したうえで、DatadogのLog Explorerでtestmessage1を検索してみると、以下のようにログエントリがヒットします。

image.png

ログエントリを一つクリックして詳細を開いてみると、testmessage1というログメッセージの他に、それに付随する様々なメタデータが確認できます。

image.png

ログエントリに自動付与されたメタデータの確認

  • HOST: ログを出力したPodがスケジュールされているホスト名(=EC2インスタンスのインスタンスID)
  • SOURCE: コンテナ名
  • TAGS: Datadogタグ
    • pod_name: Pod名
    • kube_replicaset: ReplicaSet名
    • container_name: Dockerコンテナ名
    • kube_namespace: PodがスケジュールされているNamespace名
    • host: PodがスケジュールされているKubernetesノードのEC2インスタンスID
    • zone: Availability Zone
    • aws_account_id: AWSアカウントID
    • env: 環境名

Log Explorerを使うと、すべてのAWSアカウントのすべてのKubernetesクラスタ上のすべてのPodからのログが一つのタイムラインで見られます。それを上記のようなメタデータを使って絞り込むことができます。

ログエントリの絞り込み

ログエントリの詳細から特定のタグを選択すると、「Filter by」というメニュー項目が見つかります。

image.png

これを選択すると、検索ボックスに選択したタグがkey:value形式で入力された状態になり、そのタグが付与されたログエントリだけが絞り込まれます。

もちろん、検索ボックスに直接フリーワードを入力したり、key:value形式でタグを入力してもOKです。

Facetingを試す

定型的な絞り込み条件がある場合は、Facetを作成すると便利です。

ログエントリの詳細から特定のタグを選択すると、「Create new facet」というメニュー項目が見つかります。

image.png

これを選択すると、以下のようにどのような階層のどのような名前のFacetにするかを入力できます。

image.png

例えば、

  • Path: kube_namespace
  • Name: Namespace
  • Group: Kubernetes

のようなFacetを作成すると、ログエントリに付与されたkube_namespaceというタグキーとペアになったことがある値を集約して、検索条件のショートカットをつくってくれます。実際のNamespace Facetは以下のように見えます。

image.png

kube-system、mumoshu、istio-system、defaultなどが表示されていますが、それぞれkube_namespaceというタグキーとペアになったことがある値(=クラスタに実在するNamespace名)です。また、その右の数値はそのNamespaceから転送されたログエントリの件数です。この状態で例えばistio-systemを選択すると、kube_namespace:istio-systemというタグが付与されたログエントリだけを絞り込んでみることができます。

image.png

アーカイブ、ETLパイプラインへの転送など

kube-fluentdにはアーカイブやETLパイプラインのサポートは今のところないので、必要に応じてはfluentd.confテンプレート変更して、それを含むDockerイメージをビルドしなおす必要があります。

fluentd.confテンプレートは以下の場所にあります。

https://github.com/mumoshu/kube-fluentd/blob/master/rootfs/etc/confd/templates/fluent.conf.tmpl

fluentd.confテンプレートから参照できる環境変数を追加したい場合は、以下のconfd設定ファイルを変更します。

https://github.com/mumoshu/kube-fluentd/blob/master/rootfs/etc/confd/conf.d/fluent.conf.toml

// 今後、configmap内に保存したfluent.confの断片をfluentdの@includeを使ってマージしてくれるような機能を追加してもよいかもしれませんね。

まとめ

FluentdとDatadog Logsを使って、Kubernetes上のアプリケーションログを自動的に収集し、Datadog LogsのWeb UIからドリルダウンできるようにしました。

アプリ側はTwelve-Factor Appに則って標準出力・標準エラーにログを出力するだけでよい、という簡単さです。ドリルダウンしたり、そのためのFacetを作成するときも、グラフィカルな操作で完結できます。

また、ログの収集をするためだけにいちいちインフラエンジニアが呼び出されることもなくなって、楽になりますね!

Kubernetes上のアプリケーションの分散ロギングを自動化したい方は、ぜひ試してみてください。

(おまけ) 課題: ログメッセージに含まれるメタデータの抽出

Stackdriver Loggingではできて、Datadog Logsでは今のところできないことに、ログメッセージに含まれるメタデータの抽出があります。

例えば、Stackdriver Loggingの場合、

  • ログにメタデータを付与して検索対象としたい

    • 例えば「ログレベルDEBUGでHello World」のようなログを集約して、Web UIなどから「DEBUGレベルのログだけを絞り込みたい」

というような場合、アプリからは1行1 jsonオブジェクト形式で標準出力に流しておいて、fluent-plugin-google-cloud outputプラグイン(kube-fluentd内で利用しているプラグイン)でStackdriver Loggingに送ると、jsonオブジェクトをパースして、検索可能にしてくれます。

例えば、

{"message":"Hello World", "log_level":"info"}

のようなログをStackdriver Loggingにおくると、log_levelで検索可能になる、ということです。

このユースケースに対応する必要がある場合は、いまのところDatadog LogsではなくStackdriver Loggingを採用するとよいと思います。

今後の展望

同じくkube-fluentdでDatadog Logsへログを転送するために利用しているfluent-plugin-datadog-logに、fluent-plugin-google-cloudと同様にJSON形式のログをパースしてDatadogのタグに変換する機能を追加することはできるかもしれません。

また、Datadog Logsには、ログエントリのメッセージ部分に特定のミドルウェアの標準的な形式のログ(例えばnginxのアクセスログ)が含まれる場合に、それをよしなにパースしてくれる機能があります。その場合にログエントリに付与されるメタデータは、タグではなくアトリビュートというものになります。アトリビュートはタグ同様に検索条件に利用することができます。

ただ、いまのところfluent-plugin-datadog-logからの出力はすべてsyslog扱いになってしまっており、ログの内容によらず以下のようなアトリビュートが付与されてしまっています。

image.png

JSONをパースした結果がこのアトリビュートに反映されるような実装が可能であれば、それが最適なように思えます。

続きを読む

Ubuntu✕Terraform✕ItamaeでKinesis-firehoseを使う

What the Kinesis-firehose?

  • Streams,Analyticsなど、KinesisStreamingDataPlatformの一部
    スクリーンショット 2017-11-08 15.26.52.png
  • kinesis-agentをサーバで起動させ、configに処理を定義します
    • Javaで動き、任意のログをS3などのデータレイクへ任意のタイミングでPushします

Kinesis-agent

Prerequisites

  • UbuntuというかDebianは入ってないです…
  • Writing to Amazon Kinesis Streams Using Kinesis Agent

    • Prerequisites

      Your operating system must be either Amazon Linux AMI with version 2015.09 or later, or Red Hat
      Enterprise Linux version 7 or later.
      

Method

  • 公式ドキュメントには書いてないけど、ReadMeにBuildすれば使えるって書いてありました

    Building from Source
    The installation done by the setup script is only tested on the following OS Disributions:
    Red Hat Enterprise Linux version 7 or later
    Amazon Linux AMI version 2015.09 or later
    Ubuntu Linux version 12.04 or later
    Debian Linux version 8.6 or later
    

Enviroment

  • ubuntu15.04(サポート終了してるしLTSでさえないことは諸事情により触れないでください…)
  • Terraform v0.10.7
  • itamae (1.9.11)

Apply

Firehose delivery streams

terraform

  • 構成は端的に書くと以下

    • 他サービスと同じリージョンに作成するなら、構造は分離しなくてもOK
.
├── kinesis_firehose_delivery_stream.tf
├── main.tf
└── terraform_remote_state.tf
main.tf
// config
provider "aws" {
  region  = "ap-northeast-1"
  profile = "xxxxxx"
}
// backend
terraform {
  backend "s3" {
    bucket  = "xxxxxx"
    key     = "xxxxxx"
    region  = "ap-northeast-1"
    profile = "xxxxxx"
  }
}
terraform_remote_state.tf
data "terraform_remote_state" "xxxxxx" {
  backend = "s3"
  config {
    bucket  = "xxxxxx"
    key     = "xxxxxx"
    region  = "ap-northeast-1"
    profile = "xxxxxx"
  }
}
kinesis_firehose_delivery_stream.tf
// syslog
resource "aws_kinesis_firehose_delivery_stream" "xxxxxx-syslog" {
  name        = "xxxxxx-syslog"
  destination = "s3"
  s3_configuration {
    role_arn        = "${aws_iam_role.xxxxxx.arn}"
    buffer_interval = "300"
    buffer_size     = "5"
    bucket_arn      = "arn:aws:s3::: xxxxxx"
    prefix          = "kinesis-firehose/rsyslog/syslog/"
  }
}

itamae

  • 構成は以下
.
├── provisioner
│   └── cookbooks
│       ├── aws-kinesis
│       │   ├── default.rb
│       │   └── file
│       │       └── etc
│       │           └── aws-kinesis
│       │               └── agent.json
default.rb
#kinesis-agent depend-packages install
execute "updte repository" do
  command "sudo apt-get update"
end

package 'openjdk-8-jdk' do
  action :install
end

#kinesis-agent install
execute "git clone" do
  command "git clone https://github.com/awslabs/amazon-kinesis-agent.git"
  not_if 'test -e /home/ubuntu/amazon-kinesis-agent'
end

execute "build" do
  command "cd /home/ubuntu/amazon-kinesis-agent;./setup --build"
end

execute "install" do
  command "cd /home/ubuntu/amazon-kinesis-agent;./setup --install"
end

#change to the agent.json
remote_file "/etc/aws-kinesis/agent.json" do
  source "file/etc/aws-kinesis/agent.json"
  mode "644"
  owner "root"
  group "root"
end

directory "/var/log/nginx" do
  mode "755"
end

service 'aws-kinesis-agent' do
  action [:enable, :start]
end
agent.json
{
  "cloudwatch.emitMetrics": true,
  "cloudwatch.endpoint": "https://monitoring.ap-northeast-1.amazonaws.com",
  "firehose.endpoint": "https://firehose.ap-northeast-1.amazonaws.com",
  "flows": [
    {
      "filePattern": "/var/log/syslog*",
      "deliveryStream": "xxxxxx-syslog",
      "initialPosition": "END_OF_FILE",
      "maxBufferAgeMillis": "60000",
      "maxBufferSizeBytes": "1048576",
      "maxBufferSizeRecords": "100",
      "minTimeBetweenFilePollsMillis": "100",
      "partitionKeyOption": "RANDOM",
      "skipHeaderLines": "0",
      "truncatedRecordTerminator": "'n'"
    }
//以下、必要な分を記述
  ]
}

Check

  • プロセスは正常に起動しているか確認

    • ヒープ全体はデフォルトで512MBなので、要チューニング
    PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    12037 999       20   0 4053620 244480  19052 S   1.1  1.5   3:47.96 /usr/bin/java -server -Xms32m -Xmx512m -XX:OnOutOfMemoryError="/bin/kill -9 %p" -cp /usr/share/aws-kinesis-agent/lib:/usr/share/aws-kinesis-+
    9 root      20   0       0      0      0 S   0.3  0.0   1:00.50 [rcuos/0]
    18 root      20   0       0      0      0 S   0.3  0.0   0:15.21 [rcuos/1]
    1 root      20   0   35896   6024   3688 S   0.0  0.0   0:02.82 /sbin/init
    
  • /var/log/aws-kinesis-agent/aws-kinesis-agent.logにError,WARNが出てないか確認

  • 指定したバケットにログが格納されているか確認

Monitor

  • kinesis-agentが正常に動作してるかCloudWatchで監視
.
├── kinesis_firehose_delivery_stream.tf
├── cloudwatch_metric_alarm.tf
├── main.tf
└── terraform_remote_state.tf
  • treat_missing_dataを使用することで不連続なデータの扱いを定義できます
treat_missing_data - (Optional) Sets how this alarm is to handle missing data points. The following values are supported: missing, ignore, breaching and notBreaching. Defaults to missing.
cloudwatch_metric_alarm.tf
resource "aws_cloudwatch_metric_alarm" "xxxxxx-syslog-ServiceErrors" {
  alarm_name          = "[KINESIS-AGENT] xxxxxx-syslog-ServiceErrors"
  alarm_description   = "Number of calls to PutRecords that have become service errors (except throttling errors) within the specified time period"
  comparison_operator = "GreaterThanOrEqualToThreshold"
  evaluation_periods  = "1"
  treat_missing_data  = "notBreaching"
  metric_name         = "ServiceErrors"
  namespace           = "AWSKinesisAgent"
  period              = "300"
  statistic           = "Sum"
  threshold           = "2"
  alarm_actions       = ["arn:aws:sns:ap-northeast-1:012345678910:xxxxxx"]
  ok_actions          = ["arn:aws:sns:ap-northeast-1:012345678910:xxxxxx"]
  dimensions {
    Destination = "DeliveryStream:xxxxxx-syslog"
  }
}

Caution

  • agentには取得対象のログがローテートされた時copytruncateが定義されているとエージェントが停止するバグがあるので、createを使用します

続きを読む

AWS CloudWatch で、Amazon Linux のパフォーマンスとログの監視をしてみる

0.はじめに

Amazon Linuxを利用していますが、
パフォーマンス監視は Zabbix を使って、
ログ監視は特に何も、
という感じでした。

CloudWatch のメトリクスの保存期間も長くなったみたいですし、
運用の手間やリスク、コスト削減も考慮して、
パフォーマンス監視を CloudWatch、
ログ監視を CloudWatch Logs、
にしようかと思います。

1.IAM Role へのポリシーのアタッチ

  1. 以下の IAM ポリシーを作成します。

    • ポリシー名 : GSCloudWatchWriteOnlyAccess ※ 任意
    • 説明 : ※ 任意
    • ポリシードキュメント :
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "Stmt1459146265000",
                "Effect": "Allow",
                "Action": [
                    "cloudwatch:PutMetricData"
                ],
                "Resource": [
                    "*"
                ]
            },
            {
                "Sid": "Stmt1459146665000",
                "Effect": "Allow",
                "Action": [
                    "logs:CreateLogGroup",
                    "logs:CreateLogStream",
                    "logs:PutLogEvents"
                ],
                "Resource": [
                    "arn:aws:logs:*:*:*"
                ]
            }
        ]
    }
    

  2. 作成したポリシーを EC2 インスタンスに割り当てられている IAM Role に付与します。

1.CloudWatch へのメトリクスデータの送信

  1. 色々調べたところ、collectd と その CloudWatch 用プラグインを利用するのが一般的みたいなので、今回はその手順で進めていきます。

  2. collectd をインストールします。

    $ sudo yum -y install collectd
    

  3. collectd の CloudWatch 用プラグインをインストールします。

    $ git clone https://github.com/awslabs/collectd-cloudwatch.git
    $ cd collectd-cloudwatch/src
    $ sudo ./setup.py
    
    Installing dependencies ... OK
    Installing python dependencies ... OK
    Downloading plugin ... OK
    Extracting plugin ... OK
    Moving to collectd plugins directory ... OK
    Copying CloudWatch plugin include file ... OK
    
    Choose AWS region for published metrics:
      1. Automatic [ap-northeast-1]
      2. Custom
    Enter choice [1]: 
    
    Choose hostname for published metrics:
      1. EC2 instance id [i-00484bb5ac67e244d]
      2. Custom
    Enter choice [1]: 
    
    Choose authentication method:
      1. IAM Role [testuekamawindowsserver]
      2. IAM User
    Enter choice [1]: 
    
    Enter proxy server name:
      1. None
      2. Custom
    Enter choice [1]: 
    
    Enter proxy server port:
      1. None
      2. Custom
    Enter choice [1]: 
    
    Include the Auto-Scaling Group name as a metric dimension:
      1. No
      2. Yes
    Enter choice [1]: 
    
    Include the FixedDimension as a metric dimension:
      1. No
      2. Yes
    Enter choice [1]: 
    
    Enable high resolution:
      1. Yes
      2. No
    Enter choice [2]: 
    
    Enter flush internal:
      1. Default 60s
      2. Custom
    Enter choice [1]: 
    
    Choose how to install CloudWatch plugin in collectd:
      1. Do not modify existing collectd configuration
      2. Add plugin to the existing configuration
      3. Use CloudWatch recommended configuration (4 metrics)
    Enter choice [3]: 
    Plugin configuration written successfully.
    Creating backup of the original configuration ... OK
    Replacing collectd configuration ... OK
    Replacing whitelist configuration ... OK
    Stopping collectd process ... NOT OK
    Starting collectd process ... NOT OK
    Installation cancelled due to an error.
    Executed command: '/usr/sbin/collectd'.
    Error output: 'Error: Reading the config file failed!
    Read the syslog for details.'.
    

  4. collectd の起動に失敗しています。collectd の python 用ライブラリが足りないみたいなので、インストールします。

    $ sudo yum -y install collectd-python
    

  5. collectd を起動します。

    $ sudo service collectd start
    

  6. collectd の自動起動の設定をします。

    $ sudo chkconfig collectd on
    $ sudo chkconfig --list | grep collectd
    
    collectd           0:off    1:off    2:on    3:on    4:on    5:on    6:off
    

  7. /etc/collectd.conf の設定を変更します。

    $ sudo cp -frp /etc/collectd.conf /etc/collectd.conf.ORG
    $ sudo vi /etc/collectd.conf
    
    • cpu :

      • LoadPlugin cpu をコメント解除し、以下の設定を行う。
      <Plugin cpu>
              ReportByCpu false
              ReportByState true
              ValuesPercentage true
      </Plugin>
      
    • df :

      • LoadPlugin df をコメント解除し、以下の設定を行う。
      <Plugin df>
      #       Device "/dev/hda1" 
      #       Device "192.168.0.2:/mnt/nfs" 
      #       MountPoint "/home" 
      #       FSType "ext3" 
      #       IgnoreSelected false
              ReportByDevice false
              ReportInodes false
              ValuesAbsolute true
              ValuesPercentage true
      </Plugin>
      
    • load :

      • LoadPlugin load をコメント解除し、以下の設定を行う。
      <Plugin load>
              ReportRelative true
      </Plugin>
      
    • memory :

      • LoadPlugin memory をコメント解除し、以下の設定を行う。
      <Plugin memory>
              ValuesAbsolute true
              ValuesPercentage true
      </Plugin>
      
    • swap :

      • LoadPlugin swap をコメント解除し、以下の設定を行う。
      <Plugin swap>
              ReportByDevice false
              ReportBytes false
              ValuesAbsolute false
              ValuesPercentage true
      </Plugin>
      

  8. /opt/collectd-plugins/cloudwatch/config/whitelist.conf の設定を変更します。以下のメトリクスの中で不要なものがあれば、適当に削除して下さい。

    $ cd /opt/collectd-plugins/cloudwatch/config/
    $ sudo cp -frp whitelist.conf whitelist.conf.ORG
    $ sudo vi whitelist.conf
    
    cpu-.*
    df-root-df_complex-free
    df-root-df_complex-reserved
    df-root-df_complex-used
    df-root-percent_bytes-free
    df-root-percent_bytes-reserved
    df-root-percent_bytes-used
    load--load-relative
    memory--percent-free
    memory--percent-used
    memory--memory-free
    memory--memory-used
    swap--percent-cached
    swap--percent-free
    swap--percent-used
    

  9. collectd を再起動します。

    $ sudo service collectd restart
    

  10. CloudWatch のマネジメントコンソールの左側ペインから、「メトリクス」を選択します。カスタム名前空間の「collectd」→「Host, PluginInstance」→ EC2 インスタンスの ID でフィルタをかけて、設定したメトリクスのデータがあるか確認します。

    • FireShot Capture 165 - CloudWatch Management Console_ - https___ap-northeast-1.console.aws.png

    • FireShot Capture 166 - CloudWatch Management Console_ - https___ap-northeast-1.console.aws.png

    • FireShot Capture 171 - CloudWatch Management Console_ - https___ap-northeast-1.console.aws.png

2.CloudWatch Logs へのログデータの送信

  1. awslogs をインストールします。

    $ sudo yum -y install awslogs
    

  2. /etc/awslogs/awscli.conf の設定を変更します。

    $ sudo cp -frp /etc/awslogs/awscli.conf /etc/awslogs/awscli.conf.ORG
    $ sudo vi /etc/awslogs/awscli.conf
    
    [plugins]
    cwlogs = cwlogs
    [default]
    region = ap-northeast-1
    

  3. /etc/awslogs/awslogs.conf の設定を変更します。

    • apache や nginx の設定もしています。不要であれば、削除して下さい。
    $ sudo cp -frp /etc/awslogs/awslogs.conf /etc/awslogs/awslogs.conf.ORG
    $ sudo vi /etc/awslogs/awslogs.conf
    
    [/var/log/messages]
    datetime_format = %b %d %H:%M:%S
    file = /var/log/messages
    buffer_duration = 5000
    log_stream_name = {instance_id}
    initial_position = start_of_file
    log_group_name = AmazonLinux/var/log/messages
    
    [/var/log/cron]
    datetime_format = %b %d %H:%M:%S
    file = /var/log/cron
    buffer_duration = 5000
    log_stream_name = {instance_id}
    initial_position = start_of_file
    log_group_name = AmazonLinux/var/log/cron
    
    [/etc/httpd/logs/access_log]
    datetime_format = [%a %b %d %H:%M:%S %Y]
    file = /etc/httpd/logs/access_log
    buffer_duration = 5000
    log_stream_name = {instance_id}
    initial_position = start_of_file
    log_group_name = AmazonLinux/etc/httpd/logs/access_log
    
    [/etc/httpd/logs/error_log]
    datetime_format = [%a %b %d %H:%M:%S %Y]
    file = /etc/httpd/logs/error_log
    buffer_duration = 5000
    log_stream_name = {instance_id}
    initial_position = start_of_file
    log_group_name = AmazonLinux/etc/httpd/logs/error_log
    
    [/etc/httpd/logs/ssl_access_log]
    datetime_format = [%a %b %d %H:%M:%S %Y]
    file = /etc/httpd/logs/ssl_access_log
    buffer_duration = 5000
    log_stream_name = {instance_id}
    initial_position = start_of_file
    log_group_name = AmazonLinux/etc/httpd/logs/ssl_access_log
    
    [/etc/httpd/logs/ssl_error_log]
    datetime_format = [%a %b %d %H:%M:%S %Y]
    file = /etc/httpd/logs/ssl_error_log
    buffer_duration = 5000
    log_stream_name = {instance_id}
    initial_position = start_of_file
    log_group_name = AmazonLinux/etc/httpd/logs/ssl_error_log
    
    [/etc/httpd/logs/ssl_request_log]
    datetime_format = [%a %b %d %H:%M:%S %Y]
    file = /etc/httpd/logs/ssl_request_log
    buffer_duration = 5000
    log_stream_name = {instance_id}
    initial_position = start_of_file
    log_group_name = AmazonLinux/etc/httpd/logs/ssl_request_log
    
    [/var/log/nginx/access.log]
    datetime_format = %Y/%m/%d %H:%M:%S
    file = /var/log/nginx/access.log
    buffer_duration = 5000
    log_stream_name = {instance_id}
    initial_position = start_of_file
    log_group_name = AmazonLinux/var/log/nginx/access.log
    
    [/var/log/nginx/backend.access.log]
    datetime_format = %Y/%m/%d %H:%M:%S
    file = /var/log/nginx/access.log
    buffer_duration = 5000
    log_stream_name = {instance_id}
    initial_position = start_of_file
    log_group_name = AmazonLinux/var/log/nginx/backend.access.log
    
    [/var/log/nginx/badactor.log]
    datetime_format = %Y/%m/%d %H:%M:%S
    file = /var/log/nginx/badactor.log
    buffer_duration = 5000
    log_stream_name = {instance_id}
    initial_position = start_of_file
    log_group_name = AmazonLinux/var/log/nginx/badactor.log
    
    [/var/log/nginx/error.log]
    datetime_format = %Y/%m/%d %H:%M:%S
    file = /var/log/nginx/error.log
    buffer_duration = 5000
    log_stream_name = {instance_id}
    initial_position = start_of_file
    log_group_name = AmazonLinux/var/log/nginx/error.log
    

  4. awslogs を起動します。

    $ sudo service awslogs start
    

  5. awslogs の自動起動の設定をします。

    $ sudo chkconfig awslogs on
    $ sudo chkconfig --list | grep awslogs
    
    awslogs            0:off    1:off    2:on    3:on    4:on    5:on    6:off
    

99.ハマりポイント

  • 今回は、凡ミスばかりで本当に自分が嫌になりました…。もう、毎回、何やってんだ…。

  • CloudWatch へのメトリクスデータの送信では、 CloudWatch のカスタム名前空間の「collectd」ではなく、AWS の EC2 のフィルタに表示されると勘違いして、全然ログが出てこないと悩んでいました…。もう、本当馬鹿…。
  • 後、/etc/collectd.conf の設定も結構悩みました。
  • CloudWatch Logs へのログデータの送信では、/etc/awslogs/awscli.conf の設定を /etc/awslogs/awslogs.conf にすると勘違いして、本当に無駄な時間を浪費しました…。

XX.まとめ

以下、参考にさせて頂いたサイトです。
ありがとうございました。

続きを読む

EC2+goofysでS3バケットをマウントしたい

概要

  • S3をファイルシステムとしてマウントしたいと思い試行錯誤したメモ。
  • 実現するためのOSSでは メジャーなもので s3fsgoofys があるっぽい。
  • goofys の方が評判が良いようなのでgoofysで検証。

目標

  • golangおよび gooyfs を導入
  • fstab で起動時に毎回マウントしたいので諸々の設定を整備

本家情報

goofysインストールの参考情報


作業環境

  • AWS + EC2(AmazonLinux) + S3

事前準備

1. マウント対象のS3バケットを新規作成。
2. 作成したバケットにアクセス可能となる IAMアカウントを用意
3. AmazonLinuxのEC2を作成し ec2-user または root でaws configure でIAMの設定を完了させておく
4. マウントポイントを先に作成しておく: 例) `mkdir -p /mnt/s3test`

参考サイトに従ってインストールを進めたが最新版goofysはそのままでは実装できなかった。とりあえずメモ残し。

バージョン確認

  • go versiongo version go1.7.5 linux/amd64 が入った

goofys インストール

  • go get github.com/kahing/goofys
  • バージョン確認: goofys --versiongoofys version 0.0.17-usemake build’ to fill version hash correctly`

マウント実行(エラー)

  • goofys <bucket> <mountpoint>

エラーメッセージ: goofys/internal/handles.go:456: undefined: url.PathUnescape
作者のkahing氏コメント: https://github.com/kahing/goofys/issues/196
go 1.8以上を入れてね、との事なのだが AmazonLinuxのリポジトリでは go 1.7.5 が入るので yumではNGか…

yumで導入したパッケージ一式を撤去

  • yum remove golang fuse -y

go lang本家からLinux用バイナリを取得して再度環境を構築

go lang のLinux用バイナリファイルを/usr/local/src へDL

  • cd /usr/local/src
  • wget https://storage.googleapis.com/golang/go1.9.linux-amd64.tar.gz

go lang のバイナリファイルを展開

  • tar -C /usr/local -xzf /usr/local/src/go1.9.linux-amd64.tar.gz
  • ls -al /usr/local/go

go lang バイナリを展開した先へ path を通す

  • export GOROOT=/usr/local/go
  • export PATH=$PATH:$GOROOT/bin
  • env | grep -i go

${GOROOT} は goライブラリの設置されているパスを設定する環境変数らしい…
参考: GOROOT と GOPATH : “http://qiita.com/1000ch/items/e42e7c28cf7a7b798a02#goroot-%E3%81%A8-gopath

go lang のパスが通った事とバージョンを確認

  • go versiongo version go1.9 linux/amd64 が入った

goofysを再度インストール

  • export GOPATH=${HOME}/go
  • go get github.com/kahing/goofys
  • go install github.com/kahing/goofys

${GOPATH} は作業ディレクトリを指す環境変数らしい…
参考: “http://qiita.com/1000ch/items/e42e7c28cf7a7b798a02#goroot-%E3%81%A8-gopath

goofys 実行ファイルのあるディレクトリにもpathを通す

  • export PATH=${PATH}:${GOPATH}/bin

S3バケットをマウントしてみる

  • goofys <bucket> <mountpoint>

エラーが出る > main.FATAL Unable to mount file system, see syslog for details syslogを見てねとの事なので確認。
syslogには main.FATAL Mounting file system: Mount: mount: running fusermount: exec: "fusermount": executable file not found in $PATH#012#012stderr:#012 という事で fusemount コマンドが無い、というエラーのためマウントできないっぽい。

エラー対処

goofys本家のInstallation の項目で On Linux, install via pre-built binaries. You may also need to install fuse-utils first. って書いてた…
そういえば↑の手順の中で fuseパッケージを1回 yumで入れたものを消してたな…
fuse についてよく知らなかったので、go関連のパッケージであればgolangが関連パッケージで上書きインストールされてしまう?とも思ったがfuse パッケージ単体でOKだった
fuseとは : https://ja.wikipedia.org/wiki/Filesystem_in_Userspace
fuseとは : https://www.ibm.com/developerworks/jp/linux/library/l-fuse/index.html
libfuse公式 : https://github.com/libfuse/libfuse

goofys マウント実行

  • マウント: goofys <bucket> <mountpoint>
  • アンマウント : umount <mountpoint>

その他調整

  • DocumentRootに利用できるか
  • fstab で再起動後も設定反映させたい
  • 関連環境変数設定のまとめ
  • 再起動して確認

DocumentRootに利用できるか

  • mount <bucket> <mountpoint>/ -o allow_other,--uid=<uid>,--gid=<gid>
  • uid gid の確認 : id apache または id nginx などで

allow_otherオプション無しでマウントしていると apache/nginx の実行ユーザーから読めないっぽい…
allow_otherオプション+ uid gid はdaemon実行ユーザと同じ設定にしてマウントすれば動いた:

fstab で再起動後も設定反映させたい

  • /etc/fstab に設定を追記
  • <fullpath/to/>goofys#<bucket> <mountpoint> fuse _netdev,allow_other,--dir-mode=0755,--file-mode=0666,--uid=<uid>,--gid=<gid> 0 0

本家のUsage にfstab で使う場合は root にAWS credentials 設定をせよとあるのでrootのユーザ環境に設定。
fstab のサンプルもUsageにある : goofys#bucket /mnt/mountpoint fuse _netdev,allow_other,--file-mode=0666 0 0
その他参考: http://caters.works/2016/08/%E3%81%95%E3%81%8F%E3%82%89%E3%81%AEvps%E3%81%AB-goofys-%E3%81%A7-s3-%E3%82%92%E3%83%9E%E3%82%A6%E3%83%B3%E3%83%88/

fstab 設定の試行(再起動無しで)

  • sudo mount -a

fstabに記載したのと同じ<mountpoint>をマウントした状態で実行している場合は、umountした後に実行

aws credential の profile を指定したい場合(未検証)

  • goofys#<bucket> <mountpoint> fuse _netdev,allow_other,--file-mode=<filemode>,--profile=<profile> 0 0 っぽい

本家のissues でやり取りを発見 : https://github.com/kahing/goofys/issues/222

環境変数回りをまとめる

  • rootユーザの環境変数へ設定を追加 : /root/.bashrc
export GOROOT=/usr/local/go
export GOPATH=${HOME}/go
export PATH=${PATH}:${GOROOT}/bin:${GOPATH}/bin

システム再起動後にも各所の設定が反映される事を確認

環境変数 : sudo env | grep -i go
go lang : go version
goofys : goofys -v
fstabログ : sudo tail -f /var/log/messages | grep goofys : main.INFO File system has been successfully mounted.
マウント状況 : df -ah # s3の空き表示って 1ペタになるのか…

続きを読む

EC2が止まったらS3に「死にました」と投稿する

概要

EC2インスタンスのシャットダウンをトリガーに、何か処理を実行する方法を記します。
今回はS3に辞世の句を投稿していますが、AutoScalingでterminateされるEC2のlocalのsyslogをS3に転送する等の処理にも応用できます。

やり方

S3編

S3にバケットを作成する

death_poem_1_1.png
  ※S3のバケット名はFQDNにしておくと色々捗る(余談) 

IAM編

S3にフルアクセスできるIAMを作成する

death_poem_2_1.png

death_poem_2_2.png

death_poem_2_3.png

death_poem_2_4.png

death_poem_2_5.png

 ※アクセスキーIDとシークレットアクセスキーは後で使うのでメモ帳にコピペしてください 

EC2編

1.AWS CLIをインストールする

 ※Amazon Linuxの場合は不要です  

//pipのインストール
# curl -O https://bootstrap.pypa.io/get-pip.py

//Python を使用してスクリプトを実行
# python get-pip.py --user

//PATH 変数に実行可能パスを追加
# export PATH=~/.local/bin:$PATH
# source ~/.bash_profile

//pipが正しくインストールされたことを確認
# pip --version

//pip を使用して AWS CLI をインストール
# pip install awscli --upgrade --user

//AWS CLI が正しくインストールされたことを確認
# aws --version

2.AWS CLIの初期設定をする

# aws configure

AWS Access Key ID [None]: [アクセスキーID]
AWS Secret Access Key [None]: [シークレットアクセスキー]
Default region name [None]: [空でok]
Default output format [None]:[空でok]

3.辞世の句スクリプトを作成する

# vim /etc/rc.d/init.d/DeathPoem.sh
/etc/rc.d/init.d/DeathPoem.sh

#!/bin/sh

InstanceId=`wget -q -O - http://169.254.169.254/latest/meta-data/instance-id`

declare logdir=/var/www/log
declare log=/death_poem.log
declare bucket=files.hoge.com
declare now=`date +'%Y-%m-%d'`
declare s3_target="s3://${bucket}/death_poem_${now}/"

mkdir $logdir >/dev/null 2>&1

printf 'I am '$InstanceId'¥n' >> $logdir$log
printf 'I was born 'date --date=@$(expr `date +%s` - `cut -d "." -f 1 /proc/uptime`) >> $logdir$log
printf 'I was just 'cat /proc/uptime | awk '{print $1 / 60 /60 /24 "days (" $1 "sec)"}' |  tr -d '¥n''  from birth ''¥n' >> $logdir$log
printf 'I will die 'date'¥n¥n' >> $logdir$log

aws s3 sync $logdir $s3_target

4.辞世の句スクリプトに実行権限を与える

# chmod 755 /etc/rc.d/init.d/DeathPoem.sh

5.rc.local(起動時実行)を編集する

# vim /etc/rc.d/rc.local
/etc/rc.d/rc.local

#!/bin/sh
#
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don't
# want to do the full Sys V style init stuff.

touch /var/lock/subsys/local

/sbin/ethtool -s eth0 wol g

touch /var/lock/subsys/DeathPoem
ln -s /etc/init.d/DeathPoem.sh /etc/rc0.d/K00DeathPoem
ln -s /etc/init.d/DeathPoem.sh /etc/rc6.d/K00DeathPoem

6.EC2インスタンスを再起動する

# reboot

7.ログを確認する

# tailf /var/www/log/death_poem.log
/var/www/log/death_poem.log

I am i-************
I was born Mon Sep 11 04:00:48 UTC 2017
I was just 0.00817488days (706.31sec)  from birth 
I will die Mon Sep 11 04:12:34 UTC 2017

8.S3のバケットを確認する

上記と同じ内容の辞世の句が投稿されているはず!

余談

昔は簡単だった(らしい)

EC2で起動時やterminate時にシェルを実行する | Developers.IO

mytest.sh
#!/bin/sh
# chkconfig: 2345 99 10
# description: test shell

case "$1" in
 start)
       echo "start!" > /path/your/start.txt
       ;;
 stop)
       echo "stop!" > /path/your/stop.txt
       ;;
  *) break ;;
esac

あのクラスメソッドさんが書いた記事なら間違いない!
…と思っていたのですが、上記の方法では”start”のイベントしか取得できませんでした。
コメントにあったprocessnameを追加しても結果は同様でした。
原因をご存じの方いたらぜひ教えて欲しいです :bow:

とても参考になった文献

CentOS6.0 Shutdown時にコマンド実行 : 事象の水平線 :

リスペクト

心臓が止まったらSNSに「死にました」と投稿する

続きを読む

Deep Security User Night #5 レポート

こんにちは、ひろかずです。

Deep Security User Night #5に行ってきたので一筆書きます。
会場は前回に続きHAPON新宿
日本地図をモチーフにした机がオシャレな空間です。

プシュッと開けてからスタートです。

お品書き

  • Google Cloud Platformの紹介とセキュリティとDS on GCPの話
  • 我が家の箱入り娘を世間に晒すのは危険なのでDeep Securityに見守ってもらった話
  • Deep Security APIを活用したルールアップデートの自動化について

Google Cloud Platformの紹介とセキュリティとDS on GCPの話

Google Cloud Japan
金子さん

トレンドマイクロとは長い付き合い
よなよなエール好き(箱買い派)

2017/6にDeep SecurityがGCPに対応
AWSに比べてまだまだ機能は足りないけど、これから
評価ガイドあります!(スタートアップガイド)

  • IaaSにManagerを立てて、保護サーバーにAgentを入れる方式

GCPの概要
Google関連サービスは、10億を超えるユーザー
どういうインフラで動いてるの?

  • バカでかいデータセンター
  • データセンターから自作
  • ラックも自作
  • 国内サーバベンダーより多くのサーバを作ってる
  • コンポーネントを極限まで削っているので、セキュア
  • 管理は自動化。分散処理基盤がある。
  • データセンター as a Computer
  • その一部を切り出すのがGCP
  • 東京リージョン開設時は超忙しかった
  • インフラ規模のインフラ(プラネットスケールインフラストラクチャ)
  • 3年間で3兆円の投資

セキュリティ頑張ってます!

  • すべてのレイヤーに厳しいセキュリティが施されている
  • Googleのセキュリティ専任部門(750人)
  • FISCにも対応!
  • NICに特注チップを付けて、変なところにパケットを飛ばさないようにチェック
  • データは暗号化され、分割と難読化でディスク単位では読みだせないようにしている。
    データは、GCP内でやり取りされる(VMコピー時に、通信はインターネットに出ない)

HTTP(S)ロードバランサ

  • 1IPでリージョン跨ぎの負荷分散
  • 暖気申請なしで100万リクエストに対応

IaaSの特徴

  • ライブマイグレーション
  • 勝手にやってくれるクラウドサービスはGCPだけ。
  • KVMベースのハイパーバイザで対応している
  • 1000VMが5分で起動する
  • VMネットワークは16Gbps
  • GCPカスタムマシンタイプ(GPU特化型とか)

BigQuery

  • SaaSのようなデータウェアハウス
  • 72GBのフルスキャンが6.7秒
  • 大量サーバとストレージ、ペタビットネットワークによる超並列処理クエリ
  • 1TBを1秒でスキャンするために、10000ディスクスピンドルを用意する考え方

そろそろDeep Security

  • BigQueryでDSのログを検索(1.32TB, 40億レコード)
  • 4.2秒で検索!

我が家の箱入り娘を世間に晒すのは危険なのでDeep Securityに見守ってもらった話

フューチャーアーキテクト株式会社
日比野さん

Deep SecurityとElasticSearch

  • ハニーポットに対する通信をDSでの検知状況を可視化
  • パロアルトのファイアウォールも用意
  • ハニーポットはコンテナ
  • 今回は、サーバ型、低対話型のハニーポットを用意
  • 低対話型は、簡単だが取れる情報はそれなり

標的型攻撃の攻撃フェーズに対してハニーポットが取れる情報

  • 偵察
  • 情報探査
  • 情報集約
  • 情報送信

ハニーポット書籍

  • 実線サイバーセキュリティモニタリング
  • サイバー攻撃の足跡を分析するハニーポット観察日記

今回のハニーポットは、Open Canaryを採用(コンテナでデプロイ)

  • Dockerコンテナ実行環境を用意して、
  • ログはLogStashでElasticSearchに送信
  • ハニーポットのAWS適正利用規約がある(事業者によって異なるので注意)
  • Deep Securityは、10.1を使用
  • DSaaS環境を利用(今回は双方向通信を採用)
  • Deep Securityのログは、UDP514で通信させた

Paro Alto

  • 15日間は無料
  • ライセンス高いから、忘れずに消す!

ログの可視化には、ElasticStackがおすすめ!

  • Kibana
  • Elastich
  • X-Pack(有償サブスクリプション:レポーティング、アラート、グラフ、ML)
  • 最新版5.5で構築し、Syslog受信したログをElasticSearch

結果

  • 中国、台湾が大活躍
  • 8/31-9/3ごろまで
  • ピーク時6000件のログがでた(ParoAlto)
  • 平日は、MSSQL(1433)が多かったが、土日はSSHが爆裂
  • 攻撃で使われるアカウントやパスワードは、リストに載っているものがやはり多かった(デフォルトパスワードは、やはり危険)
  • 機械学習は、閾値を設けた使い方が有効そう
  • Deep Securityのログの正規化は簡単にできた。
  • ファイアウォール機能で遮断していたので、侵入防御やセキュリティログ監視は反応しなかった。

まとめ

  • ログは事実だが、それだけでは意味がある分析結果は得られない
  • とりあえずログを集めるのはNG
  • 何をなすためにログを集めるのかという必要性を理解して、小さく始めるのがいい
  • ログの結果から対策に活かすPDCAが大事!

Deep Security APIを活用したルールアップデートの自動化について

アイレット株式会社
恩田さん

Deep Securityは、securitypackというサービスで使っている。
ルールアップデートしてますか?

  • 手動や自動で適用してもいいけど、いきなり防御されたら大変
  • アップデート処理は、アクセスが集中するので処理が重くて大変!

DeepSecurity API

  • REST
  • Sorp

REST API

  • 機能がだいぶ足りない
  • 新しい機能が実装されている

SOAP API

  • 古典的な機能が実装されている
  • 機能の数は多数

SDK

  • 統一されたフロントを提供するので区別しなくていい(機能の60%)
  • dsm.py:マネージャークラス
  • polices.py:ポリシークラス, ルールクラス
  • が、GitHubプロジェクトは全然動いてない
  • なので、足りない部分は実装しよう!

まとめ

  • SOAPが解決してくれる

要望

  • アップデート配信日はサーバーを強化してください!
  • APIとUIのドメインを統一してほしい

今回も盛り上がった回でした!

今日はここまでです。
お疲れさまでした。

続きを読む

CloudWatchカスタムメトリクス追加方法(ディスク、メモリ)

やること

AWSのCloudWatchは、デフォルトだとディスクとメモリ使用率を見ることができません。
そこで利用するのがカスタムメトリクスです。
ディスクとメモリのカスタムメトリクスを追加します。

前提

  • インスタンスに、EC2FullAccessとCloudWatchFullAccessの権限を持ったIAMロールを関連づけている。(推奨)
  • もしくは、上記権限を持ったユーザがおり、アクセスキーとシークレットキーを用意している。(非推奨)

手順

1.対象サーバへログインする

2.スクリプトのインストール

# yum install perl-Switch perl-DateTime perl-Sys-Syslog perl-LWP-Protocol-https perl-Digest-SHA
# curl http://aws-cloudwatch.s3.amazonaws.com/downloads/CloudWatchMonitoringScripts-1.2.1.zip -O

3.圧縮ファイルの解凍と圧縮ファイルの削除

# unzip CloudWatchMonitoringScripts-1.2.1.zip
# rm CloudWatchMonitoringScripts-1.2.1.zip

4.crontabへのスクリプト実行設定

# crontab -e

 以下の内容を記述する。
 今回は、5分に1回の実行に設定する。

●IAMロール適用バージョン(推奨)
*/5 * * * * ~/aws-scripts-mon/mon-put-instance-data.pl  --mem-util --disk-space-util --disk-path=/ --from-cron

●アクセスキーとシークレットキーを記載(非推奨)
*/5 * * * * ~/aws-scripts-mon/mon-put-instance-data.pl  --mem-util --disk-space-util --disk-path=/ --from-cron --aws-access-key-id=アクセスキー --aws-secret-key=シークレットキー

5.crondの再起動

# systemctl restart crond

6.追加の確認
 AWSのコンソール画面で、CloudWatchを選択し、DiskSpaceUtilizationが追加されていることを確認する。

参考URL
http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/mon-scripts.html#using_put_script

続きを読む