AMao
小菜鸡目前对一些东西的认知,希望师傅们可以帮忙纠正!

浅谈 Docker

2020-07-17 计算机基础 Docker
Word count: 8.7k | Reading time: 33min

基础

概述

  • Docker 是开源的应用容器引擎。(Goalng编写)

  • Docker 可以让你将所有应用软件以及它的以来打包成软件开发的标准化单元。

  • Docker 容器将软件以及它运行安装所需的一切文件(代码、运行时、系统工具、系统库)打包到一起,这就保证了不管是在什么样的运行环境,总是能以相同的方式运行。就好像 Java 虚拟机一样,“一次编写,到处运行(Write once, run anywhere)”,而 Docker 是“一次构建,到处运行(Build once,run anywhere)”。

  • 概括的说

    Docker 是为开发人员和系统管理员用于构建、发布、并运行分布式应用程序的开放式平台。该平台由 Docker 引擎(一个便携、轻巧的运行时和打包工具) 和 Docker Hub (一个共享应用程序和自动化工作流的云服务)等组成。

  • Docker 可以使应用程序从组件迅速组装并消除了开发、质量保证和生产环境之间的摩擦问题。这样一来,IT部门可以更快地发布,而这些应用程序不管是运行在笔记本电脑、数据中心的虚拟机,还是任何的云,其运行过程和结果都是一致的。

优点

  • 轻量级

    所有容器在一台机器上共享同一个操作系统内核,这样他们立即开始,并更有效地利用内存。Image 是从分层文件系统的构建,这样他们能够共享公共文件,使得磁盘使用率和 Image 的下载更加高效。

  • 开放

    Docker 容器是基于开发的标准,允许容器运行在主流的 Linux 发布版和 Microsoft 操作系统作为所有的基础设施。

  • 安全

    容器使得应用程序彼此隔离,而基础架构同时为应用程序提供了额外的保护层。

相关概念

镜像(Image)

  • Docker 镜像就是一个只读的模板。

    例如:一个镜像可以包含一个完整的 centos 操作系统环境,里面仅安装了 Apache 或用户需要的其它应用程序。

  • 镜像可以用来创建 Docker 容器。

  • Docker 提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用。

容器(Container)

  • Docker 利用容器来运行应用。

  • 容器是从镜像创建的运行实例。

    它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。

  • 可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。

  • 注:镜像是只读的,容器在启动的时候创建一层可写层作为最上层。

    仓库(Repository)**

    仓库是集中存放镜像文件的场所。有时候会把仓库和仓库注册服务器(Registry)混为一谈,并不严格区分。实际上,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。

    仓库分为公开仓库(Public)和私有仓库(Private)两种形式。

容器(Container)

  • Docker 利用容器来运行应用

  • 容器是从镜像创建的运行实例

    它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。

  • 可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。

  • 注:镜像是只读的,容器在启动的时候创建一层可写层作为最上层。

仓库(Repository)

仓库是集中存放镜像文件的场所。

  • 有时候会把仓库和仓库注册服务器(Registry)混为一谈,并不严格区分。实际上,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。

  • 仓库分为公开仓库(Public)和私有仓库(Private)两种形式。

    • 最大的公开仓库是 Docker Hub,存放了数量庞大的镜像供用户下载。

      国内的公开仓库包括 Docker Pool 等,可以提供大陆用户更稳定快速的访问。

    • 用户也可以在本地网络内创建一个私有仓库。

    当用户创建了自己的镜像之后就可以使用 push 命令将它上传到公有或者私有仓库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上 pull 下来就可以了。

  • 注:Docker 仓库的概念跟 Git 类似,注册服务器可以理解为 GitHub 这样的托管服务。

Docker和虚拟机的区别

虚拟机架构

每个虚拟机都包括应用程序、必要的二进制文件和库以及一个完整的客户操作系统(Guest OS),尽管它们被分离,它们共享并利用主机的硬件资源,将近需要十几个 GB 的大小。

  • Hypervisor:管理程序

  • Infrastructure:底层结构

容器的架构

容器包括应用程序及其所有的依赖,但与其他容器共享内核。它们以独立的用户空间进程形式运行在主机操作系统上。

他们也不依赖于任何特定的基础设施,Docker 容器可以运行在任何计算机上,任何基础设施和任何云上。

Docker 的容器利用了 LXC(Linux Container),管理利用了 namespaces 来做权限的控制和隔离,cgroups 来进行资源的配置,并且还通过 aufs 来进一步提高文件系统的资源利用率,而这些技术都不是 Docker 独创。

特性 容器 虚拟机
启动 秒级 分钟级
硬盘使用 一般为MB 一般为GB
性能 接近原生 弱于
系统支持 单机支持上千个容器 一般为几十个

LXC

LXC 与虚拟机的不同之处在于,它是一个操作系统级别的虚拟化环境,而不是硬件虚拟化环境。

