Running a Containerized Deno Web Application on Microsoft Azure Container Registry
Tags: deno, azure, docker, javascript
Published: 2020-05-19 14:49:32

---
title: "Running a Containerized Deno Web Application on Microsoft Azure Container Registry"
summary: "Deno v1.0.0 was just released. This article will serve as a step-by-step guide to get you started with hosting a web application on Azure using a Deno docker container."
author: Steven Roeland | Codestack BV
---

This morning my twitter feed featured a post that mentioned `Deno`.

{% twitter 1260756707690418177%}

Not really knowing what the fuss was all about I started doing some research and eventually I ended up with a full web application running containerized on Microsoft Azure using Container Instances. What a beautiful day indeed. In this post I will give you a step-by-step overview of how I got to that point and what the challenges and hiccups were along the road.

But first, let's take a look at what Deno really is. From the [official website](https://deno.land/):

> Deno is a simple, modern and secure runtime for JavaScript and TypeScript that uses V8 and is built in Rust.
>
> - Secure by default. No file, network, or environment access, unless explicitly enabled.
> - Supports TypeScript out of the box.
> - Ships only a single executable file.
> - Has built-in utilities like a dependency inspector (deno info) and a code formatter (deno fmt).
> - Has a set of reviewed (audited) standard modules that are guaranteed to work with Deno: deno.land/std

