当前位置: > Linux服务器 > Docker >

Docker学习总结

时间:2018-06-06 17:48来源:linux.it.net.cn 作者:IT

1. 什么是Docker

  Docker是一种虚拟化技术,其在容器的基础上进一步封装了文件系统、网络互联、进程隔离等等,从而极大地简化了容器的创建和维护。Docker使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核的 cgroup,namespace,以及 AUFS 类的 Union FS 等技术,实现进程隔离、文件系统隔离、网络隔离等。Docker 底层的核心技术包括 Linux 上的命名空间(Namespaces)、控制组(Control groups)、Union 文件系统(Union file systems)和容器格式(Container format)。

Docker的作用之一:隔离进程——Docker容器内的进程无法看到宿主机以及其他Docker容器内的进程,这样可以防止一个进程被入侵了来恶意访问或破坏其他非本Docker容器内的进程。

Docker和传统虚拟机的区别:传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。如下图展示了其区别:

           

 

 

2. Docker三个核心概念

镜像Image:

对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系 统。除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

容器Container:容器是以镜像为基础,再加一层容器存储层,组成多层存储结构去运行的。

镜像( Image )和容器( Container )的关系,就像是面向对象程序设计中的 类 和 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删 除、暂停等。容器实质是个进程。

容器和镜像的区别就在于,所有的镜像都是只读的,而每一个容器其实等于镜像加上一个可读写的层,也就是同一个镜像可以对应多个容器。

仓库Repository:就是一个集中存储、分发镜像的服务,类似于Maven的Repository。(注意与注册服务器Registry的区别,后者指管理仓库Repository的具体服务器。每个服务器上可以有多个仓库,而每个仓库下面有多个镜像。)

3. Docker架构

Docker 采用了 C/S 架构,包括客户端和服务端。客户端和服务端既可以运行在一个机器上,也可通过 socket 或者 RESTful API 来进行通信。

  • Docker 守护进程 (Daemon)作为服务端接受来自客户端的请求,并处理这些请求(创建、运行、分发容器)。Docker 守护进程一般在宿主主机后台运行。
  • Docker 客户端则为用户提供一系列可执行命令,用户用这些命令实现跟 Docker 守护进程交互。

Docker 镜像(Images)

Docker 镜像是用于创建 Docker 容器的模板。

Docker 容器(Container)

容器是独立运行的一个或一组应用。

Docker 客户端(Client)

