- docker create -it 其中 -it选项,如果没有的话,docker exec 进去,top时会报 TERM environment variable not set. 错误 ; 其实没有关系,手动 export TERM=xterm-256color 就可以了;其实, -it 选项和1号进程为 /bin/bash 是密切相关的; 如果1号进程不是 /bin/bash 的话,-it选项没有屁用
- docker 的CMD 其实是1号进程,一定不能立即就会退出的进程,如: service sshd start 就不行,如下脚本就可以:
123456#!/bin/bash# this is a start shell for containnerservice sshd startwhile :; dosleep 10000done
- 容器可以自杀: 容器内进程使用root kill -9 1 默认是杀不死1号进程的,但是:
当strace -p 1 的时候,kill -9 1 是可以杀死1号进程的 (难道说这是个bug?)
因为docker stop时是先给1号进程发送sigterm,是在不行才kill -9 ; 所以,1号进程最好能合理处理sigterm信号,最后退出;然而,容器内的root进程是有权限给1号进程发送sigterm信号的,所以,容器自杀其实是很方便的 - 改进版的1号进程
myinit.c
123456789#include <stdlib.h>#include <unistd.h>int main(int ac, char **av) {while(1){sleep(10000);}return 0;}
gcc -o myinit myinit.c
myinit.sh
1234#!/bin/bash# this is a start shell for containnerservice sshd startexec /sbin/myinit
- 其实还不够
你会慢慢发现,ssh连接失败,因为:sshd接到连接请求之后,检查是否session太多了(默认最大10个),超过了就不伺候了,直接断开; 为什么会太多了?sshd每次接到连接请求,会fork => fork (两次fork)出来一个子进程处理请求,就因为是两次fork,这个新的sshd进程便“过继”给了1号进程;但是上面的1号进程还不够成熟,不会带孩子,当这个新的sshd进程退出的时候,就需要1号进程来做一些处理(如:清理进程表项),但是1号进程还不会,于是新的sshd进程会处于 <defunct>状态;而sshd的祖先还以为该session还没结束,就不再接受新的请求了,解决办法:添加信号处理,如下:
1234567891011#include <stdlib.h>#include <unistd.h>#include <signal.h>int main(int ac, char **av) {signal(SIGCHLD, SIG_IGN);while(1){sleep(10000);}return 0;}
参考资料:
https://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/
https://github.com/phusion/baseimage-docker/blob/rel-0.9.16/image/bin/my_init
dockerd 提供了init 和init-path的选项,允许配置是否启动一个指定的(默认的)init进程, 该进程就是为了转发信号和收割僵尸进程 的 - 上面sshd对于连接请求是两次fork的说法不太对,见下图:
99、134进程并没有立即退出(不过,一旦意外退出,则 101、136将会被1号进程收养)
还有一种情况为:sshd被restart了,这时候30号进程退出,99、134被1号进程收养,如下:
由于我重启了sshd,再次连接就会失败,如下:
为什么呢?
稍后再查,至少可以确定的是,启动容器时候启动的sshd是可以正常服务的,登录进去重启的sshd是不能正常服务的
see also : https://docs.docker.com/engine/examples/running_ssh_service/
关于docker的内存限制:
- 如果每个docker容器限制最大使用4G,则可能会使用超过4G,(似乎是使用了交换分区了)
- 如果宿主机有64G内存,则允许docker容器内存总和大于64G,(这个不会也和交换分区有关吧)
- 文档说–memory-swap=-1 就禁止使用交换分区了,但是测试发现还是使用了1倍内存的交换分区