Docker 01: first 3 steps of your web app — Pragmatic Docker series

A 7 minutes story written on Sep 2018 by Adrian B.G.

Containers in general, but Docker in particular is a concept harder to grasp. I will try to write the simplest and most straightforward tutorial for a first hands-on experience for a developer.

Pragmatic Docker series for developers


Containers for everyone

The size of this tutorial may seem scary but it is all boilerplate, I only introduce 3 new commands: docker create network, docker build and docker run.

To keep the tutorial simple I will presume you already have:

  • Bash (even on windows)
  • basic knowledge on Linux, Docker and bash/CLI
  • installed docker at least version 15 and git
  • basic knowledge on developing back-end web services
  • ~200MB free space on HDD (for the images)

Optional you should:

  • be able to run docker commands with your user (without sudo) OR add **sudo** to all commands and scripts from this tutorial
  • allow HTTP traffic (port 80) if you use Google Cloud, AWS … and you want to access the web service trough a browser or remote> To learn about Docker I suggest the following resources:, IBM essentials, tutorial assumes that you already have a basic knowledge about Docker, hence the name “pragmatic”.

Docker terms #likeimfive

  • Docker — collection of tools to deploy and run your apps
  • Image — An executable blueprint for containers, a Class in OOP, a wrapper for your all app dependencies, code and configs
  • Container — a set of isolated Linux processes in a bubble, an Object in OOP, the run-time instance of an Image
  • Network — is like your Wireless home network where Docker is the router
  • Volume — a portion of your hard-disk that can be accessed by a container

What are we going to do today

  1. Create a private docker network
  2. Run a container with a popular database (memcached in this case)
  3. Run a container with a simple web service that “talks” to the database> TL;TR: You will find all the scripts, configs with comments, and the web app source in this repository. The files are heavily annotated for a better understanding of how Docker works and how your code is affected by it.




We need a network in order for our containers to “talk” to each other. It will behave like a “bubble”, it will surround our containers and protect them from the outside “world”, and vice-versa. Imagine that we will create a WiFi network and Docker is the router.

In older docker tutorials you will notice the usage of the link param of the docker run command, but that feature is deprecated since late 2015.

Before we create our (running) containers we must build a “home” for them, a local private network. It sounds complicated but docker makes it easy for us:

$ docker network create tut-network 
$ docker network ls #list all the networks, to confirm it was created``

After this step, all the containers we will create will have the following parameter docker run .... --network tut-network ..... All the containers that are not part of this network cannot access their open ports, including your machine (localhost), for security reasons. In order to gain access to the web app we will use another docker run parameter that links a container port to a (localhost) port: --publish localhost:myport:containerport.

The database

This tutorial only covers one service, namely memcached for simplicity reasons, you can repeat these steps with any other technology: MySQL, PhpMyAdmin, MongoDB you name it. You can use the search command or visit docker search "mysql" to find more images.

We will keep the memcached port private, for security reasons. Only containers that run in our (newly) created docker private network tut-network will have access to it. You can access the full bash script here.

$ docker run `#main command, run a container on my machine` \
  --name tut-memcache `#unique name so you can access it later` \
  --detach `#detach the process from the current bash` \
  --network tut-network `#connect it to the private network` \
  --restart=on-failure:3 `#if the memcached process crashes, docker will restart the container 3 times max` \
  memcached:1.5.10-alpine `#the name of the image, see, alpine is small`

With docker ps you should see the tut-memcache container running.

docker ps  
... STATUS              PORTS                      NAMES  
... Up 2 seconds        11211/tcp                  tut-memcache

Memcached is a popular technology, so we used a pre-built image generated by the memcached developers.

The Image

Our app on the other hand is not so popular either so public, so we will have to build our own image (blueprint), before we can run it in a container.

For the app:

  • you can build your own web app that talks to tut-memcache:11211
  • or you can use my simple Node app (JS for popularity reasons) that does NOT require NPM. You can clone repo.

Because we will run the app in a container you don’t even need to have Node installed on your system.

Regarding the app, I kept everything as simple as I could. In order to use the memcached storage, at every request the web server receives, it increments a numerical value from the database: cache.increment("pageviews",1,0); .

Now we will take our app, dependencies and config files and copy them in a docker Image. The easiest (native) way to build an image is to have a Dockerfile:

FROM node:8.12.0-slim
ADD memjs ./memjs
COPY app.js .
CMD node app.js

This config file (download here) will “tell” docker to build an image that has NodeJS, with an open port 80, to copy the memjs folder (vanilla memcached client) and the app.js file inside the image. The last command is the entry-point of the container (main process). To get a local copy of the project you can clone it:

$ git clone  
$ cd docker-tutorials/01-first-steps

Next step is to build the docker image, run this command in the folder that contains the Dockerfile.

`$ docker build \
    -t tut-app-image:v1 `#tag it with this name:tag` \
    -t tut-app-image:latest  `#make it the latest version too` \
    . `#build with the instructions found on ./Dockerfile`

$ docker images `#to list all your docker images`

If you encounter permissions errors like [context]( see this page.

Now we have an executable image (tut-app-image), that contains everything the app needs to run. This allows us to run the app on any computer that has Docker, without polluting the system with its dependencies and files.

The container

$ docker run \
    --name tut-app `#put it an unique name so you can access it later` \
    --detach `#detach the process from the current bash` \
    --network tut-network `#connect it to the private network we created, --link is deprecated` \
    --restart=on-failure:3 `#if the app.js crashes, docker will restart the container 3 times max` \
    --publish `#link EXPOSEd port from Docker file to your localhost` \
    tut-app-image:latest `#the name of the image:tag`

Running docker ps should confirm that the container is running. By accessing http://localhost (or your public ip for VMs) should increase a key stored in memcached, proof that the 2 containers can “speak” to each other.

$ curl localhost  
Hello from app.js! Request count: 0  
$ curl localhost  
Hello from app.js! Request count: 1  
$ curl localhost  
Hello from app.js! Request count: 2

Now you can modify the app.js file (in any way you want, go ahead I’ll wait ….). After that, you will have to also update the image and the container. To ease these operations I wrote a script that builds and run the app: $ ./

Do not forget to READ all the files from my repo, they are heavily annotated, hopefully it will help understand what each command and parameter does.

Your app should be functional by now

Operational commands

  • docker start|stop|restart|kill tut-app
  • docker ps -a — list all your containers
  • docker images — list all your images, don’t forget to clean them up
  • docker network ls — all your networks
  • docker network inspect tut-network — detailed view of a network
  • docker inspect tut-app — everything about a specific container
  • docker logs -f tut-app — tailing your app logs


Thanks! 🤝

Please share the article, subscribe or send me your feedback so I can improve the following posts!

comments powered by Disqus