Docker 客户端通过命令行或者其他工具使用 Docker API (https://docs.docker.com/reference/api/docker_remote_api) 与 Docker 的守护进程通信。

Docker 主机(Host)

一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。

Docker 仓库(Registry)

Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。

Docker Hub(https://hub.docker.com) 提供了庞大的镜像集合供使用。

Docker Machine

Docker Machine是一个简化Docker安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker,比如VirtualBox、 Digital Ocean、Microsoft Azure。

4. 安装Docker

Docker分为社区版CE和企业版EE,前者免费。不同OS及同中OS的不同版本上安装Docker的方法各异,详见 Docker安装。

这里以Ubuntu16.04为例。

1. apt源使用HTTPS以确保软件下载过程中不被篡改,故先安装HTTPS传输及CA证书相关:

sudo apt-get update
sudo apt-get install \
  apt-transport-https \
  ca-certificates \
  curl \
  software-properties-common

2. 为确认所下载软件包的合法性,需添加软件源的GPG密钥: curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -

3. 向/etc/apt/source.list添加Docker软件源:

sudo add-apt-repository \
  "deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu \
  $(lsb_release -cs) \
  stable"

4. 更新apt软件包缓存,安装Docker CE: sudo apt-get update && sudo apt-get install docker-ce

5. 启动Docker CE:

设置docker服务开机启动: sudo systemctl enable docker

启动docker服务: sudo systemctl start docker

6. 测试是否正确安装: sudo docker run hello-world ,该命令首次运行会从Docker仓库下载hello-world镜像,输出如下信息表示运行成功:

 View Code

7. 由于国内网络原因,拉取镜像会很慢,可以设置为国内仓库服务器:在 /etc/docker/daemon.json 添加如下内容(若文件不存在则先建之):

{
  "registry-mirrors": [
    "https://registry.docker-cn.com"
  ]
}

然后重启服务:

sudo systemctl daemon-reload
sudo systemctl restart docker

执行 docker info ,若看到 Registry Mirrors: https://registry.docker-cn.com/ 则说明修改成功。

 

5. 镜像与容器操作

各命令具体用法可以通过 docker 命令 --help 查看。下面稍做总结。

5.0 查找与推送镜像

查找示例: docker search centos ,会从镜像仓库中查找指定镜像。

推送示例: docker push zsm/ubuntu:16.04 ,会推送到镜像服务器。不过需要事先注册镜像服务器账号,且只能传到自己账号的下面,因此需将待传的镜像标签改为账号前缀。

5.1 获取镜像

命令格式: docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签] ,如 $ docker pull ubuntu:16.04 。不写标签的话默认是latest,即最新版。在 Docker 1.13+ 版本中推荐使用 docker image 来管理镜像。

此外,也可以通过 docker import 导入容器,会创建响应的镜像。

具体可参见:获取镜像

5.2 容器创建与容器操作

运行示例: $ docker run -it --rm ubuntu:16.04 bash ,表示在终端交互式操作、容器退出后删除掉,运行的是linux下的bash,若不指定运行的命令则默认运行/bin/bash;可以指定运行其他命令,如: docker run -it ubuntu cat /etc/os-release

另一示例:  docker run --name zsmserver -d -p 80:80 nginx , #从镜像nginx启动名为zsmserver的容器,监听80短口,若镜像不存在则会下载 。

可以通过-d参数让Docker在后台运行(守护态运行)而不是把命令执行结果输出到当前宿主主机下(即这里的后台是相对于宿主主机而言的);但是,容器是否会长久运行,是和 docker run 指定的命令有关,和 -d 参数无关。

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

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

其他容器操作命令:

复制代码
docker run 镜像名 [运行的程序命令及参数]     #从镜像新建容器并启动,若镜像不存在则先下载
docker ps -a                             #查看所有容器,包括正在运行的、已终止的等
docker container ls #查看正在运行的容器
docker [container] start/stop/restart containerid_or_name     #启动/停止/重启 已存在的容器
docker logs containerid_or_name          #获取后台运行的容器的输出
docker exec -it containerid 命令          #重新进入后台运行的容器,也可以通过命令 docker attach containerid 进入,但这种方式下进入再退出时容器会跟着终止,所以推荐用exec方式。

docker export containerid  > saved_container_filename           #将容器到处为tar压缩文件
docker import saved_container_filename_or_url  image_name     #从指定地方导入容器快照文件,按指定文字生成镜像。如 docker import ubuntu.bak test/ubuntu:v1.0

docker [container] rm [-f -v] containerid    #删除指定的容器。-f参数可删除运行中的容器Docker会发SIGKILL信号给容器、-v参数删除容器关联的数据卷
docker container prune                    #删除所有终止状态的容器,也可以 docker rm $(docker ps -aq),括号里的命令功能是获取所有container的id

docker tag src_image_name  new_image_name #为镜像重命名,如docker tag ubuntu:1.0 zsm/ubuntu:1.0

docker network create/connnect/disconnect/inspect/ls/prune/rm #网络管理
复制代码

 注:用户既可以使用 docker load 来导入镜像存储文件到本地镜像库,也可以使用 docker import 来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。此外,从容器快照文件导入时可以重新指定标签等元数据信息。

5.3 查看镜像

列出已下载镜像: docker images 或 docker image ls 。

  • 显示的镜像大小是解压后的,官网Docker Hub上显示的则是压缩了的;
  • 由于镜像是分层存储的,可以继承使用,因此总占用空间并不是各镜像占用大小的和;
  • 该命令列出顶层镜像,如果要列出包括中间层镜像的所有,可以加-a参数。可以看出,这里的ls跟Linux下的ls命令用法类似,可以部分匹配等、还支持强大的过滤器参数,具体可输入help命令查看。如列出redis镜像的镜像ID: docker image ls -q redis

查看镜像、容器、数据卷所占用的空间: docker system df ,结果如下:

5.4 移除虚悬镜像

命令: docker image prune

5.5 删除本地镜像

命令: docker image rm [选项] <镜像1> [<镜像2> ...] 或 docker rmi [选项] <镜像1> [<镜像2> ...] ,这里的镜像标识可以是ID、镜像名、镜像摘要等。

  • 删除镜像时实际上是在要求删除某个标签的镜像,由于一个镜像可对应多个标签,因此若删除指定标签的镜像后仍有其他标签指向该镜像则实际上不会删除该镜像,而只是标记指定标签被删除。
  • 同样地,对于要删除的镜像,若有从该镜像启动的容器存在,则即使容器没在运行,该镜像也不会被删除。

5.6 定制docker镜像

可以通过commit命令(具体参见利用-commit-理解镜像构成),但是不推荐,因为会产生不必要的修改使得镜像臃肿;

通常通过Dockerfile定制镜像。文件Dockerfile的内容示例如下:

复制代码
 1 FROM debian:jessie
 2 RUN buildDeps='gcc libc6-dev make' \
 3 && apt-get update \
 4 && apt-get install -y $buildDeps \
 5 && wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \
 6 && mkdir -p /usr/src/redis \
 7 && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
 8 && make -C /usr/src/redis \
 9 && make -C /usr/src/redis install \
10 && rm -rf /var/lib/apt/lists/* \
11 && rm redis.tar.gz \
12 && rm -r /usr/src/redis \
13 && apt-get purge -y --auto-remove $buildDeps
复制代码

RUN指令用来执行命令行命令:

  • 可以是shell 格式: RUN <命令> ,像直接在命令行输入命令一样,如 RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html ;
  • 也可以是exec 格式: RUN ["可执行文件", "参数1", "参数2"] ,像是函数调用中的格式。

Dockerfile 中每一个指令都会建立一层新存储层, RUN指令也不例外(即每一个RUN指令都对应一个新容器。将保护如下指令的Dockerfile构建运行后会提示找不到txt文件就是因为这个原因,若在中间加上WORKDIR则没问题),并且Docker中有层数的限制。比较好的做法是用一个RUN指令和多个&&将多个命令连接起来。

RUN cd /app
# WORKDIR /app
RUN echo "hello" > world.txt

此外,这组命令的最后添加了清理工作的命令,删除了为了编译构建所需要的 软件,清理了所有下载、展开的文件,并且还清理了 apt 缓存文件。这是很重要的一步,镜像是多层存储,每一层的东西并不会在下一层被删除,会一直跟随着镜像。 因此镜像构建时,一定要确保每一层只添加真正需要添加的东西,任何无关的东西都应该清理掉。

5.7 构建镜像

(具体可参见 镜像构建上下文 )

写了上节所述的Dockerfile后,执行命令生产Docker镜像: docker build [选项] <上下文路径/URL/-> 。假设Dockerfile在./dockertest/下,则命令为: Docker build -t zsmserver ./dockertest 

  • docker build的工作原理:Docker在运行时分为 Docker 引擎(即服务端守护进程)和客户端工具。Docker 引擎提供了一组 REST API,被称为 Docker Remote API,而如 docker 命令这样的客户端工具则是通过这组 API 与 Docker 引擎交互,从而完成各种功能。因此,docker build 命令构建镜像其实并非在本地构建,虽表面上像是在本机执行各种 docker 功能,但实际上一切都是使用的远程调用形式在服务端(Docker 引擎)完成。
  • 关于上下文路径:进行镜像构建时并非所有定制都会通过 RUN 指令完成,经常需将一些本地文件复制进镜像,如通过 COPY 指令、ADD 指令等,这些指令指定的路径参数以给定的上下文路径作为根目录。
  • Docker构建实际上是把当前上下文下的文件打包上传到服务端,在服务端进行构建,服务端以上传上来的该文件夹为上下文(即根目录)。
  • 一般将Dockerfile置于空目录或项目根目录,若不希望目录下的一些东西构建时传给Docker引擎,可以用与Git的.gitignore一样的语法写个.dockerignore文件加以剔除。
  • 构建命令中并没有指定Dockerfile的名字,服务端构建时默认会查找名字为“Dockerfile”的文件进行构建,也可以通过-f参数指定Dockerfile文件。如: docker build -t zsmnginx -f MyDockerFile2 .

其他构建方式(详见其他Docker Build方法):

  • 直接用 Git repo 进行构建,要求repo内有Dockerfile
  • 用给定的 tar 压缩包构建,要求压缩包内有Dockerfile
  • 从标准输入中读取 Dockerfile 进行构建
  • 从标准输入中读取上下文压缩包进行构建等

6. Dockerfile指令

(详见Dockerfile指令详解)

在一个Dockerfile中,CMD、ENTRYPOINT、HEALTHCHECK等只可出现一次,若出现多次则只有最后一次生效。

6.1 COPY

格式: COPY <源路径>... <目标路径> 或 COPY ["<源路径1>",... "<目标路径>"] 。如: COPY package.json zh* /usr/src/app/

作用:从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置,复制时源文件的各种元数据都会保留。

6.2 ADD

与COPY类似,只不过源文件可以为URL或压缩包,会自动下载或解压。推荐优先使用COPY。

6.3 CMD

作用:指定容器启动时的默认执行程序。上面示例 docker run -it ubuntu cat /etc/os-release 指定启动时显示系统信息,该默认操作可通过Dockerfile里的CMD指令指定(注:若在启动容器时指定默认执行程序,则会覆盖Dockerfile里CMD指定的)

格式: shell 格式:CMD <命令> 或 exec 格式:CMD ["可执行文件", "参数1", "参数2"...] 。如: CMD cat /etc/os-release ,第一种格式实际上会被包装为 sh -c 的参数 的形式执行,即: CMD [ "sh", "-c", "cat /etc/os-release" ] 。

Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样, 用 upstart/systemd 去启动后台服务,容器内没有后台服务的概念。如 CMD service nginx start 并不会使得容器一直在运行,其实际上会被理解为 CMD [ "sh", "-c", "service nginx start"] ,此时主进程实际上是 sh。则当 service nginx start 命令结束后,sh 也就结束了,sh 作为主进程退出了,自然就会令容器退出。正确做法是直接以前台形式执行nginx: CMD ["nginx", "-g", "daemon off;"]  

6.4 ENTRYPOINT

目的和 CMD 一样,都是在指定容器启动时执行的默认程序及参数,命令格式也一样。不同的是ENTRYPOINT功能更强大,使用ENTRYPOINT指定的默认程序,可以接收在启动容器时给定的参数,从而使容器像个可执行程序一样。

应用场景1:让镜像如一个命令般可执行。”An ENTRYPOINT allows you to configure a container that will run as an executable.“

示例如下,功能为显示当前的公网IP:

复制代码
FROM ubuntu:16.04
RUN apt-get update \
    && apt-get install -y curl \
    && rm -rf /var/lib/apt/lists/*

#CMD [ "curl", "-s", "http://ip.cn" ]
ENTRYPOINT [ "curl", "-s", "http://ip.cn" ]
复制代码

经构建 docker build -t myip . 后,若Dockerfile中使用CMD则只能 docker run myip 运行,无法为curl指定其他参数;若用ENTRYPOINT则可以 docker run myip -i 为curl进一步指定参数(-i表示curl结果输出响应头)。

从上面可见CMD和ENTRYPOINT的区别:后者在运行容器时指定的参数(即-i)会拼接到ENTRYPOINT指定的命令上(变成curl -s http://ip.cn -i);前者则不会拼接而是替换,即把 -i 当成默认命令替换掉 curl -s http//ip.cn 进行执行,从而报错。

另一示例: ENTRYPOINT ["/bin/echo"] ,假设build成镜像echoimage,则可以执行 docker run -it imageecho “this is a test” 就会输出字符串,使得镜像像个echo可执行程序。

应用场景2:应用运行前的准备工作。

借助ENTRYPOINT指定一个脚本文件作为默认程序,完成系统配置、初始化等预处理工作。由于启动docker时指定的参数会拼接到ENTRYPOINT指定的默认程序后,因此参数被当成脚本的参数,脚本里可以根据这些参数作一些处理工作。用CMD则无法达到此功能。

6.5 ENV

设置环境变量,格式为: ENV <key> <value>  或 ENV <key1>=<value1> <key2>=<value2>... ,Docker里后面的指令如RUN以及运行时的应用都可以用此定义的变量,引用方式示例:$filename。 

6.6 ARG

与ENV类似,定义环境变量及默认值。不同的是定义的环境变量在容器运行时不存在;此外,该默认值可在构建命令 docker build 中用 --build-arg <参数名>=<值> 来覆盖。

6.7 VOLUMN

定义匿名卷及其挂载位置,格式为: VOLUME ["<路径1>", "<路径2>"...]  或 VOLUME <路径> ,如 VOLUMN /data ,容器运行时会自动将匿名卷挂载到指定目录。可在容器运行时指定数据卷的位置,覆盖匿名卷设置,如 docker run -d -v mydata:/data echo 将本机的命名卷mydata挂载到容器内的目录 /data 下。

注:

容器运行时应尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中。定义匿名卷后,Docker容器启动时会将指定的路径挂载为匿名卷,这样向该路径写入的数据不会容器存储层,从而保证容器存储层无状态化。

对于 匿名卷 和 非绝对路径的 命名卷,默认都存于本机的 /var/lib/docker/volumes/ 下。

更多相关见下文的 数据卷操作 一节。

6.8 EXPOSE

格式: EXPOSE <端口1> [<端口2>...] 。作用:声明容器运行时可以使用的端口。这只是声明容器打算使用的端口,在运行时并不会因为这个声明应用就会开启指定的端口,容器启动时通过 -p <宿主端口>:<容器端口> 可启用对应端口。

6.9 RUN

见5.6节

6.10 WORKDIR

格式: WORKDIR <工作目录路径> 。作用:指定工作目录(或称为当前目录),以后各层的当前目录就被改为指定的目录,若该目录不存在,WORKDIR 会建立该目录。

6.11 USER

格式: USER <用户名> 。作用:与WORKDIR类似,切换为指定的用户,改变之后层执行 RUN, CMD 以及 ENTRYPOINT 这类命令的身份。用户需要事先存在。 

6.12 HEALTHCHECK

作用:周期性运行给定的命令以判断容器主程序是否正常运行。详见 healthcheck-健康检查。格式如下:

 HEALTHCHECK [选项] CMD <命令> :设置检查容器健康状况的命令

 HEALTHCHECK NONE :如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

6.13 ONBUILD

格式: ONBUILD <其它Dockerfile指令> 。作用:用来设定触发器,在当前镜像build时不会执行ONBUILD指定的指令,只有在当前镜像的直接子镜像(即不包括孙镜像)build时才会执行ONBUILD指定的指令。

ONBUILD指令相当于创建一个模板镜像,后续可根据该模板镜像创建不同的特定子镜像,需要在子镜像构建过程中执行的一些通用操作就可以在模板镜像对应的Dockerfile文件中用ONBUILD指令指定,从而减少dockerfile文件的重复内容编写。

示例:

Dockerfile1: 

FROM ubuntu
ONBUILD RUN mkdir mydir

构建为onbuild_image1: docker build -t onbuild_image -f Dockerfile1 . ,此时不会执行ONBUILD指定的指令。

Dockerfile2:

FROM onbuild_image1
CMD echo

构建为onbuild_image2: docker build -t onbuild_image2 -f Dockerfile2 . ,此时会执行ONBUILD指定的指令。如下:

 

分别查看是否有mydir目录: docker run --rm onbuild_image2 ls |grep mydir ,可以得到onbuild_image2有mydir目录而onbuild_image1没有。

6.14 多阶段构建

作用:从Docker 17.05.0-ce版本起,官方提供了简便的多阶段构建(multi-stage build) 方案,允许在同一Dockerfile中书写多阶段构建指令。

示例:(关键在于AS关键字和 --from 选项)

 View Code

在多阶段构建的支持下,可以在build时加上  --target 阶段名 选项来只构建某阶段的镜像,如: docker build --target build-env -t go/helloworld:v1 .

此外,借助多阶段构建,可以将多个项目的二进制文件集成到一个镜像里,伪码示例如下:

 View Code

7. 私有仓库

有时候公共仓库不方便,可以搭建私有仓库供私人或团队使用。构建私有镜像仓库可以借助官方工具docker-registry。详见 私有仓库 。

8. 数据卷与挂载

数据卷的作用在于把宿主机上的指定目录挂载到容器内的某个位置(目录)上,即把宿主机的指定目录共享给容器,因此容器内对该目录的操作会反应到宿主机,从而操作永久有效,即使容器被删除了。

在Docker中管理数据的方式有两种:挂载数据卷(Volumes)和挂载主机目录(Bind mounts)。前者本质上就是后者,因为创建数据卷就是在本机上创建一个目录(默认在本机的 /var/lib/docker/volumes/ 下创建目录)并此后将该目录关联到容器内的指定目录。这两种方式都使得可以在主机和容器间共享文件夹或文件。

数据卷:

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

数据卷绕过 UFS,可以提供很多有用的特性:

  • 数据卷可以在容器之间共享和重用
  • 对数据卷的修改会立马生效
  • 对数据卷的更新,不会影响镜像
  • 数据卷默认会一直存在,即使容器被删除

数据卷操作:

docker volumn create   vol_name  #创建数据卷,名字中的字符只能是[a-zA-Z0-9_.-]
docker volumn   ls  #查看所有数据卷
docker volumn inspect   vol_name  #查看指定数据卷
docker volumn rm   vol_name  #删除指定数据卷
docker volumn   prune  #删除无主数据卷

数据卷 是被设计用来持久化数据的,其生命周期独立于容器,Docker不会在容器被删除后自动删除数据卷,也不存在垃圾回收这样的机制来处理没有任何容器引用的数据卷。若需要在删除容器的同时移除数据卷,可在删除容器时加 -v 参数。

挂载操作:将本机上的目录或创建的数据卷挂载到容器内的指定路径上,两种:一种是用 --mount 参数、另一种是用-v(或--volumn)参数,大同小异。数据卷可以不用事先创建,指定挂载时若数据卷不存在则会创建之。

法1: -v vol_name_or_absolute_path:target_dir ,对于挂载数据卷或挂载本机目录命令一样,如 -v my-vol:/webapp 或 -v /home/zsm/data:/webapp ,卷或源目录不存在时会创建。

法2: --mount [type=bind] source=vol_name_orabsolute_path,target=target_dir [,readonly] 。卷不存在时会创建、源目录不存在时会报错。当挂载本机目录时需要 type=bind 选项,当启用readonly时在容器内的挂载目录内只有读权限。示例:

docker run -d -p 80:80 \
    --name web \
    # -v my-vol:/wepapp \
    --mount source=my-vol,target=/webapp \
    #--mount type=bind source=/home/zsm/data,target=/webapp,readonly\
    training/webapp  python app.py

通过命令 docker inspect web 查看容器信息,数据卷信息在“Mounts”key下,可见my-vol被创建在了 /var/lib/docker/volumns/ 下:

复制代码
"Mounts": [
            {
                "Type": "volume",
                "Name": "my-vol",
                "Source": "/var/lib/docker/volumes/my-vol/_data",
                "Destination": "/webapp",
                "Driver": "local",
                "Mode": "z",
                "RW": true,
                "Propagation": ""
            }
        ]
复制代码

也可以将主机的一个文件挂载到容器中,示例如下(下例使得主机可以记录在容器中输入过的命令):

docker run --rm -it \
   # -v $HOME/.bash_history:/root/.bash_history \
   --mount type=bind,source=$HOME/.bash_history,target=/root/.bash_history \
   ubuntu:17.10 \
   bash 

9. 进阶_网络设置

见 使用网络、高级网络设置、Docker网络实现

10. 进阶_底层实现

(见 底层实现)

Docker 底层的核心技术包括 Linux 上的命名空间(Namespaces)、控制组(Control groups)、联合文件系统(Union file systems)和容器格式(Container format)。

命名空间:命名空间是 Linux 内核一个强大的特性。每个容器都有自己单独的命名空间,运行在其中的应用都像是在独立的操作系统中运行一样。命名空间保证了容器之间彼此互不影响。包括pid命名空间、net命名空间、ipc命名空间、mnt命名空间、uts命名空间、user命名空间等。

控制组:是 Linux 内核的一个特性,主要用来对容器的内存、CPU、磁盘IO等共享资源进行隔离、限制、审计等。只有能控制分配到容器的资源,才能避免当多个容器同时运行时的对系统资源的竞争。

联合文件系统:是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。联合文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像;另外,不同 Docker 容器就可以共享一些基础的文件系统层,同时再加上自己独有的改动层,大大提高了存储的效率。Docker 目前支持的联合文件系统(存储驱动)包括 OverlayFS, AUFS, Btrfs, VFS, ZFS 和 Device Mapper,overlay2 是目前 Docker 默认的存储驱动,以前则是 aufs。

容器格式:最初,Docker 采用了 LXC 中的容器格式。从 0.7 版本以后开始去除 LXC,转而使用自行开发的 libcontainer,从 1.11 开始,则进一步演进为使用 runC 和 containerd。

11. 参考资料

《Docker-从入门到实践》

 


(责任编辑:IT)
------分隔线----------------------------
栏目列表
推荐内容