2011-11-09 56 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,那么这就是方法。