他们都做同样的事情,但 LXC 是操作系统级别的虚拟化环境,虚拟环境有它自己的进程和网络空间,而不是创建一个完整成熟的虚拟机。

因此,一个 LXC 虚拟操作系统具有最小的资源需求,并启动只需几秒钟。

Docker和Microservices

Microservices(微服务) 依赖于“基础设施自动化”,而 Docker 正是“基础设施自动化”的利器。可以说 Docker 的火爆,一定程度上也带动了微服务架构的兴起,而微服务的广泛应用也促进了 Docker 繁荣。可以说两者相辅相成。

有关微服务的介绍,可以移步至 《简述 Microservices(微服务)》

优势

  • 开发更加敏捷

    • Docker 让开发人员可以自由定义环境,创建和部署的应用程序更快、更容易,IT 运维人员快速应对变化也更加灵活性。

    • Docker 可以快速创建容器,快速迭代应用程序,并让整个过程全程可见,使团队中的其他成员更容易理解应用程序是如何创建和工作的。

  • 更加可控

    Docker 使得开发人员保存从基础设施到应用的代码,帮助 IT 运维人管理拥有标准的、安全的、可扩展的操作环境。

  • 高可移植性

    Docker 允许自由选择,可以是从笔记本电脑到一个团队,从私人基础设施到公共云提供商。

  • 更高效的虚拟化

    Docker 容器的运行不需要额外的 hypervisor 支持,它是内核级的虚拟化,因此可以实现更高的性能和效率。

创建镜像

修改已有的镜像

需要启动一个容器,在容器内进行修改,并提交

  • 启动docker服务 (Centos)

    systemctl start docker.service

  • 查看已有镜像

    docker images

  • 启动容器并运行 /bin/bash 应用

    docker run -t -i Image_ID(前几位即可) /bin/bash

    • TIPS

      记住容器的 ID 每次启动都不同

  • 新建一个文件

    echo "hello word" > test.txt

  • 退出容器

    exit

  • 提交更新后的副本

    docker commit -m "提交的说明信息" -a "update_user_info" container_id localhost:5000/centos7:tag

    • -m

      指定提交的说明信息,跟我们使用的版本控制工具一样;

    • -a

      指定更新的用户信息

    • 创建镜像的容器的 ID;

    • 指定目标镜像的仓库名和 tag 信息。

    创建成功后会返回这个镜像的 ID 信息

利用Dockerfile创建镜像

使用 docker commit 来扩展一个镜像比较简单,但是不方便在一个团队中分享

Dockerfile

  • 概述

    Dockerfile是一个包含用于组合映像的命令的文本文档,可以使用在命令行中调用任何命令。 Docker通过读取Dockerfile中的指令自动生成映像。

    可以把每一层的安装、修改、构建、操作的命令都写入一个脚本 (dockerfile) ,用这个脚本来构建、定制镜像,那么之前我们提及的无法重复的问题、镜像构建透明性的问题、体积的问题都会解决

  • Dockerfile的基结构:

    • 基础镜像信息
    • 维护者信息
    • 镜像操作指令
    • 容器启动时执行指令
    • 注释 #

    示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # This dockerfile uses the Ubuntu image
    # VERSION 2
    # Author: docker_user
    # Command format: Instruction [arguments / command] …

    # 第一行必须指定基于的容器镜像
    FROM ubuntu

    # 维护者信息
    MAINTAINER docker_user docker_user@email.com

    # 镜像的操作指令,创建中运行(如安装软件包)
    RUN echo “deb http://archive.ubuntu.com/ubuntu/ raring main universe” >> /etc/apt/sources.list
    RUN apt-get update && apt-get install -y nginx
    RUN echo “\ndaemon off;” >> /etc/nginx/nginx.conf

    # 容器启动时执行指令
    CMD /usr/sbin/nginx
  • Dockerfile文件说明:

    Docker以从上到下的顺序运行Dockerfile的指令。为了指定基本映像,第一条指令必须是FROM。

    可以在Docker文件中使用指令

    • ADD

      复制本地文件到镜像

    • RUN

      镜像创建中执行的命令

    • CMD

      描述容器启动后运行的程序(命令)

    • FROM

      指定基于的容器镜像

    • EXPOSE

      指定向外部开放端口

      EXPOSE port

    • ENV

      定义镜像的环境变量

Dockerfile 创建镜像

  • 命令格式

    docker build [options] Path | URL | .

  • eg.

    docker build -t="myimage/centos7:v3" .

    • -t

      添加 tag,指定新的镜像的用户信息

  • 创建过程

    根据进程操作的输出信息

    • 首先上传 Dockerfile 内容,因为所有的操作都要依据 Dockerfile 来进行。

    • Dockfile 中的指令被一条一条的执行

      每一步都创建了一个新的容器,在容器中执行指令并提交修改(就跟之前介绍过的 docker commit 一样)。

    • 当所有的指令都执行完毕之后,返回了最终的镜像 id。

      所有的中间步骤所产生的容器都被删除和清理了

  • TIPS:

    一个镜像不能超过 127 层

镜像构建上下文

  • 在上面的构建命令中,会看到在 docker build 命令的结尾处有一个 .,表示当前目录,而Dockerfile就在当前目录,因此不少初学者以为这个就是指定Dockerfile所在路径,这么理解其实是不准确的。对应上面的命令格式,这其实是在指定上下文路径。

  • Docker在运行时分为 Docker 引擎和客户端工具。

    • Docker引擎提供了一组REST API,被称为 Docker Remote API
    • Docker命令这样的客户端工具,则是通过Docker Remote API 来与 Docker 引擎进行交互,从而完成各种功能的

    虽然表面上是在本机上完成各种Docker功能,但是实际上是通过 Docker Remote API 与Docker引擎交互,在Docker引擎中完成的各种功能。

    正是因为这种C/S设计,使得我们操作远程服务器的 Docker 引擎变得轻而易举。

  • 当我们进行镜像构建时,并非所有定制都会通过RUN命令完成,经常我们需要将一些本地文件复制至镜像,比如通过COPY指令、ADD指令等。

    可是镜像的构建是在Docker引擎中完成的,该如何将本地的文件上传到Docker引擎中呢?

    这就引入上下文概念,当镜像构建时会指定上下文路径,docker build 得知这个路径时,会将该路径下的所有内容打包,上传给Docker引擎。Docker引擎接收到这个上下文包之后,展开就会获得构建镜像的一切所需文件。

  • Dockerfile 中

    1
    COPY ./package.json /app/

    命令指定上下文路径为:. ,则将 当前目录(执行命令)/package.json 复制到镜像中的 /app/ 目录下

Dockerfile 文件命名

Dockerfile的文件名并不要求必须是Dockerfile,也并不要求必须将Dockerfile文件置于上下文目录当中,可以添加 -f 参数来指定 Dockerfile 的文件

镜像操作

查看

  • 命令

    docker images

导入

  • 命令(在镜像目录下)

    cat ubuntu-14.04.tar.gz | docker import - ubuntu:14.04

  • 导出的本地文件中再导入到本地镜像库

    docker load --input package_name.tar

导出

  • 命令

    docker save -o package_name.tar ubuntu:tag

删除本地镜像

  • 命令

    docker rmi Image_id/name

  • TIPS

    在删除镜像之前要先用 docker rm 删掉依赖于这个镜像的所有容器

  • 清理正在运行的容器

    docker stop $(docker ps -a -q)

    docker rm $(docker ps -a -q)

使用镜像创建容器

  • 命令

    docker run -t -i Image_ID /bin/bash

    • -t

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

    • -i

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

    • -d

      后台运行

容器管理

  • 查看

    docker ps -a

  • 启动

    docker start Container_ID

  • 停止

    docker stop Container_ID

  • 查看输出信息

    docker logs Container_ID

  • 退出

    exit

    Ctrl + C

  • 进入

    • docker exec -it container_ID sh

    • docker attach container_ID

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

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

    • nsenter

      • 安装

        大部分Linux发行版本都有

        1
        2
        3
        4
        5
        6
        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
        cp nsenter /usr/lacal/bin
      • 使用

        为了连接到容器,需要找到容器的第一个进程的 PID

        1
        2
        PID=$(docker inspect --format= "{{.State.Pid}}" container_ID)
        nsenter --target $PID --mount --uts --ips --net -pid

        也可以编写自动脚本

  • 删除

    docker rm Container_ID

  • 删除正在运行的容器

    docker rm -f COntainer_ID

    Docker 会发送 SIGKILL 信号给容器

容器与主机之间的文件操作

  • 复制文件到容器

    docker cp /xx/xx/xxx.xxx Container_ID:/xxx/xxx/xxx.xx

Docker Compose

Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,可以使用 YML 文件来配置应用程序需要的所有服务

  • Compose 使用的三个步骤:

    • 使用 Dockerfile 定义应用程序的环境
    • 使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
    • 最后,执行 docker-compose up 命令来启动并运行整个应用程序。
  • 示例

    • Dockerfile

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      # 从 Python 3.7 映像开始构建镜像
      FROM python:3.7-alpine
      # 将工作目录设置为 /code
      WORKDIR /code
      # 设置 flask 命令使用的环境变量
      ENV FLASK_APP app.py
      ENV FLASK_RUN_HOST 0.0.0.0
      # 安装 gcc,以便诸如 MarkupSafe 和 SQLAlchemy 之类的 Python 包可以编译加速。
      RUN apk add --no-cache gcc musl-dev linux-headers
      COPY requirements.txt requirements.txt
      RUN pip install -r requirements.txt
      COPY . .
      # 容器提供默认的执行命令为:flask run
      CMD ["flask", "run"]
    • docker-compose.yml

      1
      2
      3
      4
      5
      6
      7
      8
      9
      # yaml 配置
      version: '3'
      services:
      web:
      build: .
      ports:
      - "5000:5000"
      redis:
      image: "redis:alpine"
    • 启动应用程序

      docker-compose up

      加上 -d 可以后台运行

