Dockerことはじめ 2

前の投稿の続き。
Linking containers togetherに従い、PlayframeworkアプリとDBを別のコンテナイメージで作成。
link を使用してコンテナ間で、セキュアな情報のやり取りに挑戦。
前回と同じく、Dockerfileからimageを作成。前回と違うのは、アプリとDBを別コンテナにするので、それぞれDockerfileを作成。
DB用Dockerfile

# This is a comment
FROM ubuntu:14.10
MAINTAINER Yuichiro Uyama <yuichiro.uyama@gmail.com>
# mysql install
RUN apt-get -y install mysql-server
RUN /usr/bin/mysqld_safe & \
        sleep 10s && \
        mysqladmin -u root password genesis
RUN echo "CREATE DATABASE play_db character set utf8" > /tmp/createDataBase.sql
RUN /usr/bin/mysqld_safe & \
        sleep 10s && \
        mysql -u root -p --password='genesis' < /tmp/createDataBase.sql
# 権限の追加
RUN echo 'GRANT ALL PRIVILEGES ON play_db.* to root@"%" identified by "genesis";' > /tmp/createUser.sql
RUN echo "FLUSH PRIVILEGES;" >> /tmp/createUser.sql
RUN /usr/bin/mysqld_safe & \
        sleep 10s && \
        mysql -u root -p --password='genesis' < /tmp/createUser.sql
# 外部からmysqlサーバにアクセスできるように
RUN sed -i -e"s/^bind-address\s*=\s*127.0.0.1/bind-address = 0.0.0.0/" /etc/mysql/my.cnf
# ポート番号 3306 を外部に公開
#EXPOSE 3306
ADD playdb.sql /tmp/playdb.sql
RUN /usr/bin/mysqld_safe & \
        sleep 20s && \
        mysql -u root -p play_db --password='genesis' <  /tmp/playdb.sql
CMD ["/usr/bin/mysqld_safe"]

アプリ用Dockerfile

# This is a comment
FROM ubuntu:14.10
MAINTAINER Yuichiro Uyama <yuichiro.uyama@gmail.com>
# java install
RUN apt-get update
RUN apt-get install software-properties-common -y
RUN add-apt-repository ppa:webupd8team/java -y
RUN apt-get update
RUN echo debconf shared/accepted-oracle-license-v1-1 select true | debconf-set-selections
RUN apt-get install oracle-jdk7-installer -y
# scala install
RUN cd /usr/local/src/
RUN wget http://downloads.typesafe.com/scala/2.11.0/scala-2.11.0.tgz
RUN tar zxvf scala-2.11.0.tgz
RUN mv scala-2.11.0 /usr/local/
RUN ln -s /usr/local/scala-2.11.0 /usr/local/scala
ENV PATH=$PATH:/usr/local/scala/bin
# git install
RUN add-apt-repository ppa:git-core/ppa
RUN apt-get update
RUN apt-get -y install git
# playframework! install
RUN cd /usr/local/src/
RUN wget http://downloads.typesafe.com/play/2.1.1/play-2.1.1.zip
RUN apt-get -y install unzip 
RUN unzip play-2.1.1.zip
RUN mv play-2.1.1 /usr/local
ENV PATH=$PATH:/usr/local/play-2.1.1
# PartList install
RUN cd /usr/local
RUN git clone git://git.sourceforge.jp/gitroot/open-pdm-light/PartList.git
RUN mv /PartList /usr/local
RUN echo "#!/bin/bash" > ./run.sh
Run echo "cd /usr/local/PartList/PartsList/PartsList" >> ./run.sh
Run echo "play start" >> ./run.sh
RUN chmod 777 ./run.sh
ADD AuthAction.scala /usr/local/PartList/PartsList/PartsList/app/mvc/AuthAction.scala
ADD application.conf /usr/local/PartList/PartsList/PartsList/conf/application.conf
CMD ["./run.sh"]

それぞれ、buildコマンドにてイメージを作成。

