Heroku - Могу ли я позвонить Maven из Procfile? - PullRequest
5 голосов
/ 09 ноября 2011

Я исследую Heroku как платформу и пытаюсь заставить работать на ней простое веб-приложение на Java. Веб-приложение уже создается и работает с Maven (используя Tomcat и плагин cargo-maven), поэтому я решил, что это должно быть очень просто, учитывая, что Heroku использует 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, поэтому команда не выполняется.

Можно ли вызвать mvn из Heroku Procfile? И есть ли где-нибудь определенный список команд, которые доступны и недоступны из Procfile?

Ответы [ 3 ]

7 голосов
/ 09 ноября 2011

Maven не находится в слаге, который развертывается на dynos.Это доступно только во время компиляции.Одним из вариантов решения этой проблемы является использование пакетов appassembler-maven-plugin и jar для генерации сценария запуска:

        <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-plugin и war:

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

с Procfile из:

web: java $JAVA_OPTS -jar target/dependency/jetty-runner.jar --port $PORT target/*.war
2 голосов
/ 14 ноября 2011

В ответе Джеймса содержатся хорошие инструкции по настройке Jetty для работы с Heroku, а в его комментарии содержится ссылка на хороший справочник по использованию встроенного Tomcat. Но также возможно запустить стандартную, автономную версию Tomcat на Heroku. Вот как я смог заставить его работать:

Сначала настройте 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 разрешено связываться только с одним портом (который изменяется каждый раз при создании нового экземпляра и указывается в переменной среды $PORT). Попытка привязки к любому другому порту приведет к сбою вашего приложения. Поскольку порт динамический, он должен быть передан в server.xml через системное свойство http.port, но мы вернемся к этому позже.

Пока вы это делаете, также создайте файл 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 указывает URL базы данных, который ваше приложение должно использовать в переменной среды $DATABASE_URL.

Теперь пришло время создать простой сценарий оболочки, который настраивает среду и настраивает все так, чтобы Tomcat мог действительно работать:

#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. Он говорит Tomcat использовать артефакты конфигурации и развертывания, которые груз упаковал как часть вашей сборки, установив CATALINE_BASE, чтобы он указывал на правильное место.
  2. Перезаписывает файлы по умолчанию server.xml и persistence.xml с их характерными для heroku вариантами.
  3. Он отмечает все сценарии запуска в экземпляре Tomcat, которые груз установил как часть сборки, как исполняемый файл.
  4. Указывает значения для http.port и hibernate.connection.url на основе переменных среды, предоставляемых платформой Heroku.
  5. Наконец, запускается Tomcat. Обратите внимание, что вы не можете использовать startup.sh для этого, так как startup.sh запустит Tomcat в новом процессе, а затем завершит работу. Героку не понимает этого и думает, что завершение startup.sh - это завершение процесса Tomcat.

Наконец, последний шаг - настроить Procfile для вызова сценария запуска, что-то вроде:

web: sh startServer-heroku.sh

При таком подходе вы можете создать проект, совместимый с Heroku, при этом сохраняя возможность автономной работы в качестве стандартного веб-приложения Java.

0 голосов
/ 19 марта 2014

Да, вы можете вызвать maven из вашего Procfile.

Для этого вам нужно включить maven в ваш slug, внеся небольшую модификацию в скрипт компиляции в пакете сборки java, как описано в README.md файл из проекта heroku-buildpack-java :

Например, если вы хотите, чтобы maven был доступен для использования во время выполнения в вашем приложении, вам просто нужноскопируйте его из каталога кэша в каталог сборки, добавив в скрипт компиляции следующие строки:

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

I добавил эти строки сразу после загрузки maven и перед изменениемto BUILD_DIR.

В вашем Procfile вы можете затем вызвать .maven / bin / mvn

Если вы создаете артефакт (war / jar), который вы можете запустить из java или в контейнере сервлетатогда вы, вероятно, должны сделать что-то по пути других ответов, но если вам действительно нужно запустить maven, то это путь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...