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

2015年2月7日土曜日

SES(Simple Email Service)の監視について確認した時のメモ

このエントリーをはてなブックマークに追加 はてなブックマーク - SES(Simple Email Service)の監視について確認した時のメモ

SESを使うときの監視について確認したのでメモ。

概要

SESでは以下については監視などしておくと良さそうです。

  1. 24時間以内の送信メール数と上限値
  2. Bounce数
  3. Complaint数

1は単純にそれを超えると送信ができなくなるため(上限値は徐々にあがるのを待つか別途申請が必要) 2,3もその割合が多すぎるとAWS側でメールサービスを停止することがあるからです。

具体的にどう監視するかという所で大きく分けて2つあるようです。

  1. AWS CLI(SDK)を使って定期的に取得する
  2. SESの配信通知を使う

1.AWS CLI(SDK)を使って定期的に取得する

AWS CLI(SDK)で監視すべき内容が取得できます(恐らくSDKでも取れると思います)

AWS CLI ses

具体的なオプションとしては「get-send-quota」および「get-send-statistics」が該当します。

get-send-quotaでは24時間以内のメール送信数の上限と現在の送信数が取得でき、get-send-statisticsでは2週間以内の15分ごとの送信状況(何通送って何通がBounceしたかComplaintになったか)などが取得できます。

なので例えば24時間以内のメール送信数と上限の割合を取得する場合、具体的に以下のコマンドでパーセンテージが取得できます。(動作確認済み)

上記を利用してAWSのCloudWatchと連携すると「上限数のhoge%を超えたらアラートメールを送る」などという事が可能です。

CloudWatchとの連携は以下サイトが参考になると思います。(ここで紹介されているPythonツールは個人でメンテナンスしているようでAmazonとしてno longer supportらしいのでSDKかCLIを使ったほうが良さそうです)

Amazon Simple Email Service (SES)の送信件数をCloudWatchのカスタムメトリクスで監視する

2.SESの配信通知を使う

SESで設定をしておけば、

  • Bounce
  • Complaint
  • Delive(正常に宛先に届いたか)

などの時にAWS-SNSを通じて通知が受け取れるようです。

【AWS発表】SESの配信通知

SNSではメール通知やHTTPによって通知などできるので監視やBounceやComplaint時の送信先宛先リストからの削除などが出来ると思います。

2015年1月31日土曜日

logrotateでnginxのログを1時間ごとにローテートをする

このエントリーをはてなブックマークに追加 はてなブックマーク - logrotateでnginxのログを1時間ごとにローテートをする

logrotateについて全然知らなかったので勉強した時のメモ。

やりたいこととしては

  • 特定のファイルだけ時間でローテートしたい
  • ローテート対象のファイルはgzipで圧縮したい
  • ローテート対象ファイルのファイル名はYYYYmmddHHMMとしたい

という感じ。

今回はnignxのログを時間ごとにローテートするようにしてみました。

使ったのが初めてだったので基本的な概要は以下で勉強しました

logrotateによるログのローテーション

さっき気づいたこと

logrotateの3.8.5からhourly対応したらしい。

logrotate-Changelog

3.8.5未満の場合の話

以下がとても参考になりました。

apacheのlogrotateを1時間毎に吐き出そうとした記録

logrotateを1時間ごとに実行させる

1時間に1回logrotateが動くように/etc/cron.dailyの中のlogrotatedというファイルを/etc/cron.hourlyにコピーします。

$sudo cp /etc/cron.daily/logrotate /etc/cron.hourly/

これによってlogrotateコマンド自体が1時間に1回実行されますが、ローテートの周期としてweeklyなどの設定をしていれば何回実行されても1週間経過しないとローテートされないはずなので時間ごとにローテートしたくなくファイル群は特に影響は受けないかと思います。(1週間経過しているかの判定はデフォルトでは/var/lib/logrotate.statusの日時を参照します)

/etc/logrotate.d/nginxを編集する

/etc/logrotate.d/配下にあるアプリケーションごとの設定でsizenodateexを指定します。また、compressをコメントアウトします。(理由は後述)

$sudo vi /etc/logrotate.d/nginx

