2013-03-12 132 views
13

在遠程Linux服務器上部署Scala應用程序的首選方式是什麼。在遠程服務器上部署,啓動和停止Scala應用程序

這是一個相當簡單的,但有限的,部署在遠程服務器上Scala的應用程序的方式(尼斯不那麼敏感項目的快速測試):

  1. 從遠程服務器我拉我的從混帳
  2. 源使用sbt-assembly插件我建立服務器上的罐子
  3. 我然後運行使用nohup的Scala的應用程序,它可以讓你在不終止該進程退出遠程會話:

    nohup的Java的罐子myapp.jar> myapp.log 2> myapp.err <的/ dev/null的&

首先,什麼是停止的過程中,一旦運行它的最好辦法,考慮到它的使用資源如數據庫等。我只是查找Java進程ID並核彈它?其次,在重新啓動時自動啓動Java應用程序的最佳方式是什麼?我記得過去曾經使用過init.d,但記得自從它是一個Java應用程序以來就有些艱難。

更新:

我錯過了在房間裏的大象在這裏。我使用Spray庫,它依次使用Akka,以便提供一些有趣的選項。

+0

將應用程序安裝爲服務或通過TCP套接字發送關機消息如何? – 2013-03-12 14:52:07

+0

關於您在任何時候停止進程的第一個要求,我建議使用'screen'並在屏幕會話中運行您的jar。使用'ctrl + a k'殺死一個窗口及其中運行的進程。 – Kane 2013-03-12 19:43:49

+0

謝謝@Kane。我忘記了那個。這是一個很酷的想法,尤其是因爲您可以與其他開發人員共享屏幕(如果內存能爲我服務) – Jack 2013-03-13 04:25:27

回答

17

有多種方法對皮膚一隻貓......

你可以使用sbt-start-script https://github.com/sbt/sbt-start-script或甚至sbt-native-packager https://github.com/sbt/sbt-native-packager

你可以將Spray的Boot示例腳本包裝在一個簡單的ini t.d腳本調用sbt,詳見本答案https://stackoverflow.com/a/17399574/155689,或者只使用普通的nohup java命令。

您可以創建更大的守護程序感知類和腳本,也可以使用使用Jsvc http://commons.apache.org/proper/commons-daemon/jsvc.html或Java Service Wrapper的init.d腳本來擴展它們。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() 
    } 
    } 

} 

如果部署在/opt/myapplication/myapplication.jar罐子(使用SBT-大會脂肪罐子),加上一些外部的配置在/etc/mycompany文件夾,然後你可以使用的jsvc包裝,在一個/etc/init.d/myapplication腳本,例如:

#!/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 

此守護程序方法適用於噴霧的應用程序我有。

+0

優秀的答案!不幸的是,我不太清楚「在/ etc/mycompany文件夾中添加一些外部配置」部分。你是指罐子等?仍然很好的答案。 – Jack 2014-03-19 09:21:27

+0

外部配置是可選的,並由 APP_LOG_CONFIG和APP_CONFIG 引用,即logback和spray的application.conf配置,可能會覆蓋jar配置中的配置。但是你需要你的build.sbt和Build.scala來監聽這些java選項。 如果你不需要它們,你可以通過刪除它們的引用來簡化你的DAEMON_ARGS和JAVA_OPTS。 – flurdy 2014-03-19 11:18:45

相關問題