1. docker 分层概念
- 内核空间:kernel,Linux 刚启动时会加载 bootfs 文件系统,之后 bootfs 会被卸载
- 用户空间:文件系统是 rootfs,包含 /dev, /proc, /bin 等
对与基础镜像,底层直接使用 Host 的 kernel,而自己只需要提供 rootfs 。
容器只能共用 Host kernel,不能修改。容器共用 host kernel,容器不能 kernel 升级。如果容器 kernel 版本有要求,这种更适合虚拟机。
1.1 为什么镜像采用分层结构
好处就是共享资源
新镜像从 base 镜像一层一层叠加生成的。每RUN一次,就在现有镜像的基础上增加一层。
只需在磁盘上保存一份 base 镜像;内存中也只需一份 base 镜像,就可以为所有容器使用。而且镜像的每一层都可以被共享
当需要修改时才拷贝数据,这种称作 Copy-on-Write。
2 Dockerfile 指令
COPY
将文件从 build context 复制到镜像。支持两种形式:
- COPY src dest
- COPY ["src", "dest"]
注意:src 只能指定 build context 中的文件或目录
ADD
从 build context 复制文件到镜像。不同的是,如果 src 是归档文件,文件会被自动解压到 dest。
ENV
设置环境变量,环境变量可被后面的指令使用。
WORKDIR
为后面指令设置镜像中的当前工作目录。
CMD
容器启动时运行指定的命令。
Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 可以被 docker run 之后的参数替换
ENTRYPOINT
设置容器启动时运行的命令。
Dockerfile 中可以有多个 ENTRYPOINT,只有最后一个生效。CMD 或 docker run 之后的参数会被当做参数传递给 ENTRYPOINT。
3 Docker 命令
attach vs exec
- attach 直接进入容器启动命令的终端,不会启动新的进程
- exec 是在容器中打开新的终端,并且可以启动新的进程
如果想直接在终端中查看启动命令的输出,用 attach;其他情况使用 exec。
stop start restart
stop 命令向该进程发送一个 SIGTERM 信号。如果想快速停止容器,用 docker kill 命令,向容器进程发送 SIGKILL 信号,docker pause命令则不一样,它利用了cgroups的特性将运行中的进程空间暂停。
容器可能会因某种错误而停止运行。对于服务类容器能够自动重启。启动容器时设置 --restart = always 就可以
rm
批量删除所有已经退出的容器,可以执行如下命令:
docker rm $(docker ps -aq)
docker rm -v $(docker ps -aq -f status=exited)
build 命令根据 Dockerfile 文件中的 FROM 指令获取到镜像,然后重复地(create和start),修改,commit。在循环中的每一步都会生成一个新的层,因此许多新的层会被创建。
docker exec 命令会在运行中的容器执行一个新进程。
docker inspect命令会提取出容器或者镜像最顶层的元数据。
在 Docker 容器中的初始化进程(PID1 进程)在容器进程管理上具有特殊意义。它可以被 Dockerfile 中的 ENTRYPOINT
或 CMD
指令所指明;也可以被docker run
命令的启动参数所覆盖。
4 Docker 内存限额
容器使用的内存包括两部分:物理内存和 swap。 Docker 两组参数来控制容器内存:
-m
或--memory
:内存的使用限额,例如 100M, 2G。--memory-swap
:内存+swap 的使用限额。
例如运行命令如下:
$ docker run --memory=100M --memory-swap=200M progrium/stress --vm 1 --vm-bytes 90M
如果在启动容器时只指定 -m
而不指定 --memory-swap
,那么 --memory-swap
默认为 -m
的两倍
5 Docker CPU 限额
通过 -c
或 --cpu-shares
设置容器使用 CPU 的权重。如果不指定,默认值为 1024。
容器能分配到的 CPU 资源取决于它的 cpu share 占所有容器 cpu share 总和的比例。换句话说:通过 cpu share 可以设置容器使用 CPU 的优先级。
6 Docker Block IO 限额
Block IO:指的是磁盘的读写,docker 可以通过设置权重,限制bps和iops的方式控制容器读写磁盘的带宽
注:目前block IO限额只对direct IO(不使用文件缓存)有效。
Block IO权重:--blkio-weight,这个--blkio-weight的权重值在 10~1000之间
和容器cpu的使用机制是一致的,所有容器都可以平等的读写磁盘,可以通过--blkio-weight参数来改变容器的优先级
--blkio-weight和-c类似,设置的都是资源使用的权重,都是在资源紧张的情况下才会起到权重的作用,正常情况下,都是平等的
- bps:byte per second ,每秒读写的数据量
- iops:io per second ,每秒IO次数
可以通过以下参数来控制容器的bps 和iops:
- --device-read-bps:限制读某个设备的bps(数据量) 例:docker run -d --device-read-bps /dev/sdb:30M httpd
- --device-write-bps : 限制写入某个设备的bps(数据量) 例:docker run -d --device-write-bps dev/sdb:30M httpd
- --device-read-iops :限制读某个设备的iops(次数) 例:docker run -d --device-read-iops /dev/sdb
- --device-write-iops :限制写入某个设备的iops(次数)
7 Docker 网络
Docker 安装会在 host 上创建三个网络,docker network ls
命令查看:
none
这个网络下的容器除了 lo,没有其他任何网卡。容器创建时,--network=none
使用 none 网络
host
容器共享 host 的网络栈,容器的网络配置与 host 完全一样。--network=host
使用 host 网络。
最大的好处就是性能,适用的情况容器对网络传输效率有较高要求
7.1 创建网络
网络驱动:bridge, overlay 和 macvlan。overlay 和 macvlan 用于创建跨主机的网络
docker network create --driver bridge --subnet 172.200.200.0/24 --gateway 172.200.200.1 bridge_ne
可以使用新创建的网络如下所示:
docker run --network bridge_net
静态IP 分配 --ip
容器添加网卡:
docker network connect $network $docker_id
7.2 网络基础
- 网络命名空间
- veth 设备对
- Iptables / Netfilter
- 网桥
- 路由
Docker 容器中的各类网络栈设备都是 Docker Daemon 在启动时自动创建和配置的
网络命名空间代表的是一个堵路的协议栈,彼此之间相互隔离,无法通信:Veth 设备对就是打通互相看不到的协议栈 (不同命名空间进行通信)
8 Docker 信号处理
执行 docker stop
命令,docker 首先向容器的 PID1 进程发送一个SIGTERM信号,用于容器内程序的退出。如果容器在收到 SIGTERM 后没有结束, 那么 Docker Daemon 会在等待一段时间(默认是10s)后,再向容器发送 SIGKILL 信号,将容器杀死变为退出状态。这种方式给 Docker 应用提供了退出(graceful stop)机制,允许应用在收到 stop 命令时清理和释放使用中的资源。而 docker kill
可以向容器内 PID1 进程发送任何信号,缺省是发送 SIGKILL 信号来强制退出应用。
由于 PID1 进程的特殊性,Linux 内核做了特殊处理。如果它没有提供某个信号的处理逻辑,那么与其在同一个PID 名空间下的进程发送给它的该信号都会被屏蔽。主要是防止 init 进程被误杀。
8.1 孤儿进程
当一个子进程终止后,首先会变成一个失效(defunct)的进程,也称为僵尸 zombie 进程,等待父进程或系统收回。在 Linux 内核中维护了关于僵尸进程的信息(PID,终止状态,资源使用信息),从而允许父进程能够获取子进程的信息。如果不能正确回收僵尸进程,那么他们的进程描述符仍然保存在系统中,系统资源会缓慢泄露。
执行 docker stop
命令,docker 首先向容器的 PID1 进程发送一个SIGTERM信号,用于容器内程序的退出。如果容器在收到 SIGTERM 后没有结束, 那么 Docker Daemon 会在等待一段时间(默认是10s)后,再向容器发送 SIGKILL 信号,将容器杀死变为退出状态。这种方式给 Docker 应用提供了退出(graceful stop)机制,允许应用在收到 stop 命令时清理和释放使用中的资源。而 docker kill
可以向容器内 PID1 进程发送任何信号,缺省是发送 SIGKILL 信号来强制退出应用。
8.2 信号与init进程
当容器内的init进程可以对信号进行捕获,当SIGTERM或SIGINT等信号,对其子进程做信息保存,资源回收等处理。
9. docker run参数
docker version: 17.12.1-ce
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
Run a command in a new container
Options:
--add-host list 为容器添加host与ip的映射关系
-a, --attach list 容器的用户
--blkio-weight uint16 限制容器读写权重,权重值在10~1000之间,0为关闭权重(该参数默认为0) 默认,所有的容器对于 IO 操作都拥有相同优先级。
--blkio-weight-device list 设置设备的权重,权重值在10~1000之间,且优先级高于blkio.weigh (docker run --blkio-weight-device "/dev/sda:100" )
--cap-add list 添加权限 http://linux.die.net/man/7/capabilities (在docker容器内限制了大部分的linux权限,在之前,需要开启这些功能需要结合--privileged开启特权模式才能使用这些参数,考虑到安全性,可以通过该参数来开启指定的linux功能,若参数为all则默认开启所有linux权限)
--cap-drop list 删除权限 http://linux.die.net/man/7/capabilities
--cgroup-parent string 配置容器的控制组,继承该控制组的资源限制模式
--cidfile string 运行容器后,在指定文件中写入容器PID值,一种典型的监控系统用法(若该文件存在,则会返回一个错误)
--cpu-period int 与参数--cpu-quota配合使用,设定cpu从新分配资源的时间周期,时间周期结束后,会对cpu进行重新分配。
--cpu-quota int 与参数--cpu-period配合使用,设定容器在资源分配周期内占用cpu的时间,若容器设定--cpu-quota=1000000 --cpu-period=500000,则该容器在这个时间周期内权重为50%,容器的权重比,用来解决宿主机内若干容器的资源抢占导致重要容器cpu性能不足的场景(Linux 的CFS模式)
--cpu-rt-period int 为--cpu-period量级微妙
--cpu-rt-runtime int 在一个cpu资源分配周期内,优先保证某容器的cpu使用的最大微秒数。例如,默认周期为 1000000 微秒(1秒),设置 --cpu-rt-runtime=800000 可确保使用实时调度程序的容器每 1000000 微秒可运行 800000 微秒,并保留至少 200000 微秒用于非实时任务
-c, --cpu-shares int 设置容器CPU权重,在CPU共享场景使用
--cpus decimal 设置容器使用cpu的数量,该参数为1.3新增参数用于快速设置容器对于cpu的占用
--cpuset-cpus string 设置容器可以使用哪些CPU,此参数可以用来容器独占CPU
--cpuset-mems string 同参数--cpuset-cpus
,但该参数是作用于NUMA 架构的 CPU
-d, --detach 容器运行于前台还是后台默认为false
--detach-keys string 设置容器的键盘映射键位,在容器被链接到前台时,若宿主机的键盘键位与容器键位冲突,可以使用该指令对容器的键位进行重新映射
--device list 添加主机设备给容器,相当于设备直通,将宿主机的设备映射至容器
--device-cgroup-rule list 将宿主机的设备添加到cgroup规则列表中
--device-read-bps list 以字节数/每秒的形式限制设备的读取速率 (docker run --device-read-bps /dev/sda:100KB)
--device-read-iops list 以每秒所执行IO操作的次数的形式限制设备的读取速率
--device-write-bps list 以字节数/每秒的形式限制设备的写入速率
--device-write-iops list 以每秒所执行IO操作的次数的形式限制设备的写入速率
--disable-content-trust 忽略镜像的校验 (default true)
--dns list 指定容器的dns服务器,默认和宿主一致
--dns-option list 设置DNS选项,同修改/etc/resolv.conf文件
--dns-search list 指定容器的dns搜索域名,默认和宿主一致,写入到容器的/etc/resolv.conf文件
--entrypoint string 覆盖image的入口点
-e, --env list 环境变量
--env-file list 指定环境变量文件,文件格式为每行一个环境变量
--expose list 指定容器暴露的端口,即修改镜像的暴露端口
--group-add list 为容器添加用户组
--health-cmd string 执行一个健康检查命令
--health-interval duration 设置健康检查的执行的间隔时间 (ms|s|m|h) (default 0s)
--health-retries int 健康检查命令失败重试的次数
--health-start-period duration Start period for the container to initialize before starting health-retries
countdown (ms|s|m|h) (default 0s)
--health-timeout duration 设置健康检查命令超时时间 (ms|s|m|h) (default 0s)
--help Print usage
-h, --hostname string 容器的主机名
--init 使用init在容器中新增一个守护进程,来预防该容器出现僵尸进程的可能性
-i, --interactive 打开STDIN,用于控制台交互
--ip string IPv4 address (e.g., 172.30.100.104)
--ip6 string IPv6 address (e.g., 2001:db8::33)
--ipc string 启用ipc命名空间。容器中进程交互采用了Linux进程间交互方法(interprocess communication - IPC), 包括信号量、消息队列和共享内存等。容器的进程间交互实际上还是host上具有相同pid命名空间中的进程间交互,因此需要在IPC资源申请时加入命名空间信息,每个IPC资源有一个唯一的32位id。
--isolation string 使用容器隔离
default 与使用dockerd --exec-opt的参数默认效果相同
process 使用linux内核命名空间进行隔离,该参数不支持windows环境。
--kernel-memory bytes 限制该容器内核的内存使用
-l, --label list 设置该容器的元数据
--label-file list 通过本地文件导入元数据至该容器
--link list 指定容器间的关联,使用其他容器的IP、env等信息
--link-local-ip list 设置本地链路地址(link-local address)ip
--log-driver string 设置一个指定日志接受工具,用于动态收集日志。扩展阅读日志处理与log-driver实现
--log-opt list 用于设置日志输出参数
--mac-address string 设置该容器mac地址
-m, --memory bytes 容器的内存上限
--memory-reservation bytes 软限制该容器的内存使用,当宿主机内存空闲时,该容器的内存使用可以一定比例超出限制,但当宿主机内存紧张时,会强制该容器内存使用限制在该参数之内
--memory-swap bytes 内存交换分区大小限制。配合参数--memory使用,且最小内存交换限制应该大于内存限制。该参数有4种情况:(1)不设置--memory与该参数:则该容器默认可以用完宿舍机的所有内存和 宿主机 swap 分区。
- (2)设置--memory 50MB 不设置--memory-swap(默认为0):则--memory-swap值等于限制内存大小,即该容器能够申请的最大内存为100MB。
- (3)设置--memory 50MB --memory-swap为-1:则该容器最大可以申请的内存为50MB+宿主机swap分区大小
- (4)设置--memory 50MB --memory-swap 100MB:则该容器可以申请的最大内存为100MB-50MB=50MB
--memory-swappiness int 用于调整虚拟内存的控制行为,为0~100之间的整数。在linux内存管理中,将内存中不活跃的页交换至硬盘中,以缓解内存紧张,该参数设置为0则认定该容器所有内存中的内容均不允许交换至硬盘,用以保障最大性能,若设置为100,则认为该容器所有内存中的数据均可以交换至硬盘。扩展阅读Linux内存管理
--mount mount 将文件系统挂载附加到容器
--name string 指定容器名字,后续可以通过名字进行容器管理,links特性需要使用名字
--network string 容器网络设置:
bridge 使用docker daemon指定的网桥
host //容器使用主机的网络
container:NAME_or_ID >//使用其他容器的网路,共享IP和PORT等网络资源
none 容器使用自己的网络(类似--net=bridge),但是不进行配置
--network-alias list 设置该容器在网络上的别名
--no-healthcheck 禁止一切健康检查行为
--oom-kill-disable 设置是否禁止oom kill行为,若该容器因为需要大量请求内存,导致宿主机内存不足或触发到内存限制,导致杀死该容器进程,若设置该参数为true则会关闭这个检查
--oom-score-adj int 调整主机的OOM首选项(从-1000到1000)不建议用户修改--oom-score-adj
--oom-kill-disable
--pid string 自定义设置该容器的pid namespace
--pids-limit int 该参数值为整数,为限制该容器所能创建的最大进程数。
--privileged 指定容器是否为特权容器,特权容器拥有所有的capabilities
-p, --publish list 容器暴露的端口
-P, --publish-all 容器暴露所有端口到宿主机随机端口
--read-only 设置该容器只读
--restart string 指定容器停止后的重启策略:
no:容器退出时不重启
on-failure:容器故障退出(返回值非零)时重启
always:容器退出时总是重启
--rm 指定容器停止后自动删除容器(不支持以docker run -d启动的容器)
--runtime string 指定该容器关联一个runtime的容器
--shm-size bytes 设置/dev/shm/目录的大小
--sig-proxy 设置由代理接受并处理信号,但是SIGCHLD、SIGSTOP和SIGKILL不能被代理
--stop-signal string 停止带有信号的容器,在linux环境下输入kill -l
,就可以看到所有信号名称,可以指定容器发出某种信号时停止该容器,譬如SIGKILL
(default "SIGTERM")
--stop-timeout int 设置容器调用命令超时后自动退出。该参数可以设置容器在调用命令时导致超时后多少秒退出,0为永远不退出,该参数单位为秒
--storage-opt list 设定该容器的存储空间,可以分别指定dm.basesize、dm.loopdatasize、dm.loopmetadatasize等项,指定单个容器可用数据空间、元数据可用数据空间。
--sysctl map 修改内核参数,对应修改容器中的/etc/sysctl.conf
文件
--tmpfs list 指定挂载一个tmpfs目录,tmpfs是一种虚拟内存文件系统。可以不经由镜像直接创建一个容器
-t, --tty 分配tty设备,持终端登录默认为false
--ulimit ulimit 设置容器的ulimit选项
-u, --user string 该容器下添加新用户 (format: <name|uid>[:<group|gid>])
--userns string 指定该容器运行在指定user namespace中
--uts string 使用uts命名空间
-v, --volume list 容器挂载存储卷,挂载到容器的某个目录
--volume-driver string 默认 volume loclal,主机上的一个目录 mount 到容器内的一个目录,不具备可移植性
--volumes-from list 给容器挂载其他容器上的卷,挂载到容器的某个目录
-w, --workdir string 容器的工作目录