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>

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