page_adsence

2017年9月10日日曜日

Jenkins公式のDockerイメージを使って、プラグインインストール済みのJenkinsイメージを作る

Dockerを使ってJenkinsサーバを立てようと思ったのですが、プラグインをインストールした状態のイメージを自分で作りたくて色々調べたので、その結果を書いていこうと思います。

まず最初に見つけたのが下記のリポジトリのものです。

blacklabelops/jenkins

docker-composeで立ち上げる際に、env_fileを食わせてやることで、プラグインインストール済みのJenkinsサーバが立ち上がるらしいのですが、インストールしたいプラグインを入れても、なぜか上手くいかなかったので別のを探すことに。

引き続き調べていたら、Jenkins公式の配っているイメージでもプラグインをインストール出来ることがわかったので、それを試してみました。

jenkins

FROM jenkins
COPY plugins.txt /usr/share/jenkins/ref/
COPY custom.groovy /usr/share/jenkins/ref/init.groovy.d/custom.groovy
RUN /usr/local/bin/plugins.sh /usr/share/jenkins/ref/plugins.txt

こんな感じで書くとプラグインがインストール出来ると書いてあるのですが、依存関係を自動で解決してくれないので、依存しているプラグインを全部自力で順番通りに書かないといけないということで、ちょっとだけやってみたのですが、現実的ではないということでこれも諦めました。

Jenkinsのコンテナ作って中に入って色々見ていたら、気になるシェルスクリプトを見つけたので、試しに使ってみることにしました。

FROM jenkins
RUN /usr/local/bin/install-plugins.sh git github

こんな感じで、インストールしたいプラグインIDを空白区切りで列挙します。
記載が終わったらビルドして新しいJenkinsのイメージを作ります。

docker build . -t jenkins

続いて、docker-compose.ymlに下記のように指定します。

jenkins:
  image: jenkins
  container_name: jenkins
  ports:
   - "8080:8080"
   - 50000
  volumes_from:
    - volumes
  environment:
    - JAVA_OPTS="-Djenkins.install.runSetupWizard=false"

volumes:
  image: busybox
  container_name: jenkins_data
  volumes:
    - /var/jenkins_home

この中でJenkinsの初回起動時のウィザードを出さないようにしています。
で、

docker-compose up -d

で起動します。

http://localhost:8080/

にアクセスして、Jenkinsのプラグイン管理の画面に行くと、ちゃんとインストールされてました!
DockerHubの方のページには書いてなかったので気づけなかったのですが、githubの方にはちゃんと書いてありました・・・。

jenkinsci/docker

なんにせよこれでプラグインの依存関係を気にせず入れれるようになりました。

2017年8月4日金曜日

IntelliJとVisualVMでScalaのベンチマークを取る

Scalaで作っているAPIサーバがあるのですが、自分が作った部分がリリースされた直後、APIのレスポンスが悪くなりアラート連発という事態が発生。
今回のリリースで対象のAPIサーバをいじったのは自分だけ。
しかし、ソースはレビュー済みで、切り戻し後にもう一度確認してみたのですが、誰が見ても特に重そうという処理はしてなさそうという結論に至りました。

そこで、修正前後のベンチマークを取って比べてみようということに。
最初は「sbt-jmh」を使ってベンチマークを取ろうとしたのですが、うまく行かず・・・。
Javaでプロファイルするのに使っていたVisualVMというものがあって、もしかしたらそれでScalaのプロファイルも出来るかもというアドバイスを貰ったので、早速調べてみると比較的最近の記事が出てきました。

Scalaで書いたProcessing のプログラムを VisualVM でプロファイルする

上の記事を見てScalaのプロファイル取れることがわかったので、早速導入してみた。

VisualVMの入手とインストール

  1. VisualVM にアクセス
  2. Download ボタンをクリック
  3. Mac OS X Application Bundleをクリックしダウンロードしてくる
  4. 落としてきたdmgファイルダブルクリックしてインストール

