How to assign variable and use sed to replace contents of configuration file in Dockerfile

dockerenvironment-variablessed

I am running a Dockerfile, but, am encountering a problem when I assign a variable for modifying /etc/fail2ban/jail.local, with its string content-"PRIVATEIP".

Dockerfile generates an error and stops. Because I have no idea about assigning a variable with sed to modify the string content in a specific file.

RUN IP=$(cat /root/ip_variable) | sed -i -r "s/PRIVATEIP/${IP}/g" /etc/fail2ban/jail.local
 ---> Running in 1e78ef4318ab

If there are any alternative methods to handle this please let me know.

===========================================================================

Add more explanation for an alternative method as below on 2018/July 11:

I add some command lines on Dockerfile. The purpose is same as before. I alternatively use echo to write a script as below. But, it's weird. Why does the fellow character "/" after "s" on "sed" this command get missed? (If there are any methods to add high light or mark on the character within the output of the code, I thanks to you.) If this matter is resolved, I thinks I am able to close this issues.

Step 64/73 : RUN echo "#!/bin/bash\nexport PRIVATEIP=$(cat /home/ip_variable)\nsed -i -r \"s/\bPRIVATEIP\b/\${PRIVATEIP}/g\" /etc/fail2ban/jail.local\nsed -i -r \"s/\bPRIVATEIP\b/\${PRIVATEIP}/g\" /etc/opendkim/TrustedHosts" > /home/start_script.sh
 ---> Running in bbff59f82475
Removing intermediate container bbff59f82475
 ---> 0068d9d600ff
Step 65/73 : RUN cat /home/ip_variable
 ---> Running in faeb4bb1a6ba
172.17.0.2/16
Removing intermediate container faeb4bb1a6ba
 ---> f6cc35fd01e5
Step 66/73 : RUN cat /home/start_script.sh
 ---> Running in 95a5ef3b7d23
#!/bin/bash
export PRIVATEIP=172.17.0.2/16
sed -i -r "sPRIVATEI/${PRIVATEIP}/g" /etc/fail2ban/jail.local
sed -i -r "sPRIVATEI/${PRIVATEIP}/g" /etc/opendkim/TrustedHosts
Removing intermediate container 95a5ef3b7d23
 ---> 6720e7c01efc
Step 67/73 : RUN chmod 755 /home/start_script.sh
 ---> Running in d8ab5e04a846
Removing intermediate container d8ab5e04a846
 ---> decb9e147db9
Step 68/73 : RUN sh /home/start_script.sh
 ---> Running in fc86000f9a2f
sed: -e expression #1, char 28: unknown option to `s'
sed: -e expression #1, char 28: unknown option to `s'
The command '/bin/sh -c sh /home/start_script.sh' returned a non-zero code: 1

Best Answer

This works for me:

FROM alpine

COPY ipaddr /ipaddr
COPY ipconf /ipconf
RUN export IPADDR=$(cat /ipaddr) ; sed -i -r "s/IPADDR/${IPADDR}/g" /ipconf
CMD cat /ipconf

With ipconf & ipaddr

IP address is IPADDR

1.2.3.4

Then:

>docker build -t dynchange .
Sending build context to Docker daemon   5.12kB
Step 1/5 : FROM alpine
---> 3fd9065eaf02
Step 2/5 : COPY ipaddr /ipaddr
---> Using cache
---> 1828c3157d41
Step 3/5 : COPY ipconf /ipconf
---> 4f43e88e4425
Step 4/5 : RUN export IPADDR=$(cat /ipaddr) ;  sed -i -r "s/IPADDR/${IPADDR}/g" /ipconf
---> Running in 722c3d3d9d9e
Removing intermediate container 722c3d3d9d9e
---> 32e31198b70a
Step 5/5 : CMD cat /ipconf
---> Running in 72ea59543a7f
Removing intermediate container 72ea59543a7f
---> 73f8a50d650a
Successfully built 73f8a50d650a
Successfully tagged dynchange:latest

>docker run --rm dynchange
IP address is 1.2.3.4

However, this is exactly how I would not do it. A better way is to use a build arg:

FROM alpine

COPY ipconf /ipconf
ARG IPADDR
RUN sed -i -r "s/IPADDR/${IPADDR}/g" /ipconf
CMD cat /ipconf

Then:

>docker build -t dynchange --build-arg IPADDR=4.5.6.7  .
Sending build context to Docker daemon   5.12kB
Step 1/5 : FROM alpine
---> 3fd9065eaf02
Step 2/5 : COPY ipconf /ipconf
---> Using cache
---> f5ac88ee48d5
Step 3/5 : ARG IPADDR
---> Running in 58d972e14660
Removing intermediate container 58d972e14660
---> fc3de48160c6
Step 4/5 : RUN sed -i -r "s/IPADDR/${IPADDR}/g" /ipconf
---> Running in 8ec855697510
Removing intermediate container 8ec855697510
---> 67e946559316
Step 5/5 : CMD cat /ipconf
---> Running in a5260c593c02
Removing intermediate container a5260c593c02
---> 567a31a517d1
Successfully built 567a31a517d1
Successfully tagged dynchange:latest

>docker run --rm dynchange
IP address is 4.5.6.7

However I'm not even sure this is the right solution. I would either:

  • build the configuration file outside of the container, and create/replace it with a COPY. This gives full control on its contents.
  • pass that IP address as a parameter when the container is run (environment variable or else), so you have one single container image that can be used in several environments. The CMD orENTRYPOINT can be script that patches the file before calling the main command. You can also pass the configuration file as a VOLUME (this can avoid issues if CMD is run as an application user and patching the config requires root privileges).
Related Question