Replacing Docker environment variables while running the image locally - docker

Docker Image : test
Following are default value in Dockerfile:
ENV users=2
ENV rampup=10
ENV duration=120
ENV environment=DEV
Following is entrypoint
ENTRYPOINT ["/entrypoint.sh"]
entrypoint.sh :
bash ./bin/jmeter.sh -n -t -Jenvironment=${environment} -Jusers=${users} -Jrampup=${rampup} -Jduration=${duration} -j ${workspace}report.log
Now I want to run it locally by replacing the environment variables:
docker run test -e environment=STG -e users=20 -e rampup=10 -e duration=120
But, somehow the values are not getting replaced. What is that I am doing incorrectly, can someone please help?

Any docker run options (like -e to set environment variables) need to go before the image name in the docker run command. Anything after the image name is interpreted as the command you'd like the container to run, and when you also have an entrypoint, gets passed as parameters to the entrypoint. (If you edit your script to include the line echo "$#" you'll see those -e options.)
docker run \
-e environment=STG -e users=20 -e rampup=10 -e duration=120 \
test

Dockerfile and Docker run command seems fine, I am pretty sure the issue is not with Docker, Here is the simplest example that you can.
FROM alpine
ENV users=2
ENV rampup=10
ENV duration=120
ENV environment=DEV
#COPY entrypoint.sh /entrypoint.sh
RUN echo $'#!/bin/ash \n\
echo \"env is Jenvironment=${environment} -Jusers=${users} -Jrampup=${rampup} -Jduration=${duration} -j ${workspace}report.log"' > /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
Build
Docker build -t testenv .
Run
docker run -e rampup=10 -e users=test -t alpintenv ash
So you can try to change you entrypoint.sh to
#!/bin/bash
./bin/jmeter.sh -n -t -Jenvironment=${environment} -Jusers=${users} -Jrampup=${rampup} -Jduration=${duration} -j ${workspace}report.log

Related

Shell script on running a docker container

I created a Dockerfile like below:
From alpine:latest
WORKDIR /
COPY ./init.sh .
CMD ["/bin/sh", "./init.sh"]
and a script file init.sh like below:
#!/bin/sh
mkdir -p mount_point
echo hello > ./mount_point/hello.txt
and I built an image using these:
docker build . -t test_build
and ran it as
docker container run --rm --name test_run -it test_build sh
where there are only two above files in the folder.
In the container, I can find the init.sh file with x (executable) as is in the host.
However, there is no folder mount_point which should be created by
CMD ["bin/sh", "./init.sh"]
Note that, when I run any of the below in the container, it successfully creates mount_point as I expected
sh init.sh
or
/bin/sh init.sh
and
sh -c ./init.sh
Could you tell me where I made mistakes?
When you do
docker container run --rm --name test_run -it test_build sh
the sh at the end overrides the CMD definition in the image and the CMD isn't run.
To verify that your script works, your can change the script to something like this
#!/bin/sh
echo Hello from the script!
mkdir -p mount_point
echo hello > ./mount_point/hello.txt
ls -al ./mount_point
Then run the image without the sh and you should see the 'Hello' message and the directory listing from the ./mount_point directory.
docker container run --rm --name test_run test_build

Docker is "too verbose" in npm-cli-adduser

When my Dockerfile does the RUN command:
RUN npm-cli-adduser -r https://$PRIVATE_REPOSITORY_URL/repository/npm-read -u $PRIVATE_USERNAME -p "$PRIVATE_PASSWORD" -e service-foobar#example.com
It echos the private environment variables in the terminal. I would like to hide these variables, so that users who read the terminal do not see it.
Is this possible?
You can use docker secrets, but you will need to store the variable in a file as far as i understand
Like this:
Dockerfile
FROM node:12
RUN --mount=type=secret,id=mysecret,dst=/foobar echo $(cat /foobar) >> test.txt
# In your case
# RUN npm-cli-adduser -r https://$PRIVATE_REPOSITORY_URL/repository/npm-read -u $PRIVATE_USERNAME -p $(cat /foobar) -e service-foobar#example.com
Build command
docker build --secret id=mysecret,src=mysecret.txt . -t docker-debug
mysecret.txt contect:
YOURPASSWORD
Reference