yml 配置指令参考

  • version

    指定本 yml 依从的 compose 哪个版本制定的。

  • build

    指定为构建镜像上下文路径:

    例如 webapp 服务,指定为从上下文路径 ./dir/Dockerfile 所构建的镜像:

    1
    2
    3
    4
    version: "3.7"
    services:
    webapp:
    build: ./dir

    或者,作为具有在上下文指定的路径的对象,以及可选的 Dockerfile 和 args:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    version: "3.7"
    services:
    webapp:
    build:
    context: ./dir
    dockerfile: Dockerfile-alternate
    args:
    buildno: 1
    labels:
    - "com.example.description=Accounting webapp"
    - "com.example.department=Finance"
    - "com.example.label-with-empty-value"
    target: prod
    • context:上下文路径。
    • dockerfile:指定构建镜像的 Dockerfile 文件名。
    • args:添加构建参数,这是只能在构建过程中访问的环境变量。
    • labels:设置构建镜像的标签。
    • target:多层构建,可以指定构建哪一层。
  • cap_add,cap_drop

    添加或删除容器拥有的宿主机的内核功能。

    1
    2
    3
    4
    5
    cap_add:
    - ALL # 开启全部权限

    cap_drop:
    - SYS_PTRACE # 关闭 ptrace权限
  • cgroup_parent

    为容器指定父 cgroup 组,意味着将继承该组的资源限制。

    1
    cgroup_parent: m-executor-abcd
  • command

    覆盖容器启动的默认命令。

    1
    command: ["bundle", "exec", "thin", "-p", "3000"]
  • container_name

    指定自定义容器名称,而不是生成的默认名称。

    1
    container_name: my-web-container
  • depeds_on

    设置依赖关系。

    • docker-compose up :以依赖性顺序启动服务。在以下示例中,先启动 db 和 redis ,才会启动 web。
    • docker-compose up SERVICE :自动包含 SERVICE 的依赖项。在以下示例中,docker-compose up web 还将创建并启动 db 和 redis。
    • docker-compose stop :按依赖关系顺序停止服务。在以下示例中,web 在 db 和 redis 之前停止。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    version: "3.7"
    services:
    web:
    build: .
    depends_on:
    - db
    - redis
    redis:
    image: redis
    db:
    image: postgres

    注意:web 服务不会等待 redis db 完全启动 之后才启动。

  • deploy

    指定与服务的部署和运行有关的配置。只在 swarm 模式下才会有用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    version: "3.7"
    services:
    redis:
    image: redis:alpine
    deploy:
    mode:replicated
    replicas: 6
    endpoint_mode: dnsrr
    labels:
    description: "This redis service label"
    resources:
    limits:
    cpus: '0.50'
    memory: 50M
    reservations:
    cpus: '0.25'
    memory: 20M
    restart_policy:
    condition: on-failure
    delay: 5s
    max_attempts: 3
    window: 120s

    可以选参数:

    • endpoint_mode:访问集群服务的方式。

      1
      2
      3
      4
      endpoint_mode: vip 
      # Docker 集群服务一个对外的虚拟 ip。所有的请求都会通过这个虚拟 ip 到达集群服务内部的机器。
      endpoint_mode: dnsrr
      # DNS 轮询(DNSRR)。所有的请求会自动轮询获取到集群 ip 列表中的一个 ip 地址。
    • labels:在服务上设置标签。可以用容器上的 labels(跟 deploy 同级的配置) 覆盖 deploy 下的 labels。

    • mode:指定服务提供的模式。

      • replicated:复制服务,复制指定服务到集群的机器上。
      • global:全局服务,服务将部署至集群的每个节点。
    • replicas:mode为 replicated 时,需要使用此参数配置具体运行的节点数量。

    • resources:配置服务器资源使用的限制,例如上例子,配置 redis 集群运行需要的 cpu 的百分比 和 内存的占用。避免占用资源过高出现异常。

    • restart_policy:配置如何在退出容器时重新启动容器。

      • condition:可选 none,on-failure 或者 any(默认值:any)。
      • delay:设置多久之后重启(默认值:0)。
      • max_attempts:尝试重新启动容器的次数,超出次数,则不再尝试(默认值:一直重试)。
      • window:设置容器重启超时时间(默认值:0)。
    • rollback_config:配置在更新失败的情况下应如何回滚服务。

      • parallelism:一次要回滚的容器数。如果设置为0,则所有容器将同时回滚。
      • delay:每个容器组回滚之间等待的时间(默认为0s)。
      • failure_action:如果回滚失败,该怎么办。其中一个 continue 或者 pause(默认pause)。
      • monitor:每个容器更新后,持续观察是否失败了的时间 (ns|us|ms|s|m|h)(默认为0s)。
      • max_failure_ratio:在回滚期间可以容忍的故障率(默认为0)。
      • order:回滚期间的操作顺序。其中一个 stop-first(串行回滚),或者 start-first(并行回滚)(默认 stop-first )。
    • update_config:配置应如何更新服务,对于配置滚动更新很有用。

      • parallelism:一次更新的容器数。
      • delay:在更新一组容器之间等待的时间。
      • failure_action:如果更新失败,该怎么办。其中一个 continue,rollback 或者pause (默认:pause)。
      • monitor:每个容器更新后,持续观察是否失败了的时间 (ns|us|ms|s|m|h)(默认为0s)。
      • max_failure_ratio:在更新过程中可以容忍的故障率。
      • order:回滚期间的操作顺序。其中一个 stop-first(串行回滚),或者 start-first(并行回滚)(默认stop-first)。

      注:仅支持 V3.4 及更高版本。

  • devices

    指定设备映射列表。

    1
    2
    devices:
    - "/dev/ttyUSB0:/dev/ttyUSB0"
  • dns

    自定义 DNS 服务器,可以是单个值或列表的多个值。

    1
    2
    3
    4
    5
    dns: 8.8.8.8

    dns:
    - 8.8.8.8
    - 9.9.9.9
  • dns_search

    自定义 DNS 搜索域。可以是单个值或列表。

    1
    2
    3
    4
    5
    dns_search: example.com

    dns_search:
    - dc1.example.com
    - dc2.example.com
  • entrypoint

    覆盖容器默认的 entrypoint

    1
    entrypoint: /code/entrypoint.sh

    也可以是以下格式

    1
    2
    3
    4
    5
    6
    7
    entrypoint:
    - php
    - -d
    - zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20100525/xdebug.so
    - -d
    - memory_limit=-1
    - vendor/bin/phpunit
  • env_file

    从文件添加环境变量。可以是单个值或列表的多个值。

    1
    env_file: .env

    也可以是列表格式:

    1
    2
    3
    4
    env_file:
    - ./common.env
    - ./apps/web.env
    - /opt/secrets.env
  • environment

    添加环境变量。您可以使用数组或字典、任何布尔值,布尔值需要用引号引起来,以确保 YML 解析器不会将其转换为 True 或 False。

    1
    2
    3
    environment:
    RACK_ENV: development
    SHOW: 'true'
  • expose

    暴露端口,但不映射到宿主机,只被连接的服务访问。

    仅可以指定内部端口为参数:

    1
    2
    3
    expose:
    - "3000"
    - "8000"
  • extra_hosts

    添加主机名映射。类似 docker client –add-host。

    1
    2
    3
    extra_hosts:
    - "somehost:162.242.195.82"
    - "otherhost:50.31.209.229"

    以上会在此服务的内部容器中 /etc/hosts 创建一个具有 ip 地址和主机名的映射关系:

    1
    2
    162.242.195.82  somehost
    50.31.209.229 otherhost
  • healthcheck

    用于检测 docker 服务是否健康运行。

    1
    2
    3
    4
    5
    6
    healthcheck:
    test: ["CMD", "curl", "-f", "http://localhost"] # 设置检测程序
    interval: 1m30s # 设置检测间隔
    timeout: 10s # 设置检测超时时间
    retries: 3 # 设置重试次数
    start_period: 40s # 启动后,多少秒开始启动检测程序
  • image

    指定容器运行的镜像。以下格式都可以:

    1
    2
    3
    4
    5
    image: redis
    image: ubuntu:14.04
    image: tutum/influxdb
    image: example-registry.com:4000/postgresql
    image: a4bc65fd # 镜像id
  • logging

    服务的日志记录配置。

    driver:指定服务容器的日志记录驱动程序,默认值为json-file。有以下三个选项

    1
    2
    3
    driver: "json-file"
    driver: "syslog"
    driver: "none"

    仅在 json-file 驱动程序下,可以使用以下参数,限制日志得数量和大小。

    1
    2
    3
    4
    5
    logging:
    driver: json-file
    options:
    max-size: "200k" # 单个文件大小为200k
    max-file: "10" # 最多10个文件

    当达到文件限制上限,会自动删除旧得文件。

    syslog 驱动程序下,可以使用 syslog-address 指定日志接收地址。

    1
    2
    3
    4
    logging:
    driver: syslog
    options:
    syslog-address: "tcp://192.168.0.42:123"
  • network_mode

    设置网络模式。

    1
    2
    3
    4
    5
    network_mode: "bridge"
    network_mode: "host"
    network_mode: "none"
    network_mode: "service:[service name]"
    network_mode: "container:[container name/id]"

    networks

    配置容器连接的网络,引用顶级 networks 下的条目 。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    services:
    some-service:
    networks:
    some-network:
    aliases:
    - alias1
    other-network:
    aliases:
    - alias2
    networks:
    some-network:
    # Use a custom driver
    driver: custom-driver-1
    other-network:
    # Use a custom driver which takes special options
    driver: custom-driver-2
    • aliases :同一网络上的其他容器可以使用服务名称或此别名来连接到对应容器的服务。
  • restart

    • no:是默认的重启策略,在任何情况下都不会重启容器。
    • always:容器总是重新启动。
    • on-failure:在容器非正常退出时(退出状态非0),才会重启容器。
    • unless-stopped:在容器退出时总是重启容器,但是不考虑在Docker守护进程启动时就已经停止了的容器
    1
    2
    3
    4
    restart: "no"
    restart: always
    restart: on-failure
    restart: unless-stopped

    注:swarm 集群模式,请改用 restart_policy。

  • secrets

    存储敏感数据,例如密码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    version: "3.1"
    services:

    mysql:
    image: mysql
    environment:
    MYSQL_ROOT_PASSWORD_FILE: /run/secrets/my_secret
    secrets:
    - my_secret

    secrets:
    my_secret:
    file: ./my_secret.txt
  • security_opt

    修改容器默认的 schema 标签。

    1
    2
    3
    4
    5
    security-opt:
    - label:user:USER # 设置容器的用户标签
    - label:role:ROLE # 设置容器的角色标签
    - label:type:TYPE # 设置容器的安全策略标签
    - label:level:LEVEL # 设置容器的安全等级标签
  • stop_grace_period

    指定在容器无法处理 SIGTERM (或者任何 stop_signal 的信号),等待多久后发送 SIGKILL 信号关闭容器。

    1
    2
    stop_grace_period: 1s # 等待 1 秒
    stop_grace_period: 1m30s # 等待 1 分 30 秒

    默认的等待时间是 10 秒。

  • stop_signal

    设置停止容器的替代信号。默认情况下使用 SIGTERM 。

    以下示例,使用 SIGUSR1 替代信号 SIGTERM 来停止容器。

    1
    stop_signal: SIGUSR1
  • sysctls

    设置容器中的内核参数,可以使用数组或字典格式。

    1
    2
    3
    4
    5
    6
    7
    sysctls:
    net.core.somaxconn: 1024
    net.ipv4.tcp_syncookies: 0

    sysctls:
    - net.core.somaxconn=1024
    - net.ipv4.tcp_syncookies=0
  • tmpfs

    在容器内安装一个临时文件系统。可以是单个值或列表的多个值。

    1
    2
    3
    4
    5
    tmpfs: /run

    tmpfs:
    - /run
    - /tmp
  • ulimits

    覆盖容器默认的 ulimit。

    1
    2
    3
    4
    5
    ulimits:
    nproc: 65535
    nofile:
    soft: 20000
    hard: 40000
  • volumes

    将主机的数据卷或着文件挂载到容器里。

    1
    2
    3
    4
    5
    6
    7
    version: "3.7"
    services:
    db:
    image: postgres:latest
    volumes:
    - "/localhost/postgres.sock:/var/run/postgres/postgres.sock"
    - "/localhost/data:/var/lib/postgresql/data"

