之所以会有这个主题,是因为这几天我给mysql集群前置了一个keepalived,为了方便也做成了docker镜像,丢给k8s来部署。但实际测试时发现,当停止或者删除keepalived容器后,网卡上还残余之前keepalived下发的virtual ip。

直接在宿主机上安装keepalived不会有这个问题。从keepalived源码上来看,它会接管linux发给它的SIGTERM信号,之后清理现场,包括下发给接口的虚IP,所以问题原因就比较简单了,容器在退出时,并没用将SIGTERM信号传递给keepalived进程,造成keepalived强制退出,最终virtual ip残留。

要解决这个问题,还需要从容器退出开始谈起。先挖个坑,晚上填。

docker容器退出会收到哪些信号?

不同的命令,收到的信号不同。

docker stop

默认docker stop会向容器发送SIGTERM信号,并等待10秒;如果10秒后容器没有退出,则会发送SIGKILL信号,强制杀死该容器。我的keepalived容器就是收到信号10s后仍然存活,最后被SIGKILL杀死的,docker ps -a查看容器的STATUS,可以看到Exited (137) 2 hours ago。137=128+9,即退出原因是收到了信号9(即SIGKILL)。

如果你的应用在退出时要做的事情比较多,可以docker stop的时候宽限几天。

docker stop ----time=30 xxx

docker kill

默认docker kill会向容器发送SIGKILL信号,即直接杀死容器,不叨叨。不过你可以通过–signal=SIGXXX参数来修改docker kill发送的信号。注意docker kill和linux kill命令的默认行为不同,后者默认发送的是SIGTERM(类似docker stop)。docker kill和linux kill -9的行为是类似的。

docker rm -f

docker rm -f会发送SIGKILL杀死容器,并清理容器痕迹,类似docker kill && docker rm。

应用应该处理哪个信号?

新写的应用,建议捕捉SIGTERM,因为这是docker stop时默认发出的信号;旧有的应用,则需要一房一价,具体问题具体分析,例如NGINX需要SIGQUIT,Apache需要SIGWINCH。keepalived比较友好:

/* Terminate handler */

void

sigend(void *v, int sig)

{

int status;

/* register the terminate thread */

thread_add_terminate_event(master);

if (vrrp_child > 0) {

kill(vrrp_child, SIGTERM);

waitpid(vrrp_child, &status, WNOHANG);

}

if (checkers_child > 0) {

kill(checkers_child, SIGTERM);

waitpid(checkers_child, &status, WNOHANG);

}

}

/* Initialize signal handler */

void

signal_init(void)

{

signal_handler_init();

signal_set(SIGHUP, sighup, NULL);

signal_set(SIGINT, sigend, NULL);

signal_set(SIGTERM, sigend, NULL);

signal_ignore(SIGPIPE);

}

不管是SIGINT还是SIGTERM,都能sigend走清理。

应用是怎么接收到信号的

docker会将信号传给pid=1的进程。

换句话说,如果你的应用跑起来时pid不为1,那么就收不到docker发出来的信号,也就做不到gracefully退出了。因此,我们的目标就是要让需要gracefully退出的应用跑在pid=1的位置上。

举个例子。

先写个loop.sh。

#!/usr/bin/env bash

trap 'exit 0' SIGTERM

whiletrue; do :; done

然后是Dockerfile。

FROM ubuntu:trusty

COPY loop.sh /

CMD /loop.sh

你可以试着build/run/stop一下,会发现docker stop需要10s才能停掉这个容器,说明loop.sh没有收到信号。为什么呢?我们知道信号是发给pid=1的进程,那么来看看容器里的情况:

docker exec 838 ps aux

USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND

root 1 0.0 0.0 4460 696 ? Ss 05:26 0:00 /bin/sh -c /loop.sh

root 6 99.6 0.0 17968 2716 ? R 05:26 0:29 bash /loop.sh

root 7 0.0 0.0 15580 2156 ? Rs 05:26 0:00 ps aux

显然loop.sh收不到信号。

