Docker实战

一、欢迎来到Docker世界

A.什么是Docker

1.容器:防止对受保护资源的访问,隔离后有资源,除非明确允许

2.容器不是虚拟化:运行在Docker容器中的程序接口和主机的Linux内核直接打交道,可以帮助使用已经内置到操作系统中的容器技术

3.在隔离的容器中运行软件:使用Linux命名空间和cgroups

4.分发容器:通过Docker镜像(是一个容器中运行程序的所有文件的捆绑快照)

B.Docker解决了什么

1.组织有序:Docker保留了通过容器和镜像进行隔离的所有一切

2.提高可移植性:

  • 将软件以前无法使用的地方彻底解锁
  • 可在任何系统上运行相同的软件
  • 软件维护人员可以集中精力在单一平台和一套依赖关系中编写他们的软件

3.保护你的机器:容器限制了一个程序对其他程序带来的影响范围、可访问的数据和系统资源的影响范围

C.为什么Docker如此重要

1.Docker提供了所谓的抽象:允许你以简化的方式处理复杂的工作,在使用Docker的前提下,不用再专注于与安装应用程序相关的复杂性和细节 ,只考虑我们想安装什么样的软件

2.有一个重要的推广使用容器和Docker的软件社区

3.为PC端所做的像应用商店 为移动设备所做的一样

4.终于开始看到通过操作系统实现的更好、更先进的隔离功能

D.何时何处使用Docker

1.只能运行Linux操作系统上的应用程序,限定在Linux服务器或桌面上运行的软件

2.每天的日常任务使用Docker有助于保持计算机的清洁

3.容器不能改善程序的安全,特别当不得不用最高权限访问计算机的时候

二、在容器中运行软件

A.从Docker命令行工具获得帮助

1.docker help

2.docker help cp

B.控制容器:建立一个网站的监控器

1.守护进程:意味着它们将在后台运行,而不连接到任何输入或输出流,非常适合那些在后台静默运行的程序,这些程序被称为守护程序,使用—detach或-d

2.交互进程:—interactive或-I,—tty或-t

C.已解决的问题和PID命名空间

1.每一个运行的程序或进程,在Linux机器都有一个唯一编号,叫作进程标识符(PID),一个PID命名空间是一组识别进程的数字。Linux提供了工具可以创建多个PID命名空间,每个命名空间拥有一套完整的PID

D.消除元数据冲突:构建一个网站农场

1.docker create —cidfile /xxx/cid,创建但不运行,—cidfile保存cid到指定目录文件

2.容器需要以其依赖关系链相反的顺序来启动,—link,循环依赖是不可能使用Docker容器来构建的

E.构建与环境无关的系统

1.Docker有三个特定功能建立与环境无关的系统:

  • 只读文件系统:容器不能更改它所包含的文件,—read-only
  • 环境变量注入:环境变量来传达相关信息,包括容器的守护选项、容器的主机名,以及他在容器中运行程序的实用信息,—env或-e
  • 存储卷

*运行run -d --name wp3 --link wpdb:mysql -p 80 -v /run/lock/apache2/ -v /run/apache2 -v /tmp/ --read-only wordpress:4,书中少了-v /tmp/

F.建立持久化的容器

1.Docker容器四种状态:运行、已暂停、重新启动、已退出

2.自动重启容器:—restart

3.使用init和supervisor进程维持容器的运行状态:init、systemd、runit、upstart、supervisord

G.清理

1.列出所有容器:docker ps -a

2.删除:docker rm xxx

3.快速全部消除:docker rm -vf $(docker ps -a -q)

三、软件安装的简化

A.选择所需的软件

1.仓库是一个有名字的镜像桶,名字类似于URL

2.标签是唯一指定镜像的重要途径,也是一种创建有用别名的便利方法

B.查找和安装软件

1.docker search xxx

2.注册服务器,使用户可不用考虑镜像存储和运输的问题

3.docker load -i,加载镜像文件,docker save,把镜像保存到文件

4.docker rmi,删除镜像文件

C.安装文件和隔离

1.镜像层,一个镜像层至少和一个其他的镜像相关联

2.镜像维护着父/子关系。在这些依赖关系中,从父层构建形成新的一层。容器中的文件是镜像所创建容器的所有层合集。镜像可以与任何其他镜像有依赖关系,包括为不同的所有者提供不同仓库的镜像

3.Union文件系统:容器中正在运行的程序对镜像分层一无所知,仿佛该操作不是在容器中或操作镜像上运行的。从容器角度看,它具有由镜像所提供文件的独占副本。其他工具还有MNT命名空间和chroot系统调用。

