jBatchを使ってバッチアプリケーションのサンプルを作ってみた

WebLogic Serverも、先日リリースされた12cR2でJava EE 7に完全対応となりました。
そこで、Java EE 7から加わった仕様である、jBatchを使って、簡単なサンプルアプリケーションを作ってみました。

jBatchそのものに関しては、主に以下の資料で勉強させていただきました。

サンプルアプリケーションの説明

今回作成したアプリケーションでやっている処理は至ってシンプルです。
chunk方式のメソッドが実行される順序を実際に見てみたかったので、1つのstepをchunk方式で実装し、以下のような処理を行っています。

  • ItemReader等の各インターフェースのメソッドが実行されたら、標準出力にその旨を出力する
  • ItemReader#readItem()、ItemWriter#writeItem()の実行回数をチェックポイント情報として返す
  • ItemWriter#writeItem()が実行されたら、readItem()、writeItem()の累積実行回数を標準出力に出力する

今回のアプリケーションのコードは、githubに公開してます。
コードを取得しでmavenでビルドすると、Java EEコンテナにデプロイするだけで実行可能なwarができ上がります。WebLogicでしか確認してませんが、シンプルなアプリなので他のコンテナでも大丈夫なはず…。

$ mvn package

ジョブの実行は、そのためのRESTのインターフェースを用意しています。以下のURLにGETリクエストを投げてください。

http://${host}:${PORT}/${CONTEXT_ROOT}/resources/JobController/Start

コード抜粋

以下、コードの抜粋です。Job定義とItemWriterの実装。

実行してみる

WebLogicにデプロイして、上記のRESTインターフェースを呼び出すと、標準出力に以下のような結果が出力されます。
ジョブ定義のitem-countの回数(3)だけreadItem(),processItem()を実行した後、writeItems()を1回実行、以下その繰り返しとなっているのがわかります。

jp.gr.java_conf.hhayakawa_jp.sample.jbatch.resource.JobController#start(31)
jp.gr.java_conf.hhayakawa_jp.sample.jbatch.SimpleItemReader#open(62)
jp.gr.java_conf.hhayakawa_jp.sample.jbatch.SimpleItemWriter#open(54)
jp.gr.java_conf.hhayakawa_jp.sample.jbatch.SimpleItemReader#readItem(79)
jp.gr.java_conf.hhayakawa_jp.sample.jbatch.SimpleItemProcessor#processItem(26)
jp.gr.java_conf.hhayakawa_jp.sample.jbatch.SimpleItemReader#readItem(79)
jp.gr.java_conf.hhayakawa_jp.sample.jbatch.SimpleItemProcessor#processItem(26)
jp.gr.java_conf.hhayakawa_jp.sample.jbatch.SimpleItemReader#readItem(79)
jp.gr.java_conf.hhayakawa_jp.sample.jbatch.SimpleItemProcessor#processItem(26)
jp.gr.java_conf.hhayakawa_jp.sample.jbatch.SimpleItemWriter#writeItems(71)
ItemReader#readItem() has been executed [3] times.
ItemWriter#writeItem() has benn executed [1] times(including this execution).
jp.gr.java_conf.hhayakawa_jp.sample.jbatch.SimpleItemReader#checkpointInfo(41)
jp.gr.java_conf.hhayakawa_jp.sample.jbatch.SimpleItemWriter#checkpointInfo(33)
jp.gr.java_conf.hhayakawa_jp.sample.jbatch.SimpleItemReader#readItem(79)
jp.gr.java_conf.hhayakawa_jp.sample.jbatch.SimpleItemProcessor#processItem(26)
…
ItemReader#readItem() has been executed [10] times.
ItemWriter#writeItem() has benn executed [4] times(including this execution).
jp.gr.java_conf.hhayakawa_jp.sample.jbatch.SimpleItemReader#checkpointInfo(41)
jp.gr.java_conf.hhayakawa_jp.sample.jbatch.SimpleItemWriter#checkpointInfo(33)
jp.gr.java_conf.hhayakawa_jp.sample.jbatch.SimpleItemWriter#close(42)
jp.gr.java_conf.hhayakawa_jp.sample.jbatch.SimpleItemReader#close(50)

今後、このサンプルをベースにいろいろ試してみたいと思います。
次回は、チェックポイントを使って中断/再開とか、試してみようかな。

WebLogic Server 12.2.1 + サンプルドメイン がインストールされた Docker コンテナを、Vagrant のゲストOS上に構成する

前回の記事に引き続き、WebLogic Server 12.2.1 がインストールされた Docker コンテナを、Vagrant のテストOS上に構成します。
今回は、WebLogic 公式のサンプルである、medrec ドメインを構成し、サンプルアプリケーションを動かしてみます。

本記事の手順により、12.2.1 の目玉機能である、Multitenant(マルチテナント)機能を試すこともできます。

手順

1. 事前準備

まずは、前回の記事の、「1-5. WebLogic Server, JDKインストーラをダウンロードする」までの手順を済ませてください。 以降はそれが済んだ後の手順となります。

1-1. サンプルドメイン構成用の Dockerfile を修正する

