一、Docker相关概念

1. Docker的前生LXC

LXC为Linux Container的简写。可以提供轻量级的虚拟化,以便隔离进程和资源,而且不需要提供指令解释机制以及全虚拟化的其他复杂性。相当于C++中的NameSpace。容器有效地将由单个操作系统管理的资源划分到孤立的组中,以更好地在孤立的组之间平衡有冲突的资源使用需求。
与传统虚拟化技术相比,它的优势在于:
(1)与宿主机使用同一个内核,性能损耗小;
(2)不需要指令级模拟;
(3)不需要即时(Just-in-time)编译;
(4)容器可以在CPU核心的本地运行指令,不需要任何专门的解释机制;
(5)避免了准虚拟化和系统调用替换中的复杂性;
(6)轻量级隔离,在隔离的同时还提供共享机制,以实现容器与宿主机的资源共享。
总结:Linux Container是一种轻量级的虚拟化的手段。Linux Container提供了在单一可控主机节点上支持多个相互隔离的server container同时执行的机制。Linux Container有点像chroot,提供了一个拥有自己进程和网络空间的虚拟环境,但又有别于虚拟机,因为lxc是一种操作系统层次上的资源的虚拟化。虚拟机更像是提供”机器环境”,而 LXC 则是提供”运行环境”。单看概念它们的区别有些微妙,但是 LXC 的特点就是,同样是提供一套完全隔离的操作系统环境,它很快,超级快。

2. Docker简介

Docker 是一套 Linux 的 LXC 管理工具。
Docker并不是LXC替代品,docker底层使用了LXC来实现,LXC将linux进程沙盒化,使得进程之间相互隔离。在LXC的基础之上,docker提供了一系列更强大的功能。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。
在使用上,概念上的区别就是,用虚拟机,可能更多是想做一个电脑,让它跑起来,然后再说让这台电脑干什么事。
而 Docker 的使用,则是做一个环境(一组进程,还有虚拟的设备等),用环境来运行一个命令。环境-命令 是一体的(一个容器),命令一旦执行完成,那么一个容器实例的任务就结束了。所以如果我们想让一个容器像一台电脑那样, 通常我们给它一个像 /usr/bin/sshd -D 这样的命令,这个容器像一台电脑,是因为这个命令一直”没有执行完成”的效果。
虚拟机的使用,一个镜像就是一个安装好的系统。而 docker 中,镜像更像是一张安装光盘(刻盘后不能更改),容器才是安装好的系统。这种两层式结构相较于传统的”快照”机制,要好用得多。
image.png
图1. 容器和虚拟机

我们用的传统虚拟机如 VMware , VisualBox 之类的需要模拟整台机器包括硬件,每台虚拟机都需要有自己的操作系统,虚拟机一旦被开启,预分配给它的资源将全部被占用。每一台虚拟机包括应用,必要的二进制和库,以及一个完整的用户操作系统。 而容器技术是和我们的宿主机共享硬件资源及操作系统,可以实现资源的动态分配。容器包含应用和其所有的依赖包,但是与其他容器共享内核。容器在宿主机操作系统中,在用户空间以分离的进程运行。

更具体一些, 使用 docker ,就是在指定的环境中执行一条命令,比如:

$ docker run ubuntu:14.04 /bin/bash

意思就是,在 ubuntu:14.04 这个环境中,执行 /bin/bash 这条命令。当然,这条命令显然是瞬间就执行完了的。如果和这个命令立即有交互,那么需要一些参数:

$ docker run –t –I ubuntu:14.04 /bin/bash

-t 是分配一个虚拟终端, -i 是获取当前的输入。这样你可以立即使用一个终端来和这个环境交互了。

回顾上面的过程,提出两个概念,镜像容器
镜像 指上面的 ubuntu:14.04 这种环境,这种系统。后面会讲如何做一个自己的镜像。

