Let's say you have your shiny web app and you want to containerize it and publish it.
In my case, it is a simple app based on create-react-app, which connects to a GraphQL backend and I use NGINX as a webserver to serve my built frontend. I have two environments, one of them is public (production) and the second one is secured with basic auth (staging). The two environments have different NGINX config files.
So let's get started step by step.
I have the React app and I created two Nginx config files
Both NGINX configurations are based on Sara Vieiras article https://medium.com/yld-blog/deploy-your-create-react-app-with-docker-and-ngnix-653e94ffb537
So what I need to achieve is passing a build time environment variable into our React app build, and based on a second build time variable I need to choose the right Nginx configuration.
So first we define the base image then we copy our app into our work directory then we go to the root of our app. In my case it is a yarn workspaces monorepo and I have some business logic in the upper levels, that's why the long path.
FROM node as build WORKDIR /app COPY . . WORKDIR /app/packages/reactapp
In my app I am using as my GrqphQL endpoint constant this value
process.env.REACT_APP_GRAPHQL_ENDPOINT || "http://localhost:4000/graphql".
So To build our app we need to pass a build time environment variable which is represented by
process.env.REACT_APP_GRAPHQL_ENDPOINT otherwise it will use the localhost value.
To achieve this we initialize a build-time argument, and based on this argument we set our environment variable. It is very important that our value needs to start with
REACT_APP otherwise create-react-app ignores our value.
( there are some exceptions read more: https://create-react-app.dev/docs/advanced-configuration )
ARG REACT_APP_GRAPHQL_ENDPOINT_ARG ENV REACT_APP_GRAPHQL_ENDPOINT=$REACT_APP_GRAPHQL_ENDPOINT_ARG RUN yarn RUN yarn build
At this point, we have built our app with a custom build-time variable, now we can set up our Nginx web server, so let's continue our docker file. So we initialize an Nginx image and we copy our built React app into the folder which is set as root in our Nginx configuration.
FROM nginx:alpine COPY --from=build /app/packages/reactapp/build /usr/share/nginx/html
Then we can continue with the initialization of our second environment variable which helps to decide which configuration file to pick from the two we created. I use the build-time argument to dynamically create the filename I want to use. And I also copy the file which contains the encrypted credentials for the basic auth for the staging environment.
ARG NGINX_ENV_CONF COPY nginx.$NGINX_ENV_CONF.conf /etc/nginx/nginx.conf COPY .htpasswd /etc/apache2/.htpasswd
In the end, we expose our port 80 and we fire up Nginx in the foreground.
EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
.dockerfile looks like this:
FROM node as build WORKDIR /app COPY . . WORKDIR /app/packages/reactapp ARG REACT_APP_GRAPHQL_ENDPOINT_ARG ENV REACT_APP_GRAPHQL_ENDPOINT=$REACT_APP_GRAPHQL_ENDPOINT_ARG RUN yarn RUN yarn build FROM nginx:alpine COPY --from=build /app/packages/reactapp/build /usr/share/nginx/html ARG NGINX_ENV_CONF COPY nginx.$NGINX_ENV_CONF.conf /etc/nginx/nginx.conf COPY .htpasswd /etc/apache2/.htpasswd EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
Now we can build our app for the staging:
docker build -t dockerized-react --build-arg REACT_APP_GRAPHQL_ENDPOINT_ARG=http://mystaging.dev/graphql --build-arg NGINX_ENV_CONF=staging .
Then we can run it like this:
docker run -d --name dockerized-react -p 80:80 dockerized-react
As an alternative to conditionally choosing a different Nginx configuration, we could use an Nginx template file, but in this case for me, it was easier to choose between files.
English isn’t my first language, so please excuse any mistakes.
Thank you all for your attention and time;