Building services

We now know how to run and stop services. But how to actually build them? Before we build one from scratch, let's start with modifying our example service a little bit. Instead of showing environment variables in random order we will return them in an ordered manner sorted by variable name.

$ mkdir -p /tmp/example ; cd /tmp/example ; curl -sLO http://armada.sh/intro/example.zip ; unzip example.zip
Archive: example.zip inflating: Dockerfile creating: src/ inflating: src/app.js ...(skipped)...
/tmp/example$ vim ./src/routes/index.js
...edit file... exports.index = function(request, response) { var output = ''; Object.keys(process.env).sort(). forEach(function(var_name) { output += ' "' + var_name + '": "' + process.env[var_name] + "\"\n"; }); response.send(output); };

Our change is in place, we'll now use another Armada command to build new service image:

/tmp/example$ armada build example
Pulling repository dockyard.armada.sh/microservice_node b1c1208331bb: Download complete 511136ea3c5a: Download complete ...(skipped)... Removing intermediate container ddb95e1eddb0 Removing intermediate container b9b891eb90ce

If you used docker before, this kind of output should look familiar. In fact what we did now is we've built a new docker image containing our modified service. This time, to run it we'll use a new parameter -d local. It prevents Armada from downloading service image from its default repository. Rather it will use the image we've just built that resides on your local docker repository.

/tmp/example$ armada run example -d local
Running microservice example from dockyard: (alias: local) locally... Service is running in container efe0e1ab41e5 available at addresses: 192.168.3.141:49156 (80/tcp)
/tmp/example$ curl 192.168.3.141:49156
"CEREBRO_BASIC_APT_GET_UPDATE_DATE": "2014-07-14" "HOME": "/" "HOSTNAME": "efe0e1ab41e5" "MICROSERVICE_APT_GET_UPDATE_DATE": "2014-08-11" "MICROSERVICE_NAME": "example" ...(skipped)... "SUPERVISOR_SERVER_URL": "unix:///var/run/supervisor.sock"

Indeed the output is now sorted!

As you can see modifying existing service, running it, and verifying changes is a matter of few simple steps. You don't have to install the entire environment required by the service in your system which is often very time-consuming and can leave unnecessary mess. Also, sometimes it can be almost impossible when services have conflicting requirements (different glibc versions etc.). With docker it's no more the case.

Dockyard - service image repository

Another concept that we've mentioned before is service image repository - a place where you store all your service images ready to be deployed. Armada uses docker repositories which we conveniently call dockyards. You can use your existing docker repository if you have one or create your own using helper Armada service.

$ armada run dockyard -v /tmp/mydockyard:/repository -p 10000:80
Running microservice dockyard from dockyard: dockyard.armada.sh (alias: armada) locally... Service is running in container 27cc85f15888 available at addresses: 192.168.3.141:10000 (80/tcp)

We have added parameter -p 10000:80, because this time we want the dockyard to be available at constant address (port 10000), not at some random port assigned by docker.

Parameter -v works the same way as in docker. That means directory /tmp/mydockyard from your machine will be mapped to directory /repository inside dockyard service that we've just run.

It's important to remember that containers running our services don't maintain their state after stopping them. In order to preserve data produced by the service (in our case it's a repository of service images) we can mount directories from inside container to your host machine.

Let Armada know about our newly created repository.

$ armada dockyard set myrepo 192.168.3.141:10000
Warning! Your dockyard alias has been set BUT: If you are trying to use dockyard using HTTP protocol make sure that its address is added to docker insecure registries list, e.g.: echo DOCKER_OPTS=\"\$DOCKER_OPTS --insecure-registry 192.168.3.141:10000\" | sudo tee --append /etc/default/docker sudo service docker restart sudo service armada restart All docker containers will be stopped! armada services will be restarted.

The warning message above tells us that the image repository we're going to use is not trusted. It is served with non-secure HTTP protocol, not using any SSL certificates. If we want Docker to be able to push/pull to this repository we have to add it to the "insecure-registry" list.

The easiest way to do it is by running those 3 above commands that Armada conveniently prepared for us. After running them, we can try:

$ armada dockyard list
Default Alias Address User Password armada dockyard.armada.sh -> myrepo 192.168.3.141:10000

Using command armada dockyard list we can see a list of image repositories which Armada knows about. You can have as many repositories as you need, for example local company repository and remote production repository.

First listed repository (alias armada) is a public Armada repository that contains a number of helper services (such as already known example, dockyard) and armada itself. That's where we were downloading those services from in previous parts.

After adding our new repository, Armada has set it to default (-> sign), which means armada run will look for service images there in the first place.

But first, we have to upload something there.

$ armada push example
Pushing microservice example to dockyard: 192.168.3.141:10000... The push refers to a repository [192.168.3.141:10000/example] (len: 1) Sending image list Pushing repository 192.168.3.141:10000/example (1 tags) 511136ea3c5a: Image successfully pushed ...(skipped)... 43e83b0e7d58: Image successfully pushed e66bb335bef7: Image successfully pushed Pushing tag for rev [e66bb335bef7] on {http://192.168.3.141:10000/v1/repositories/example/tags/latest}

If you want to upload image to dockyard which is not currently default, you can use -d parameter, e.g. armada push example -d production_aws.

We can check that the image is in fact stored on our machine:

$ ls -l /tmp/mydockyard/repositories/library/
total 4 drwxr-xr-x 2 root root 4096 Oct 14 08:52 example

Upgrading services

Now, instead of simply running the service, let's do something different. Let's try to upgrade one of our example services run in previous parts. Remember?

$ armada list
Name Address ID Status Tags armada 192.168.3.141:49153 ae148a2d3a1a passing - dockyard 192.168.3.141:10000 27cc85f15888 passing - example 192.168.3.141:49156 efe0e1ab41e5 passing - example 192.168.3.141:49158 a9992ef1f772 passing - example 192.168.3.141:49160 f7a09fb19009 passing ['env:funny-service']

Upgrading a service can be as simple as restarting it with newly built image.

$ armada restart f7a
Restarting service f7a... Service has been restarted and is running in container 50d6e904a684 available at addresses: 192.168.3.141:49160 (80/tcp)
$ curl 192.168.3.141:49184
"CEREBRO_BASIC_APT_GET_UPDATE_DATE": "2014-07-14" "HOME": "/" "HOSTNAME": "50d6e904a684" "MICROSERVICE_APT_GET_UPDATE_DATE": "2014-08-11" "MICROSERVICE_ENV": "funny-service" "MICROSERVICE_NAME": "example" ...(skipped)... "SUPERVISOR_SERVER_URL": "unix:///var/run/supervisor.sock"

The results are now sorted, and we can see that the variable MICROSERVICE_ENV is preserved. The same would be true for other parameters supplied for the first time that we started this service.

To sum it up, upgrading a service with Armada is a breeze!

Now, how about creating new one?