# sudo docker build -t yuichiro/db:v1 .
# sudo docker build -t yuichiro/partslist_exdb:devel .

イメージが作成できたら、起動。
まず、DBを以下のコマンドにて起動。

# sudo docker run -d --name db yuichiro/db:v1

引き続き、アプリを起動

# sudo docker run -d --name web -p 5000:9000 --link db:db yuichiro/partslist_exdb:devel

アプリ側のデータソースの指定は、ホスト名にdbを指定。

しばらくしてから、localhostの5000ポートにアクセス。すばらしい!

以上のdocker imageはDB/アプリ。docker pull後、上記の起動コマンドで動くはず。

Docker ことはじめ

またも更新まで、間が開いてしまった。反省。
春さきより、気になっていたDockerをはじめる。

日本語の良い記事が見つからず、辞書を片手に、docker user guide
最初に躓いたのが、ubuntuを使って試用したのだが、64bitしか対応していないため、
64bit版のubuntu15.04をインストール。
一通りガイドに沿って手を動かし、python.appをコンテナで動かしてみるが、身につかない。
一昨年から続けているPlayFrameworkを利用したproductsをDockerコンテナ上で動かしてみることに挑戦。
構成は、ひとつのコンテナ上で、playアプリとmysqlを構成してみる。dockerfileは以下

# This is a comment
FROM ubuntu:14.10
MAINTAINER Yuichiro Uyama <yuichiro.uyama@gmail.com>
# java install
RUN apt-get update
RUN apt-get install software-properties-common -y
RUN add-apt-repository ppa:webupd8team/java -y
RUN apt-get update
RUN echo debconf shared/accepted-oracle-license-v1-1 select true | debconf-set-selections
RUN apt-get install oracle-jdk7-installer -y
# scala install
RUN cd /usr/local/src/
RUN wget http://downloads.typesafe.com/scala/2.11.0/scala-2.11.0.tgz
RUN tar zxvf scala-2.11.0.tgz
RUN mv scala-2.11.0 /usr/local/
RUN ln -s /usr/local/scala-2.11.0 /usr/local/scala
ENV PATH=$PATH:/usr/local/scala/bin
# git install
RUN add-apt-repository ppa:git-core/ppa
RUN apt-get update
RUN apt-get -y install git
# playframework! install
RUN cd /usr/local/src/
RUN wget http://downloads.typesafe.com/play/2.1.1/play-2.1.1.zip
RUN apt-get -y install unzip 
RUN unzip play-2.1.1.zip
RUN mv play-2.1.1 /usr/local
ENV PATH=$PATH:/usr/local/play-2.1.1
# mysql install
RUN apt-get -y install mysql-server
RUN /usr/bin/mysqld_safe & \
        sleep 10s && \
	mysqladmin -u root password password
RUN echo "CREATE DATABASE play_db character set utf8" > /tmp/createDataBase.sql
RUN /usr/bin/mysqld_safe & \
	sleep 10s && \
	mysql -u root -p --password='password' < /tmp/createDataBase.sql
# 外部からmysqlサーバにアクセスできるように
RUN sed -i -e"s/^bind-address\s*=\s*127.0.0.1/bind-address = 0.0.0.0/" /etc/mysql/my.cnf
# PartList install
RUN cd /usr/local
RUN git clone git://git.sourceforge.jp/gitroot/open-pdm-light/PartList.git
RUN mv /PartList /usr/local
RUN echo "#!/bin/bash" > ./run.sh
RUN echo "/etc/init.d/mysql start" >> ./run.sh
Run echo "cd /usr/local/PartList/PartsList/PartsList" >> ./run.sh
Run echo "play start" >> ./run.sh
RUN chmod 777 ./run.sh
ADD AuthAction.scala /usr/local/PartList/PartsList/PartsList/app/mvc/AuthAction.scala
ADD playdb.sql /usr/local/PartList/PartsList/PartsList/conf/evolutions/default/playdb.sql
RUN /usr/bin/mysqld_safe & \
	sleep 20s && \
	mysql -u root -p play_db --password='password' <  /usr/local/PartList/PartsList/PartsList/conf/evolutions/default/playdb.sql
CMD ["./run.sh"]

躓いたのは、
mysqlのインストール後の各種設定(パスワード設定やテーブルの作成)。
mysqlのスタートとcreateコマンドを別のRUNにまたぐとうまく行かない。
詳しくはこちら(いつもお世話になっております)
上のDockerfileを使って、イメージを作成。

# sudo docker build -t yuichiro/partslist:devel .

コマンドの末尾の.(コロン)が重要。「カレントのDockerfileを使用」との意味。
以下のコマンドにて起動。

# sudo docker run -d -p 5000:9000 yuichiro/partslist:devel

sbtやplayのコンパイルが終わるまで(私の環境では20分ほど)待って、
localhostの5000ポートにアクセス。起動完了!

以上のdocker imageはこちら。docker pull後、上記の起動コマンドで動くはず。

Akka-Actor サンプリング

Java8がリリースされたのを期に、こちらを参考にしながらJVMの並行性について学習。
引き続き、並列、平行、分散処理を簡単に記述するためのScalaのライブラリ:Akkaに
ついて学習。
とてもわかりやすいサンプルで学習を始めるも、仕様変更のためコンパイルエラー。
こちらのページAkka公式ページを参考にしてサンプリング。

[Actorクラス]

import akka.actor.Actor

class MyActor extends Actor{
  def receive = {
    case i: Int =>println("Int=" +i)
    case msg => {
      println(msg + " by MyAkkaActor")
      sender() ! ("Hello, " + msg.toString)
    }
  }
}

[Mainクラス]

import akka.actor.ActorSystem
import akka.actor.Props
import actor.MyActor
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._
import scala.concurrent.Await
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import java.util.Date

object Main {
  def main(args: Array[String]) {
    println("main start:" + new Date())
    val system = ActorSystem("sample")
    val myAkkaActor = system.actorOf(Props[MyActor])
    // 非同期実行
    val result = myAkkaActor ! 100
    println("result = " + result)
    // 
    implicit val timeout = Timeout(5 seconds)
    // 同期実行
    val future = myAkkaActor ? "uyaji"
    val result2 = Await.result(future, timeout.duration).asInstanceOf[String]
    println("result = " + result2)
    // 非同期の結果待ち(Futureを返す)
    val resultFuture = myAkkaActor ? "uyama"
    resultFuture.onSuccess {
      case result => println("result = " + result)
    }
    println("main end:" + new Date())
    Thread.sleep(500)
    system.shutdown
  }
}

[実行結果]

main start:Thu Oct 30 18:25:09 JST 2014
result = ()
Int=100
uyaji by MyAkkaActor
result = Hello, uyaji
uyama by MyAkkaActor
main end:Thu Oct 30 18:25:14 JST 2014
result = Hello, uyama

非同期実行は、結果を出力できず。
同期実行は、結果出力。
非同期の結果待ちは、main end:メッセージ出力後に結果出力

なるほど!

playframework scalaのリフレクション

先のブログのプロジェクトの機能追加として、CSVファイルから、部品表(PartsStructureテーブル)を登録する機能について検討。
CVSファイルを、play.api.mvc.MultipartFormData.FilePartで取り込む。
取り込んだファイルをjava.io.FileInputStream,scala.io.Source.fromInputStreamでscala.io.BufferedSourceに取り込み、getLineメソッドでIteratorへ。

    val file = atach.ref.file
    val fis = new FileInputStream(file)
    val src = Source.fromInputStream(fis)
    val itr = src.getLines

