LoginSignup
0
0

More than 1 year has passed since last update.

Play Frameworkで作成したアプリケーションをIBM Cloud Code Engineにデプロイしてみる

Posted at

はじめに

前回の記事でIBM Cloud Code Engineにサンプルアプリケーションをデプロイしましたが、今回は自作のアプリケーションをデプロイしてみようと思います。アプリケーションはコンテナになっていればどんな言語やフレームワークを使ってもいいはずなので、今回は(あまりネット上にも情報がなさそうだった)Play Frameworkを使ったアプリケーションをデプロイしてみようと思います。

Play Frameworkとは

Play Frameworkとは、公式サイトによると

The High Velocity Web Framework For Java and Scala

とのことです。日本語だと JavaとScalaを使った高速ウェブアプリケーションフレームワーク といったところでしょうか。私はJavaの経験が長いので今回はこちらのフレームワークを選んでみます。

Dockerを使った開発

Play Frameworkを動かすにはJavaはもちろんsbtが動く環境が必要です。ですが、Javaもsbtもローカル環境にインストールするとバージョンやら何やらの依存関係で案外管理が難しくなりそうです。なので今回はDockerを使ってなるべく実行環境をコンテナ内に閉じ込めて開発するスタイルを探っていきます。

開発環境

まず開発環境の方は、Javaとsbtが既に入っているscala-sbtを使わせてもらうことにします。以下のような docker-compose.yml を用意して簡単に起動できるようにしておきます。

docker-compose.yml
version: "3.9"
services:
  sbt:
    image: hseeberger/scala-sbt:11.0.13_1.5.8_2.13.7
    ports:
      - 9000:9000
    volumes:
      - ./root:/root

これを使ってコンテナを起動します。

$ mkdir root
$ docker-compose up -d
[+] Running 1/1
 ⠿ Container play_test_sbt_1  Started
$ docker exec -it play_test_sbt_1 bash
root@8a50fee5f6b7:~# pwd
/root

こうなっているので、このディレクトリに作られたファイルはローカルの ./root に保持されます。

アプリケーションの作成

では早速この環境を使ってアプリケーションを作成してみます。ドキュメントにある通りにコマンドを実行します。

root@8a50fee5f6b7:~# sbt new playframework/play-scala-seed.g8 --name=fterui-play-test
[info] welcome to sbt 1.5.8 (Oracle Corporation Java 11.0.13)
[info] set current project to new (in build file:/tmp/sbt_56c7b9f2/new/)

結構時間がかかるのでしばらく待ちます。アプリケーションが作成されると以下のようになります。

root@8a50fee5f6b7:~# cd fterui-play-test/
root@8a50fee5f6b7:~/fterui-play-test# ls
app  build.sbt	conf  project  public  test

早速実行してみます。

root@8a50fee5f6b7:~/fterui-play-test# sbt run
[info] [launcher] getting org.scala-sbt sbt 1.5.2  (this may take some time)...

多くのライブラリをダウンロードした後アプリケーションが起動します。

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