今回の手順では、サンプルドメイン構成用の Dockerfile を利用します。
ダウンロードしたものをそのまま利用すると、後の手順で Docker run したときに自動的にドメインの構成が開始されます。今回はそれでは都合がわるいので、少し手を加えます。

$ cd ~/dock/OracleWebLogic/samples/1221-domain
$ vi Dockerfile.supplementaldomain

ファイルの終わりの方に、Docker イメージの .bashrc に3行追記している箇所がある(L71-L73)ので、最後の1行の追記が行われないように編集してください。

編集前

RUN echo "cp /u01/oracle/weblogic.properties /u01/oracle/weblogic/wlserver/samples/server/medrec/weblogic.properties" >> /u01/oracle/.bashrc && \
    echo "cp /u01/oracle/startSamples.sh /u01/oracle/weblogic/wlserver/samples/server/medrec/startSamples.sh" >> /u01/oracle/.bashrc && \
    echo ". /u01/oracle/weblogic/wlserver/samples/server/medrec/startSamples.sh" >> /u01/oracle/.bashrc

編集後

RUN echo "cp /u01/oracle/weblogic.properties /u01/oracle/weblogic/wlserver/samples/server/medrec/weblogic.properties" >> /u01/oracle/.bashrc && \
    echo "cp /u01/oracle/startSamples.sh /u01/oracle/weblogic/wlserver/samples/server/medrec/startSamples.sh" >> /u01/oracle/.bashrc

1-2. 必要なインストーラをダウンロードする

サンプルドメインをインストールするには、Suppelemental Quick Installer で、追加のコンポーネントをインストールする必要があります。

こちらから、fmw_12.2.1.0.0_wls_supplemental_quick.jar をダウンロードし、~/dock/OracleWebLogic/samples/1221-domain/ に配置します。

2. ゲストOS、Docker コンテナを起動する

2-1. ゲストOSのプロビジョニング

前回の記事の「2-1. ゲストOSのプロビジョニング」と同じ手順を実施してください。

2-2. Dcoker イメージのビルド

ここからは、ゲストOS上での手順です。まずは Docker イメージをビルドします(前回と同じ)。

[vagrant@guest] $ cd ~/sync/OracleWebLogic/dockerfiles
[vagrant@guest] $ sudo sh buildDockerImage.sh -v 12.2.1 -d

この Docker イメージをベースにして、Supplemental Quick Installer の追加コンポーネントをインストールした Docker イメージをビルドします。

[vagrant@guest] $ cd ~/sync/OracleWebLogic/samples/1221-domain
[vagrant@guest] $ ln -s ./Dockerfile.supplementaldomain ./Dockerfile
[vagrant@guest] $ sudo docker build -t wls.supplementaldomain:12.2.1 ./

2-3. Docker コンテナの起動

以下のコマンドで Docker コンテナを起動します(ポートフォワーディングの設定は必要な物に絞ってあります)

[vagrant@guest] $ sudo docker run -p 7011:7011 -it --name=wlsadmin wls.supplementaldomain:12.2.1
[oracle@xxxxxxxxxxxx medrec]$ (←コンテナのシェルに切り替わる)

3. medrec ドメインを構成する

3-1. 管理サーバーの起動スクリプトの修正

ドメインの構成を行う前に、構成時に実行される管理サーバーの起動スクリプトに手を加えます。

このスクリプトでは、WLST を使って管理サーバーの起動をおこなっています。この処理で、起動状態のヘルスチェックでタイムアウトとなることを避けるため、タイムアウト時間を無制限(0)に変更します。

[oracle@xxxxxxxxxxxx medrec]$ cd /u01/oracle/weblogic/wlserver/samples/server/medrec/install/common
[oracle@xxxxxxxxxxxx common]$ vi startAdminServer.py

変更前

startServer(serverName, domainName, url, username, password, domainDir, 'true', jvmArgs=jvmargs)

変更後

startServer(serverName, domainName, url, username, password, domainDir, 'true', 0, jvmArgs=jvmargs)

3-2. ドメイン構成用スクリプトの修正(マルチテナントの medrec ドメインを構成する場合)

(シングルテナント(=従来と同じ)のドメインを構成したい場合は 3-3. に進んでください)

ドメインを構成するときに実行する startSamples.sh は、内部で ant コマンドを使っています。このコマンドのオプションを変えることによって、マルチテナントのドメインを構成することができます。

[oracle@xxxxxxxxxxxx medrec]$ cd /u01/oracle/weblogic/wlserver/samples/server/medrec
[oracle@xxxxxxxxxxxx common]$ vi startSamples.sh

変更前

ant single.server.sample

変更後

ant mt.single.server.sample

3-3. マルチテナントの madrec ドメインを構成する

いよいよドメインの構成を開始します。 コンテナ上で、以下のコマンドを実行します(結構時間がかかります)

[oracle@xxxxxxxxxxxx medrec]$ cd /u01/oracle/weblogic/wlserver/samples/server/medrec
[oracle@xxxxxxxxxxxx medrec]$ sh ./startSamples.sh

3-4. medrec アプリケーションにアクセスしてみる

無事に "BUILD SUCCESSFUL" のメッセージが表示されたら、ドメインの構成は完了です。WebLogic Server 管理コンソールと、medrec アプリケーションにアクセスしてみます。