Unable to pass the env variable to container

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-alpine
ENV CORECLR_ENABLE_PROFILING=1 \
CORECLR_PROFILER={846F5F1C-F9AE-4B07-969E-05C26BC060D8} \
CORECLR_PROFILER_PATH=/opt/datadog/Datadog.Trace.ClrProfiler.Native.so \
DD_INTEGRATIONS=/opt/datadog/integrations.json \
DD_DOTNET_TRACER_HOME=/opt/datadog
WORKDIR /app
RUN apk --no-cache update \
&& apk add bash make curl
ARG TRACER_VERSION=1.19.1
RUN mkdir -p /opt/datadog
RUN curl -L https://github.com/DataDog/dd-trace-dotnet/releases/download/v${TRACER_VERSION}/datadog-dotnet-apm-${TRACER_VERSION}.tar.gz \
| tar xzf - -C /opt/datadog
WORKDIR /app
COPY --from=buildcontainer /app/build .
COPY ./Entrypoint.sh /
RUN chmod +x /Entrypoint.sh && /Entrypoint.sh
ENTRYPOINT ["dotnet","testdatadog.dll"]
Entrypoint.sh
#!/bin/bash
set -e
curl http://169.254.169.254/latest/meta-data/local-ipv4 > temp_var
export DD_AGENT_HOST=$(cat temp_var)
exec "$#"
When I ssh in to my ec2 and see for environment variables I don't see the DD_AGENT_HOST set. When I am manually trying to set the env it works. Am I missing something? appreciate the inputs.
The gist of the problem is that your directive RUN chmod +x /Entrypoint.sh && /Entrypoint.sh got executed at BUILD time, and had no impact on your RUNTIME environment.
Konrad's correct in changing your ENTRYPOINT to have Entrypoint.sh change your environment.
The issue with Konrad's solution is that the run command he used to start the container had no impact on the bash shell that docker ran when he issued the exec command.
Expanding on Konrad's answer a little, you can actually get entrypoint.sh to set your environment for you.
I copied Konrad's Dockerfile, but changed the ENTRYPOINT as follows:
FROM alpine:latest AS build
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
FROM alpine:latest
RUN apk add --no-cache bash
COPY --from=build /entrypoint.sh /entrypoint.sh
ENTRYPOINT [ "/entrypoint.sh", "bash" ]
Now, the entrypoint.sh will set the environment, and execute bash.
I used Konrad's command to run the container:
docker run -itd --rm --name entrypoint entrypoint-test:latest
24a7f3d740c37bb345374a835a465482e3bf49a04361e55205b6d63af48d5c3d
This results in the container being launched. Entrypoint.sh will run bash for us, but it's in daemon mode, so we will have to attach to it:
$ docker attach 24a7f3d740c37bb345374a835a465482e3bf49a04361e55205b6d63af48d5c3d
bash-5.0# echo $DD_AGENT_HOST
127.0.0.1
Alternatively, you can just run the docker image without the -d option, avoiding the daemon mode:
$ docker run -it --rm --name entrypoint entrypoint-test:latest
bash-5.0# echo $DD_AGENT_HOST
127.0.0.1
bash-5.0# echo Hit Ctrl-P Ctrl-Q to leave this container running
All that said, will this work for your dotnet invocation?
ENTRYPOINT [ "/entrypoint.sh", "dotnet" , "testdatadog.dll" ]
This:
RUN chmod +x /Entrypoint.sh && /Entrypoint.sh
actually runs the following command:
bash -c "chmod +x /Entrypoint.sh && /Entrypoint.sh"
Your script sets the environment variable for the Bash instance that runs it, which itself exits as soon as the script is finished, discarding its environment.
You need to move the execution of Entrypoint.sh to the ENTRYPOINT line.
Edit:
So this is my test Dockerfile (note that copying and changing permissions on the script is done in a separate stage to reduce the size of the final image):
FROM alpine:latest AS build
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
FROM alpine:latest
RUN apk add --no-cache bash
COPY --from=build /entrypoint.sh /entrypoint.sh
ENTRYPOINT [ "/entrypoint.sh", "sleep", "10m" ]
and entrypoint.sh:
#!/bin/bash
set -e
echo "127.0.0.1" > temp_var
export DD_AGENT_HOST=$(cat temp_var)
exec "$#"
I ran the following commands:
docker build -t entrypoint-test .
docker run -itd --rm --name entrypoint entrypoint-test:latest
docker exec -it entrypoint bash
and inside the newly opened Bash shell:
export
Result:
declare -x HOME="/root"
declare -x HOSTNAME="c951e699bf7b"
declare -x OLDPWD
declare -x PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
declare -x PWD="/"
declare -x SHLVL="1"
declare -x TERM="xterm"
No DD_AGENT_HOST!
So the I searched for the container's main process (in my case sleep)
ps -a | grep sleep
and got
1 root 0:00 sleep 10m
32 root 0:00 grep sleep
Finally I ran
strings /proc/1/environ
to see the environment of that proces.
Result:
HOSTNAME=3f9760ceb473
PWD=/
HOME=/root
TERM=xterm
SHLVL=0
DD_AGENT_HOST=127.0.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
DD_AGENT_HOST found!
So what's happening?
It's simple. entrypoint.sh sets the variable only for the process it executes - in my case sleep. docker exec creates a new, unrelated process running Bash. Since a new process (both in Linux and Windows) inherits environment from the parent process and the new Bash process, spawned by docker exec, is not a child (but rather a sibling) of the container's main process, it has no knowledge of DD_AGENT_HOST variable.
I hope this helps.
Edit 2:
I believe that what David Maze meant is that you can replace
ENTRYPOINT [ "/entrypoint.sh", "sleep", "10m" ]
with
ENTRYPOINT [ "/entrypoint.sh" ]
CMD [ "sleep", "10m" ]
and then you can run
docker run -it --rm --name entrypoint entrypoint-test:latest bash
so that entrypoint.sh executes bash rather than sleep 10m, allowing you to inspect the environment directly rather than through /proc/$pid/environ.
The equivalent in your Dockerfile would be:
ENTRYPOINT [ "/Entrypoint.sh" ]
CMD [ "dotnet" , "testdatadog.dll" ]