4.Linux内核提供了MNT系统命名空间,当docker创建一个容器,这个新的容器会有自己的MNT命名空间,以及为镜像创建新的挂载点

5.chroot通过容器上下文来构建镜像的根文件系统。可以防止运行于容器内的任何程序与主机系统的其他部分有所关联

6.分层文件系统及其工具的优点:

  • 公共层仅需安装一次
  • 分层提供了用于依赖管理和隔离的工具
  • 很容易地构建专业的软件,因为你只要在某个基本镜像上做些细微的变化就可以了

7.Union文件系统的不足:

  • 不同的文件系统对于文件属性、大小、名称和字符都有不同的规则
  • Union文件系统使用一种称为写时复制的模式,这使得内存映射文件(mmap()的系统调用)的实现比较困难

8.使用info命令来决定安装哪些文件系统

四、持久化存储和卷间状态共享

A.存储卷的简介

1.存储卷是容器目录树上的挂载点,其中一部分主机目录树已经被挂载了

2.从语义上来说,存储卷是一个数据分割和共享的工具,有一个与容器无关的范围或生命周期

3.镜像适合打包和分发相对静态的文件,如程序;存储卷则持有动态或专门数据。这种区别使得镜像可重用,数据也可以简单分享

B.存储卷的类型

1.绑定挂载卷

  • 指向主机文件系统上用户指定的位置,在主机提供的文件或目录需要挂载到容器的特定位置时,非常有用
  • 使用-v(—volume)选项和位置映射来创建绑定挂载点,映射以冒号分隔,映射键(冒号前)是主机文件系统上的一个绝对路径,键值(冒号后)是容器中挂载的目标存储位置
  • run -d --name bmweb -v ~/MyProject/docker/4:/usr/local/apache2/htdocs -p 8080:80 httpd
  • 可以添加:ro将挂载卷和存储卷设为只读
  • ~/MyProject/docker/4:/usr/local/apache2/htdocs:ro
  • 两个问题:将可移植容器绑定到特定主机的文件系统;创造了与其他容器发生冲突的机会
  • 绑定挂载卷比较适合需要使用特殊挂载点的工作站或机器,在通用平台或硬件池避免这类绑定

2.Docker管理卷:使用管理卷是一种在文件系统特定位置解耦卷的方法

C.共享存储卷

1.—volumes-from标志,复制任何本卷所引用的源容器到新的容器中,复制卷始终具有相同的挂载点

2.有三种情况下不能使用—volumes-from:

  • 如果你构建的容器需要共享卷挂载到不同的位置,就不能使用
  • 源卷之间彼此冲突,或者有新的卷规格
  • 如果你需要更改卷的写权限,就不能使用

D.管理卷的生命周期

1.管理卷的生命周期独立于任何容器,但截至目前,你只能通过容器来引用它们

2.管理卷是二等实体,你没有办法分享或删除特定的管理卷,因为你没有办法指定一个管理卷,如果你不使用绑定挂载卷,只创建了管理存储卷的话,那么只能通过它们的容器来区分

3.区分存储卷最好的方法是为每个管理卷定义一个容器

4.使用-v运行docker rm命令将试图删除目标容器中引用的任何管理卷,如果删除每一个已引用被处理卷的容器,但没有使用-v标志,就会产生孤立卷,移除孤立卷需要一系列手工操作

E.存储卷的高级容器模式

1.卷容器模式:一个容器,只是提供卷的句柄,不需要运行,因为停止时容器仍能保证存储卷的引用

2.卷容器对于数据句柄的维护非常重要,即使单个容器对数据具有一定的独占访问权限,这些句柄仍使其轻松地备份、恢复和迁移数据

3.当你控制并能够使挂载点的命名惯例标准化,那么存储卷容器将会最有用,这是因为每一个容器从卷容器复制卷并继承了挂载点的定义,具有特定要求的镜像应清楚地传达其文档中的内容或找到一种可编程的方法

4.数据打包的存储卷容器:将容器中的数据打包以此增加其价值,它描述了镜像是如何被用于分发静态资源,比如在由其他镜像构建的容器中使用的配置或代码。数据打包的卷容器将镜像中的静态内容复制到其定义的存储卷,这些容器可用于分发关键架构信息

5.多态工具就是以一致性的方式进行交互,但可能有几个实现,分别做不同的事情,使用存储卷,可以注入不同的行为到容器中,而无需修改其镜像

