Ansible で各言語を完全にマスターするロール作った

これはさすかめ Advent Calendar 2016 の 9 日目の記事です。

www.adventar.org

かなり簡単にですが、各言語を Ansible で完全にマスターする sasukame ロールを作りました。

github.com

まだ Java しか対応してませんが、git clone して ansible-playbook -i hosts site.yml すれば以下の出力が得られます。

PLAY [all] *********************************************************************

TASK [setup] *******************************************************************
ok: [localhost]

TASK [sasukame : include] ******************************************************
included: /home/ewigkeit/sasukame/roles/sasukame/tasks/java.yml for localhost

TASK [sasukame : Create Hello class] *******************************************
changed: [localhost]

TASK [sasukame : Compile Hello class] ******************************************
changed: [localhost]

TASK [sasukame : Run Hello class] **********************************************
changed: [localhost]

TASK [sasukame : Output run result] ********************************************
ok: [localhost] => {
    "msg": [
        "Hello, world."
    ]
}

PLAY RECAP *********************************************************************
localhost                  : ok=6    changed=3    unreachable=0    failed=0   

Ansible のバグを見つけて Pull Request を投げた話

この記事は Ansible Advent Calendar 2016 の 8 日目の記事です。

qiita.com

Ansible を触り始めてから、かれこれ 1 年以上が経過しましたが、現在業務の片手間でやっていたサーバ移行がやっと終わりそうです。もちろん、移行に関する処理を全て Ansible で書いているので、移行作業自体は物理的な手作業を除いてほぼ一瞬で終わる予定です。

さて、本題です。皆さん、copy モジュール使ってますか?使ってますよね。かなり多用しますよね。私も大変お世話になっています。サーバ移行用に書いた処理でも使っていて、例えば RPM ファイルに入っているデフォルト設定をもとに lineinfile とかで設定を書き換えたいというときに、まずは /usr/share/hogehoge 配下に入ってる settings.conf.example とかを所定の /etc 配下にコピーすることを想定していました。当時はこんな感じのタスクを書いていました。

- name: デフォルト設定をコピー
  copy: src=/usr/share/hogehoge/settings.conf.example dest=/etc/hogehoge/settings.conf remote_src=True

さて、タスクが書けたら、まずは check モードで動作確認ですね。ansible-playbook コマンドに --check オプションを付ければいいだけです。簡単ですね。ところがどっこい、check モードで確認したはずなのに、実際にファイルが書き換えられてしまいました。

いやまぁ、草とか言ってる場合ではないんですが、どうやら調べてみたら、remote_src を付けてなければファイルが書き換えられることもなく、正しく check モードで動作していることは確認できました。

せっかくバグも見つけたんだし、と思って、さっそく Pull Request を投げてみました。

github.com

説明足らずでコミッタから再現手順くれよとか言われちゃいましたが、無事マージされて現在は上のようなバグはありません。自分が好きな Ansible に貢献できてよかったな~と思っています。

実は、現在も nmcli モジュールで少し困っていて、設定は変わっていないのに changed 扱いになってしまう問題があります。Ansible のバグ報告見てても、同様の報告が数件あるにも関わらず、現在も解消されていないようです。せっかくなので、自分が直してまた Pull Request を投げようかなと思っているところです。

Ansible でターゲットホストのファイルをターゲットホスト内でコピーする

最近 Ansible ばっかり触ってます。こんにちは。Ansible のちょっとしたテクニックなど、ググったらまぁ大抵出てくることには出てくるんですけど、だいたい英語の記事しか出てこないので、日本語でナレッジを残していくという意味でアウトプットしていきたいと思います。Ansible 好きだし、広く使ってもらいたいので。

で、掲題の件ですよ。Ansible でファイルをコピーと言えば、コントロールホスト上にあるファイルをターゲットホストにコピーする copy モジュール を使いますよね。でも、そうじゃなくて、ターゲットホスト内にあるファイルを、ターゲットホスト内でコピーしたいときどうするのかっていう話です。

これだけじゃあまり伝わらないと思うのですが、例えば RPM ファイルに含まれる /usr/share/hogehoge/sample.conf みたいなサンプルの設定を、そのまま設定ファイルとして /etc/hogehoge/main.conf にコピーしたい、みたいなことってたまにあると思うんです。そういうことです。で、こういうことは copy モジュールだと実現できません。

