Подтвердить что ты не робот

Развертывание, запуск и остановка приложений Scala на удаленном сервере

Какой предпочтительный способ развертывания приложений Scala на удаленном сервере Linux.

Это довольно простой, но ограниченный способ развертывания приложения Scala на удаленном сервере (хорошо для быстрого тестирования не очень чувствительных проектов):

  • На удаленном сервере я вытаскиваю свой источник из git
  • Использование sbt-assembly подключаемый модуль Я создаю банку на сервере
  • Затем я запускаю приложение Scala, используя nohup, что позволяет выйти из удаленного сеанса без завершения процесса:

    nohup java -jar myapp.jar > myapp.log 2 > myapp.err </dev/null &

Во-первых, как лучше всего остановить процесс после его запуска, учитывая его использование таких ресурсов, как базы данных и т.д. Я просто просматриваю идентификатор процесса java и nuke?

Во-вторых, что лучше всего запустить приложение Java автоматически при перезагрузке. Я вспоминаю использование init.d в прошлом, но помню, как можно было подняться в гору, поскольку это было Java-приложение.

Update:

Я пропустил слона в комнате здесь. Я использую библиотеку Spray, которая по очереди использует Akka, поэтому предоставляет ряд интересных вариантов.

4b9b3361

Ответ 1

Существует несколько способов скинуть кошку...

Вы можете использовать sbt-start- script https://github.com/sbt/sbt-start-script или даже sbt-native-packager https://github.com/sbt/sbt-native-packager

Вы можете включить пример загрузки Spray Boot script в простой init.d script, который вызывает sbt, как описано в этом ответе fooobar.com/questions/249240/..., или просто используйте простая команда nohup java.

Вы можете создавать классы и сценарии с более высоким демонами или расширять их с помощью сценариев init.d, которые используют Jsvc http://commons.apache.org/proper/commons-daemon/jsvc.html или Java Service Обертка. http://wrapper.tanukisoftware.com/

Пример демона и класса приложения:

package com.example.myapplication.server

import akka.actor.{Props, ActorSystem}
import spray.can.Http
import akka.io.IO
import com.example.myapplication.api.MyServiceActor
import org.apache.commons.daemon._

trait ApplicationLifecycle {
  def start(): Unit
  def stop(): Unit
}

abstract class AbstractApplicationDaemon extends Daemon {
  def application: ApplicationLifecycle

  def init(daemonContext: DaemonContext) {}

  def start() = application.start()

  def stop() = application.stop()

  def destroy() = application.stop()
}

class ApplicationDaemon() extends AbstractApplicationDaemon {
  def application = new Application
}

object ServiceApplication extends App {

  val application = createApplication()

  def createApplication() = new ApplicationDaemon

  private[this] var cleanupAlreadyRun: Boolean = false

  def cleanup(){
    val previouslyRun = cleanupAlreadyRun
    cleanupAlreadyRun = true
    if (!previouslyRun) application.stop()
  }

  Runtime.getRuntime.addShutdownHook(new Thread(new Runnable {
    def run() {
      cleanup()
    }
  }))

  application.start()
}


class Application() extends ApplicationLifecycle with Logging {

  private[this] var started: Boolean = false

  private val applicationName = "MyApplication"

  implicit val actorSystem = ActorSystem(s"$applicationName-system")

  def start() {
    logger.info(s"Starting $applicationName Service")

    if (!started) {
      started = true

      val myService = actorSystem.actorOf(Props[MyServiceActor], "my-service")

      IO(Http) ! Http.Bind(myService, interface = "0.0.0.0", port = 8280)
    }
  }

  def stop() {
    logger.info(s"Stopping $applicationName Service")

    if (started) {
      started = false
      actorSystem.shutdown()
    }
  }

}

Если вы разворачиваете банку (используйте sbt-assembly для жирной банки) в /opt/myapplication/myapplication.jar, добавьте некоторые внешние конфигурации в папку /etc/mycompany, тогда вы можете обернуть это в /etc/init.d/myapplication script, например используя Jsvc:

#!/bin/sh
### BEGIN INIT INFO
# Provides:          myapplication
# Required-Start:    $local_fs $remote_fs $network
# Required-Stop:     $local_fs $remote_fs $network
# Should-Start:      $named
# Should-Stop:       $named
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Control myapplication
# Description:       Control the myapplication daemon.
### END INIT INFO

set -e

if [ -z "${JAVA_HOME}" ]; then
        JAVA_HOME=$(readlink -f /usr/bin/java | sed "s:/bin/java::")
fi
JAVA_OPTS="-Xms512m -Xmx1024m"

APP=myapplication

PID=/var/run/${APP}.pid
OUT_LOG=/var/log/myapplication/${APP}_out.log
ERR_LOG=/var/log/myapplication/${APP}_err.log

DAEMON_USER=yourserviceuser

APP_LOG_CONFIG=/etc/mycompany/${APP}_logback.xml
APP_CONFIG=/etc/mycompany/${APP}.conf
APP_HOME=/opt/${APP}
APP_CLASSPATH=$APP_HOME/${APP}.jar
APP_CLASS=com.example.myapplication.server.ApplicationDaemon

if [ -n "$APP_LOG_CONFIG}" ]; then
        JAVA_OPTS="-Dlogback.configurationFile=${APP_LOG_CONFIG} ${JAVA_OPTS}"
fi

DAEMON_ARGS="-home ${JAVA_HOME} -Dconfig.file=${APP_CONFIG} ${JAVA_OPTS} -pidfile ${PID} -user ${DAEMON_USER} -outfile ${OUT_LOG} -errfile ${ERR_LOG} -cp ${APP_CLASSPATH} ${APP_CLASS}"

. /lib/lsb/init-functions

case "$1" in
        start)
                log_daemon_msg "Starting ${APP}"
                cd ${APP_HOME} && jsvc ${DAEMON_ARGS}
                log_end_msg 0
                ;;
        stop)
                log_daemon_msg "Stopping ${APP}"
                cd ${APP_HOME} && jsvc -stop ${DAEMON_ARGS}
                log_end_msg 0
                ;;
        *)
                log_success_msg "Usage:  {start|stop}"
                echo "Usage:  {start|stop}"
                exit 1
                ;;
esac

exit 0

С этим вы можете теперь sudo service myapplication start|stop

И если, как уже упоминалось, вы хотите, чтобы он автоматически запускался при загрузке, запустите эту команду

sudo update-rc.d myapplication defaults

Этот демон работает с приложениями Spray, которые у меня есть.

Ответ 2

Если подходит maven, то можно использовать следующий плагин: http://evgeny-goldin.com/wiki/Sshexec-maven-plugin

Возможно, его можно легко портировать на sbt