おまけ: スクリーンショット

管理コンソール(マルチドメイン)にアクセスしたところ。
3つのドメインパーティションが構成されているのがわかります。

f:id:charlier_shoe:20151118123811p:plain

medrec アプリケーションにアクセスしたところ。
ドメインの切り分けが、URLのパス "/valley1" のところに反映されています。 ホストパート部分で切り替えることはできるのかな?パスで切り替えるのは嫌われるケースもありそうな気が。

f:id:charlier_shoe:20151118123817p:plain

WebLogic Server 12.2.1 がインストールされた Docker コンテナを、Vagrant のゲストOS上に構成する

本記事では、Oracle 公式の Dockerfile とスクリプトを利用して、WebLogic Server 12.2.1 がインストールされた Docker コンテナを、Vagrant のゲストOS上に構成します。
この手順により、以下のような構成の WLS 12.2.1 環境が出来上がります。

  --------------------------------------------------
  | Dockerコンテナ (Oracle Linux 7.0) + WLS 12.2.1 |
  --------------------------------------------------
  | ゲストOS(CentOS 7) + Docker                   |
  --------------------------------------------------
  | ホストOS (Windows) + VirtualBox                |
  --------------------------------------------------

私の環境は Windows 7 Professional x64 なので、本手順の実績のあるホストOSは左記のものになります。また、WLS のドメインは、本記事の手順では空のドメインが構成されます。

サンプルアプリなどがインストールされた環境を作ることもできるはずですが、手順を確立したら、追って紹介したいと思います。

手順

1. 事前準備

1-1. 必要なソフトウェアを準備する

はじめに、ソフトウェアをインストールしていきます。(括弧内は、本手順の確認に使用したバージョン)

1-1-1. VirtualBoxのインストール

ダウンロードサイトから適切なインストーラをダウンロードし、実行します。

1-1-2. Cygwinのインストール

ダウンロードサイトから適切なインストーラをダウンロードし、実行します。

Cygwinのインストールの際、以下のコンポーネントを併せてインストールしておく必要がありますので注意してください(後からでも追加できます)。

インストールが完了したら、Cドライブへのシンボリックリンクを貼っておきます。これにより、ゲストOSとホストOSの共有フォルダを構成する際に、ホストOS側のパスを正しく解決できるようにします。
Cygwinを起動して、以下のコマンドを実行してください。

$ cd /
$ ln -s /cygdrive/c c
1-1-3. Vagrantのインストール

ダウンロードサイトから適切なインストーラをダウンロードし、ウィザートにしたがってインストールします。

インストールが完了したら、vbguestプラグインをインストールします。これにより、VagrantにVirtutalBoxのguest additionsを自動更新するためのプラグインをインストールします。
Cygwinを起動して、以下のコマンドを実行してください。

$ cd ~/
$ vagrant plugin install vagrant-vbguest

1-2. 作業フォルダを作成する

今回は、作業フォルダのトップを "~/dock" とします。ここが Vagrant プロジェクトのルートディレクトリも兼ねることにします。
Cygwinを起動して、以下のコマンドを実行します。

$ mkdir ~/dock

1-3. Oracle 公式の Dockerfile、スクリプト群をダウンロードする

Oracle が提供する Dockerfile、スクリプト群 をダウンロードします。公式のマニュアルからリンクされていますので、Oracle が公式に提供しているもののようです。

上記リンク先で、[Download ZIP] をクリックして zip アーカイブをダウンロードします。アーカイブを解凍したら、docker-master ディレクトリ配下のファイル、ディレクトリを、~/dock 直下にコピーします。

1-4. Vagrantfile を作成する

ゲストOSは Vagrant を使ってプロビジョニングするので、Vagrantfile を ~/dock の配下に作成します。
内容は以下のようにします。リソースの割当て量は、環境に合わせて調整してください。

Vagrant.configure(2) do |config|

    config.vm.define :dock, primary: true do |dock|
        # VM settings
        dock.vm.box = "centos/7"
        dock.vm.provider "virtualbox" do |v|
            v.name = "dock"
            v.cpus = "2"
            v.memory = "4096"
        end
        dock.vm.synced_folder ".", "/vagrant", type: "rsync"
        dock.vm.network "forwarded_port", host: 5556, guest: 5556
        dock.vm.network "forwarded_port", host: 7001, guest: 7001
        dock.vm.network "forwarded_port", host: 7011, guest: 7011
        dock.vm.network "forwarded_port", host: 8001, guest: 8001

        # Provisioner settings
        config.vm.provision "docker"
    end

end

ゲストOSに Dockerfile 等を転送する手間を省くために、~/dock(カレントディレクトリ)との共有ディレクトリを設定しています。
また、WebLogic Server を使うときに用いる主要なポート対し、ポートフォワーディングの設定をしています。

1-5. WebLogic Server,JDKインストーラをダウンロードする

以下のインストーラをダウンロードし、~/dock/OracleWebLogic/dockerfiles/12.2.1/ に配置します。

ここまでの手順を終えると、ディレクトリは、以下の様な構成となるはずです。間違って配置されていないか、注意してください。