五、网络访问

A.网络相关背景知识

B.Docker的网络

1.Docker关心两种类型的网络:单主机虚拟网络和多主机虚拟网络。本地虚拟网络用来提供容器的隔离。多主机虚拟网络构建了一个抽象的覆盖网络,在这个网络中,任何容器相对于网络上的其他容器都拥有独立的、可路由的IP地址

2.Docker使用操作系统的底层特性构建了一个特殊的、可定制的虚拟网络拓扑结构,每个容器各自拥有一个本地回环接口和一个分享的以太网接口,其中以太网接口连接着在主机命名空间上的另一个虚拟接口

3.四种网络容器原型:Closed容器、Joined容器、Bridged容器、Open容器

C.Closed容器

1.运行在这种容器中的进程只能够访问本地回环接口,如果进程只需要和本身或者和其他本地进程通信的话,选择这一种是非常合适的

2.在docker run命令后添加—net none作为参数来告诉Docker创建一个Closed容器

D.Bridged容器

1.拥有两个接口,一个私有的本地回环接口,另外一个私有接口通过网桥连接到主机的其他容器

2.默认或使用—net bridge选项

3.使用—hostname选项,可以设置一个新容器的主机名;使用—dns设置DNS服务器ip;—dns-search允许你指定一个DNS查找 域,这个查找域就像host名的一个默认后缀;—add-host,能自定义从主机名到IP地址的映射关系

4.所有的自定义转换关系都保存在容器中的/etc/hosts文件中

5.Bridged容器默认不能够被主机网络访问,被主机的防火墙保护了起来,默认的网络拓扑结构没有提供任何从主机外部接口到容器接口的路由

6.-p或—publish选项,能够在主机网络栈上的端口和容器端口之间创建映射关系;使用-P或—publish-all,会告诉Docker daemon去创建作用于容器所有的端口,将容器的商品都暴露出去;—expose选项,能设置容器想要开放的端口;docker port 命令会输出一个列表,每一行对应一个端口映射

7.默认情况下,容器对本地的其他容器是完全开放的;使用docker -d —icc=false可以选择关闭容器之间的网络连接

8.docker -d —big “ip”可以设置docker创建网桥接口的IP地址,也可以使用docker -d -fixed-cidr “"无类域内路由(CIDR)地址来设置子网的大小;docker -d -mtu 1200来设置设置最大传输单元(MTU);-b或-bridge来使用Linux自定义网桥

E.Joined容器

1.当你想要不同容器上的程序通过本地回环接口进行通信时;当一个容器中的程序将要改变Joined网络栈,而另外一个程序将要使用那个被改变的网络栈时;当你想要监控另外一个容器中某个程序的网络流量时;

F.Open容器

1.—net host命令创建,对主机网络有完全的访问权,没有提供任何隔离

G.跨容器依赖

1.链接——本地服务发现:当新容器被创建时,目标容器必须正在运行,会发生三件事:

  • 描述目标容器的环境变量会被创建
  • 链接的别名和对应的目标容器的IP地址会被添加到DNS覆盖列表中
  • 如果跨容器通讯被禁止了,Docker会添加特定的防火 墙规则来允许被链接 的容器间的通信

2.当跨容器通信(ICC)被允许时,—expose选项为容器端口到主机端口的映射,当ICC被禁止时,—expose选项成了定义防火墙规则 和在网络上显式声明容器接口的一个工具

3.—link 容器名:别名,链接

4.只有正确恰当的配置、强大的网络规则设置,加上服务依赖的声明,才能构造一个深度安全防御的系统

5.链接的本质就是静态的、具有方向性和无传递性的依赖;链接通过检测目的容器的网络信息(IP地址和开放端口),然后将这些信息注入新容器中

六、隔离——限制危险

A.资源分配

1.内存-m或-memory,可用单位有b,k,m和g,内存限制并不是内存保留,而是防止容器使用超出具体大小的内存资源

2.cpu权重,—cup-shares=整数;cup限定指定的CPU,—cpuset-cpus;

3.设备授权,使用—device选项来指定一个设备的集合,这些设备会被挂载进新容器中,选项的值必须 是主机操作系统上的设备文件到新容器中位置的映射

B.共享内存

1.Linux的IPC命名空间分区共享内存单元,比如说命名的共享内存块、信号量和消息队列,默认情况下Docker为每一个容器创建了一个独立的IPC命名空间

2.—ipc选项支持创建的新容器的IPC命名空间和另外一个目标容器是一样的

