本文的目的是介绍从Docker的信号机制看容器的优雅停止的详细情况,特别关注从docker的信号机制看容器的优雅停止运行的相关信息。我们将通过专业的研究、有关数据的分析等多种方式,为您呈现一个全面的了
本文的目的是介绍从 Docker 的信号机制看容器的优雅停止的详细情况,特别关注从 docker 的信号机制看容器的优雅停止运行的相关信息。我们将通过专业的研究、有关数据的分析等多种方式,为您呈现一个全面的了解从 Docker 的信号机制看容器的优雅停止的机会,同时也不会遗漏关于django的信号机制、Docker 创建容器 查看容器状态 - 三、Docker 启动 / 停止 / 进入容器的常见操作、Docker 命令-查看容器日志,查看容器进程,查看容器内部细节(9)的知识。
本文目录一览:- 从 Docker 的信号机制看容器的优雅停止(从 docker 的信号机制看容器的优雅停止运行)
- django的信号机制
- Docker 创建容器 查看容器状态 - 三
- Docker 启动 / 停止 / 进入容器的常见操作
- Docker 命令-查看容器日志,查看容器进程,查看容器内部细节(9)
从 Docker 的信号机制看容器的优雅停止(从 docker 的信号机制看容器的优雅停止运行)
此文是前段时间做相关工作时笔记的整理,之前自己对这方面的关注不够,因此做下记录。
有太多的文章介绍如何运行容器,然而如何停止容器的文章相对少很多。
根据运行的应用类型,应用的停止过程非常重要。如果应用要写文件,停止前要保证正确刷新数据并关闭文件;如果是 HTTP 服务,要确保停止前处理所有未完成的请求。
信号
信号是 Linux 内核与进程以及进程间通信的一种方式。针对每个信号进程都有个默认的动作,不过进程可以通过定义信号处理程序来覆盖默认的动作,除了 SIGSTOP
和 SIGKILL
。二者都不能被捕获或重写,前者用来将进程暂停在当前状态,而后者则是从内核层面立即杀掉进程。
有两个比较重要的进程 SIGTERM
和 SIGKILL
。SIGTERM
是优雅地关闭命令,SIGKILL
则是暴力的关闭命令。比如 Docker,容器会先收到 SIGTERM
信号,10s 后会收到 SIGKILL
信号。
还有很多其他的信号,只是限定于特定的上下文。
中断
硬件的中断就像操作系统的信号。通常发生在硬件想要向操作系统注册事件时。操作系统必须立即停止运行,并处理中断。
比较常见的中断例子就是键盘中断,比如按下 ctrl+z
或者 ctrl+c
。Linux 将其分别转换成 SIGTSTP
和 SIGINT
。硬件中断过去通常用来处理键盘和鼠标输入,但如今被用作操作系统软件驱动层面的信号轮训。
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 -f
和 docker kill
干掉容器很容器,但是为了实现容器的优雅退出,应该使用 docker stop
命令,同时 Dockerfile 中应尽量避免使用 shell 格式设置 ENTRYPONT
或者 CMD
。
文章统一发布在公众号
云原生指北
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 创建容器
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 启动 / 停止 / 进入容器的常见操作
以下操作基于上一篇所述容器
地址: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)
查看容器日志log
docker run -d centos /bin/sh -c "while true;do echo hello zzyy;sleep 2;done"
docker logs b281a776e2d0
查看日志显示时间-t
docker logs -t b281a776e2d0
实时查看产出的日志-f
docker logs -t -f b281a776e2d0
docker logs -f b281a776e2d0
日志查看最后几行
docker logs --tail 3 b281a776e2d0
实时显示最后3行
docker logs -tf --tail 3 b281a776e2d0
查看容器内运行的进程
docker top b281a776e2d0
查看容器内部细节inspect
docker inspect b281a776e2d0
进入正在运行的容器以命令行交互
docker exec -t 2964afa886b8 ls -l /tmp
docker exec -it 2964afa886b8 ls -l /tmp
重新进入容器attach
docker attach 2964afa886b8
从容器内拷贝文件copy
docker cp 2964afa886b8:/tmp/ks-script-z6zw_bhq /root/
我们今天的关于从 Docker 的信号机制看容器的优雅停止和从 docker 的信号机制看容器的优雅停止运行的分享已经告一段落,感谢您的关注,如果您想了解更多关于django的信号机制、Docker 创建容器 查看容器状态 - 三、Docker 启动 / 停止 / 进入容器的常见操作、Docker 命令-查看容器日志,查看容器进程,查看容器内部细节(9)的相关信息,请在本站查询。
本文标签: