Skip to content

Latest commit

 

History

History
60 lines (46 loc) · 4.34 KB

01-07b-jq.md

File metadata and controls

60 lines (46 loc) · 4.34 KB

Lesson 7b - Using jq to modify environment variables

This lesson uses some advanced concepts and some bash scripting to build a better Dockerfile. By using the concepts showed here, you will be able to build more future-proof and production ready containers. If you prefer to focus on the content about continers, feel free to ignore this lesson and come back to it later on if needed.

In the last lesson, you saw how to use sed to overwrite the hard-coded path to the API. This works well when there is a single value to replace. Now if one of your team members replaced the value of localhost:3000, your build will break. There is a better solution to do this but it involves adding a new software into that first container.

To change this value, we will use jq. Jq is a command-line tool that makes it easy to change values in a JSON file. The base image that we used for building the application does not contain this tool, but that is not an issue. Because a container is essentially just like a Linux machine, you can install the software in your image and then use this tool to perform various operations. To install jq, you will need to download the binary. To make it easier to eventually upgrade it is there is a security vulnerability of some sort, you can add the version number as an environment variable. You can specify this variable with the ENV keyword. This should be added right after the WORKDIR line from your existing Dockerfile

# Dockerfile
[...]
WORKDIR /app
ENV JQ_VERSION=1.5

Next, you can download jq from the Github repository https://github.com/stedolan/jq/releases/download/jq-${JQ_VERSION}/jq-linux64. Note how the JQ_VERSION environment variable is used in the URL. Jq will be downloaded using wget which is already installed in the base image. You will also need to specify wget to ignore certificates and to output the content of this URL into a file in the /tmp folder. Next, you will copy this binary file into the /usr/bin folder so that it is now in the default path for executables. And finally, you must change the permissions on that file so that is can be executed. This is done with the chmod command.

RUN wget --no-check-certificate https://github.com/stedolan/jq/releases/download/jq-${JQ_VERSION}/jq-linux64 -O /tmp/jq-linux64
RUN cp /tmp/jq-linux64 /usr/bin/jq
RUN chmod +x /usr/bin/jq

Now that jq is installed, you will be able to use it to change the value of the BASE_URL property of the config.json file. To do so, change the working directory to the /app/src folder and then use RUN to execute the following command. First, we tell jq to execute the command jq '.BASE_URL = "$BASE_URL"' config.json. This finds the BASE_URL property in the config.json file and replaces the value of it with "$BASE_URL". The output is then stored in a variable called $contents. Once this is done, you can echo the content of this variable back into the config.json file to overwrite the content of the existing file. These Docker instructions should be placed right after the jq installation lines.

WORKDIR /app/src
RUN contents="$(jq '.BASE_URL = "$BASE_URL"' config.json)" && echo ${contents} > config.json

Finally, you can remove the line that used sed to do the substitution.

The nice thing with jq is that you only changed the value of one of the JSON properties. If your developer team added more values to this file, the script in the Dockerfile won’t change the rest of the file. This makes it a safer way to change only the values that need to change in this file. You could also add more jq commands to overwrite other values in this config.json file that you need to overwrite with environment variables.

Your full Dockerfile should now look like this

# Dockerfile
FROM node:14 AS builder
COPY . /app
WORKDIR /app
ENV JQ_VERSION=1.5
RUN wget --no-check-certificate https://github.com/stedolan/jq/releases/download/jq-${JQ_VERSION}/jq-linux64 -O /tmp/jq-linux64
RUN cp /tmp/jq-linux64 /usr/bin/jq
RUN chmod +x /usr/bin/jq
WORKDIR /app/src
RUN contents="$(jq '.BASE_URL = "$BASE_URL"' config.json)" && echo ${contents} > config.json
WORKDIR /app
RUN npm install
RUN npm run build
FROM nginx:1.17
WORKDIR /usr/share/nginx/html
COPY --from=builder /app/dist .
COPY start_nginx.sh /
RUN chmod +x /start_nginx.sh
ENTRYPOINT ["/start_nginx.sh"]

This makes for a Dockerfile that is a little bit more robust and more future-proof.