IntelliJのプラグインの入手と設定

  1. Preferences -> Plugins -> Browse repositories -> 検索窓に「VisualVM Launcher」と入力し、「Install」ボタンをクリック
  2. プラグインのインストールが完了すると、「Restart IntelliJ IDEA」ボタンに切り替わるので、IntelliJを再起動する。
  3. Preferences -> Other Settings -> VisualVM Launcher のメニューをクリックし、
    VisualVM executable: に 「/Applications/VisualVM.app/Contents/MacOS/visualvm」 と入力
  4. それ以外の部分はそのままにして、OKをクリック
  5. 通常の「Run」や「Debug」と同じ様に、「Run With VisualVM」か「Debug With VisualVM」を押すと、アプリが起動する。
    ■ Before

    ■ After
  6. メニューの方も変わっている
    ■Before

    ■After
  7. 後は勝手にVisualVMが起動するので、必要な部分を見ればOK

以上で設定は完了です。

2016年7月4日月曜日

IntelliJを使ってGo言語の開発環境を整えてみる for Windows

会社のPCは現在Windowsなので、Windows上でGo言語の開発環境を作ってみた。
OS:Windows7
IntelliJ:15.0.6
今回行う事は大きく2つです。
1. Windows上へのGoのインストール
2. IntelliJ側のプラグインのインストールと設定
では早速Goのインストールから始めようと思います。

Go SDKのインストール

  1. 下記のサイトからGoのインストーラー「go1.6.2.windows-amd64.msi」をダウンロードしてきます。
    https://golang.org/dl/
  2. インストーラーを起動し、インストールを開始します。
    インストーラーはデフォルトだとインストール先がC:\Goになっているので、
    別のディレクトリに入れたい場合は、任意のディレクトリを指定して下さい。
  3. インストールが完了したら、コマンドプロンプトを起動し、goのバージョンを確認します。
    > go version
    バージョンの確認が出来たらプロンプトは閉じても問題ありません。
    ※この時点でPathやGOROOT等の環境変数は自動で設定されています。
これでGoのインストール作業は完了です。
では引き続きIntelliJ側の設定を行っていきます。

IntelliJのPluginインストール

  1. IntelliJを起動します。
  2. 「Welcome to IntelliJ IDEA」の画面右下の「configure」→「Plugins」をクリック
  3. 画面下側の「Browse repositories…」をクリック。
  4. 画面上部の検索窓に「GO」と入力し、「GO」と書いてあるものをインストールします。
  5. プラグインのインストールが完了すると、再起動を求められるので、IntelliJを再起動します。

  6. 再起動したら、「Welcome to IntelliJ IDEA」画面で「Create New Project」をクリック。
  7. 画面左側のリストにGoがあるので、GoをクリックしてNextをクリック
  8. Procjet SDKの画面で「Configure...」をクリック
  9. Goをインストールしたディレクトリを指定し、OKを押下、Project SDKにGoと出てれば、Nextボタンを押下する。
    (Go言語をインストール時に何も変更指定なければ、C:\Goにインストールされているので、そのままOKを押せば問題ない)

  10. Procjet NameとProject locationを任意の場所にしてFinishをクリック
  11. 開いたプロジェクトでGo Fileを追加して、Hello World的なのを書いてみる。
    package main
    
    import "fmt"
    
    func main(){
     fmt.Printf("Hello World!")
    }
  12. 書いたら実行(メニューバーのRun -> Run ‘go run XXXXX.go’)
  13. コンソールにHello World!と出れば成功!
古い情報とかだとjarファイル落としてこないといけないとか書かれていますが、
基本的にはGoをインストールとIntelliJの画面内の操作で完結するようです。

おまけ

最初はIntelliJのバージョンが15.0.4のものを使っていたのですが、
なぜかGo SDKのディレクトリを指定しても、下記の様なエラーが出てしまって使えませんでした。
「The Selected directory is not a valid home for Go SDK」
IntelliJのバージョンと、Pluginのバージョンが合っていないのかとも思ったのですが、
PluginのREADMEを確認する限りでは問題ありませんでした。
go-lang-idea-plugin
取り敢えずIntelliJの最新バージョンが出てたのでアップデートしてみたら使えるようにはなったのですが、
これで根本原因が解決出来たのかは不明です・・・。

2016年6月29日水曜日

Nginxのstable版とmainline版に関して

開発環境でNginxの1.9を利用していたのですが、インフラ屋さんに1.10と1.11が出てますけど、どっちにしますかと言われたので調べてみた。
yumでインストールしたNginxのバージョンが1.9だったので、何も考えずに1.9を使っていたのですが、どうやらNginxはナンバリング方法がちょっと特殊っぽい。

