Demystifying containers using Crystal, Amber, and Docker
Tags: docker, crystal, amber, beginners
Published: 2018-02-11 01:42:50

---
title: Demystifying containers using Crystal, Amber, and Docker
published: true
description: Once you understand how containers work, you'll never want to deploy your code differently.
tags: #docker, #crystal, #amber, #beginners
---

If you're like me, you have heard a lot about Docker and containerization, but haven't fully tapped into it's potential, or you aren't sure why or how it can fit your use cases.

Like with all new technologies, there comes a learning curve, and with Docker there exists a curve, but thankfully there is a TON of [documentation](https://docs.docker.com/) to help reduce the curve.

I'm going to try and explain things like I'm not a super duper noob, but this post is going to assume that you know Amber and Crystal well enough to make small changes to a web application. If you need to learn more about Amber and Crystal, I would highly recommend looking at the posts that [Elias Perez](https://dev.to/eliasjpr) has made, as they're very thorough and can help you gain a very good understanding of how Amber apps are created.

# Generating an Amber App

To get started, I would just recommend generating your own amber app using the `amber new` command:

```
amber new <name_of_app>
```

I'm currently [working](https://github.com/jvarness/tour-of-heroes-amber) on implementing the Tour of Heroes tutorial application in Amber instead of Angular, but it's nowhere close to what I've written from [this post](https://dev.to/jvarness/angular-apps-in-typescript-or-dart-9hi).

Without providing any options to the `amber new` command, a new project is generated that uses PostgreSQL and Granite as it's DB and ORM. This normally isn't so bad, but when it comes to configuring databases I typically get pretty annoyed. Throughout my career I remember running into a lot of issues trying to configure Oracle databases, and just a few weeks ago I tried installing PostgreSQL in a Linux Mint VM before I gave up and installed a Xubuntu VM.

It gets really annoying when all you want to do is *code*, but you have to set up an infrastructure to run your app! This is tiring, doesn't get you any closer to the ultimate goal of writing and running your application, and even if you get your environment working, it's no guarantee that it'll be _exactly_ like the ones your clients have.

If only there was a simpler thing we could do...

# Don't Download Databases, Download Docker!

Seriously, if you're at this step, save yourself the trouble of downloading PostgreSQL and trying to get it to run. Downloading [Docker](https://docs.docker.com/install/), if you can believe this, is going to make things easier for you right now, as well as in the long run.

I downloaded Docker onto my Mac last night, and I was able to deploy my Amber app to a container on my machine within a half hour of downloading it. Without it, I probably would have spent a good chunk of time downloading PostgreSQL and attempting to stand up a DB instance, which is time I really could have spent coding.

If you have a simple application created, and you have Docker downloaded for your platform, head to your terminal, and use the following command to get your app running:

```
docker-compose up -d
```

By running `docker-compose up`, you're asking docker to compose your application using the configuration defined in the `Dockerfile` and `docker-compose.yml` files that were created when you generated your app. The `-d` option just tells Docker that once the images were built and they're running, run them in the background so that the running Docker process isn't still attached to your terminal session.

To see your new images running, run the command `docker container ls -a` and you'll see all the containers that Docker created and ran for you:

```
$ docker container ls -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS                    NAMES
459baf330231        tour-of-heroes      "amber watch"            4 minutes ago       Up 4 minutes               0.0.0.0:3000->3000/tcp   tourofheroes_app_1
cd860dfd3fc3        tour-of-heroes      "bash -c 'while ! nc…"   4 minutes ago       Exited (0) 4 minutes ago                            tourofheroes_migrate_1
b0a5fd0d4ce5        postgres            "docker-entrypoint.s…"   4 minutes ago       Up 4 minutes               5432/tcp                 tourofheroes_db_1
```

# What Did I Just Do?

Well, you locally deployed your first Docker image using `docker-compose` of course! But what did Docker do?

Take a look at the `docker-compose.yml` file, and you'll probably be able to piece together what happened. There are three services defined in the `docker-compose.yml` file: `app`, `migrate`, and `db`. The `app`  and `migrate` services are services belonging to your Docker image, and the `db` service uses the `postgres` image so that _you don't have to manage the db yourself_. That's right: no configuring default admin users, no downloading of databases required.

Since the `db` service sets up the database, you'll need to migrate your Granite models into the database... Well, YOU won't need to, because Docker already created a container that did that for you! The `migrate` service will run all of the appropriate `amber migrate` commands to migrate the models into the database, as well as run any seeders that have been written for your project.

Lastly, there's the `app` service, which just runs your app as defined in your `Dockerfile`. Once this container starts running, the application is ready to be accessed by going to `http://localhost:3000`.

# Making Changes to the App

With your Docker image running, you can actually make changes to your application and they will be reflected in your image!

I had asked Amber to generate a scaffold for me for a `Hero` model, but it wasn't smart enough to know that the plural of "hero" was "heroes" and not "heros". I went around and fixed all the places where "heros" was and it was immediately reflected in the application!

Amber is also cool enough to pull in [Bootstrap 3.3.7](https://getbootstrap.com/docs/3.3/) into the application via CDN by default, so I updated the `index.slang` file to show a star glyph when the hero is a "favorite" hero rather than "true" or "false".

Now, if you need to bring down the application, you can bring the application down using `docker-compose down`, but *beware*, for invoking `down` will bring down the `app`, `migrate`, AND `db` containers, and any info you had saved in there before will be lost.

You can safely rebuild the the Docker image for you application and bring it up by invoking:

```
docker-compose up -d --no-deps --build app
```

This will rebuild only the application and not include any dependencies, such as the database. If you need to execute another `migrate` command, you can include the `migrate` at the end of the command.

# Wrapping Up

If you read this, I hope you found it helpful or useful! Hopefully after reading this and maybe following along with it, you're a little more comfortable with containers. I know that going through this boosted my confidence a little!