docker镜像就是一个只读模板,比如,一个镜像可以包含一个完整的centos,里面仅安装apache或用户的其他应用,镜像可以用来创建docker容器,另外docker提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下周一个已经做好的镜像来直接使用

容器 是在具体的 镜像 上 run 具体的命令,得到的一个”绑定状态”。 run 命令执行时的一些参数(比如和实体机的端口映射),也是”状态”的一部分, run 过之后就不能更改了。

docker利用容器来运行应用,容器是从镜像创建的运行实例,它可以被启动,开始、停止、删除、每个容器都是互相隔离的,保证安全的平台,可以吧容器看做是要给简易版的linux环境(包括root用户权限、镜像空间、用户空间和网络空间等)和运行再其中的应用程序。 镜像容器的关系,有些像编程语言中的实例。run 时的命令就像是类实例化时的参数。后面会提到,你可以删除容器,也可以删除 镜像。当你想删除 镜像,但是使用它的 容器 还存在时,你会得到操作失败的提示。

3. Docker的应用场景

  • Web 应用的自动化打包和发布。
  • 自动化测试和持续集成、发布。
  • 在服务型环境中部署和调整数据库或其他的后台应用。
  • 从头编译或者扩展现有的 OpenShift 或 Cloud Foundry 平台来搭建自己的 PaaS 环境。

    4. Docker的优点

  • docker 启动快速属于秒级别。虚拟机通常需要几分钟去启动

  • docker 需要的资源更少,docker 在操作系统级别进行虚拟化, docker 容器和内核交互,几乎没有性能损耗,性能优于通过 Hypervisor 层与内核层的虚拟化
  • docker 更轻量,docker 的架构可以共用一个内核与共享应用程序库,所占内存极小。同样的硬件环境, Docker 运行的镜像数远多于虚拟机数量,对系统的利用率非常高
  • 与虚拟机相比,docker 隔离性更弱, docker 属于进程之间的隔离,虚拟机可实现系统级别隔离
  • 安全性:docker 的安全性也更弱。 Docker 的租户 root 和宿主机 root 等同,一旦容器内的用户从普通用户权限提升为root权限,它就直接具备了宿主机的root权限,进而可进行无限制的操作。虚拟机租户 root 权限和宿主机的 root 虚拟机权限是分离的,并且虚拟机利用如 Intel 的 VT-d 和 VT-x 的 ring-1 硬件隔离技术,这种隔离技术可以防止虚拟机突破和彼此交互,而容器至今还没有任何形式的硬件隔离,这使得容器容易受到攻击
  • 可管理性:docker 的集中化管理工具还不算成熟。各种虚拟化技术都有成熟的管理工具,例如 VMware vCenter 提供完备的虚拟机管理能力
  • 高可用和可恢复性:docker 对业务的高可用支持是通过快速重新部署实现的。虚拟化具备负载均衡,高可用,容错,迁移和数据保护等经过生产实践检验的成熟保障机制, VMware 可承诺虚拟机99.999% 高可用,保证业务连续性
  • 快速创建、删除:虚拟化创建是分钟级别的,Docker 容器创建是秒级别的, Docker 的快速迭代性,决定了无论是开发、测试、部署都可以节约大量时间
  • 交付、部署:虚拟机可以通过镜像实现环境交付的一致性,但镜像分发无法体系化。Docker 在 Dockerfile 中记录了容器构建过程,可在集群中实现快速分发和快速部署

    5. Docker架构

    (1)总体架构

    image.png

  • distribution 负责与docker registry交互,上传下载镜像以及v2 registry 有关的源数据

  • registry负责docker registry有关的身份认证、镜像查找、镜像验证以及管理registry mirror等交互操作
  • image 负责与镜像源数据有关的存储、查找,镜像层的索引、查找以及镜像tar包有关的导入、导出操作
  • reference负责存储本地所有镜像的repository和tag名,并维护与镜像id之间的映射关系
  • layer模块负责与镜像层和容器层源数据有关的增删改查,并负责将镜像层的增删改查映射到实际存储镜像层文件的graphdriver模块
  • graghdriver是所有与容器镜像相关操作的执行者

    (2)Docker架构2

    如果觉得上面架构图比较乱可以看这个架构:
    image.png
    从上图不难看出,用户是使用Docker Client与Docker Daemon建立通信,并发送请求给后者。
    而Docker Daemon作为Docker架构中的主体部分,首先提供Server的功能使其可以接受Docker Client的请求;而后Engine执行Docker内部的一系列工作,每一项工作都是以一个Job的形式的存在。
    Job的运行过程中,当需要容器镜像时,则从Docker Registry中下载镜像,并通过镜像管理驱动graphdriver将下载镜像以Graph的形式存储;当需要为Docker创建网络环境时,通过网络管理驱动networkdriver创建并配置Docker容器网络环境;当需要限制Docker容器运行资源或执行用户指令等操作时,则通过execdriver来完成。
    而libcontainer是一项独立的容器管理包,networkdriver以及execdriver都是通过libcontainer来实现具体对容器进行的操作。当执行完运行容器的命令后,一个实际的Docker容器就处于运行状态,该容器拥有独立的文件系统,独立并且安全的运行环境等。

    (3) Docker架构3

    再来看看另外一个架构,这个个架构就简单清晰指明了server/client交互,容器和镜像、数据之间的一些联系。
    image.png
    Docker daemon就是docker的守护进程即server端,可以是远程的,也可以是本地的,这个不是C/S架构吗,客户端Docker client 是通过rest api进行通信。
    Docker cli 用来管理容器和镜像,客户端提供一个只读镜像,然后通过镜像可以创建多个容器,这些容器可以只是一个RFS(Root file system根文件系统),也可以是一个包含了用户应用的RFS,容器再Docker client中只是要给进程,两个进程之间互不可见。
    用户不能与server直接交互,但可以通过与容器这个桥梁来交互,由于是操作系统级别的虚拟技术,中间的损耗几乎可以不计。

    二、 Docker安装

    1.Ubuntu安装

    | $ sudo apt install docker.io | | :—- |

