7
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Heroku で Payara Micro (Gradle)

Last updated at Posted at 2015-09-22

ソースは GitHub に上げてます。

#環境構築
こっち参照

#やること
基本はキクタローさんのこちらの記事を参考にしました。

ただ、こちらのスライドの方法だと、Payara Micro を起動するアプリとは別に Web アプリを作成しておき、 war を手動?で Payara Micro 起動用のアプリに移すことになっている。
そこを1つのリポジトリで作成できるようにしてみる。

#フォルダ構成

|-server/
|  |-src/main/java/sample/heroku/
|  |  `-Main.java
|  |
|  `-build.gradle
|
|-webapp/
|  |-src/main/java/sample/heroku/webapp/
|  |  |-MyApplication.java
|  |  `-HelloResource.java
|  |
|  `-build.gradle
|
|-gradle/
|-build.gradle
|-settings.gradle
|-gradlew
|-gradlew.bat
|-Procfile
`-system.properties

Gradle のマルチプロジェクト構成でアプリケーションを作る。

server は、 Payara Micro を起動するためのプロジェクト。
webapp は、 Payara Micro にデプロイする Web アプリのプロジェクト。

#実装
##Gradle の設定ファイル

/build.gradle
subprojects {
    apply plugin: 'eclipse'
    apply plugin: 'java'

    sourceCompatibility = '1.8'
    targetCompatibility = '1.8'

    compileJava.options.encoding = 'UTF-8'

    repositories {
        mavenCentral()
    }

    task stage(dependsOn: ['clean', ':server:installDist', ':webapp:war']) // ★
}

ext {
    payaraDependency = 'fish.payara.extras:payara-micro:4.1.153'
}

task wrapper(type: Wrapper) {
    gradleVersion = '2.7'
}

stage タスクが実行されたら、 server プロジェクトを実行可能な状態にビルドして、 webapp プロジェクトを war ファイルにビルドする。

/server/build.gradle
apply plugin: 'application'

mainClassName = 'sample.heroku.Main'
applicationName = 'server'

dependencies {
    compile payaraDependency
}

eclipse.project.name = 'payara-micro-on-heroku-server'

installDist.mustRunAfter clean
/webapp/build.gradle
apply plugin: 'war'

war.baseName = 'webapp'

dependencies {
    providedCompile payaraDependency
}

eclipse.project.name = 'payara-micro-on-heroku-webapp'

war.mustRunAfter clean

###dependsOn で指定したタスクの実行順序を制御する

/build.gradle
    task stage(dependsOn: ['clean', ':server:installDist', ':webapp:war'])

stage タスクが依存するタスクとして clean, :server:installDist, :webapp:war を指定している。
一見するとこの順序でタスクが実行されそうだが、実際はそうならない。

dependsOn で並べた依存タスクの実行順序を制御するには、それぞれのタスクの mustRunAfter() メソッドを使って以下のように定義しないといけない。

/server/build.gradle
installDist.mustRunAfter clean
/webapp/build.gradle
war.mustRunAfter clean

<後に実行されるタスク>.mustRunAfter <先に実行されるタスク> とする。

これをしておかないと、ビルドした後に clean タスクが実行されて残念なことになる。

##Heroku 用の設定ファイル

Procfile
web: server/build/install/server/bin/server
system.properties
java.runtime.version=1.8

Procfile で、 :server:installDist タスクで生成される起動用スクリプトファイルを叩くようにしている。

##Java 実装
###server

Main.java
package sample.heroku;

import fish.payara.micro.PayaraMicro;

public class Main {
    
    public static void main(String[] args) throws Exception {
        PayaraMicro.getInstance()
            .setHttpPort(Integer.parseInt(System.getenv("PORT")))
            .addDeployment("webapp/build/libs/webapp.war") // ★ :webapp:war タスクで生成される war
            .bootStrap();
    }
}

###webapp

MyApplication.java
package sample.heroku.webapp;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/api")
public class MyApplication extends Application {
}
HelloResource.java
package sample.heroku.webapp;

import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Path("/hello")
public class HelloResource {
    
    @GET
    public String hello() {
        return "<h1>Hello Payara Micro on Heroku!!!!</h1>";
    }
}

#動作確認
https://payara-micro.herokuapp.com/webapp/api/hello にブラウザからアクセス。

heroku.JPG

※404 エラーが表示される場合はアプリが再起動している最中なので、しばらく(1分ほど)待ってから再度アクセスしたら見れるようになります。

#おまけ(失敗例)
以前、同じように Heroku で Payara Micro を動かすために、以下のような方法を試したことがある。

  • プロジェクトは war ファイル用のプロジェクトを1つだけ用意する。
  • Payara Micro の依存関係は providedCompile で定義しておく。
  • stage タスクが実行されるときに Procfile を動的に生成する。
  • Procfile には、 Gradle がビルドするときにダウンロードした jar ファイルを使って Payara Micro を立ち上げるようにコマンドを記述する。

build.gradle は以下のような感じ。

build.gradle
apply plugin: 'war'

repositories {
    mavenCentral()
}

dependencies {
    providedCompile 'fish.payara.extras:payara-micro:4.1.153'
}

war.baseName = 'webapp'
war.mustRunAfter clean

task wrapper(type: Wrapper) {
    gradleVersion = '2.7'
}

task stage(dependsOn: ['clean', 'war']) << {
    new File('./Procfile').delete()

    // ★ここで Procfile を動的に生成
    configurations
        .providedCompile
        .findAll {it.name =~ /payara-micro.*\.jar/}
        .each { file ->
            def payaraJar = file.absolutePath
            new File('./Procfile').write("web: java \$JAVA_OPTS -jar ${payaraJar} --deploy ${war.archivePath} --port \$PORT")
        }
}

configurations.providedCompile で、依存関係で指定した jar のパスが指定できるので、それを利用している。

stage タスクが実行されると、以下のような Procfile が生成される。

Procfile
java -jar /app/tmp/cache/.gradle/caches/modules-2/files-2.1/fish.payara.extras/payara-micro/4.1.153/ce4e16681e0873bf05074cc2017c43e69db7c1e1/payara-micro-4.1.153.jar --deploy /tmp/build_1ca90667e1a4987c5289672cd294bee9/build/libs/webapp.war --port 52002

ちゃんと、 Heroku 上のパスで Procfile が生成されているっぽい。

しかし、実際に Heroku で動かすと以下のようにエラーが発生する。

Herokuにアップしたときのログ
app[web.1]: Error: Unable to access jarfile /app/tmp/cache/.gradle/caches/modules-2/files-2.1/fish.payara.extras/payara-micro/4.1.153/ce4e16681e0873bf05074cc2017c43e69db7c1e1/payara-micro-4.1.153.jar
heroku[web.1]: Process exited with status 1
heroku[web.1]: State changed from starting to crashed

jar にアクセスできないらしい。

当時は原因が分からなかったが、今回試しにサーバーに SSH で繋いでみたところ、なんとなく原因が分かった。

SSHでサーバーに接続
> heroku run bash

~ $ pwd
/app

~ $ ls
LICENSE   README.md     gradle   gradlew.bat  settings.gradle    webapp
Procfile  build.gradle  gradlew  server       system.properties

/app/tmp が存在しない。

たぶん、ビルドしている環境とビルド後のアプリケーション(slug)が実行される環境は別で、 Gradle がキャッシュした jar ファイルは実行環境の方に持ってこられていないのだと思う。おそらく。

#参考

7
7
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
7
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?