1. 运行容器
docker run是启动容器的方法。可用三种方式指定容器启动时执行的命令:
(1) CMD 指令。
(2) ENTRYPOINT 指令。
(3) 在 docker run 命令行中指定
容器启动时执行pwd,返回的 / 是容器中的当前目录。执行 docker ps 或 docker container ls 可以査看 Docker host 中当前运行的容器
docker ps -a
docker container -a
以上命令均可全部显示docker中的容器,包括已经停止或者退出的容器
1.1 让容器长期运行
如何让容器保存运行呢? 因为容器的生命周期依赖于启动时执行的命令,只要该命令不结束,容器也就不会退出。理解了这个原理,我们就可以通过执行一个长期运行的命令来保持容器的运行状态。
docker run ubuntu /bin/bash -c "while true;do sleep 1;done"
如果按照这种方式运行会导致终端一直被占用,可以通过加上参数
-d
以后台服务的方式运行,避免终端占用
注意一下容器的CONTAINERID和NAMES这两个字段。
CONTAINER ID是容器的短ID,启动容器时返回的是长ID。短ID 是长ID的前 12个字符。
NAMES 字段显示容器的名字,在启动容器时可以通过--name
参数显式地为容器命名,如果不指定,docker 会自动为容器分配名字。对于容器的后续操作,我们需要通过长ID
、短ID
或者名称
来指定要操作的容器。
docker stop xxx # xxx代表ID或者镜像名称
1.2 进入容器
- docker attach
通过 docker attach 可以 attach 到容器启动命令的终端。Ctrl + C 退出并停止容器
- docker exec
通过 docker exec 进入相同的容器
① -it 以交互模式打开 pseudo-TTY,执行 bash,其结果就是打开了一个 bash 终端。
② 进入到容器中,容器的 hostname 就是其 短ID
③ 可以像在普通 Linux 中一样执行命令。
④)执行 exit 退出容器,回到 docker host。
docker exec -it <container> bash|sh
- attach 和 exec区别
(1) attach 直接进入容器启动命令的终端,不会启动新的进程。
(2) exec则是在容器中打开新的终端,并且可以启动新的进程。
(3) 如果想直接在终端中查看启动命令的输出,用attach; 其他情况使用exec。
如果只是为了查看启动命令的输出,可以使用 docker logs 命令。
docker logs -f xxxx # xxx代表容器的ID或者容器名称,-f 跟 tail -f 一样的效果,持续打印输出
2. 运行容器的最佳实践
按用途容器大致可分为两类: 服务类容器
和工具类的容器
。
-
服务类容器以 daemon 的形式运行,对外提供服务,比如 Web Server、数据库等。通过
-d
以后台方式启动这类容器是非常合适的。如果要排查问题,可以通过exec -it
进入容器。 -
工具类容器通常能给我们提供一个临时的工作环境,通常以
run -it
方式运行。
运行 busybox
,run -it
的作用是在容器启动后就直接进入。我们这里通过 wget 验证了在容器中访问 internet 的能力。执行exit 退出终端,同时容器停止。工具类容器多使用基础镜像
,例如busybox、debian、ubuntu等
3. stop/start/restart 容器
通过 docker stop 可以停止运行的容器
docker stop xxx # xxx可以是容器ID或者容器名称
容器在 docker host中实际上是一个进程,docker stop 命令本质上是向该进程发送一个SIGTERM 信号。如果想快速停止容器,可使用docker kill 命令,其作用是向容器进程发送SIGKILL 信号。
对于处于停止状态的容器,可以通过docker start 重新启动
docker start xxx # 重启已经停止的容器
docker start 会保留容器的第一次启动时的所有参数。
docker restart 可以重启容器,其作用就是依次执行 docker stop 和 docker start。容器可能会因某种错误而停止运行。对于服务类容器,我们通常希望在这种情况下容器能够自动重启。启动容器时设置--restart
就可以达到这个效果。
docker run -d --restart=always xxx # 以后台服务的方式启动容器并保持容器一直启动
--restart=always 意味着无论容器因何种原因退出(包括正常退出),都立即重启;
该参数还可以是 --restart=on-failure:3,意思是如果启动进程退出代码非0,则重启容器,最多重启3次。
4. pause/unpause 容器
有时我们只是希望让容器暂停工作一段时间,比如要对容器的文件系统打个快照,或者docker host 需要使用 CPU,这时可以执行 docker pause。
处于暂停状态的容器不会占用CPU资源,直到通过dockerunpause 恢复运行。
5. 删除容器
使用 docker 一段时间后,host上可能会有大量已经退出了的容器
这些容器依然会占用host的文件系统资源,如果确认不会再重启此类容器,可以通过docker rm 删除。
docker rm 一次可以指定多个容器,如果希望批量删除所有已经退出的容器,可以执行如命令
docker rm -v $(docker ps -aq -f status=exited)
6. 状态机
(1) 创建容器
docker create --name myhttpd httpd
docker start 命令以后台方式启动容器,docker run 实际是 docker create 和 docker start 的组合
docker start myhttpd
只有当容器的启动进程退出时,--restart 才生效
退出包括正常退出或者非正常退出。例如:启动进程正常退出或发生OOM,此时 Docker 会根据
--restart
的策略判断是否需要重启容器。但如果容器是因为执行 docker stop 或 docker kill 退出,则不会自动重启。
7. 资源限制
一个 docker host 上会运行若干容器,每个容器都需要 CPU、内存和 IO资源。对于 KVM、VMware 等虚拟化技术,用户可以控制分配多少CPU、内存资源给每个虚拟机。对于容器,Docker 也提供了类似的机制避免某个容器因占用太多资源而影响其他容器乃至整个host的性能。
7.1 内存限额
与操作系统类似,容器可使用的内存包括两部分: 物理内存和swap。Docker通过下面两组参数来控制容器内存的使用量。
(1) -m
或--memory
: 设置内存的使用限额,例如 100MB,2GB。
(2)--memory-swap
: 设置内存+swap
的使用限额。
docker run -m 200M --memory-swap=300M ubuntu
其含义是允许该容器最多使用200MB的内存和100MB的swap。默认情况下,上面两组参数为-1,即对容器内存和 swap 的使用没有限制。
验证内存分配使用:
docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M
--vm 1: 启动一个内存工作线程
--vm-bytes 280M :每个线程分配280MB内存
可以看到没有超过 300M阈值,容器一直正常运行
将内存限制提高到 310MB,容器就直接运行失败,容器退出。
如果在启动容器时只指定 -m 而不指定 --memory-swap,那么-memory-swap 默认为 -m 的两倍
7.2 CPU限额
默认设置下,所有容器可以平等地使用 host CPU 资源并且没有限制。Docker可以通过 -c
或 --cpu-shares
设置容器使用 CPU 的权重。如果不指定,默认值为 1024。
与内存限额不同,通过 -c
设置的cpu share
并不是CPU 资源的绝对数量,而是一个相对的权重值。某个容器最终能分配到的CPU资源取决于它的cpu share
占所有容器cpu share
总和的比例。通过cpu share
可以设置容器使用CPU的优先级。
docker run --name "containerA" -c 1024 ubuntu
docker run --name "containerB" -c 512 ubuntu
containerA的 cpu share 是1024,是containerB的两倍。当两个容器都需要 CPU 资源时,containerA可以得到的CPU是containerB 的两倍。
注意:按权重分配CPU只会发生在CPU资源紧张的情况下。如果 containerA 处于空闲状态,这时,为了充分利用CPU资源,containerB也可以分配到全部可用的 CPU。
docker run --name containerA -it -c 1024 progrium/stress --cpu 1
docker run --name containerB -it -c 512 progrium/stress --cpu 1
--cpu 用来设置工作线程的数量。因为当前host只有1颗CPU,所以一个工作线程就能将CPU压满。如果host有多颗CPU,则需要相应增加--cpu 的数量。
如果 机器只有一个CPU,执行top命令,可以观察到CPU的占比情况为1:2,如果有多个CPU,则观察不到。
7.3 BlocklO 带宽限额
Block IO 是另一种可以限制容器使用的资源。BlockIO指的是磁盘的读写,docker 可通过设置权重、限制bps
和iops
的方式控制容器读写磁盘的带宽。
注:目前BlockI0限额只对 directIO(不使用文件缓存)有效。
- block l0 权重
默认情况下,所有容器能平等地读写磁盘,可以通过设置--blkio-weight
参数来改变容器blockIO 的优先级。
--blkio-weight
与--cpu-shares
类似,设置的是相对权重值,默认为500
。containerA读写磁盘的带宽是containerB的两倍。
docker run --name containerA -it --blkio-weight 600 ubuntu
docker run --name containerB -it --blkio-weight 300 ubuntu
- 限制 bps 和 iops
bps是byte per second,每秒读写的数据量
iops 是io per second,每秒 IO 的次数。
--device-read-bps: 限制读某个设备的 bps。
--device-write-bps: 限制写某个设备的 bps。
--device-read-iops: 限制读某个设备的 iops。
--device-write-iops: 限制写某个设备的 iops。
docker run -it --device-write-bps /dev/sda:30MB ubuntu # 限制读取/dev/sda 设备的速率为30MB/s
# 进入容器内执行
time dd if=/dev/zero of=test.out bs=1M count=800 oflag=direct
通过 dd 测试在容器中写磁盘的速度。因为容器的文件系统是在host /dev/sda上的,在容器中写文件相当于对 host /dev/sda 进行写操作。另外,oflag=direct 指定用directIO 方式写文件,这样--device-write-bps 才能生效。
8. 实现容器的底层技术
cgroup 和 namespace 是最重要的两种技术。
- cgroup 实现资源限额
- namespace 实现资源隔离。
8.1 cgroup
cgroup 全称 ControlGroup。Linux操作系统通过cgroup可以设置进程使用CPU、内存和 IO 资源的限额。前面我们看到的--cpu-shares
、-m
、--device-write-bps
实际上就是在配置cgroup。
可以在 /sys/fs/cgroup 中可以找到 cgroup。还是用例子来说明,启动一个容器,设置 --cpu-shares=512
docker run -it --cpu-shares 512 progrium/stress -c 1
在 /sys/fs/cgroup/cpu/docker 目录中,Linux会为每个容器创建一个 cgroup 目录,以容器长 ID 命名,目录中包含所有与 cpu 相关的 cgroup 配置,文件cpu.shares保存的就是--cpu-shares 的配置,值为 512。
同样的,/sys/fs/cgroup/memory/docker 和/sys/fs/cgroup/blkio/docker 中保存的是内存以及 BlockIO 的 cgroup 配置。
8.2 namespace
在每个容器中,我们都可以看到文件系统、网卡等资源,这些资源看上去是容器自己的。拿网卡来说,每个容器都会认为自己有一块独立的网卡,即使host 上只有一块物理网卡。这种方式非常好,它使得容器更像一个独立的计算机。
Linux 实现这种方式的技术是 namespace。namespace 管理着 host 中全局唯一的资源,并可以让每个容器都觉得只有自己在使用它。换句话说,namespace 实现了容器间资源的隔离。
Linux 使用了6种namespace,分别对应6种资源:Mount、UTS、IPC、PID、Network、User
- Mount namespace
Mount namespace 让容器看上去拥有整个文件系统。容器有自己的/
目录,可以执行mount和umount 命令。这些操作只在当前容器中生效,不会影响到host和其他容器。
- UTS namespace
默认情况下,简单地说,UTS namespace 让容器有自己的 hostname。容器的 hostname 是它的短 ID,可以通过-h或--hostname 参数设置。
docker run -it -h myhostname --cpu-shares 512 progrium/stress -c 1
-
lPC namespace
IPC namespace 让容器拥有自己的共享内存和信号量(semaphore)来实现进程间通信,而下会与host和其他容器的PC混在一起。 -
PlD namespace
容器在 host 中以进程的形式运行。例如当前host中运行了一些容器。
所有容器的进程都挂在 dockerd 进程下,同时也可以看到容器自己的子进程。
如果进入到某个容器内部,就只能看到自己的进程。
而且进程的PID不同于host 中对应进程的PID,容器中PID=1 的进程当然也不是 host的 init 进程。也就是说:容器拥有自己独立的一套PD,这就是PID namespace 提供的功能。
- Network namespace
Network namespace 让容器拥有自己独立的网卡、IP、路由等资源。
- User namespace
User namespace 让容器能够管理自己的用户,host 不能看到容器中创建的用户。
容器中创建 test 用户,host并不会创建对应的用户。
标签:容器,--,namespace,host,docker,CPU From: https://www.cnblogs.com/ccblblog/p/18065692