かばちんのエンジニアブログ

日々の経験の中で培った内容を備忘録も兼ねて記録していくブログです。少しでも誰かの役に立つために頑張って続けていけたらなと思います。

DockerのUbuntuコンテナにScala開発環境を構築

この記事を書くに至った動機

エンジニアにはあるあるですが環境構築途中で失敗して、一度削除してまたいちから作成する時に調べ直さなくてもいいように手順を記録していきたいと思います。
(もうすでに1回やり直してます。。)

環境構築の手順

・ベースとなる Ubuntu コンテナの作成
・Redisサーバのインストール
MySQLサーバのインストール
JDK 8 のインストール
・Play Framework (Activator) のインストール
・新規プロジェクトの作成
・アプリケーションの起動
・ブラウザからアクセスして確認
・コンテナの保存
・ポートフォワード設定をして実行
・再度ブラウザからアクセスして確認


かなり長い道のりで、おそらくすんなりいかずに1日がかりの作業になると思いますが
頑張ってベースとなる開発環境構築の手順をお伝えできたらと思います。


Ubuntu コンテナの作成

まずは空の Ubuntu コンテナを作成します。
タグは「Trusty」を使います。

$ docker run -it --name develop ubuntu:trusty /bin/bash


すぐに exit してコンテナが正しく作成されたかを確認してみます。

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
0309d0f2f1bd        ubuntu:trusty       "/bin/bash"         5 minutes ago       Up 5 minutes                            develop


正常にコンテナが作成されていることを確認したら再度コンテナに入ります。

$ docker exec -it develop /bin/bash

Redisサーバのインストール

とりあえずホームディレクトリに移動したのち、「redis-server」をインストールしたいと思います。

$ cd ~
$ apt-get update
$ apt-get install -y redis-server


少し待つとインストールが完了します。
早速Redisサーバを起動しておきしょう。
正しく起動したかどうかの確認も忘れずに。

$ service redis-server start
Starting redis-server: redis-server.

$ps -ef | grep redis
redis      209     1  0 05:45 ?        00:00:00 /usr/bin/redis-server 127.0.0.1:6379       
root       213    46  0 05:45 ?        00:00:00 grep --color=auto redis

MySQLサーバのインストール

次はMySQLのインストールです。
インストール時に root ユーザのパスワード入力を求められるので入力します。

$ apt-get install -y mysql-server

少し待つとインストールが完了します。
こちらも忘れずにMySQLサーバを起動しておきましょう。

$ service mysql start
 * Starting MySQL database server mysqld                              [ OK ]
 * Checking for tables which need an upgrade, are corrupt or were 
not closed cleanly.

$ps -ef | grep redis
root       754     1  0 05:48 ?        00:00:00 /bin/sh /usr/bin/mysqld_safe
mysql     1101   754  0 05:48 ?        00:00:00 /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib/mysql/plugin --user=mysql --log-error=/var/log/mysql/error.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/run/mysqld/mysqld.sock --port=3306
root      1265    46  0 05:49 ?        00:00:00 grep --color=auto mysql

JDK 8 のインストール

次はJavaをインストールします。
Play Framework を利用するにはJDK8以上が必要なようです。

Ubuntu 14.04 では公式リポジトリに JDK8 が用意されていないとのこと。
サードパーティ製のリポジトリを追加してインストール必要があります。
そこで登場するのが「add-apt-repository」ですが、空のUbuntuにはこれすらもありません。
まずは使えるように設定をします。

$ apt-get install -y apt-file
$ apt-file update
$ apt-file search add-apt-repository


検索して見つかったリポジトリをインストールします。

$ apt-get install software-properties-common


ここまでやるとやっと「add-apt-repository」が使えるようになります。
アップデートを忘れずに実行し、続けて JDK8 をインストールします。

$ apt-add-repository ppa:openjdk-r/ppa
$ apt-get update
$ apt-get install -y openjdk-8-jdk


しばらく待つとインストールが完了するので、バージョンを確認してみます。

$ java -version
openjdk version "1.8.0_72-internal"
OpenJDK Runtime Environment (build 1.8.0_72-internal-b15)
OpenJDK 64-Bit Server VM (build 25.72-b15, mixed mode)

$javac -version
javac 1.8.0_72-internal

Play Framework (Activator) のインストール

最後に Scala の Framework である、Play Framework をインストールします。
まずは下記のサイトで配布されている Activator という zip ファイルを wget で取得します。
2016年2月25日時点での最新版は Play 2.4.6 / Activator 1.3.7 のようです。
https://www.playframework.com/download