[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0.0.0.0:9000

(Server started, use Enter to stop and go back to the console...)

このように表示されれば成功です。このコンテナの9000番ポートはローカルにマップされていますので、ブラウザにlocalhost:9000と入力すればアプリケーションにアクセスできます。

スクリーンショット 2021-12-23 17.29.34.png

アプリケーションの開発

上記のコンテナの/root./rootがマウントされているので、ローカルのファイルシステムにあるファイルを編集すれば自動的に実行環境に反映されます。つまりローカルのPCにインストールされている好みのエディタやIDEを使って開発を行うことができます。ここでは例としてこのトップページにHello World!の文字列を表示する変更を加えたいと思います。 app/views/index.scala.htmlを開くと以下のようになっていると思います。

app/views/index.scala.html
@()

@main("Welcome to Play") {
  <h1>Welcome to Play!</h1>
}

これを以下のように変更します。

app/views/index.scala.html
@()

@main("Welcome to Play") {
  <h1>Welcome to Play!</h1>
  Hello World!
}

これを保存してブラウザをリロードすると、ちゃんと変更が反映されていることがわかります。
スクリーンショット 2021-12-23 17.36.11.png

アプリケーションのコンソールの方でもリロードされたことが確認できます。

2021-12-23 08:26:54 INFO  play.api.Play  Application started (Dev) (no global state)
[info] compiling 1 Scala source to /root/fterui-play-test/target/scala-2.13/classes ...

--- (RELOAD) ---

2021-12-23 08:35:17 INFO  play.api.http.EnabledFilters  Enabled Filters (see <https://www.playframework.com/documentation/latest/Filters>):

    play.filters.csrf.CSRFFilter
    play.filters.headers.SecurityHeadersFilter
    play.filters.hosts.AllowedHostsFilter
2021-12-23 08:35:17 INFO  play.api.Play  Application started (Dev) (no global state)

アプリケーションのビルド

この状態のアプリケーションはあくまでも開発用なので、実際にデプロイする前にはプロダクション用にビルドする必要があります。ビルドはこれもsbtコマンドから簡単に行うことができます。

root@8a50fee5f6b7:~/fterui-play-test# sbt dist
[info] welcome to sbt 1.5.2 (Oracle Corporation Java 11.0.13)
[info] loading settings for project fterui-play-test-build from plugins.sbt ...
[info] loading project definition from /root/fterui-play-test/project
[info] loading settings for project root from build.sbt ...
...(snip)...
[success] All package validations passed
[info] Your package is ready in /root/fterui-play-test/target/universal/fterui-play-test-1.0-SNAPSHOT.zip
[success] Total time: 21 s, completed Dec 23, 2021, 8:40:10 AM

このように表示されたら完了です。 target/universal以下にできたzipファイルが成果物となります。試しにこちらを起動してみます。

Play Frameworkは起動するときにapplication secretを要求します。詳しくはドキュメントにありますので参照してください。例えば以下のようなコマンドで作成することができます。

# head -c 32 /dev/urandom | base64
HORVsaoVwdmKFsw8Pxl2vvWhCwmOCEuMCUjf/IFawzs=

sbt distで作成されたzipファイルを展開したディレクトリで、以下のコマンドでアプリケーションを実行できます。実行ファイル名はプロジェクト名です。

# ./bin/fterui-play-test -Dplay.http.secret.key=HORVsaoVwdmKFsw8Pxl2vvWhCwmOCEuMCUjf/IFawzs=
...(snip)...
2021-12-23 08:51:08 INFO  play.api.Play  Application started (Prod) (no global state)
2021-12-23 08:51:09 INFO  play.core.server.AkkaHttpServer  Listening for HTTP on /0.0.0.0:9000

開発中同様9000番ポートにアクセスすればアプリケーションの動作が確認できます。

デプロイするイメージの作成

上で作成したzipファイルを使ってデプロイするイメージを作成します。実行にはjavaが必要ですがsbtは不要なので、もっとサイズの小さいイメージを利用できます。ここではopenjdkの11-jre-slimを使います。以下のようなDockerfileを作成し、zipファイルを展開したディレクトリに置きます。

Dockerfile
FROM openjdk:11-jre-slim
COPY . /root/

CMD ["/root/bin/fterui-play-test", "-Dplay.http.secret.key=HORVsaoVwdmKFsw8Pxl2vvWhCwmOCEuMCUjf/IFawzs="]

実際の運用ではsecret keyは外から与えることになると思いますが、ここではそのままイメージ内で指定します。

イメージを作成して動作確認を行います。

$ docker build . -t fterui_play_test

...(snip)...

$ docker run --rm -p 9001:9000 fterui_play_test

...(snip)...

2021-12-23 09:07:21 INFO  play.api.Play  Application started (Prod) (no global state)
2021-12-23 09:07:21 INFO  play.core.server.AkkaHttpServer  Listening for HTTP on /0.0.0.0:9000

開発用のコンテナが9000番ポートを使っているので、こちらは9001番にマップしました。ブラウザからlocalhost:9001にアクセスするとプロダクション用のアプリケーションにアクセスできます。

スクリーンショット 2021-12-23 18.16.28.png

問題なく動作していることが確認できました。

IBM Cloud Container Registryへpush

作成したイメージをIBM Cloud Code Engineで実行するためには、Code Engine側からpullできる場所へイメージをpushしておく必要があります。

まずibmcloud crコマンドが使えるようになっている必要があります。ドキュメントによるとIBM Cloud CLIをインストールすると使えるようになっているはずですが、私のところではプラグインがインストールされていなかったので手動でインストールしました。

$ ibmcloud cr    
失敗
'cr' は登録済みコマンドではありません。 インストール済みプラグインのリストを確認してください。 'ibmcloud help' を参照してください。

$ ibmcloud plugin install container-registry
リポジトリー 'IBM Cloud' から 'container-registry' を検索しています...
プラグイン 'container-registry 0.1.553' がリポジトリー 'IBM Cloud' 内で見つかりました
バイナリー・ファイルをダウンロードしようとしています...
 11.50 MiB / 11.50 MiB [=============================================================================================================] 100.00% 0s
12058224 バイトがダウンロードされました
バイナリーをインストールしています...
OK
プラグイン 'container-registry 0.1.553' は /Users/fterui/.bluemix/plugins/container-registry に正常にインストールされました。 'ibmcloud plugin show container-registry' を使用して詳細を表示してください。
$ ibmcloud cr
名前:
  ibmcloud cr - 

使用法:
  ibmcloud cr command [arguments...] [command options]

...(snip)...

コマンドが使えるようになったら、まずnamespaceを作成します。

$ ibmcloud cr namespace-add fterui_test_ns
レジストリー jp.icr.io のアカウント Fumihiko Terui's Account 用のリソース・グループ「Default」に、名前空間「fterui_test_ns」を追加中...

名前空間「fterui_test_ns」は正常に追加されました

OK

ローカルのdockerをcontainer registryに接続させます。

$ ibmcloud cr login
「jp.icr.io」にログインしています...
「jp.icr.io」にログインしました。

OK

接続したら、pushしたいローカルのイメージにタグ付けをします。

$ docker tag fterui_play_test:latest jp.icr.io/fterui_test_ns/fterui_play_test:latest
$ docker images
REPOSITORY                                  TAG                    IMAGE ID       CREATED          SIZE
fterui_play_test                            latest                 fbf7830ee235   28 minutes ago   264MB
jp.icr.io/fterui_test_ns/fterui_play_test   latest                 fbf7830ee235   28 minutes ago   264MB

いざpushします。

$ docker push jp.icr.io/fterui_test_ns/fterui_play_test:latest                       
The push refers to repository [jp.icr.io/fterui_test_ns/fterui_play_test]
cde2813440c5: Pushed 
7fe0bd342c72: Pushed 
053ceb7fe9fc: Pushed 
b549e2f2b0ec: Pushed 
f397c6a338e4: Pushed 
1c79be3b9ceb: Pushed 
latest: digest: sha256:ef8a1cb7baacac3b55b87325b602aab7c1f01d342f90a200dface3605bb56701 size: 1577

これでローカルのイメージがレジストリにpushされました。

アプリケーションのデプロイ

Pushしたイメージからアプリケーションをデプロイします。IBM Cloudのコンソールからプロジェクトを選んでアプリケーションの作成を選択します。名前を決定してコンテナー・イメージを選択するところまではサンプルの時と同様で、イメージ参照のところに先ほどpushしたイメージを指定します。このイメージはパブリックではないレジストリに置いてあるので場所を指定する必要があります。「イメージの構成」をクリックすると自分のアカウントに結び付けられているレジストリー・サーバーや名前空間などを選択するフライアウトが表示されます。それぞれ1つしか作成してなければ自動的に選択された状態になりますね。

スクリーンショット 2021-12-23 18.43.58.png

Listenポートに9000を指定するのをお忘れなく。全て設定したら「作成」をクリックして完了です。デプロイされるまでお茶でも飲んで待ちます。

が、実際は待てど暮らせど起動しません。流石にそんなに遅いはずはないと思い、ログを確認してみました。

$ ibmcloud ce application logs -n fterui-play-test
アプリケーション 'fterui-play-test' のすべてのインスタンスのログを取得中...
OK

fterui-play-test-00001-deployment-699c85577-flctb/user-container:    
standard_init_linux.go:228: exec user process caused: exec format error

これは実行ファイルのアーキテクチャが違ってる時とかに出るやつですね。私の開発環境はMacbook Air(M1)なのでもしかしたらこれが原因かもと。あともう一つ、Code Engineではrootユーザーで実行してはいけないに引っかかってる可能性もありました。なのでまずDockerfileを変更します。

Dockerfile
FROM openjdk:11-jre-slim
COPY . /root/

RUN addgroup nonroot --gid 1100 && \
  adduser nonroot --ingroup nonroot --uid 1100 --disabled-password && \
  chown -R nonroot:nonroot /root

USER nonroot
WORKDIR /root

CMD ["/root/bin/fterui-play-test", "-Dplay.http.secret.key=HORVsaoVwdmKFsw8Pxl2vvWhCwmOCEuMCUjf/IFawzs="]

さらにM1 Mac上でビルドする時にplatformを指定します。

$ docker build . -t fterui_play_test --platform linux/amd64   

そしてもう一度 docker tagdocker pushをしてイメージを更新してアプリケーションを作成したところ、無事起動しました!

スクリーンショット 2021-12-23 19.32.55.png

喜び勇んでアプリケーションにアクセスしたところ、見事以下のような… orz

スクリーンショット 2021-12-23 19.34.56.png

これは play.filters.hosts.AllowedHostsFilter によって許可されてないホストからのアクセスとみなされたためですね。アプリケーションを起動したときにコンソールに出ているやつです。このフィルターにアプリケーションのホスト名を追加してやらないといけなさそうです。詳細はこちらの公式ドキュメントを参照してください。

アプリケーションのapplication.confに以下のようなエントリを作成します。

play.filters.hosts {
    allowed = ["your_host_name", "localhost:9000"]
}

(もちろんyour_host_nameは実際のホスト名を入れることになります。)
開発環境で起動して普通にアクセスできることを確認し、それからもう一度イメージをビルドしてローカルのdockerで起動してアクセスしてみます。すると以下のように表示されます。
スクリーンショット 2021-12-24 9.44.59.png

これはポートを9001番にマップしているせいで許されてないホストからのアクセスだと認識されて拒否されているわけです。開発環境で起動した9000番は大丈夫だったのでちゃんと設定が効いていることが確認できました。このイメージを再度レジストリにpushして、コンソールのアプリケーションから「編集して新規リビジョンを作成」を選び、そのまま何も変更せず作成してしばらく待ちます。デプロイが終わったらいざ確認です。

スクリーンショット 2021-12-24 9.55.18.png
無事アプリケーションの動作が確認できました。

まとめ

IBM Cloud Code Engineを使ってPlay Frameworkを利用したアプリケーションのデプロイを行うのに必要な手順と陥りがちな注意点についてまとめました。完了してみるとある意味straight forwardでしたが、気にしてないとハマる点もいくつか見えたので、同じことを試される方の一助になれば良いかなと思っております。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0