数据管理

  • 概述

    Docker镜像是由多个文件系统(只读层)叠加而成。

    当我们启动一个容器的时候,Docker会加载只读镜像层并在其上(镜像栈顶部)添加一个读写层。

    如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏。

    当删除Docker容器,并通过该镜像重新启动时,之前的更改将会丢失。在Docker中,只读层及在顶部的读写层的组合被称为 Union File System(联合文件系统)

    为了能够保存(持久化)数据以及共享容器间的数据,Docker提出了 Volume 的概念。简单来说,Volume就是目录或者文件,它可以绕过默认的联合文件系统,而以正常的文件或者目录的形式存在于宿主机上。

  • 在容器中管理数据主要有两种方式:

    • 数据卷(Data volumes)

      数据卷是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,

      可以提供很多有用的特性:

      • 数据卷可以在容器之间共享和重用

      • 对数据卷的修改会立马生效

      • 对数据卷的更新,不会影响镜像

      • 卷会一直存在,即使容器被删除

      数据卷的使用,类似于 Linux 下对目录或文件进行 mount,镜像中的被指定为挂载点的目录中的文件会隐藏掉,能显示看的是挂载的数据卷

    • 数据卷容器(Data volume containers)

      如果有一些持续更新的数据需要在容器之间共享,最好创建数据卷容器。

      数据卷容器,其实就是一个正常的容器,专门用来提供数据卷供其它容器挂载的

