[2.0.x] Deployment model

509 views
Skip to first unread message

Alex Povar

unread,
Nov 4, 2012, 9:49:49 AM11/4/12
to play-fr...@googlegroups.com
Hi, what is best deployment model for Play 2 applications on my own linux server?
For a now I am doing the following:
1) play clean compile stage on my laptop
2) tar -czvf ./tarball.tar.gz ./target
3) scp ./tarball.tar.gz my-host
4) starting ssh session
5) nohup ./start -Dhttp.port=80 & on server

I don't know is it right, but this works. Is there any ways like play do-deploy or something like this, or this is quite ok and I should write one extra-feature-full bash script to run my app on target server?

Frederic Masion

unread,
Nov 4, 2012, 10:15:18 AM11/4/12
to play-fr...@googlegroups.com

Hi Alex,

I don't find this being the best way too
I haven't investigated what openStack can provide

I would like to deploy without having to interupt the service like it could be possible for exemple in PHP. This seams only possible if you can load balance on more than one server.

There's still a problem with database evolutions => you must stop all servers

One more thing : when i use play natively (not as a war in a web server) is there a way to publish more than one app on the server, each app being bound to a sub domain ?

Alex Povar

unread,
Nov 4, 2012, 10:39:23 AM11/4/12
to play-fr...@googlegroups.com
Thanks for link, now I don't need to write my own featurefull-bash-script )
But there still a question, is there any out-of-box and author-recomended way? Moreover I am very intresting how authors do.

As for code reloading, I don't think that class-loading tricks are good idea in production mode. So there are few alternatives:
  • let it works in dev mode
  • frontend reverse proxy like nginx
  • or old-school quick kill-start your app.

воскресенье, 4 ноября 2012 г., 22:15:18 UTC+7 пользователь Frederic Masion написал:

Will Sargent

unread,
Nov 4, 2012, 2:17:40 PM11/4/12
to play-fr...@googlegroups.com
It would be nice if Play had something like Capistrano, that would automate deployments, but sbt-deploy is the only thing I know of there.  

There are general purpose deployment automation tools like Fabric or Deployit, but they're not as tied into the build (and also not Scala).  

Will.

--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To view this discussion on the web visit https://groups.google.com/d/msg/play-framework/-/zEDasRw3DksJ.

To post to this group, send email to play-fr...@googlegroups.com.
To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.

Ike

unread,
Nov 5, 2012, 4:46:28 PM11/5/12
to play-fr...@googlegroups.com
To save a step you can use the 'dist' target instead of 'stage'. It will create a compressed (zip) archive that you can simply scp over and unzip on the other side.

biesior

unread,
Nov 5, 2012, 5:47:08 PM11/5/12
to play-fr...@googlegroups.com
If your remote server has enough memory and CPU it's much better option to create dist package on the destination machine(s). It's pretty similar like described in the post mentioned by Frederic, however main difference is that what you have to send. Often you need to fix one file (ie. 20kb.) so sending 50MB+ every time doesn't make a sense. When your app will grow and you'll have to set-up many instances in the future you'll see why it's uncomfortable idea. Instead you can just push small fixes with git and then re-deploy it in on the remote destination(s).

Your re-deploying should be as easy as writing the command:

   git push some-remote master 

and happily Play allows that! (with git+some bash scripting)

Although I'm obligated to keep scripts unpublished, there is very general checklist of our solution:

 * Create a git repository on the remote
 * configure some lightweight HTTP server with load-balance at least to the 2 ports
 * Install current Play version on the remote
 * Ignore dist folder in git
 * Commit/push source files of your app into the repo
 * use post-receive hook on the remote to:
    - create dist package  
    - unzip dist package
    - move unzipped folder to new destination outside the dist folder of your app (because it will be deleted BEFORE next play dist operation!)
    - start the application on the second LB port (stop app on this port before if required)
    - start the application on the first LB port (stop app on this port before if required)
    - Remove the folder created  while previous 're-deploy`

Tip: keep your static public assets in separate folder and git repository to avoid re-deploying your app every time when you need to fix layout's CSS or images. You can use HTTP server to access them or maybe better some 3-rd party CDN solutions allowing for geo-replication, advanced caching (without writing it manually) etc.

