• Stars
    star
    498
  • Rank 88,494 (Top 2 %)
  • Language
    Elixir
  • Created over 8 years ago
  • Updated over 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Deployment tool for Phoenix apps

Gatling

Build Status Hex Version

Conveniently deploy a bunch of Phoenix apps

The main goal of Gatling is to make it very easy, cheap, and convenient to deploy Phoenix apps.

Gatling is essentially a collection of mix tasks that (from a Git push) automatically create a Distillery release and launches/upgrades it on your server.

Changelog

  • v1.1.1 fixes deployment regressions introduced with v1.1.0
  • v1.1.0 catches up with a changed default build directory in Distillery
  • v1.0.0 switches from Exrm to Distillery for packaging releases

For more information see the detailed changelog.

Gatling, Distillery and Nginx

As you read through the instructions, keep in mind that both Distillery and Nginx have tons of options you can configure outside of Gatling. Gatling's goal is to offer an out-of-the-box solution that keeps out of the way of your custom deployment strategy. For example, Distillery requires a configuration file in ./rel/config.exs of your project. There is a lot you can do with this but if you decide not to install this yourself, Gatling will generate a basic one for you.

Please see the Distillery docs to unlock the full power of your releases. Gatling simply triggers them in a convenient way.

Instructions

Setting up the server

This has been tested on an Ubuntu 16.04 x64 server on Ec2 and Digital Ocean.

Install Elixir, Nginx, and the Gatling archive on your server:

$ ssh server.address

Follow instructions here to install Elixir.

$ sudo apt-get install nginx git
$ mix archive.install https://github.com/hashrocket/gatling_archives/raw/master/gatling.ez

If needed, install hex and rebar:

mix local.hex
mix local.rebar

Deploying your app

For a brand new project, SSH into your server and run the following:

$ mix gatling.load {mix project name}

This only creates git repository on your server. Remember, when pushing to this repository, it would be [email protected]_server:<project name> e.g. for a Digital Ocean box, you would push to [email protected]:sample_project

Ensure your Elixir project can build a production release with Distillery.

Add a file to the root of your project named domains and list all domains that will point to this project. See an example here.

In your config/prod.exs, ensure your port configuration uses an environment variable called PORT (Gatling will set this for you automatically):

config :my_app, MyApp.Endpoint, [
 http: [port: {:system, "PORT"}],
 # root: ".", # add if using Phoenix
 # server: true, # add if using Phoenix
 # url: [host: "www.yourdomain.com"], # add if using Phoenix
]

config :phoenix, :serve_endpoints, true # uncomment if your using Phoenix

Setup your Git remote and push to your server:

$ git remote add production user_with_root_access@<address.to.server>:<project_name>
$ git push production master

SSH back into your server and ensure you have your secret.exs file(s) installed if needed.

Set your environment to prod by adding the following to /etc/environment:

$ MIX_ENV=prod

For the initial deploy, run $ sudo --preserve-env mix gatling.deploy {project_name} and Gatling will do the following:

  • Create a distillery release and put all the parts in the right place
  • Find an open port, configure Nginx to proxy to your app
  • Create an init.d file so your app will boot if/when your server restarts

Performing hot upgrades to your running application

Once your app is running do the following:

  • Increase the version number of your application. See here for an example to automatically increase the version number along with your commit
  • Commit your new changes
  • git push path.to.remote:project

And that's it! You'll see the new version being deployed with no downtime!

Callbacks

Gatling.Tasks.Deploy

In your project root, create a file called deploy.exs. Define any of the following functions to wrap the Gatling deployment actions:

defmodule SampleProject.DeployCallbacks do
  import Gatling.Bash

  def before_mix_deps_get(env)
  def after_mix_deps_get(env)

  def before_mix_compile(env)
  def after_mix_compile(env)

  def before_mix_digest(env)
  def after_mix_digest(env)

  def before_mix_release_init(env)
  def after_mix_release_init(env)

  def before_mix_release(env)
  def after_mix_release(env)

  def before_make_deploy_dir(env)
  def after_make_deploy_dir(env)

  def before_copy_release_to_deploy(env)
  def after_copy_release_to_deploy(env)

  def before_expand_release(env)
  def after_expand_release(env)

  def before_install_init_script(env)
  def after_install_init_script(env)

  def before_mix_ecto_setup(env)
  def after_mix_ecto_setup(env)

  def before_start_service(env)
  def after_start_service(env)

  def before_configure_nginx(env)
  def after_configure_nginx(env)

end

Note: the env is passed to every function. It is a READ only struct you can use. Returning env from a callback function will have no effect on the rest of the deployment process. Here is an example of the env that is passed in.

Gatling.Tasks.Upgrade

In your project root, create a file called upgrade.exs. Define any of the following functions to to wrap the Gatling upgrade actions:

defmodule SampleProject.UpgradeCallbacks do
  import Gatling.Bash

  def before_mix_deps_get(env)
  def after_mix_deps_get(env)

  def before_mix_compile(env)
  def after_mix_compile(env)

  def before_mix_digest(env)
  def after_mix_digest(env)

  def before_mix_release_init(env)
  def after_mix_release_init(env)

  def before_mix_release(env)
  def after_mix_release(env)

  def before_make_upgrade_dir(env)
  def after_make_upgrade_dir(env)

  def before_copy_release_to_upgrade(env)
  def after_copy_release_to_upgrade(env)

  def before_upgrade_service(env)
  def after_upgrade_service(env)

end

Note: the env is passed to every function. It is a READ only struct you can use. Returning env from a callback function will have no effect on the rest of the upgrade process. Here is an example of the env that is passed in.

System Commands In Your Callbacks

While implementing your callback functions. If you are going to use System.cmd/3, you can instead add import Gatling.Bash to the top of your module and use bash/3 to get a more transparent output.

Example

Deploy Callbacks

Say I want to install wget before my dependencies are installed in the deploy task. Also I want to avoid complaints about the priv/static directory not existing. I would create a file in my project called ./deploy.exs with the following:

defmodule SampleProject.DeployCallbacks do
  import Gatling.Bash

  def before_mix_deps_get(_env) do
    bash("sudo", ~w[apt-get install wget])
  end

  def before_mix_digest(env) do
    # optional: release may complain about this directory not existing
    bash("mkdir", ~w[-p priv/static], cd: env.build_dir)

    # you might also want to add the asset compiling here.
    # see the upgrade example below for details.
  end

end

This wget install function will be called right before mix deps get and the mkdir will happen before mix phoenix.digest.

Upgrade Callbacks

Say I want the server to run npm install and recompile assets as well as migrate on upgrade:

defmodule SampleProject.UpgradeCallbacks do
  import Gatling.Bash

  def before_mix_digest(env) do
    bash("npm", ~w[install], cd: env.build_dir)
    bash("npm", ~w[run deploy], cd: env.build_dir)
  end

  def before_upgrade_service(env) do
    bash("mix", ~w[ecto.migrate], cd: env.build_dir)
  end

end

Guides and Resources

Development

$ git clone https://github.com/hashrocket/gatling.git
$ cd gatling
$ mix deps.get
# Clone the archives repo
$ git clone https://github.com/hashrocket/gatling_archives.git

Releases

To create a new release, take the following steps:

  1. Bump your version number in mix.exs
  2. git add . && git commit -m 'Bump to v<version>'
  3. $ MIX_ENV=prod mix do compile, build
  4. $ cd gatling_archives
  5. $ git add .
  6. $ git commit -m "Release v<version>" && git tag v<version>
  7. $ git push origin master && git push origin --tags
  8. $ cd ../ && git tag v<version>
  9. $ git push origin master && git push origin --tags

About

Hashrocket logo

Gatling is supported by the team gatling_archives Hashrocket, a multidisciplinary design and development consultancy. If you'd like to work with us or join our team, don't hesitate to get in touch.

More Repositories

1

decent_exposure

A helper for creating declarative interfaces in controllers
Ruby
1,799
star
2

