关于docker容器优雅退出的问题详解

前言

最近因为工作的原因,谈到了关于如何正确的退出运行中的docker容器,这是一个非常值得讨论的话题了。本文将给出详细的介绍,下面来一起看看吧。

容器信号使用

我们跑在容器中的程序通常想在容器退出之前做一些清理操作,比较常用的方式是监听一个信号,延迟关闭容器。

docker提供了这样的功能:

╰─➤ docker stop --help

Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]

Stop one or more running containers

Options:
 --help Print usage
 -t, --time int Seconds to wait for stop before killing it (default 10)

docker 1.13以上版本在创建容器时可直接指定STOP_TIMEOUT 和STOP_SIGNAL参数:

$ docker run --help
...
--stop-signal string   Signal to stop a container, SIGTERM by default (default "SIGTERM")
--stop-timeout int   Timeout (in seconds) to stop a container
...

但是。。。

我们测试一个:

package main

import (
 "fmt"
 "os"
 "os/signal"
 "syscall"
 "time"
)

func main() {
 fmt.Println("signal test")
 go func() {
 for {
  c := make(chan os.Signal, 1)
  signal.Notify(c, syscall.SIGTERM)
  s := <-c
  fmt.Println("Got signal:", s)
 }
 }()
 time.Sleep(time.Second * 100)
}

Dockerfile:

FROM golang:1.8.0
COPY main.go .
RUN go build -o signal && cp signal $GOPATH/bin
CMD signal 

构建:

docker build -t signal:latest .

运行:

docker run --name signal signal:latest

再开一终端,运行:

docker stop -t 10 signal

发现并没有打印出Got signal:... 监听信号失败。

问题再于:我们docker inspect signal看一下

可以看到

Path:/bin/sh
Args:[
 -c,
 signal
]

或者docker exec signal ps 看一下可以看到pid为1的进程并不是signal, 而是shell.

所以原因找到了,是因为docker engine只给pid为1的进程发送信号,sh收到了信号而我们想要的signal进程没有收到信号

解决办法:

FROM golang:1.8.0
COPY main.go .
RUN go build -o signal && cp signal $GOPATH/bin
CMD ["signal"] # 不能写成 CMD signal, 这会直接exec,否则会以shell的方式派生子进程。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • Docker 容器操作退出后进入解决办法

    在我们对Docker容器操作的时候,有时候会误操作或者其他的原因无意间退出了正在操作的容器,也许你会担忧你在其中的一些操作未保存下来,无须担忧,本文中将会提供各种方法供你参考(我的建议使用最后一种).在本文,我们将讨论五种(4+1)连接Docker容器并与其进行交互的方法.例子中所有的代码都可以在GitHub中找到,你可以亲自对它们进行测试. 1.nsenter 安装 nsenter 工具在 util-Linux 包2.23版本后包含. 如果系统中 util-linux 包没有该命令,可以按照下

  • 关于docker容器优雅退出的问题详解

    前言 最近因为工作的原因,谈到了关于如何正确的退出运行中的docker容器,这是一个非常值得讨论的话题了.本文将给出详细的介绍,下面来一起看看吧. 容器信号使用 我们跑在容器中的程序通常想在容器退出之前做一些清理操作,比较常用的方式是监听一个信号,延迟关闭容器. docker提供了这样的功能: ╰─➤ docker stop --help Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...] Stop one or more running

  • docker容器的几种存储详解

    目录 写在前面 几种存储挂载方式 1.bind mounts 2.volumes 3.tmpfs mount 存储数据共享 写在前面 我们在上篇学习了容器网络,对容器网络驱动bridge工作原理做了较为详细的介绍,今天小作文一起看看容器中另一个关键域-存储. 容器的存储可以分为两大类: 一种是与镜像相关的即我们在<docker容器技术基础之联合文件系统OverlayFS>一文提到的容器层Copy-On-Write特性.默认情况下,在容器内创建的所有文件都存储在可写容器层上,这种直接将文件存储在

  • Golang实现程序优雅退出的方法详解

    目录 1. 背景 2. 常见的几种平滑关闭 2.1 http server 平滑关闭 2.2 gRPC server 平滑关闭 2.3 worker 协程平滑关闭 2.4 实现 io.Closer 接口的自定义服务平滑关闭 2.5 集成其他框架怎么做 1. 背景 项目开发过程中,随着需求的迭代,代码的发布会频繁进行,在发布过程中,如何让程序做到优雅的退出? 为什么需要优雅的退出? 你的 http 服务,监听端口没有关闭,客户的请求发过来了,但处理了一半,可能造成脏数据. 你的协程 worker

  • Docker容器化spring boot应用详解

    前置条件 容器化spring boot应用所需环境: jdk 1.8 + maven 3.0 + 我们的需求是:使用maven打包,将spring boot应用制作成docker镜像并上传到docker hub.在其他机器上,可以直接docker pull并运行容器. 创建spring boot应用 spring boot 包结构为: └── src └── main └── java └── me └── ithakar 创建spring boot Application主类,src/main

  • 运行中的docker容器端口映射如何修改详解

    前言 在docker run创建并运行容器的时候,可以通过-p指定端口映射规则.但是,我们经常会遇到刚开始忘记设置端口映射或者设置错了需要修改.当docker start运行容器后并没有提供一个-p选项或设置,让你修改指定端口映射规则.那么这种情况我们该怎么处理呢?今天Docker君教你如何修改运行中的docker容器的端口映射? 方法一:删除原有容器,重新建新容器 这个解决方案最为简单,把原来的容器删掉,重新建一个.当然这次不要忘记加上端口映射. 优缺点:优点是简单快捷,在测试环境使用较多.缺

  • Docker容器网络端口配置过程详解

    暴露网络端口 实际上,Docker中涉及暴露网络端口的参数有两个,分别是-p和-P.下面分别来介绍. -P 使用-P,Docker会在宿主机上随机为应用分配一个未被使用的端口,并将其映射到容器开放的端口,以Nginx 为例,如下: 可以看到,Docker为应用分配了一个随机端口32768,使用该端口即可访问容器中的 nginx(http://lcalhost:32768). -p -p参数则有几种不同的用法: hostPort:containerPort 这种用法是将宿主机端口和容器端口绑定起来

  • 利用 trap 在 docker 容器优雅关闭前执行环境清理的方案

    当一个运行中的容器被终止时,如何能够执行一些预定义的操作,比如在容器彻底退出之前清理环境.这是一种类似于 pre stop 的钩子体验.但 docker 本身无法提供这种能力,本文结合 Linux 内置命令 trap ,实现在容器优雅关闭之前,可以执行自定义的操作. 当一个运行中的容器被终止时,如何能够执行一些预定义的操作,比如在容器彻底退出之前清理环境.这是一种类似于 pre stop 的钩子体验.但 docker 本身无法提供这种能力,本文结合 Linux 内置命令 trap ,实现在容器优

  • Docker通过容器生成镜像提交DockerCommit详解

    目录 在本地创建一个容器后,可以依据这个容器创建本地镜像,并可把这个镜像推送到Docker hub中. 根据镜像启动容器:docker run 根据启动的容器创建新的镜像:docker commit 将由容器生成的镜像push到镜像仓库docker hub push失败之后,需要根据镜像仓库的路径打tag,然后提交到镜像仓库: 在另一台服务器下载上图push到镜像仓库的新镜像 参考文章:通过容器提交镜像DockerCommit及推送镜像DockerPush 以上就是Docker通过容器生成镜像提

  • Docker run 命令的使用方法详解

    注意,本文基于最新的Docker 1.4文档翻译. Docker会在隔离的容器中运行进程.当运行 docker run命令时,Docker会启动一个进程,并为这个进程分配其独占的文件系统.网络资源和以此进程为根进程的进程组.在容器启动时,镜像可能已经定义了要运行的二进制文件.暴露的网络端口等,但是用户可以通过docker run命令重新定义(译者注:docker run可以控制一个容器运行时的行为,它可以覆盖docker build在构建镜像时的一些默认配置),这也是为什么run命令相比于其它命

  • 滚动 docker 中的 nginx 日志思路详解

    docker使用 1. docker ps 查看运行中的容器 2. docker images 查看docker镜像 3. docker rm id(容器id)  删除容器(容器id可以通过docker ps查看,容器必须停止后才能删除) 3.1 删除全部的容器 docker rm `docker ps -a -q` 4. docker stop  id(容器id) 停止容器运行 5. docker rmi  id(镜像id) 删除镜像 6. docker pull ubuntu:16.04(镜

随机推荐