GVKun编程网logo

从 Docker 的信号机制看容器的优雅停止(从 docker 的信号机制看容器的优雅停止运行)

11

本文的目的是介绍从Docker的信号机制看容器的优雅停止的详细情况,特别关注从docker的信号机制看容器的优雅停止运行的相关信息。我们将通过专业的研究、有关数据的分析等多种方式,为您呈现一个全面的了

本文的目的是介绍从 Docker 的信号机制看容器的优雅停止的详细情况,特别关注从 docker 的信号机制看容器的优雅停止运行的相关信息。我们将通过专业的研究、有关数据的分析等多种方式,为您呈现一个全面的了解从 Docker 的信号机制看容器的优雅停止的机会,同时也不会遗漏关于django的信号机制、Docker 创建容器 查看容器状态 - 三、Docker 启动 / 停止 / 进入容器的常见操作、Docker 命令-查看容器日志,查看容器进程,查看容器内部细节(9)的知识。

本文目录一览:

从 Docker 的信号机制看容器的优雅停止(从 docker 的信号机制看容器的优雅停止运行)

从 Docker 的信号机制看容器的优雅停止(从 docker 的信号机制看容器的优雅停止运行)

此文是前段时间做相关工作时笔记的整理,之前自己对这方面的关注不够,因此做下记录。


有太多的文章介绍如何运行容器,然而如何停止容器的文章相对少很多。

根据运行的应用类型,应用的停止过程非常重要。如果应用要写文件,停止前要保证正确刷新数据并关闭文件;如果是 HTTP 服务,要确保停止前处理所有未完成的请求。

信号

信号是 Linux 内核与进程以及进程间通信的一种方式。针对每个信号进程都有个默认的动作,不过进程可以通过定义信号处理程序来覆盖默认的动作,除了 SIGSTOPSIGKILL。二者都不能被捕获或重写,前者用来将进程暂停在当前状态,而后者则是从内核层面立即杀掉进程。

有两个比较重要的进程 SIGTERMSIGKILLSIGTERM 是优雅地关闭命令,SIGKILL 则是暴力的关闭命令。比如 Docker,容器会先收到 SIGTERM 信号,10s 后会收到 SIGKILL 信号。

还有很多其他的信号,只是限定于特定的上下文。

中断

硬件的中断就像操作系统的信号。通常发生在硬件想要向操作系统注册事件时。操作系统必须立即停止运行,并处理中断。

比较常见的中断例子就是键盘中断,比如按下 ctrl+z 或者 ctrl+c。Linux 将其分别转换成 SIGTSTPSIGINT。硬件中断过去通常用来处理键盘和鼠标输入,但如今被用作操作系统软件驱动层面的信号轮训。

Docker

前面说了这么多终于来到 Docker,容器的独特之处在于通常只运行一个进程。即使是单进程,容器内 PID 为 1 的进程也具有 init 系统的特殊规则和职责。

PID 1 在 Linux 中非常重要,通常是 init 进程。通常进程在收到 SIGTERM 信号后,假如不对信号进程处理,会快速退出。但 PID 1 的进程收到 SIGTERM 之后假如不对信号进行处理则什么都不会做

容器内 PID 1 通常有两种情况: shell 进程 PID 为 1 和你的进程 PID 为 1。分别对应着 shell 和 exec 格式的命令。

shell 格式

Dockerfile 有个特点,就是如果不使用 JSON 格式 来指定容器命令,会通过 shell 以 fork 的形式来执行命令,也就是 /bin/sh -c

  • docker run(宿主机上)
    • /bin/sh -c(PID 1,容器内)
      • /loop.sh (PID 2,容器内)

这种格式的命令特点是不会向业务进程发送信号。比如发送给 shell 的 SIGTERM 信号不会转发给子进程,而是等待子进程的退出。唯一杀死容器的方式就是发送 SIGKILL 信号,或者碰巧子进程自己崩溃。

所以应该尽量避免使用这种方式,

exec 格式

这个就是 Dockerfile 的推荐语法了,你的进程会立即启动并作为容器的初始化进程,然后就有了下面的进程树:

  • docker run(宿主机上)
    • /loop.sh(PID 1,容器内)