さて、じゃあ何を使えばいいのかって言うと、synchronize モジュール を使います。synchronize モジュールは rsync の動きをするんですが、他のモジュールと違って、rsync をターゲットホスト上ではなく、コントロールホスト上で動かします。で、この synchronize モジュールをそのまま使うだけだと意図した動作を得られないのですが、ここで delegate_to というオプションを使います。具体的なコードは以下の通り。

- synchronize:
    src: /usr/share/hogehoge/sample.conf
    dest: /etc/hogehoge/main.conf
  delegate_to: "{{ inventory_hostname }}"

delegate_to オプションは このドキュメント に記載されてるんですが、任意のタスクを実行するホストを指定する、つまり処理の移譲先を指定するオプションなんですね。上の例だと、{{ inventory_hostname }} に対して処理を委譲しているので、ターゲットホストで synchronize モジュールを動かすことになります。

これによって、ターゲットホスト上で rsync を動かして、ターゲットホスト内のファイルをコピーするという動きが実現できるようになります。

Java Day Tokyo 2016 に行ってきました

毎年恒例?の Java Day Tokyo 2016 に行ってきました。午前のセッションは会場に行くほどではないかなーと思ったので、午前は会社で仕事しつつ Ustream で午前のセッションの中継を見て、午後から現地で各セッションを見てきました。

[1-A] Java SE 9 Overview

スピーカーは Bernard Traversat 氏。英語セッションです。英語のリスニングは不得意なんですが、今回わざと同時通訳無しで聞いてみようとトライしてみましたが、見事撃沈しました。所々聞き取れる英単語とスライドの内容からなんとか理解を進めてました。

個人的に、"Linking" という開発フェーズが追加されたという内容が気になり、そのフェーズで使用する jlink コマンドが用意されたという話をしていたのですが、スライド上は具体的な話をしていなかったのでどういうものかはわからず。

他、Data Layout の話で、value というキーワードが出てきて気になりました。例えば

final class Point {
    final int x;
    final int y;
}

Point[] pts = ...;

というコードで、配列 pts は Point クラスのインスタンスの配列として、要素はそれぞれひとつのデータとしてメモリ上に存在するという話だったのが、

value class Point {
    final int x;
    final int y;
}

Point[] pts = ...;

と宣言することで、メモリ上は変数 x と y がずらっと並ぶ構造になるという話が面白かったです。

[2-A] Project Jigsaw ではじめるモジュール開発

スピーカーはさくらば (@skrb) さん。なんだかんだで Java Day Tokyo に来ると毎回さくらばさんのセッション見てます。

Project Jigsaw で解決する問題点と、歴史についての話が冒頭で行われました。Project Jigsaw までの道のりってこんなに長かったんですね・・・。

あと、前のセッションでよくわからなかった jlink の具体的な話をされていて、目的のアプリケーションを実行するための最低限のモジュールを含んだ、最小構成の JRE を作るということでした。これはかなりびっくりしました。このまままるっと tar とかでアーカイブしちゃえば、目的のホスト上で JVM の面倒なインストール作業とかもいらなくなりますしね。あとは最小構成なので、メモリ消費も最低限と。

[3-C] Java Concurrency, A(nother) Peek Under the Hood

スピーカーは David Buck 氏。毎回 JVM の深い話をしてくれるので大ファンです。Java Day Tokyo 2014 から氏のセッション毎回見てます。今回も例に漏れず。

並列処理プログラミングの話でしたが、JIT コンパイラが生成したコードをディスアセンブル HSDIS が出てきて個人的に激震が走りました。こんなことできるんですね、今の Java。C1 コンパイラと C2 コンパイラで生成するコードが違って、デッドロックが発生する / しないパターンの話とか興奮してました。

書籍「Java 並行処理プログラミング」の紹介もされていましたが、もちろん私も持っているので、再度読み直そうと思いました。まる。

[4-A] Java 9 で進化する診断ツール

スピーカーは末永氏。OpenJDK コミッタで、HeapStats の開発者でもあります。JDK 9 から解析ツールは jcmd と jhsdb コマンドで十分だよというお話をされていました。というか、JDK 8 の時点で jstack やら jmap は既に非推奨で、jcmd 経由で叩くことすら知りませんでした。

jhsdb を使えばハングした Java プロセスの解析もできるという話や、core 吐いて死んだプロセスの解析に HSDB というツールが使えるという話もありました。今後の仕事に活かせそうです。

まとめ

