Use container's environment variable for a command lie - bash

I would like to use some environment variables in a bash script that contains :
#!/usr/bin/env bash
docker-compose exec apache bash -c "\
printenv | grep BLACKFIRE\
&& blackfire-agent --register --server-id=$BLACKFIRE_SERVER_ID --server-token=$BLACKFIRE_SERVER_TOKEN \
&& /etc/init.d/blackfire-agent restart"
echo "Blackfire agent configured !"
I pass the variable from my .env :
BLACKFIRE_SERVER_ID=xxxxx
BLACKFIRE_SERVER_TOKEN=xxxxx
BLACKFIRE_CLIENT_ID=xxxxx
BLACKFIRE_CLIENT_TOKEN=xxxxx
using docker-compose.yml
environment:
- DAMART_ENV=dev
- BLACKFIRE_SERVER_ID=${BLACKFIRE_SERVER_ID}
- BLACKFIRE_SERVER_TOKEN=${BLACKFIRE_SERVER_TOKEN}
- BLACKFIRE_CLIENT_ID=${BLACKFIRE_CLIENT_ID}
- BLACKFIRE_CLIENT_TOKEN=${BLACKFIRE_CLIENT_TOKEN}
The apache container has the environment variables (here is the result of printenv)
If I change the variables by their values it works but I don't want to use them directly in this script.
How should I call the variables for them to work.

The code repository usually has a function to store secret keys and environment tokens. For instance, github secrets can be kept in https://github.com/user/repo/settings/secrets/actions for your actions or https://github.com/user/repo/settings/secrets/codespaces/new for the repo.

The problem comes from the use of " (double quotes) that made the string to be interpreted not by the container but by the machine running the docker exec. This machine did not have the env variables as they are set in the container.
Replace with ' (simple quotes) make the script to use the environment variables set in the container.
docker-compose exec apache bash -c '\
blackfire-agent --register --server-id=$BLACKFIRE_SERVER_ID --server-token=$BLACKFIRE_SERVER_TOKEN \
&& /etc/init.d/blackfire-agent restart'

Related

Setting environment variable derived in container at runtime within a shell

I have custom entrypoint where a environment variable is exported. The value of the environment variable is constructed using two other variables provided at runtime.
Snippet from Dockerfile CMD ["bash", "/opt/softwareag/laas-api-server/entrypoint.sh"].
Snippet from entrypoint.sh
export URL="$SCHEME://$HOST:$PORT"
echo "URL:$URL"
Command docker run -e HOST="localhost" -e PORT="443" mycentos prints URL:localhost:443 as expected but the same variable appears to have lost the value when the following command is executed.
docker exec -ti <that-running-container-from-myimage> bash
container-prompt> echo $URL
<empty-line>
Why would the exported variable appear to have lost the value of URL? What is getting lost here?
The environment variable will not persist across all bash session. when the container run it will only available in that entrypoint session but later it will not available if it set using export.
docker ENV vs RUN export
If you want to use across all session you should set them in Dockerfile.
ENV SCHEME=http
ENV HOST=example.com
ENV PORT=3000
And in the application side, you can use them together.also it will be available for all session.
curl "${SCHEME}://${HOST}:${PORT}
#
Step 8/9 : RUN echo "${SCHEME}://${HOST}:${PORT}"
---> Running in afab41115019
http://example.com:3000
Now if we look into the way you are using, it will not work because
export URL="$SCHEME://$HOST:$PORT"
# only in this session
echo "URL:$URL"
# will be available for node process too but for this session only
node app.js
For example look into this Dockerfile
FROM node:alpine
RUN echo $'#!/bin/sh \n\
export URL=example.com \n\
echo "${URL}" \n\
node -e \'console.log("ENV URL value inside nodejs", process.env.URL)\' \n\
exec "$#" \n\
' >> /bin/entrypoint.sh
RUN chmod +x /bin/entrypoint.sh
entrypoint ["entrypoint.sh"]
So you when you Run docker container for the first time you will able to see the expected response.
docker run -it --rm myapp
example.com
ENV URL value inside nodejs example.com
Now we want to check for later session.
docker run -it --rm abc tail -f /dev/null
example.com
ENV URL value inside nodejs example.com
so the container is up during this time, we can verify for another session
docker exec -it myapp sh -c "node -e 'console.log(\"ENV URL value inside nodejs\", process.env.URL)'"
ENV URL value inside nodejs undefined
As we can same script but different behaviour because of docker, so the variable is only available in that session, you can write them to file if you are interested in later use.