Iterator[String]の各行と変換後のBean名をパラメータで受け取り、Any型を戻り値とする変換クラス(CastBean.scala)を製作。
大雑把な仕様は、
第2パラメータで受けたbeanクラス名(String)から、beanの属性を取得。
第1パラメータで受けたStringをカンマで区切り、順に取得した属性にセットする。
参考にしたページ
scala.reflect.runtime.{universe= ru}のruntimeMirrorを生成。
beanクラス名から、classSymbolを生成。
Class.forName(clsName).newInstance()にてインスタンス取得後、
runtimeMirror.reflectメソッドで、インスタンスミラー取得。
classSymbolのdeclarationメソッドを利用して各fieldSymbolを取得。
その際、field名が必要になる。
field名の取得は、Class.forName(clsName).getDeclaredFields()にて、フィールド名のコレクション
を取得し、各フィールドに対しruntimeMirror.newTermNameメソッドでフィールドシンボルを取得。
インスタンスミラーのreflectFieldメソッドにてフィールドミラー取得。
あとは、setterメソッドでCSVで切り分けた値をセット。

def stringToBean(it: String , clsName: String):Any = {
  import scala.reflect.runtime.{universe => ru}
  val runtimeMirror=ru.runtimeMirror(Thread.currentThread.getContextClassLoader)
  val beanClassSymbol = runtimeMirror.staticClass(clsName).toType
  val bcm = Class.forName(clsName).newInstance()
  val bim = runtimeMirror.reflect(bcm)
  var i:Int=0
  if(it!="") {
    for(f<-Class.forName(clsName).getDeclaredFields()){
       val fieldSymbol= beanClassSymbol.declaration(ru.newTermName(f.getName())).asTerm
       val fm =bim.reflectField(fieldSymbol)
       fm.set(
         f.getType().getName() match {
            case "long" => it.split(",").apply(i) match{
               case "" => 0
               case _ => it.split(",").apply(i).toInt
            }
            case _ => it.split(",").apply(i) match{
              case "" => " "
              case _ => it.split(",").apply(i)
            }
         }
       )
       i += 1
    }
  }
  bcm
}

呼び出し元では、Any型を、asInstanceメソッドで、テーブルの型へ変換する。
クラスネーム(String)をパラメータで受けることにより、PSテーブルとの依存度を下げれた。
他のテーブルへの出力にも利用可能。

PlayframeworkでPDM

1年数カ月ぶりのブログ更新です。
一年以上何もしていなかった訳ではないのです。

昨年は、PlayFramework1.2(java)を集中的に学んでいました。
PlayFramework2も、検討していたのですが
ドキュメントの豊富さの優位性より1系を選びました。

年が明けて、時間が取れるようになってきたので
Play2系(Scala)を改めて学び始めました。
まだ、Scalaが充分に理解できてはいないのですが、
4月頃より、こつこつと制作してきたサンプルが形になってきたので
SourceForgeソースコードをアップし
デモの公開サイトを立ち上げました。
ライトウェイトなPDM(Product Data Management System)です。
まだ、BOMの作成と通知機能しか実装できていません。
(ただし、デモサイトのメイル通知機能は潰しています。踏み台にされる不安が拭えないので)
ソースコードの方は実装しています。
機能説明は、wikiに書く予定です。
今後、設計変更機能、材料費の積算機能を実装していければと思っています。


PluginでPlay!

Play!学習中。

Play!(2.01)自体はフルスタックということで単体でも十分に利用可能。
しかしSpringを併用したり、TomcatへのDeployを行おうと思うと
Pluginの利用が必要。
Pluginの利用にはsbtが必要。Mavinの様に、依存性をnetにアクセスし解決。
ただ、社内ネットワークでの環境の場合、proxyやフィルタリングが邪魔をする。
playコマンドや、runコマンド発行の際に、依存性が見つからないエラー発生。

環境を調査し、jarの置き場らしきものを確認したので覚書。
[jarの保存場所]

[Playインストルフォルダ]\repository\cache\配下に展開される模様。
WAR Pluginの場合、以下のパス。
D:\play-2.0.1\repository\cache\com.github.play2war\play2-war-core_2.9.1\jars\play2-war-core_2.9.1-0.4.jar