wget が使えない場合は、wget を先にインストールします。

$ apt-get install -y wget


適当なフォルダ(今回はActivator)を作成し、先ほどの zip ファイルをダウンロードします。

$ mkdir Activator
$ cd Activator
$ wget https://downloads.typesafe.com/typesafe-activator/1.3.7/typesafe-activator-1.3.7-minimal.zip


ダウンロードが完了したら zip ファイルを解凍します。
解凍するには unzip コマンドを使いますが、例に漏れずこれもインストールが必要です。

$ apt-get install -y unzip


unzip のインストールができたら早速ダウンロードした zip ファイルを解凍します。

$ unzip typesafe-activator-1.3.7-minimal.zip


一瞬で解凍が終わりますが、解凍した後はフォルダが1つ作成されていると思います。

$ ls -al
drwxr-xr-x 3 root root    4096 Feb 25 06:18 ./
drwx------ 3 root root    4096 Feb 25 06:13 ../
drwxr-xr-x 2 root root    4096 Dec  2 20:27 activator-1.3.7-minimal/
-rw-r--r-- 1 root root 1056830 Dec  3 01:28 typesafe-activator-1.3.7-minimal.zip


中に入って内容を確認してみます。

$ cd activator-1.3.7-minimal
$ ls -al
drwxr-xr-x 2 root root    4096 Dec  2 20:27 .
drwxr-xr-x 3 root root    4096 Feb 25 06:18 ..
-rwxr--r-- 1 root root    9507 Dec  2 20:27 activator
-rw-r--r-- 1 root root 1213545 Dec  2 20:27 activator-launch-1.3.7.jar
-rwxr--r-- 1 root root    7342 Dec  2 20:27 activator.bat


この activator というファイルは今後よく使うことになるためパスを通しておきます。

$ pwd
/root/Activator/activator-1.3.7-minimal

$ env | grep PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

$ export PATH=$PATH:/root/Activator/activator-1.3.7-minimal
$ env | grep PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/Activator/activator-1.3.7-minimal

こんな感じになったかと思います。
これでいつでもどこでも activator コマンドが利用できます。

新規プロジェクトの作成

新しくプロジェクトを作成するのはコマンドひとつで行えます。
まずはプロジェクト用のフォルダを作成して、その中で「activator new」コマンドを実行します。
※初回実行時のみいろいろインストールされるので非常に時間がかかります。コーヒーでも飲みながら気長に待ちましょう。

$ mkdir sampleapp
$ cd sampleapp
$ activator new <appname(省略可)> <apptype(省略可)>
# ひとまずは「activator new」のみで実行してみてください


事前ダウンロードなどが終わると以下のような画面が出てくると思います。

Browse the list of templates: http://typesafe.com/activator/templates
Choose from these featured templates or enter a template name:
  1) minimal-akka-java-seed
  2) minimal-akka-scala-seed
  3) minimal-java
  4) minimal-scala
  5) play-java
  6) play-scala
(hit tab to see a list of all templates)


今回は Scala を利用するので「play-scala」と入力してリターンキーを押します。
するとさらに今度はアプリケーションの名前の入力を求められます。
好きな名前を入力しましょう。未入力時は「play-scala」が設定されるようです。

> play-scala
Enter a name for your application (just press enter for 'play-scala')

> sampleapp
OK, application "sampleapp" is being created using the "play-scala" template.

To run "sampleapp" from the command line, "cd sampleapp" then:
/root/Activator/sampleapp/sampleapp/activator run

To run the test for "sampleapp" from the command line, "cd sampleapp" then:
/root/Activator/sampleapp/sampleapp/activator test

To run the Activator UI for "sampleapp" from the command line, "cd sampleapp" then:
/root/Activator/sampleapp/sampleapp/activator ui


こんなメッセージが表示されたらプロジェクトファイル群がすでに作成されています。
アプリケーション名で新たにフォルダが作成されているので、構成を見てみましょう。

$ cd sampleapp
$ ls -al
-rw-r--r-- 1 root root     591 Feb 25 06:34 LICENSE
-rw-r--r-- 1 root root     148 Feb 25 06:34 README
-rwxr--r-- 1 root root    9507 Feb 25 06:34 activator
-rw-r--r-- 1 root root 1213545 Feb 25 06:34 activator-launch-1.3.7.jar
-rwxr--r-- 1 root root    7342 Feb 25 06:34 activator.bat
drwxr-xr-x 4 root root    4096 Feb 25 06:34 app
-rw-r--r-- 1 root root     472 Feb 25 06:34 build.sbt
drwxr-xr-x 2 root root    4096 Feb 25 06:34 conf
drwxr-xr-x 2 root root    4096 Feb 25 06:34 project
drwxr-xr-x 5 root root    4096 Feb 25 06:34 public
drwxr-xr-x 2 root root    4096 Feb 25 06:34 test

