If you’ve ever had to install a Software Collections (SCL) binary on a Docker image, you probably felt really confused when a simple “yum install” in your Dockerfile failed to work. “I’ve installed plenty of binaries using yum”, you said. What’s the deal with these SCL binaries?
The truth is, the yum command did install the binary correctly, but not in the way that you’d expect without knowing more about SCL. Software Collections allow you to have multiple versions of the same tool available on a system. Because of this, it is up to the administrator to enable the correct version of the tool using commands provided by SCL.
In this post, we will learn how to persistently enable SCL binaries on a Docker image, such that the correct version of the binary is enabled on startup. We’ll look at two different methods of doing this – first by creating an entrypoint and second by utilizing environment variables.
Method #1 – Entrypoint
An entrypoint can be written in the Dockerfile to enable the SCL binary on container startup. Here’s an example Dockerfile:
FROM docker.io/centos:7 # Install SCL release package and python SCL RUN yum -y install centos-release-scl && \ yum -y install --setopt=tsflags=nodocs rh-python35 # Enable rh-python scl binary COPY entrypoint.sh /usr/bin/entrypoint.sh RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT [ "/usr/bin/entrypoint.sh" ]
And the entrypoint.sh script:
#!/bin/bash source scl_source enable rh-python35 exec "$@"
Let’s test this out with:
docker build -t scl-test:latest .
docker run --name scl-test -it scl-test python --version
The result should be (at the time of writing):
Python 3.5.1
Method #2 – Environment Variables
Another way to persistently enable scl binaries in a docker image is to set environment variables.
FROM docker.io/centos:7 # Install SCL release package and python SCL RUN yum -y install centos-release-scl && \ yum -y install --setopt=tsflags=nodocs rh-python35 # Enable rh-python scl binary COPY scl_enable /usr/bin/scl_enable ENV BASH_ENV="/usr/bin/scl_enable" \ ENV="/usr/bin/scl_enable" \ PROMPT_COMMAND=". /usr/bin/scl_enable"
And here’s the scl_enable script:
unset BASH_ENV PROMPT_COMMAND ENV source scl_source enable rh-python35
Let’s test is out with:
docker build -t scl-test:latest .
docker run --name scl-test -it scl-test /bin/bash -c "python --version"
Again, the result should be:
Python 3.5.1
Each environment variable set plays a role in making sure scl is enabled:
- BASH_ENV: Specifies a command or script to run when bash is started non-interactively
- ENV: Specifies a command or script to run when sh is started interactively
- PROMPT_COMMAND: Specifies a command or script to run before bash displays a prompt (for interactive sessions)
Note that in the “docker run” command above, we needed to pass /bin/bash in as a command. This is because we are starting a non-interactive session (leveraging the BASH_ENV variable). Without passing /bin/bash, the scl binary wouldn’t have been enabled.
With the given Dockerfile, you could, however, run docker run –name scl-test -it scl-test to start an interactive /bin/sh session (leveraging ENV), and your scl binaries would be enabled there.
Thanks for Reading!
Hopefully this helps resolve some confusion around Software Collections and persistently enabling scl binaries in a Dockerfile.
I just set environment variables in my Dockerfile to match /opt/rh/rh-python35/enable
I prefer to use “source scl_source enable” in order to abstract away the file path, but setting the env vars in that way should work as well.
Isn’t it simpler to just set ENTRYPOINT [“/usr/bin/scl”, “enable”, “rh-python35” ] and avoid all the scripts?
Using the entrypoint script provided in the post allows for general use cases. The script will allow you to start an interactive bash session or run a specific command, and python 3.5 will be enabled in both cases.
However, you’re on the right track if you have a more specific use case you want to cover. You could build an image using your entrypoint and execute a script inline by running
docker run --name scl-test -it scl-test "python -c 'print(\"Hello world\")'"
. You could also say something likeENTRYPOINT ["/usr/bin/scl","enable","rh-python35","script.py"]
to execute a specific python script using python 3.5.