Nginxのバージョン1.10と1.11のリリースノート

図を見てもらうだけで大体理解出来ると思いますが、
現在Nginxでは「mainline版」と「stable版」の2つをリリースしている。

mainline版(1.11が最新)

新機能の追加、仕様変更、バグ修正等が行われる。

stable版(1.10が最新)

mainline版からフォークされたもので、mainline版で行った重要なバグ修正のみをstable版にマージするようになっている。

といった形になっています。
記事を軽く読んだ限りですと、バグ修正もmainlineに先に取り込まれるので、mainlineを使った方が安定するようです。
なのでインフラ屋さんにはmainline版である1.11を使ってもらうようにお願いしました。
取り敢えずNginx使おうと思って始めたので、バージョンをあまり気にしていなかったのですが、きちんと確認するべきですね・・・。

2016年6月15日水曜日

docker-composeのextra_hosts

docker-composeのリファレンスを読んでいたら、extra_hostsなるオプションがあった。
自分が初めてDocker使った時にあったのかどうかは調べてないのですが、こんな便利なオプションを見逃していたなんて・・・。
dockerコンテナは基本的に起動時にIPを動的に割り当てているため、毎回コンテナ上のhostsファイルが書き換わってしまい、独自の設定を入れる方法がなかった。
力技でやる場合は、ENTRYPOINTとかのシェルスクリプト内でhosts書き換えたりする程度しか思いついていなかった。

早速使ってみた。
※ローカルにphpやmysqlという名前のイメージがある状態で行っています。
適当なディレクトリにdocker-compose.ymlを作って、下記の内容を記述します。
$ vi docker-compose.yml
mysql:
  image: mysql
  container_name: mysql
  hostname: mysqldb
  ports:
    - 3306:3306

php:
  image: php
  container_name: php
  hostname: php
  extra_hosts:
    - test1.com:111.111.111.111
    - test2.com:222.222.222.222
  links:
    - mysql
この状態で
$ docker-compose up -d
してから、コンテナ内に入る。
$ docker exec -it php bash
で、hostsファイルを確認する。
# view /etc/hosts
172.17.2.103    php
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.2.95       mysql mysqldb
172.17.2.95       mysql_1 mysqldb mysql
111.111.111.111   test1.com
222.222.222.222   test2.com
こんな感じで、記載される様になります。
便利!

※但し、大量のhostsを記載する場合はdocker-compose.ymlのファイル内が長くなってしまうので、
その辺はある程度長くなってしまったら力技の方がいいのかもしれないです。
extra_hostsもファイル指定出来ればいいんですけどね。

2016年5月25日水曜日

PHPのバージョンアップに伴うPHP関連の調査メモ

PHPを5.2系から5.6系にバージョンアップするにあたって、諸々調査してみました。
  • php.ini関連(主にAPC- > APCu + OPCacheへの移行に関して)
  • php-fpmの設定値に関して
  • mysqlndの利用可・不可

php.ini関連(主にAPC- > APCu + OPCacheへの移行に関して)

APCはPHP 5.5以降では利用できなくなってしまったため、APCu + OPCacheに乗り換える必要があります。
乗り換えるにあったって、諸々調査したのでその結果を残しておこうと思います。

APC(Alternative PHP Cache)

まずAPCとは「Alternative PHP Cache (APC) は、PHP の実行コードをキャッシュする仕組みで、 フリーかつオープンに使用できます。PHP の中間コードのキャッシュ・最適化を行うための、フリーでオープンかつ堅牢なフレームワークを提供するということを目標としています。」(PHPの公式から抜粋)
と書かれていますが、実際は中間コードのキャッシュだけではなく、インメモリ型のKVSとして利用することも可能です。
※但しネットワーク越しのアクセスは不可

APCu

APCu is APC stripped of opcode caching.
→ APCuはAPCのオペコードキャッシュを除いたものです。

The first APCu codebase was versioned 4.0.0, it was forked from the head of the APC master branch at the time.
→ APCuの最初のコードはバージョン4.0.0で、APCのマスターブランチをフォークして作成されています。

PHP 7 support is available as of APCu 5.0.0.
→ PHP 7はAPCu5.0.0が利用出来る様になっています。