開発ではなくサポートのお仕事をしているので、どちらかというとトラブルシューティングに活かせそうな話を中心に聞いて回ってたので、こんなラインナップでした。このあともセッションはあるんですが、まだ下の子が小さいので早々に引き上げました。ナイトセッションまで参加するのは、下の子がもう少し大きくなってからですかね。

というわけで、来年もあればまた行きます。

WAR 版 JIRA のインストール方法

前回に引き続き、また JIRA の話になります。WAR 版 JIRA のインストール方法です。「WAR 版 JIRA の環境構築なら前回書いただろ!」と言われるかもしれませんが、、、前回の記事についていたブックマークに「WAR版のデプロイ方法がわからなかったので助かります。」というコメントをいただき、需要があるんだなーと思って記事を読み返していたら、すいません、若干手順を間違えていました。本当に申し訳ありません。ちょうど、Jiemamy サーバ上の JIRA のバージョンアップを行う機会があったので、その際の作業ログがてら、WAR 版 JIRA のインストール方法をご紹介します。

環境

以下で紹介する WAR 版 JIRA のインストールに使用している環境は次の通りです。

インストール手順

1. JIRA 用の $CATALINA_BASE を用意します。前回の記事でも紹介した通り、せっかくなので TomcatFedora で提供されている rpm で管理していきましょう。その方がアップデートの時も楽です。

$ sudo mkdir -m 0775 /usr/share/jira \
    /usr/share/jira/bin \
    /etc/jira \
    /var/log/jira \
    /var/cache/jira \
    /var/cache/jira/temp \
    /var/cache/jira/work \
    /opt/jira \
    /opt/jira/webapps
$ sudo mkdir /usr/share/java/jira
$ sudo ln -s /etc/jira /usr/share/jira/conf
$ sudo ln -s /usr/share/java/jira /usr/share/jira/lib
$ sudo ln -s /var/log/jira /usr/share/jira/logs
$ sudo ln -s /var/cache/jira/temp /usr/share/jira/temp
$ sudo ln -s /opt/jira/webapps /usr/share/jira/webapps
$ sudo ln -s /var/cache/jira/work /usr/share/jira/work
$ sudo chown -R root:tomcat /usr/share/jira \
    /etc/jira \
    /var/log/jira \
    /var/cache/jira \
    /opt/jira
$ sudo ln -s /usr/share/tomcat6/bin/tomcat-juli.jar /usr/share/jira/bin/tomcat-juli.jar
$ sudo cp -p /etc/tomcat6/server.xml /etc/jira/
$ sudo ln -s /etc/tomcat6/catalina.properties /etc/jira/catalina.properties
$ sudo cp -p /etc/sysconfig/tomcat6 /etc/sysconfig/jira
$ sudo ln -s /etc/init.d/tomcat6 /etc/init.d/jira
$ sudo chkconfig --add jira

2. WAR 版 JIRA をダウンロードして、/opt/jira/ ディレクトリ配下に展開します。

3. /opt/jira/atlassian-jira-4.4.4-war/edit-webapp/WEB-INF/classes/jira-application.properties を編集し、jira.home を適切に設定します。ここは、JIRA のデータをどこに置くかを指定しますので、用意するディレクトリのアクセス権は tomcat ユーザで書き込みできる必要があります。

4. 必要に応じて、war に含めなければならないプラグイン等を /opt/jira/atlassian-jira-4.4.4-war/edit-webapp/ ディレクトリ配下に配置したり設定を行います。

5. JIRA をビルドします。build.sh を叩けばいいだけです。

$ cd /opt/jira/atlassian-jira-4.4.4-war/
$ sudo JAVA_HOME=/usr/java/default sh build.sh

6. JIRA が接続するデータベースの JDBC ドライバを Tomcat の lib ディレクトリに入れます。ここでは、データベースに PostgreSQL を使っており、rpm 版の PostgreSQL JDBC ドライバを入れていますので、その jar ファイルに向けてシンボリックリンクを張ります。

$ sudo ln -s /usr/share/java/postgresql-jdbc.jar /usr/share/java/jira/postgresql-jdbc.jar

7. JIRA の稼働に必要な Tomcat 用のライブラリを、Tomcat の lib ディレクトリに入れます。必要なライブラリは、JIRA のドキュメントにリンクが記載されています。参照:Installing JIRA on Tomcat 6.0 - JIRA 4.4 - Atlassian Documentation

