• Docker技术入门与实战 第二版-学习笔记-5-容器-命令及限制内存与cpu资源


    1.启动容器

    启动容器有两种方式:

    • 基于镜像新建一个容器并启动
    • 将在终止状态(stopped)的容器重新启动

    1)新建并启动——docker run

    比如在启动ubuntu:14.04容器,并输出“Hello World”,之后终止容器:

    userdeMBP:~ user$ docker run ubuntu:14.04 /bin/echo 'Hello world'
    Hello world

     如果要启动一个bash终端,并且允许用户进行交互:

    userdeMacBook-Pro:~ user$ docker run -t -i ubuntu:14.04 /bin/bash
    root@db3bc701340a:/# 

     -t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上

    -i 则让容器的标准输入保持打开

     然后在交互模式上就能够通过所创建的终端对ubuntu系统进行操作,如:

    root@db3bc701340a:/# pwd
    /
    root@db3bc701340a:/# ls
    bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
    root@db3bc701340a:/# 

    当利用 docker run来创建容器时,Docker 在后台运行的标准操作包括:

    • 检查本地是否存在指定的镜像,不存在就从公有仓库下载
    • 利用镜像创建并启动一个容器
    • 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
    • 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
    • 从地址池配置一个 ip 地址给容器
    • 执行用户指定的应用程序
    • 执行完毕后容器被终止

    2) 启动已终止容器——docker start

    容器的核心为所执行的应用程序,所需要的资源都是应用程序运行所必需的。

    除此之外,并没有其它的资源。可以在伪终端中利用 ps或 top来查看进程信息。

    root@db3bc701340a:/# ps
      PID TTY          TIME CMD
        1 pts/0    00:00:00 bash
       18 pts/0    00:00:00 ps
    root@db3bc701340a:/# top
    
    top - 03:22:22 up 8 min,  0 users,  load average: 0.36, 0.29, 0.15
    Tasks:   2 total,   1 running,   1 sleeping,   0 stopped,   0 zombie
    %Cpu(s):  1.7 us,  1.8 sy,  0.0 ni, 96.2 id,  0.2 wa,  0.0 hi,  0.1 si,  0.0 st
    KiB Mem:   2046748 total,  1942204 used,   104544 free,    23888 buffers
    KiB Swap:  1048572 total,     1844 used,  1046728 free.   984796 cached Mem
    
      PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                                                                     
        1 root      20   0   18188   3248   2764 S   0.0  0.2   0:00.04 bash                                                                                                                                        
       19 root      20   0   19868   2392   2068 R   0.0  0.1   0:00.00 top  

    可见,容器中仅运行了指定的 bash 应用。这种特点使得 Docker 对资源的利用率 极高,是货真价实的轻量级虚拟化。

    2.后台(background)运行

    很多时候,需要让 Docker在后台运行而不是直接把执行命令的结果输出在当前宿主机下。

    此时,可以通过添加 -d 参数来实现。

      -d, --detach     Run container in background and print container ID 即在后台运行容器,并打印出容器ID

    比如,当你不使用-d 参数时:

    userdeMacBook-Pro:~ user$ docker run ubuntu:14.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
    hello world
    hello world
    hello world
    hello world
    hello world
    .....

    容器会把输出的结果(STDOUT)打印到宿主机上面

    但是如果使用 -d 参数:

    userdeMacBook-Pro:~ user$ docker run -d ubuntu:14.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
    3c091389b4ffb583b4cca578b751e0a4b4e1d556852fe58a5f3d50003cb95737

    此时容器会在后台运行并不会把输出的结果(STDOUT)打印到宿主机上面

    输出结果可以用docker logs 查看:

    userdeMacBook-Pro:~ user$ docker logs 3c091389b4ff
    hello world
    hello world
    hello world
    hello world
    hello world
    hello world
    hello world
    ....

    注: 容器是否会长久运行,是和docker run指定的命令有关,和 -d 参数无关。

    使用docker ps查看容器信息:

    userdeMacBook-Pro:~ user$ docker ps
    CONTAINER ID        IMAGE                COMMAND                  CREATED              STATUS              PORTS                     NAMES
    3c091389b4ff        ubuntu:14.04         "/bin/sh -c 'while t…"   About a minute ago   Up 59 seconds                                 gallant_franklin

    3.终止容器 ——docker stop

    终止状态的容器可以使用docker ps -a命令查看:

    userdeMacBook-Pro:~ user$ docker ps -a
    CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS                        PORTS                     NAMES
    3c091389b4ff        ubuntu:14.04         "/bin/sh -c 'while t…"   5 minutes ago       Up 5 minutes                                            gallant_franklin

    对于这些终止了的容器,可以通过docker start来重启;

    docker restart命令会将一个运行态的容器终止,然后重新启动

    4.进入容器

    某些时候需要进入容器进行操作,有很多种方法,包括使用 docker attach命令或 nsenter工具等

    1) attach 命令

    使用方法:

    • 首先以后台方式打开一个容器
    • 然后使用docker attach +容器名 来进入该容器
    userdeMacBook-Pro:~ user$ docker run -idt ubuntu:14.04
    3adcf64dd30067011f15ef1c8b341f505f9900f382252da27d963c81aee4ba10
    
    userdeMacBook-Pro:~ user$ docker ps
    CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                     NAMES
    3adcf64dd300        ubuntu:14.04         "/bin/bash"              16 seconds ago      Up 15 seconds                                 elastic_easley
    3c091389b4ff        ubuntu:14.04         "/bin/sh -c 'while t…"   23 minutes ago      Up 23 minutes                                 gallant_franklin
    
    userdeMacBook-Pro:~ user$ docker attach elastic_easley
    root@3adcf64dd300:/# 

    但是使用 attach 命令有时候并不方便。

    当多个窗口同时 attach 到同一个容器的时候,所有窗口都会同步显示。

    当某个窗口因命令阻塞时,其他窗口也无法执行操作了。

    2) nsenter 命令

    工具在 util-linux 2.23版本后包含,如果没有,本地的安装方法为:

    $ cd /tmp; curl https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz | tar -zxf-; cd util-linux-2.24;
    $ ./configure --without-ncurses
    $ make nsenter && sudo cp nsenter /usr/local/bin

    使用方法:

    nsenter启动一个新的shell进程(默认是/bin/bash), 同时会把这个新进程切换到和目标(target)进程相同的命名空间,这样就相当于进入了容器内部。

    nsenter 要正常工作需要有 root 权限。 很不幸,Ubuntu 14.04 仍然使用的是 util-linux 2.20。安装最新版本的 util-linux(2.29)版,请按照以下步骤:

    $ wget https://www.kernel.org/pub/linux/utils/util-linux/v2.29/util-linux-2.29.tar.xz; tar xJvf util-linux-2.29.tar.xz
    $ cd util-linux-2.29
    $ ./configure --without-ncurses && make nsenter
    $ sudo cp nsenter /usr/local/bin

    运行时有错:

    userdeMacBook-Pro:util-linux-2.29 user$ ./configure --without-ncurses && make nsenter
    ...省略
        warnings:
    
     -fno-common -Wall -Werror=sequence-point -Wextra -Wextra-semi -Wembedded-directive -Wmissing-declarations -Wmissing-prototypes -Wno-missing-field-initializers -Wredundant-decls -Wsign-compare -Wtype-limits -Wuninitialized -Wunused-parameter -Wunused-result -Wunused-variable -Wnested-externs -Wpointer-arith -Wstrict-prototypes -Wformat-security -Wimplicit-function-declaration
    
        Type 'make' or 'make <utilname>' to compile.
       CCLD     nsenter
    clang: error: no input files
    make: *** [nsenter] Error 1

    说是找不到nsenter文件

    后面分开运行:

    $./configure --without-ncurses
    $make

    又有问题:

    login-utils/login.c:61:10: fatal error: 'sys/sendfile.h' file not found
    #include <sys/sendfile.h>

    查找资料后在发现上面的安装方法是linux系统的,sys/sendfile.h是Linux自带的文件,而我使用的是mac系统,所以打算使用别的方法来使用nsenter

    后面发现其实不是这个问题,不应该运行mask,就是要运行make nsenter

    后面就换了一个版本看看,下载2.24版本,也没有成功

    后面使用github的jpetazzo/nsenter也没能成功

    安装nsenter到/usr/local/bin:

    userdeMacBook-Pro:~ user$ docker run --rm -v /usr/local/bin:/target jpetazzo/nsenter
    Unable to find image 'jpetazzo/nsenter:latest' locally
    latest: Pulling from jpetazzo/nsenter
    5c90d4a2d1a8: Pull complete 
    c6c4c486dd77: Pull complete 
    0ed6ac9f06ed: Pull complete 
    404416bec766: Pull complete 
    4bf954ba4ae2: Pull complete 
    23f698ff1fd0: Pull complete 
    b39fba43fbdb: Pull complete 
    7889943d47f6: Pull complete 
    446df4bc8efe: Pull complete 
    6074415f722e: Pull complete 
    72024cea4c47: Pull complete 
    6c4b4f4219d3: Pull complete 
    93da7ec1688f: Pull complete 
    0c4337c5a938: Pull complete 
    Digest: sha256:a30e7da907a9abb715027677c21468005beee06251b7737c86f84fa148d572b0
    Status: Downloaded newer image for jpetazzo/nsenter:latest
    Installing nsenter to /target
    Installing docker-enter to /target
    Installing importenv to /target

      -v, --volume list    Bind mount a volume 绑定装入卷

    jpetazzo/nsenter容器将检测到/target是一个挂载点,并将nsenter二进制文件复制到其中

    运行时有错误:/usr/local/bin/nsenter: /usr/local/bin/nsenter: cannot execute binary file

    如果有小伙伴有解决的办法,希望能告知

    为了连接到容器,你还需要找到容器的第一个进程的 PID,可以通过下面的命令获取:

     PID=$(docker inspect --format "{{ .State.Pid }}" <container>)

    通过这个 PID,就可以连接到这个容器:

    $ nsenter --target $PID --mount --uts --ipc --net --pid

    3)exec命令

    userdeMBP:~ user$ docker run -idt ubuntu:14.04
    2084e92eea8c494023db35709d3d13054359ba71bca533371d04463652272a7b
    userdeMBP:~ user$ docker ps
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
    2084e92eea8c        ubuntu:14.04        "/bin/bash"              4 seconds ago       Up 3 seconds                                 boring_jackson
    b4a512f0230f        registry            "/entrypoint.sh /etc…"   2 days ago          Up About an hour    0.0.0.0:5000->5000/tcp   registry
    userdeMBP:~ user$ docker exec -it 2084e92eea8c /bin/bash
    root@2084e92eea8c:/# 

    还可以使用其来打印容器中的ip:

    userdeMBP:~ user$ docker exec -it 2084e92eea8c ip a
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        inet 127.0.0.1/8 scope host lo
           valid_lft forever preferred_lft forever
    2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1
        link/ipip 0.0.0.0 brd 0.0.0.0
    3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN group default qlen 1
        link/tunnel6 :: brd ::
    10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
        link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
        inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
           valid_lft forever preferred_lft forever

    5.导出和导入容器

    1) 导出容器——docker export

    userdeMacBook-Pro:~ user$ docker ps -a
    CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS                      PORTS                     NAMES
    dd8f619aef03        jpetazzo/nsenter     "bash"                   41 minutes ago      Exited (0) 41 minutes ago                             jovial_burnell
    3adcf64dd300        ubuntu:14.04         "/bin/bash"              2 hours ago         Exited (127) 2 hours ago                              elastic_easley
    3c091389b4ff        ubuntu:14.04         "/bin/sh -c 'while t…"   3 hours ago         Up 3 hours                                            gallant_franklin
    f7efcb534bb0        ubuntu:14.04         "/bin/sh -c 'while t…"   3 hours ago         Exited (0) 3 hours ago                                fervent_ritchie
    db3bc701340a        ubuntu:14.04         "/bin/bash"              3 hours ago         Exited (0) 3 hours ago                                focused_sanderson
    9dc39aa922f4        ubuntu:14.04         "/bin/echo 'Hello wo…"   15 hours ago        Exited (0) 15 hours ago                               nostalgic_burnell
    83fbcec3feda        568c4670fa80         "/bin/sh -c 'apt-get…"   21 hours ago        Exited (100) 21 hours ago                             ecstatic_ritchie
    889e5311532c        nginx:v2             "nginx -g 'daemon of…"   27 hours ago        Exited (255) 3 hours ago    0.0.0.0:81->80/tcp        web2

    然后导出上面的nginx:v2:

    userdeMacBook-Pro:~ user$ docker export 889e5311532c > nginx.tar

    然后就会在本地的~目录下生成nginx.tar文件

    2)导入容器快照——docker import

    userdeMacBook-Pro:~ user$ cat nginx.tar | docker import - test/nginx:v1
    sha256:02548ab0445a4490b1801762d2d8c342a8ec4a38f1686165c4e6eb4f10fc87ad
    userdeMacBook-Pro:~ user$ docker images
    REPOSITORY                                 TAG                 IMAGE ID            CREATED             SIZE
    test/nginx                                 v1                  02548ab0445a        6 seconds ago       107MB

    也可以通过指定 URL 或者某个目录来导入,如:

    docker import http://example.com/exampleimage.tgz example/
    imagerepo

    ⚠️用户既可以使用 docker load来导入镜像存储文件到本地镜像库,也可以使用 docker import来导入一个容器快照到本地镜像库。

    这两者的区别在于容器快照文件(docker import)将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件(docker load)将保存完整记录,体积也要大。

    此外,从容器快照文件导入时可以重新指定标签等元数据信息。

    6) 删除容器——docker rm

    删除一个处于终止状态(先docker stop)的容器

    如果要删除一个运行中的容器,可以添加 -f参数。Docker 会发送 SIGKILL信号给容器。

    清理所有处于终止状态的容器

    先使用docker ps -a查看所有查看所有已经创建的包括终止状态的容器

    一个个删除会很麻烦,可以使用下面的方法:

    userdeMacBook-Pro:~ user$ docker rm $(docker ps -a -q)
    dd8f619aef03
    3adcf64dd300
    f7efcb534bb0
    db3bc701340a
    9dc39aa922f4
    83fbcec3feda
    889e5311532c
    f97514a2ac93
    45104c30f94e
    67cf9831aa1b
    eb38c07055c8
    40d9af4487ce
    f44af23ba62c
    b6ea66b4a0d8
    b9606b2017da
    6b94d698640d
    60b85b6d1d40
    a9905c000180
    90dfc4e533af
    Error response from daemon: You cannot remove a running container 3c091389b4ffb583b4cca578b751e0a4b4e1d556852fe58a5f3d50003cb95737. Stop the container before attempting removal or force remove
    Error response from daemon: You cannot remove a running container f6a9a111a55d08f44da9b0a41755618e23baf3298f77b64f1c7375667721648b. Stop the container before attempting removal or force remove
    userdeMacBook-Pro:~ user$ docker ps -a
    CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                     NAMES
    3c091389b4ff        ubuntu:14.04         "/bin/sh -c 'while t…"   3 hours ago         Up 3 hours                                    gallant_franklin
    f6a9a111a55d        kumavis/zeroclient   "/bin/sh -c 'npm sta…"   4 weeks ago         Up 3 hours          0.0.0.0:32768->9000/tcp   zero-client_zeroClient_1
    userdeMacBook-Pro:~ user$ docker stop 3c091389b4ff
    3c091389b4ff
    userdeMacBook-Pro:~ user$ docker stop f6a9a111a55d
    f6a9a111a55d
    userdeMacBook-Pro:~ user$ docker rm $(docker ps -a -q)
    3c091389b4ff
    f6a9a111a55d

    上面可见其实docker rm默认是不会清除正在运行中的容器的,你需要先docker stop他们,再删除即可

    此时再查看就发现容器已经清空了

    userdeMacBook-Pro:~ user$ docker ps 
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

    7)限制资源:

    1》内存

    因为虚拟机容量有限,容器的内存如果总是增加,那么就可能会出现容器报错的情况,所以要对容器利用的资源进行限制,避免某个容器因占用太多资源而影响其他容器乃至整个 host 的性能

    运行docker run命令时使用以下的参数进行限制即可:

     -m, --memory bytes         Memory limit,限制内存,如--memory=200M
    --memory-swap 设置 内存+swap 的使用限额

    ⚠️如果在启动容器时只指定 -m 而不指定 --memory-swap,那么 --memory-swap 默认为 -m 的两倍

    使用 progrium/stress 镜像来学习如何为容器分配内存。该镜像可用于对容器执行压力测试

    参考https://www.cnblogs.com/CloudMan6/p/6986499.html

    userdeMacBook-Pro:~ user$ docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M
    Unable to find image 'progrium/stress:latest' locally
    latest: Pulling from progrium/stress
    a3ed95caeb02: Pull complete 
    871c32dbbb53: Pull complete 
    dbe7819a64dd: Pull complete 
    d14088925c6e: Pull complete 
    58026d51efe4: Pull complete 
    7d04a4fe1405: Pull complete 
    1775fca35fb6: Pull complete 
    5c319e267908: Pull complete 
    Digest: sha256:e34d56d60f5caae79333cee395aae93b74791d50e3841986420d23c2ee4697bf
    Status: Downloaded newer image for progrium/stress:latest
    stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
    stress: dbug: [1] using backoff sleep of 3000us
    stress: dbug: [1] --> hogvm worker 1 [8] forked
    stress: dbug: [8] allocating 293601280 bytes ...
    stress: dbug: [8] touching bytes in strides of 4096 bytes ...
    stress: dbug: [8] freed 293601280 bytes
    stress: dbug: [8] allocating 293601280 bytes ...
    stress: dbug: [8] touching bytes in strides of 4096 bytes ...
    --vm 1:启动 1 个内存工作线程。
    --vm-bytes 280M:每个线程分配 280M 内存

    因为设置给每个线程分配的280M内存小于设置的300M内存,所以成功运行

    但是如果每个线程分配的内存大于300M的话,就会出错,stress 线程报错,容器退出:

    userdeMacBook-Pro:~ user$ docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 310M
    stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
    stress: dbug: [1] using backoff sleep of 3000us
    stress: dbug: [1] --> hogvm worker 1 [8] forked
    stress: dbug: [8] allocating 325058560 bytes ...
    stress: dbug: [8] touching bytes in strides of 4096 bytes ...
    stress: FAIL: [1] (416) <-- worker 8 got signal 9
    stress: WARN: [1] (418) now reaping child worker processes
    stress: FAIL: [1] (422) kill error: No such process
    stress: FAIL: [1] (452) failed run completed in 0s
    userdeMacBook-Pro:~ user$ 

     2》cpu

    运行docker run命令时使用以下的参数进行限制即可:

     -c, --cpu-shares int       CPU shares (relative weight)CPU份额(相对权重),如--cpu-shares=10;默认为1024

    ⚠️通过 cpu share 可以设置容器使用 CPU 的优先级

     还是使用progrium/stress镜像:

    userdeMacBook-Pro:~ user$ docker run --name test1 -it --cpuset-cpus="0" -c 1024 progrium/stress --cpu 1
    stress: info: [1] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
    stress: dbug: [1] using backoff sleep of 3000us
    stress: dbug: [1] --> hogcpu worker 1 [6] forked
    userdeMacBook-Pro:~ user$ docker run --name test2 -it --cpuset-cpus="0" -c 1024 progrium/stress --cpu 1
    stress: info: [1] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
    stress: dbug: [1] using backoff sleep of 3000us
    stress: dbug: [1] --> hogcpu worker 1 [6] forked

    两个都设置为1024,通过--cpuset-cpus="0"参数设置它们使用的是同一个CPU。因为当 CPU 资源充足时,设置 CPU 的权重是没有意义的。只有在容器争用 CPU 资源的情况下, CPU 的权重才能让不同的容器分到不同的 CPU 用量

    然后调用docker stats命令来查看它们的CPU占比情况:

    可见基本上是1:1的情况

  • 相关阅读:
    牛客小白赛23
    三分查找模板和例题
    链式前向星存图模板
    树形dp求解树的重心和例题
    P3915-树的分解-(dfs)
    P2119 魔法阵-(桶排序+前后缀和)
    小阳的贝壳-(差分+线段树+gcd)
    NOJ1370: [蓝桥杯2018初赛]测试次数-(dp)
    begin.lydsy 入门OJ题库:3611-3613:神炎皇、降雷皇、幻魔皇
    1797: [Noi2010]海拔
  • 原文地址:https://www.cnblogs.com/wanghui-garcia/p/10122158.html
Copyright © 2020-2023  润新知