14Room

みんな泣きながらオトナになったんだ。

td-agentでtemporarily failed to flush the buffer error="could not find a temporary directory" と言われたら

td-agentでログをS3にアップロードって、よくやりますよね。 でも、アップロードされないのです(TT)。

で、td-agentのログを調べたら、

temporarily failed to flush the buffer. next_retry=2016-11-11 07:26:34 +0000 error_class="ArgumentError" error="could not find a temporary directory"

なんて言われてる。バッファをフラッシュできないから、ログがS3に上がらないのは分かるけど、temporary directory ってなんだろ?w

と思って調べたら、/tmp の事らしい。

で、確認したら、この問題が起こったサーバだけパーミッションがおかしい。。。。。

ls -la /
drwxrwxrwt.  12 root root      12288 Oct 10 06:01 tmp

こうなってて欲しいのに実際は、

ls -la
drwxr-xr-x.   4 root root       4096 Oct 10 07:03 tmp

なので、パーミッションを直して、td-agentを再起動したら、無事にログがS3に送られるようになりました。

apt-get updateでAn error occurred during the signature verificationが出たときの対処法

久しぶりに apt-get update しようとしたところ、

W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: http://packages.treasuredata.com trusty InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 901F9177AB97ACBE

W: Failed to fetch http://packages.treasuredata.com/2/ubuntu/trusty/dists/trusty/InRelease

W: Some index files failed to download. They have been ignored, or old ones used instead.

なんてメッセージが表示されました。 どうもtreasuredataのsha1で作られたGPG keyが廃止になったのが原因で、古いGPG keyを使ってるとerrorになるようです。 なので下記の手順で古いのを消して、新しいのを入れましょう。

% apt-key del A12E206F
% curl -O https://packages.treasuredata.com/GPG-KEY-td-agent
% apt-key add GPG-KEY-td-agent

ansibleのset_factで宣言した変数は、同じset_fact内では参照できない

下記のようなplaybookを作って実行したところ、

- hosts:
  - localhost
  connection: local
  become: False
  gather_facts: False
  tasks:
  - set_fact:
      aaa="naked"
      bbb="{{ aaa }}"

undefined variableとか言われちゃって、エラーになっちゃいます。

# ansible-playbook test.yml
...
TASK [set_fact] ********************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'aaa' is undefined\n\nThe error appears to have been in '/home/naked123/test.yml': line 7, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n  tasks:\n  - set_fact:\n    ^ here\n"}

うーん、 aaa は直前で宣言してるんだけどなぁ。 しょうがないので、下記のようにset_factを2つ使うとエラーは無くなりました。

- hosts:
  - localhost
  become: False
  gather_facts: False
  connection: local
  tasks:
  - set_fact:
      aaa="naked"

  - set_fact:
      bbb="{{ aaa }}"

かっこ悪いなぁ。

githubに登録したpublic keyが分からなくなったら

仮の話ですが、例えばgithubに登録していたSSHのprivate keyが外部に流出しちゃった場合は早急にその鍵を使えなくする必要があると思うのですが、たくさん登録してたりすると、どれが流出したprivate keyと対になるpublic keyなのか分からない事があります。(いや、普通は無いと思うのですけどね)

そんな時は下記のようにフィンガープリントを出力して、githubに設定してあるpublic keyの値と比べてみましょう。

$ ssh-keygen -E md5 -lf id_rsa
2048 MD5:xx:yy:zz:ac:cd:de:9a:ad:bb:5c:fc:0d:55:bd:f0:21 naked@local (RSA)

この xx:yy:zz:ac:cd:de:9a:ad:bb:5c:fc:0d:55:bd:f0:21 がフィンガープリントです。

docker execでパイプ「|」を含んだコマンドを実行させたい。

題名のままなのですが、docker execでパイプ「|」を含んだコマンドを実行させたい状況が発生しました。

例えばdockerで動くpostgresに対して、下記のようなコマンドでデータをリストアしようとした場合です。

docker exec postgres_container gunzip -c backup.gz | psql -U postgres mydb

しかし、このまま実行すると、パイプから後のコマンド( psql -U postgres mydb ) はコンテナ内のコマンドではなく、dockerが動いてるホストマシン上のコマンドと認識されてしまい、意図した通りに動きません。

そこで、こんな時は下記のようにsh -c を使うとうまくいきます。

docker exec postgres_container sh -c "gunzip -c backup.gz | psql -U postgres mydb"

単純にダブルクォートで囲んだだけでは上手く行かないところが落とし穴ですね。

参考にしたページ

docs.docker.com

td-agentでログをS3に送る、ついでに暗号化もする。

概要

ある程度の規模になると、日々サーバ上に溜まるログを何処かに集約したくなります。 オートスケールなどを利用するとサーバ停止時にログも一緒に失われるので、サーバ上のストレージ以外の場所に待避した方が良さそうです。 今なら安価で安全なS3に置くのが吉でしょう。また昨今、セキュリティ的に暗号化の機運が高まって来てる?のでS3に置く際に暗号化もしてみました。

td-agentの設定

td-agentのインストールは割愛します。あとログを送る側のサーバはIAM roleでS3のバケツへのフルアクセス権限があるものとします。

<source>
  type tail
  format none
  path /var/log/audit/audit.log
  pos_file /var/tmp/td-agent/aws_s3_logs.audit.audit.pos
  tag aws_s3_logs.audit.audit
  @label @raw
</source>


<label @raw>
  <match aws_s3_logs.**>
      type forest
      subtype s3
      <template>
        format single_value
        s3_bucket "server-logs-naked-com"
        s3_region "#{`curl -s -m 1 http://169.254.169.254/latest/meta-data/placement/availability-zone`.chop}"
        s3_object_key_format "%{path}.%{time_slice}.%{index}.%{file_extension}"
        path "${tag_parts[1]}/%Y/%m/%d/${tag_parts[1]}.${tag_parts[2]}.#{`hostname -s`.chomp}.#{`curl -s -m 1 http://169.254.169.254/latest/meta-data/instance-id`.chomp}"
        time_slice_format "%Y%m%dT%H00Z"
        time_slice_wait 10m
        use_server_side_encryption AES256
        utc
        buffer_type file
        buffer_path "/var/tmp/td-agent/s3.${tag}"
        buffer_chunk_limit 128m
        disable_retry_limit true
      </template>
  </match>
</label>

結果

f:id:naked123:20170522100412p:plain 実際にS3に置かれたログファイルのプロパティを見ると暗号化されたことが確認できる。

ausearchをcronで定期実行させる

auditのlogから欲しい情報を検索するために使えるausearchはとても便利です。 -kでkey fieldに設定した文字列を含む情報だけ抜き出すとか、–start, –endで指定した時間の情報だけ見るとかもできます。

しかし、crontab中でausearchを呼び出すと期待した結果が得られません。コマンドラインで実行するとちゃんと結果が出るのに何故?と私はハマりました。 そんな時は --input-logs オプションをつけて呼び出すか、-if <Input File name> オプションで読み込むlogファイルを指定することで、コマンドライン実行時と同じ結果が得られます。

ausearchのオプションを見るとちゃんと書いてあるんですけどね・・・・(汗