Setting environment variable for docker container at runtime

I have a requirement to set the environment variable for docker container at runtime. The value can only be determined at runtime by combination two other variables which are available at runtime. In a simpler form, the following is not working.
docker run -ti -e host="name" -e port="123" centos:7 bash -c "export url=$host:$port; env"
returns the following where url is empty when the value of $host and $port is available to construct $url ?
...
host=name
url=:
port=123
...
You have to single quote the shell command to avoid your interactive shell expanding the variable before the docker shell sees them:
docker run -ti -e host="name" -e port="123" centos:7 bash -c 'export url=$host:$port; env'
With single quotes, your shell will pass export url=$host:$port; env to Docker.
With double quotes, your current shell will first dutifully expand the variables, and therefore just pass url=:; env

Access a bash script variable outside the docker container in which the script is running

I have a bash script running inside a docker container. In this script, I set the value of some variable.
Can I somehow access the value of this variable outside the container?
I tried to make the variable "global" but could not figure out how to do it. Is it a good idea to make the required variable an environment variable inside the container?
How to reproduce
Create a bash script called temp.sh with the following contents:
a=$RANDOM
Now, run this file in a docker container as follows:
docker run -it --rm -v $(pwd):/opt alpine sh -c "sh /opt/temp.sh"
Desired behaviour: To be able to access the variable a outside the docker container
Credit: This comment by Mark
I mounted a directory on the docker filesystem using
docker run -v <host-file-system-directory>:<docker-file-system-directory>
In the bash script, I added
echo "$variable" >docker-file-system-directory/variable.txt
As I had mounted a host filesystem directory on the docker filesystem, I can still access variable.txt simply using cat <host-file-system-directory>/variable.txt
Note that docker-file-system-directory must be an absolute path, and not a relative path.
One way of achieving that is using docker exec, if your container is running and has access to bash.
#!/usr/bin/env bash
set -x
yourContainerName="testContainerName"
test=$(docker exec -i "${yourContainerName}" bash <<EOF
# do some work here e.g. execute your script
testVar="thisIsTest" # the value we want to access outside of container
echo \$testVar
EOF
)
echo $test
We pass a multiline script to docker container, which in the end echo's the value we need. This value is then accessible from shell that executed docker exec.
Output looks like this:
++ docker exec -i testContainerName bash
+ test=thisIsTest
+ echo thisIsTest
thisIsTest

Set environment variables in Docker

I'm having trouble with Docker creating a container that does not have environment variables set that I know I set in the image definition.
I have created a Dockerfile that generates an image of OpenSuse 42.3. I need to have some environment variables set up in the image so that anyone that starts a container from the image can use a code that I've compiled and placed in the image.
I have created a shell file called "image_env_setup.sh" that contains the necessary environment variable definitions. I also manually added those environment variable definitions to the Dockerfile.
USER codeUser
COPY ./docker/image_env_setup.sh /opt/MyCode
ENV PATH="$PATH":"/opt/MyCode/bin:/usr/lib64/mpi/gcc/openmpi/bin"
ENV LD_LIBRARY_PATH="/usr/lib64:/opt/MyCode/lib:"
ENV PS1="[\u#docker: \w]\$ "
ENV TERM="xterm-256color"
ENV GREP_OPTIONS="--color=auto"
ENV EDITOR=/usr/bin/vim
USER root
RUN chmod +x /opt/MyCode/image_env_setup.sh
USER codeUser
RUN /opt/MyCode/image_env_setup.sh
RUN /bin/bash -c "source /opt/MyCode/image_env_setup.sh"
The command that I use to create the container is:
docker run -it -d --name ${containerName} -u $userID:$groupID \
-e USER=$USER --workdir="/home/codeUser" \
--volume="${home}:/home/codeUser" ${imageName} /bin/bash \
The only thing that works is to pass the shell file to be run again when the container starts up.
docker start $MyImageTag
docker exec -it $MyImageTag /bin/bash --rcfile /opt/MyCode/image_env_setup.sh
I didn't think it would be that difficult to just have the shell variables setup within the container so that any entry into it would provide a user with them already defined.
RUN entries cannot modify environment variables (I assume you want to set more variables in image_env_setup.sh). Only ENV entries in the Dockerfile (and docker options like --rcfile can change the environment).
You can also decide to source image_env_setup.sh from the .bashrc, of course.
For example, you could either pre-fabricate a .bashrc and pull it in with COPY, or do
RUN echo '. /opt/MyCode/image_env_setup.sh' >> ~/.bashrc
you can put /opt/MyCode/image_env_setup.sh in ~/.bash_profile or ~/.bashrc of the container so that everytime you get into the container you have the env's set