Dockerfile对于CMD command param1 param2这种形式的命令,具体执行的是bash -c command param1 param2,也就是上面我们看到的结果。

正确的写法是,使用CMD ["executable","param1","param2"]这种形式,例如上面:

FROM ubuntu:trusty

COPY loop.sh /

CMD [/loop.sh]

这样容器启动时,会直接执行loop.sh,不会在外面再套一层bash:

docker exec 638 ps aux

USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND

root 1 91.8 0.0 17968 2864 ? Rs 05:36 0:09 bash /loop.sh

root 6 0.0 0.0 15580 2032 ? Rs 05:36 0:00 ps aux

这样应用就可以拿到docker发送的SIGTERM信号了。

再举个例子。

比如我的keepalived容器。由于容器启动时我需要做一些配置修改(keepalived.conf),需要把这些操作放在一个脚本里,所以我的CMD是:CMD ["/opt/entry-point.sh"],在entry-point.sh中启动keepalived进程。

#!/bin/bash -x

#entry-point.sh

#replace variables in /etc/keepalived/keepalived.conf

/sbin/ipvsadm-restore < /etc/sysconfig/ipvsadm

/usr/sbin/keepalived --dont-fork --log-console --pid /keepalived.pid -D

tail -f /var/log/yum.log

entry-point.sh脚本的确是pid=1了,但keepalived进程的pid并不是1,因为它和上面的CMD command一样,是bash -c方式以entry-point.sh的子进程的身份执行的。正确的做法是什么呢?

要exec,不要fork:

#!/bin/bash -x

#entry-point.sh

#replace variables in /etc/keepalived/keepalived.conf

/sbin/ipvsadm-restore < /etc/sysconfig/ipvsadm

exec /usr/sbin/keepalived --dont-fork --log-console --pid /keepalived.pid -D

此时再来看容器内的进程,keepalived就是pid=1了,这时去docker stop容器,keepalived会捕捉到SIGTERM信号,然后清理掉virtual ip,gracefully的退出。

docker exec 576 ps aux

USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND

root 1 0.0 0.0 111660 4000 ? Ss 09:41 0:00 /usr/sbin/keepalived --dont-fork --log-console --pid /keepalived.pid -D

root 18 0.0 0.0 113904 2952 ? S 09:41 0:02 /usr/sbin/keepalived --dont-fork --log-console --pid /keepalived.pid -D

root 19 0.0 0.0 113780 2192 ? S 09:41 0:04 /usr/sbin/keepalived --dont-fork --log-console --pid /keepalived.pid -D

root 24 0.0 0.0 35884 1456 ? Rs 13:48 0:00 ps aux

Ref:

mysql小鲸鱼_杀死一只小鲸鱼相关推荐

  1. 万能门店小程序_超市门店微信小程序注册流程

    现在超市门店商家利用小程序卖货已经非常普遍,小程序可以便捷地连接线上线下通道,让商家不再局限于门店周围的流量,能够从微信获取更多客户,从而提升销量和店铺知名度.超市要想有自己的线上电商小程序,就得先注 ...

  2. 专属海报小程序_剑3泡泡 | 小程序给你一份专属的账号海报!

    01按照惯例,这里是简介 paopaods.com 本期推送的是: 如何正确的使用小程序 每个账号均可小程序[剑3泡泡]搜到,生成专属账号海报! 点击底部[点我卖号]即可拥有! 02教程开始之前,安利 ...

  3. 多个 小程序_最简单的小程序制作方法,不会代码也能撸一个

    前言 / 小程序从17年上线到现在已经构造了新的开发环境和开发者生态,现在已经有超过150万的开发者加入到开发,小程序应用数量超过100万,覆盖200多个行业.虽然开发难度较app减少了很多,但是对于 ...

  4. B站小姐姐分享--“含羞草“一只小短短OwO

    什么是短短? 短短的舞蹈,平心而论,在B站的舞见里不算非常出挑,但是看得出来录制的投稿都是用心在跳的.尤其是<恋爱循环>.<咏春>还有<玉生烟>是我最喜欢的三支舞, ...

  5. 可爱的小老鼠计算机教案,一只小老鼠小班教案

    在看看.猜猜.说说中理解故事内容,尝试学说故事中的短句,小班教案+小老鼠奇奇+反思.愿意和朋友互送礼物,体验同伴间分享的快乐.小班教案+小老鼠奇奇+反思范文,一起来看看.幼儿园小班教案+新朋友一:活动 ...

  6. 一个公众号可以绑定几个小程序_如何实现微信小程序和公众号的绑定

    再此之前,为什么要有小程序和公众号绑定这一个操作. 第一:小程序绑定公众号之后,公众号可以推文. 如下所示,公众号推文,文章内容由后台发布,因为公众号分为服务号和订阅号,订阅号每天可以发送一次,一次最 ...

  7. 不同主体公众号跳转小程序_公众号和小程序的区别

    其实公众号和小程序都是微信的衍生功能,同时微信的产品.但是它们的功能不同.公众号更倾向于引流,主要是通过持续的输出有价值的文案视频图片来吸引大量的粉丝(顾客),并且培育粉丝最终获得收益.(在这里特别提 ...

  8. 联想笔记本声音太小怎么办_笔记本声音太小,详细教您笔记本电脑声音太小解决方法...

    网友们在玩电脑游戏时,会遇到声音会很小的情况,如果笔记本游戏声音小的话,会让我们在使用笔记本时不自在,然而,笔记本声音小是低端笔记本的一个通病.那么该怎么去解决呢?下面,小编就来跟大家介绍笔记本电脑声 ...

  9. mysql小计_使用SQL实现小计,合计以及排序_MySQL

    bitsCN.com --说明:个人学习笔记,实现小计合计显示,分组按BANK_ID+OP_DATE升序排序 --测试数据CREATE TABLE #TB(ID VARCHAR(10),BANK_ID ...

最新文章

  1. LPSTR LPCSTR LPWSTR LPCWSTR区别
  2. 1.深度好文:带缓冲I/O 和不带缓冲I/O的区别与联系
  3. 网络爬虫入门系列(3) httpClient
  4. 303. 区域和检索 - 数组不可变
  5. Coil - Google推荐的协程图片加载库
  6. GTKmm 学习资料
  7. .NET异步编程之新利器——Task与Await、Async
  8. Android逆向笔记-使用Android Studio调试Smali代码(方式二)
  9. sql内部连接_SQL内部联接的分步演练
  10. 关于进程与线程的讲解 最最最生动的理解
  11. 基于Haproxy的高可用实战
  12. SpringCloud Ribbon的分析
  13. Extjs4.2如何实现鼠标点击统计图时弹出窗口来展示统计的具体列表信息
  14. Atitit 写的计算机技术类的书 与it类紧密的学科 atiitt it学科体系化 体系树与知识点概念大总结 v3 t88.xlsx 门类 学科一级分类 专业、二级学科分类 课程 书籍 工学
  15. 干货分享:如何挑选一款高效的原型工具?
  16. everything开启服务器功能
  17. 将图片背景设置为透明的方法介绍
  18. 台大林轩田机器学习课程笔记2----机器学习的分类
  19. python人脸特征提取_Python实现识别人脸特征并打印出来
  20. python多线程爬取m3u8视频(包含AES解密)

热门文章

  1. NOIP 2016(不是游记)
  2. 论文笔记 - 《Very Deep Convolutional Networks For Large-Scale Image Recognition》 精典
  3. 重启服务器导致网站系统错误,win10怎么总是莫名其妙重启?_网站服务器运行维护...
  4. 2014 UESTC Training for Data Structures D - 长使英雄泪满襟
  5. 公网ip和私网ip的区别_自带公网IP上阿里云
  6. CentOS7环境下搭建Kibana
  7. mosquitto源码分析(四)
  8. matlab机械臂工作空间代码_轻型协作机械臂运动学及工作空间分析
  9. keil4怎么移植其他人的程序_关节炎怎么治疗效果才会好?
  10. Unity3D性能优化