Packaging
Rails Apps
Lee Jones
Web Operations @ Lonely Planet
Hello everyone! My name is Lee Jones. I work in web operations at Lonely Planet.
Slide 2
Slide 2 text
Explore
the Planet
Lonely Planet is a company that helps people travel.
A big part of how we do that online is powered by various Ruby on Rails applications behind the scenes. Today, I want to share how we use packages to
deploy those Rails apps.
Slide 3
Slide 3 text
Packages!
A package is a collection of software that is gathered together into a format that can be distributed to other systems. A package may include metadata
like a name, version, description, and dependencies. This metadata helps the packaging system know how to install the package.
Slide 4
Slide 4 text
Packages?
So you might be thinking, “Rails apps as packages?”. Yeah, we typically think of packages for system level software like web servers and databases. Before
I joined Lonely Planet I wasn’t familiar with this pattern, but the more I’ve seen it in action, the more I like it. It brings some nice advantages that we’ll get
to shortly.
Slide 5
Slide 5 text
typical
deployment
A typical rails deployment involves 5 key parts: fetching source code, installing gems, compiling assets, migrating the database, and restarting the app.
Our packaging process handles 4/5 of those steps. We handle migrations separately. Looks look at how our packaging process works.
Slide 6
Slide 6 text
automated
We often deploy 15 or more times per day so a key point of the process I’m about to describe is that it is completely automated. There is no one hand
crafting these packages and tweaking configuration flags. When a developer gets the :thumbsup: on a PR and merges into master, our continuous
integration server (Jenkins) begins the automated process of moving that code to production.
Slide 7
Slide 7 text
tests: pass
Step 0 is run the tests. If our tests pass, we are ready to begin packaging the Rails app.
Slide 8
Slide 8 text
<% code %>
The first thing we need to gather is the source code. We pull the code down into clean workspace in preparation for building the package.
Slide 9
Slide 9 text
gems
Next, we include gems in our application packages so that it’s more self-contained and so the actual deploy is faster. We add the deployment flag and the
path flag so that gems are installed into the vendor directory instead of on the system. One thing to note here is that you want to make sure that your
build system closely matches production because otherwise you’ll run into issue with libraries being in different places etc.
Slide 10
Slide 10 text
assets
We precompile the assets on our build server, but we don’t include them in the package because our app servers do not serve any asset requests. We
push these up to S3 to be served by our CDN. We DO however include the asset manifests in the package because the application needs those during
startup.
Slide 11
Slide 11 text
cleanup
We’ve gathered what we need for the release, so now we can remove what we don’t need: log, tmp, doc, spec, features, and even .git. This saves on
storage space and transfer time.
Slide 12
Slide 12 text
jordansissel/fpm
It’s now time to build a package. For that we use fpm. fpm is an awesome tool that creates a nice abstracted interface to iron out the quirks of various
packaging systems. We run Ubuntu Server in production so we output .deb files, but you could adapt this to your platform of choice.
Slide 13
Slide 13 text
> fpm
We pass a several options to fpm including:
Slide 14
Slide 14 text
--name foo
Make sure you pick a name that will not conflict with other system packages you use.
Slide 15
Slide 15 text
--version x.y.z
Each release needs a unique version number that increments over time. We use the Jenkins build number to help generate this.
Slide 16
Slide 16 text
--description “An
application that does
foo - $GIT_COMMIT”
Adding the commit revision to the description makes it easier to trace back a particular package version to its revision in the source code repository.
Slide 17
Slide 17 text
--depends libxml
Many Rails apps depend on system level software being installed. For example, the nokogiri gem depends on libxml and libxslt (available as packages).
We can specify those dependencies here and they will be installed along with the app.
Slide 18
Slide 18 text
krobertson/deb-s3
Once we’ve built the package, we push it up to our private package repository. The repository itself is static files served over http. We host the package
repository on S3 so it is pretty fast and very reliable. The tool we use to manage the repository is deb-s3.
Slide 19
Slide 19 text
> apt-get update
To deploy the package we first need to update the list of known packages on each server.
Slide 20
Slide 20 text
> apt-get install foo
When we call the install command apt will recognize that a newer version of the package is available. It installs the newer version and restarts the
application using a configured post-install hook.
Slide 21
Slide 21 text
fast
reliable
low-impact
That’s an overview of how we do it. It works well for us because it’s fast, reliable, and low-impact.
Slide 22
Slide 22 text
fast
reliable
low-impact
It’s fast because when the deploy step happens we only need to copy the bits from the package repository and restart. This also really nice when we need
to scale up or replace a server. Rollbacks are fast too because the repository (or better yet, the local cache) has previous version so we can quickly roll back
to a previous version.
Slide 23
Slide 23 text
fast
reliable
low-impact
It is reliable because we’ve isolated our interaction with 3rd party services to the packaging step. We’re not making calls to fetch source code and gems
over X number of servers for each deploy. S3 is fairly reliable and the package repository has no moving parts so it makes a solid dependency. In the past
6 months we’ve not had an issue related to deploying the packages.
Slide 24
Slide 24 text
fast
reliable
low-impact
It’s low-impact because we don’t actually need to do any work on the servers (ex. compiling assets or installing gems, etc).
Slide 25
Slide 25 text
Thank You
We’re hiring!
lonelyplanet.com/jobs
I hope that gives you some ideas of how to optimize your deployment process. For me, the big takeaway (whether you use packages or not) is to focus on
making your deployment fast, reliable, and low-impact. Thank you for letting me describe this process. I’d love to hear any feedback or questions you
might have for me.