Hello everyone! Before we get started with this tutorial, I'd like to cover some prerequisites. I am expecting you to already have previous knowledge of React and working with the command line. That's it! :)
Disclaimer: This is only meant to be an introduction. I am not making claims this will make you an expert at Docker, nor am I making any claims this is a good production-level workflow.
What is Docker?
A short and simple definition of what docker is would be: Docker is an ecosystem around containers. But this definition would quickly lead to a lot more other questions, so let's go over the basic terminology.
All containers start with an image. An image is a file that has a set of configuration which is responsible for installing the dependencies needed for the program and how to run it. A container is an instance of an image that is responsible for running the program you have in that container.
Why use Docker?
One of the biggest challenges in software development is dealing with dependencies and also perhaps dealing with dependency versions. This is what Docker aims to solve. It allows you to run a program without requiring you to actually have the dependencies installed on your local machine.
Imagine a company that hired a new developer. They would have to spend some time going over their local development environment setup and most likely deal with installation hassles. With docker, all they would need to do is type in a few commands and they're ready to start developing on any system, not just restricted to one.
Installing Docker
Ok! Let's get to the fun part! There are several options for you, depending on what OS you are on.
Windows 10 Pro/Enterprise: https://docs.docker.com/docker-for-windows/install/.
Other versions of Windows (for purposes of this tutorial): https://docs.docker.com/toolbox/toolbox_install_windows/.
Mac: https://docs.docker.com/docker-for-mac/install/
Once you got it installed, type in docker run hello-world and you should get something like this:
docker : Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete
Digest: sha256:c3b4ada4687bbaa170745b3e4dd8ac3f194ca95b2d0518b417fb47e5879d9b5f
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
Creating the Dockerfile
The last major step is to create our Dockerfile, but before we do that, let's take a small aside to better understand what a Dockerfile actually is.
Earlier, it was mentioned that Docker is an ecosystem around containers. To add a bit more detail to this, it has a set of tools. These tools are:
- Docker Client: This is that allows us to interact with Docker, through the CLI and input the Docker commands.
- Docker Server: This is reponsible for the actual processing of the Docker config we write and to actually start/stop the containers.
- Docker Machine: Responsible for where Docker is run.
- Docker Images: As mentioned earlier, a file that contains configuration for some program.
- Docker Hub: A Repository where images are publicly stored, and where Docker server looks for images.
- Docker Compose: A tool that allows communication through a set of multiple containers.
So how does this all come together? Well, a Dockerfile can be thought of as a link from our local environment to the Docker environment. It is a plain text file with configuration that tells Docker what the container should do. This process is triggered through a Docker command we input through the Docker client and then is passed to the Docker server, which is what, in the end, gets the work done.
Every dockerfile has the following format:
1. Some kind of base image
2. Some commands to install the dependencies needed
3. A command to run when container is run
Now let's take a closer look at this Dockerfile setup and build one! Go ahead and create a new React project. Once that's finished create a new file and name it Dockerfile. No file extension and it must start with a capital D. Next, let's start writing the configuration we need.
FROM node:alpine
This line tells docker to download a pre-existing base image that was already made by someone else. To go over this in detail would take a lot of time, but basically this image will give us everything we need to get this specific application to run. There are plenty of other base images to pick from as well that you can explore later on.
WORKDIR '/app'
This will declare the working directory we want our container to be. What this essentially means is that any following commands we execute, will be relative to this path.
COPY package.json .
In order for us to be able to run our program in the container, we need to copy them from our local machine to the container. What this command is doing is copying the package.json file from our local machine to the current directory in the container.
RUN npm install
This one is pretty self-explanatory, it will install the dependencies in the container.
COPY . .
This command is another copy command. What this one is doing is it's copying the files from the current build context to the current directory in the container. The current build context refers to the location where the Dockerfile exists.
CMD ["npm", "run", "start"]
Finally, this command will actually boot up the react server inside the container.
The final code for this Dockerfile should look like this:
FROM node:alpine
WORKDIR '/app'
COPY package.json .
RUN npm install
COPY . .
CMD ["npm", "run", "start"]
The last step before we get actually see this stuff in action is to create a docker ignore file. Create a new file named .dockerignore and put in /node_modules in there. This is so docker ignores the node_modules folder in our local machine.
Running the Docker container
Before you do anything else from this point on, make sure your docker server is running! Nothing will work otherwise.
In your terminal type the following command:
docker build .
You will see something like this in your terminal at the start
$ docker build .
Sending build context to Docker daemon 826.9kB
Step 1/6 : FROM node:alpine
---> 72eea7c426fc
Step 2/6 : WORKDIR '/app'
---> Using cache
---> 220b2b3abcac
Step 3/6 : COPY package.json .
---> 9bbd128be740
Step 4/6 : RUN npm install
---> Running in 64ba0ac700c2
Once it's done you should see something like this at the end:
Successfully built e0b8ed6b59bf
Take note of that id as you will need that in the next step. Last step, type in the following command:
docker run -it -p 3000:3000 e0b8ed6b59bf
Notice that the id used at the end is the same as the one that was displayed at the end of the build process. This is the id of the container that you want to run. Make sure to use your container id and not the one shown here
-p 3000:3000
You're probably wondering what this thing is about. Basically we need to map our ports from our local machine to the container that we're running. The number on the left side is the port on our local machine and the number on the right side is the port in the container.
Please note, if you are using Docker Toolbox, you need to access this in your browser using 192.168.99.100:3000/ instead of localhost:3000.
Conclusion
Ok that's all! You should now have a basic application running inside a docker container! If you'd like to just have access to the code and play around with the docker commands without writing out the Dockerfile, here is my repo you can clone/fork: https://github.com/Dan-Y-Ko/simple_docker_example
Top comments (0)