An introduction to Docker using React.js

Install Docker.

To use Docker on your local machine, you can find installation instructions here. There are instructions specific to your correct operating system (Mac, Ubuntu, and Windows).

Open your default command-line client; it is Terminal in my case. Type the following command to create a new development folder and access it.

mkdir dev && cd dev

The command below will run Docker in interactive mode, -it flags, the Linux Alpine and runs the sh command. Docker will download the alpine image to your local machine in case you don’t have it.

$ docker run -it alpine sh

You would be presented with alpine’s sh shell mode if the command ran without an error, which means you’re in a terminal of a Linux running inside a container. It was all accomplished within few seconds. Incredible! You can check the folders and files pulled with the following command ls.

Here’s a screenshot of mine:

Alpine

You can type exit in the terminal to exit and stop the container.

Nugget: They built Docker for Linux, but now it is native to Windows as well. However, Mac requires VM running in the background for it to emulate the host. The only thing is, it is much lighter than using Virtual Machines.

So, why did we use Alpine as a Base Docker Image?

Simply put, you want to shrink your Docker images, start services faster and secure your application. Alpine 3.6 Dockerized version weighs a little less than 4MB; it sits at 3.98MB.

You can compare it to other popular Linux distributions:

Distribution Version Size
Alpine 3.6 3.98MB
Ubuntu 16.04 118MB
Fedora 25 231MB
CentOS 7 193MB
Debian Jessie 123MB

Amazeballs! Size does matter, and Alpine is about 30x smaller than Ubuntu. Also, you can perform additional tests by downloading the Base Image on a new machine.

Alpine

$ time docker run --rm -it alpine sh -c "apk add --no-cache gcc"
...
real 0m 4.62s
user 0m 0.02s
sys 0m 0.04s

Ubuntu

$ time docker run --rm -it ubuntu sh -c "apt-get  update && apt-get install -y gcc"
...
real 0m 14.66s
user 0m 0.02s
sys 0m 0.05s

Alpine is 3x faster than Ubuntu with a 4.62 real life seconds wait time compared to Ubuntu’s 14.66 seconds. It is time too valuable to be wasted just for a programming test.

Dockerfile

You can clone/download this project from Github, it is an integral part of the next few steps. The project consists of two folders; one is for a simple server while the other is for a web application. We need to create a Dockerfile in the root of the web application. You can read the Docker documentation for an extended overview.

We need to set a starter image for our application in the Dockerfile. Since it is a React web application, an installed Node.js environment ought to be sufficient. DockerHub has a Node.js image that we can pull.

FROM node:9.8.0

The command above will start with node:9.8.0 image. It will install Node.js version 9.8.0 on a Linux distribution, in our case, Alpine. The entire Dockerfile commands are:

FROM node:9.8.0

# This command will create a directory called "web-app" inside "usr" in a container
RUN mkdir -p /usr/web-app

# Set the working directory of our web app to the newly created directory
WORKDIR /usr/web-app

# Copy all the files from current directory to the new one in the container
COPY . /usr/web-app

# Install node dependencies 
RUN npm install

# Define a command to execute when the container starts
CMD npm start

Now that our Dockerfile is ready to embark on its new adventure. You can go ahead and run the application in a container.

$ cd webapp
$ docker build -t web-app .

It is time for a freshly brewed coffee as it will take some time for the Node image to download. The build in the command above will build the image based on the Dockerfile that’s inside the . directory. -t tags the image with the name web-app.

$ docker images

The command will list all the available images, web-app is the only image listed in our case. Let’s run our new app.

$ docker run -d --name web-app-container -p 3000:3000 web-app

You can now access the app in your default browser by following this URL http://localhost:3000. By specifying the d flag in the command, it is running in a non-interactive mode. We named the container with --name web-app-container and mapped it to a port using -p in this format port-on-my-machine:port-on-the-container.

React App

The web app cannot retrieve data from the node service because it is currently not running. Let’s stop the container and create a new Dockerfile for the service.

$ docker ps

The command will list all the containers running, and you can include the -a flag to list all the containers we have created.

$ docker stop <container-id-listed-on-ps>

Use the following commands to create a new Dockerfile in the root folder of the node service:

FROM node:9.8.0

RUN mkdir -p /usr/node-service

WORKDIR /usr/node-service

COPY . /usr/node-service

RUN npm install

CMD npm start

We can now build, run the node service container and reload the web app to see if it’s retrieving any data.

$ cd ../node-service
$ docker build -t node-service .
$ docker run -d --name node-service-container -p 8080:8080 node-service

React App

Absolute beauty! Your containers are fully functional and can talk to each other. If you want to delete a container or an image, you can use the following commands:

$ docker rm <containerID> # use this for containers
$ docker rmi <containerID> # use this for images

Also, if you want to run a container in bash or interactive mode, combine the -it flag and bash together in your command. Here’s an example:

$ docker exec -it <containerID> bash

There is still so much to learn, but we have an excellent foundation on how to use Docker for containers. A la prochaine! ✌🏽

Additional Reading

  1. Docker Compose
  2. Docker Swarm
  3. Volumes
  4. Kubernetes

😎