Working with docker
Every time you start a new project you need a different version of the tools or packages that you use. It is manageable by some version managers, but there is a better way. You can start every project and install all the dependencies on a docker container. I will show you how to do it without getting into the whole boring stuff that docker for beginners tutorials cover.
First things first. You need to have docker installed on your system.
This post covers the example react application. I'm planning to add at least one more (rails application with Postgres database).
Create a folder that will store the application code, then create a Dockerfile
file. A Dockerfile
is a file that describes the container that you want to build.
mkdir react_on_docker
cd react_on_docker
As a first step we just want to install an Alpine Linux with nodeJS installed. Here is the content of the Dockerfile
that does that:
FROM node:17.5.0-alpine3.15
WORKDIR /code
The first line says that we want to install container based on a node
image and we want to use 17.5.0-alpine3.15
version of the image. You can find those images and tags (latest version etc.) on docker hub website (eg. node docker hub).
The second line instructs Docker that we want to create and start working in the code
directory of the container. The code
directory in docker container will be the same as the main project directory on your system.
Next thing that we need to setup is docker-compose.yml
file. Using this file we can describe a few services (containers) that are dependent on each other. docker-compose
allows us to use one command to run the whole application (eg. frontend and backend). There are a lot of use cases, but let's skit the theory for now.
version: "3.9"
services:
app:
build: .
command: npm start
volumes:
- .:/code
ports:
- "3005:3000"
As you can see above we described a service called app
that has the build instructions in the .
directory (current). The command that will start this service is npm start
, we added a volume /code
. The ports section mapped the 3005 port from our system to 3000 port from the inside of the container (create-react-app
sets 3000 as a default port for the application).
Next thing to do is to initialise the react application using create-react-app
. But we don't want to install node on our system, we want to use node that is installed inside the container.
docker-compose build
docker-compose run --rm app npx create-react-app app
To run something in a docker container we need to create it first. The first is responsible for that. It builds an image according to instructions from Dockerfile
.
Second command starts the container, but it is not using the default command stated in docker-compose.yml
, but executes the npx create-react-app app
command to install react application in the app
folder. Using the --rm
option we ask docker to remove the container after the specified command finishes.
If you know a bit more about docker-compose you will probably ask yourself why we haven’t used the docker-compose exec
here? The answer is simple: Because the service is not running yet. What to do then to run the service? We need to run docker-compose up
, but it won’t work, because it tries to start application using npm start
command. That's why we used the run command. We just need to set up the app, we don't have anything to run yet.
Now we can change the WORKDIR
in the Dockerfile
to be /code/app
because create-react-app installed react in the app
folder and this will be our working directory now.
FROM node:17.5.0-alpine3.15
WORKDIR /code/app
To run the application, we need to rebuild the container (because we did some changes in Dockerfile
). And then start it:
docker-compose build
docker-compose up
Now the application is running. You can visit the [localhost:3005](http://localhost:3005)
(or whatever port you specified in your docker-compose
) address and you will see the placeholder react application. You can start creating you own web application now.
If you want to run scripts from the inside of the container (examples given below), run:
docker-compose exec app sh
docker-compose exec app npm install package
docker-compose exec app npm run test
To be able to setup the application faster we can add the node packages installation step to the Dockerfile
. Thanks to that step, when somebody clones our application, they can just run docker-compose build
and everything will be setup. Without that step, after any change in the package.json
, you need to execute npm install
command inside the container.
Let’s get to it. Add following changes to the Dockerfile
. The first two added lines are responsible for copying the package files into the docker container. Third added line runs installation of npm
packages.
FROM node:17.5.0-alpine3.15
WORKDIR /code/app
COPY /app/package.json ./
COPY /app/package-lock.json ./
RUN npm install
As you should remember you need to build and run the container once again, because you changed the Dockerfile
.
Now you can develop your application. You don’t need to build the container after each change to see it. If you will add a package or change some config you will probably need to restart the container or build it once again.
That’s it. You haven’t installed anything (but Docker) on you system. The drawback of this solution is that the setup of the application is a lot more difficult and time consuming. I hope that using this tutorial it won’t be so hard and you will use it for other projects as well.
Thank you!