{"id":2157,"date":"2015-10-30T16:34:28","date_gmt":"2015-10-30T23:34:28","guid":{"rendered":"https:\/\/www.microsoft.com\/reallifecode\/index.php\/2015\/10\/30\/streamlined-dokku-deployment-on-azure\/"},"modified":"2020-03-18T15:32:07","modified_gmt":"2020-03-18T22:32:07","slug":"streamlined-dokku-deployment-on-azure","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/ise\/streamlined-dokku-deployment-on-azure\/","title":{"rendered":"Streamlined Dokku Deployment on Azure"},"content":{"rendered":"<p><a href=\"http:\/\/github.com\/progrium\/dokku\">Dokku<\/a> is one of the most popular application frameworks for deploying apps for development and testing. With the tiny amount of code that is Dokku, you can git-push any application or any Dockerfile. It\u2019s <em>almost<\/em> magic.<\/p>\n<p>Dokku is powered by Docker, and automatically builds a Docker image for any application you push to it. These apps can be linked to databases which can also run as local containers using container linking.<\/p>\n<p>Previously, Dokku wasn\u2019t very straightforward to install on Azure. It required you to create a virtual machine, a public IP, and a VNET, then run the installation.<\/p>\n<p>We <a href=\"https:\/\/github.com\/progrium\/dokku\/pull\/1623\">worked directly<\/a> with the Dokku maintainers as well as <a href=\"https:\/\/github.com\/Azure\/azure-quickstart-templates\/pull\/757\">Azure engineering<\/a> to make the process as easy as possible.<\/p>\n<h2 id=\"deploying-dokku-to-azure---the-easy-way\">Deploying Dokku to Azure &#8211; The Easy Way<\/h2>\n<p>Now that we\u2019ve contributed an Azure Resource Manager (ARM) template to automagically create a Dokku instance, you can literally create a Dokku instance with just a few clicks. Just follow these steps:<\/p>\n<ul>\n<li><a href=\"https:\/\/help.github.com\/articles\/generating-ssh-keys\/\">Create an ssh key pair<\/a> using <code class=\"highlighter-rouge\">ssh-keygen<\/code>.<\/li>\n<li>Head over to the <a href=\"https:\/\/azure.microsoft.com\/en-us\/documentation\/templates\/dokku-vm\/\">Dokku deployment for Azure page<\/a> and click the pretty blue <strong>Deploy to Azure<\/strong> button.<\/li>\n<li>You\u2019ll be swept off to the <a href=\"https:\/\/portal.azure.com\">Azure Portal<\/a> to fill in the parameters to create the instance. You\u2019ll need a unique name for the <strong>NEWSTORAGEACCOUNTNAME<\/strong> and <strong>DNSNAMEFORPUBLICIP<\/strong> values:<\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2020\/03\/2015-10-26-Streamlined-Dokku-Deployments-ss1.png\" alt=\"Parameters Window\" \/><\/p>\n<p>After about 5 minutes, the Dokku instance will be up and running.<\/p>\n<h2 id=\"configuring-dokku\">Configuring Dokku<\/h2>\n<p>Now that the instance is up and running, we need to do a couple of tiny steps to get things working.<\/p>\n<p>First <a href=\"https:\/\/help.github.com\/articles\/generating-ssh-keys\/\">create another ssh key pair<\/a> for deploying Dokku applications.<\/p>\n<p>Then browse to your Dokku instance in your browser, which is this address:<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"highlight\"><code>http:\/\/[[DNSNAMEFORPUBLICIP]].[[LOCATION]].cloudapp.azure.com\r\n<\/code><\/pre>\n<\/div>\n<p>Where <code class=\"highlighter-rouge\">DNSNAMEFORPUBLICIP<\/code> and <code class=\"highlighter-rouge\">LOCATION<\/code> are the template variables you filled out. For example, if your <code class=\"highlighter-rouge\">DNSFORPUBLICIP<\/code> is \u2018helloauniquename\u2019 and your <code class=\"highlighter-rouge\">LOCATION<\/code> is \u2018West US\u2019 then your address would be:<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"highlight\"><code>http:\/\/helloauniquename.westus.cloudapp.azure.com\r\n<\/code><\/pre>\n<\/div>\n<p>When Dokku first starts up, it spins up a tiny web server which allows you to configure the deployment settings:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2020\/03\/2015-10-26-Streamlined-Dokku-Deployments-ss2.png\" alt=\"Dokku Configuration Page\" \/><\/p>\n<ul>\n<li>Copy and paste your SSH public key for Dokku deployments to the public key box.<\/li>\n<li>Check off \u2018Use virtualhost naming for apps\u2019.<\/li>\n<li>Thanks to the folks at <a href=\"http:\/\/xip.io\">xip.io<\/a> you can use your public IP as its own domain. Change your hostname to <code class=\"highlighter-rouge\">[[your azure public IP]].xip.io<\/code>. Check out your VM properties in the <a href=\"https:\/\/portal.azure.com\">Azure Portal<\/a> to find your VM\u2019s public IP address.<\/li>\n<\/ul>\n<h2 id=\"deploy-your-app\">Deploy Your App!<\/h2>\n<h3 id=\"create-a-rails-app\">Create a Rails App<\/h3>\n<p>Let\u2019s deploy a Rails application. Clone the Heroku rails example from github to your local machine:<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"highlight\"><code>git clone https:\/\/github.com\/heroku\/ruby-rails-sample.git\r\n<\/code><\/pre>\n<\/div>\n<p>SSH into the VM using the private key you generated to provision the VM:<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"highlight\"><code>ssh -i &lt;your-ssh-private-key&gt; your-admin-user-name@[[DNSNAMEFORPUBLICIP]].[[LOCATION]].cloudapp.azure.com\r\n<\/code><\/pre>\n<\/div>\n<p>Then create a new Dokku application:<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"highlight\"><code>dokku apps:create ruby-rails-sample\r\n<\/code><\/pre>\n<\/div>\n<h3 id=\"add-postgres\">Add Postgres<\/h3>\n<p>What\u2019s a Rails application without Postgres? We can easily add a <a href=\"https:\/\/github.com\/dokku\/dokku-postgres\">Postgres plugin<\/a> to create an instance and link it to the application we created:<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"highlight\"><code># install the postgres plugin\r\n# plugin installation requires root, hence the user change\r\nsudo dokku plugin:install https:\/\/github.com\/dokku\/dokku-postgres.git\r\n\r\n# create a postgres service with the name rails-database\r\ndokku postgres:create rails-database\r\n\r\n# each official datastore offers a `link` method to link a service to any application\r\ndokku postgres:link rails-database ruby-rails-sample\r\n-----&gt; Setting config vars\r\n       DATABASE_URL: postgres:\/\/postgres:ef081eb5672fcdc4d16e95d9805047cb@dokku-postgres-rails-database:5432\/rails_database\r\n-----&gt; Restarting app ruby-rails-sample\r\nApp ruby-rails-sample has not been deployed\r\n<\/code><\/pre>\n<\/div>\n<p>The new Postgres instance is created in another container on the Dokku host.<\/p>\n<h1 id=\"git-push\">Git-Push!<\/h2>\n<p>Finally, exit out of your VM and add a <code class=\"highlighter-rouge\">dokku<\/code> remote to your local repo using the <code class=\"highlighter-rouge\">dokku<\/code> username and push the app.<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"highlight\"><code>ssh-add &lt;your-dokku-deploy-private-key&gt;\r\ngit remote add dokku dokku@[[DNSNAMEFORPUBLICIP]].[[LOCATION]].cloudapp.azure.com\r\ngit push dokku master\r\n<\/code><\/pre>\n<\/div>\n<p>You\u2019ll start to see some remote output showing that Dokku detects a Rails application and starts to build a deployment image for Ruby:<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"highlight\"><code>Counting objects: 231, done.\r\nDelta compression using up to 8 threads.\r\nCompressing objects: 100% (162\/162), done.\r\nWriting objects: 100% (231\/231), 36.96 KiB | 0 bytes\/s, done.\r\nTotal 231 (delta 93), reused 147 (delta 53)\r\n-----&gt; Cleaning up...\r\n-----&gt; Building ruby-rails-sample from herokuish...\r\n-----&gt; Adding BUILD_ENV to build environment...\r\n-----&gt; Ruby app detected\r\n-----&gt; Compiling Ruby\/Rails\r\n-----&gt; Using Ruby version: ruby-2.2.1\r\n-----&gt; Installing dependencies using 1.9.7\r\n       Running: bundle install --without development:test --path vendor\/bundle --binstubs vendor\/bundle\/bin -j4 --deployment\r\n       Fetching gem metadata from https:\/\/rubygems.org\/...........\r\n       Fetching version metadata from https:\/\/rubygems.org\/...\r\n       Fetching dependency metadata from https:\/\/rubygems.org\/..\r\n       Using rake 10.4.2\r\n\r\n=====&gt; Application deployed:\r\n       http:\/\/ruby-rails-sample.40.118.253.250.xip.io\r\n<\/code><\/pre>\n<\/div>\n<p>After a short while, the application is deployed and at the end of the output you\u2019ll see its address. Browse to the provided URL at the end of the output and you\u2019ll see that your app is up and running:<\/p>\n<p><img decoding=\"async\" src=\"\/developerblog\/wp-content\/uploads\/2015-10-26-Streamlined-Dokku-Deployments\/ss3.png\" alt=\"Running Rails Example\" \/><\/p>\n<h1 id=\"what-else-does-it-do\">What Else Does it Do?<\/h2>\n<p>Despite being a single instance PaaS development playground, Dokku comes packed with features that can get you ready to scale up to a high-availability PaaS platform like <a href=\"http:\/\/deis.io\">Deis<\/a> with ease.<\/p>\n<h2 id=\"ssl-certificates\">SSL Certificates<\/h2>\n<p>Creating a self-signed or certificate signing request (CSR) is a cinch using the <code class=\"highlighter-rouge\">certs<\/code> plugin:<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"highlight\"><code>certs:generate &lt;app&gt; DOMAIN\r\ncerts:add &lt;app&gt; CRT KEY\r\n<\/code><\/pre>\n<\/div>\n<p>Checkout the <a href=\"http:\/\/dokku.viewdocs.io\/dokku\/deployment\/ssl-configuration\/\">official documentation<\/a> for more info on using SSL with Dokku apps.<\/p>\n<h2 id=\"load-balancing--routing\">Load Balancing &amp; Routing<\/h2>\n<p>Dokku can support any number of applications each backed by any number of containers. Out of the box, it comes with HTTP load balancing and routing thanks to <a href=\"http:\/\/nginx.com\">nginx<\/a>.<\/p>\n<p>This makes Dokku ideal for developing <a href=\"http:\/\/12factor.net\/\">12 factor applications<\/a> where applications can be horizontally scaled simply by adding more instances behind a load balancer.<\/p>\n<h2 id=\"zero-downtime-deployments\">Zero-downtime Deployments<\/h2>\n<p>Dokku also supports zero-downtime application deployments and will redirect traffic from old containers to new containers of an application.<\/p>\n<p>Here\u2019s an example that highlights this simple but super useful feature:<\/p>\n<p>Say you want to update the Rails application we just deployed. First add a file called <code class=\"highlighter-rouge\">CHECKS<\/code> to the root repo. This file instructs Dokku to wait 10 seconds to check the output of the new container, giving the application time to start up. If the check succeeds (when the <code class=\"highlighter-rouge\">GET \/<\/code> response contains \u2018Hello World\u2019) then Dokku will kill the old container and reroute traffic to the new ones.<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"highlight\"><code>\/                       Hello World\r\nWAIT=10     # Wait 10 seconds\r\nTIMEOUT=30  # Timeout after 30 seconds\r\n<\/code><\/pre>\n<\/div>\n<p>In one window we\u2019ll run a simple script that sends a request to the server continuously:<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"highlight\"><code>while true\r\ndo\r\necho =====================================\r\ncurl http:\/\/ruby-rails-sample.40.118.253.250.xip.io\/\r\necho =====================================\r\nsleep .8\r\ndone\r\n<\/code><\/pre>\n<\/div>\n<p>In the other, we\u2019ll perform the git-push deployment:<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"highlight\"><code>git push dokku master\r\n<\/code><\/pre>\n<\/div>\n<p>You can see from the animation below, that the script (left console) always receives a response, even though its continuously sending requests to the server. The console on the right is the Dokku output of the git-push.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2020\/03\/2015-10-26-Streamlined-Dokku-Deployments-ss4.gif\" alt=\"Animation of Zero-downtime deploy\" \/><\/p>\n<p>In the animation above, Dokku checks that the new container is up and running before redirecting traffic and killing the old one. The output seamlessly changes from <code class=\"highlighter-rouge\">Hello World 1.0<\/code> to <code class=\"highlighter-rouge\">Hello World 2.0<\/code> without a hitch!<\/p>\n<h1 id=\"useful-links\">Useful Links<\/h2>\n<p>Here are some useful links to get started:<\/p>\n<ul>\n<li><a href=\"http:\/\/progrium.viewdocs.io\/dokku\/getting-started\/install\/azure\/\">Official Dokku Azure Documentation<\/a><\/li>\n<li><a href=\"https:\/\/azure.microsoft.com\/en-us\/documentation\/templates\/dokku-vm\/\">Dokku Template Documentation<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Dokku is a very small PaaS implementation, powered by Docker.  In this code story, we walk through how to deploy Dokku on Azure, and how to use Dokku to deploy, load balance, and update a simple Rails app.<\/p>\n","protected":false},"author":21345,"featured_media":12804,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[16],"tags":[60,156,158],"class_list":["post-2157","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","tag-azure","tag-docker","tag-dokku"],"acf":[],"blog_post_summary":"<p>Dokku is a very small PaaS implementation, powered by Docker.  In this code story, we walk through how to deploy Dokku on Azure, and how to use Dokku to deploy, load balance, and update a simple Rails app.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/2157","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/users\/21345"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/comments?post=2157"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/2157\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media\/12804"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media?parent=2157"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/categories?post=2157"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/tags?post=2157"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}