说了这么多,很多人觉得不够直观。我们会用示例应用来进行说明,但在这之前简单说下如何发送信号来停止容器。

发送信号

有几种方式来停止容器。

docker stop

默认情况下 docker stop 命令会向容器发送 SIGTERM 信号,然后等待 10s,如果容器没停止再发送 SIGKILL 信号。

在 Dockerfile 中,可以通过 STOPSIGNAL 指令来设置默认的退出信号,比如 STOPSIGNAL SIGKILL 将退出信号设置为 SIGKILL。或者在 docker run 是通过 --stop-signal 参数来覆盖镜像中的 STOPSIGNAL 设置。

docker kill

默认情况下 docker kill 会直接杀死容器,不给容器任何机会进行优雅停止,这里发出的就是 SIGKILL 信号。

当然 docker kill 可以通过 --signal 来指定要发送的信号,类似 Linux 的 kill 命令:

docker kill ----signal=SIGTERM foo

docker rm -f

通常情况下 docker rm 用来删除已经停止的容器,但是加上 --force(简写 -f)会强制删除正在运行的容器。同样,也不会给容器任何优化停止的机会。

信号处理

我们使用一个简单的应用对 shell 和 exec 两种格式做下对比。在这个应用中,对 SIGTERM 进行处理:收到信号后退出。

#!/usr/bin/env sh
trap ''exit 0'' SIGTERM
while true; do :; done

接下来我们使用两种不同格式的 CMD 来构建镜像。

shell 格式

使用下面的 Dockerfile 来构建镜像 term

FROM alpine:3.15.0
COPY loop.sh /
CMD /loop.sh

执行下面的命令构建镜像、启动容器、停止容器。

docker build -t term .
docker run --name term -d term
docker stop term

此时你会发现容器并没有立刻停止,而是大约 10s 之后才被停止。可以通过命令查看容器的退出状态:

docker inspect -f ''{{.State.ExitCode}}'' term
137

137 = 128 + 9 说明容器的退出信号是 SIGKILL

exec 格式

调整下 Dockerfile,将 CMD 修改为推荐的 JSON 格式:

FROM ubuntu:trusty
COPY loop.sh /
CMD ["/loop.sh"]

执行下面的命令构建镜像、启动容器、停止容器。(需要先执行 docker rm term 删除之前停止的容器)

docker build -t term .
docker run --name term -d term
docker stop term

此时容器会立刻退出。查看容器的退出状态:

docker inspect -f ''{{.State.ExitCode}}'' term
0

总结

docker rm -fdocker kill 干掉容器很容器,但是为了实现容器的优雅退出,应该使用 docker stop 命令,同时 Dockerfile 中应尽量避免使用 shell 格式设置 ENTRYPONT 或者 CMD

文章统一发布在公众号云原生指北

django的信号机制

django的信号机制

一 信号的简介

Django提供一种信号机制。其实就是观察者模式,又叫发布-订阅(Publish/Subscribe) 。当发生一些动作的时候,发出信号,然后监听了这个信号的函数就会执行。

通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者。用于在框架执行操作时解耦。

 二 django的内置信号

Model signals
    pre_init                    # django的modal执行其构造方法前,自动触发
    post_init                   # django的modal执行其构造方法后,自动触发
    pre_save                    # django的modal对象保存前,自动触发
    post_save                   # django的modal对象保存后,自动触发
    pre_delete                  # django的modal对象删除前,自动触发
    post_delete                 # django的modal对象删除后,自动触发
    m2m_changed                 # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
    class_prepared              # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
Management signals
    pre_migrate                 # 执行migrate命令前,自动触发
    post_migrate                # 执行migrate命令后,自动触发
Request/response signals
    request_started             # 请求到来前,自动触发
    request_finished            # 请求结束后,自动触发
    got_request_exception       # 请求异常后,自动触发
Test signals
    setting_changed             # 使用test测试修改配置文件时,自动触发
    template_rendered           # 使用test测试渲染模板时,自动触发
Database Wrappers
    connection_created          # 创建数据库连接时,自动触发
Django 提供了一系列的内建信号,允许用户的代码获得DJango的特定操作的通知。这包含一些有用的通知:
django.db.models.signals.pre_save & django.db.models.signals.post_save