tilex

Today I Learned
Elixir
495
star
3

ws

websocket command line tool
Go
425
star
4

websocket-shootout

A comparison of websocket servers in multiple languages and frameworks
JavaScript
417
star
5

dotmatrix

Hashrocket Dot Files
Vim Script
363
star
6

hr-til

Today I Learned in Ruby
Ruby
341
star
7

slurper

Gem for slurping plain text stories into Pivotal Tracker
Ruby
127
star
8

view_specify

Auto-generate RSpec view specs by interrogating your existing views.
Ruby
55
star
9

unencumbered

Just enough Cucumber in RSpec.
Ruby
53
star
10

capybara-webmock

Mock external requests for Capybara JavaScript drivers
Ruby
48
star
11

mousetrap

CheddarGetter API Client in Ruby
Ruby
34
star
12

namecheap

ruby namecheap API wrapper
Ruby
32
star
13

coming-soon

App to register emails addresses. Intended as a coming soon, pre-launch, splash page.
JavaScript
27
star
14

acts_as_featured

Ruby
25
star
15

design_patterns_in_ruby

Wherein we reimplement the design patterns from the _Design Patterns in Ruby_ book, by Russ Olsen.
Ruby
25
star
16

vim-hashrocket

Mappings we find useful
Vim Script
23
star
17

localpolitics.in

Hashrocket's Martin Luther King Jr. Memorial 2009 Hack Day Apps for America Celebrity Rabies Awareness Pro-Am Fun Run Race For The Cure
JavaScript
18
star
18

terraformation

Generators with a Hashrocket twist
Ruby
15
star
19

vim-macdown

write markdown in Vim with live-reloads in MacDown
Vim Script
14
star
20

hashrocket-rails

Rails engine & generators for bootstrapping a Hashrocket project
Ruby
12
star
21

slack-command-api

A Sinatra API for processing custom Slack commands
Ruby
12
star
22

boot_devcards_example

Example of using devcards with boot
Clojure
10
star
23

graphql_way_rails

This is a Proof of Concept Rails project using GraphQL
Ruby
6
star
24

wowza

Ruby wrapper around the Wowza REST API
Ruby
5
star
25

hr_hotels

Example database for hotels.
Ruby
5
star
26

hr

Hashrocket Sub
Ruby
5
star
27

ecto_pg_extras

A collection of custom functions for PostgreSQL features in Ecto
Elixir
4
star
28

my_emma

Ruby wrapper for the MyEmma Remote Signup API
Ruby
4
star
29

university-bookstore

Hashrocket Training Project for Pre-RailsConf 2010 Workshop
Ruby
4
star
30

hashrocket-vr-example

JavaScript
3
star
31

dibs-ios

An iOS client for the Dibs "Online classifieds without the strangers" web application.
Objective-C
3
star
32

OffBot

🔌 🤖 Timely slack notifications for scheduled holidays and vacations
Ruby
3
star
33

learn_to_program

Curriculums and Programs for Teaching people how to build web applications
Ruby
2
star
34

concepts

A gallery for our side projects
JavaScript
2
star
35

wowza-webhooks

Java
2
star
36

vim-hr-psql

Open psql formatted table definitions from Vim Postgres
Vim Script
2
star
37

chime

Chimes in the Chicago office when someone comes in the front door
Arduino
1
star
38

hacktive

Github activity tracker
Ruby
1
star
39

homebrew-formulas

Hashrocket homebrew formulas
Ruby
1
star
40

spices

Ruby
1
star
41

metro_relic

Easily track custom newrelic metrics with a config file
Ruby
1
star
42

vostok

The Hashrocket middleman template
CSS
1
star
43

trybool

The value parsing tool to return a boolean that you never knew you needed!
Ruby
1
star
44

homebrew-fdw

FDW formulas for Homebrew package manager
Ruby
1
star
45

scored

Simple iPhone app
Objective-C
1
star
46

hashshake

Hashrocket shakes hands 🤝
Ruby
1
star