The Deno project was created by Ryan Dahl, original creator of Node.js.
I would strongly encourage you to watch 2 talks from him on YouTube which make a lot of things clear: [10 Things I Regret About Node.js](https://youtu.be/M3BM9TB-8yA) and [Deno, a new way to JavaScript](https://youtu.be/HjdJzNoT_qg).

Just to make sure, this article will not be a _Node vs Deno_ discussion. This article will show you how to serve an application using containerized Deno. That being said, buckle up, let's get started.

Getting your application up and running will come down to this:

- Create an Azure account if you don't have one yet
- Create an Azure Container Registry
- Install docker desktop + Deno
- Build the Deno docker image
- Push the Deno docker image to your Container Registry
- Create a Container Instance off your docker image
- See if everything works and cheer if it does

#### Setup an Azure account if you don't have one yet

Having worked a lot with Google Cloud Platform(GCP)/Kubernetes on my last project, I chose Azure to host my docker images this time to see what they had done related to containers since the last time I used it. Getting started with Azure is really easy. Just head over to the [Microsoft Azure Website](https://azure.microsoft.com/en-us/) and create a new account. You can start off for free and even get free credit for the first month.

Of course, you can choose whichever platform you like to host your docker containers. For the sake of this demo, I will include the steps to configure this on Azure.

#### Create an Azure Container Registry

Once you have your Azure account all set up, on the [portal](https://portal.azure.com/)

- search for `Container Registries`
- select `Add` in the top left corner
- provide a `Resource group` and `Registry name`
- Next through the remaining steps of the wizard to Create a new registry

Once your registry is created, head over to the `Access keys` section in the `Settings` section of your registry.
Enable the `Admin user` toggle. This will allow us to connect to the repository using `docker login` later on.

#### Install docker desktop + Deno

Head over to the official [Docker Website](https://www.docker.com/products/docker-desktop) and download the correct version of Docker Desktop for your machine. This article will not cover docker itself. I advise you to go through [the excellent docs](https://docs.docker.com/get-started/overview/) on the docker website to get familiar with the main concepts if you aren't already.

When building a Deno application, it might also be nice to install.. Deno.

**Using PowerShell**

```
iwr https://deno.land/x/install/install.ps1 -useb | iex
```

This will allow you to run your Deno application without having to actually `docker build` and `docker run`.

#### Build the Deno docker image

Aha! Now that we have all of that out of the way, let's build the actual web application.
For now, it seems as if there are no official Docker images YET (I will update the article accordingly when official Deno Docker containers appear online). Via one of the [github issues](https://github.com/denoland/deno/issues/3356) on the Deno repo I came across this nice [`deno-docker`](https://github.com/hayd/deno-docker) project which I used as a starting point.

Create a new project folder somewhere on your filesystem. At a bare minimum, you will need the following 3 files:

**A static html page to serve (index.html)**

Let's start with the html file. Create a subfolder named `public` in your project folder and add an `index.html` file.
You can go as crazy as you want with the content, that really is outside of the scope of this article.

**An entry point for your application (main.ts)**

Create a file called `main.ts` at the root of your project folder with the following content:

```
import { Application } from 'https://deno.land/x/abc/mod.ts';

const PORT = 80;
const app = new Application();

app
  .static('/css', 'public/assets/css')
  .file('/', 'public/index.html')
  .start({ port: PORT });

console.log(`Server started on port ${PORT}`);

```

Let's take a second to see what's going on here.

- `Application` is imported from `abc`. `abc` is a Deno framework to create web applications. More info [here](https://github.com/zhmushan/abc).
- the application will be started at port `80`. I chose `80` specifically as this plays along nice with (the limitation of) Azure Container Instances. More on that, further on.
- app.static() static registers a new route to serve files from the provided root directory
- app.file() registers a new route with path to serve a static file

**A Dockerfile to create your container image**

Finally, we add the file that will allow us to create a nice Docker image of our web application.
Add a file called `Dockerfile` to your root project folder (no extension). This is how it should look:

```
FROM hayd/alpine-deno:1.0.0

EXPOSE 80

WORKDIR /app

ADD . .
RUN deno cache main.ts

CMD ["run", "--allow-net", "--allow-read", "main.ts"]
```

Let's take another second to see what's going on HERE.

- `FROM hayd/alpine-deno:1.0.0` specifies the pre-existing image to start from
- `EXPOSE 80` informs Docker that the container is listening on port 80 at runtime.
- the `CMD` directive references the `main.ts` file we created earlier

I would like to delve a little deeper into the `CMD` directive here. It describes how to run a container based on the image we are creating. The command that will be executed in a container will be:

```
deno run --allow-net --allow-read main.ts
```

With Deno, code is executed in a secure sandbox by default. Scripts cannot access the hard drive, open network connections, or make any other potentially malicious actions without permission.\
Users must first give permission. Deno provides analogous behavior in the terminal.

`--allow-net` allows network access

`--allow-read` allows read access to the file system. This is necessary for our `abc` framework to serve our html file.
If you don't specify the `--allow-read` flag, you will run into the following error at runtime:

```
{"statusCode":500,"error":"Internal Server Error","message":"read access to \"C:\\deno-web-app\", run again with the --allow-read flag"}

```

Since we're talking error messages.. One thing I ran into was that initially, the `Dockerfile` specified a user with limited permissions. This throws a very cryptic exception:

```
error: Uncaught PermissionDenied: Permission denied (os error 13)
    at unwrapResponse ($deno$/ops/dispatch_json.ts:43:11)
    at Object.sendSync ($deno$/ops/dispatch_json.ts:72:10)
    at Object.listen ($deno$/ops/net.ts:51:10)
    at listen ($deno$/net.ts:152:22)
    at serve (https://deno.land/std@0.50.0/http/server.ts:261:20)
    at file:///app/main.ts:4:11
```

As it turns out, this was because we want to serve the application on port `80`. Non-privileged user (not root) can't open a listening socket on ports below 1024. Thank you [StackOverflow](https://stackoverflow.com/questions/9164915/node-js-eacces-error-when-listening-on-most-ports).
To solve this, make sure that user running the process (which can be specified by using `USER` in your `Dockerfile`) has enough permission. In our case, just omitting the `USER` works just fine.

Now that we have everything in place. Let's build our Docker image.

```
docker build -t deno-web-app .
```

#### Push the Deno docker image to your Container Registry

Now that we've built that shiny Docker image, let's push it to our registry.
To do that, of course, we have to follow a few more steps.

**login to your Azure Container Registry**

```
docker login [your-azure-registry-name].azurecr.io
```

You'll be prompted for a username and password. Use the credentials you configured in the beginning of this article while creating your registry.

After that, prefix the image with your registry login URI so that it can be pushed.

```
docker tag deno-web-app [your-azure-registry-name].azurecr.io/deno-web-app
```

And finally, push your image to your registry.

```
docker push [your-azure-registry-name].azurecr.io/deno-web-app
```

#### Create a Container Instance off your docker image

So now that we got the image in our registry, it's time to create an actual container, so that we can actually host our web application.

- Go to Azure [portal home page](https://portal.azure.com/)
- In the search box type `Container instances`
- select `Add` in the top left corner

This will bring up a step wizard where you need to provide some information about the Container Instance you're about to create.

On the first step

- Provide a `Resource group` and a `Container name`
- Select `Azure Container Registry` as your `Image source`
- Select the correct `Registry` and `Image`
- for now, just use `latest` as `Image tag`

On the next step - Networking - just enter a nice DNS name label, so that you will have a nice url to access your application.
You can leave the default port settings.

When working with Docker containers, it is common to match the TCP port in the container to a port on the Docker host. One of the limitations I ran into with Azure Container Registries (as far as I can tell) is that this kind of port forwarding is not possible here. This is the reason why, in the `Dockerfile` I opted to open up port `80` in the container by using `EXPOSE 80`. That way it will do a `PORT 80:80` binding between host and container.

Anyways, _next_ through the remaining steps of the wizard to Create your Container instance.

#### See if everything works and cheer if it does

After a few moments, Azure should finish creating your Container Instance.
You should now be able to see your web application running at the url you just configured.
To find the exact url, look for the `FQDN` property of your `Container Instance` on its `Overview` page.

All good? Hooray!

#### tl;dr

The complete code for this article is available on [our GitHub repo](https://github.com/codestack-bv/deno-web-app)

The code on the repo slightly deviates from the code snippets used in this article. The index page of the web application on the repo has a templated landing page and therefore loads additional static content in the `main.ts` file. Also, the `abc` dependency was moved to a separate file.

This however changes nothing to the main building blocks discussed in this article and therefore, for the sake of simplicity, it was not mentioned here.

#### Final words

I really enjoyed learning about the Deno project. I really hope this article can be of value for anyone getting started with Deno, docker or Azure Container Registries. If you found this article useful, give us a quick shoutout on our new [twitter account](https://twitter.com/CodestackBV).

And with that, I would like to thank you for following along with me on my first REAL blog post.

I hope to welcome you here for another one.