Deploying Dart to Google Compute Engine

With continuous integration and deployment using Codeship!

You'll notice that there aren't a lot of documented ways to deploy Dart onto Google's cloud. App Engine has no support and Managed Vm while technically supports Dart, it's not out of beta yet, so I don't trust it.

One way to deploy Dart to your server is to install Dart, FTP stuff over and run dart bin/server.dart.

I personally hate this method, I like having everything automated and tested before it's deployed.

I want to commit stuff to the master branch 100x a day, run 100 unit tests for each of those commits, and if all pass, then I want the code to automatically be deployed to production.

How do we achieve this Dart deployment nirvana? Lets assume you have your Dart server app ready and have some sort of unit tests in place (even if you don't it's OK!, just skip the continuous integration part of this tutorial)

This tutorial is lengthy, if you get lost please leave some feedback on where I can make this better!

The first step is to get some sort of CI (Continuous Integration) system running. This will run your tests whenever you push to your github or bitbucket repository.

One of the best CI tool's I've used in recent times is Codeship.

Codeship.com

Setting up Dart on Codeship

When you signup to Codeship, connect your Github or Bitbucket account. When it comes time to configure your project, select Dart as the technology.

Be warned that the current Codeship SDK is outdated, so you'll have to install a recent version of Dart during configuration.

wget <https: storage.googleapis.com="" dart-archive="" channels="" stable="" release="" latest="" sdk="" dartsdk-linux-x64-release.zip="">  
unzip -o dartsdk-linux-x64-release.zip -d ~  
pub get

This is just telling Codeship to download the latest sdk, unzip it and run pub get on it.

Next if you have unit tests, you can tell Codeship to run them in the Test Configuration Pipeline section.

For now all I have here is dart test/all.dart which runs my Dart unit tests.

Click save, go to dashboard and follow the on-boarding steps to push your project. Ignore any deployment options it may ask you, we will revisit that shortly.

Do a git push to your master branch and let codeship do it's magic. If all works well you'll see this.

If it fails, see what test is failing and fix it. This is the first (if not last) line of defense before going production so make sure it passes!

Great, CI is now setup!

Cool, so now CI is setup and good to go. You write code, you push, your tests run, if all goes well Codeship gives you the green and you are in the clear.

Now what? How do I deploy this to Google Compute Engine (GCE)

Setting up GCE for Dart

I'm going to assume you don't have a GCE server setup. Lets walk you through this.

Go to console.developers.com and create a new project for your Dart application. Click the blue New Project button top left.

In the sidebar on the left, click on VM Instances.

And click on New Instance.

Setup your new instance by following the screenshot below. For testing purposes we will use the micro instance with ubuntu 14.04LTS.

Don't hit create just yet! follow along after the screenshot

Before you hit Create, click on the Management Disk, networking, access & security options blue link.

Then click on Access & Security and add in your public ssh key here.

To get your ssh key on mac try the command below. It should typically show your public key

cat ~/.ssh/id_rsa.pub

Once you have it, put it in the box and the username box will automatically populate.

After this, you are good to go. Your username to login to ssh with is shown. Click create and watch it go!

After a minute or two and you will see your dashboard with your awesome new GCE server running.

Setting up Docker on your GCE machine

Docker is an easy way to run your application inside virtualized secure containers. Gone are the days where you pollute the host system with software, now you just have a single contained Docker instance that contains your application and all of it's dependencies.

Installing Docker on your GCE machine is straight forward.

SSH into your machine,

ssh (username)@ip

and follow the steps below

Installing Docker on Ubuntu

Make sure you have installed the prerequisites for your Ubuntu version. Then, install Docker using the following steps taken from

Verify that you have wget installed.

$ which wget

If wget isn't installed, install it after updating your manager:

$ sudo apt-get update $ sudo apt-get install wget

Get the latest Docker package.

$ wget -qO- <https: get.docker.com=""> | sh

The system prompts you for your sudo password. Then, it downloads and installs Docker and its dependencies.

Verify docker is installed correctly.

$ sudo docker run hello-world

This command downloads a test image and runs it in a container.

Perfect. if you followed along and all this works, you are doing great!

Preparing GCE to accept Codeship Deployments

Now before we leave ssh land, go to your home directory (~/) and create a folder called dart. (mkdir dart)

In a new tab, go back to Codeship, go to project settings and click on general.

Grab Codeship's public ssh key from here. This will let Codeship deploy to your server easily.

Then back in your terminal, open up allowed_hosts in .ssh and paste that key from codeship in

vim ~/.ssh/allowed_hosts

Boom!

To recap, you've setup Docker and allowed Codeship to access your GCE. This will let it do continuous deployments, which we will setup next.

Setting up your Dart app to support Docker

In order to let Docker know about your application, you need to setup a Dockerfile. A Dockerfile is a simple script which tells Docker what to install, how to run your application, and what ports to expose. Create a Dockerfile at the root of your project directory.

Our Dart specific Dockerfile looks like the following.

FROM google/dart

WORKDIR /app

ADD pubspec.* /app/

RUN pub get

ADD . /app

RUN pub get — offline

CMD []

EXPOSE 3030

ENTRYPOINT ["/usr/bin/dart", "bin/server.dart"]

FROM google/dart is telling Docker that we want to use the google/dart docker base image. More details about that can be found here

*WORKDIR /app *is creating a directory called app in your Docker container.

*ADD pubspec. /app/ **is adding the pubspec file to the app folder.

RUN pub get is running pub get.

ADD . /app is adding the rest of your files to the app directory

We run pub twice, find out why

next we expose port 3030. If your application is using a different port, then change it here.

Lastly we tell Docker how to run our app via ENTRYPOINT. By executing the dart command with the file as the argument.

Commit this and push it. Since we haven't made any code changes, your unit tests should pass and Codeship should give you a green.

Next up, time to deploy this!

Continuous deployment to GCE with Codeship

In Codeship, go to project settings and deployment.

Click custom script as your deployment pipeline

Here you will see a box to type in your deployment script. The script is easy, contains just a few commands.

First, rsync -av copies all the files from the clone directory which Codeship creates on every push, into your dart folder that we previous created on your host GCE system.

Next we run some commands over ssh. The commands are we run basically cd into the dart directory, build the docker image, stop all previously running docker instances and run the docker app on port 3030 binding to port 3030 inside the image.

rsync -av ~/clone/ [email protected]:dart

ssh [email protected] 'cd dart &amp;&amp; docker build -t app . &amp;&amp; docker stop $(docker ps -a -q) &amp;&amp; docker run -d -p 3030:3030 app'

Command summary

cd dart   
#change into the dart folder that has all the source code

docker build -t app .    
#build the current folder into an image called app

docker stop $(docker ps -a -q)   
#stop all currently running docker instances

docker run -d -p 3030:3030 app   
#run the newly created app image. binding to port 3030 on host system to port 3030 in docker image

Remember if you used a different port, or want to bind to a different port on your host system, change that in the script.

Testing it all together now

It's time we test the whole flow now. The easiest way to do that is just hit restart build in Codeship.

Hitting restart will run all your unit tests. If they pass, it'll run your deployment workflow and voila! Visit your ip:port and you'll see your Dart application running!

Summary

A bit lengthy but a worthwhile process. This will save you countless hours in the future when you are making quick changes to your system friday night and want to deploy it. Codeship makes it easy to ensure that your code won't blow up in production, and Dart combined with the power of GCE will make your applications fly.