From 90c584436227c225f784c6d2cd1bb51351730b07 Mon Sep 17 00:00:00 2001 From: Ariejan de Vroom Date: Fri, 1 Nov 2013 09:29:30 +0100 Subject: [PATCH] Deploying with git-deploy --- content/css/_pygments.scss | 4 +- content/css/screen.sass | 3 + .../2013-10-31-deploying-with-git-deploy.md | 209 ++++++++++++++++++ 3 files changed, 214 insertions(+), 2 deletions(-) create mode 100644 content/posts/2013-10-31-deploying-with-git-deploy.md diff --git a/content/css/_pygments.scss b/content/css/_pygments.scss index a7a3171..6ba43c7 100644 --- a/content/css/_pygments.scss +++ b/content/css/_pygments.scss @@ -4,10 +4,10 @@ pre, .plaincode{ border-radius: none; font-size: 12px; - overflow: visible; + overflow: auto; padding: 6px 6px; - margin: 0; + margin: 0 0 10px 0; word-break: normal; word-wrap: normal; diff --git a/content/css/screen.sass b/content/css/screen.sass index b37b704..d8a960e 100644 --- a/content/css/screen.sass +++ b/content/css/screen.sass @@ -24,6 +24,9 @@ h1, h2, h3, h4, h5, h6 font-weight: 400 -webkit-font-smoothing: antialiased +code + font-size: 12px + #header border-top: 3px solid $focus-color diff --git a/content/posts/2013-10-31-deploying-with-git-deploy.md b/content/posts/2013-10-31-deploying-with-git-deploy.md new file mode 100644 index 0000000..816195a --- /dev/null +++ b/content/posts/2013-10-31-deploying-with-git-deploy.md @@ -0,0 +1,209 @@ +--- +title: "Deploying with git-deploy" +kind: article +created_at: 2013-10-31 +tags: + - deployment + - git + - rails + - devops +summary: | + I've blogged before about deploying Rails applications. Normally I opt for using capistrano, + but it turns out git-deploy is a light-weight, but worthy alternative. +--- + +I've blogged before about deploying Rails applications. Normally I opt for using capistrano, as it provides all the features I need and is pretty easy to customize if needed. + +One of my previous strategies was to use capistrano to checkout a branch on a remote server, and `git fetch` that branch upon a new deployment. + +The problem with capistrano, however, is that it can be quite slow from time to time. It also has a lot of features I never or only rarely use, like multi-host deployments. + +A few days ago someone pointed out [git-deploy](https://github.com/mislav/git-deploy) to me. I tried it out and it is _fantastic_. Let me explain that. + +## Light-weight + +What could be the easiest way to deploy an app? + + * SSH to the server + * Fetch code changes + * `bundle install`, `rake db:migrate`, `rake assets:precompile` + * Restart + +Yes, you could write a script to do all that, but there's an even easier way: git hooks. + +Git hooks are triggered after certain events on a git repository. In this case, the flow becomes: + + * Push code to server + +In the git hooks, we still need to handle: + + * `bundle install`, `rake db:migrate`, `rake assets:precompile` + * Restart + +Now, here comes `git-deploy`. What it does is add a few scripts to your project. Setup is rather easy: + + # Install the gem, no need for Gemfile. + gem install git-deploy + + # Add a git remote to your server + git remote add production "user@server.com:/home/myapp/app" + + # Setup deployments + git deploy setup -r production + + # Generate deploy scripts (locally) + git deploy init + +After this, you should find the following files in `deploy/`: + + * `after_push` + * `before_restart` + * `restart` + +The filenames are self explanatory, but here's a quick run through: + +**`after_push`** + +This file is run after you've pushed your code to the remote server. It gathers some information about your changes, sets up the environment and kicks of the other two scripts. + +**`before_restart`** + +Before you can restart your server, you will probably need to update some things. By default git-deploy will check if it needs to run migrations, perform a `bundle install` and precompile your assets. + +**`restart`** + +Does exactly what it says, it will restart your Rails app. By default it's configured for Passenger, so it simply touches `tmp/restart.txt`. + +## Server setup, RVM and Sidekiq + +What follows is a step-by-step guide of how I setup a new server. In this case for a project using ruby-2.0 with RVM and Sidekiq for background processing. + +**0. Set your RAILS_ENV** + +I always declare `RAILS_ENV` en `/etc/environment`. This file gets loaded everywhere and saves you the headache of adding this env variable with every rails command you execute later. + +I also set my editor here, so I'm not surprised by nano when doing `visudo` or `crontab -e`. + + RAILS_ENV=production + RACK_ENV=production + EDITOR=vi + +**1. Create a user for the app** + + adduser myapp + +**2. Add user to sudoers** + + sudo vi /etc/sudoers + + # Add the following line: + myapp ALL=(ALL) NOPASSWD: ALL + +**3. Setup SSH Keys** + +In this case all you need to do is add your own public key(s) to `/home/myapp/.ssh/authorized_keys`. + +**4. Setup RVM for `myapp`** + +I prefer to setup RVM for the specific user (instead of system-wide). The following command will directly install the latest ruby as well. + + \curl -L https://get.rvm.io | bash -s stable --ruby + +**5. Apache + Passenger** + +Then I setup Apache with Passenger. It's fine if you want to use Nginx instead. + + sudo apt-get install libcurl4-openssl-dev apache2-mpm-worker libapr1-dev libaprutil1-dev apache2-threaded-dev + gem install passenger + passenger-install-apache2-module + +Just follow the instructions of the Passenger install script. Depending on your system configuration, you may be asked to add some (temporary) swap space. + +Passenger will spit out three lines that you should add to the bottom of `/etc/apache2/apache2.conf`: + + LoadModule passenger_module /home/myapp/.rvm/gems/ruby-2.0.0-p247/gems/passenger-4.0.21/buildout/apache2/mod_passenger.so + PassengerRoot /home/myapp/.rvm/gems/ruby-2.0.0-p247/gems/passenger-4.0.21 + PassengerDefaultRuby /home/myapp/.rvm/wrappers/ruby-2.0.0-p247/ruby + +**6. Configure Apache VirtualHost** + +Next, create and enable an Apache virtual host for your app: + + + ServerName myapp.example.com + DocumentRoot /home/myapp/app/public + + AllowOverride all + Options -MultiViews + + + +And enable it: + + sudo ln -sf /etc/apache2/sites-available/myapp.example.com /etc/apache2/sites-enabled/010-myapp.example.com + service apache2 restart + +**7. Install your database, tools, etc.** + +Install postgres, redis or whatever rocks your boat. Make sure to also install the proper tools (like imagemagick) and development headers. + +Also make sure that you update `config/database.yml` in your project and commit these changes and the files in `deploy`. + +I'm assuming you also create a database now, as we won't be running `rake db:create` later on. + +**8. Add foreman for Sidekiq** + +I want to use foreman to manage starting/stopping sidekiq. Add foreman to your `Gemfile`: + + gem 'foreman' + # Optional, but works well with a Debian server + gem 'foreman-export-initscript' + +And add a line to `Procfile`, of course, add any parameters you need for running sidekiq here. + + worker: bundle exec sidekiq + +**9. Enable RVM for git-deploy** + +In order to use RVM and `rvmsudo` properly, we need to set that up in `deploy/after_push`. Add the following lines before the `run` commands at the bottom. + + export rvmsudo_secure_path=1 + PATH=$PATH:$HOME/.rvm/bin + +**10. Sidekiq deploy configuration** + +There are two things we need to do. Firstly, we need to generate an initscript with foreman. We do this in `deploy/before_restart`: + + run "rvmsudo bundle exec foreman export initscript /etc/init.d -a myapp -u myapp -l /var/log/myapp" + run "rvmsudo chmod +x /etc/init.d/myapp" + +Secondly, we need to use this initscript to actually restart Sidekiq in `deploy/restart`: + + echo "restarting foreman" + sudo /etc/init.d/myapp restart + +**11. Ready? Deploy it!** + +Now, deploying is rather easy: + + git push production master + +That's it. + +## Future deployments + +Well, from now on you can simply push your code with git and `git-deploy` will take care of it all: + + git push production master + +A few things to keep in mind: + + * You don't need the `git-deploy` gem installed to deploy your project. + * Keep your `deploy/` scripts up to date and under version control. + * Anyone with SSH access to your server can deploy the project. + +## Conclusion + +I think that capistrano is a fine tool, but for many projects it's overkill. `git-deploy` is light weight and easy to use and gets the job of deploying your app done quickly. It's also easily extendable, if you need it. + +Give it a try. You can easily spin up a VPS over at [Digital Ocean](http://aj.gs/digitalocean) to play around or host your next awesome project. (Disclaimer: referral link). If you use Digital Ocean, you may also be interested in my iOS App: [Binary Deep](http://aj.gs/binary-deep).