3.—ipc host,可以和运行在主机上的进程通信,属于开放内存容器

C.理解用户

1.提供了-u或—user选项来设置run-as用户,可以设置用户和用户组,-u nobody:default或-u 10000:20000

2.除非你想要主机的文件能够被容器访问,否则不要将文件以卷的形式挂载到容器上

D.能力——操作系统功能的授权

1.通过—cap-drop选项为容器去除能力,通过—cap-add选项能够增添能力

E.运行特权容器

1.特权容器维持它们自己的文件系统和网络隔离,但却拥有对设备和共享内存的全部访问权,还具备全部的系统能力

2.使用—privileged选项来开启这种模式

F.使用加强工具创建更健壮的容器

1.Docker提供了一个在容器创建或者运行时指定Linux安全模块(LSM)的选项,LSM是Linux采用的一个框架,用作操作系统和安全供应商之间的接口层。AppArmor和SELinux都是LSM的供应商

2.通过—security-opt选项来设置

3.通过—exec-driver=lxc来使用LXC,一旦被配置为LXC可以使用—lxc-conf来设置LXC的配置

G.因地制宜的构建容器

1.应用:确保运行应用的用户具有有限的权限;限制 浏览器的系统能力;限制应用的CPU和内存资源;

七、在镜像中打包软件

A.从容器构建镜像

1.从一个容器构建一个镜像的基本工作流包含三部分:

  • 需要从一个已存在的镜像创建一个容器
  • 修改这个容器的文件系统
  • 一旦改动完成,那么就要将这些改动提交(commit)

2.审查文件的改动:docker diff xxxx

3.docker commit命令从被修改的容器上创建新镜像,最好使用-a为新镜像指定作者信息,使用-m选项能够设置关于提交的信息

4.docker run —entrypoint,指定入口点,一个入口点就是一个程序,它会在容器启动时被执行,如果没有设置,那么默认的命令会被直接执行,如果被设置,那么默认的命令和它的参数就会作为参数传递给入口点

5.当使用docker commit命令,就向镜像提交了一个新的文件层,但不是只有文件系统快照被提交,每一层都包含描述执行上下文(execution context)的元数据

B.深入Docker镜像和层

1.联合文件系统由多个层组成,每当对联合文件系统改动一次,改动会被记录到一个新的层中,这个新层放置于所有层的最上面

2.当从联合文件系统读取一个文件时,系统会从存在该文件的、最上面的一层中读取

3.大多数的联合文件系统采用了写时复制(copy-on-write)的技术,如果你将它理解为改动时复制(copy-on-change)会更好理解。当只读层(read-only layer)上一个文件被修改了,那么这整个文件会在改动发生之前被复制到最上面的可写层(writable layer),这对运行时性能和镜像的大小会有负面影响

4.一个镜像由多个层以栈的形式组成,首先给出一个顶层作为起始点,然后根据每层元数据中的父层ID将多个层由上而下地连接起来,从某些起始层开始,遍历寻找它们的依赖层

5.仓库和标签通过docker tag、docker commit、docker build命令创建

docker commit xxx 仓库/容器名:标签

docker tag 仓库/容器名:标签 xxxxx

6.联合文件系统实际上会在最顶层添加一个文件来标记一个文件被删除,原始的文件和任何文件副本依旧保留在镜像的其他层中,联合文件系统可能有一个层数量的限制,42层限制在使用AUFS系统的计算机上很常见,可以使用docker history命令来查看一个镜像的所有层

C.导出和导入扁平文件系统

1.socket export命令会将扁平的联合文件系统的所有内容导出到标准输出或者一个压缩文件上,如果需要在容器上下文外使用镜像中的文件系统,这是非常有帮助的

2.docker import命令会将压缩格式的内容导入到一个新镜像中,能够识别多种压缩或未压缩的压缩文件格式,是一个将最小文件集合导入到新镜像的简单方法

D.版本控制的最佳实践

1.在Docker中,维护同一个软件的多个版本的关键是设置正确的仓库标签,每个仓库包含多个标签,多个标签能够指向同一个镜像,这两点是实用标签框架的核心

2.版本控制系统的最小单元要和实际软件迭代的最小单元保持一致

3.latest标签指向最新的稳定版本,而不是测试版本

4.如果软件依赖变去了,或者软件需要基于多个底层系统发布,那么这些依赖应该要被包含到你的标签框架中

八、构建自动化和高级镜像设置

A.使用Dockerfile打包Git