~/dock
├─MySQL/
├─OracleCoherence/
│    …
├─OracleWebLogic/
│  ├─dockerfiles/
│  │  ├─12.1.3/
│  │  │    …
│  │  ├─12.2.1/
│  │  │  ├―fmw_12.2.1.0.0_wls_quick.jar
│  │  │  ├―jdk-8u60-linux-x64.rpm
│  │  │  └―Dockerfile.developer
│  │  │    …
│  │  └─buildDockerImage.sh
│  └─samples/
│      ├─1213-domain/
│      │  └─container-scripts/
│      │        …
│      │    …
│      └─1221-domain/
│          ├─container-scripts/
│          │    …
│          └―Dockerfile.emptydomain
│              …
├─README.md
└―Vagrantfile

以上で準備完了です。

2. ゲストOS、Dockerコンテナを起動する

2-1. ゲストOSのプロビジョニング

ゲストOSの box イメージを取得します。本記事では CentOS 7 を利用します。Cygwin を起動して、以下のコマンドを実行します。

$ vagrant box add centos/7 --provider virtualbox

次に、以下のコマンドを実行します。ゲストOSのプロビジョニングが行われ、続けてゲストOSが起動します。

$ cd ~/dock
$ vagrant up

上記のコマンドの完了したら、SSHでゲストOSに接続し、~/sync フォルダ以下にホストOSの ~/dock 配下のファイルが参照できることを確認してください。

$ vagrant ssh
[vagrant@guest] $ ls ~/sync

2-2. Dockerイメージのビルド

以下のコマンドを実行して Docker イメージをビルドします。以降のコマンドは、ゲストOS上で実行することに注意してください。

[vagrant@guest] $ cd ~/sync/OracleWebLogic/dockerfiles
[vagrant@guest] $ sudo sh buildDockerImage.sh -v 12.2.1 -d

ビルドの処理の中で、WebLogic Server のインストールも行われます。正常に処理が完了すると、WebLogic Server をインストール済みの Docker イメージができあがります。

更に、上記の Docker イメージをベースにして、空のWLSドメインを構成済みの Docker イメージをビルドします。

[vagrant@guest] $ cd ~/sync/OracleWebLogic/samples/1221-domain
[vagrant@guest] $ ln -s ./Dockerfile.emptydomain ./Dockerfile
[vagrant@guest] $ sudo docker build -t myweblogic:12.2.1 ./

2-3. Dockerコンテナの起動

以下のコマンドを実行して、ビルドした Docker イメージからコンテナを起動します。startWebLogic.sh が自動的に実行されます。

[vagrant@guest] $ sudo docker run -p 5556:5556 -p 7001:7001 -p 7011:7011 -p 8001:8001 -it --name=wlsadmin myweblogic:12.2.1

上記のコマンドで、-p オプションを複数していますが、これらは、Docker コンテナとゲストOS間のポートフォワーディングの設定です。

バックグラウンドで起動する場合は、以下のようにコマンドのオプションを変更します。

[vagrant@guest] $ sudo docker run -p 5556:5556 -p 7001:7001 -p 7011:7011 -p 8001:8001 -d --name=wlsadmin myweblogic:12.2.1

2-4. 管理コンソールにアクセスしてみる

Dockerコンテナへのポートフォワーディングが設定済みです。ホストOSのブラウザで、以下のURLにアクセスすると、WLSの管理コンソールにアクセスできます。

http://localhost:8001/console

管理者ユーザーのユーザーのユーザー名、パスワードは以下のとおりです。

  • ユーザー名: weblogic
  • パスワード: welcome1


WebLogic Server 12.2.1 がインストールされた Docker コンテナを、Vagrant のゲストOS上に構成する手順は、以上です。

Oracle Linux 7.1 の Docker コンテナに SSH で接続する

今回は、表題の通り、Oracle Linux 7.1 の Docker コンテナにSSHでアクセスするために必要な手順を紹介します。

前提として、VirtualBox 上の Oracle LinuxVagrant でゲストOSを構成し、そこに Docker コンテナを立てているものとします。今回は、この Docker コンテナにホストOS からSSHで接続します。

f:id:charlier_shoe:20151022120149p:plain

今回は、過去の記事で作成した環境をベースに作業を行いますので、前提条件の詳細については、左記の記事を参照ください。

手順

1. Vagrantfile の編集

1-1. ポートマッピング

Docker コンテナの22ポートにアクセスするため、ゲストOS <-> Docker コンテナ、およびホストOS <-> ゲストOSのポートマッピングを設定します。

ゲストOS <-> Docker コンテナ のポートマッピングは、”docker run" コマンドのオプションで指定します。Vagrant から Docker コンテナをプロビジョニングをしているので、Vagrantfile 内に run コマンドを記述しています。したがって、この記述にポートマッピングのオプションを追記します。

今回は、Docker コンテナの22番ポートをゲストOSの10022番ポートにマップします("-p 10022:22" という部分)。

Vagrant.configure(2) do |config|
…
    # Provisioner settings
    config.vm.provision "docker" do |d|
        d.build_image "/vagrant", args: "-t charlier_shoe/hoge"
        d.run "charlier_shoe/hoge",
               args: "-d -t -p 10022:22 -p 17001:7001 -v /vagrant:/tmp/shared --memory-swap -1"
    endend

