2011-11-09 54 views
5

我正在調查Heroku作爲一個平臺,並試圖獲得一個基本的Java Web應用程序來運行它。該webapp已經建立並運行於Maven(使用Tomcat和cargo-maven插件),所以我認爲這應該是一件輕而易舉的事,因爲Heroku使用Maven來管理其安裝/部署任務。Heroku - 我可以從Procfile調用Maven嗎?

但事實並非如此,因爲我無法讓事情真正開始。我Procfile已經在它下面:

web: sh ./startServer-heroku.sh 

而且startServer-heroku.sh就是:

mvn clean install cargo:start -Dcargo.maven.wait=true 

這工作得很好,當我在本地測試使用foreman start命令,如Heroku的教程文檔描述。但是,當我嘗試它的實際Heroku的服務器上,我得到以下日誌消息:

2011-11-09T02:30:27+00:00 heroku[web.1]: State changed from created to starting 
2011-11-09T02:30:27+00:00 heroku[slugc]: Slug compilation finished 
2011-11-09T02:30:33+00:00 heroku[web.1]: Starting process with command `sh ./startServer-heroku.sh` 
2011-11-09T02:30:33+00:00 app[web.1]: ./startServer-heroku.sh: 1: mvn: not found 
2011-11-09T02:30:33+00:00 heroku[web.1]: Process exited 
2011-11-09T02:30:34+00:00 heroku[web.1]: State changed from starting to crashed 

看來,mvn是上無處可尋了系統的PATH,所以命令失敗。

是否可以從Heroku Procfile中調用mvn?並且是否有任何有Procfile不可用的命令清單?

+0

