skip to Main Content

Using a Dockerfile to build an image which I later use to run a container used to cross-compile a binary for a target platform. This container is used for development, so I work hours inside this container. The "make" command is building the binary properly.

For debug purposes, I need the output of the make command being saved to a logfile transparently. I solved this adding a bash "make" function to my Dockefile:

RUN echo 'make() { DATE=$(date "+%Y%m%d-%H%M%S"); LOGNAME=build_$DATE.log; $(which make) "$@" 2>&1 | tee /tmp/$LOGNAME; }' >> ~/.bashrc

As you can see, I modify the .bashrc. Function "make" is declared when I run into the container. Inside the container, whenever I run "make" command, the logs are always saved into /tmp/$LOGNAME, as expected.

I wonder if there is a more convenient / clean way to define a bash function in the running shell without defining this RUN command in the Dockefile.

3

Answers


  1. I will

    • Externalize your Bash function in a dedicated file make.sh aside your Dockerfile:
    #!/usr/bin/env bash
    
    make() {
       DATE=$(date "+%Y%m%d-%H%M%S")
       LOGNAME=build_$DATE.log
       $(which make) "$@" 2>&1 | tee /tmp/$LOGNAME
    }
    
    • Add a Dockerfile instruction to copy the make.sh script in the container:
    COPY make.sh ~/make.sh
    
    • Add a Dockerfile instruction to source the make.sh script in the .bashrc:
    RUN echo "source ~/make.sh" >> .bashrc
    

    [ EDIT ]

    After reading @david-maze answer getting rid of the .bashrc sourcing part and copying the script directly under /usr/local/bin seems to be a more efficient and cleaner way since it allows calling the function both from inside and outside the container.

    Login or Signup to reply.
  2. One alternative is to fully control your .bashrc file from within the host and copy it to the image with a Dockerfile COPY instruction.

    Login or Signup to reply.
  3. Most paths of invoking Docker containers don’t read shell dotfiles or have well-defined concepts of home directories. It’s rarely useful to write to a .bashrc in your Dockerfile since it’s highly likely that file won’t be read; for example, docker run --rm your-image make won’t read the .bashrc file before trying to run the make command.

    What you can do is write these commands into a shell script. This is just a file with a list of commands that will be run. Outside of Docker, create a simple file:

    #!/bin/sh
    # ^^ Name the interpreter that will run this script.
    # This must be the absolute very first line of the file.
    # Use /bin/sh in most cases; many images do not have GNU bash.
    # (And make sure to avoid bash-specific syntax, like "function"
    # or "source").
    
    # This is the sequence of commands you had originally,
    # one to a line.
    DATE=$(date "+%Y%m%d-%H%M%S")
    LOGNAME="build_$DATE.log"
    make "$@" 2>&1 | tee "/tmp/$LOGNAME"
    

    Mark this script as executable and run it.

    chmod +x make_and_log
    ./make_and_log compile
    ls -l build_*.log
    tail build_20220706-063319.log
    

    Now in your Dockerfile, you just need to copy this script into somewhere that’s in the standard $PATH directories; /usr/local/bin is frequently a good choice.

    COPY make_and_log /usr/local/bin/
    

    You can’t use shell scripts like this if they need to modify environment variables in the containing shell (if you needed to export LOGNAME and use it later) but this script doesn’t need that. Otherwise, a shell script will generally be a little easier to manage than a shell function. In this case note that we’ve never needed to escape a quote inside a quoted string we’re writing out to a file; we’ve just written the script and hand-tested it separately from the Docker setup.

    Since this is now an ordinary program in a normal place, you can just run it

    docker run --rm 
      -v "$PWD:/src" -w /src 
      the-image 
      make_and_log compile
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search