8

In a Dockerfile, the latest instruction is:

CMD  sudo chown -R user:user /home/user/che && \
     sudo service docker start && \
     cd /home/user/che/bin/ && ./che.sh run

It works but I can't pass more arguments to ./che.sh.

The che.sh checks if the internal docker is started after doing other tasks. And it can accept several optional arguments, like -r:111.111.111.111.

I tried to modify the instruction as:

RUN sudo chown -R user:user /home/user/che && \
     sudo service docker start
ENTRYPOINT ["/home/user/che/bin/che.sh"]

in order to invoke it like docker run -it --priviledged my/che -r:111.111.111.111 run, but the che.sh shell will report internal docker is not working well.

I also tried:

ENTRYPOINT ["sudo service docker start", "&&", "/home/user/che/bin/che.sh run"]

even:

ENTRYPOINT ["sh", "-c" "sudo service docker start && /home/user/che/bin/che.sh run"]

But it will report sudo service docker start is not found in $PATH, or the che.sh doesn't run.

What's the correct way to write it?

  1. sudo service docker start should run when che.sh is invoked
  2. I need to pass arguments from outside to che.sh, like docker run -it --priviledged my/che -r:111.111.111.111 run
Freewind
  • 193,756
  • 157
  • 432
  • 708

2 Answers2

8

You have to use supervisord inside a Docker container able to use more complex shell syntax when you creating containers.

Docker documentation about supervisord: https://docs.docker.com/engine/articles/using_supervisord/

YOU CAN use more complex shell syntax (that you want to use) when you create a new container with $ docker run command, however this will not work within systemd service files (due to limitation in systemd) and docker-compose .yml files and the Dockerfiles also.

First, you have to install supervisord in your Dockerfile:

RUN apt-get -y update && apt-get -y dist-upgrade \
    && apt-get -y install \
        supervisor
RUN mkdir -p /var/log/supervisord

Than place this at the end of the Dockerfile:

COPY etc/supervisor/conf.d/supervisord.conf /etc/supervisor/conf.d/
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]

Create a file in etc/supervisor/conf.d/supervisord.conf next to your Dockerfile:

[unix_http_server]
file=/var/run/supervisord.sock
chmod=0777
chown=root:root
username=root

[supervisord]
nodaemon=true
user=root
environment=HOME="/root",USER="root"
logfile=/var/log/supervisord/supervisord.log
pidfile=/var/run/supervisord.pid
childlogdir=/var/log/supervisord
logfile_maxbytes=10MB
loglevel=info

[program:keepalive]
command=/bin/bash -c 'echo Keep Alive service started... && tail -f /dev/null'
autostart=true
autorestart=true
stdout_events_enabled=true
stderr_events_enabled=true
stdout_logfile=/var/log/supervisord/keepalive-stdout.log
stdout_logfile_maxbytes=1MB
stderr_logfile=/var/log/supervisord/keepalive-stderr.log
stderr_logfile_maxbytes=1MB

[program:dcheck]
command=/bin/bash -c 'chmod +x /root/dcheck/repo/dcheck.sh && cd /root/dcheck/repo && ./dcheck.sh'
autostart=true
autorestart=true
stdout_events_enabled=true
stderr_events_enabled=true
stdout_logfile=/var/log/supervisord/dcheck-stdout.log
stdout_logfile_maxbytes=10MB
stderr_logfile=/var/log/supervisord/dcheck-stderr.log
stderr_logfile_maxbytes=1MB

This is a more complex supervisord.conf and probably you don't need many of the commands here, plus you have to change the file locations to your needs. However you can see how to create log files from the bash output of the script.

Later on you have to docker exec in that container and you can watch real-time the log with:

docker exec -it your_running_container /bin/bash -c 'tail -f /var/log/supervisord/dcheck-stdout.log'

You have the option to show subprocess log in the main supervisord log with loglevel=debug, however this is full of timestamps and comments, not the pure bash output like when you run the script directly.

As you can see in my scipt, I keeping alive the container with tail -f /dev/null, however this is a bad practice. The .sh script should keep alive your container on their own.

When you sending your scipt to ENTRYPOINT as ENTRYPOINT ["sudo service docker start", "&&", "/home/user/che/bin/che.sh run"], you want to change the default docker ENTRYPOINT from /bin/sh -c to sudo (also, use full location names).

There are two ways to change docker ENTRYPOINT in Dockerfile. One is to place this in the head section of your Dockerfile:

RUN ln -sf /bin/bash /bin/sh && ln -sf /bin/bash /bin/sh.distrib

Or place this at the bottom:

ENTRYPOINT ['/bin/bash', '-c']

After when you send any CMD to this Dockerfile, it will be run by /bin/bash -c command.

One more thing to note is that the first command takes PID1, so if you want to run the .sh script without tail -f /dev/null in my supervisord script, it will take PID1 process place and CTRL+C command will not gonna work. You have to shut down the container from another shell instance.

But if you run the command with:

[program:dcheck]
command=/bin/bash -c 'echo pid1 > /dev/null && chmod +x /root/dcheck/repo/dcheck.sh && cd /root/dcheck/repo && ./dcheck.sh'

echo pid1 > /dev/null will take PID1 and SIGTERM, SIGKILL and SIGINT will work again with your shell script.

I try to stay away running Docker with --privileged flag. You have many more options to get away on the limitations.

I don't know anything about your stack, but generally good idea to not dockerise Docker in a Container. Is there a specific reason why sudo service docker start is in your Dockerfile?

I don't know anything about this container, is it have to be alive? Because if doesn't, there is a more simple solution, only running the container when it has to process something from the command line. Place this file on the host with the name of run let's say in /home/hostuser folder and give it chmod +x run:

#!/bin/bash
docker run --rm -it -v /home/hostuser/your_host_shared_folder/:/root/your_container_shared_folder/:rw your_docker_image "echo pid1 > /dev/null && chmod +x /root/script.sh && cd  /root && ./script.sh"

In this case, ENTRYPOINT is preferred to be ENTRYPOINT ['/bin/bash', '-c'].

Run this script on the host with:

$ cd /home/hostuser
$ ./run -flag1 -flag2 args1 args2 args3
Lanti
  • 2,299
  • 2
  • 36
  • 69
  • It cost me several hours before I finally got the job done, following your answer and example, and I want to say thank you very very much!! I didn't really realise that docker container is not a vm, but more like a single process. Thanks for emphasis it for me many times and now I finally get it. – Freewind Jan 09 '16 at 14:23
  • 1
    My final solution is following you last "simple" case, neither write `ENTRYPOINT` nor `CMD`, just `RUN sudo chown -R user:user /home/user/che`, and invoke it like this: `docker run -it --rm --privileged --net=host my/che bash -c " sudo service docker start && cd /home/user/che/bin/ && ./che.sh -r:159.203.211.163 run"`, which is working as I expected, although looks a little ugly – Freewind Jan 09 '16 at 14:24
  • 1
    Let me explain why there is a docker in the docker. Che is a web ide, and it uses docker images to run different kinds of projects. But for some reason, I want to run multiple che instances, so I want to run each of them in docker container to make them standalone – Freewind Jan 09 '16 at 14:27
  • 1
    Probably not for this specific project, but for future projects can be really useful the `docker-compose` client which helps easily build Docker container services. Compose not comes with Docker built-in, but you can install it from github. Here is my Dockerised LEMP stack: https://github.com/DJviolin/LEMP/blob/master/install-lemp.sh I can start everything with one command, which is great. Look for the `docker-compose.yml` file in the linked install script. Docker-compose reference: https://docs.docker.com/compose/ Now I so in love with Docker + Docker-compose that I use it for every project. – Lanti Jan 09 '16 at 17:43
  • 1
    thanks for recommending docker-compose, sure I will look into it – Freewind Jan 10 '16 at 12:42
0

Try:
1. in Dockerfile

RUN sudo chown -R user:user /home/user/che && \
    sudo service docker start
ENTRYPOINT ["/bin/sh", "-c", "/home/user/che/bin/che.sh run"]
  1. Start container
    docker run -it --priviledged my/che -r:111.111.111.111
gaal
  • 148
  • 1
  • 5
  • I just tried, but it fails. The "docker" checking in `che.sh` fails. – Freewind Jan 09 '16 at 11:01
  • 2
    When you `RUN` a `service` with `sudo` privileges, this is not gonna work for every possible reason. 1: `service` only starts when you fire up the container from the image. Eg. instead of `RUN service sshd start` you have to use `CMD ["/usr/bin/sshd", "-D"]`. So the `RUN sudo service docker start` command not will be executed on `$ docker run`. 2: In a Dockerfile every command running as root, in fact there's no another user by default in most dockerised linux distros, just the superuser. Installing or using `sudo` in Dockerfile useless. 3: ENTRYPOINT proper usage explanation is in my post. – Lanti Jan 09 '16 at 11:28
  • Also, I used `sshd` example in my upper comment only for presentation purposes, good practice also to not place any SSH services in your docker images. Use `docker exec` instead and keep only one SSH instance on your host OS. – Lanti Jan 09 '16 at 11:30
  • 1
    Docker is not a VM. Instead think about like a mobile Java app on the nokia Symbian S40 platform. It was something that looked like an executible, but if you opened with Winrar, you saw bunch of text files. Well, if you go to the Docker main folder at `/var/lib/docker` on the host, you can see the images and containers as unextracted files. – Lanti Jan 09 '16 at 11:37