Will Sargent

unread,
Nov 6, 2012, 3:15:58 AM11/6/12
to play-fr...@googlegroups.com
I don't know is it right, but this works. Is there any ways like play do-deploy or something like this, or this is quite ok and I should write one extra-feature-full bash script to run my app on target server.

You can always use rsync over ssh if you want a more incremental style of deploy:

rsync -avz --delete -e ssh $deployed_code staging:/opt/play-app

Good for staging, not so hot for production.

Will.

Alex Povar

unread,
Nov 6, 2012, 5:58:34 AM11/6/12
to play-fr...@googlegroups.com

Nice to meet you again biesior)

My linux server doesn't have enought memory for build. I was thinking about idea your published earlier but with building stage in my laptop. 
It is not very comfortable to keep 50MB+ in SCM (I use mercurial, looks like it have special extension for this), but idea is not bad.

I just wondered that there is no out-of-box tool for this.


вторник, 6 ноября 2012 г., 5:47:08 UTC+7 пользователь biesior написал:

El Softwarerero (the player formerly known as sun)

unread,
Nov 6, 2012, 7:55:10 AM11/6/12
to play-fr...@googlegroups.com
Like Will points out rsync can really help in this situation. Just exclude what you don't need, e.g. "--exclude=conf/* " and it might be good enough for production.

Ike

unread,
Nov 7, 2012, 10:30:19 PM11/7/12
to play-fr...@googlegroups.com
For several reasons, most importantly security, many enterprise production systems don't have a full JDK available (only a JRE). So the only choice is to build elsewhere (e.g. Jenkins build server) and ship the JARs to the production machines.

Copying a 50 MB file shouldn't be an issue if the build server is on the same network as prod. But you can save some network traffic by using 'stage' and doing an rsync instead as Will suggests.

You could still keep biesior's heroku-like approach for convenience on the build server and automate deployment separately.

Ike

unread,
Nov 7, 2012, 10:31:35 PM11/7/12
to play-fr...@googlegroups.com
I've always wondered what the difference is between play's 'stage' and 'dist'. They definitely have different layouts.

Justin Holmes

unread,
Nov 8, 2012, 8:46:42 AM11/8/12
to play-fr...@googlegroups.com
I am just making you aware that is my old way of deployment.

Now Jenkins polls Github for changes, builds the Play App, then a downstream job will copy the files over to the prod box and restart the Play upstart daemon.

iammichiel

unread,
Nov 9, 2012, 12:03:35 PM11/9/12
to play-fr...@googlegroups.com
I must disagree with Biesor (as I already did on StackOverflow). Compilation must not be done on production server. Let me explain why.

I have noticed that in some cases, simply recompiling is not enough. By recompiling, I mean the incremental compilation. For some reason, some changes were not taking into account. I always clean before I compile. (on production anyway). So in order to deploy, you have to clean/compile or dist. Let's take my main Play2 project. 100+ scala files, 80 routes. Working on a Macbook Pro from 2010, I need 2,3 full minutes at 100% of CPU to compile/dist the projet. That means blocking my production server for 2 or 3 minutes on full cpu which is, in my opinion, unacceptable. 

Solution : Use continious integration and go a little further continious delivery. Working with github, after each push on master branch, Jenkins is triggered and does a full compilation of the project (running tests and all). And finally publishes the zip on S3. Afterwards, all I have to do is download the zip from S3, unzip and start the application. 

1. Your server is not blocked by high CPU usage. 
2. The 50mb to upload are no longer relevant as your CI is doing the upload for you. (Got a micro server at 15€/month doing that for you). And btw, bandwitdh on a server should not be a problem.. :)

Ben McCann

unread,
Nov 9, 2012, 12:15:47 PM11/9/12
to play-fr...@googlegroups.com
I run "dist-unzip", which runs "play dist" and then unzips the resulting distribution file and makes the start script executable.  I then use fabric to deploy to the remote server where I run the server with supervisor.

-Ben

Ike