How to get enviroment variables injected via -e key in entrypoint script?

I need to launch my app on the port, set via -e key in docker run command
I run my app in ENTRYPOINT script and try to get $PORT env variable, but there no any env variable, set via -e keys.
Serving the app in Dockerfile
ENTRYPOINT ["sh", "entrypoint.sh"]
entrypoint.sh script:
#!/bin/bash
func start --port $PORT
Docker run command:
docker run -d -p 20937:8081 --name queue_0_middleware -e WEBSITE_CORS_ALLOWED_ORIGINS=https://functions.azure.com,https://functions-staging.azure.com,https://functions-next.azure.com -e PORT=8081
If I run this command locally I add image name like this: sudo docker run -p 15615:8081 30c7bb13d4b4 --name queue_2_middleware -e PORT=8081
That won't do what you expect, the docker command line is order sensitive. Everything after the image name is used to replace the value of CMD inside your image. With the entrypoint defined, those are just args to your entrypoint script. In other words, the docker command looks like:
docker run ${args_to_run} ${image_name} ${cmd_override}
The fix is to reorder your command with the args to run placed before the image name:
sudo docker run -p 15615:8081 --name queue_2_middleware -e PORT=8081 30c7bb13d4b4

Environment variables with docker run -e

Here is my Dockerfile :
FROM ubuntu:16.04
RUN apt-get update
RUN apt-get install -y default-jdk
ADD sample-docker-1.0-SNAPSHOT.jar app.jar
EXPOSE 8080
ENV SITENAME="ASDASD"
ENTRYPOINT ["java", "-jar", "app.jar"]
and here is a bit of Java code that i use:
#Value("${SITENAME:testsite}")
private String siteName;
with this setup everything works good and environment value of SITENAME is indeed "ASDASD". But when i try to set that variable with:
docker run -P -d --name spring spring-app -e SITENAME='DOCKERlocal'
it doesn't work (value is the one from Dockerfile). What am i missing here ?
You want to pass the -e to the docker command. So:
docker run -P -d --name spring -e "SITENAME=DOCKERlocal" spring-app
As you are doing it, you are passing it to the image entrypoint.

Resources