APCu can provide a compatibility mode, such that it can provide a drop in replacement for the applicable parts of APC.
→ APCuは互換性モードを提供しており、APCの一部の機能の下位互換を持っています。

公式から抜粋して訳してみたのですが、合っている保証はありません。
要するにインメモリ型のKVSの機能のみを提供するもので、APCからフォークされて出来ているみたいです。

OPCache(Zend OPCache)

OPCacheは「OPcache はコンパイル済みのバイトコードを共有メモリに保存し、PHP がリクエストのたびにスクリプトを読み込み、パースする手間を省くことでパフォーマンスを向上させます。」
と記載されている通りの機能です。
1点問題になるのは、OPCacheはシンボリックリンクを解決した状態でキャッシュされるため、
シンボリックリンクを変更しても、キャッシュは更新されないという問題がある。

http://kohkimakimoto.hatenablog.com/entry/2014/09/13/154342

また、opcache_resetもCLIから実行するとCLI側のオペコードキャッシュしか消えないようです。
そしてWebから実行されたopcache_resetはWeb側もCLI側も消えるという・・・。
この辺は自分でも検証してみようと思います。
結果は後日追記する予定です。

http://tech.gmo-media.jp/post/136590171029/php-53-to-php-56

php-fpm(FastCGI Process Manager)の設定値に関して

「PHP の FastCGI 実装のひとつで、 主に高負荷のサイトで有用な追加機能を用意しています。」 各サーバのスペックに応じてチューニングする必要のある部分は下記の所になります。(下記はデフォルト値です)
項目名設定値
pm.max_children50
pm.start_servers5
pm.min_spare_servers5
pm.max_spare_servers35
pm.max_requestsコメントアウト

この辺の値を変更する必要があるのですが、一律で変更出来るものではないので、
各自負荷テストを行った結果を反映させる必要があります。

mysqlndの利用可・不可

mysqlnd「MySQL Native Driver」とは「MySQL Client Library」に変わる新たなライブラリです。
mysqlndにしかない機能も多数あるので、移行出来るものならしたいものですが、そうはいかない世の中でした。
php5.5以降からmysqlndがデフォルトで利用される様になったのですが、mysqlndで16バイト長のパスワードが設定されているMySQL Serverに接続しにいくと、エラーが出てしまい接続出来ないという現象が発生します。
現状稼働しているMySQLに接続しにいかないといけないとかがあると、一手間必要になってしまいます。
どういった事が必要になるかというと、mysqlndでは41バイト長のパスワードハッシュでないと接続出来ないので、
バージョンの古いMySQLのバージョンだと、16バイト長のパスワードハッシュになっているので、それを41バイトハッシュに書き換えてやる必要があります。
影響範囲の洗い出しが簡単で、DB停止とかが出来るのであれば、変更可能だとは思いますが、そうでない場合は簡単には踏み切れないですね・・・。
PHP5.2(libmysql)とPHP5.6(mysqlnd)で、それぞれ16バイトと41バイトのパスワードが設定されている時にどういった挙動になるかを表にしてみました。
PHP5.2.17(libmysql)PHP5.6.18(mysqlnd)
MySQL5.1 [16byte Password]OKNG(mysqlnd cannot connect)
MySQL5.6 [16byte Password]OKNG(パスワード不一致)
MySQL5.1 [41byte Password]OKOK
MySQL5.6 [41byte Password]OKOK

基本的にはパスワードさえ41バイト長のものに変えてしまえばログイン出来るのですが、
注意点としては、MySQL4.0以前のクライアントが残っていると41バイト長のパスワードは受け付けられないので、ログインできなくなります。(下記の様なエラーが出るみたいです)
> mysql -h localhost -u root
Client does not support authentication protocol requested
by server; consider upgrading MySQL client
とはいえ、MySQL5.7では16バイト長のパスワード(OLD_PASSWORD)のサポートがなくなるみたいですので、早めに移行するに越したことはないですね。
既存のデータベースに引っ張られない様なシステムの構築する場合は、積極的に使っていきたいと思います。

現状利用しているphpのモジュール一覧を取得する。

phpのモジュール一覧を確認しようと思ったのですが、オプション忘れたので調べた。

言わずと知れたphpinfoのコマンド版
php -i
今回知りたかったロードしているモジュール一覧
php -m