unread,
Nov 9, 2012, 1:21:44 PM11/9/12
to play-fr...@googlegroups.com
I've seen this pattern on this list a couple of times and it seems backwards to me. Instead of zipping and then immediately unzipping a file that has a script with bad permissions, why not have an intermediate step that creates the distribution layout (with the proper execute bit on the start script for posix-like OSs) for people who don't need the zip step (i.e. people deploying using rsync). And a separate 'zip' task that creates the final archive.

It could look something like this:

play dist-prepare (prepare the distribution)
play dist (create the compressed archive)

We (Ben, Peter and I) talked about this at some length in the past (https://groups.google.com/d/topic/play-framework/vS6KlkQigs4/discussion) but I think it was bad timing because the team was very busy with the 2.0 release.

I'm hopeful that I won't be the only voice asking for this change this time around. I think we should revisit the possibility of having this intermediate step. It's clearly a stage that would be useful to many people/deployment scenarios and sbt needs to do it as part of the packaging process anyway.

Ben, do you still have that pull request that can be dusted off? :) Maybe for 2.1? 

Ben McCann

unread,
Nov 9, 2012, 1:29:41 PM11/9/12
to play-fr...@googlegroups.com
Here's the old pull request I put together. I submitted a pull request to the sbt goodies project (the project which provides dist-unzip), and it has been pending for months. Last I asked Peter about it, I believe he said rather than accepting the pull request he was considering whether the functionality should be part of the main project instead.  I can't remember exactly the conversation nor can I find it, so I could be recalling incorrectly.  I don't know what the latest thinking is.

-Ben


--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To view this discussion on the web visit https://groups.google.com/d/msg/play-framework/-/EAxHciWWGNkJ.

To post to this group, send email to play-fr...@googlegroups.com.
To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.

Ike

unread,
Nov 9, 2012, 2:19:10 PM11/9/12
to play-fr...@googlegroups.com
As you stated in that other thread, it's wasteful and, I think, more error-prone to do it backwards. I really don't see any technical or conceptual reasons why we shouldn't support an intermediate (expanded) dist build step. Please correct me if I'm missing something here.

How much effort would it be to split that sbt task in two steps? I haven't looked at that part of the code but I can't imagine it being a big effort. I'll take a look at the pull request to get a better idea.

El Softwarerero (the player formerly known as sun)

unread,
Nov 9, 2012, 4:45:51 PM11/9/12
to play-fr...@googlegroups.com
+1 for "play dist-prepare" or something like that

Ben McCann

unread,
Nov 25, 2012, 3:53:49 PM11/25/12
to play-fr...@googlegroups.com
Sure, here you go:

#!/usr/BIN_DIR/python

from fabric.api import *
from fabric.contrib.project import rsync_project
import inspect
import os

# Local directories
FAB_DIR = os.path.dirname(inspect.getfile(inspect.currentframe()))
DIST_DIR = FAB_DIR + '/../frontend/dist'

# Environment settings
env.hosts = ['55.55.55.55']

USER = 'myuser'
PROJECT = 'myprojcet'
VERSION = '1.0-SNAPSHOT'

# Remote directories
BIN_DIR = '/usr/local/users/' + USER

def deploy():
  # Make sure the files to deploy exist
  with open(DIST_DIR + '/' + PROJECT + '-' + VERSION + '/start') as infile:
    pass

  # Transfer the files over
  rsync_project(BIN_DIR, DIST_DIR + '/', delete=True, extra_opts="--omit-dir-times")

  # Run the binaries
  run('supervisorctl restart ' + PROJECT)



On Fri, Nov 23, 2012 at 11:49 PM, Chris Miller <cmi...@6ps.com> wrote:
Ben:

Can you share your fabric script that you use to deploy? I'm looking for some templates to use as a starting point.

-Chris

On Friday, November 9, 2012 11:15:47 AM UTC-6, Ben McCann wrote:
I run "dist-unzip", which runs "play dist" and then unzips the resulting distribution file and makes the start script executable.  I then use fabric to deploy to the remote server where I run the server with supervisor.

-Ben

--
 
 



--
about.me/benmccann
Reply all
Reply to author
Forward
0 new messages