Dockerfile参考(5) – .dockerignore文件

在docker CLi发送上下文到docker daemon之前,它首先先在上下文的根目录查找名为.dockerignore的文件。如果这个文件存在,CLI则更改上下文来排除与这文件里的模式匹配的文件和目录。这帮助避免了发送不必要的大的或敏感的文件和目录到daemon,以及有可能使用ADD或COPY把不必要的文件添加到镜像。
CLI解析.dockerignore为以行为分隔的模式列表,类似于Unix shells的golbs文件。基于匹配的目的,上下文的根目录可以是工作目录或根目录。例如,/foo/bar和foo/bar模式都是排除PATH或URL git仓库根目录的子目录foo下的bar文件。
如果.dockerignore中的一行以#开始,那么这行视为注释,会以CLI解析前忽略。
例如:

  1. # comment
  2.     */temp*
  3.     */*/temp*
  4.     temp?

行为解释如下:

  • # comment:忽略
  • <*/temp*:排除在任意根目录的子目录下以temp开始的文件和目录。例如,/somedir/temporary.txt文件和/somedir/temp目录都被排除。
  • */*/temp*:排除从根目录两级目录的子目录下以temp开始的文件或目录。例如,/somedir/subdir/temporary.txt文件会被排除。
  • temp?:排除temp后加一个字符的文件或目录。如/tempa和/tempb被排除。
  • 使用Go的filepath.Match规则完成匹配。除了Go的filepath.Match规则,docker也支持一个特殊的通配符**,用来匹配任意数量的目录。如**/*.go将排除在所有目录中以.go后缀的文件,包括根目录。
    以!开始的行表示与排除相反的动作,即包括。如下:

    1. *.md
    2.     !README.md

    除了README.md,其它的.md文件排除。
    放置!例外规则影响的行为:.dockerignore的最后行匹配的文件决定是否是包含或排除。如下:

    1. *.md
    2.     !README*.md
    3.     README-secret.md

    除了README markdown文件(不含README-secret.md),其它的markdown文件包括全都排除。
    再看一个例子:

    1. *.md
    2.     README-secret.md
    3.     !README*.md

    包括所有的README文件。中间的行没有影响是因为!README*.md匹配了README-secret.md。
    你甚至可以使用.dockerignore文件来排除Dockerfile和.dockerignore文件。这些排除的文件仍然会发送到daemon,因为需要它们来工作。不过ADD和COPY命令不再复制它们到镜像。
    最后,你可能想指定包括一些文件,而不是排除。那么可以在第一行输入*,随后的行使用!来包括。

    注意:由于历史原因,模式.会被忽略。

    Dockerfile参考(4) – 使用环境变量

    由EVN指令声明的环境变量也可以用在Dockerfile的一些指令中作为变量使用。转义符也将类似变量的语法转义为语句。
    在Dockerfile引用环境变量可以使用$variable_name或${variable_name}。它们是等同的,其中大括号的变量是用在没有空格的变量名中的,如${foo}_bar。
    ${variable_name}变量也支持一些标准的bash修饰符,如:

  • ${variable:-word}表示如果variable设置了,那么结果就是设置的值。否则设置值为word
  • ${variable:+word}表示如果variable设置了,那么结果是word值,否则为空值。
  • word可以是任意的字符,包括额外的环境变量。
    转义符可以添加在变量前面:$foo or ${foo},例如,会分别转换为$foor和${foo}。
    示例:

    1. FROM busybox
    2. ENV foo /bar
    3. WORKDIR ${foo}   # WORKDIR /bar
    4. ADD . $foo       # ADD . /bar
    5. COPY $foo /quux # COPY $foo /quux

    环境变量支持在下面的指令中使用:

  • ADD
  • COPY
  • ENV
  • EXPOSE
  • LABEL
  • USER
  • WORKDIR
  • VOLUME
  • STOPSIGNAL
  • 也包括:

  • ONBUILD
  • 注意:1.4之前的版本,ONBUILD指令不支持环境变量,即使是与上面列出的指令一起使用。

    环境变量的替换在整个命令使用的值是一样的。例如:

    1. ENV abc=hello
    2. ENV abc=bye def=$abc
    3. ENV ghi=$abc

    def的值是hello,不是bye,不过,ghi的值为bye,因为设置abc为bye的命令与设置ghi命令不同。

    Dockerfile参考(3) – 解释器指令escape

    解释器指令是可选的,并影响Dockerfile随后行的处理方式。解释器指令不会添加新层到镜像,也不会显示在构建步骤中。解释器指令的编写格式是一种特定的注释格式# directive=value。一个指令只能用一次。
    一旦注释,空行或构建器指令已经被处理,Docker不再寻找解析器指令。相反,它将格式化为解析器指令的任何内容视为注释,并且不尝试验证它是否可能是解析器指令。因此,所有解析器指令必须位于Dockerfile的最顶端。
    解析器指令不区分大小写。不过,约定使用小写。也约定解释器指令后包括一个新空行。解析器指令不支持行连续字符。
    由于这些规则,下面的示例都是无效的:
    由于使用了行连续字符无效:

    1. # direc
    2. tive=value

    由于出现两次相同的解释器指令:

    1. # directive=value1
    2. # directive=value2
    3.  
    4. FROM ImageName

    由于出现在构建指令后,所以视为注释:

    1. FROM ImageName
    2. # directive=value

    由于出现在不是解释器指令的注释后面,视为一个注释:

    1. # About my dockerfile
    2. FROM ImageName
    3. # directive=value

    由于不被识别,未知的指令视为一个注释。此外由于出现在不是解释器指令的注释后面,一个已知的指令也视为注释。

    1. # unknowndirective=value
    2. # knowndirective=value

    解析器指令中允许使用非换行符空格。因此,下面的指令视为同样的:

    1. #directive=value
    2. # directive =value
    3. #   directive= value
    4. # directive = value
    5. #     dIrEcTiVe=value

    目前支持的解释器指令有:

  • escape
  • escape

    格式为:

    1. # escape= (backslash)

    1. # escape=` (backtick)

    escape指令用于设置在Dockerfile中转义使用的字符。如果不指定,默认的转义字符是。
    转义字符用来转义一行中的字符,也可以转义一个新行。这就允许Dockerfile的指令跨越多行。注意,不管escape解析器指令是否包括在Dockerfile中,除了在行尾转义新行 RUN命令中不进行字符转义。
    设置转义字符`对于windows上使用Dockerfile非常有用,因为默认的是目录路径的分隔符。而`与Windows PowerShell使用的转义字符一致。
    看下下面的在windows Dockerfile的示例,不是很显然地看出错误。第二行行尾的第二个解释为转义新行,而不是第一个的转义目标。结果是这个Dockerfile的第2行和第3行合并为一行处理:

    1. FROM windowsservercore
    2. COPY testfile.txt c:\
    3. RUN dir c:

    构建时输出:

    1. PS C:John> docker build -t cmd .
    2. Sending build context to Docker daemon 3.072 kB
    3. Step 1 : FROM windowsservercore
    4.  —> dbfee88ee9fd
    5. Step 2 : COPY testfile.txt c:RUN dir c:
    6. GetFileAttributesEx c:RUN: The system cannot find the file specified.
    7. PS C:John>

    上面的一个解决方法是使用/作为COPY和dir的路径分隔符。不过这个语法最好的结果是只会由于不是windows原生的分隔符感到混乱,最糟糕的情况是会导致错误,因为windows不是所有的命令都支持这个分隔符。
    所以最好的解决方法是使用excape解释器指令来指令`作为分隔符:

    1. # escape=`
    2.  
    3. FROM windowsservercore
    4. COPY testfile.txt c:
    5. RUN dir c:

    结果:

    1. PS C:John> docker build -t succeeds –no-cache=true .
    2. Sending build context to Docker daemon 3.072 kB
    3. Step 1 : FROM windowsservercore
    4.  —> dbfee88ee9fd
    5. Step 2 : COPY testfile.txt c:
    6.  —> 99ceb62e90df
    7. Removing intermediate container 62afbe726221
    8. Step 3 : RUN dir c:
    9.  —> Running in a5ff53ad6323
    10.  Volume in drive C has no label.
    11.  Volume Serial Number is 1440-27FA
    12.  
    13.  Directory of c:
    14.  
    15. 03/25/2016  05:28 AM    <DIR>          inetpub
    16. 03/25/2016  04:22 AM    <DIR>          PerfLogs
    17. 04/22/2016  10:59 PM    <DIR>          Program Files
    18. 03/25/2016  04:22 AM    <DIR>          Program Files (x86)
    19. 04/18/2016  09:26 AM                 4 testfile.txt
    20. 04/22/2016  10:59 PM    <DIR>          Users
    21. 04/22/2016  10:59 PM    <DIR>          Windows
    22.                1 File(s)              4 bytes
    23.                6 Dir(s)  21,252,689,920 bytes free
    24.  —> 2569aa19abef
    25. Removing intermediate container a5ff53ad6323
    26. Successfully built 2569aa19abef
    27. PS C:John>

    Dockerfile参考(2) – 格式

    下面是Dockerfile的格式:

    1. # Comment
    2. INSTRUCTION arguments

    instruction指令是不区分大小写的,不过一般约定使用大写字符以与参数区分开来。
    docker按顺序执行Dockerfile中的指令。第一个指令必须是FROM,用于指定从哪个Base Image构建镜像。
    Docker把以#开头的行视为注释,除非该行是一个有效的解释器指令。#标志在行中的其它地方视为一个参数,如:

    1. # Comment
    2. RUN echo ‘we are running some # of cool things’

    注释中不支持行连续字符。

    Dockerfile参考(1) – 用法

    docker build命令从Dockerfile文件和上下文构建一个镜像。构建的上下文是一个指定的PATH或URL位置。PATH是你本地文件系统的一个目录。URL是git仓库地址。
    上下文是递归处理的。所以PATH包括所有的子目录,URL包括仓库和它的子模块。下面是使用当前目录作为上下文的简单build命令:

    1. $ docker build .
    2. Sending build context to Docker daemon  6.51 MB

    build命令来docker daemon运行,不是由CLI。build进程的第一件事是递归发送整个上下文给daemon。大多数情况下,最好使用一个空的目录作为上下文并放置Dockerfile到此目录。只添加构建Dockerfile时所需的文件。

    警告:不要使用root目录/作为PATH,因为它会导致build传递你硬盘的所有内容到docker daemon。

    Dockerfile包括了一系列用于构建镜像的指令,例如COPY指令。为了提高构建性能,可以通过添加.dockerignore文件到上下文目录来排除文件和目录。
    通常称为Dockerfile的Dockerfile文件放置在上下文的根目录。你可以将docker build与-f参数一起使用来指向你文件系统的任何位置的Dockerfile。

    1. $ docker build -f /path/to/a/Dockerfile .

    可以使用-t参数指定保存新镜像的仓库和标签:

    1. $ docker build -t shykes/myapp .

    要标记镜像到多个仓库,可以在build命令中使用多个-t参数:

    1. $ docker build -t shykes/myapp:1.0.2 -t shykes/myapp:latest .

    docker daemon一个接一个运行Dockerfile中的指令,在最后生成新镜像之前,如果需要,将提交每一个指令的结果到新镜像。docker daemon会自动清理你发送过来的上下文。
    注意每个指令都是独立运行的,所以RUN cd /tmp不会对下一个指令有任何影响。
    如果有可能,docker会重用镜像缓存来加速docker build进程。在控制台输出中使用到缓存时将显示Using cache消息。如:

    1. $ docker build -t svendowideit/ambassador .
    2. Sending build context to Docker daemon 15.36 kB
    3. Step 1 : FROM alpine:3.2
    4.  —> 31f630c65071
    5. Step 2 : MAINTAINER [email protected]
    6.  —> Using cache
    7.  —> 2a1c91448f5f
    8. Step 3 : RUN apk update &&      apk add socat &&        rm -r /var/cache/
    9.  —> Using cache
    10.  —> 21ed6e7fbb73
    11. Step 4 : CMD env | grep _TCP= | (sed ‘s/.*_PORT_([0-9]*)_TCP=tcp://(.*):(.*)/socat -t 100000000 TCP4-LISTEN:1,fork,reuseaddr TCP4:2:3 &/’ && echo wait) | sh
    12.  —> Using cache
    13.  —> 7ea8aef582cc
    14. Successfully built 7ea8aef582cc

    创建MongoDB Docker镜像

    简介

    本文我们准备学习如何构建MongoDB Docker镜像。以及如何推送镜像到Docker Hub registr和与其他人共享。
    使用docker和容器部署mongodb实例有几个好处:

  • 易于维护,高度可配置的MongoDB实例
  • 毫秒级运行和启动
  • 可共享镜像
  • 创建MongoDB Dockerfile

    我们来创建Dockerfile并开始构建它:
    以下说明的可选的,不过在Dockerfile开头添加注释可以说明它的目的:

    1. # Dockerizing MongoDB: Dockerfile for building MongoDB images
    2.     # Based on ubuntu:latest, installs MongoDB following the instructions from:
    3.     # http://docs.mongodb.org/manual/tutorial/install-mongodb-on-ubuntu/

    我们使用从Docker Hub最新的Ubuntu版本来构建镜像。

    1. # Format: FROM    repository[:version]
    2. FROM       ubuntu:latest

    然后声明此Dockerfile的维护者:

    1. # Format: MAINTAINER Name <[email protected]>
    2. MAINTAINER M.Y. Name <[email protected]>

    导入MongoDB公共GPG密钥。然后创建一个MongoDB仓库文件。

    1. # Installation:
    2. # Import MongoDB public GPG key AND create a MongoDB list file
    3. RUN apt-key adv –keyserver hkp://keyserver.ubuntu.com:80 –recv 7F0CEB10
    4. RUN echo "deb http://repo.mongodb.org/apt/ubuntu "$(lsb_release -sc)"/mongodb-org/3.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-3.0.list

    完成这些初始准备后我们就可以更新软件包并安装MongoDB。

    1. # Update apt-get sources AND install MongoDB
    2. RUN apt-get update && apt-get install -y mongodb-org

    MongoDB需要一个数据目录。

    1. # Create the MongoDB data directory
    2. RUN mkdir -p /data/db

    最后设置ENTRYPOINT来让docker从镜像运行一个容器时执行这个ENTRYPOINT。对于端口,使用EXPOSE暴露。

    1. # Expose port 27017 from the container to the host
    2. EXPOSE 27017
    3.  
    4. # Set usr/bin/mongod as the dockerized entry-point application
    5. ENTRYPOINT ["/usr/bin/mongod"]

    构建MongoDB Docker镜像

    开始构建镜像。

    1. # Format: docker build –tag/-t <user-name>/<repository> .
    2. # Example:
    3. $ docker build –tag my/repo .

    推送MongoDB镜像到Docker Hub

    首先登录到docker hub。

    1. # Log-in
    2. $ docker login
    3.  
    4. Username:
    5. ..

    开始推送:

    1. # Push the image
    2. # Format: docker push <user-name>/<repository>
    3. $ docker push my/repo
    4.  
    5. The push refers to a repository [my/repo] (len: 1)
    6. Sending image list
    7. Pushing repository my/repo (1 tags)
    8. ..

    使用MongoDB镜像

    使用刚构建好的MongoDB镜像,我们可以运行一个或多个MongoDB实例。

    1. # Basic way
    2. # Usage: docker run –name <name for container> -d <user-name>/<repository>
    3. $ docker run -p 27017:27017 –name mongo_instance_001 -d my/repo
    4.  
    5. # Dockerized MongoDB, lean and mean!
    6. # Usage: docker run –name <name for container> -d <user-name>/<repository> –noprealloc –smallfiles
    7. $ docker run -p 27017:27017 –name mongo_instance_001 -d my/repo –smallfiles
    8.  
    9. # Checking out the logs of a MongoDB container
    10. # Usage: docker logs <name for container>
    11. $ docker logs mongo_instance_001
    12.  
    13. # Playing with MongoDB
    14. # Usage: mongo –port <port you get from `docker ps`>
    15. $ mongo –port 27017
    16.  
    17. # If using docker-machine
    18. # Usage: mongo –port <port you get from `docker ps`>  –host <ip address from `docker-machine ip VM_NAME`>
    19. $ mongo –port 27017 –host 192.168.59.103

    如果需要在一个主机运行多个实例,需要映射不同的端口。

    1. # Start two containers and map the ports
    2. $ docker run -p 28001:27017 –name mongo_instance_001 -d my/repo
    3.  
    4. $ docker run -p 28002:27017 –name mongo_instance_002 -d my/repo
    5.  
    6. # Now you can connect to each MongoDB instance on the two ports
    7. $ mongo –port 28001
    8.  
    9. $ mongo –port 28002

    Docker管理指南(5) – 使用systemd控制和配置Docker

    许多Linux发行版本使用systemd来启动docker daemon。本文介绍如何自定义docker设置的一些示例。

    启动docker daemon

    docker安装后,开始启动docker daemon。

    1. $ sudo systemctl start docker
    2. # 或旧的发行版本,使用
    3. $ sudo service docker start

    设置docker开机启动:
    $ sudo systemctl enable docker
    # 或旧的发行版本,使用
    $ sudo chkconfig docker on

    自定义docker daemon选项

    有几种方法来配置docker daemon的参数和环境变量。
    推荐的方法是使用systemd的drop-in文件。这些是在/etc/systemd/system/docker.service.d目录的命名为.conf的本地文件。也可以放置在/etc/systemd/system/docker.service文件,会覆盖默认的/lib/systemd/system/docker.service文件。
    不过如果你使用包管理器安装了docker,那么可能EnvironmentFile已经存在,为了向后兼容,在/etc/systemd/system/docker.service.d放置一下.conf文件,内容如下:

    1. [Service]
    2. EnvironmentFile=-/etc/sysconfig/docker
    3. EnvironmentFile=-/etc/sysconfig/docker-storage
    4. EnvironmentFile=-/etc/sysconfig/docker-network
    5. ExecStart=
    6. ExecStart=/usr/bin/dockerd $OPTIONS
    7.           $DOCKER_STORAGE_OPTIONS
    8.           $DOCKER_NETWORK_OPTIONS
    9.           $BLOCK_REGISTRY
    10.           $INSECURE_REGISTRY

    检查docker.service是否使用了EnvironmentFile:

    1. $ systemctl show docker | grep EnvironmentFile
    2.  
    3. EnvironmentFile=-/etc/sysconfig/docker (ignore_errors=yes)

    或者找出service文件放置的位置:

    1. $ systemctl show –property=FragmentPath docker
    2.  
    3. FragmentPath=/usr/lib/systemd/system/docker.service
    4.  
    5. $ grep EnvironmentFile /usr/lib/systemd/system/docker.service
    6.  
    7. EnvironmentFile=-/etc/sysconfig/docker

    你可以使用一个覆盖文件来自定义docker daemon选项。位于/usr/lib/systemd/system或/lib/systemd/system目录的文件包含了默认的选项,不应该去编辑它。

    运行时目录和存储驱动

    你可能想控制docker镜像,容器和volumes占用的硬盘空间,这个可以把它们移动到一个单独的分区。
    在这个示例中,我们假设你的docker.service文件类似如下:

    1. [Unit]
    2. Description=Docker Application Container Engine
    3. Documentation=https://docs.docker.com
    4. After=network.target
    5.  
    6. [Service]
    7. Type=notify
    8. # the default is not to use systemd for cgroups because the delegate issues still
    9. # exists and systemd currently does not support the cgroup feature set required
    10. # for containers run by docker
    11. ExecStart=/usr/bin/dockerd
    12. ExecReload=/bin/kill -s HUP $MAINPID
    13. # Having non-zero Limit*s causes performance problems due to accounting overhead
    14. # in the kernel. We recommend using cgroups to do container-local accounting.
    15. LimitNOFILE=infinity
    16. LimitNPROC=infinity
    17. LimitCORE=infinity
    18. # Uncomment TasksMax if your systemd version supports it.
    19. # Only systemd 226 and above support this version.
    20. #TasksMax=infinity
    21. TimeoutStartSec=0
    22. # set delegate yes so that systemd does not reset the cgroups of docker containers
    23. Delegate=yes
    24. # kill only the docker process, not all processes in the cgroup
    25. KillMode=process
    26.  
    27. [Install]
    28. WantedBy=multi-user.target

    我们可以在/etc/systemd/system/docker.service.d目录放置一个drop-in文件,包含如下内容:

    1. [Service]
    2. ExecStart=
    3. ExecStart=/usr/bin/dockerd –graph="/mnt/docker-data" –storage-driver=overlay

    可以在这个文件设置其它的环境变量,例如,HTTP_PROXY。
    要更改ExecStart配置,可以在一行空的ExecStart的下一行放置一个新的ExecStart:

    1. [Service]
    2. ExecStart=
    3. ExecStart=/usr/bin/dockerd –bip=172.17.42.1/16

    HTTP proxy

    此示例覆盖了默认的docker.service文件。
    如果你的主机需要通过Http代理服务器连网,你需要在docker systemd service文件配置一个http代理。
    1.为docker service创建一个systemd drop-in目录:

    1. $ mkdir /etc/systemd/system/docker.service.d

    2.创建/etc/systemd/system/docker.service.d/http-proxy.conf文件,添加HTTP_PROXY环境变量:

    1. [Service]
    2. Environment="HTTP_PROXY=http://proxy.example.com:80/"

    3.可以使用NO_PROXY指定不需要代理的一些地址:

    1. Environment="HTTP_PROXY=http://proxy.example.com:80/" "NO_PROXY=localhost,127.0.0.1,docker-registry.somecorporation.com"

    4.重载配置

    1. $ sudo systemctl daemon-reload

    5.验证配置是否已经加载:

    1. $ systemctl show –property=Environment docker
    2. Environment=HTTP_PROXY=http://proxy.example.com:80/

    6.重启docker

    1. $ sudo systemctl restart docker

    手动创建systemd单元文件

    如果你不是使用包管理器安装的docker,但想整合docker进systemd便于管理。可以从https://github.com/docker/docker/tree/master/contrib/init/systemd下载两个单元文件安装到/etc/systemd/system目录即可。

    Docker管理指南(4) – daemon停止时保持容器继续运行

    默认下,当docker daemon停止时,随即停止正在运行的容器。从Docker Engine 1.12开始,你可以配置daemon如果daemon变为不可用时容器保持继续运行。这个减少由于daemon崩溃,计划中断或升级导致的容器停机时间。

    启用live-restore选项

    有两种方式来启用live-restore设置来保持容器当daemon变为不可用时继续运行:

  • 如果daemon已经运行且你不想停止它,你可以把配置添加到daemon配置文件。例如,linux系统默认配置文件是/etc/docker/daemon.json。

    1. {
    2. "live-restore": true
    3. }

    编辑好之后需要发送一个SIGHUP信号到daemon进程来重载配置。

  • 启动docker daemon时,传递–live-restore参数:

    1. sudo dockerd –live-restore
  • 升级期间的live restore

    live restore功能支持在从一个小版本升级到下一个版本时恢复容器到daemon。例如从docker engine 1.12.1升级到1.13.2。
    如果在升级期间跳过版本,daemon可能无法恢复容器的连接。如果daemon无法恢复连接,则它将忽略正在运行的容器,这时你必须手动管理它们。daemon不会关闭断开连接的容器。

    重启时的live restore

    live restore选项仅可以恢复daemon重启前后配置相同选项的daemon。例如,如果daemon重启之后使用了不同的bridge IP或不同的graphdrive,则live restore无法工作。

    live restore对正在运行的容器的影响

    daemon长时间离线会影响到运行中的容器。容器进行向daemon写FIFO日志。如果由于daemon变不可用而无法处理这个输出,buffer将会被填满进而阻塞容器进一步写日志。默认的buffer大小为64K
    你必须重启docker来刷新buffers。
    可以通过改变/proc/sys/fs/pipe-max-size值来更改内核buffer大小。

    live restore与swarm模式

    live restore选项与docker engine swarm模式不兼容。当docker engine运行在swarm模式,编排功能管理任务并使容器根据服务规范运行。

    Docker管理指南(3) – 限制容器资源使用

    默认一个容器没有资源限制,能使用与主机内核调度器允许的给定资源一样多的资源。Docker提供了一个控制一个容器能使用多个内存,CPU或块IO的方法,就是在docker run命令设置运行时的配置参数。本文详细介绍你什么时候应该设置这些限制和设置它们时可能存在的影响。

    内存

    Docker可以设置内存硬限制,只允许使用不超过用户或系统内存给定的内存数量,或者软限制,允许容器使用它所需的尽可能多的内存,除非是遇到了一些条件,如内核检测下系统处理低内存状态或一些竞争情况。当单独使用或当使用超过一个选项,这些选项中的一些会有不同的影响。
    这些选项的大多数允许指定正整数,后面跟着一个后缀b,k,m,g来表示字节,千字节,兆字节或千兆字节。

  • -m or –memory=:容器可以使用的最大内存量。设置的值不能低于4m
  • –memory-swap*:允许容器交换到硬盘的最大内存量
  • –memory-swappiness:默认情况下,主机内核可以交换容器使用的匿名页面的百分比。你可以设置–memory-swappiness的值为0到100之间。
  • –memory-reservation:允许你指定一个比–memory小的软限制,在docker探测到主机低内存时激活。如果你使用–memory-reservation,必须设置一个比–memory小的值,以便软限制优先到达。因为软限制不保证容器不会超过这个限制。
  • –kernel-memory:容器能使用的最大内核内存量。最小可以设置到4m。因为内核内存不能被交换出去,一个缺乏内核内存的容器可能会阻塞主机资源,这会对主机和其他容器产生副作用。
  • –oom-kill-disable:默认下,当out-of-memory(OOM)错误产生时,内核会kill掉容器中的进程。可以使用–oom-kill-disableg来改变这个行为。如果设置了这个选项,那么仅在设置了-m/–memory的容器禁止OOM killer,如果-m没有设置,那么主机就能够用完所有内存,然后内核可能会杀死主机系统的进程来释放内存。
  • 关于cgroups和内存最多的信息请到https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt。

    –memory-swap详情

  • 如果这个选项没有设置,设置了–memory,容器能够使用-memory值的两倍swap。例如,–memory=”300m”,–memory-swap没有设置,那么容器能够使用300m内存和600m swap。
  • 如果–memory和–memory-swap都设置了,–memory-swap表示能够使用内存和swap的总数,–memory控制非swap内存的数量。所以如果–memory=”300m”,–memory-swap=”1g”,那么容器能够使用300m的内存和700m(1g -300m)的swap
  • 如果设置为-1(默认),容器就可以无限制使用swap。
  • –memory-swappiness详情

  • 值为0将关闭匿名页面交换。
  • 值100将所有匿名页面设置为可交换。
  • 默认情况下,如果不设置–memory-swappiness,将继承主机计算机的值。
  • –kernel-memory详情

    有以下几种情况:

  • 无限制的内存,无限制的内核内存:这个是默认行为。
  • 无限制的内存,有限制的内核内存:当所有的cgroups所需的内存量超过主机实际拥有的内存量时,适合设置为这样的。你可以配置内核内存不超过主机可用内存,容器需要更多的内存时只能等待了。
  • 有限制的内存,无限制的内核内存:总内存是有限制的,不过内核内核无限制。
  • 有限制的内存,有限制的内核内存:用户和内核限制都限制时对调试内存相关的问题会有帮助。如果一个容器用完了这两种内存其中的一种,它不会影响到其它的容器或主机。如果内核内存限制比用户内存低,使用完内核内存后会导致容器产生OOM错误。反之,不会遇到OOM。
  • CPU

    默认情况下,每个容器使用主机的CPU无限制。你可以通过下面的选项来对容器的CPU使用设置限制。

  • –cpu-shares:设置此参数比默认的1024大或小会增加或减小容器的权重,给它更大或更小主机CPU周期的比例的访问。这个只在CPU周期受到限制时才强制执行。当大量的CPU可用时,所有的容器都能够使用它们所需尽量多的CPU资源。所以这个是软限制。–cpu-shares不会阻容器在swarm模式下的调度。它会优先从可用CPU周期满足容器的CPU使用,但不过保证或保留特定的CPU周期。
  • –cpu-period:一个容器的一个逻辑CPU的调度周期。默认值是100000(100ms)
  • –cpu-quota:在由–cpu-period设置的时间段内容器可以调度的最大时间量。
  • –cpuset-cpus:使用此选项将容器固定到一个或多个CPU核心,以逗号分隔。
  • –cpu-period和–cpu-qota示例

    如果你有一个1 vCPU的系统,容器以–cpu-period=100000和–cpu-quota=50000运行,那么容器最大能消耗1个CPU的50%资源。

    1. $ docker run -ti –cpu-period=10000 –cpu-quota=50000 busybox

    如果你有一个4 vCPU系统,容器以–cpu-period=100000和–cpu-quota=200000运行,那么你的容器能最大消耗2个逻辑CPU(200%的–cpu-period)。

    1. $ docker run -ti –cpu-period=100000 –cpu-quota=200000

    –cpuset-cpus示例

    设置容器最大使用4 CPU,执行如下命令:

    1. $ docker run -ti –cpuset-cpus=4 busybox

    Block IO (blkio)

    有两个选项可用于调整给定容器对直接块IO设备的访问。你还可以按照每秒的字节数或每秒的IO操作来指定带宽限制。

  • blkio-weight:默认情况下,每个容器可以使用相同比例的块IO带宽(blkio)。默认权重是500。要提高或降低给定容器使用的blkio的比例,可以设置–blkio-weight为介于10和1000之间的值。此设置将平等地影响所有块IO设备。
  • blkio-weight-device:与–blkio-weight相同,但你可以使用语法–blkio-weight-device =“DEVICE_NAME:WEIGHT”为每个设备设置权重。DEVICE_NAME:WEIGHT是一个字符串,包含冒号分隔的设备名称和权重 。
  • –device-read-bps和–device-write-bps:根据大小限制设备的读取或写入速率,使用kb,mb或gb后缀。
  • –device-read-iops or –device-write-iops:通过IO操作/秒限制设备的读取或写入速率。
  • 块IO权限示例

    注意:–blkio-weight只影响直接IO,对缓冲IO没有影响。

    如果指定–blkio-weight和-blkio-weight-device,Docker使用–blkio-weight作为默认权重,并使用–blkio-weight-device重写命名设备上的默认值。
    要将/dev/sda的容器的设备权重设置为200,而不指定默认blkio-weight:

    1. $ docker run -it
    2.   –blkio-weight-device "/dev/sda:200"
    3.   ubuntu

    块带宽限制示例

    此示例将ubuntu容器对/dev/sda的最大写入速度限制为为1mbps:

    1. $ docker run -it –device-write-bps /dev/sda:1mb ubuntu

    此示例将ubuntu容器对/dev/sda的最大读取速率限制为每秒1000次IO操作:

    1. $ docker run -ti –device-read-iops /dev/sda:1000 ubuntu

    Docker管理指南(2) – 自动启动容器

    docker 1.2版本,docker机制内置了当容器退出时重启它们的重启策略。如果设置了,重启策略会在docker daemon启动时使用,如经典场景系统启动时。同时重启策略会确保链接容器以正确的顺序启动。
    如果重启策略没有满足你的需求(如你可能有非docker进程依赖docker容器),你可以使用进程管理器,如upstart,systemd或supervisor。

    使用进程管理器

    docker默认不会设置任何的重启策略,不过需要注意它们会与大多数的进程管理器冲突。所以如果你使用了进程管理器就不要设置重启策略了。
    当你设置好你的镜像并已经运行容器,你可以把它们附加到进程管理器来管理。当你执行docker start -a,docker就会自动附着所有运行的容器,或按需启动并转向所有信号以便进程管理器在一个容器停止能探测到并正确重启它。

    示例

    下面的示例显示两个进程管理器的配置,upstart和systemd。在这个示例中我们假设你已经启动了一个Redis容器,命名为redis_server。这些文件定义了当docker daemon启动时自动启动容器。

    upstart

    1. description "Redis container"
    2. author "Me"
    3. start on filesystem and started docker
    4. stop on runlevel [!2345]
    5. respawn
    6. script
    7.   /usr/bin/docker start -a redis_server
    8. end script

    systemd

    1. [Unit]
    2. Description=Redis container
    3. Requires=docker.service
    4. After=docker.service
    5.  
    6. [Service]
    7. Restart=always
    8. ExecStart=/usr/bin/docker start -a redis_server
    9. ExecStop=/usr/bin/docker stop -t 2 redis_server
    10.  
    11. [Install]
    12. WantedBy=default.target

    如果你想设置为一个系统服务,把上面的内容放到/etc/systemd/system目录下的一个文件,如/etc/systemd/system/docker-redis_server.service。
    如果你需要传递选项到redis容器,如–env,那么你需要使用docker run而不是docker start来启动容器。这个会每次服务启动时创建一个新的容器,这容器当服务停止时会自动停止和删除。

    1. [Service]
    2. ExecStart=/usr/bin/docker run –env foo=bar –name redis_server redis
    3. ExecStop=/usr/bin/docker stop -t 2 redis_server
    4. ExecStopPost=/usr/bin/docker rm -f redis_server

    要使用这个服务,重载systemd和启动服务:

    1. systemctl daemon-reload
    2. systemctl start docker-redis_server.service

    设置开机启动:

    1. systemctl enable docker-redis_server.service