DEV Community

Cover image for Yet Another Article to Dockerizing An App — But with a twist
Antwi Isaac
Antwi Isaac

Posted on

Yet Another Article to Dockerizing An App — But with a twist

Do-cker... doc-ker…. dock-er. You’ve probably heard this term so much and you’re wondering what the fuss is. What is it? Do I need it? Does it make a difference? I’ve been building apps without Docker just fine… I hear you. Just hold my mug.…

Officially, “docker is a tool that helps you develop, ship and run applications within lightweight containers.” Okay.. but what does this mean?

Say you’re building the next billion dollar app with your friend. You’re using a windows laptop while he’s using a mac. You make some changes to the code and push your updates to Github. He then pulls your updates and tries to run the application — damn, it doesn’t work. Ei? You jump on a Zoom call and show him that it works fine on your laptop; he then shares his screen and shows you a weird error… well, that’s awkward. It works fine on your machine, but it doesn’t on his. Why?

It doesn't work on his machine

For some kinds of apps, this wouldn’t have been an issue. Your todo app built using HTML, CSS and JavaScript maybe fine ;). However, other apps, for example, a NodeJS service that requires specific OS-level drivers / packages to work would easily run into compatibility issues — Windows and MacOS are fundamentally different. Also remember that the server your application would be deployed on might come with a different OS, setup and environment.

That’s where docker comes into play. What if in building, testing and deploying, you can have the same “configuration” used everywhere? You share that “configuration” with your friend, deploy it on your production server and it runs — just like magic, except that it’s not magic *wink.

Lets dive into Docker: Concepts

To get started with Docker, download Docker Desktop here: https://www.docker.com/get-started. It installs a GUI you can use as well as the command line tools.

At the core of docker, there are three concepts to understand: Dockerfile, Images and Containers.

1. Dockerfile

It is text file with instructions on how to build a Docker image. Think of the Dockerfile as a recipe or a blueprint. It contains all the instructions — step by step — to set up your application. You specify everything your app needs and how to run / start it in the Dockerfile.

2. Image

Using the recipe (Dockerfile), you bake a cake (Image). Docker images are immutable, which means if you make any change to the Dockerfile and rebuild, you create a new image and do not modify the existing one (if any exist). Versions of an image are managed using tags.

Images can be shared with other developers anywhere — just think of it as giving a file to someone. Many developers use DockerHub to share images.

As an example, here’s the official MongoDB Image on Docker: https://hub.docker.com/_/mongo

3.Container

A container is running instance of a Docker image. This is like eating or serving the cake to your guests. The image is static, but the container is a live process running inside of an isolated environment.

Now that we’re clear with the basic concepts and rationale behind using docker, lets dockerize (create a Dockerfile, build an image and use that to spin up a container).

Here’s the repo of what we’re building: https://github.com/okraks/dockerizing-app-example

Create a Dockerfile

Create a Dockerfile in the root of your application. The Dockerfile contains instructions (remember the recipe?) on how to package and run your app.

1.Set the base image: This command sets the base image (think of it as a minimal OS that can run processes, libraries, networking and a filesystem). In this command, I use the official NodeJS image from Docker hub (it has nodejs and npm already installed)

FROM node:18.11.0
Enter fullscreen mode Exit fullscreen mode
  1. Set working directory: It’s usually good practice to set the working directory inside the container. All subsequent commands (COPY, RUN, etc.) will be executed inside /app. If /app doesn’t exist, it will be created automatically.
WORKDIR /app 
Enter fullscreen mode Exit fullscreen mode
  1. Copy package.json and yarn.lock into the /app directory: This is a common optimization. You copy dependency files first, then run yarn install, so Docker can cache that layer if your dependencies haven’t changed everytime you rebuild the image.
COPY ./package.json ./yarn.lock /app/
Enter fullscreen mode Exit fullscreen mode
  1. Install Dependencies: RUN executes a command at build time (in contrast to CMD which runs at container start). This installs all dependencies listed in package.json using yarn.
RUN yarn install --frozen-lockfile
Enter fullscreen mode Exit fullscreen mode
  1. Copy code in src folder into docker: Copies your app’s source code from your local ./src folder into the container’s /app/src directory. The syntax means COPY “from” “into”
COPY ./src /app/src
Enter fullscreen mode Exit fullscreen mode
  1. Start the application. Similar to running yarn dev to invoke the dev script in package.json. CMD defines the default command that runs when the container starts. For production builds, you’d use “yarn start”
CMD ["yarn", "dev"]
Enter fullscreen mode Exit fullscreen mode

Build the Image

Now that we have our instructions (Dockerfile), we can build our image using the command bellow. The flag -t assigns a name (and optionally a tag using syntax name:tag) to the image you’re building. The full stop is to point to the current folder we’re in.

docker build -t our_awesome_app .
Enter fullscreen mode Exit fullscreen mode

So now we have an image called “our_awesome_app” and we can start a container using it, or even share it.

Here’s the example image shared on DockerHub: https://hub.docker.com/r/okraks/dockerizing-app-example

Start a Container using the Image

This command tells docker take the image “our_awesome_app” and start a new container using it. If the image doesn’t exist locally, it would try to pull it from DockerHub or any other registry.
“-p” is the port mapping flag. It connects a port inside the container to a port on your machine (the host). In our app, we started our server on PORT 8080 so we expose that same PORT from our container to our host machine. The syntax is
-p <host_port>:<container_port>

docker run -p 8080:8080 our_awesome_app
Enter fullscreen mode Exit fullscreen mode

That’s it! Your application is running now and is available on your laptop on port 8080. In another article, we’d explore a setup of several applications (for example, a frontend, a database server and a backend service) using a popular library: docker-compose.

Enough talk. Time to build.


Resources

Learn Docker in 7 Easy Steps — Full Beginner’s Tutorial
https://www.youtube.com/watch?v=gAkwW2tuIqE

The Only Docker Tutorial You Need To Get Started https://youtu.be/DQdB7wFEygo

Docker Docs
https://docs.docker.com/get-started/docker-overview/

Top comments (0)