zoukankan      html  css  js  c++  java
  • 如何优雅的停止容器

    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不一样。

  • 相关阅读:
    [导入]mootools框架【二】Core篇: 主要方法测试实例
    公司招聘中不能说的秘密 【转载】
    国外10个ASP.Net C#下的开源CMS
    [导入][Flash开发笔记] List控件删除指定label或data的项
    [导入]用C#截取指定长度的中英文混合字符串 改进版
    今天小侄子出生,想了一天的名字
    一个正则表达式的解释
    今日小收获
    昨天的事
    两点东西
  • 原文地址:https://www.cnblogs.com/double12gzh/p/13426937.html
Copyright © 2011-2022 走看看