dockerfile怎么执行shell脚本(利用tail -f /dev/null命令防止container启动后退出)

Royal
2022-04-18 / 0 评论 / 4,930 阅读 / 正在检测是否收录...

最近在测试应用通过docker容器部署时发现,容器启动后无法自动启动NGINX和PHP程序,需要进入到容器内部来完成nginx和php的启动。
具体的指令就是:

 docker exec -it 容器ID /bin/bash
 /usr/local/nginx/sbin/nginx   #启动nginx
 /usr/local/php7/sbin/php-fpm  #启动php
 ps -ef | grep 'nginx'
 ps -ef | grep 'php'

通过以上指令才能完成容器内部的程序启动,那有没有办法在启动docker容器时自动启动内部程序运行呢?
当然有!

  1. 通过运行shell脚本的方式:
    l24dpz0l.png
    我们在Dockerfile的同级目录下创建一个shell脚本,名字为start.sh
    编写start.sh文件

    #!/bin/bash
    
    /usr/local/php7/sbin/php-fpm
    /usr/local/nginx/sbin/nginx

    然后我们重新编写Dockerfile文件

    # base image
    FROM ci:latest
    
    # MAINTAINER
    MAINTAINER sangshuaidong <sangshuaidong@comleader.com.cn>
    
    # COPY
    COPY ci.localhost.com* /www/
    
    COPY ["start.sh", "/root/start.sh"]
    
    
    RUN chmod -R 777 /www/
    
    WORKDIR /root
    
    #CMD 
    CMD ["/bin/bash","./start.sh"]

    注释:COPY脚本文件start.sh到我们容器内部的root目录下,然后设置工作目录为root,然后通过CMD命令来运行start.sh文件.
    我们先来看下CMD命令是用来做什么的?类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:

  • CMD 在docker run 时运行。
  • RUN 是在 docker build。
    作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。
    注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
    COMMAND为docker容器的默认启动命令,查看容器镜像的Dockerfile,一般体现为 CMD ["命令"] ,如 CMD ["/bin/bash"]
    每个容器都会有一个 pid 为 1 的进程,如果这个进程执行结束了,容器也就 close 了;
    COMMAND 为 /bin/bash, 说明这个容器的初始进程就是 bash 进程;
    默认情况下,docker logs <container_id> 也只会打印 pid 为 1 进程的输出
    现在我们打包镜像,运行一下容器看看是否可以正常启动php和nginx服务

    docker build -t ci:v3 .
    docker iamges

    l24f3b32.png
    l24f4616.png
    启动容器:

    docker run -dit -p 8080:80 -p 443:443 -p 9000:9000 --privileged=true --name=civ3 ci:v3
    docker ps 

    l24f7lus.png
    我们发现容器没有启动成功,这是为什么呢?
    我们分析下:
    container 刚起来的时候,用户可以通过 dockerfile 中的 CMD,ENTRYPOINT,或者直接在 docker run 后面接 comand,来指定 container 启动时执行的程序。如果指定的程序只是一个短暂的任务,比如 echo sorry。那么,sorry,container 在输出 “sorry” 之后,就退出了。可以通过 docker inspect 看到,container 状态变成了 Exited。
    docker build Dockerfile后,采用docker run –name xxx -d 运行容器,发现start.sh执行后容器就退出了,根本无法启动nginx和php。
    分析了一下docker的机制,一个docker容器同时只能管理一个进程,这个进程退出后,容器也就退出了。这并不意味着一个容器里只能同时运行一个进程(那样太浪费了),只是最后一个运行的进程不能退出。
    start.sh总结总结:

  • 容器中运行多个守护进程时,前面的进程要用后台方式运行(或添加 &),否则后面的服务无法启动
  • 容器中最后一个守护进程一定要用前台方式运行,否则start.sh退出,容器退出,所有的服务就白启动

    解决方法
    可以利用tail -f /dev/null让容器一直处于runing状态,用CMD 执行一个脚本,在脚本中启动多个服务。
    例如我们要执行start.sh这个脚本,利用这个脚本启动主服务,并执行tail -f /dev/null:
    我们重新编写start.sh文件 只需要在末尾加上tail -f /dev/null

    #!/bin/bash
    
    /usr/local/php7/sbin/php-fpm
    /usr/local/nginx/sbin/nginx
    tail -f /dev/null

    然后我们重新按照上面流程打包镜像,启动容器即可!
    l24fn2f8.png
    发现 php和nginx程序都是运行状态!
    那除了shell脚本方式运行 还有其他方式么?待更....

0

评论

博主关闭了当前页面的评论