检查docker版本

$ docker version

2.Mac安装

$ brew cask install docker

3.Windows安装

参照https://www.runoob.com/docker/windows-docker-install.html

三、Docker镜像使用

1.列出镜像列表

$ docker images

2.查找镜像

我们可以从 Docker Hub 网站来搜索镜像,Docker Hub 网址为: https://hub.docker.com/,我们也可以使用 docker search 命令来搜索镜像。比如我们需要一个httpd的镜像来作为我们的web服务。我们可以通过 docker search 命令搜索 httpd 来寻找适合我们的镜像。

$ docker search [OPTIONS] NAME
示例:
$ docker search –s 10 java

OPTIONS说明:

  • —automated: 只列出 automated build类型的镜像;
  • —no-trunc: 显示完整的镜像描述;
  • -s: 列出收藏数不小于指定值的镜像。

    3.获取一个新的镜像

    当我们在本地主机上使用一个不存在的镜像时 Docker 就会自动下载这个镜像。如果我们想预先下载这个镜像,我们可以使用 docker pull 命令来下载它。例如:
$ docker pull ubuntu:13.10

4.创建镜像

当我们从docker镜像仓库中下载的镜像不能满足我们的需求时,我们可以通过以下两种方式对镜像进行更改。

(1)基于已有镜像创建

更新镜像

更新镜像之前,我们需要使用镜像来创建一个容器。在运行的容器内使用 apt-get update 命令进行更新。在完成操作之后,输入 exit命令来退出这个容器。

命令 docker commit来创建
$ docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

例如:

$ docker commit -m=”updated” -a=”LiMing” e218edb10161 test/ubuntu:v2

各个参数说明:
-m:提交的描述信息
-a:指定镜像作者
e218edb10161:容器ID
test/ubuntu:v2:指定要创建的目标镜像名

