Containerizing your projects with Docker simplifies the development experience and facilitates easy deployment in cloud environments. Let’s take a look at how to package a React site as a Docker container.
This article focuses on projects started with create-react-app
(CRA). If you’ve deleted your CRA configuration or are using a custom build process, you need to get it npm run build
command accordingly.
Docker images are created through a Dockerfile
. This defines a base image to use, such as the Apache web server. You then list a series of commands that add packages, apply configuration changes, and copy files that your application requires.
Defining our requirements
CRA includes a built-in live build and reload system, which you can access via npm run start
. This allows you to quickly repeat your site during development.
When you go to production, you need to compile your static sources with npm run build
. This produces scaled down HTML, CSS and JavaScript bundles in your build
directory. You upload these files to your web server.
Could be a basic approach to Dockerising npm run build
local. You would then change the content of it build
directory in your Docker image ̵
This approach is not very scalable, especially when you build your Docker image in a CI environment. Your app build process is not completely encapsulated in the container build, as it relies on the external npm run build
order. We now move on to a more complete example where the entire routine is run in Docker.
A Docker file for CRA
FROM node:latest AS build WORKDIR /build COPY package.json package.json COPY package-lock.json package-lock.json RUN npm ci COPY public/ public COPY src/ src RUN npm run build FROM httpd:alpine WORKDIR /var/www/html COPY --from=build /build/build/ .
This one Dockerfile
contains everything needed to fully containerize the project. It uses Docker’s multi-stage builds to run the React build first and then output to a alpine
Apache server container. This ensures that the final image is as small as possible.
The first part of the file defines the construction phase. It uses the official Node.js base image. The package.json
and package-lock.json
files are copied in. npm ci
is then used to install the project’s npm packages. ci
is used instead of install
because it enforces an exact match with the contents of package-lock.json
.
Once the dependencies are installed, the public
and src
folders are copied to the container. The folders are copied after the npm ci
command because they are likely to change much more often than the dependencies. This ensures that the build can take full advantage of Docker’s Layer caching – the potentially expensive one npm ci
command is not executed unless the package.json
or package-lock.json
files change.
The last step in this build phase is to npm run build
. CRA will compile our React app and export it into it build
directory.
The second phase in the Dockerfile
is much simpler. The httpd:alpine
base image is selected. It contains the Apache web server in an image that weighs about 5MB. The compiled HTML, CSS, and JavaScript are copied from the build phase container and into the final image.
Using the Docker image
Use the docker build
command to build your image:
docker build -t my-react-app:latest .
This builds up the image and tags it as my-react-app:latest
. It uses the Dockerfile
found in your workbook (specified as .
).
The build can take a few minutes. Subsequent builds will be faster because layers such as the npm ci
command is cached between runs.
Once your image is created, you are ready to use it:
docker run -d -p 8080:80 my-react-app:latest
Docker creates a new container with the my-react-app:latest
statue. Port 8080 on the host (your machine) is bound to port 80 in the container. This means you can visit http://localhost:8080
in your browser to see your React project! The -d
flag is present so that the container runs in the background.
Switch to NGINX
The above example uses Apache, but you can simply switch to NGINX instead.
FROM nginx:alpine COPY --from=build /build/build/ /usr/share/nginx/html
You can use alternative web servers in a similar way; since CRA produces completely static output, you have great flexibility in selecting how your site is hosted. Copy the contents of the /build/build
directory from the build
stage in the default HTML folder of your chosen server software.
Advantages of this approach
Using Docker to not only encapsulate your final build but also create the build itself will make your project fully portable across different environments. Developers only need Docker to build and run your React site.
More realistically, this image is ready for use with a CI server to automatically create images. As long as a Docker environment is available, you can convert your source code to a deployable image without manual intervention.
Using multiphase builds keeps the final image streamlined and should be just a few megabytes in size. The much bigger node
image is only used during the compilation phase, where Node and npm are required.
Source link