1.docker build -t ubuntu:auto . ,—tag或-t选项的值指定想要使用的完事仓库设计,—file或-f能够设置Dockerfile的名字

2.Dockerfile文件:

  • FROM ubuntu:latest,告诉Docker从最新的ubuntu镜像创建新镜像
  • MAINTAINER,设置镜像维护者的名字和邮箱
  • RUN apt-get install -y git,运行命令
  • ENTRYPOINT [“git”],将镜像的入口点设置为git

3.构建程序能够缓存每一步的结果,当运行完几个指令,下一条指令出现问题时,构建程序能够在问题被修复后,从同一步重新启动

B.Dockerfile入门

1.Dockerfile文件

  • ENV,类似于docker run 命令中的—env,设置镜像的环境变量
  • LABEL用来定义键值对,被记录为镜像或容器的额外元数据,和—label功能一致
  • WORKDIR,与—workdir一致,生成一个默认工作目录
  • EXPOSE指令与—expose一致,对外开放端口
  • COPY,从镜像被创建的文件系统上复制文件到容器中,需要两个参数,最后一个参数是目的目录,其他则为源文件,任何被复制文件都会成为root用户,如果任何一个参数包含了空格,必须使用exec格式
  • VOLUME,与—volume一致,参数中的每一个值都会在产生的新层中被创建为一个新的卷定义
  • CMD,与ENTRYPOINT相关,在容器中启动一个进程
  • ADD,类似于COPY,如果指定了一个URL,会拉取远程源文件,会将被判定为存档文件的源中的文件提取出来

C.注入下游镜像在构建时发生的操作

1.如果生成的镜像被作为另一个构建的基础镜像,则ONBUILD指令定义了需要被执行的那些指令,跟随在ONBUILD后的指令不会在包含它们的Dockerfile被构建时被执行,这些指令会被记录在生成镜像的元数据ContainerConfig.OnBuild下

D.使用启动脚本和多进程容器

1.基于UNIX的计算机通常会先启动一个初始化(init进程)。这个init进程负责启动所有其他的系统服务,让它们持续运行,然后负责关闭它们

2.主流的工具包括runit、Busybox init、Supervisord和DAEMON工具

E.加固应用镜像

1.包含尽量少的组件 ,构建最小化的镜像;强制基于某个特定镜像来构建镜像;拥有一个合适的默认用户;去除root用户提权的通用途径;

2.包含有摘要组件的镜像ID被称为内容可寻址镜像标识符(CAID),它引入的是一个包含特殊内容的特殊层

3.如果你构建的镜像被设计用来运行某些特定的应用程序,那么默认配置应该尽可能地削减用户权限,但要注意确定时间,避免用户缺少权限导致Dockerfile中余下脚本无法执行

九、公有的私有软件分发

A.通过托管Registry发布

1.docker login(Docker Hub网站账号)

2.docker build -t 帐号名(Docker Hub帐号)/项目名

3.docker push 帐号名/项目名

B.私有Registry介绍

1.Docker Registry软件(称为Distribution),这款软件的可用性和宽容的许可证让运行自己的Registry的成本非常低廉,可以通过Docker Hub运行,易于在非生产环境下使用

C.镜像的手动发布和分发

1.docker build命令来创建一个镜像,用docker save命令或者docker export命令来创建一个镜像文件

2.一旦有了镜像文件,就可以使用docker load或者import命令完成传输

D.镜像源代码分发工作流程

1.仅包含一个Dockerfile和你的项目源代码

2.使用git保存一个Dockerfile即可,与所有的Docker分发工具是脱离的,仅令依靠镜像构建器

十、运行自定义Registry

A.运行个人Registry

1.关键组件:

registry的基础镜像是基于Debian的,已经更新了依赖关系

主程序被命名为registry,并在PATH路径上可用

默认的配置文件为config.yml

十一、Docker Compose声明式环境

A.Docker Compose

1.Compose是一个用于定义、启动和管理服务的工具,其中一个服务可以定义为Docker容器的一个或多个副本,在YAML文件中定义了服务和服务系统,并通过命令行docker-compose进行管理

十二、Docker Machine和Swarm集群

1.Docker Machine可以构建一个分布式系统,创建和移除启用了Docker的主机集群

2.Swarm集群由两类机器组成,以管理模式运行Swarm的机器称为manager,而运行Swarm代理的机器称为node,为集群处理容器调度问题

https://github.com/zhangyue0503/docker/tree/master/dockerinaction

原文发布于微信公众号 - 硬核项目经理(fullstackpm)

原文发表时间:2017-08-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券