数据卷的操作

  • 创建一个数据卷

    docker volume create my-vol

  • 查看数据卷

    docker volume ls

    • 查看指定数据卷

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      $ docker volume inspect volume_name
      [
      {
      "Driver": "local",
      "Labels": {},
      "Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
      "Name": "my-vol",
      "Options": {},
      "Scope": "local"
      }
      ]
  • 启动一个挂载数据卷的容器

    在用 docker run 命令的时候,使用 --mount 标记来将 数据卷 挂载到容器里

    在一次 docker run 中可以挂载多个数据卷

    1
    2
    3
    4
    5
    6
    $ docker run -d -P \
    --name web \
    # -v my-vol:/wepapp \
    --mount source=my-vol,target=/webapp \
    training/webapp \
    python app.py
  • 查看数据卷的具体信息

    docker inspect web

  • 删除数据卷

    docker volume rm volume_name

    数据卷是被设计用来持久化数据的,它的生命周期独立于容器,Docker 不会在容器被删除后自动删除数据卷,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的数据卷

    • 删除容器的时候使用 docker rm -v 删除数据卷

    • 清理无主的数据卷,避免占据空间

      docker volume prune

  • 在用 docker run 命令的时候,使用 -v 标记来创建一个数据卷并挂载到容器里

    在一次 run 中多次使用可以挂载多个数据卷

    也可以在 Dockerfile 中使用 VOLUME 来添加一个或者多个新的卷到由该镜像创建的任意容器

    • 加载一个数据卷到容器的 /webapp 目录,命令

      docker run -d -P --name web -v /webapp training/webapp python app.py

      创建一个 web 容器,并加载一个数据卷到容器的 /webapp 目录

      • -d:后台运行
      • -P:自动映射任意网络端口到我们Docker主机上介于49000到49900之间的随机高位端口
      • --name:启动的时候使用了 –name 命名这个container为 web
      • -v: 标记数据卷
    • 挂载一个主机目录作为数据卷

      交互模式:docker run -it -v /home/dock/Downloads:/usr/Downloads ubuntu64 /bin/bash

      后台运行:docker run -d -v /home/dock/Downloads:/usr/Downloads --name ubuntu1 ubuntu64

      加载主机的 /home/dock/Downloads 目录到容器的/usr/Downloads 目录

      • 本地目录的路径必须是绝对路径,如果目录不存在 Docker 会自动创建
      • Dockerfile 中不支持这种用法,这是因为 Dockerfile 是为了移植和分享用的。然而,不同操作系统的路径格式不一样,所以目前还不能支持
  • Docker 挂载数据卷的默认权限是读写,用户也可以通过 :ro 指定为只读

    docker run -d -P -name web -v /src/webapp:/opt/webapp:ro training/webapp python app.py