これがデフォルト状態(空状態)のプロジェクトファイル構成になります。
ここら辺については Play Framework のチュートリアルやドキュメントで詳しく書かれていますのでそちらを参照してみてください。


アプリケーションの起動

作成した空のアプリケーションを実行してみたいと思います。
実行時にも「activator run」コマンドを利用します。
アプリケーション作成時同様、初回のみいろいろダウンロードしたりチェックが行われたりして非常に時間がかかりますので大人しく待ちましょう。

$ activator run
・
・
・
--- (Running the application, auto-reloading is enabled) ---

[info] p.c.s.NettyServer - Listening for HTTP on /0:0:0:0:0:0:0:0:9000

(Server started, use Ctrl+D to stop and go back to the console...)

こんな表示が出たら見事アプリケーションの起動に成功です!!
おめでとうございます!!


ブラウザからアクセスして確認

アプリケーションが起動したら、実際に見てみたいですよね?
というわけで、早速ブラウザからアクセスしてページを表示してみましょう!

VM環境のIPアドレスとポート番号9000を入力してリターン!

f:id:kabatin:20160225162336p:plain


残念つながりませんでした・・・。
でもこれ、当然繋がらなくて当たり前ですよね。

最初にコンテナを起動するときにポートフォワード設定をせずに起動していますから。
コンテナの9000番ポートに対してアクセスするには一度コンテナから抜けて、コンテナ起動時に9000番ポートに対してポートフォワード設定を指定する必要があります。


が、ここで問題が・・・。

ポートフォワード指定は「docker run」コマンド実行時しかできないため、一度コンテナを削除する必要があります。
ここまで数時間かけて作ってきたコンテナを破棄するなんて…。

ということでコンテナを削除する前にここまで設定したコンテナを保存したいと思います。


コンテナの保存

一度コンテナから抜けるために exit して、以下のコマンドを実行します。

$ docker commit -m "ここにコメントが書けます" <Image Id> <Image Name>

$ docker images
REPOSITORY                  TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
develop                     latest              8c7f1c246564        26 seconds ago      1.192 GB

無事にイメージとして保存することができました。


ポートフォワード設定をして実行

develop コンテナを本当に削除して作り直してもいいんですが、ビビリな僕は残したまま別コンテナとして立ち上げることにします。
コンテナ名を「develop9000」、イメージはさっき自分で作成した「develop」イメージを利用します。

$ docker run -it -p 9000:9000 --name develop9000 develop /bin/bash

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS                     PORTS               NAMES
9ca7253918d2        develop:latest      "/bin/bash"         About a minute ago   Exited (0) 3 seconds ago                       develop9000         
0309d0f2f1bd        ubuntu:trusty       "/bin/bash"         4 hours ago          Exited (0) 2 hours ago                         develop             

無事に起動されました。
それでは、前の手順に合わせて sampleapp を実行してブラウザで確認してみたいと思います。
まずは作成したコンテナへ入ります。

$ docker start develop9000
$ docker exec -it develop9000 /bin/bash

プロジェクトがあるフォルダへ移動して「activator run」コマンドを実行します。
コンテナを一度抜けるとパス設定が元に戻っていたようなので再度設定しておきます。

$ export PATH=$PATH:/root/Activator/activator-1.3.7-minimal
$ cd /root/Activator/sampleapp/sampleapp
$ activator run
[info] Loading project definition from /root/Activator/sampleapp/sampleapp/project
[info] Set current project to sampleapp (in build file:/root/Activator/sampleapp/sampleapp/)

--- (Running the application, auto-reloading is enabled) ---

[info] p.c.s.NettyServer - Listening for HTTP on /0:0:0:0:0:0:0:0:9000

(Server started, use Ctrl+D to stop and go back to the console...)

今回は2回目の実行なので初回に比べたらはるかに早く起動しました。


再度ブラウザからアクセスして確認

それではブラウザから再度アクセスしてみましょう…。
f:id:kabatin:20160225192004p:plain

やったーーー!!
やっとページが表示されました!!!

ようやくベースとなる開発環境が出来上がったかな…?
これから Redis や MySQL とかの設定したり、Scala で RestfulAPI の作り方を調べたりとやること満載ですが、ひとまずの導入としてはここまでにしておきたいと思います!


長くなってしまいましたが、少しでもみなさまのお役に立てることを願って…