2015年4月18日土曜日

IAMロールを使ってEC2からS3のバケット一覧を取得してみた時のメモ

このエントリーをはてなブックマークに追加 はてなブックマーク - IAMロールを使ってEC2からS3のバケット一覧を取得してみた時のメモ

IAMロールを使ってEC2からS3のバケット一覧を取得してみた時のメモ

参考

EC2からS3へアクセスするIAMロールを作る

  • Roles
  • Create New Role
  • ロール名を決める(S3_Accessなど)
  • AWS Services RoleではAmazon EC2を選択
  • Attach PolicyではAmazonS3FullAccessを選択(一覧を取るだけなのでReadOnlyのものでもOK)
  • Create Role

EC2の起動

起動する時のIAM Roreの項目で先ほどのロールを選択(S3_Accessなど)

確認

以降、対象のEC2にSSHログインしてからの操作。

Rubyでやってみる。まずはAWS-SDKをインストール

$gem install aws-sdk-core

コードを書いてみる

$vi get_buckets.rb

以下のようにする。

require "aws-sdk-core"

Aws.config[:region] = 'ap-northeast-1'
s3 = Aws::S3::Client.new

resp = s3.list_buckets
puts resp.buckets.map(&:name)

実行

$ruby get_buckets.rb

これで取得できちゃいます。credentialsの設定とかを特にしなくて良いので楽。ドキュメントを見るとローカルのcredential情報を探した後になければIAMRoleの情報を探して使うようです。便利。

This code initializes an AWS::S3 object without specifying any credentials, which initiates a search for credentials using the default credential provider chain. The default credential provider chain looks for credentials specified in the environment, and failing that, will look for credentials from EC2’s metadata service.