数据卷容器

如果用户需要在多个容器之间共享一些持续更新的数据,最简单的方式是使用数据卷容器。数据卷容器也是一个容器,但是它的目的是专门用来提供数据卷供其他容器挂载。

创建

  • 创建一个命名的数据卷容器 dbdata

    docker run -d -v /data --name dbdata training/postgres echo Data-only container for postgres

  • 在其他容器中使用 –volumes-from 来挂载 dbdata 容器中的数据卷。

    docker run -d --volumes-from dbdata --name db1 training/postgres

    docker run -d --volumes-from dbdata --name db2 training/postgres

    三个容器任何一方在该目录下的写入,其他容器都可以看到

    可以多次使用–volumes-from参数来从多个容器挂载多个数据卷

  • 也可以从其他已经挂载了容器卷的容器来挂载数据卷:

    链式dbdata -> db1 -> db3

    docker run -d --name db3 --volumes-from db1 training/postgres

  • 把所有mount volumes的container都移除掉(包括初始化的那个 dbdata container), volume才会被移除掉。通过这个属性可以方便的升级数据或者在不同container间迁移数据。

  • TIPS:使用 –volumes-from 参数所挂载数据卷的容器自己并不需要保持在运行状态

数据迁移

  • 备份

    • 启动数据容器

      docker run -d -v /dbdata --name dbdata training/postgres echo Data-only container for postgres

    • 本地主机挂载当前目录到容器的 /backup 目录

      docker run --volumes-from dbdata -v$(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata

      容器启动后,将容器中的/backup/backup.tar 备份到 /dbdata

      $(pwd) 是当前目录

  • 恢复

    • 首先

    • 创建一个带有数据卷的容器 dbdata2

      docker run -v /dbdata --name dbdata2 ubuntu /bin/bash

    • 然后创建另一个容器,挂载 dbdata2 的容器,并使用 tar 解压备份文件到挂载的容器卷中

      docker run --volumes-from dbdata2 -v $(pwd):/backup basybox tar xvf /backup/backup.tar

网络使用

Docker 允许通过外部访问容器或容器互联的方式来提供网络服务。

当docker启动时,它会在宿主机器上创建一个名为docker0的虚拟网络接口。它会从RFC 1918定义的私有地址中随机选择一个主机不用的地址和子网掩码,并将它分配给docker0

外部访问容器

  • 随机映射

    使用 -P 标记时,Docker 会随机映射一个 49000~49900 的端口到内部容器开放的网络端

    docker run -d -P training/webapp python app.py

  • 指定映射

    -p则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器

    • 格式

      • ip:host_port:container_port

      • ip::container_port

        主机端口随机,指定 IP 和容器端口

      • host_port:container_port

  • 查看映射端口配置

    • docker port Container_ID
    • docker port Container_ID Port_ID

容器互联

容器的连接(linking)系统是除了端口映射外,另一种跟容器中应用交互的方式。

该系统会在源和接收容器之间创建一个隧道,接收容器可以看到源容器指定的信息

  • 自定义容器命名

    连接系统依据容器的名称来执行。因此,首先需要自定义一个好记的容器命名。

    虽然当创建容器的时候,系统默认会分配一个名字,使用 --name 标记可以为容器自定义命名

    docker run -d --name Database training/postgres

    在启动 Database 容器的时候并没有使用 -p 和 -P 标记,从而避免了暴露数据库端口到外部网络上

  • --link 参数可以让容器之间安全的进行交互

    docker run -d -P --name Web --link Database:alias training/webapp python app.py

    • –link 参数的格式:--link name:alias
      • name 是要链接的容器的名称
      • alias 是这个连接的别名
  • Docker 通过 2 种方式为容器公开连接信息。

    • 环境变量

      命令:env

      DATABASE_ 开头的环境变量是供 web 容器连接 db 容器使用,前缀采用大写的连接别名

    • 更新 /etc/hosts 文件

      Docker 还添加 host 信息到父容器(这里指Web)的 /etc/hosts 的文件

      命令:cat /etc/hosts

      容器的ID作为主机名

      • 测试连通性

        ping Container_Name 会解析成具体的IP

管理工具

Supervisor

Shipyard

DockerUI

参考资料

Docker入门到实践

Docker中文指南

Docker官网

Docker交流网站

UnionFS

dionaea低交互式蜜罐和记录分析

蜜罐快速搭建

Dockefile文件下载

深入了解Docker Volume

声明

菜鸡还不具备创造能力,部分学习内容来自网络,回馈网络,如涉及版权问题,请联系删除 orz

Author: AMao

Link: https://passenger-amao.github.io/2020/07/17/Docker/

Copyright: 本站所有文章均采用 署名-非商业性使用-相同方式共享 4.0 国际(CC BY-NC-SA 4.0) 许可协议。转载请注明出处!

< PreviousPost
Linux 快速入门
NextPost >
2019湖湘杯WP-Web
CATALOG
  1. 1. 基础
    1. 1.1. 概述
    2. 1.2. 优点
    3. 1.3. 相关概念
      1. 1.3.1. 镜像(Image)
      2. 1.3.2. 容器(Container)
      3. 1.3.3. 容器(Container)
      4. 1.3.4. 仓库(Repository)
    4. 1.4. Docker和虚拟机的区别
      1. 1.4.1. 虚拟机架构
      2. 1.4.2. 容器的架构
      3. 1.4.3. LXC
      4. 1.4.4. Docker和Microservices
      5. 1.4.5. 优势
  2. 2. 创建镜像
    1. 2.1. 修改已有的镜像
    2. 2.2. 利用Dockerfile创建镜像
      1. 2.2.1. Dockerfile
      2. 2.2.2. Dockerfile 创建镜像
        1. 2.2.2.1. 镜像构建上下文
        2. 2.2.2.2. Dockerfile 文件命名
    3. 2.3. 镜像操作
      1. 2.3.1. 查看
      2. 2.3.2. 导入
      3. 2.3.3. 导出
      4. 2.3.4. 删除本地镜像
  3. 3. 使用镜像创建容器
  4. 4. 容器管理
    1. 4.0.1. 查看输出信息
    2. 4.0.2. 进入
  • 5. 容器与主机之间的文件操作
  • 6. Docker Compose
    1. 6.1. yml 配置指令参考
  • 7. 数据管理
    1. 7.0.1. 数据卷(Data volumes)
    2. 7.0.2. 数据卷容器(Data volume containers)
  • 7.1. 数据卷的操作
  • 7.2. 数据卷容器
    1. 7.2.1. 创建
    2. 7.2.2. 数据迁移
  • 8. 网络使用
    1. 8.1. 外部访问容器
      1. 8.1.1. 容器互联
  • 9. 管理工具
    1. 9.1. Supervisor
    2. 9.2. Shipyard
    3. 9.3. DockerUI
  • 10. 参考资料
  • 11. 声明