Exporting a environment variable in Entrypoint file not work? - docker

I have some problems with exporting an environment variable into docker Entrypoint file.
This is my docker file content:
FROM ubuntu:16.04
ADD entrypoint.sh .
RUN chmod 777 entrypoint.sh
ENTRYPOINT ["./entrypoint.sh"]
CMD ["/bin/bash"]
In the Entrypoint file, I try to run command "export TOKEN=$client_token". Then, I create a container with that image file and I run "docker exec -it /bin/bash" command and into the container I continue run "set" command to show all environment variables. So,I can not find the $TOKEN variable that I exported before.
How can I export an environment variable into the entrypoint file?

You must inject your host environment variable (client_token) into the docker container using '-e' when running:
docker run -it --rm -e client_token=<whatever> <your image>
This works for example with this kind of entrypoint:
#!/bin/bash
export TOKEN=$client_token
echo "The TOKEN is: ${TOKEN}"
# do stuff ...
If you don't know the token value when the container was run, you should inject during attachment (docker exec) and perform required operations inside, but probably it is not valid for you if running container already needed that information.
docker exec -it -e TOKEN=<whatever> <your container>
BRs

Related

Cannot write ssh key to Docker container in CMD

I am trying to write ssh keys to docker image using CMD.
I have docker file like below.
FROM public.ecr.aws/ubuntu/ubuntu:18.04_stable
CMD ["sh", "-c", "echo $PUBLIC_KEY >> ./.ssh/id_rsa.pub"]
CMD ["sh", "-c", "echo $PRIVATE_KEY >> ./.ssh/id_rsa"]
I run the container with env var like so:
docker run -it -d -e PUBLIC_KEY="key1" -e PRIVATE_KEY="key2" my-image
As result, writing both of them doesn't work. However, when I manually docker exec these 2 cmd against the running container, it will write both public key and private key to the correct location.
Can anyone explain this? How should I make the CMD work?
CMD is a way to define a default command when starting a container. There can only be one default command. In the example you have given, the second CMD will be the default command, and the first CMD will not run. The default command will run only when you do not specify a command to run on the command line, i.e. as part of the command line
docker run [OPTIONS] IMAGE[:TAG|#DIGEST] [COMMAND] [ARG...]
if you provide a COMMAND, the CMD in the dockerfile will not be run.
When you issue docker exec, you explicitly run the command line, so it will always run.

Append argument to ENTRYPOINT in Docker run where some args are already defined

I'm using ENTRYPOINT to pass in an argument when running docker run but I cannot get the runtime argument to surface in my script as an argument.
Dockerfile
FROM debian:latest
ENV a="my arg in Dockerfile"
COPY . .
RUN chmod +x myscript.sh
ENTRYPOINT ["/bin/bash", "-c", "/myscript.sh ${a}"]
with myscript.sh
#!/bin/bash
echo "From script: $#"
When I run docker build -t my_image . then docker run -it --rm my_image I get the result as expected: From script: my arg in Dockerfile
But when I run docker run -it --rm my_image from_run I get the same result: From script: my arg in Dockerfile so the "from_run" is not being passed down to the script through ENTRYPOINT.
I read that arguments passed after the image name is appended to the ENTRYPOINT but clearly I'm not understanding something here.
Same result when using the exec form as opposed to JSON form:
ENTRYPOINT /myscript.sh ${a}
https://docs.docker.com/engine/reference/run/#entrypoint-default-command-to-execute-at-runtime
The main container command is made up of two parts. The string you pass after the docker run image-name replaces the Dockerfile CMD, and it's appended to the Dockerfile ENTRYPOINT.
For your docker run command to work, you need to provide the command you want to run as ENTRYPOINT and its arguments as CMD. You do not need an environment variable here. However, it is important that both parts use JSON-array syntax and that neither invokes a shell. If ENTRYPOINT includes a shell then things get syntactically complex (see #KamilCuk's answer); if CMD includes a shell then it won't get invoked but the command will be invoked with /bin/sh and -c as parameters instead.
FROM debian:latest
COPY myscript.sh /usr/local/bin/myscript # preserves execute permissions
ENTRYPOINT ["myscript"] # in a $PATH directory
CMD ["my", "arg", "in", "Dockerfile"]
docker run --rm the-image
docker run --rm the-image my arg from command line
If you want the initial set of command-line arguments to be included and the docker run arguments to be appended, you can move them into the ENTRYPOINT line; note that the docker run --entrypoint is syntactically awkward if you ever do decide you need to remove some of the options.
ENTRYPOINT ["myscript", "--first-default", "--second-default"]
# CMD []
docker run --rm the-image
docker run --rm the-image --user-option
docker run --entrypoint myscript the-image --first-default --no-second-default
If you can update your application to accept options as environment variables in addition to command-line settings, this makes all of this syntactically easier.
ENV FIRST_DEFAULT=yes
ENV SECOND_DEFAULT=yes
CMD ["myscript"]
docker run --rm the-image
docker run --rm -e USER_OPTION=yes the-image
docker run --rm -e SECOND_DEFAULT=no the-image
Bash is Bash, see bash manual how -c pases arguments. The following:
/bin/bash -c "/myscript.sh ${a}" from_run
passes only one argument to myscript.sh and that is unquoted $a, so $a undergoes word splitting and filename expansion. And the argument from_run is assigned to $0. I would do:
ENTRYPOINT ["/bin/bash", "-c", "./myscript.sh \"$a\" \"$#\"", "--"]
Note that it's typical to use upper case (and unique names) for environment variables $a.

Exported environmental variable via docker entrypoint are not shown when logging into the container

Assume a simple Dockerfile
FROM php-fpm:8
ADD entrypoint.sh .
RUN chmod +x entrypoint.sh
ENTRYPOINT ["./entrypoint.sh"]
CMD ["php-fpm"]
In the entry-point script I just export a variable and print the environment
#!/bin/bash
set -e
export FOO=bar
env // just print the environment while entry point is running
exec "$#"
Then I build the image as myimage and use it to deploy a stack in docker swarm mode
docker stack deploy -c docker-compose.yml teststack
// The docker-compose.yml file used is the following:
app:
image: myimage:latest
environment:
APP_ENV: production
Now the question: If a check the logs of the app service I can see (because of the env command in the entry point) that the FOO variable is exported
docker service logs teststack_app
teststack_app.1.nbcqgnspn1te#soulatso | PWD=/var/www/html
teststack_app.1.nbcqgnspn1te#soulatso | FOO=bar
teststack_app.1.nbcqgnspn1te#soulatso | HOME=/root
However if I login in the running container and manually run env the FOO variable is not shown
docker container exec -it teststack_app.1.nbcqgnspn1tebirfatqiogmwp bash
root#df9c6d9c5f98:/var/www/html# env // run env inside the container
PWD=/var/www/html
HOME=/root
// No FOO variable :(
What I am missing here?
A debugging shell you launch via docker exec isn't a child process of the main container process, and doesn't run the entrypoint itself, so it doesn't see the environment variables that are set there.
Depending on what you're trying to do, there are a couple of options to get around this.
If you're just trying to inspect what your image build produced, you can launch a debugging container instead. The command you pass here will override the CMD in the Dockerfile, and when your entrypoint script does something like exec "$#" to run the command it gets passed, it will run this command instead. This lets you inspect things in an environment just after your entrypoint's first-time setup has happened.
docker-compose run app env | grep FOO
docker-compose run app bash
Or, if the only thing your entrypoint script is to set environment variables, you can explicitly invoke it.
docker-compose exec app ./entrypoint.sh bash
It is important that your entrypoint script accept an ordinary command as parameters. If it is a shell script, it should use something like exec "$#" to launch the main container process. If your entrypoint ignores its parameters and launches a fixed command, or if you've set ENTRYPOINT to a language interpreter and CMD to a script name, these debugging techniques will not work.

I want to run a script during container run based on env variable that I pass

I want to run a script during run time and not during image build.
The script runs based on env variable that I pass during container run.
Script:
#!/bin/bash
touch $env
Docker file
FROM busybox
ENV env parm
RUN mkdir PRATHAP
ADD apt.sh /PRATHAP
WORKDIR /PRATHAP
RUN chmod 777 apt.sh
CMD sh apt.sh
when I try to run: docker container run -it -e env=test.txt sh
the script is not running
I am just getting the sh terminal. If I remove it the the container is not alive.. Please help me how to achieve it
Your docker run starts sh which overrides your CMD in Dockerfile. To get around this, you need to replicate the original CMD via the command line.
$ docker run -it -e env=test.txt <image:tag> sh -c "./init.sh; sh"
Remember that a Docker container runs a single command, and then exits. If you docker run your image without overriding the command, the only thing the container will do is touch a file inside the isolated container filesystem, and then it will promptly exit.
If you need to do some startup-time setup, a useful pattern is to write it into an entrypoint script. When a container starts up, Docker runs whatever you have named as the ENTRYPOINT, passing the CMD as additional parameters (or it just runs CMD if there is no ENTRYPOINT). You can use the special shell command exec "$#" to run the command. So revisiting your script as an entrypoint script:
#!/bin/sh
# ^^ busybox image doesn't have bash (nor does alpine)
# Do the first-time setup
touch "$env"
# Launch the main container process
exec "$#"
In your Dockerfile set this script to be the ENTRYPOINT, and then whatever long-running command you actually want the container to do to be the CMD.
FROM busybox
WORKDIR /PRATHAP # Also creates the directory
COPY apt.sh . # Generally prefer COPY to ADD
RUN chmod 0755 apt.sh # Not world-writable
ENV env parm
ENTRYPOINT ["./apt.sh"] # Must be JSON-array syntax
# Do not need to name interpreter, since
# it is executable with #! line
CMD sh # Or whatever the container actually does

Entering docker container with exec losing PATH environment variable

Here is my Dockerfile:
FROM ros:kinetic-ros-core-xenial
CMD ["bash"]
If I run docker build -t ros . && docker run -it ros, and then from within the container echo $PATH, I'll get:
/opt/ros/kinetic/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
If I exec into the container (docker exec -it festive_austin bash) and run echo $PATH, I'll get:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Why are the environment variables different? How can I get a new bash process on the container with the same initial environment?
The ENTRYPOINT command is only invoked on docker run, not on docker exec.
I assume that this /ros_entrypoint.sh script is responsible for adding stuff to PATH. If so, then you could do something like this for docker exec:
docker exec -it <CONTAINER_ID> /ros_entrypoint.sh bash
docker exec only gets environment variables defined in Dockerfile with instruction ENV. With docker exec [...] bash you additionally get those defined somewhere for bash.
Add this line to your Dockerfile:
ENV PATH=/opt/ros/kinetic/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
or shorter:
ENV PATH=/opt/ros/kinetic/bin:$PATH
This is old question but since it's where google directed me I thought I'll share solution I ended up using.
In your entrypoint script add a section similar to this:
cat >> ~/.bashrc << EOF
export PATH="$PATH"
export OTHER="$OTHER"
EOF
Once you rebuild your image you can exec into your container (notice bash is invoked in interactive mode):
docker run -d --rm --name container-name your_image
docker exec -it container-name /bin/bash -i
If you echo $PATH now it should be the same as what you have set in .bashrc

Resources