Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I detect the interactive flag in a container?

Firstly, this question is not a duplicate of the question here. I am currently learning docker, and am required to create a dockerfile which installs tomcat and runs it at the start of a container with the entrypoint command:

Following are the contents of my dockerfile:

FROM ubuntu:latest

LABEL MAINTAINER="kesarling"

RUN apt update
RUN apt upgrade -y
RUN apt install apt-utils -y
RUN apt install maven gradle -y
RUN apt install wget tar zip unzip openjdk-14-jdk -y

RUN mkdir /usr/local/apache-tomcat-v8.5.55
RUN wget http://www-us.apache.org/dist/tomcat/tomcat-8/v8.5.55/bin/apache-tomcat-8.5.55.tar.gz -O /tmp/apache-tomcat-v8.5.55.tar.gz
RUN cd /tmp && tar xvfz apache-tomcat-v8.5.55.tar.gz
RUN cp -Rv /tmp/apache-tomcat-8.5.55/* /usr/local/apache-tomcat-v8.5.55/

RUN mkdir /usr/local/spring-v5.2.6
RUN wget https://repo.spring.io/release/org/springframework/spring/5.2.6.RELEASE/spring-5.2.6.RELEASE-dist.zip -O /tmp/spring-v5.2.6.zip
RUN cd /tmp && unzip spring-v5.2.6.zip
RUN cp -Rv /tmp/spring-framework-5.2.6.RELEASE/* /usr/local/spring-v5.2.6/



RUN cd ~
RUN touch server-start.sh
RUN echo "#!/bin/sh" | cat > server-start.sh
# start of condition
RUN echo 'bash -c "/usr/local/apache-tomcat-v8.5.55/bin/catalina.sh run&"' | cat >> server-start.sh
RUN echo "/bin/bash" | cat >>server-start.sh
# end of condition
RUN chmod +x server-start.sh

EXPOSE 8080

ENTRYPOINT [ "./server-start.sh" ]

As the server starts as a background process, it runs fine only when I give the -it flag. Else, as expected, the container quits the moment I detach it.


So, in a nutshell:

docker container run -it -p 8080:8080 <mydockername>

Works but:

docker container run -dp 8080:8080 <mydockername>

Does not (as expected). That is where the condition comes in. In a nutshell, I need it to detect if the docker has been run in background or in interactive mode.


The condition block mentioned in the dockerfile needs to be as follows:

If I am executing it with the -it flag:

RUN echo 'bash -c "/usr/local/apache-tomcat-v8.5.55/bin/catalina.sh run&"' | cat >> server-start.sh
RUN echo "/bin/bash" | cat >>server-start.sh

Else if I am executing with the -d flag:

RUN echo 'bash -c "/usr/local/apache-tomcat-v8.5.55/bin/catalina.sh run"' | cat >> server-start.sh

(Notice that the /bin/bash has been removed)


How do I go about this?

P.S. This is my first week into docker, so please bear with my dockerfile :P

Oh, and not to mention that searching detect if the container has been run with an interactive flag doesn't bring up anything useful on Google

like image 378
kesarling He-Him Avatar asked Jun 09 '20 16:06

kesarling He-Him


2 Answers

At build time, you won't know what the runtime environment will look like. So there's no way to modify the RUN statements based on the -it flags or lack there of, we don't have time travel to look into the future for that, and the same image could be run multiple times with different flags.

You could do this within the entrypoint script. /dev/stdin which is mapped for interactive containers points to /proc/self/fd/0 which will point to different things based on whether you have -i, -it, or neither:

$ docker run -it --rm busybox ls -al /dev/stdin
lrwxrwxrwx    1 root     root            15 Jun 18 14:43 /dev/stdin -> /proc/self/fd/0

$ docker run -it --rm busybox ls -al /proc/self/fd/0
lrwx------    1 root     root            64 Jun 18 14:43 /proc/self/fd/0 -> /dev/pts/0

$ docker run -i --rm busybox ls -al /proc/self/fd/0
lr-x------    1 root     root            64 Jun 18 14:50 /proc/self/fd/0 -> pipe:[9858991]

$ docker run --rm busybox ls -al /proc/self/fd/0
lrwx------    1 root     root            64 Jun 18 14:43 /proc/self/fd/0 -> /dev/null

So if you stat the link to see if it's going to /dev/null or not, that would give you the answer to the question you asked.


Side note, if you only care about the -t, there's another check in shell you can run, [ -t 0 ], e.g.:

$ docker run -it --rm busybox /bin/sh -c 'if [ -t 0 ]; then echo tty; else echo no tty; fi'
tty

$ docker run -i --rm busybox /bin/sh -c 'if [ -t 0 ]; then echo tty; else echo no tty; fi'
no tty

$ docker run --rm busybox /bin/sh -c 'if [ -t 0 ]; then echo tty; else echo no tty; fi'
no tty

However, best practice with docker is to run the app itself in the foreground, as pid 1. And if you need to enter the container for debugging in a development environment, use docker exec for that. Your entrypoint then becomes:

ENTRYPOINT [ "/usr/local/apache-tomcat-v8.5.55/bin/catalina.sh", "run" ]

And by doing that, you avoid an extra shell in pid 1 that could block container stop signals from gracefully stopping the app.

Then to debug, you'd exec after the run, using the container name:

docker container run -dp 8080:8080 -n tomcat-app <mydockername>
docker container exec -it tomcat-app /bin/sh
like image 107
BMitch Avatar answered Oct 17 '22 22:10

BMitch


You don't need the start.sh at all.

Just use CMD directive as follows.

CMD ["/usr/local/apache-tomcat-v8.5.55/bin/catalina.sh", "run"]

Both the following command will start tomcat

docker run -it -p 8080:8080 <imagename> 

docker run -p 8080:8080 <imagename>

In case you want to debug something inside the container and want to access container shell, you can start a container and run bash as follows

docker run -it <imagename> bash 

This will override the defaut CMD with bash.


You can also replace CMD with ENTRYPOINT in the above suggestion but then if you want to access the container shell you have to do as follows -

docker run --entrypoint bash -it <imagename>

You can also look at official tomcat images and their dockerfiles here - https://hub.docker.com/_/tomcat

like image 31
Shashank V Avatar answered Oct 17 '22 20:10

Shashank V