Run docker with dynamic parameter - docker

I'm trying to run a java application on a docker container where the jvm argument of the java program would be dynamic.
Dockerfile:
FROM amazonlinux
ADD http://company.com/artifactory/bins-release-local/com/marc/1.3.1/marc-1.3.1.tar.gz /root/
ADD log4j2.xml /root/
RUN tar xzf /root/marc-1.3.1.tar.gz -C /root && rm -f /root/marc-1.3.1.tar.gz
RUN yum install -y java
ENTRYPOINT ["/bin/bash", "-c", "/usr/bin/java", "${JVM_ARGS}", "-jar", "/root/marc.jar"]
I try to run the container like so:
docker run --rm -it --env-file jvm_args.env -e CLIENT=google moshe/java:latest
And the jvm_args.env is:
JVM_ARGS=-d64
-Dicmq=${CLIENT}
-Dlog4j.configurationFile=/root/log4j2.xml
-server
I couldn't seem to get it to work. I need the client to be dynamic and the JVM_ARGS should contain the client.
Ideas?

Related

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" ]

docker create | Error response from daemon: No command specified

Attached there is my Dockerfile. My intention is to use the following command:
docker build -t fbprophet . && \
docker create --name=awslambda fbprophet && \
docker cp awslambda:/var/task/venv/lib/python3.7/site-packages/lambdatest.zip . \
docker rm awslambda
However, I always receive this error here:
Error response from daemon: No command specified
When running these commands here, it works. I have to run it in different shells so the container doesn't stop running before my export is done.
docker build -t fbprophet . && docker container rm awslambda && docker run -it --name=awslambda fbprophet bash
docker cp awslambda:/var/task/venv/lib/python3.7/site-packages/lambdatest.zip .
Dockerfile:
FROM lambci/lambda:build-python3.7
ENV VIRTUAL_ENV=/venv
RUN python3 -m venv $VIRTUAL_ENV
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
COPY requirements.txt .
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
WORKDIR /var/task/venv/lib/python3.7/site-packages
COPY lambda_function.py .
COPY .lambdaignore .
RUN echo "Package size: $(du -sh | cut -f1)"
RUN zip -9qr lambdatest.zip *
RUN cat .lambdaignore | xargs zip -9qr /var/task/lambdatest.zip * -x
Probably the easiest way to get files out of an image you've built is to mount a volume on to a container, and make the main container process just be a cp command:
docker run \
--rm \
-v $PWD:/export \
fbprophet \
cp lambdatest.zip /export
(If you've built an application that uses ENTRYPOINT ["python"] or some such, you need to specify --entrypoint /bin/cp before the image name, and then put the arguments after the image name. Using CMD instead avoids this complication.)
Usually a Docker image has a packaged application (or a reasonable base one could build an application on), and running a container actually runs that application. An image is kind of an inconvenient way to just pass around files. You might find it easier and safer to run the same set of commands outside of Docker on your host to create a virtual environment, and you can just directly cp the file out of there when you're done.

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.

How to write docker file to run a docker run command inside an image

I have a shell script which creates and executes docker containers using docker run command. I want to keep this script in a docker image and want to run this shell script. I know that we cannot run docker inside a container. Is it possible to create a docker file to achieve this?
Dockerfile:
FROM ubuntu:latest
RUN apt-get update && apt-get install -y vim-gnome curl
RUN curl -L https://raw.githubusercontent.com/xyz/abx/test/testing/testing_docker.sh -o testing_docker.sh
RUN chmod +x testing_docker.sh
CMD ["./testing_docker.sh"]
testing_docker.sh:
docker run -it docker info (sample command)

Why does docker "--filter ancestor=imageName" find the wrong container?

I have a deployment script that builds new images, stop the existing containers with the same image names, then starts new containers from those images.
I stop the container by image name using the answer here: Stopping docker containers by image name - Ubuntu
But this command stops containers that don't have the specified image name. What am I doing wrong?
See here to watch docker stopping the wrong container:
Here is the dockerfile:
FROM ubuntu:14.04
MAINTAINER j#eka.com
# Settings
ENV NODE_VERSION 5.11.0
ENV NVM_DIR /root/.nvm
ENV NODE_PATH $NVM_DIR/versions/node/v$NODE_VERSION/lib/node_modules
ENV PATH $NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH
# Replace shell with bash so we can source files
RUN rm /bin/sh && ln -s /bin/bash /bin/sh
# Install libs
RUN apt-get update
RUN apt-get install curl -y
RUN curl https://raw.githubusercontent.com/creationix/nvm/v0.31.0/install.sh | bash \
&& chmod +x $NVM_DIR/nvm.sh \
&& source $NVM_DIR/nvm.sh \
&& nvm install $NODE_VERSION \
&& nvm alias default $NODE_VERSION \
&& nvm use default
RUN apt-get clean
# Install app
RUN mkdir /app
COPY ./app /app
#Run the app
CMD ["node", "/app/src/app.js"]
I build like so:
docker build -t "$serverImageName" .
and start like so:
docker run -d -p "3000:"3000" -e db_name="$db_name" -e db_username="$db_username" -e db_password="$db_password" -e db_host="$db_host" "$serverImageName"
Why not use the container name to differentiate you environments?
docker run -d --rm --name nginx-dev nginx
40ca9a6db09afd78e8e76e690898ed6ba2b656f777b84e7462f4af8cb4a0b17d
docker run -d --rm --name nginx-qa nginx
347b32c85547d845032cbfa67bbba64db8629798d862ed692972f999a5ff1b6b
docker run -d --rm --name nginx nginx
3bd84b6057b8d5480082939215fed304e65eeac474b2ca12acedeca525117c36
Then use docker ps
docker ps -f name=nginx$
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3bd84b6057b8 nginx "nginx -g 'daemon ..." 30 seconds ago Up 28 seconds 80/tcp, 443/tcp nginx
According to the docs --filter ancestor could be finding the wrong containers if they are in any way children of other containers.
So to be sure my images are separate right from the start I added this line to the start of my dockerfile, after the FROM and MAINTAINER commands:
RUN echo DEVTESTLIVE: This line ensures that this container will never be confused as an ancestor of another environment
Then in my build scripts after copying the dockerfile to the distribution folder I replace DEVTESTLIVE with the appropriate environment:
sed -i -e "s/DEVTESTLIVE/$env/g" ../dist/server/dockerfile
This seems to have worked; I now have containers for all three environments running simultaneously and can start and stop them automatically through their image names.

Resources