How can i Convert CMD to Entrypoint instruction in dockerfile - docker

My cmd instruction in dockerfile is:
CMD /etc/init.d/ssh start && su - gpadmin bash -c /home/gpadmin/entrypoint.sh && tail -f /dev/null
I want to convert it to ENTRYPOINT instruction. My entrypoint script file is entrypoint.sh
I want to enter the entrypoint script with gpadmin user and also i want the container to stay alive with docker run command that is why i am using tail -f /dev/null command

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

Run command on entrypoint in docker outputs no file errors

On a simple dockerfile:
FROM python:3
ENV PYTHONUNBUFFERED 1
WORKDIR /code/
If I run:
docker build -t my_image .
docker run -v ~/Downloads/data/:/home -it -d my_image # mount data folder inside home
docker exec -it container_id sh -c "python script.py -i /home/db.sqlite"
Everything runs ok. But I would like to run the script.py on run so that there is no need for an exec command.
So I added to the dockerfile:
ENTRYPOINT ["python script.py -i /home/db.sqlite"]
But when I run my container now it fails with a file or folder not found error at python script.py
I think the problem is how the ENTRYPOINT syntax works. Your using the exec-form and it does not find the binary (it uses the whole command line as path to the binary).
From https://docs.docker.com/engine/reference/builder/#entrypoint:
ENTRYPOINT has two forms:
ENTRYPOINT ["executable", "param1",
"param2"] (exec form, preferred)
ENTRYPOINT command param1 param2
(shell form)
So try either:
ENTRYPOINT ["/path/to/python", "script.py", "-i", "/home/db.sqlite"]
Or
ENTRYPOINT python script.py -i /home/db.sqlite

Docker: running a command after init on centos7 container with systemd

According to https://hub.docker.com/_/centos/
the Centos7 container must be run with a init process to correctly get systemd working
Dockerfile
FROM centos:7
ENV container docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]
I want to be able to run a script automatically when i call "docker run" so I changed the CMD line to
COPY startup.sh /usr/local/bin/startup.sh
CMD ["/usr/sbin/init", "/usr/local/bin/startup.sh"]
When I docker exec'd into the container i see the process
root 1 0 0 18:20 ? 00:00:00 /usr/sbin/init /usr/local/bin/startup.sh
Despite the above line showing startup.sh along with init, the script, starup.sh, itself was never executed because the script is supposed to start a couple of daemons, and i dont see them running after "docker run".
When I run the script manually (not as part of CMD line, but actually executing it inside of container shell), I would see the daemons running
How can I automate startup.sh to be called? I cannot simply replace CMD line only startup.sh because then systemd would break (I need the script to be called after init is running)
I tried to put /usr/sbin/init inside of startup.sh
ie startup.sh
daemon &
daemon2 &
exec /usr/sbin/init
but the daemons couldnt be run because init was not running
if you put
/usr/sbin/init &
daemon &
daemon2
this wouldnt work because init does not have PID of 1
You do only need a systemd-init thing if you do run services. Otherwise you could just run a shell script and put daemon and daemon2 in the background.
In the case that you would really "systemctl start" something, then you could avoid the cgroup-mapping and systemd-init start ... just use the docker-systemctl-replacement script. It does also run as PID 1 if you like to.

Run docker with dynamic parameter

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?

Dockerfile run /bin/bash id ENTRYPOINT or CMD fails

I would like to run /bin/bash in the case that the CMD or ENTRYPOINT programs fails.
So: CMD top && /bin/bash
I want that when I close top with cntrl-C I get a shell in the container.
Thank you
This is the way to do it:
CMD bash -c 'top; bash'

Resources