phpの公式にコメント付きで書いてあるので、詳細はそちらで。
http://php.net/manual/ja/features.commandline.options.php

2016年4月2日土曜日

Dockerを利用してSeleniumのテスト環境を作る&WebDriverを使ってみる。

お手軽にSeleniumのテスト環境を作成する。

前提として
・CentOS7
・Docker1.8
・docker-compose1.5.2
・PHP
・composer
が導入済みの状態。

docker-compose.ymlには以下のように記載する。
selenium_chromeやselenium_firefoxで指定しているポート番号は任意で決めてもらってOK。
selenium_hub:
  image: docker.io/selenium/hub
  container_name: selenium-hub
  ports:
    - 4444:4444

selenium_chrome:
  image: docker.io/selenium/node-chrome-debug
  container_name: selenium-chrome
  ports:
    - 49154:5900
  links:
    - selenium_hub:hub

selenium_firefox:
  image: docker.io/selenium/node-firefox-debug
  container_name: selenium-firefox
  ports:
    - 49155:5900
  links:
    - selenium_hub:hub

コンテナを起動させる。
$ docker-compose up -d
こんな感じの状態になっていればOK
$ docker-compose ps
      Name                 Command           State            Ports
----------------------------------------------------------------------------
selenium-chrome      /opt/bin/entry_point.sh   Up      0.0.0.0:49154->5900/tcp
selenium-firefox       /opt/bin/entry_point.sh   Up      0.0.0.0:49155->5900/tcp
selenium-hub            /opt/bin/entry_point.sh   Up      0.0.0.0:4444->4444/tcp

で、composer.jsonは下記の様に記載して保存。
$ vi composer.json
{
    "require": {
        "phpunit/phpunit": "5.1.*",
        "phpunit/phpunit-selenium": "dev-master",
        "facebook/webdriver":"dev-master"
    }
}
composerコマンドで、上記のパッケージをインストールする。
$ composer install
とりあえずFirefoxを立ち上げて、自分のブログのページを表示させてみるスクリプトを書く。
$ vi test.php
<?php
require_once 'vendor/autoload.php';

$host   = 'http://VMのIP:4444/wd/hub';
$driver = RemoteWebDriver::create($host, DesiredCapabilities::firefox());
$driver->get('http://gyagya1111.blogspot.jp/');
で、実行する。
$ php test.php
VNCクライアントとかを使って、VMのIP:49155にアクセスすると、動いているのが見える。

2016年3月31日木曜日

composerに関して

案件でcomposer使っていて、軽い障害になりかけた時に記憶が曖昧で自信がなかったのでメモしておく。
composer install
composer.lockファイルを元にvendor配下にソースをインストールする。
composer.lockファイルが存在していない場合は、composer.jsonを元に最新バージョンをインストールする。
composer update
composer.jsonを元に最新のソースをインストールする。
バージョンアップが発生したものに関しては、composer.lockファイルの中身が更新される。
引数でパッケージ名を指定してやると、特定のパッケージのみ更新される。

2016年2月26日金曜日

Dockerfile作成時のTIPS

基本的にはコンテナの中で一通り作業をして、それをDockerfileに記述するというスタイルで作っているのですが、
一発でDockerfileが完成することなんて無いので、なるべく効率よく作れるように下記の事を心掛けています。

1.ステップは細かく分ける。

 最終的なDockerfileはステップ数をなるべく減らす必要があるが、
 Dockerfileを作成している時にはなるべく作業単位を細かくした方が効率がいい。
 例えば、インストールに時間の掛かる処理の後ろで、処理の軽い内容をやるとする。
 長い時間掛けてインストールが終わったのに、処理の軽い方で失敗した時には、
 インストールに掛かった時間がまるごと無駄になってしまう。
 時間の掛かる処理ほど細かく分けた方が、Dockerfileを書く時には効率よく書ける。

2.キャッシュをうまく使う。

 例えばDockerfileの最初でyumなりaptなりでインストール作業を行っていたとして、
 途中別の何かをインストールする際に、追加で入れないといけないミドルウェアが出てきた場合、
 最初にインストールしているところに追記するのではなく、必要になる処理の直前で追加してやる。
 こうすることにより、途中まで作成されたキャッシュイメージを無駄にせずに済む。