$ cd /usr/share/java/jira
$ sudo unzip jira-jars-tomcat-distribution-4.4-tomcat-6x.zip

8. JIRA のデプロイ用コンテキスト xml を書きます。JIRA をビルドしたら、/opt/jira/atlassian-jira-4.4.4-war/dist-tomcat/tomcat-6/ ディレクトリ配下に jira.xml というデフォルトのデプロイ用コンテキスト xml がありますので、これを参考に設定します。

$ sudo cp /opt/jira/atlassian-jira-4.4.4-war/dist-tomcat/tomcat-6/jira.xml /etc/jira/Catalina/localhost/
$ sudo vim /etc/jira/Catalina/localhost/jira.xml

9. Tomcat の server.xml を適切に変更します。デフォルトのままでもいいですが、コネクタのポート番号を変えたいときとか、結構設定変更する部分はあるかと思います。

$ sudo vim /etc/jira/server.xml

10. Tomcat環境変数を適切に変更します。

$ sudo vim /etc/sysconfig/jira

CATALINA_BASE と CATALINA_TMPDIR と CATALINA_PID の設定は忘れずに行いましょう。あと、JAVA_OPTS を適切に設定する必要があります。推奨値は JIRA のドキュメントにも記載されています。

CATALINA_BASE="/usr/share/jira"
CATALINA_TMPDIR="/var/cache/jira/temp"
CATALINA_PID="/var/run/jira.pid"
JAVA_OPTS="-Xms128m -Xmx512m -XX:MaxPermSize=256m -Dorg.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER=true -Dmail.mime.decodeparameters=true"

11. 起動します。これでインストール作業が終わりです!

$ sudo /sbin/service jira start

JIRA の運用例

1年8ヶ月ぶりにブログを書くという、なんとも申し訳ない気分になりながら、今日は JIRA についてエントリを書きたいと思います。というか、ただ @JIRA Advent Calendar 2011 で管理 Tips なのを書いてくれるはず、という無茶ぶりをされたからですがw


JIRA は Jiemamy で使われており、その管理を担当しているのもあって、数年前からお世話になっている BTS ではありますが、これがなんとも管理がややこしい!細かいことができる分、管理もそれなりにややこしいです。今回は Jiemamy JIRA で行っている管理手法について紹介したいと思います。前提として、Jiemamy JIRA は WAR 版を使っています。スタンドアロン版だと、ついてきている Tomcat のバージョンがちょっと古かったりするので、脆弱性が残っている場合があるためです。そのため、Tomcat は最新のバージョンをなるべく追えるように、JIRA は WAR 版を使っています。

環境の用意

何はともあれ、まずは環境を用意しないと何も始まりません。Jiemamy のサーバでは、OS の Tomcat パッケージを使って JIRA を動かしています。JIRA 以外にも、Confluence や Bamboo 等を動かしているので、最初は単一の Tomcat 上ですべてのアプリケーションを動かす、ということをやっていました。もちろん、こういうことをやるとサポート対象外なのでやめましょうw


なので、Tomcatインスタンス 1つあたり、1つの Atlassian 製品を動作させるのが鉄則になってきます。普通に考えると、OS から提供される Tomcat パッケージを使おうにも、1つの Tomcat インスタンスしか上げられないので、結局こういうところから Tomcat をダウンロードして、1つずつ環境を構築して、Tomcat のセキュリティアップデートが出てくると、すべての Tomcat を一斉にアップデートして・・・ということをやると思います。


ですが、Fedora とかで提供されている Tomcat パッケージはマルチインスタンス化が可能です。簡単には会社のブログで書いていて、ここではインスタンス 1つごとのディレクトリを /usr/share/instance/ 配下に全部まとめたんですが、Jiemamy のサーバでは次のようにディレクトリを細かく分けています。これは、元々の Tomcat パッケージのデフォルトのディレクトリ構成 (/usr/share/tomcat6/ ディレクトリ) を踏襲しています。

ディレクトリパス 実体のパス
/usr/share/instance/bin /usr/share/instance/bin
/usr/share/instance/conf /etc/instance
/usr/share/instance/lib /usr/share/java/instance
/usr/share/instance/logs /var/log/instance
/usr/share/instance/temp /var/cache/instance/temp
/usr/share/instance/webapps /opt/instance/webapps
/usr/share/instance/work /var/cache/instance/work

それぞれのディレクトリの所有者やアクセス権は、基本的に Tomcat パッケージのデフォルトのディレクトリ構成を真似ます。なんで webapps ディレクトリが /var/lib/instance 配下じゃなくて /opt/instance 配下になっているかですが、/var/lib/instance 配下は jira.home にしているからですw

JIRA のバージョンアップ作業

JIRA を運用していると、JIRA もバージョンアップが重ねられますし、時にセキュリティ上問題があるので早急にアップデートを行う必要が出てくる場面もあるかと思います。でも、結構 JIRA のアップデートって面倒くさいですよね。war ファイルをぽん、と置くだけじゃないですし、毎回 build.sh を叩く必要があります。そして問題が発生すれば以前のバージョンに切り戻したり、と。何かと手間がかかります。だがそれがいい


Jiemamy JIRA では、だいたい次のような手順でバージョンアップを行っています。

  1. 最新版の JIRA の WAR 版をダウンロードし、/opt/instance/ ディレクトリ配下に展開する。
  2. /opt/instance/atlassian-jira-x.x.x-war/edit-webapp/ ディレクトリ配下を適切に編集する。
  3. /opt/instance/atlassian-jira-x.x.x-war/build.sh を叩いて war ファイルを生成する。
  4. 作成した war ファイルを /opt/instance/webapps/ ディレクトリ配下に置く。

これでバージョンアップが完了です。edit-webapp に置くファイルとかをバージョン管理とかに上げておくと、楽かもしれないですね。ちなみに、Tomcat をバージョンアップすることになっても、CATALINA_HOME と CATALINA_BASE は分けてあるので、基本的に /opt/instance/webapps/ ディレクトリ配下は何も手を加える必要がありません。yum update tomcat6 を実行するだけで、すべてのインスタンスTomcat のバージョンアップが完了するからです。便利ですね!

上記の手順は少し間違えています。正しい JIRA のインストール手順についてはWAR 版 JIRA のインストール方法 - von Ewigkeitに書きました。

バックアップ関連

さて、ほとんど書くこともなくなってきたので、最後にバックアップの運用例を紹介します。


Jiemamy サーバでは、cron を使って日次でバックアップを取っています。バックアップには独自で作ったスクリプトを使っていますが、JIRA のバックアップに当たっては、だいたい次のようなことをしています。

  1. JIRA のデータベースをバックアップ。Jiemamy のサーバは PostgreSQL を使っているので、pg_dump を使っています。
  2. ${jira.home}/data/ ディレクトリを丸ごとバックアップ。

だいたいこれだけ。まぁ、これで十分かなって。というか、どういうデータをバックアップすべきかは、ちゃんとドキュメントに載っています。JIRA だけではなく、Confluence とかも載ってた気がします。ドキュメント重要。


いかがでしたでしょうか。JIRA 管理の Tips を書く、という無茶ぶりを受けつつ、結局書いたのは運用例なので、なんとも拍子抜けさせてしまっているというか、なんというかw
皆様の JIRA 運用のちょっとした参考になれば幸いです。


さて、明日の JIRA Advent Calendar は、エロ部長こと @ がお届けします!

FreeBSD で OpenGrok をインストールする。

ソースコード調査とかで使える OpenGrok を FreeBSD にインストールする方法です。Web ベースでシンボルの調査とかができるので、見た目としてはいいんじゃないかと。それでも自分は cscope 最強だと思ってますがw


OpenGrok は ports にあるので、さっくり ports から入れましょう。Apache Tomcat に依存しているので、それも一緒にインストールされます。

portmaster devel/opengrok

インストールが終わったら、OpenGrok の設定。デフォルトでは /etc/opengrok/configuration.xml に設定ファイルを用意することとなるので (なんで /usr/local/etc 配下じゃないんだろう・・・) 下記のコマンドで設定ファイルを生成します。

opengrok -v -s <ソースを配置するディレクトリ> -d <データを配置するディレクトリ> -W /etc/opengrok/configuration.xml

自分がやった例:
opengrok -v -s /home/opengrok/source -d /home/opengrok/data -W /etc/opengrok/configuration.xml

あとは Tomcat を起動して http://localhost:8080/source/ とブラウザに入力したら OpenGrok が見えます。


その後のソースファイルの配置等は、ソースを配置するディレクトリにソースをばかすかつっこんで、最後に下記コマンドをぶち込めばインデックスファイルをデータを配置するディレクトリに生成してくれます。

opengrok -R /etc/opengrok/configuration.xml

以上!