Cool guys ! It takes two minutes to put your react build inside a docker container. I assume you are familiar with docker and nginx. If not, no worries.
If you are completely new to docker here are two YouTube links which makes you understand what docker is and how to use it.
Before going into this tutorial, let me introduce what docker is. Docker enables developers to easily pack, ship, and run any application as a lightweight, portable, self-sufficient container, which can run virtually anywhere. Docker containers are easy to deploy in a cloud.
The code base for this tutorial: https://github.com/debabrata100/react-docker
Here are the steps we will follow to achieve this.
NOTE: This tutorial is based on create-react-app
There are two ways you can create your docker image.
case-1: You want to build your react application within docker container
case-2: You build your react application in local and push the build artifacts into docker
So much talk. Lets get to action.
Create a file called Dockerfile in your project root and add the following code
# stage: 1
FROM node:8 as react-build
WORKDIR /app
COPY . ./
RUN yarn
RUN yarn build
Explanation:
You must notice at line 3, we are copying everything into docker image and you think there is a problem here. Yes there is a problem, because this will copy everything including your node_modules into docker image, So we must use a .dockerignore file to get rid of this issue.
I used yarn instead of npm, because yarn is faster than npm as you know when installing dependencies for a project, npm installs packages sequentially. This slows down the performance significantly. Yarn solves this problem by installing these packages in parallel.
Now create a .dockerignore file inside your root directory and put these following lines of code into it.
.git
node_modules
build
If you have more files to ignore, you can mention inside .dockerignore file.
Now let’s go to stage-2. In this step we will copy our build artifacts and put into a server where our application will run. Put the following code into your Dockerfile.
# stage: 2 — the production environment
FROM nginx:alpine
COPY — from=react-build /app/build /usr/share/nginx/html
EXPOSE 80
CMD [“nginx”, “-g”, “daemon off;”]
Explanation:
As of now your final Dockerfile should look like this:
<a href="https://medium.com/media/ada42ceb523e2b08afa7461d920ab888/href">https://medium.com/media/ada42ceb523e2b08afa7461d920ab888/href</a>
At line-10, I have added COPY nginx.conf /etc/nginx/conf.d/default.conf. I will explain this in issues section. Please remove this line or put a # at the front to comment it.
Your .dockerignore file should look as following
<a href="https://medium.com/media/46bc18c8106b248cb3f1681df6688384/href">https://medium.com/media/46bc18c8106b248cb3f1681df6688384/href</a>
Now we have done with our docker image configuration, its time to run our container.
Lets build the docker image we just created with the following command
$ docker build . -t react-docker
I hope you build the image successfully. To see the list images built in your system, run the following command
$ docker images
Lets run container now
$ docker run -p 8000:80 react-docker
Now open http://localhost:8000 in your browser to check its running !
<a href="https://medium.com/media/901b6b701ae11087429ce2c5022d615b/href">https://medium.com/media/901b6b701ae11087429ce2c5022d615b/href</a>
To check running containers run $ docker ps
To dive into your docker container run $ docker exec <container_id> sh
The deployment process we have discussed here works only in your local environment, If you are facing any issue with deployment in production environment using kubernetes , please comment here I can help you out .
In case: 1 we have discussed how to build and deploy the complete application inside docker. Many developers choose not build the application inside docker since the above process creates two docker containers hence increase space in your disk though you can write commands to delete the node_modules generated in stage-1 which takes more space. Now lets choose another way of deploying.
Run
$ yarn build. // This will generate the build artifacts in local.
Now in your Dockerfile, Write only stage-2 commands as below
FROM nginx:alpine
COPY /build /usr/share/nginx/html
EXPOSE 80
CMD [“nginx”, “-g”, “daemon off;”]
Now before building the docker image, make sure you exclude build folder from your .dockerignore file
Now run
$ docker build . -t react-docker
This should build your docker image successfully.
To check that, run $ docker images
Now run $ docker run -p 8000:80 react-docker and navigate to http://localhost:8000
You should be able to run your application in browser successfully.
If you are using react-routers, you might find the routes are not working when you refresh the particular page. Now try refreshing you page on the browser and you might get 404 page by nginx server. No worry, here is a solution from stack-overflow.
When your react.js app loads, the routes are handled on the frontend by the react-router. Say for example you are at http://a.com. Then on the page you navigate to http://a.com/b. This route change is handled in the browser itself. Now when you refresh or open the url http://a.com/b in the a new tab, the request goes to your nginx where the particular route does not exist and hence you get 404.
To avoid this, you need to load the root file(usually index.html) for all non matching routes so that nginx sends the file and the route is then handled by your react app on the browser. To do this you have to make the below change in your nginx.conf or sites-enabled appropriately
location / {
try_files $uri /index.html;
}
This tells nginx to look for the specified $uri, if it cannot find one then it send index.html back to the browser.
So In order to implement this create a file call nginx.conf in your project root and the following code into it
<a href="https://medium.com/media/e2789738cdf24a55632513c56103d971/href">https://medium.com/media/e2789738cdf24a55632513c56103d971/href</a>
You can remove the comment lines as you wish, I copied this file from /etc/nginx/conf.d/default.conf
Now we need to overwrite this default.conf file with our nginx.conf created shortly. The only extra line added at line -10 is
try_files $uri /index.html;
We need to change our docker file to push this file into docker as I have discussed this before when I added an extra line to the dockerfile i.e
COPY nginx.conf /etc/nginx/conf.d/default.conf
<a href="https://medium.com/media/d001754c664e3f68da1a3ab6eb47009b/href">https://medium.com/media/d001754c664e3f68da1a3ab6eb47009b/href</a>
If you have skipped this line in the previous docker files in both case-1 and case-2, add it back to get rid of this issue.
Thank you :)