Docker学习教程笔记整合(完整)
本文主要是整理了DockerOne组织翻译的Flux7的Docker入门教程,通过markdown记录,方便离线学习。原文地址,http://dockone.io/article/101.
文中一些链接可能会跳转国外的网站,如果没有插件或开VPN的朋友,可以尝试修改一下Hosts文件,如何修改Hosts文件。或者使用XXNet插件,如何使用XXnet
介绍
Docker是一个新的容器化的技术,它轻巧,且易移植,号称“build once, configure once and run anywhere(译者注:这个就不翻译了,翻译出来味道就没了)”。本文是Flux7的Docker系列教程的第一部分。请和这份教程一起学习和理解Docker有什么优势以及如何更好地使用它。
让我们一起来学习Docker。
本文主要涉及Docker的基础知识:Docker的特征、理念以及如何安装使用Docker。
Docker特征
Docker有不少有趣的功能,通过本教程相信你会更好地理解它们。
Docker的特性主要包括以下几点:
- 速度飞快以及优雅的隔离框架
- 物美价廉
- CPU/内存的低消耗
- 快速开/关机
- 跨云计算基础构架
Docker 组件与元素
Docker有三个组件和三个基本元素,读者可以快速浏览下面这个视频来了解这些组建和元素,以及它们的关系。
三个组件分别是:
* Docker Client是用户界面,它支持用户与Docker Daemon之间通信。
* Docker Daemon运行于主机上,处理服务请求。
* Docker Index是中央registry,支持拥有公有与私有访问权限的Docker容器镜像的备份。
三个基本要素分别是:
- Docker Containers负责应用程序的运行,包括操作系统、用户添加的文件以及元数据。
- Docker Images是一个只读模板,用来运行Docker容器。
- DockerFile是文件指令集,用来说明如何自动创建Docker镜像。
在讨论Docker组件和基本要素如何交互之前,让我们来谈谈Docker的支柱。Docker使用以下操作系统的功能来提高容器技术效率:
- Namespaces 充当隔离的第一级。确保一个容器中运行一个进程而且不能看到或影响容器外的其它进程。
- Control Groups是LXC的重要组成部分,具有资源核算与限制的关键功能。
- UnionFS(文件系统)作为容器的构建块。为了支持Docker的轻量级以及速度快的特性,它创建了用户层。
如何把它们放在一起
运行任何应用程序,都需要有两个基本步骤:
1.构建一个镜像。
2.运行容器。
这些步骤都是从Docker Client的命令开始的。Docker Client使用的是Docker二进制文件。在基础层面上,Docker Client会告诉Docker Daemon需要创建的镜像以及需要在容器内运行的命令。当Daemon接收到创建镜像的信号后,会进行如下操作:
第1步:构建镜像
如前所述,Docker Image是一个构建容器的只读模板,它包含了容器启动所需的所有信息,包括运行程序和配置数据。
每个镜像都源于一个基本的镜像,然后根据Dockerfile中的指令创建模板。对于每个指令,在镜像上创建一个新的层面。
一旦镜像创建完成,就可以将它们推送到中央registry:Docker Index,以供他人使用。然而,Docker Index为镜像提供了两个级别的访问权限:公有访问和私有访问。你可以将镜像存储在私有仓库,Docker官网有私有仓库的套餐可以供你选择。总之,公有仓库是可搜索和可重复使用的,而私有仓库只能给那些拥有访问权限的成员使用。Docker Client可用于Docker Index内的镜像搜索。
第2步:运行容器
运行容器源于我们在第一步中创建的镜像。当容器被启动后,一个读写层会被添加到镜像的顶层。当分配到合适的网络和IP地址后,需要的应用程序就可以在容器中运行了。
如果你还是不太理解,先别急,在接下来的内容中我们将会和你分享很多的实战案例。
目前为止,我们已经介绍了Docker的基本概念,接下来,让我们一起安装Docker.
命令
我们将学习15个Docker命令,并通过实践来学习它是如何工作的。
首先,让我们通过下面的命令来检查Docker的安装是否正确:
*docker info
如果没有找到这条命令,则表示Docker安装错误。如果安装正确,则会输出类似下面的内容:
到这一步Docker里还没有镜像或是容器。所以,让我们通过使用命令预先构建的镜像来创建来一个:
- sudo docker pull busybox
BusyBox是一个最小的Linux系统,它提供了该系统的主要功能,不包含一些与GNU相关的功能和选项。
下一步我们将运行一个“Hello World”的例子,我们暂且叫它“Hello Docker”吧。
- docker run busybox /bin/echo Hello Docker
现在,让我们以后台进程的方式运行hello docker
- sample_job=$(docker run -d busybox /bin/sh -c “while true; do echo Docker; sleep 1; done
sample_job命令会隔一秒打印一次Docker,使用docker logs可以查看输出的结果。如果没有给这个job起名字,那这个job就会被分配一个id,以后使用命令例如docker logs查看日志就会变得比较麻烦。
运行docker logs命令来查看job的当前状态:
- docker logs $sample_job
所有Docker命令可以用以下命令查看:
- docker help
名为sample_job的容器,可以使用以下命令来停止:
- docker stop $sample_job
使用以下命令可以重新启动该容器:
- docker restart $sample_job
如果要完全移除容器,需要先将该容器停止,然后才能移除。像这样:
- docker stop $sample_job
- docker rm $sample_job
将容器的状态保存为镜像,使用以下命令:
- docker commit $sample_job job1
注意,镜像名称只能取字符[a-z]和数字[0-9]。
现在,你就可以使用以下命令查看所有镜像的列表:
- docker images
在我们之前的Docker教程中,我们学习过镜像是存储在Docker registry。在registry中的镜像可以使用以下命令查找到:
- docker search (image-name)
查看镜像的历史版本可以执行以下命令:
- docker history (image_name)
最后,使用以下命令将镜像推送到registry:
- docker push (image_name)
非常重要的一点是,你必须要知道存储库不是根存储库,它应该使用此格式(user)/(repo_name)。
这都是一些非常基本的Docker命令。在我们Docker教程系列的第六章,我们将讨论如何使用Docker运行Python的Web应用程序,以及一些进阶的Docker命令。
Dockerfile
上文,我们介绍了15个Docker命令,你应该对Docker有个大致的了解了。那15个命令在手动创建镜像时会用到,它们涵盖了镜像的创建、提交、搜索、pull和push的功能。
现在问题来了,既然Docker能自动创建镜像,那为什么要选择耗时而又乏味的方式来创建镜像呢?
Docker为我们提供了Dockerfile来解决自动化的问题。在这篇文章中,我们将讨论什么是Dockerfile,它能够做到的事情以及Dockerfile的一些基本语法。
易于自动化的命令
Dockerfile包含创建镜像所需要的全部指令。基于在Dockerfile中的指令,我们可以使用Docker build命令来创建镜像。通过减少镜像和容器的创建过程来简化部署。
Dockerfile支持支持的语法命令如下:
- INSTRUCTION argument
指令不区分大小写。但是,命名约定为全部大写。
所有Dockerfile都必须以FROM命令开始。 FROM命令会指定镜像基于哪个基础镜像创建,接下来的命令也会基于这个基础镜像(译者注:CentOS和Ubuntu有些命令可是不一样的)。FROM命令可以多次使用,表示会创建多个镜像。具体语法如下:
- FROM
例如:
- FROM ubuntu.
上面的指定告诉我们,新的镜像将基于Ubuntu的镜像来构建
继FROM命令,DockefFile还提供了一些其它的命令以实现自动化。在文本文件或Dockerfile文件中这些命令的顺序就是它们被执行的顺序。
让我们了解一下这些有趣的Dockerfile命令吧。
- MAINTAINER:设置该镜像的作者。语法如下:
- MAINTAINER
- RUN:在shell或者exec的环境下执行的命令。RUN指令会在新创建的镜像上添加新的层面,接下来提交的结果用在Dockerfile的下一条指令中。语法如下:
- RUN 《command》
- ADD:复制文件指令,它有两个参数source和destination。destination是容器内的路径。source可以是URL或者是启动配置上下文中的一个文件。语法如下:
- ADD 《src》 《destination》
- CMD:提供了容器默认的执行命令。 Dockerfile只允许使用一次CMD指令。 使用多个CMD会抵消之前所有的指令,只有最后一个指令生效。 CMD有三种形式:
- CMD [“executable”,”param1”,”param2”]
- CMD [“param1”,”param2”]
- CMD command param1 param2
- EXPOSE:指定容器在运行时监听的端口。语法如下:
- EXPOSE ;
- ENTRYPOINT:配置给容器一个可执行的命令,这意味着在每次使用镜像创建容器时一个特定的应用程序可以被设置为默认程序。同时也意味着该镜像每次被调用时仅能运行指定的应用。类似于CMD,Docker只允许一个ENTRYPOINT,多个ENTRYPOINT会抵消之前所有的指令,只执行最后的ENTRYPOINT指令。语法如下:
- ENTRYPOINT [“executable”, “param1”,”param2”]
- ENTRYPOINT command param1 param2
- WORKDIR:指定RUN、CMD与ENTRYPOINT命令的工作目录。语法如下:
- WORKDIR /path/to/workdir
- ENV:设置环境变量。它们使用键值对,增加运行程序的灵活性。语法如下:
- ENV
- USER:镜像正在运行时设置一个UID。语法如下:
- USER
- VOLUME:授权访问从容器内到主机上的目录。语法如下:
- VOLUME [“/data”]
Dockerfile最佳实践
与使用的其他任何应用程序一样,总会有可以遵循的最佳实践。你可以阅读更多有关Dockerfile的最佳实践。
以下是我们列出的基本的Dockerfile最佳实践:
* 保持常见的指令像MAINTAINER以及从上至下更新Dockerfile命令;
* 当构建镜像时使用可理解的标签,以便更好地管理镜像;
* 避免在Dockerfile中映射公有端口;
* CMD与ENTRYPOINT命令请使用数组语法。
Docker Registry
上文,我们讨论了Dockerfile的重要性并提供了一系列Dockerfile的命令,使镜像的自动构建更加容易。在这篇文章中,我们将介绍Docker的一个重要组件:Docker Registry。它是所有仓库(包括共有和私有)以及工作流的中央Registry。在深入Docker Registry之前,让我们先去看看一些常见的术语和与仓库相关的概念。
1.Repositories(仓库)可以被标记为喜欢或者像书签一样标记起来。
2.用户可以在仓库下评论。
3.私有仓库和共有仓库类似,不同之处在于前者不会在搜索结果中显示,也没有访问它的权限。只有用户设置为合作者才能访问私有仓库。
4.成功推送之后配置webhooks。
Docker Registry有三个角色,分别是index、registry和registry client。
角色 1 – Index
index 负责并维护有关用户帐户、镜像的校验以及公共命名空间的信息。它使用以下组件维护这些信息:
Web UI
元数据存储
认证服务
符号化
这也分解了较长的URL,以方便使用和验证用户存储库。
角色 2 –Registry
registry是镜像和图表的仓库。然而,它没有一个本地数据库,也不提供用户的身份认证,由S3、云文件和本地文件系统提供数据库支持。此外,通过Index Auth service的Token方式进行身份认证。Registries可以有不同的类型。现在让我们来分析其中的几种类型:
Sponsor Registry:第三方的registry,供客户和Docker社区使用。
Mirror Registry:第三方的registry,只让客户使用。
Vendor Registry:由发布Docker镜像的供应商提供的registry。
Private Registry:通过设有防火墙和额外的安全层的私有实体提供的registry。
角色 3 –Registry Client
Docker充当registry客户端来负责维护推送和拉取的任务,以及客户端的授权。
Docker Registry工作流程详解
现在,让我们讨论五种情景模式,以便更好地理解Docker Registry。
情景A:用户要获取并下载镜像。所涉及的步骤如下:
1.用户发送请求到index来下载镜像。
2.index 发出响应,返回三个相关部分信息:
- 该镜像所处的registry
- 该镜像包括所有层的校验
- 以授权为目的的Token > 注意:当请求header里有X-Docker-Token时才会返回Token。而私人仓库需要基本的身份验证,对于公有仓库这一点不是强制性的。
3.用户通过响应后返回的Token和registry沟通,registry全权负责镜像,它用来存储基本的镜像和继承的层。
4.registry现在要与index证实该token是被授权的。
5.index会发送“true” 或者 “false”给registry,由此判定是否允许用户下载所需要的镜像。
情景B:用户想要将镜像推送到registry中。其中涉及的步骤如下:
1.用户发送附带证书的请求到index要求分配库名。
2.在认证成功,命名空间可用之后,库名也被分配。index发出响应返回临时的token。
3.镜像连带token,一起被推送到registry中。
4.registry与index证实token被授权,然后在index验证之后开始读取推送流。
5.该index由Docker校验的镜像更新。
情景C:用户想要从index或registry中删除镜像:
1.index接收来自Docker一个删除库的信号。
2.如果index对库验证成功,它将删除该库,并返回一个临时的token。
3.registry现在接收到带有该token的删除信号。
4.registry与index核实该token,然后删除库以及所有与其相关的信息。
5.Docker现在通知有关删除的index,然后index移除库的所有记录。
情景D:用户希望在没有index的独立模式中使用registry。
使用没有index的registry,这完全由Docker控制,它最适合于在私有网络中存储镜像。registry运行在一个特殊的模式里,此模式限制了registry与Docker index的通信。所有有关安全性和身份验证的信息需要用户自己注意。
情景E:用户想要在有index的独立模式中使用registry。
在这种情况下,一个自定义的index会被创建在私有网络里来存储和访问镜像的问题。然而,通知Docker有关定制的index是耗时的。 Docker提供一个有趣的概念chaining registries,从而,实现负载均衡和为具体请求而指定的registry分配。在接下来的Docker教程系列中,我们将讨论如何在上述每个情景中使用Docker Registry API ,以及深入了解Docker Security。
Docker安全
我们必须高度重视开源软件的安全问题,当开发者在使用Docker时,从本地构建应用程序到生产环境部署是没有任何差异的(译者注:作者的言外之意是更应该重视Docker的安全问题)。当Docker被越来越多的平台使用的时候,我们需要严格保证Docker作为一个项目或者平台的安全性。
因此,我们决定在Docker系列教程的第五篇来讨论Docker安全性的相关问题以及为什么会它们影响到Docker的整体安全性。由于Docker是LXC的延伸,它也很容易使用LXC的安全特性。
在本系列的第一篇文章中,我们知道docker run命令可以用来运行容器。那运行这个命令后,Docker做了哪些具体的工作呢?具体如下:
1.docker run命令初始化。
2.Docker 运行 lxc-start 来执行run命令。
3.lxc-start 在容器中创建了一组namespace和Control Groups。
对于那些不知道namespace和control groups的概念的读者,我在这里先给他们解释一下:namespace是隔离的第一级,容器是相互隔离的,一个容器是看不到其它容器内部运行的进程情况(译者注:namespace系列教程可以阅读DockerOne上的系列教程)。每个容器都分配了单独的网络栈,因此一个容器不可能访问另一容器的sockets。为了支持容器之间的IP通信,您必须指定容器的公网IP端口。
Control Groups是非常重要的组件,具有以下功能:
1.负责资源核算和限制。
2.提供CPU、内存、I/O和网络相关的指标。
3.避免某种DoS攻击。
4.支持多租户平台。
Docker Daemon的攻击面
Docker Daemon以root权限运行,这意味着有一些问题需要格外小心。
下面介绍一些需要注意的地方:
1 当Docker允许与访客容器目录共享而不限制其访问权限时,Docker Daemon的控制权应该只给授权用户。
2 REST API支持Unix sockets,从而防止了cross-site-scripting攻击。
3 REST API的HTTP接口应该在可信网络或者VPN下使用。
4 在服务器上单独运行Docker时,需要与其它服务隔离。
一些关键的Docker安全特性包括:
1 容器以非特权用户运行。
2 Apparmor、SELinux、GRSEC解决方案,可用于额外的安全层。
3 可以使用其它容器系统的安全功能。
Docker.io API
用于管理与授权和安全相关的几个进程,Docker提供REST API。以下表格列出了关于此API用于维护相关安全功能的一些命令。
另外的15个Docker命令
在之前的文章中,我们介绍了15个Docker命令,并分享了它们的实践经验。在这篇文章中,我们将学习另外的15个Docker命令。它们分别是:
daemon:
Docker daemon是一个用于管理容器的后台进程。一般情况下,守护进程是一个长期运行的用来处理请求的进程服务。-d参数用于运行后台进程。
build:
如之前所讨论的,可以使用Dockerfile来构建镜像。简单的构建命令如下:
docker build [options] PATH | URL
还有一些Docker提供的额外选项,如:
–rm=true表示构建成功后,移除所有中间容器
–no-cache=false表示在构建过程中不使用缓存
下面是一张使用Docker build命令的截图。
attach:
Docker允许使用attach命令与运行中的容器交互,并且可以随时观察容器內进程的运行状况。退出容器可以通过两种方式来完成:
1 Ctrl+C 直接退出
2 Ctrl-\ 退出并显示堆栈信息(stack trace)
attach命令的语法是:
- docker attach container
下面是一张显示执行attach命令的截图。
diff:
Docker提供了一个非常强大的命令diff,它可以列出容器内发生变化的文件和目录。这些变化包括添加(A-add)、删除(D-delete)、修改(C-change)。该命令便于Debug,并支持快速的共享环境。
语法是:
- docker diff container
截图显示diff的执行。
vents:
打印指定时间内的容器的实时系统事件。
import:
Docker可以导入远程文件、本地文件和目录。使用HTTP的URL从远程位置导入,而本地文件或目录的导入需要使用-参数。从远程位置导入的语法是:
- docker import http://example.com/example.tar
截图表示本地文件:
export:
类似于import,export命令用于将容器的系统文件打包成tar文件。
下图描述了其执行过程:
cp:
这个命令是从容器内复制文件到指定的路径上。语法如下:
- docker cp container:path hostpath.
截图展示了cp命令的执行。
login:
此命令用来登录到Docker registry服务器,语法如下:
- docker login [options] [server]
如要登录自己主机的registry请使用:
docker login localhost:8080
inspect:
Docker inspect命令可以收集有关容器和镜像的底层信息。这些信息包括:
容器实例的IP地址
端口绑定列表
特定端口映射的搜索
收集配置的详细信息
该命令的语法是:
- docker inspect container/image
kill:
发送SIGKILL信号来停止容器的主进程。语法是:
- docker kill [options] container
rmi:
该命令可以移除一个或者多个镜像,语法如下:
- docker rmi image
镜像可以有多个标签链接到它。在删除镜像时,你应该确保删除所有相关的标签以避免错误。下图显示了该命令的示例。
wait:
阻塞对指定容器的其它调用方法,直到容器停止后退出阻塞。
load:
该命令从tar文件中载入镜像或仓库到STDIN。
截图显示载入app_box.tar到STDIN:
save:
类似于load,该命令保存镜像为tar文件并发送到STDOUT。语法如下:
- docker save image
简单截图示例如下: