• 如何优雅的停止容器


    1. docker容器和PID 1

    当在容器中执行一个bash脚本时,它就是个1号进程,应用进程就是这个1号进程的
    子进程,这是bash的问题,因为它不会将终止信号SIGTERM发送到容器中的应用进程。
    相反,在收到终止信号后,docker将会在10s后将容器kill掉。我们可以调整这个
    时间,这个时间的存在主要是为了尽最大可能的让应用能够优雅的停止。

    为了解决上述问题,一个比较简单的做法就是在bash脚本中使用exec命令。
    exec将会取代shell并且不会创建新的进程,并且应用也将会是1号进程

    2. 示例

    假如我们有一个Dockerfile文件,它将会在容器中的运行redis服务。内容如下:

    FROM ubuntu:trusty
    ENV DEBIAN_FRONTEND noninteractive
    
    RUN 
      apt-get update && 
      apt-get -y install 
              software-properties-common && 
      add-apt-repository -y ppa:chris-lea/redis-server && 
      apt-get update && 
      apt-get -y install 
              redis-server && 
      rm -rf /var/lib/apt/lists/*
    
    COPY start.sh start.sh
    RUN chmod +x start.sh
    
    EXPOSE 6379
    
    RUN rm /usr/sbin/policy-rc.d
    CMD ["/start.sh"]
    

    start.sh中的内容如下:

    #!/usr/bin/env bash
    
    # Disable THP Support in kernel
    echo never > /sys/kernel/mm/transparent_hugepage/enabled
    # TCP backlog setting (defaults to 128)
    sysctl -w net.core.somaxconn=16384
    #---------------------------------------------------------------
    /usr/bin/redis-server
    
    

    下面我们将会生成镜像并运行容器:

    docker build -t my/redis .
    docker run -d --privileged --name test my/redis
    

    检查运行的容器进程:

    docker exec test ps -ef
      UID        PID  PPID  C STIME TTY          TIME CMD
      root         1     0  0 13:20 ?        00:00:00 bash /start.sh
      root         6     1  0 13:20 ?        00:00:00 /usr/bin/redis-server *:6379
    

    正如我们看到的,这个redis服务的进程号为PID6。这种情况下,当我们执行docker stop test
    时我们将无法优雅的停止容器。10s后容器将会被kill掉。执行docker logs test
    时,最新的消息为Ready to accept connection,这意味着redis并没有收到终止
    信号。

    最简单的实现优雅停止redis容器的方法就是将start.sh的最后一行
    /usr/bin/redis-server改为exec /usr/bin/redis-server

    重新构建镜像并启动容器,然后再检查进程:

    docker exec test ps -ef
      UID        PID  PPID  C STIME TTY          TIME CMD
      root         1     0  1 13:24 ?        00:00:00 /usr/bin/redis-server *:6379
    

    正如我们看到的,现在redis进程已经是1号进程了,并且执行docker stop时也能
    正常优雅的stop掉了redis服务。再次检查日志发现,redis log: Received SIGTERM scheduling shutdown...

    3. 其它

    在上面的例子中,redis进程是以root权限运行的,但这并不是一个很好的实践。
    下面这几个例子中,我是以非root权限运行Postgres和Tomcat容器,

    exec sudo -E -u tomcat7 ${CATALINA_HOME}/bin/catalina.sh run
    exec su postgres -c "${POSTGRES_BIN} -D ${PGDATA} -c config_file=${CONF}"
    

    在这些例子中,应用进程并不是PID 1的进程,但是docker stop 却可以优雅的
    停止他们,因为我使用了sudo和su命令,这两个命令都会将SIGTERM信号发送给
    子进程,这一点与Bash不一样。

  • 相关阅读:
    发布国内首个无服务器容器服务,运维效率从未如此高效
    阿里云异构计算团队亮相英伟达2018 GTC大会
    阿里如何将“高峰前扩容、高峰后缩容”的梦想照进现实?
    迁移到 GRUB 2
    (11计科1班-孙鹏启)SHELL脚本—期末成绩统计
    硬盘分区的c盘在外圈还是内圈
    Linux内核设计的艺术(第2版)
    卸载,弹出,安全移除驱动器 的区别
    (11级计科2班-张文旭)关于LINUX连接网络问题
    安装Zend Guard Loader
  • 原文地址:https://www.cnblogs.com/double12gzh/p/13426937.html
Copyright © 2020-2023  润新知