看一下[jcabi-heroku-maven-plugin](http://www.jcabi.com/jcabi-heroku-maven-plugin/index.html),它將整個部署過程自動化到Heroku。也許它會幫助你的情況。 – yegor256

回答

2

James的回答爲獲得Jetty在Heroku上的工作提供了很好的指導,他的評論包含一個指向使用嵌入式Tomcat的良好參考的鏈接。但是也可以在Heroku上運行標準的Tomcat獨立版本。以下是我能得到它的工作:

首先,設置你的POM您的應用程序安裝和配置Tomcat作爲構建的一部分,並且還部署到安裝Tomcat實例:

 <plugin> 
      <groupId>org.codehaus.cargo</groupId> 
      <artifactId>cargo-maven2-plugin</artifactId> 
      <configuration> 
       <container> 
        <containerId>tomcat6x</containerId> 
        <zipUrlInstaller> 
         <url>http://archive.apache.org/dist/tomcat/tomcat-6/v6.0.18/bin/apache-tomcat-6.0.18.zip</url> 
        </zipUrlInstaller> 
        <dependencies> 
         <dependency> 
          <groupId>javax.activation</groupId> 
          <artifactId>activation</artifactId> 
         </dependency> 
         <dependency> 
          <groupId>javax.mail</groupId> 
          <artifactId>mail</artifactId> 
         </dependency> 
        </dependencies> 
       </container> 
       <configuration> 
        <type>standalone</type> 
        <deployables> 
         <deployable> 
          <groupId>com.yourcompany.name</groupId> 
          <artifactId>yourArtifact</artifactId> 
          <type>war</type> 
          <properties> 
           <context>ROOT</context> 
          </properties> 
         </deployable> 
        </deployables> 
       </configuration> 
      </configuration> 
      <executions> 
       <execution> 
        <phase>package</phase> 
        <goals> 
         <goal>install</goal> 
         <goal>configure</goal> 
         <goal>deploy</goal> 
         <goal>package</goal> 
        </goals> 
       </execution> 
      </executions> 
     </plugin> 

接下來,創建一個簡裝server.xml文件,將在Heroku工作:

<?xml version='1.0' encoding='utf-8'?> 
<Server port="-1"> 
    <Listener className="org.apache.catalina.core.JasperListener" /> 
    <Service name="Catalina"> 
     <Connector port="${http.port}" protocol="HTTP/1.1" connectionTimeout="20000"/> 
     <Engine name="Catalina" defaultHost="localhost"> 
      <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"/> 
     </Engine> 
    </Service> 
</Server> 

...這是必要的,因爲你的Heroku應用程序只允許綁定到一個單一的端口(每個時間而改變的新實例已創建,並在中指定環境變量)。嘗試綁定到任何其他端口都會導致應用程序崩潰。由於端口是動態的,因此必須通過http.port系統屬性傳遞給server.xml,但我們稍後會介紹。

當你在它,還可以創建一個persistence.xml文件,將與Heroku的工作:

<?xml version="1.0" encoding="UTF-8"?> 
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
    http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"> 
    <persistence-unit name="quiz_devel"> 
    <provider>org.hibernate.ejb.HibernatePersistence</provider> 
    <exclude-unlisted-classes>false</exclude-unlisted-classes> 
    <properties> 
     <property name="hibernate.archive.autodetection" value="class"/> 
     <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/> 
     <property name="hibernate.hbm2ddl.auto" value="update"/> 
     <property name="hibernate.show.sql" value="true"/> 
     <property name="hibernate.c3p0.acquire_increment" value="1"/> 
     <property name="hibernate.c3p0.idle_test_period" value="10"/> 
     <property name="hibernate.c3p0.max_size" value="20"/> 
     <property name="hibernate.c3p0.max_statements" value="40"/> 
     <property name="hibernate.c3p0.min_size" value="1"/> 
     <property name="hibernate.c3p0.timeout" value="30"/> 
    </properties> 
    </persistence-unit> 
</persistence> 

注意,有沒有在這裏指定hibernate.connection.url。這是因爲Heroku指定了應用程序應在$DATABASE_URL環境變量中使用的數據庫url。

現在是時候創建一個配置環境,並完成所有設置,使Tomcat的可以實際運行一個簡單的shell腳本:

#point to the correct configuration and webapp 
CATALINA_BASE=`pwd`/target/cargo/configurations/tomcat6x 
export CATALINA_BASE 

#copy over the Heroku config files 
cp ./server-heroku.xml ./target/cargo/configurations/tomcat6x/conf/server.xml 
cp ./persistence-heroku.xml ./target/cargo/configurations/tomcat6x/webapps/ROOT/WEB-INF/classes/META-INF/persistence.xml 

#make the Tomcat scripts executable 
chmod a+x ./target/cargo/installs/apache-tomcat-6.0.18/apache-tomcat-6.0.18/bin/*.sh 

#set the correct port and database settings 
JAVA_OPTS="$JAVA_OPTS -Dhttp.port=$PORT -Dhibernate.connection.url=$DATABASE_URL" 
export JAVA_OPTS 

#start Tomcat 
./target/cargo/installs/apache-tomcat-6.0.18/apache-tomcat-6.0.18/bin/catalina.sh run 

這是做了一些事情:

  1. 它通過將CATALINE_BASE設置爲指向正確的位置,告訴Tomcat使用貨物作爲構建的一部分進行打包的配置和部署工件。
  2. 它用他們的heroku專用變體覆蓋默認的server.xmlpersistence.xml文件。
  3. 它標記Tomcat實例中的所有啓動腳本,將貨物作爲構建的一部分安裝爲可執行文件。
  4. 它根據Heroku平臺提供的環境變量來指定http.porthibernate.connection.url的值。
  5. 最後,它運行Tomcat。請注意,您不能使用startup.sh來執行此操作,因爲startup.sh將在新流程中啓動Tomcat,然後終止。 Heroku不理解這一點,並認爲終止startup.sh是Tomcat進程的終止。

最後,最後一步就是設置你的Procfile打電話給你的啓動腳本,沿着線的東西:

web: sh startServer-heroku.sh 

通過這種方法,你可以有一個項目,是與Heroku的兼容,同時仍然保持其作爲標準Java Web應用程序獨立運行的能力。

7

Maven不在被部署到dynos的slu in中。它只在編譯時纔可用。爲應對這種情況的一個選項是使用appassembler-maven-pluginjar包裝生成啓動腳本:

 <plugin> 
      <groupId>org.codehaus.mojo</groupId> 
      <artifactId>appassembler-maven-plugin</artifactId> 
      <version>1.1.1</version> 
      <configuration> 
       <assembleDirectory>target</assembleDirectory> 
       <programs> 
        <program> 
         <mainClass>foo.Main</mainClass> 
         <name>webapp</name> 
        </program> 
       </programs> 
      </configuration> 
      <executions> 
       <execution> 
        <phase>package</phase> 
        <goals> 
         <goal>assemble</goal> 
        </goals> 
       </execution> 
      </executions> 
     </plugin> 

然後Procfile是:

web: sh target/bin/webapp 

另一種選擇是maven-dependency-pluginwar包裝:

 <plugin> 
      <groupId>org.apache.maven.plugins</groupId> 
      <artifactId>maven-dependency-plugin</artifactId> 
      <version>2.3</version> 
      <executions> 
       <execution> 
        <phase>package</phase> 
        <goals> 
         <goal>copy</goal> 
        </goals> 
        <configuration> 
         <artifactItems> 
          <artifactItem> 
           <groupId>org.mortbay.jetty</groupId> 
           <artifactId>jetty-runner</artifactId> 
           <version>7.5.3.v20111011</version> 
           <destFileName>jetty-runner.jar</destFileName> 
          </artifactItem> 
         </artifactItems> 
        </configuration> 
       </execution> 
      </executions> 
     </plugin> 

With a Procfile of:

web: java $JAVA_OPTS -jar target/dependency/jetty-runner.jar --port $PORT target/*.war 
+0

謝謝,這很有道理,雖然你的例子是使用Jetty。你知道是否有可能與Tomcat做類似的事情? – aroth

+1

Tomcat沒有相當於jetty-runner,但仍可以通過多種方式部署Tomcat。一種是使用嵌入式Tomcat。查看剛發佈的這篇文章:http://devcenter.heroku.com/articles/create-a-java-web-application-using-embedded-tomcat –

0

是的,你可以從你的Procfile中調用maven。

要做到這一點,你需要通過使作爲README.md file from the "heroku-buildpack-java" project描述一個小的修改,以在Java構建包中的「編譯」的腳本,包括你塞行家:

例如,如果你想擁有可在應用程序運行時使用Maven您只需將其從緩存目錄複製到構建目錄中加入以下行編譯腳本:

for DIR in ".m2" ".maven" ; do 
cp -r $CACHE_DIR/$DIR $BUILD_DIR/$DIR 
done 

added these lines [R在Maven下載之後,以及在更改爲BUILD_DIR之前。

在你Procfile,你可以調用.maven /斌/ MVN

如果你正在建設一個神器(戰爭/罐),您可以從Java或在servlet容器中運行,那麼你或許應該做些什麼沿着其他答案的路上,但如果你確實需要運行maven,那麼這就是方法。