また、メタデータ(curl http://169.254.169.254/latest/meta-data/iam/security-credentials/S3_Access)を直接取得すると分かるのですが、利用できるAccessKeyIdとSecretAccessKeyは一定周期でより変わるので、直接credentialファイルを置くよりもよりセキュアだと思います。

2015年4月16日木曜日

AWS-VPCピアリングを試してみた

このエントリーをはてなブックマークに追加 はてなブックマーク - AWS-VPCピアリングを試してみた

VPCピア接続を行い、異なるVPC間でのSSH接続を確認した時のメモ

参考

前提

  • 同一リージョン
  • アベイラビリティゾーンは違っても大丈夫
  • AWSアカウントが違っても大丈夫
  • IPアドレス帯域が重複することはNG。VPCに割り当たっているのが172.16.0.0/16と172.16.0.0/16だとNGダメ。同じように172.16.0.0/16と172.16.1.0/24でも重複する帯域があるのでNG

AWSでの設定

上記がとても詳しく書いてありました。下記メモ。

  • 異なるCIDRのVPCを作成。今回の場合、VPC-A(172.31.0.0/16)とVPC-B(10.0.0.0/16)のCIDRを持つVPCで検証。
  • VPCのPeering Connectionsを選択し、VPC-A側でVPC Peering Connectionを作成する。Local VPC to peerでは接続するVPC-Bを選択する。別のAWSアカウントを利用する場合、Account情報を入れる
  • 上記実施後、VPC-B側でPeeringの承認をする
  • VPC-A,Bそれぞれでルーティング設定を行う

テストしてみる

準備ができたのでEC2を起動して、異なるVPC間でSSH接続ができるか確認します。

  • VPC-A,VPC-BにそれぞれEC2を起動します。どちらのEC2でもAuto-assign PublicIPの設定を行います。また、SecurityGroupでは22ポートでanywhere(0.0.0.0)からの接続を許可するようにします。
  • 自分のPCからどちらにもSSH接続できることを確認します。
  • VPC-Bで新しくユーザーを作成します。EC2にSSH接続用のユーザーを作成するを実施。
  • VPC-Aにログイン。~/.ssh/id_rsaを上記でコピペしたid_rsaの内容に変更。その後、chmod 0600 ~/.ssh/id_rsaを行う。
  • ssh deploy@10.0.1.233としてSSHログインできるか確認。指定するVPC-Bに存在するEC2のプライベートIPの部分は読み替えてください。
  • VPC-B側のSecurityGroupでSSHのinboundを許可するIPをanywhere(0.0.0.0/0)からVPC-A側のプライベートIP(172.31.15.213/16)などに指定します。そうすることでVPC-B側へのSSHはVPC-Aのインスタンスを介してのみできるような設定とできます。

2015年4月11日土曜日

fluentd-v2+elasticsearch+kibana3をEC2上で実施する

このエントリーをはてなブックマークに追加 はてなブックマーク - fluentd-v2+elasticsearch+kibana3をEC2上で実施する

nginxのアクセスログをfluentdを使ってelasticsearchに登録し、その情報をkinaba3を使って見れるようにした時のメモ

環境

  • Amazon Linux AMI 2015.03 (HVM), SSD Volume Type
  • td-agent 0.12.7
  • elasticsearch 1.3(最終的に1.4にアップグレード)
  • kibana3

td-agent2のインストール

最新のFluentd(td-agent2)ではAmazonLinuxもサポートとなったようなのでスクリプトからインストールします

td-agent2をAmazon Linuxで実行する

curl -L http://toolbelt.treasuredata.com/sh/install-redhat-td-agent2.sh | sudo sh
$td-agent --version
td-agent 0.12.7
$sudo chkconfig td-agent on
$sudo chkconfig --list |grep td-agent

elastic-search1.3のインストール、起動

基本的には公式サイトに書いてあるように進めます。

elastic-search(YUM)

$sudo rpm --import https://packages.elasticsearch.org/GPG-KEY-elasticsearch
$sudo vi /etc/yum.repos.d/elasticsearch.repo

以下を記載します。

[elasticsearch-1.3]
name=Elasticsearch repository for 1.3.x packages
baseurl=http://packages.elasticsearch.org/elasticsearch/1.3/centos
gpgcheck=1
gpgkey=http://packages.elasticsearch.org/GPG-KEY-elasticsearch
enabled=1

インストールおよび自動起動登録、起動をします。

$sudo yum install elasticsearch
$sudo chkconfig --add elasticsearch
$sudo chkconfig --list |grep elasticsearch
$sudo service elasticsearch start

なお、起動時にメモリ量が確保出来なくてエラーになる場合があります。その場合には不要なプロセスをkillすればt2.microでも起動できました。もしくは/etc/elasticsearch/elasticsearch.ymlでメモリ量を記載することでも調整できるようです。

クラスタとノードの名前を確認

クラスタとノードの名前を確認します。 jqをインストールしていない人はyumでインストールしておくと便利だと思います。

# cluster
$curl -XGET http://localhost:9200/_cluster/health | jq .
{
  "cluster_name": "elasticsearch",
  "status": "green",
  "timed_out": false,
  "number_of_nodes": 1,
  "number_of_data_nodes": 1,
  "active_primary_shards": 0,
  "active_shards": 0,
  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 0
}

# node
$curl -XGET http://localhost:9200/ | jq .
{
  "status": 200,
  "name": "Sam Wilson",
  "version": {
    "number": "1.3.9",
    "build_hash": "0915c7306e6264ba21a6cb7609b93545ccc32ef1",
    "build_timestamp": "2015-02-19T12:34:48Z",
    "build_snapshot": false,
    "lucene_version": "4.9"
  },
  "tagline": "You Know, for Search"
}

デフォルトだとクラスタ名はelasticsearch、ノードは任意のマーベルコミックの人物になるようです。

クラスタの名前を変更する

クラスタ名とノード名を任意のものに変更します。本例ではクラスタ名をtest_cluster、ノード名をnode_1としました。

$sudo vi /etc/elasticsearch/elasticsearch.yml

cluster.name: test_cluster

node.name: "node_1"

設定後、サービスを再起動します。

$sudo service elasticsearch restart

変更を確認します。

# cluster
$curl -XGET http://localhost:9200/_cluster/health | jq .

# node
curl -XGET http://localhost:9200/ | jq .

どちらも変更されていることが確認できると思います。

nginxのインストール

$sudo yum install nginx
$sudo service nginx start
$sudo chkconfig nginx on
$chkconfig --list |grep nginx

fluentdのelastic-searchプラグインのインストール

fluentd経由でelastic-searchのプラグインをインストールします。事前に必要となるDevelopment toolscurl-develもインストールします。

$sudo yum groupinstall 'Development tools'
$sudo yum -y install curl-devel
$sudo /opt/td-agent/embedded/bin/fluent-gem install fluent-plugin-elasticsearch

nginxのアクセスログのフォーマットを確認する

nginxのログフォーマットを確認するためにFluentularというサイト上でFluentdのログフォーマットを確認できるサイトを使います。

上記サイトで実際に出力されるログとそのフォーマットが正しくできるまでを確認後、実際に設定ファイルに記載して内容を確認します。

まずは、標準出力に出すようにしています。

$sudo vi /etc/td-agent/td-agent.conf

以下のように記載します。

<source>
  type tail
  path /var/log/nginx/access.log
  format /^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)" "(?<forward>[^\"]*)")?$/
  time_format %d/%b/%Y:%H:%M:%S %z
  pos_file /var/log/td-agent/nginx-access.log.pos
  tag nginx.access
</source>

<match nginx.access.**>
  type stdout
</match>

実際に動作が可能なやってみます。 今回はログがわかり易いようにflunetdをトレースモードで起動します。

$sudo td-agent -vv &

その後、実際にnginxにアクセスしてみます。

$wget http://localhost
--2015-04-11 02:53:04--  http://localhost/
localhost (localhost) をDNSに問いあわせています... 127.0.0.1
localhost (localhost)|127.0.0.1|:80 に接続しています... 接続しました。
2015-04-11 02:53:04 +0000 nginx.access: {"remote":"127.0.0.1","host":"-","user":"-","method":"GET","path":"/","code":"200","size":"3770","referer":"-","agent":"Wget/1.16.1 (linux-gnu)","forward":"-"}
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 3770 (3.7K) [text/html]
`index.html' に保存中

index.html          100%[=====================>]   3.68K  --.-KB/s 時間 0s

2015-04-11 02:53:04 (555 MB/s) - `index.html' へ保存完了 [3770/3770]

設定がうまくいっていれば、上記のメッセージの中にnginx.accessなどのように正しくfluentdがログをパースできているか確認できます。

上記、問題なければ一度fluentdを止めます。

$ps aux|grep ruby|awk ‘{ print $2 }’|sudo xargs kill -KILL

td-agentの設定ファイルを変更します。 デバッグ用にcopyプラグインを使って、標準出力もしつつ、ElasticSearchへの登録を行う設定に変更します。

$vi td-agent.conf

以下のように変更します。

<source>
  type tail
  path /var/log/nginx/access.log
  format /^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)" "(?<forward>[^\"]*)")?$/
  time_format %d/%b/%Y:%H:%M:%S %z
  pos_file /var/log/td-agent/nginx-access.log.pos
  tag nginx.access
</source>

<match nginx.access.**>
  type copy

  <store>
    type stdout
  </store>

  <store>
    type elasticsearch
    host localhost
    port 9200
    type_name nginx_log
    include_tag_key true
    logstash_format true
    tag_key tag
  </store>
</match>

再起動後、nginxにリクエストを投げてアクセスログを更新します。

$td-agent -vv &
$wget http://localhost

先程と同じように標準出力にログがパースできているか確認し、問題なければ少し待つと以下のような出力がされます。

2015-04-11 04:19:50 +0000 [info]: plugin/out_elasticsearch.rb:67:client: Connection opened to Elasticsearch cluster => {:host=>"localhost", :port=>9200, :scheme=>"http"}

上記出力後、問題なければlogstash–2015.04.11というような今日の日付のインデックスができていると思うので全ての内容を取得します。

#データ取得(全件)
curl -XGET http://localhost:9200/logstash-2015.04.11/_search -d '
{
  "query": {
    "match_all" : {}
  }
}
' | jq .
{
"took": 44,
"timed_out": false,
"_shards": {
  "total": 5,
  "successful": 5,
  "failed": 0
},
"hits": {
  "total": 1,
  "max_score": 1,
  "hits": [
    {
      "_index": "logstash-2015.04.11",
      "_type": "nginx_log",
      "_id": "8w0OI32bRRObQna13HGcJQ",
      "_score": 1,
      "_source": {
        "remote": "127.0.0.1",
        "host": "-",
        "user": "-",
        "method": "GET",
        "path": "/",
        "code": "200",
        "size": "3770",
        "referer": "-",
        "agent": "Wget/1.16.1 (linux-gnu)",
        "forward": "-",
        "tag": "nginx.access",
        "@timestamp": "2015-04-11T04:18:57+00:00"
      }
    }
  ]
}
}

例えばsizeパラメーターが3000より大きいものみ取得したい場合には以下のようなリクエストを送ります。

curl -XGET http://localhost:9200/logstash-2015.04.11/_search -d '
{
  "query": {
    "query_string" : {
    "query" : "size:>3000"
   }
 }
}
' | jq .

kibanaのインストール

現在はKibana4がリリースされていますが、導入してみたところ、elasticsearch1.4.4以上である必要があったので今回はKinaba3で実施することにしました。

Kibana3.1.2

$wget https://download.elastic.co/kibana/kibana/kibana-3.1.2.tar.gz
$tar -zxvf kibana-3.1.2.tar.gz
$mv kibana-3.1.2 kibana
$sudo mv kibana /usr/share/nginx/html

nginxを再起動します。

$service nginx restart

上記の場合http://yourhost/kibanaとするとkibanaのサイトにアクセスできるようになっているかと思います。

ただし、Connection failedと表示されてelasticsearchとの接続がうまくできていないようでした。

上記原因の一つとしてまず、SecurityGroupの設定で9200ポートを開いていないことが問題の一つだったので、開けるように設定します。

また、上記を対応してもまだ接続エラーとなってしまい、色々探したのですが、利用が全くわからなかったのでelasticsearchのバージョンを1.3から1.4にあげて、設定を変えてみたところうまくいきました。

ElasticSearch–1.4-YUM

$sudo vi /etc/yum.repos.d/elasticsearch.repo

以下に変更。

[elasticsearch-1.4]
name=Elasticsearch repository for 1.4.x packages
baseurl=http://packages.elasticsearch.org/elasticsearch/1.4/centos
gpgcheck=1
gpgkey=http://packages.elasticsearch.org/GPG-KEY-elasticsearch

アップデート。

$sudo yum update

また、elasticsearch1.4からセキュリティ向上が目的で設定が追加で必要になったようで、それを追加します。

Kibana3+Elasticsearch1.4.1でConnection Failedと怒られる

$sudo vi /etc/elasticsearch/elasticsearch.yml 

以下を末尾に追記。

http.cors.allow-origin: "/.*/"
http.cors.enabled: true

サービスを再起動。

$sudo service elasticsearch restart
$sudo service nginx

この状態でアクセスするとうまくできました。

2015年3月27日金曜日

JenkinsとServerspecでサーバーの設定ファイルを定期監視する

このエントリーをはてなブックマークに追加 はてなブックマーク - JenkinsとServerspecでサーバーの設定ファイルを定期監視する

既に動いているサーバーの運用をしていて

  • 検証環境と本番環境で設定ファイルが意図せず違うことがある(DB接続先が違うというものではなく)
  • 運用でよく使う設定(cron,logrotate)の設定方針がサーバーで違う

など辛かったので、状況を改善するためにまずはJenkinsとServerspecを使って設定ファイルの定期監視をするようにしました。(本来はそのような状況になっていないべきですが、既にその状況になっている場合にはまず現状把握が大事かと個人的には思いました)

具体的には

  • Serverspecで指定された場所にファイルがあるか確認する(cronであればanacronなのか/etc/cron.dなのか/var/spool/なのか)
  • 設定ファイルをGitlabに登録し、実サーバーのファイルと同一であるか確認する(md5sum)

ということをJenkinsのデイリーで実行するジョブを設定するようにしてみました。

実際に行うと

  • SSHしなくても設定ファイルがどのようになっているかをGitlab(ブラウザ)から見れるように可視化
  • cronなどの設定がサーバーごとにどこにされているか分かるようにする
  • Gitlabに登録されたファイルと違う場合にはエラーとしてすぐに検出し、誰が何のために変えたかを確認し、Gitlabに登録することで履歴を追えるようにする

というメリットが得られました。

本サンプルではJenkinsを動かすサーバーとServerspecで検証するサーバーを同じにしていますが、実際はServerspecで検証したいサーバーは別ホストになると思うので適宜置き換えてください。

サンプル

toshihirock/MonitorFiles

とりあえず構成みたい、最終的にどんな感じになるか確認する場合にはどうぞ。

準備

各サーバーから設定ファイルを取得してGitlabに登録しておきます。検証、本番でファイルが違う場合にはフォルダを分けるなどして管理とします。

例えばnginxの設定ファイルが各環境で違う場合

nginx/
├── development
├── production
└── verification

という風にします。トップディレクトリをverificationなどの環境にしてその下にサービスごとにディレクトリを切ってもいいでしょうし、状況に応じて構成を変更すれば良いと思います。

差分が少ないファイル(DB接続先が違うだけなど)であれば管理するファイルは一つにしてServerspecのテスト内でファイル内の文字列を置き換える方式でも良いかもしれません。

Jenkinsのインストール

Jenkinsをインストールします。

  • インストール方法はJenkinsの公式サイト参照
  • JenkinsのGit Pluginをインストールしておくこと

また、Jenkinsユーザーになり、以下のコマンドでbundleは入れておきます。

$gem install bundle

Serverspecのテストを書く

設定ファイルが登録してあるリポジトリでServerspecのテストを書きます。書くテストコードですが、ServerspecはRubyなので以下のようにすることで設定ファイルが同一か確認出来きます。

require 'spec_helper'
require 'digest/md5'

describe file('/etc/nginx/nginx.conf') do
  its(:md5sum) { should eq Digest::MD5.file('nginx/nginx.conf').to_s }
end

パスの設定部分(nginx/nginx.conf)は適宜環境に合わせて変更してください。

Jenkinsで実行する

ジョブを作って以下のようなスクリプトを実行することでServerspecを実行できます。

bundle install
bundle exec rake

ただ、この状態だとJenkinsの出力結果で色がつかず見ずらいので、設定変更およびJenkinsプラグインを使って見やすくします。

まず、以下2つのJenkinsプラグインをインストールします。

次にJenkinsの設定でURL of theme CSSと記載されている場所にhttp://jazzzz.github.io/jenkins-black-console/black-console.cssというコンソールの背景を黒くするCSSを指定します。

また、対象のジョブの設定のColor ANSI Console Outputで任意のAnsiColorMapを指定します。

Jenkins側の設定はこれで終わりなのですが、Serverspec側でも.rspecファイルに–ttyを追加してRspec実行時にttyオプションを有効化します。

--color
--format documentation
--tty

これでジョブを実行すればいい感じに色付きで見えるようになります。

XMLでのテスト結果の出力を行う

通常出力されるメッセージでもわかりやすいのですが、せっかくJenkinsを使っているのでより見やすいようにXML出力して、グラフ形式などで見れるようにしようと思います。

RSpec(Servespec)ではXML出力は出来ないのでrspec_junit_formatterを利用します。

$echo "gem 'rspec_junit_formatter'" >> Gemfile
$bundle install

これでbundle exec rake –format RspecJunitFormatter –out reports/result.xmlとするとXML出力は可能です。ただし、CLIから実行するとホストが複数ある時に後で実行した結果をresultx.xmlで上書きするので、一つのホストの結果しか見えません。なので、Rakefileでホスト名ごとに結果のxmlを出力するようにします。また、ローカルで確認する場合にはXML出力でなく、documentフォーマットで見たいのでRakefileでは環境変数JENKINSが設定されている場合のみ、XML出力するようにします。

require 'rake'
require 'rspec/core/rake_task'

task :spec    => 'spec:all'
task :default => :spec

namespace :spec do
  targets = []
  Dir.glob('./spec/*').each do |dir|
    next unless File.directory?(dir)
    target = File.basename(dir)
    target = "_#{target}" if target == "default"
    targets << target
  end

  task :all     => targets
  task :default => :all

  targets.each do |target|
    original_target = target == "_default" ? target[1..-1] : target
    desc "Run serverspec tests to #{original_target}"
    RSpec::Core::RakeTask.new(target.to_sym) do |t|
      ENV['TARGET_HOST'] = original_target
      t.pattern = "spec/#{original_target}/*_spec.rb"
      t.rspec_opts = "--format RspecJunitFormatter --out reports/#{target}.xml" if ENV['JENKINS']
    end
  end
end

上記変更後、Jenkinsのジョブで以下のように指定することでreports配下にホストごとの結果が出力され、以下のような形で確認できるようになります。

export JENKINS=True
bundle install
bundle exec rake

あとはJenkinsのジョブ設定のPublish JUnit test result reportのTest reports XMLsで「reports/*.xml」と指定すればOKです

終わりに

とりあえずこの対応を行っていくことで現状のサーバーの状況を確認、監視できるようになります。また、現状はChefAnsibleなどのコードのインフラ化は進んでいないのですが、これをもっと細かく作成できれば安心してコードによるインフラ構成管理に進めるような気がします。

2015年3月17日火曜日

cron(anacron)について確認した時のメモ

このエントリーをはてなブックマークに追加 はてなブックマーク - cron(anacron)について確認した時のメモ

ドキュメントの全くないサーバーで定期処理(cronやanacron)を調べるときに知らないことが多く、苦労したのでメモ

確認シェル作ってみた

cron(anacron含む)はとにかく書き方が色々ありすぎて、どこに何が書いてあるか分からないので、一覧である程度出すものを作りました。

知らないサーバーに入ってcronで何をやっているか把握するときはこれを使うとだいたいの内容が分かるはず!

  • /etc/crontabの内容を出力
  • /var/spool/crontab/[user-name]の内容を出力
  • /etc/cron.d/“ ”/etc/cron.hourly/“ ”/etc/cron.daily/“ ”/etc/cron.weekly/“ ”/etc/cron.monthly/

実行するとこんな感じです。

**************/etc/crontab****************
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name command to be executed

***********************************

**************/var/spool/cron/ec2-user****************
0 * * * * echo "hello" >> /tmp/hello
***********************************

**************/var/spool/cron/root****************
0 * * * * echo "hello" >> /tmp/hello
***********************************

**************/etc/cron.d/****************
0hourly  raid-check  update-motd
***********************************

**************/etc/cron.hourly/****************
0anacron  test
***********************************

**************/etc/cron.daily/****************
logrotate  man-db.cron  tmpwatch
***********************************

**************/etc/cron.weekly/****************
***********************************

**************/etc/cron.monthly/****************
***********************************

結局どうするのが良さそうか

  • 正確な時間でやりたい場合にはcron
  • daily以上の処理でかつ処理の依存関係がないものや実行時間にバラツキをもたせたい場合にはanacron。例えばバッチ実行した処理結果をDBに書くなどの場合にバッチ実行サーバーが多くあるとある時間帯に一斉にDB書き込みが走るのでそれを分散させる場合など。/etc/rc.d/hourlyはanacronではない点は注意
  • 内容にもよるがcronの設定をする場合、/etc/cron.d/配下にファイルを置くやり方の方がファイルを分けることができ、crontab -rを押して内容を消してしまう恐れもないのでベターだと思う
  • ユーザー毎に設定するものはcrontab -eで設定する(事前にバックアップはとる事)
  • cronの標準出力や標準エラー出力は捨てずにログに出力すること

記述の仕方

  • /etc/crontabに記載
  • crontab -eコマンドを使う
  • /etc/cron.d/配下にファイルを配置
  • anacronを使う

/etc/crontabに記載する

  • /etc/crontabファイルに記載した内容を定期実行する

crontab -eコマンドを使う

/etc/cron.d/配下にファイルを配置

  • /etc/cron.d/配下にファイルを置いておくと指定された時間に処理を実行する
  • crontabと違ってサービス(アプリ)ごとにファイルを分けることができるので見やすくできる
  • 後述するanacronのhourly設定のような/etc/cron.hourlyのジョブは/etc/cron.d/0hourlyによって実行されており、anacronの特徴である遅延処理などがない。デフォルトの場合、毎時0分に実行されるようになっている

anacronを使う

  • RHEL 6のジョブスケジューラ「anacron」とは Part1
  • /etc/cron.daily, /etc/cron.weekly, /etc/cron.monthly配下にファイルを置いておけば定期的に処理を実行する
  • cronと違い、正確に実行時間を指定できない(3時から5時のいつかのタイミングで実行などのレンジ指定は可能)
  • 設定内容は/etc/anacrontabに記載

2015年3月1日日曜日

EC2でSeleniumとPhantomJSを使ってブラウザのテストをする環境を作る

このエントリーをはてなブックマークに追加 はてなブックマーク - EC2でSeleniumとPhantomJSを使ってブラウザのテストをする環境を作る

自分用メモ。それぞれの概要はこちらでは説明しません。

環境

  • EC2-AmazonLinux(t2.micro)
  • Ruby(2.1.5)
  • Selenium-webdriver(2.45.0)
  • PhantomJS(2.0)

EC2でSwap領域を確保

PhantomJSはLinuxで動かす時にビルドが必要だったのですが、t2.microのデフォルト状態でやったら、メモリが足りずに途中でエラーになってしまいます。

上記より、Amazon EC2(Linux)のswap領域ベストプラクティスを参考に、Swap領域を確保してからビルドしました。

まず、/etc/rc.localに以下を追加します。 (上記リンクに書いてあるスクリプトは動かなかったので少しだけ変更)

その後、再起動。

$sudo shutdown -r now

freeコマンドを打つと、Swap領域が確保されているのが確認できます。

$ free
             total       used       free     shared    buffers     cached
Mem:       1020188     562280     457908          0      49092     346636
-/+ buffers/cache:     166552     853636
Swap:      2040372       9568    2030804

PhantomJSのビルド

PhantomJS-Buildの通りにやります。 まずは必要なパッケージ群をインストールします。

$sudo yum -y install gcc gcc-c++ make flex bison gperf ruby openssl-devel freetype-devel fontconfig-devel libicu-devel sqlite-devel libpng-devel libjpeg-devel

その後、ソースコードを落としてきてビルドします。

$git clone git://github.com/ariya/phantomjs.git
$cd phantomjs
$git checkout 2.0
$./build.sh

30分ぐらい待つと終わりました。デフォルトで平行ビルドするらしいので、スペックの低いマシンの場合、./build.sh –jobs 1として平行ビルドしないようになるみたいです。

正常に終わっていればphantomjs/bin/phantomjsという感じでバイナリが出来ているのが確認できます。

Selenium-webdriverのインストール

自分の環境だとデフォルトでインストールされたRubyからSelenium-webdriverのインストールを試みたところ、パスの問題?でうまくいかなかったので、rbenvを使って、別途Rubyをインストールしました。

rbenv を使って ruby をインストールする(CentOS編)の通りにやって2.1.5をインストール。このやり方は割とどこにでも書いてあるので省略。

終わったら以下のコマンドでインストール

$gem install selenium-webdriver

テストする

Selenium 使いのための PhantomJS 解説を参考に実施。

まず、PhantomJSを起動させます。

$ phantomjs/bin/phantomjs -w 8001 &
[1] 18769
[ec2-user@ip-172-31-15-31 ~]$ [INFO  - 2015-02-28T14:53:40.058Z] GhostDriver - Main - running on port 8910

-wオプションを使ってポートを指定しているのですが、なぜか8910が開いてしまいましたが、原因を探す時間はありませんでした。。。(80001を使っているわけでもないのに)

気持ち悪いですが、起動はしたので、irbから操作してみます。

$irb

以下irbでのコマンドを順番に打っていきます。詳細はselenium-webdriverのAPIドキュメント参照のこと

まず、selenium/webdriverを使うことを記載

irb(main):001:0> require "selenium/webdriver"
=> true

次に、利用するDriverを指定。(GhostDriverを使おうとするとエラーになってしまったので、この方法で実施)

irb(main):002:0> driver = ::Selenium::WebDriver.for(:remote, url: "http://localhost:8910")

Googleのページを開く

irb(main):003:0>driver.get "http://www.google.co.jp"
=> {}

タイトルを表示

irb(main):004:0> puts driver.title
Google
=> nil

画面キャプチャ取得

irb(main):006:0> driver.save_screenshot('/home/ec2-user/test.png')
=> #<File:/home/ec2-user/test.png (closed)>

実際に取得できたキャプチャがこちら。うーん、便利。

2015年2月20日金曜日

Fluentdを使ってApacheのログをRDS(Postgresql)に入れる

このエントリーをはてなブックマークに追加 はてなブックマーク - Fluentdを使ってApacheのログをRDS(Postgresql)に入れる

Fluentdを使ってApacheのログをRDS(Postgresql)に入れる対応をした時のメモ。

環境

  • AWS EC2 on Red Hat Enterprise Linux 6.6 (HVM)
  • RDS on PostgreSQL 9.3.5

EC2とRDS作成は省略。EC2とRDSは接続可能なようにネットワークとセキュリティグループの設定をしておくこと

Flunetdインストールの準備

Fluentdインストールの前にを参考に準備を行います。

NTP

こちらを参考に。

CentOSにntpサーバを入れて、日本標準時刻に自動的に合わせるためのメモ

まず、UTCからJST形式に変更します。

$cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

NTP自体はすでにインストールされていたので、設定ファイルを日本の設定に変更します。/etc/ntp.confを開いて

server 0.rhel.pool.ntp.org iburst
server 1.rhel.pool.ntp.org iburst
server 2.rhel.pool.ntp.org iburst
server 3.rhel.pool.ntp.org iburst

となっている部分を

server -4 ntp.nict.jp
server -4 ntp1.jst.mfeed.ad.jp
server -4 ntp2.jst.mfeed.ad.jp
server -4 ntp3.jst.mfeed.ad.jp

と変更。

サービスを起動します。

$sudo service ntpd start

確認。

$ntpq -p

自動起動ON。

 $sudo chkconfig ntpd on

ファイルディスクプリンタ

扱えるファイル数を増やすためにファイルディスクプリンタの設定をします。 /etc/security/limits.confを開いて、以下を末尾に追加します。

root soft nofile 65536
root hard nofile 65536
* soft nofile 65536
* hard nofile 65536

再起動。

$sudo shutdown -r now

確認。

$ulimit -n

ネットワーク関連のパラメータ変更

多分ここあたりの話が関係しているっぽい。

ぜんぶTIME_WAITのせいだ!

/etc/sysctl.confを開いて追記します。

net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 10240    65535

反映。

 $sudo sysctl -p

確認。

$sudo sysctl -a |grep -e recycle -e reuse -e port_range

Flunetdインストールのインストール

fluentd-インストールのページからインストール対象のディストリビューションを選んでインストール方法を確認します。 Redhatの場合、インストールスクリプトが用意されているのでそれを利用します。

$curl -L http://toolbelt.treasuredata.com/sh/install-redhat.sh | sh

これでインストールは完了です。

サービスが起動するか確認します。

$sudo /etc/init.d/td-agent start
Starting td-agent:                                         [  OK  ]

Fluent-catコマンドを使って挙動を確認する

fluentdの簡単な使い方、設定方法一覧

上記を参考にやってみました。 その他全体の概要についても詳しく書いてあり、参考になりました。

fluentdの設定を変更します。 /etc/td-agent/td-agent.confを以下のようにします。

<source>
  type forward
</source>
<match debug.**>
  type stdout
</match>

今回はわかりやすいようにtraceモードで起動したいので、一旦デーモンの方は停止させます。

$sudo /etc/init.d/td-agent stop

traceモードをバックグラウンドで起動します。

$td-agent -vv &

fluent-catコマンドを使って確認します。

$ echo '{"json":"message dayo"}' | /usr/lib64/fluent/ruby/bin/fluent-cat debug.test
2015-02-19 22:21:44 +0900 [trace]: plugin/in_forward.rb:189:initialize: accepted fluent socket from '127.0.0.1:23200': object_id=11839160
2015-02-19 22:21:44 +0900 debug.test: {"json":"message dayo"}
2015-02-19 22:21:44 +0900 [trace]: plugin/in_forward.rb:245:on_close: closed fluent socket object_id=11839160

debug.testというファイル名がマッチして表示されている事が確認できます。 試しに他のファイル名でやってみます。

$echo '{"json":"message dayo"}' | /usr/lib64/fluent/ruby/bin/fluent-cat debugaaaa.test
2015-02-19 22:23:56 +0900 [trace]: plugin/in_forward.rb:189:initialize: accepted fluent socket from '127.0.0.1:23201': object_id=70330928356440
2015-02-19 22:23:56 +0900 [warn]: fluent/engine.rb:330:emit: no patterns matched tag="debugaaaa.test"
2015-02-19 22:23:56 +0900 [trace]: plugin/in_forward.rb:245:on_close: closed fluent socket object_id=70330928356440

パターンにマッチしていない事が確認できます。

確認は終わったので、プロセスをkillします。

$ps aux|grep fluentd
$kill KILL hoge
$kill KILL fuga

Apacheのアクセスログをfluentdにかませてファイル出力する

RDSに入れる前にファイル出力が出来るか確認しました。 下記を参考にさせて頂きました。

fluentdを試してみた

まず、Apacheをインストールします。

$sudo yum install httpd -y

起動します。

$sudo service httpd start

また、td-agentがアクセスログの読み取りが出来るように権限を変更します。

$sudo chmod a+rx /var/log/httpd

fluentdの設定をApache用に変更します。 /etc/td-agent/td-agent.confを以下のようにします。

<source>
  type tail
  format apache
  path /var/log/httpd/access_log
  pos_file /var/log/td-agent/pos/apache.test.log.pos
  tag apache.access
</source>

<match apache.access>
  type file
  path /var/log/td-agent/access_log
</match>

posファイル用のディレクトリを作成します。

$sudo mkdir /var/log/td-agent/pos
$sudo chown -R td-agent:td-agent /var/log/td-agent/pos

デーモンを起動します。

$sudo service td-agent start

アクセスログが追加されるようにWebサーバーにアクセスします。

$wget http://localhost

うまく動作していれば/var/log/td-agent/access_log.20150219.b50f712d6139bb1bcという感じでファイルが出来ているかと思います。

ダメな場合、/var/log/td-agent/td-agent.logを確認するとエラーの原因が書いているかと思います。

RDSにApacheのアクセスログを送る

プラグインを追加して、RDSへ情報を送ります。

fluent-plugin-pgjson

まず、プラグインで必要なソフトウェア群をインストールします。

$sudo yum groupinstall "Development Tools" -y
$sudo yum install postgresql postgresql-devel -y

また、psqlコマンドを使ってEC2からアクセスできるか確認します。各パラメーターは自分の環境に変更してください。

$psql -U root -p 5432 -d testdb -h dbinstance.c0cdb3a3yekt.ap-northeast-1.rds.amazonaws.com

アクセス後、fluentd用のテーブルを作成します。

CREATE TABLE fluentd (
    tag Text
    ,time Timestamptz
    ,record Json
);

fluent-plugin-pgjsonを追加します。

$sudo /usr/lib64/fluent/ruby/bin/fluent-gem install fluent-plugin-pgjson

fluentdの設定ファイルを変更します。設定は適宜変更ください。

<source>
  type tail
  format apache
  path /var/log/httpd/access_log
  pos_file /var/log/td-agent/pos/apache.test.log.pos
  tag apache.access
</source>

<match apache.access>
  type pgjson
  host dbinstance.c0cdb3a3yekt.ap-northeast-1.rds.amazonaws.com
  port 5432
  database testdb
  table fluentd
  user root
  password PASSWORD
  time_col time
  tag_col tag
  record_col record
</match>

設定を反映するためにデーモンを再起動します。

 $sudo service td-agent restart

テーブルを確認するとログが登録されているのが確認できます。

testdb=> select * from fluentd;
apache.access | 2015-02-19 14:29:39+00 | {"host":"::1","user":"-","method":"GET
","path":"/","code":"403","size":"3985","referer":"-","agent":"Wget/1.12 (linux-
gnu)"}

自分でフォーマットを決める場合

今回、すでに用意されたapacheのフォーマットを利用しましたが、正規表現を用いて自分で定義することもできます。

例えばスペース区切りでcodeとsizeとkeyとする場合、以下のようにします。

<source> 
  type tail 
  path /var/log/foo/bar.log 
  pos_file /var/log/td-agent/foo-bar.log.pos 
  tag foo.bar 
  format /^(?<code>[^ ]*) (?<size>[^ ]*)$/ 
</source>

詳細や例は公式を見ると良いかと思います。

tailインプットプラグイン

また、以下のサイトで設定した正規表現がどのような挙動となるか確認できます。

Fluentular