如何编写一个 Dockerfile,我可以启动服务和 运行 一个 shell 并接受 shell 的参数?

How to write a Dockerfile which I can start a service and run a shell and also accept arguments for the shell?

在 Dockerfile 中,最新的指令是:

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

它有效,但我无法将更多参数传递给 ./che.sh

che.sh 检查内部 docker 是否在完成其他任务后启动。它可以接受几个可选参数,比如 -r:111.111.111.111

我尝试将指令修改为:

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

为了像 docker run -it --priviledged my/che -r:111.111.111.111 run 一样调用它,但是 che.sh shell 会报告内部 docker 工作不正常。

我也试过:

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

甚至:

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

但是它会报告 sudo service docker start 没有在 $PATH 中找到,或者 che.sh 没有 运行。

正确的写法是什么?

  1. sudo service docker start 应该 运行 当 che.sh 被调用时
  2. 我需要从外部向 che.sh 传递参数,例如 docker run -it --priviledged my/che -r:111.111.111.111 run

尝试:
1。在 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. 启动容器
    docker run -it --priviledged my/che -r:111.111.111.111

您必须在 Docker 容器中使用 supervisord,以便在创建容器时能够使用更复杂的 shell 语法。

Docker 关于 supervisord 的文档:https://docs.docker.com/engine/articles/using_supervisord/

当您使用 $ docker run 命令创建新容器时,您可以使用更复杂的 shell 语法(您想要使用的),但是这在 systemd 服务文件中不起作用(由于限制在 systemd 中)和 docker-compose .yml 文件以及 Docker 文件。

首先,您必须在 Docker 文件中安装 supervisord:

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

将其放在 Docker 文件的末尾:

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

在 Docker 文件旁边的 etc/supervisor/conf.d/supervisord.conf 中创建一个文件:

[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

这是一个更复杂的 supervisord.conf,您可能不需要这里的许多命令,而且您必须根据需要更改文件位置。但是,您可以从脚本的 bash 输出中了解如何创建日志文件。

稍后您必须 docker exec 在该容器中,您可以通过以下方式查看 real-time 日志:

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

您可以选择使用 loglevel=debug 在主监督日志中显示子进程日志,但是这充满了时间戳和注释,而不是像 运行 时那样的纯 bash 输出] 直接脚本。

正如您在我的 scipt 中看到的那样,我使用 tail -f /dev/null 使容器保持活动状态,但这是一种不好的做法。 .sh 脚本应该让您的容器自己保持活动状态。

当您将 scipt 作为 ENTRYPOINT ["sudo service docker start", "&&", "/home/user/che/bin/che.sh run"] 发送到 ENTRYPOINT 时,您想要将默认的 docker ENTRYPOINT 从 /bin/sh -c 更改为 sudo(同时,使用完整的位置名称).

有两种方法可以更改 Docker 文件中的 docker ENTRYPOINT。一种是将其放在 Docker 文件的头部:

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

或将其放在底部:

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

当你发送任何 CMD 到这个 Docker 文件后,它将被 /bin/bash -c 命令运行。

还有一点要注意,第一个命令使用 PID1,所以如果你想在我的 supervisord 脚本中 运行 没有 tail -f /dev/null 的 .sh 脚本,它将使用 PID1 进程,并且CTRL+C 命令将不起作用。您必须从另一个 shell 实例关闭容器。

但是,如果您 运行 使用以下命令:

[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 将采用 PID1 和 SIGTERM,SIGKILL 和 SIGINT 将再次与您的 shell 脚本一起工作。

我尽量远离 运行宁 Docker 带有 --privileged 标志。您有更多选择来摆脱限制。

我对您的堆栈一无所知,但通常最好不要 docker在容器中使用 Docker。为什么 sudo service docker start 在你的 Docker 文件中有具体原因?

我对这个容器一无所知,它必须是活的吗?因为如果没有,有一个更简单的解决方案,只有在容器必须从命令行处理某些内容时才 运行ning 容器。将此文件放在主机上,名称为 run 让我们说在 /home/hostuser 文件夹中并给它 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"

在这种情况下,ENTRYPOINT 最好是 ENTRYPOINT ['/bin/bash', '-c']

运行 主机上的此脚本:

$ cd /home/hostuser
$ ./run -flag1 -flag2 args1 args2 args3