/var/log/nginx/*log {
    create 0644 nginx nginx
    daily
    rotate 10
    missingok
    notifempty
    #compress
    size 1
    nodateext
    sharedscripts
    postrotate
        /etc/init.d/nginx reopen_logs
    endscript
}

size指定することによって指定されたsizeを越えたらローテートします。(manでgrow bigger thanなので以上ではなく超えるだと思います、多分)なお、minsizeというオプションもありこちらを指定するとローテーション周期(daily,weeklyなど)とのAND条件となるので注意。logrotate の size と minsize の違い

また、nodateextを追記します。これによってローテートするときに日付をファイル名に付けるのではなく、hoge.1というようなファイル名が連番になるようにします。/etc/logrotate.confでdateextを指定していなければこちらで明示的に指定する必要はありません。

この状態で正常に動作するか確認します。

$sudo /usr/sbin/logrotate /etc/logrotate.conf
Reopening nginx logs:                                      [  OK  ]

$wget http://localhost/

$sudo /usr/sbin/logrotate /etc/logrotate.conf
Reopening nginx logs:                                      [  OK  ]

$sudo ls -la /var/log/nginx/
total 16
drwx------ 2 nginx nginx 4096 Jan 31 13:20 .
drwxr-xr-x 6 root  root  4096 Jan 25 03:13 ..
-rw-r--r-- 1 nginx nginx    0 Jan 31 13:17 access.log
-rw-r--r-- 1 nginx nginx  101 Jan 31 13:17 access.log.1
-rw-r--r-- 1 nginx nginx  101 Jan 31 13:16 access.log.2
-rw-r--r-- 1 nginx nginx    0 Jan 13 03:14 error.log

ファイル形式を変更して圧縮する

dateformatというオプションはあるのですが、Only %Y %m %dとなっているので時間が恐らく使えません。そのため、 ログローテーション後にスクリプトを実行できるpostrotate〜endscriptを使ってリネームを行います。また、その中で圧縮も行います。(compressオプションはpostrotate-endscriptの後にローテートした元々のファイルを圧縮しようとするようでリネームを独自でやると正しく動作しないようだった)

/var/log/nginx/*log {
    create 0644 nginx nginx
    daily
    rotate 10
    missingok
    notifempty
    #compress
    size 1
    nodateext
    sharedscripts
    postrotate
        EXT=`date +%Y%m%d%H%M`
        for f in $1
        do
          ls $f.1 >/dev/null 2>&1
          if [ $? -eq 0 ] ; then
            mv $f.1 $f.$EXT
            gzip $f.$EXT
          fi
        done
        /etc/init.d/nginx reopen_logs
    endscript
}

postrotateの中では/bin/shが実行されるようでシェルスクリプトが記述できます。 詳細な仕様が書いてある所を発見できなかったのですが、動作確認したところ以下のようでした。

  • 指定されているログファイル群の一つでもローテートの条件に合致する場合にスクリプトは実行される(access.logが0バイトを超えた場合でerror.logのファイルサイズが0バイトでもスクリプトが実行される)

  • 第一引数に対象のファイル名が配列で渡される。ただし、ローテーション対象外のものも含まれる(access.logが0バイトを超えた場合でerror.logのファイルサイズが0バイトでもaccess.logとerror.logを含む配列が渡される)

あんまり綺麗に書けている自信がありませんが、動作的には大丈夫そうです。

AnsibleとJenkinsを連携させる時にやったこと

このエントリーをはてなブックマークに追加 はてなブックマーク - AnsibleとJenkinsを連携させる時にやったこと

小ネタです。

結果の出力をJenkinsのコンソール上でタスクごとに表示するようにする

ansible-playbookなどをTerminalから実行するとplaybookの途中の結果も出力されます。(例えばplaybookの中に複数のタスクがある場合に各タスクの進捗状況がわかります)

しかし、Jenkinsのシェルの実行でansible-playbookを実行するとplaybook内の全てのタスクが終了するまで結果がコンソールに表示されませんでした。

恐らくJenkinsのコンソールでは標準出力を表示しており、ansible-playbookを試しにリダイレクトさせてみた所、確かにタスクが終了するまで結果が表示されませんでした。

上記についてはexport PYTHONUNBUFFERED=1を実行前に設定すればPythonのstdin, stdout, stderr のバッファを強制的に無効にすることができるようでplaybook内の途中のタスク結果も見れるようになりました。

when does ansible-playbook write to stdout?

Python コマンドラインと環境

Jenkinsのコンソールでもansible-playbookの結果を色が付いた形で確認する

Terminalなどでansible-playbookを実行すると結果の出力が色付きで見れます。しかし、Jenkinsで普通に実行すると単色で表示されてしまいます。

色付きの結果をJenkinsでも表示するためにはまずAnsiColor PluginというJenkinsのプラグインを導入します。インストール後、ジョブの設定にColor ANSI Console Outputというチェックボックスが追加されるので設定しておきます。

ジョブでは実行時にexport ANSIBLE_FORCE_COLOR=trueという環境変数を設定してからansible-playbookを実行します。

export ANSIBLE_FORCE_COLOR=true
ansible-playbook -i hosts site.yml

これによってJenkins上でも色付きの結果が出力されて、見やすくなります。

Get colorful ansible output in Jenkins

2015年1月24日土曜日

踏み台サーバーを経由したホストでのServerspecを実行した時のメモ(+認証自動化)

このエントリーをはてなブックマークに追加 はてなブックマーク - 踏み台サーバーを経由したホストでのServerspecを実行した時のメモ(+認証自動化)

色々な制約があり、以下のように踏み台サーバーを経由してServerspecによるテストを行う必要がありました。

Serverspecを実行するホスト

↓

踏み台サーバー(公開鍵認認証。パスフレーズ入力必要あり。このサーバーでのファイル書き出し不可)

↓

テスト対象サーバー(パスワード認証。sudoを行う際にもパスワード入力が必要)

上記についてどのようにしてテストを出来るようにしたのかのメモ。また、都度「パスフレーズ」、「ログインパスワード」、「sudoパスワード」入力などが面倒なのでその辺りも自動化しました。

目次

  1. 公開鍵認証でのパスフレーズ入力を省略できるようにする
  2. 一度のSSHログインでテスト対象サーバーへSSHログインする
  3. sudo実行時のパスワードを都度入力しないようにする
  4. テスト対象サーバーログイン時のパスワード認証を自動化する

1.公開鍵認証でのパスフレーズ入力を省略できるようにする

ssh-agent でパスフレーズの入力を省く

上記に記載されているように ssh-agent を使って都度パスフレーズを入力しないようにします。

$ssh-agent bash
$ssh-add  ~/.ssh/id_rsa

addの際にパスフレーズを聞かれるので入力します。 上記までが完了すれば以降このシェルで踏み台サーバーへのSSHログイン時にはパスフレーズを聞かれることなくログインすることがでます。

$ssh hoge@FumidaiServer

ただし、あくまでもssh-agentが起動したシェルであればという制約があるため、ssh-agentを起動したシェルからexitした場合、再度ssh-agentの起動とパスフレーズの入力が必要です。

上記も自動化したいという場合、~/.bash_profileなどにログイン時にssh-agentの起動とexpectコマンドを利用してパスフレーズの入力を自動でさせることも可能です。

ssh-agent と expect で ssh のパスフレーズ入力を自動化

詳細は上記に記載されていましたが、直接パスワードを書かなければいけないのでセキュリティなど気になる人はやらない方が良いかもしれません。

2.一度のSSHログインでテスト対象サーバーへSSHログインする

ProxyCommand を使います。ProxyCommandを使うことによって踏み台サーバーへのログイン後、さらにテスト対象サーバーへSSH接続を自動で行います。

ProxyCommandによるsshの多段接続について

上記に記載されているようにServerspecを実行するホストの ~/.ssh/config を変更します。

Host FumidaiServer
  HostName FumidaiServer
  User hoge
  Port 22
  IdentityFile ~/.ssh/id_rsa

Host TestServer
  HostName TestServer
  User fuga
  Port 22
  ProxyCommand ssh -W %h:%p server

上記設定後、 

$ssh TestServer

とするとFumidaServerにSSHログイン後、自動でTestServerへSSH接続してくれます。

3.sudo実行時のパスワードを都度入力しないようにする

上記まで行えれば踏み台サーバーを気にせず、テスト対象サーバーへServerspecのテストを行うことができるかと思ったのですが、なぜか私の環境では正しいsudoのパスワードを入力してもパスワードが間違った扱いとなり、テストが実行できませんでした。

そこでsudo実行時のパスワードを省略するためには環境変数 SUDO_PASSWORD を設定しました。

$export SUDO_PASSWORD=password

詳細はserverspec-initによって自動生成される spec/spec_helper.rb を確認すれば分かるかと思います。

上記により、毎回テスト対象のサーバーへのログインパスワードの入力は必要ですが、Serverspecによるテスト自体はできるようになりました。

4.テスト対象サーバーログイン時のパスワード認証を自動化する

私の環境の場合、テスト対象のサーバーへのログイン時にパスワード認証が必要となります。 それについても自動化したいと思い、expectコマンドを使った簡単なスクリプトを作りました。

予め環境変数 LOGIN_PASSWORD を指定して、上記シェルスクリプトを実行すればテスト対象のサーバーへのパスワード認証を自動化できます。多分spec_helper.rbを上記のようなことを実行するコードに変える方がよりスマートだと思うのですが、Ruby力がまだなかったのでシェルスクリプトで対応できるようにしました。これでテスト実行時に手動入力する必要がなくなりました。

追記(2015/01/25)

Serverspec本にめっちゃ書いてあった。。。。こっちの方が自然だ。。。

まとめ

最初、この制約の中でうまくできるかなーという感じでしたが、Serverspec自体が テスト対象サーバーにSSHログインできれば良い というシンプルな構成だったので、いろんな部分を短時間で自動化させることができました。既に書いていたテストコードが無駄にならなくてよかった。。。

2015年1月13日火曜日

Proxy環境でGradleを使ってAndoridのビルドをした時にはまった時の解決方法メモ(peer not authenticated,MultipleArtifactsNotFoundExceptio)

このエントリーをはてなブックマークに追加 はてなブックマーク - Proxy環境でGradleを使ってAndoridのビルドをした時にはまった時の解決方法メモ(peer not authenticated,MultipleArtifactsNotFoundExceptio)

Proxy環境でGradleを使ってAndoridのビルドをした時にはまったのでメモ。

ビルド対象

robolectric/deckard-gradle

上記テンプレートを使ってProxy環境のサーバーでテストを含むビルドができるようにしました。(2015年1月現在)環境はLinuxOSでした。

とりあえず

これは結構どこにでも書いてあったGradledでのProxy設定する方法。~/.gradle/gradle.propertiesに設定を追記します。

systemProp.http.proxyHost=myproxy.co.jp
systemProp.http.proxyPort=8080
systemProp.http.proxyUser=****
systemProp.http.proxyPassword=****
systemProp.https.proxyHost=myproxy.co.jp
systemProp.https.proxyPort=8080
systemProp.https.proxyUser=****
systemProp.https.proxyPassword=****

これをやったのに2つのポイントでNGになった。

はまりポイント1(peer not authenticated)

実行すると以下のようなエラーが出ました。

peer not authenticated

調べると以下のようなサイトが。

Gradle Could not HEAD https://..pom > peer not authenticated

こちらを見ると書いてあるようにMaven2repositoryがHTTPSをサポートしなくなったのに

repositories {
    mavenCentral()
}

と書くとHTTPSでアクセスするようでエラーになるみたいです。 なので、build.gradleの依存解決のリポジトリを全てjcenterに変えました。

repositories {
    jcenter()
}

これで上記エラーは出なくなりました。

はまりポイント2(MultipleArtifactsNotFoundException: Missing)

やったーうまくいったと思ったら今度はMultipleArtifactsNotFoundExceptionが出て、testDebugでエラーに。

色々調べたら解決方法が書いてありました。

Unable to resolve artifact: Missing, using Eclipse and Robolectric

Mavenのプラグインでmavenの設定ファイルを探してそれを利用しているらしく、これにProxy設定を書かないとダメのようです。mavneの設定ファイルは~/.m2/settings.xmlとして記載します。

<settings>
  .
  .
  <proxies>
   <proxy>
      <active>true</active>
      <protocol>http</protocol>
      <host>proxy.somewhere.com</host>
      <port>8080</port>
      <username>proxyuser</username>
      <password>somepassword</password>
      <nonProxyHosts>www.google.com|*.somewhere.com</nonProxyHosts>
    </proxy>
  </proxies>
  .
  .
</settings>

設定したらうまくできました。。。。。