Home > Enterprise >  Is it possible to use shell processing to parse environment variables while specifying a non-shell e
Is it possible to use shell processing to parse environment variables while specifying a non-shell e

Time:09-02

What I am trying to achieve

Background information

I have a docker container set up with environmental variables pre-defined by Kubernetes and used as configuration for the docker container.

In the Dockerfile, these are meant to be read and passed to my executable program as parameters, which has been defined as the ENTRYPOINT. The parameters have been defined using the CMD command.

Here is an generalized snippet of my Dockerfile:

ENTRYPOINT [ "/path/to/executable/some-programm" ]
CMD [ "--param1=$FOO", "--param2=$BAR" ]

Since I have defined a non-shell entrypoint, the values of the EVs are not fetched from the key. Thus, "--param1=$FOO" is not expanded to its value; the parameter "some-value" is initialized with the String "$FOO".

Due to the nature of the program, I need to handle SIGTERM and SIGINT signals, which is why I cannot simply set the entry point to a shell. I have read that there are some tools that can forward these signals to the executable, but I am not able to install any additional software.

The target container uses CentOS 7.

My question

Is it possible to parse the container's environment variables as in the example above and pass them to my executable, while at the same time preserving the signal handling done by it?

What I do not want to do

  1. Use a shell command as the entrypoint instead. This would mean that SIGINT and SIGTERM signals no longer reach my executable.
  2. Install software of any kind, as I simply do not have the means to do so.
  3. Use a configuration file instead.

What I have considered

  1. Use a shell script using the "exec" command which replaces the shell with the specified executable, so that signals should reach it properly. However, I cannot seem to figure out a way to do this, as I'm getting a "permission denied" error.
  2. RUN a shell command to echo the environmental variables and store them in an ARG variable, then pass it using CMD. This seems to be the easiest way, but very unclean.

CodePudding user response:

As you describe this, it's not really possible. The rules for constructing the main container command are fairly straightforward:

  1. If either the ENTRYPOINT or CMD (or both) are bare strings, they are wrapped in ["/bin/sh", "-c", "the original command string"]; then
  2. The ENTRYPOINT and CMD word lists are concatenated.

Note that Docker itself does not expand environment variables in either step here, it relies on the shell to do it. If you're using the "container as command" pattern where the ENTRYPOINT is a command and the CMD its arguments, you can't introduce a shell into either half of this, which means there's no way to do environment-variable expansion.

You can override the CMD when you run the container and this might be one approach here. Instead of trying to move environment variables into command-line arguments in the Dockerfile, do that at the point you run the container

docker run \
  my/app \
  "--param1=$FOO" "--param2=$BAR"

If you have control over your application code, consider making it possible to directly accept these configuration settings via environment variables. In some frameworks like Spring Boot you can directly set properties from the environment; in others like the Go github.com/spf13/viper library there is a way to directly import the environment; or you can manually get the environment values and set them as defaults for your command-line options. That would let you avoid manipulating the command line at all and do the equivalent of

docker run \
  -e "MYAPP_PARAM1=$FOO"
  -e "MYAPP_PARAM2=$BAR"
  my/app
  # without setting command or entrypoint at this point

If you really want to keep this exclusively in the Dockerfile, you need to involve a shell to do the parameter expansion. That means you can't split ENTRYPOINT and CMD. If you instruct the shell to exec the process, as you note in a comment, the shell will do its expansion and then replace itself with your process; then your process will still be pid 1 and will get the container signals.

# no ENTRYPOINT
CMD exec /path/to/executable/some-programm "--param1=$FOO" "--param2=$BAR"
  • Related