Setting environment variables when running docker in detached mode

If I include the following line in /root/.bashrc:
export $A = "AAA"
then when I run the docker container in interactive mode (docker run -i), the $A variable keeps its value. However if I run the container in detached mode I cannot access the variable. Even if I run the container explicitly sourcing the .bashrc like
docker run -d my_image /bin/bash -c "cd /root && source .bashrc && echo $A"
such line produces an empty output.
So, why is this happening? And how can I set the environment variables defined in the .bashrc file?
Any help would be very much appreciated!
The first problem is that the command you are running has $A being interpreted by your hosts shell (not the container shell). On your host, $A is likely black, so your effectively command becomes:
docker run -i my_image /bin/bash -c "cd /root && source .bashrc && echo "
Which does exactly as it says. We can escape the variable so it is sent to the container and properly evaluated there:
docker run -i my_image /bin/bash -c "echo \$A"
But this will also be blank because, although the container is, the shell is not in interactive mode. But we can force it to be:
docker run -i my_image /bin/bash -i -c "echo \$A"
Woohoo, we finally got our desired result. But with an added error from bash because there is no TTY. So, instead of interactive mode, we can just set a psuedo-TTY:
docker run -t my_image /bin/bash -i -c "echo \$A"
After running some tests, it appears that when running a container in detached mode, overidding the default environment variables doesnt always happen the way we want, depending on where you are in the Dockerfile.
As an exemple if, running a container in a detached container like so:
docker run **-d** --name image_name_container image_name
Whatever ENV variables you defined within the Dockerfile takes effect everywhere (read the rest and you will understand what the everywhere means).
example of a simple dockerfile (alpine is just a lighweight linux distribution):
FROM alpine:latest
#declaring a docker env variable and giving it a default value
ENV MY_ENV_VARIABLE dummy_value
#copying two dummy scripts into a place where i can execute them straight away
COPY ./start.sh /usr/sbin
COPY ./not_start.sh /usr/sbin
#in this script i could do: echo $MY_ENV_VARIABLE > /test1.txt
RUN not_start.sh
RUN echo $MY_ENV_VARIABLE > /test2.txt
#in this script i could do: echo $MY_ENV_VARIABLE > /test3.txt
ENTRYPOINT ["start.sh"]
Now if you want to run your container in detached and override some ENV variables, like so:
docker run **-d** -e MY_ENV_VARIABLE=new_value --name image_name_container image_name
Surprise! The var MY_ENV_VARIABLE is only overidden inside the script that is run in the ENTRYPOINT (and i checked, same thing happens if your replace ENTRYPOINT with CMD). It would also be overidden in a subscript that you could call from this start.sh script. But the MY_EV_VARIABLE variables that are called within a RUN dockerfile command or within the dockerfile itself do not get overidden.
In other words we would have $MY_ENV_VARIABLE being replaced by the value dummy_value and new_value depending on if you are in the ENTRYPOINT or not.

Resources