ホストOS <-> ゲストOS のポートマッピングは、Vagrantfile 内のゲストOSの設定で行います。

以下の例では、ゲストOSの10022番ポートを、ホストOSの10022番ポートにマップしています。

Vagrant.configure(2) do |config|
…
    # VM settings
    config.vm.define :dock, primary: true do |dock|
        …
        dock.vm.network "forwarded_port", host: 10022, guest: 10022
    endend

以上の設定により、ゲストOSの22番ポートが、localhostの10022番ポートにマッピングされます。

以下、Vagrantfile の全体を示します。今後 Docker コンテナ上で WebLogic Server を動作させる予定なので、コンテナの7001番に対するポートマッピングの設定も記述しています。

Vagrant.configure(2) do |config|

    # VM settings
    config.vm.define :dock, primary: true do |dock|
        dock.vm.box = "oraclelinux-7.1-x86_64"
        dock.vm.provider "virtualbox" do |v|
            v.name = "dock"
            v.cpus = "2"
            v.memory = "4096"
        end
        dock.vm.network "forwarded_port", host: 10022, guest: 10022
        dock.vm.network "forwarded_port", host: 17001, guest: 17001
    end

    # Provisioner settings
    config.vm.provision "docker" do |d|
        d.build_image "/vagrant", args: "-t charlier_shoe/hoge"
        d.run "charlier_shoe/hoge",
               args: "-d -t -p 10022:22 -p 17001:7001 -v /vagrant:/tmp/shared --memory-swap -1"
    end
end

2. Dockerfile の編集

Dockerfile を編集して、コンテナのビルド時に、コンテナに対して必要な構成変更をおこなうようにします。
今回利用するコンテナの場合、以下の構成変更を行う必要があります。

  • root ユーザーのパスワードの変更
  • PAM認証の設定変更
  • SSH ホストキーの構成
  • 22番ポートの開放
  • "docker run" 実行時の、SSH デーモンの起動

2-1. root ユーザーのパスワードの設定

本記事では、root ユーザーで接続することにします。
今回利用するコンテナ(Oracle のオフィシャル)では、root ユーザーのパスワードがわからない(設定されていない?)ので、ここで所望のパスワードに変更しておきます。

Dockerfile に記述する内容は、以下のとおりです。

RUN echo 'root:root' | chpasswd

2-2. PAM認証の設定変更

この手順をやっておかないと、SSH 接続で認証が終わった直後に切断される現象が起きます。

Docker の公式サイトのガイドにしたがって、Dockerfile に以下の記述を追加します。

RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd

/etc/pam.d/sshd ファイルを編集して、SSH デーモンに適用される PAM認証の設定に手を入れているようです。
ちなみに、/etc/ssh/sshd_config を編集して PAM認証を無効にする方法が紹介されている場合もありますが、Oracle Linux のような RedHat 系のディストリビューションでは、この方法はサポートされていないようです。

2-3. SSH ホストキーの構成

今回利用するコンテナは、そのままでは SSH のホストキーが配置されていないので、新たに作成する必要があります。

Dockerfile に記述する内容は、以下のとおりです。

RUN /usr/bin/ssh-keygen -t rsa -b 2048 -f /etc/ssh/ssh_host_rsa_key -N ''
RUN /usr/bin/ssh-keygen -t ecdsa -b 256 -f /etc/ssh/ssh_host_ecdsa_key -N ''
RUN /usr/bin/ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ''

ssh-keygen コマンドで、所定のパスにキーを生成しています。
キーのアクセス権を絞っておかないと、SSH デーモンの起動時にエラーになるような気がしますが、今回は不要でした。

2-4. 22番ポートの開放

22番ポート(SSH の通信用のポート)を解放して、外部からのアクセスを受け付けるようにします。

Dockerfile に記述する内容は、以下のとおりです。

EXPOSE 22

2-5. "docker run" 実行時の、SSH デーモンの起動

コンテナの起動とともに SSH デーモンが起動するようにしておきます。

Dockerfile に記述する内容は、以下のとおりです。

CMD ["/usr/sbin/sshd", "-D"]

以上で Dockerfile の編集は完了です。以下に Dockerfile の全体を示します。

FROM oraclelinux:latest
MAINTAINER Oracle Linux Product Team <ol-ovm-info_ww@oracle.com>

RUN yum install -y openssh-server
RUN yum install -y openssh-clients

RUN echo 'root:root' | chpasswd
# RUN sed -i 's/#PermitRootLogin yes/PermitRootLogin without-password/' /etc/ssh/sshd_config
# RUN sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config

# edit PAM auth configuration
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd

# generate SSH host key
RUN /usr/bin/ssh-keygen -t rsa -b 2048 -f /etc/ssh/ssh_host_rsa_key -N ''
## For ECDSA keys, the -b flag determines the key length by selecting from one of
## three elliptic curve sizes: 256, 384 or 521 bits.
RUN /usr/bin/ssh-keygen -t ecdsa -b 256 -f /etc/ssh/ssh_host_ecdsa_key -N ''
## Ed25519 keys have a fixed length and the -b flag will be ignored.
RUN /usr/bin/ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ''

EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]

3. Docker コンテナをプロビジョニングする

いよいよ Docker コンテナをプロビジョニングします。
Vagrantfile を配置したフォルダをカレントにして、以下のコマンドを実行してください。

(vagrant up が終わっている状態)
$ vagrant provision

続いて、SSH でコンテナに接続してみます。

$ ssh -p 10022 root@localhost

パスワードが聞かれるので、"root" と入力します。これでコンテナにアクセスできるはずです。

英字キーボードで [CapsLock] と [Ctrl]、[ESC] と "`~" を入れ替える

今回は、入力装置系の記事です。 英字キーボードで、以下のようなキー配列の変更をする方法を紹介します。

  • キー配列
    • [CapsLock] <-> [Ctrl]
    • [ESC] <-> "`~"
  • OS

普段エディタとしてVimを使っていると、[ESC] を頻繁に利用することになります。一般的なキーボードは[ESC]がFnキーの列の一番左にあり、ホームポジションの手の位置から、かなり離れています。
そこで、[ESC] を、普段ほとんど使うことのない "`~" キーと入替えてしまいます。
また、ついでに [CapsLock] と [Ctrl] も入替えます。これはまあ、定番なので、理由は気にしないでください。

手順

今回紹介する手順では、レジストリにScancode Mapという設定を追加します。具体的な手順は「CapsLockキーとCtrlキーを入れ替え、さらに半角・全角キーとESCキーを入れ替える」を参考にしてください。

上記の手順の中で、Sacncode Mapに記述するバイナリ値を以下のように設定します。

00 00 00 00 00 00 00 00
05 00 00 00 1d 00 3a 00
3a 00 1d 00 01 00 29 00
29 00 01 00 00 00 00 00

後はマシンを再起動して、レジストリの編集を反映させればOKです。

レジストリの記述内容の意味は、上記サイトに記載があります。本記事の手順は、[ESC] のスキャンコード "01" と "`~" のスキャンコード "29" を、上記サイトの手順に当てはめている事になります。

あとはスキャンコードがわかれば、自分で好きなようにキー配列をカスタマイズできるはずです。
キーのスキャンコードの一覧は、「Windows-TIPS-レジストリを修正してCAPSLOCKの割り当て変更 - yanor.net-wiki」を参考にしてください。

参考

Vagrant + Docker で Oracle Linux 7.1のコンテナを使う

VagrantVirtualbox 上に Oracle Linux 7.1 を動作させ、その上で Oracle Linux 7.1 の Docker コンテナを動かしてみました。

前提の整理

今回作成した環境の構成は、以下のとおりです。

本記事は、VagrantCygwin はインストール済みの前提で記述します。特に、Cygwin インストール時の注意事項については、過去の記事を参照ください。

Vagrant に vbguest プラグインをインストールする

Docker コンテナの作成で Dokerfile を参照させる際、ホストOSとゲストOSの共有フォルダがあると便利です。
共有フォルダを作るには、Virtualbox の guest additions がゲストOSに適切にインストールされる必要があります。このために、Vagrant にゲストOSの guest additions を自動更新してくれるプラグインをインストールします。

$ vagrant plugin install vagrant-vbguest
Installing the 'vagrant-vbguest' plugin. This can take a few minutes...
Installed the plugin 'vagrant-vbguest (0.10.0)'!

これで、Vagrantfile があるフォルダが、ゲストOS上の /vagrant にマウントされる様になります。

ゲストOSをセットアップする

適当なフォルダを作成し、Vagrantfile を作成します。

$ cd ~/
$ mkdir dock
$ touch ~/dock/Vagrantfile
$ vi ~/dock/Vagrantfile

Vagrantfile の内容は以下のとおりです。

Vagrant.configure(2) do |config|

    # VM settings
    config.vm.define :dock, primary: true do |dock|
        dock.vm.box = "oraclelinux-7.1-x86_64"
    end

    # VM provider settings
    config.vm.provider "virtualbox" do |vb|
        vb.name = "dock"
        vb.cpus = "2"
        vb.memory = "4096"
    end
end

実際にDockerコンテナでアプリケーションを動かしたりする場合、ポートフォワーディングの設定などが必要になりますが、今回はただ動かすだけなので省略します。

ゲストOSを起動します。過去の記事に引き続き、terrywang さんが公開している Oracle Linux 7 の Base Box を利用させていただきます。

$ vagrant box add oraclelinux-7.1-x86_64 http://cloud.terry.im/vagrant/oraclelinux-7-x86_64.box
$ cd dock
$ vagrant up dock

ゲストOSの構築中に、guest additions の更新と再起動が行われます。
また、ssh でゲストOSが利用できるように、/.ssh ファイルの設定もしておきます。こちらは過去の記事の手順を参考にしてください。以降、"ssh dock-root" と打つことで、ゲストOSに root でアクセスできるものとします。

Provisioner(=Docker) をインストールし、Docker デーモンを起動する