在模型 save()方法调用之前或之后发送。
django.db.models.signals.pre_delete & django.db.models.signals.post_delete

在模型delete()方法或查询集的delete() 方法调用之前或之后发送。
django.db.models.signals.m2m_changed

模型上的 ManyToManyField 修改时发送。
django.core.signals.request_started & django.core.signals.request_finished

Django建立或关闭HTTP 请求时发送。

三 内置信号的使用

对于Django内置的信号,仅需注册指定信号,当程序执行相应操作时,自动触发注册函数:

from django.core.signals import request_finished
from django.core.signals import request_started
from django.core.signals import got_request_exception
from django.db.models.signals import class_prepared
from django.db.models.signals import pre_init, post_init
from django.db.models.signals import pre_save, post_save
from django.db.models.signals import pre_delete, post_delete
from django.db.models.signals import m2m_changed
from django.db.models.signals import pre_migrate, post_migrate
from django.test.signals import setting_changed
from django.test.signals import template_rendered
from django.db.backends.signals import connection_created

方式一:

#放到__init__里
from django.db.models.signals import pre_save
import logging
def callBack(sender, **kwargs):
    print(sender)
    print(kwargs)
    # 创建对象写日志
    logging.basicConfig(level=logging.DEBUG)
    # logging.error(''%s创建了一个%s对象''%(sender._meta.db_table,kwargs.get(''instance'').title))
    logging.debug(''%s创建了一个%s对象''%(sender._meta.model_name,kwargs.get(''instance'').title))

pre_save.connect(callBack)

方式二:

from django.db.models.signals import pre_save
from django.dispatch import receiver
@receiver(pre_save)
def my_callback(sender, **kwargs):
    print("对象创建成功")
    print(sender)
    print(kwargs)

四 自定义信号

a. 定义信号(一般创建一个py文件)(toppings,size 是接受的参数)

import django.dispatch
pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

b. 注册信号

def callback(sender, **kwargs):
    print("callback")
    print(sender,kwargs)
  
pizza_done.connect(callback)

c. 触发信号

from 路径 import pizza_done
  
pizza_done.send(sender=''seven'',toppings=123, size=456)

由于内置信号的触发者已经集成到Django中,所以其会自动调用,而对于自定义信号则需要开发者在任意位置触发。

 

Docker 创建容器 查看容器状态 - 三

Docker 创建容器 查看容器状态 - 三

Docker 创建容器

1、拉取镜像 默认是 docker.io 仓最新镜像

docker pull tomcat

2、运行一个服务容器

docker run -d -p 0.0.0.0:18080:8080 --name tomcat-web1 tomcat
-d:让容器在后台运行。 -P:将容器内部使用的网络端口映射到我们使用的主机上 -p:指定端口 --name: 给容器命名 tomcat-web1
最后一个 tomcat 是使用的镜像

3、创建启动 一个 centos 系统容器;

docker run -d -i -t -p 222:22 --name centos6-1 centos6 /bin/bash

4、 查看端口;(使用容器 ID 或者 容器名称)

docker port ID/NAMES

5、查看容器运行日志;检查 WEB 应用程序

docker logs  -f ID

6、查看 Docker 的底层信息。

docker inspect 会返回一个 JSON 文件记录着 Docker 容器的配置和状态信息

docker inspect NAMES 
# 查看容器所有状态; docker inspect
--format=''{{.NetworkSettings.IPAddress}}'' docker_NAMES
# ip 地址 docker inspect
--format ''{{.Name}} {{.State.Running}}'' NAMES
# 容器运行状态

7、查看进程信息

docker top NAMES

9、删除容器

docker rm NAMES

docker rmi REPOSITORY
# rmi 删除镜像;

 

Docker 启动 / 停止 / 进入容器的常见操作

Docker 启动 / 停止 / 进入容器的常见操作

以下操作基于上一篇所述容器

地址:https://my.oschina.net/xiaozhiwen/blog/1600659

1、查看运行中的容器