(2)使用Dockerfile 指令来创建一个新的镜像

创建一个Dockerfile文件
$ vim Dockerfile
FROM ubuntu:13.10
MAINTAINER LiMing
ENV PATH /usr/local/bin:$PATH
ADD . /code
RUN pip install –r requirements.txt
CMD python3 my_test.py
  • FROM:需要什么环境,使用哪个镜像源
  • MAINTAINER: 作者信息
  • ENV:修改path,即增加/usr/local/bin这个环境变量
  • ADD:将本地代码放到虚拟容器中,它有两个参数,第一个是 . ,代表本地当前路径;第二个参数是/code,代表虚拟容器中的路径,即将本地项目的所有内容放到虚拟容器的/code目录下,以便在虚拟容器中运行代码
  • WORKDIR:指定工作目录,也就是刚才的/code,在虚拟容器中的目录
  • RUN:指令告诉docker 在镜像内执行命令,安装什么,docker容器中只有pyton3环境,还需要python的库,这里安装那些库
  • CMD:运行项目的命令行命令
  • EXPOSE:声明会用到的端口
  • ENTRYPOINT:ENTRYPOINT 可以让你的容器表现得像一个可执行程序一样。一个 Dockerfile 中只能有一个 ENTRYPOINT,如果有多个,则最后一个生效。


每一个指令都会在镜像上创建一个新的层,每一个指令的前缀都必须是大写的。

开始创建镜像
$ docker build –t repository:tag .

5.设置镜像标签

我们可以使用 docker tag ID repository:tag命令,为镜像添加一个新的标签。

$ docker tag 860c279d2fec DataClean:v1.0

6.删除镜像

想删除指定镜像的话,由于 image 被某个 container 引用(拿来运行),如果不将这个引用的 container 销毁(删除),那 image 肯定是不能被删除。我们首先得先去停止这个容器。

$ docker ps
$ docker stop container_name/container_id
$ docker rm container_name/container_id
$ docker rm image_name

7.镜像的存出和载入

存出镜像到文件
$ docker save –o file_name image_name

从文件载入镜像
$ docker load —input file_name

8.镜像的上传

  • push到dockerhub(需要登录)或公司仓库(待建),然后在装好docker的服务器上pull下来镜像,run即可 | $ docker push NAME[:TAG] | | :—- |

  • 复制源代码到服务器,在装好docker的服务器上重新执行 build

  • 将image导出,复制到装好docker的服务器,载入image,run即可

    四、Docker容器使用

    1.查看当前容器

    | $ docker ps –a # -a 是查看当前所有的容器,包括未运行的 | | :—- |

2.进入容器

$ docker attach container_name/container_id

3.运行容器中的镜像并调用镜像里面的bash

$ docker run –t –i container_name/container_id /bin/bash

参考示例:部署一个Python项目基本流程

  1. 准备项目
  2. 准备Dockerfile文件
  3. 准备txt文件
  4. 开始创建镜像
  5. 部署,推送镜像到库或导出文件
  6. pull镜像或load镜像
  7. 运行

References:

  1. Docker 官网:http://www.docker.com
  2. Github Docker 源码:https://github.com/docker/docker-ce
  3. 这可能是最为详细的Docker入门吐血总结:https://blog.csdn.net/deng624796905/article/details/86493330
  4. W3Cschool:https://www.w3cschool.cn/use_docker/use_docker-phr127zf.html
  5. Runoob:https://www.runoob.com/docker/docker-container-connection.html
  6. Docker的基本使用(部署python项目):https://www.cnblogs.com/haoabcd2010/p/10296169.html
  7. Docker化你的Python应用:https://www.jianshu.com/p/b4ff1663d05d
  8. 终于有人把 Docker 讲清楚了,万字详解!:https://mp.weixin.qq.com/s/SUiaCS11JsIUZY_JO3nlHQ
  9. 架构 3 | Docker容器化:说一说IM系统中模块水平扩展的实现