ゲストOSに Oracle Linux を使っている場合、 yum のアドオンのリポジトリにアクセスできるように設定をおこなう必要があります。これをやっておかないと、ゲストOSに provisioner (=Docker) をインストールする際に、エラーになってしまいます。

ゲストOSで /etc/yum.repos.d/public-yum-ol7.repo を編集します。

$ ssh dock-root
[root@oraclelinux7:~]$ vim /etc/yum.repos.d/public-yum-ol7.repo

[ol7_addons] 配下の enabled の値を、1 (=有効)に変更します。

…
[ol7_addons]
name=Oracle Linux $releasever Add ons ($basearch)
baseurl=http://public-yum.oracle.com/repo/OracleLinux/OL7/addons/$basearch/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-oracle
gpgcheck=1
enabled=1
…

続いて、Vagrantfile に provisioner の設定を追記します。

Vagrant.configure(2) do |config|

    # VM settings
    config.vm.define :dock, primary: true do |dock|
        dock.vm.box = "oraclelinux-7.1-x86_64"
    end

    # VM provider settings
    config.vm.provider "virtualbox" do |vb|
        vb.name = "dock"
        vb.cpus = "2"
        vb.memory = "4096"
    end

    # Provisioner settings
    config.vm.provision "docker"
end

最後に provisioner (=Docker) を起動します。

$ vagrant provision

以上の手順により、ゲストOSに Docker がインストールされ、Docker デーモンが起動します。

Docker イメージをビルドし、コンテナを起動する

いよいよ Docker コンテナを動作させてみます。

まず、ホストOSの Vagrantfile が配置されたフォルダに、Dockerfile という名前でファイルを作成し、以下の内容を記述しておきます。

FROM oraclelinux:latest
MAINTAINER Oracle Linux Product Team <ol-ovm-info_ww@oracle.com>
CMD ["/bin/bash"]

続いて Docker イメージをビルドします。

$ ssh dock-root
root@oraclelinux7:~# docker build -t charlier_shoe/hoge /vagrant

Oracle Linux の Docker イメージは、Docker Hub に公式のものがありますので、それを利用しています。

-t オプションは、ビルドされたイメージにつけるタグ名です。後で、コンテナを起動する際、このタグ名でイメージを指定します。
Dockerfile を配置したフォルダは、ゲストOSの /vagrant に共有フォルダとしてマウントされています。コマンドの最後の "/vagrant" は、Dockerfileの配置先を指定していますが、共有フォルダの設定のおかげで、先の Dockerfile がすでに配置された状態になっています。

続いて、以下のコマンドを実行します。

$ ssh dock-root
root@oraclelinux7:~# docker run -it -v /vagrant:/tmp/shared --name="hoge" charlier_shoe/hoge

上記では、ゲストOSに root でアクセスした後、Docker イメージのビルド、コンテナの起動が行うコマンドを実行しています。オプションの意味は以下のとおりです。

  • -i
    • 標準入力を開いたままにします(=対話モード)
  • -t
    • 擬似ターミナル割り当て(…?)
  • -v /vagrant:/tmp/shared
    • /tmp/shared をゲストOSの /vagrant との共有フォルダに設定します
  • --name="hoge"
    • コンテナの名前を指定します
  • charlier_shoe/hoge
    • イメージのタグの名前を指定しています。この文字列はビルド時につけた名前です。

無事にコンテナが起動すると、コンテナに root ユーザーでアクセスした状態になります。

[root@a76d0766aba6 /]# ls
bin   dev  home  lib64  mnt  proc  run   srv  tmp  var
boot  etc  lib   media  opt  root  sbin  sys  usr
[root@a76d0766aba6 /]# ls /tmp/shared/
Dockerfile  Vagrantfile

/tmp/shared/ に、共有フォルダに配置したファイルがあるのがわかります。
アプリケーションサーバーをインストールしたいときなど、共有フォルダを使うとインストーラを転送する手間が省けて便利です。

exit コマンドを打つと、コンテナがシャットダウンします。

[root@a76d0766aba6 ~]# exit

run コマンドでは、新たにコンテナを作成しようとするため、既存のコンテナを起動するときは start コマンドを使います。

root@oraclelinux7:~# docker start hoge
hoge

起動中のコンテナに複数のターミナルからアクセスしたい場合、ゲストOSから、exec コマンドで bash を起動してやります。

root@oraclelinux7:~# docker exec -it hoge bash

コンテナの停止は stop コマンドです。

root@oraclelinux7:~# docker stop hoge
hoge

VagrantVirtualbox 上に Oracle Linux 7.1 を動作させ、その上で Oracle Linux 7.1 の Docker コンテナを動かす手順は、以上です。

JRockit JVMのガベージコレクションのまとめ

JRockit JVMガベージコレクションの仕組みを、公式のドキュメント読んでざっくりまとめてみました。
改めて調べてみると、HotSpot JVM とほとんど変わらないみたいです。既にご存知の方には釈迦に説法ですが、JVM のメモリ管理について初学者の方は、参考にしてみてください。

JRockit JVM が使用するメモリ領域

スタック領域や、パーマネント領域といった分け方もありますが、参照先では以下のような分け方で説明されています。

  • ヒープメモリ
    • 二世代のガベージコレクションが利用される場合、「ナーサリ(若い領域)」と「古い領域」の2つの領域(世代)に分割される *1
    • ナーサリ(若い領域)
      • 新しいオブジェクトの割り当てのために予約されている領域
    • 古い領域
      • 若いコレクションで昇格されたオブジェクトや、大規模オブジェクトが割り当てられる領域
  • ヒープメモリ以外のメモリ領域

若いコレクションと、古いコレクション

二世代のガベージコレクションを利用する場合、ガベージコレクションには、「若いコレクション」と「古いコレクション」とがあります。

  • 若いコレクション
    • ナーサリに保持された古いオブジェクトを、古い領域に「昇格(移動)」する処理
    • 古いコレクション(後述)や一世代のガベージコレクション(ナーサリのないヒープに対するガベージコレクション)よりも、格段に速くメモリ領域を開放できる
    • ナーサリの「保持領域」
      • ナーサリの一部に確保される領域
      • ここに保管されたオブジェクトは、直後の若いコレクションで昇格されない。このことにより、オブジェクトが割り当てられた直後に昇格してしまうのを防止する
  • 古いコレクション

小規模オブジェクトと大規模オブジェクト

JRockit JVM では、オブジェクト割り当て時に小規模オブジェクトと大規模オブジェクトが区別されます。

  • 小模オブジェクトと大規模オブジェクト

    • 通常 2 ~ 128 KB が区別の基準となる
    • 小規模か大規模化は、おおよそ以下の項目により決定される
  • 小規模オブジェクト

    • スレッドローカル領域(TLA)に割り当てられる
    • 二世代のガベージコレクションの場合、TLA はナーサリから確保される
  • 大規模オブジェクト
    • TLA に収まらないオブジェクト
    • 二世代のガベージコレクションの場合、古い領域に割り当てられる
    • 大規模オブジェクトの割り当てには、複数Java スレッド間の、オブジェクトキャッシュの同期を頻繁に行う必要がある *2

ガベージコレクション

二世代のガベージコレクションを利用している場合、ここでの記述内容は、古いコレクションに該当します。 マーク アンド スイープ モデルという、ガベージコレクションアルゴリズムについての説明です。

  • マーク アンド スイープ モデル
    • JRockit JVMガベージコレクションモデル
    • マークフェーズとスイープフェーズからなる
    • マークフェーズの動作
      • 現在使用されているオブジェクトを識別し、マークを付ける
      • 以下のようなオブジェクトが生存状態としてマークされる
        • Java スレッド、ネイティブ ハンドルおよびその他のルートソースから到達可能なオブジェクト
        • 上記のオブジェクトから到達可能なオブジェクト
    • スイープフェーズの動作
      • オブジェクトの木構造をたどることにより、生存状態としてマークされなかったオブジェクトを見つける。そのオブジェクトが配置されていた領域はフリーリストに記録され、新しいオブジェクトの割り当てに利用される。 *3
    • マークフェーズとスイープフェーズの組み合わせ方により、いくつかの方式がある

モースト コンカレント マーク アンド スイープ における処理の詳細

モースト コンカレント マーク アンド スイープ では、マーク処理とスイープ処理において、それぞれ4つのフェーズが順に実行されます。

モーストリ コンカレント マークの4つのフェーズ

名前 動作 Java スレッドの停止
初期マーキング 生存しているオブジェクトのルートセットを識別する あり
コンカレント マーキング ルートセットからの参照にしたがって、生存している残りのオブジェクトを検索してマークする なし
プレクリーニング コンカレント マーキング中のヒープの変更を識別し、生存しているオブジェクトを検索してマークする なし
最終マーキング プレクリーニング中のヒープの変更を識別し、生存しているオブジェクトを検索してマークする あり

モーストリ コンカレント スイープ の4つのフェーズ

名前 動作 Java スレッドの停止
スイープ(1回目) ヒープの半分をスイープする。この間、オブジェクトは残り半分のヒープ領域に割り当てられる なし
休止(1回目) 残り半分に切り替えるための休止 N/A
スイープ(2回目) 残り半分のヒープをスイープする。この間、オブジェクトは残り半分のヒープ領域に割り当てられる なし
休止(2回目) 同期、および統計の記録のための休止 N/A

世代別ガベージコレクション(若いコレクション)

二世代のガベージコレクションを利用している場合、ヒープメモリ上にナーサリが存在します。ナーサリの保持領域外のオブジェクトを古い領域に昇格するのが、若いコレクションです。
若いコレクションの間、Java スレッドは停止します。

*1:二世代のガベージコレクションが利用されない場合は、すべてのヒープが古い領域なのと同じことだと思われる

*2:Oracleの公式ドキュメントには、「大規模なオブジェクトの割り当てには Java スレッド間の同期をより頻繁に行う必要があります。」とありますが、たぶんこういうことでしょう。

*3:Oracleの公式ドキュメントには、「生存しているオブジェクト間のギャップを見つけるために、ヒープがトラバースされます。」とありますが、たぶんこういうことでしょう。

*4:コンカレント マーク アンド スイープとの違いは、マーク中のヒープの変更を識別して、選択的にマークし直す機構があることです。