docker ps
root@kobe:/opt/software/docker/spring-boot-docker/target# docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                    NAMES
5ecf2637f10b        cloudcomb/sun:1.0   "java -jar /app.jar"   45 seconds ago      Up 2 seconds        0.0.0.0:1024->8080/tcp   goofy_easley

2、停止容器

docker stop goofy_easley
root@kobe:/opt/software/docker/spring-boot-docker/target# docker stop goofy_easley
goofy_easley

goofy_easley:为 docker ps 返回结果中的 NAMES

3、启动容器

docker start goofy_easley
root@kobe:/opt/software/docker/spring-boot-docker/target# docker start goofy_easley
goofy_easley

4、进入容器

进入容器有多种方法,以下示例最简单的方法,使用 exec

docker exec -it 5ecf2637f10b /bin/sh

5ecf2637f10b :为 docker ps 返回结果中的 CONTAINER ID

5、退出容器

exit
root@kobe:/opt/software/docker/spring-boot-docker/target# docker exec -it 5ecf2637f10b /bin/sh
/ # ls
app.jar  bin      dev      etc      home     lib      lib64    linuxrc  media    mnt      proc     root     run      sbin     sys      tmp      usr      var
/ # env
HOSTNAME=5ecf2637f10b
SHLVL=1
HOME=/root
JAVA_VERSION=8
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
LANG=C.UTF-8
JAVA_BUILD=03
JAVA_UPDATE=77
PWD=/
JAVA_HOME=/usr/lib/jvm/default-jvm
/ # 
/ # exit
root@kobe:/opt/software/docker/spring-boot-docker/target#

6、查看容器 ip

docker inspect 容器ID | grep IPAddress

 

Docker 命令-查看容器日志,查看容器进程,查看容器内部细节(9)

Docker 命令-查看容器日志,查看容器进程,查看容器内部细节(9)

查看容器日志log
docker run -d centos /bin/sh -c "while true;do echo hello zzyy;sleep 2;done"
Docker 命令-查看容器日志,查看容器进程,查看容器内部细节(9)
docker logs b281a776e2d0
Docker 命令-查看容器日志,查看容器进程,查看容器内部细节(9)
查看日志显示时间-t
docker logs -t b281a776e2d0
Docker 命令-查看容器日志,查看容器进程,查看容器内部细节(9)
实时查看产出的日志-f
docker logs -t -f b281a776e2d0
docker logs -f b281a776e2d0
Docker 命令-查看容器日志,查看容器进程,查看容器内部细节(9)
Docker 命令-查看容器日志,查看容器进程,查看容器内部细节(9)
日志查看最后几行
docker logs --tail 3 b281a776e2d0
Docker 命令-查看容器日志,查看容器进程,查看容器内部细节(9)
实时显示最后3行
docker logs -tf --tail 3 b281a776e2d0
Docker 命令-查看容器日志,查看容器进程,查看容器内部细节(9)
查看容器内运行的进程
docker top b281a776e2d0
Docker 命令-查看容器日志,查看容器进程,查看容器内部细节(9)
查看容器内部细节inspect
docker inspect b281a776e2d0
Docker 命令-查看容器日志,查看容器进程,查看容器内部细节(9)
进入正在运行的容器以命令行交互
docker exec -t 2964afa886b8 ls -l /tmp
Docker 命令-查看容器日志,查看容器进程,查看容器内部细节(9)
docker exec -it 2964afa886b8 ls -l /tmp
Docker 命令-查看容器日志,查看容器进程,查看容器内部细节(9)
重新进入容器attach
docker attach 2964afa886b8
Docker 命令-查看容器日志,查看容器进程,查看容器内部细节(9)
从容器内拷贝文件copy
docker cp 2964afa886b8:/tmp/ks-script-z6zw_bhq /root/
Docker 命令-查看容器日志,查看容器进程,查看容器内部细节(9)


































我们今天的关于从 Docker 的信号机制看容器的优雅停止从 docker 的信号机制看容器的优雅停止运行的分享已经告一段落,感谢您的关注,如果您想了解更多关于django的信号机制、Docker 创建容器 查看容器状态 - 三、Docker 启动 / 停止 / 进入容器的常见操作、Docker 命令-查看容器日志,查看容器进程,查看容器内部细节(9)的相关信息,请在本站查询。

本文标签: