Docker由浅入深全面入门

zhyjc6于2019-09-24发布 约6379字·约14分钟 本文总阅读量

1. 什么是docker?

Docker 是一个开源的应用容器引擎(基于 Go 语言 并遵从Apache2.0协议开源),让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上

2. docker的应用场景?

3. 为什么需要docker?

软件开发最大的麻烦事之一,就是环境配置。用户计算机的环境都不相同,我们怎么知道自家的软件,能在那些机器跑起来?

用户必须保证两件事:操作系统的设置,各种库和组件的安装。只有它们都正确,软件才能运行。举例来说,安装一个 Python 应用,计算机必须有 Python 环境,还必须有各种依赖,可能还要配置环境变量。

如果某些老旧的模块与当前环境不兼容,那就麻烦了。开发者常常会说:”它在我的机器可以跑了”(It works on my machine),言下之意就是,其他机器很可能跑不了。

环境配置如此麻烦,换一台机器,就要重来一次,旷日费时。很多人想到,能不能从根本上解决问题,软件可以带环境安装?也就是说,安装的时候,把原始环境一模一样地复制过来。

这个时候人们发明了虚拟机,但是由于虚拟机在很多时候太过于笨重,docker就诞生了!

4. 虚拟机和docker?

Guest OS 是虚拟机安装的操作系统,是一个完整的系统内核,另外Hypervisor可以理解为硬件虚拟化平台,它在Host OS以内核驱动的形式存在。容器运行的是不完整的操作系统(尽管它们可以),虚拟机必须运行完整的。

  虚拟机 docker
简介 虚拟机(virtual machine)就是带环境安装的一种解决方案。它可以在一种操作系统里面运行另一种操作系统,比如在 Windows 系统里面运行 Linux 系统。应用程序对此毫无感知,因为虚拟机看上去跟真实系统一模一样,而对于底层系统来说,虚拟机就是一个普通文件,不需要了就删掉,对其他部分毫无影响。 Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离。或者说,在正常进程的外面套了一个保护层。对于容器里面的进程来说,它接触到的各种资源都是虚拟的,从而实现与底层系统的隔离。
原理 VM在物理机器的操作系统上建立了一个中间软件层Hypervisor,Hypervisor利用物理机器的资源,虚拟出多个新虚拟的硬件环境,这些硬件环境可以共享宿主机的资源。这些新的虚拟的硬件环境,安装操作系统和相应的软件后便形成了一台台的虚拟机器。 Docker选择了和虚拟化完全不同的思路,并不去虚拟化任何硬件,而是对硬件资源在不同的docker container之间做了 “隔离” 。隔离使每个docker container之间拥有了不同的环境(硬盘空间、网络、系统的工具包),并且又可以共享需要的硬件资源(cpu、内存、系统内核),达到了和虚拟机能提供的同样的功能。
优点 1.可以安装在不同的os平台上
2. 体验不同版本的操作系统,如Linux、Mac等
3. 虚拟机可以随意复制移动,方便给他人使用
4. 支持快照,当虚拟机受病毒入侵时,可以直接利用快照实现时光倒流
1. 资源占用少
容器只占用需要的资源,不占用那些没有用到的资源;虚拟机由于是完整的操作系统,不可避免要占用所有资源。另外,多个容器可以共享资源,虚拟机都是独享资源。
2. 体积小
容器只要包含用到的组件即可,而虚拟机是整个操作系统的打包,所以容器文件比虚拟机文件要小很多。
3. 启动快
容器里面的应用,直接就是底层系统的一个进程,而不是虚拟机内部的进程。所以,启动容器相当于启动本机的一个进程,而不是启动一个操作系统,速度就快很多。
缺点 1. 资源占用多
虚拟机会独占一部分内存和硬盘空间。它运行的时候,其他程序就不能使用这些资源了。
2. 冗余步骤多
虚拟机是完整的操作系统,一些系统级别的操作步骤,往往无法跳过,比如用户登录。
3. 启动慢
启动操作系统需要多久,启动虚拟机就需要多久。可能要等几分钟,应用程序才能真正运行。
1. 资源隔离方面不如虚拟机 docker是利用cgroup实现资源限制的,只能限制资源消耗的最大值,而不能隔绝其他程序占用自己的资源。
2. 安全性问题 docker目前并不能分辨具体执行指令的用户,只要一个用户拥有执行docker的权限,那么他就可以对docker的容器进行所有操作,不管该容器是否是由该用户创建。
3. 存在版本兼容问题 docker 目前还在版本的快速更新中,细节功能调整比较大。一些核心模块依赖于高版本内核,存在版本兼容问题
使用场景 虚拟机更擅长虚拟以及隔离整个环境 docker更擅长隔离不同的应用,比如前端、后端、数据库

5. docker的架构

Docker 采用 C/S 结构。 Docker 客户端与 Docker 服务器进行交互,Docker服务端负责构建、运行和分发 Docker 镜像。 Docker 客户端和服务端可以运行在一台机器上,也可以通过 RESTful 、 stock 或网络接口与远程 Docker 服务端进行通信。

docker的总体架构如下图所示:

Image(镜像)

Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

Docker Image是一个只读的模板。比如,一个Image可以包含一个Ubuntu操作系统,整个系统可以包括Apache和我们的web应用。Image是用来创建容器的。Docker提供了一种简单的方式来创建Image和更新已有的 Image, 我们可以从网上下载Image,也可以自己编译Image。

Container(容器)

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

每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们称这个为容器运行时读写而准备的存储层为 容器存储层

容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。

按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。

数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。

Repository(仓库)

Docker Registry 简介

镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。

一个 Docker Registry 中可以包含多个 仓库(Repository);每个仓库可以包含多个 标签(Tag);每个标签对应一个镜像。

通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。

Ubuntu 镜像 为例,ubuntu 是仓库的名字,其内包含有不同的版本标签,如,16.04, 18.04。我们可以通过 ubuntu:16.04,或者 ubuntu:18.04 来具体指定所需哪个版本的镜像。如果忽略了标签,比如 ubuntu,那将视为 ubuntu:latest。

仓库名经常以 两段式路径 形式出现,比如 jwilder/nginx-proxy,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务。

Docker Registry 是存放Image的仓库。我们可以使用公有的和私有的Registry来进行下载和上载。公共的Docker Registry位于Docker Hub,但是国内访问比较慢。Docker Hub包含了大量已有的Image,供用户使用。我们可以基于之前的Image来创建自己的 Image。

Docker Registry 工作方式

Docker Registry是Image的仓库,当我们编译完成一个Image时,我们可以推送到公共的Registry,比如Docker Hub,也可以推送到我们自己的私有Registry。 使用Docker Client,我们可以搜索已经发布的Image,并从中拉取Image到本地,并在容器中运行。 Docker Hub提供了公有和私有的Registry。所有人都可以搜索和下载公共镜像。私有仓库只有私有用户能够查询和下载。

Docker Client

Docker提供给用户的客户端。Docker Client提供给用户一个终端,用户输入Docker提供的命令来管理本地或者远程的服务器。Docker client和daemon可以运行在同一个系统上,也可以通过远程方式进行访问。

Docker Daemon

Docker服务的守护进程。每台服务器(物理机或虚机)上只要安装了Docker的环境,基本上就跑了一个后台程序Docker Daemon,Docker Daemon会接收Docker Client发过来的指令,并对服务器的进行具体操作。

6. docker版本选择与安装

Docker 是一个开源的商业产品,分为 CE(Community Edition) 和 EE(Enterprise Edition) 两大版本。

CE 即社区版(免费,支持周期 7 个月),EE 即企业版,强调安全,付费使用,支持周期 24 个月。

个人开发者一般用不到企业版。下面的介绍都针对社区版。

docker CE 各平台官方安装指南

安装完成后,运行下面的命令,验证是否安装成功:

$ docker version
# 或者
$ docker info

7. Dockerfile是啥?与docker有什么关系?

简单来说,Dockerfile是自动构建 docker镜像的配置文件, 用户可以使用 Dockerfile快速创建自定义的镜像。Dockerfile 中的命令非常类似于 linux 下的 shell 命令。

我们可以通过下面这幅图来直观地感受下 Docker 镜像、容器和 Dockerfile 三者之间的关系:

具体来说,Dockerfile 是由一行行命令语句组成,并且支持以 # 开头的注释行。

一般来说,我们可以将 Dockerfile 分为四个部分:

一个简单的dockerfile例子,这个例子是启动一个 python flask app 的 Dockerfile ( flask 是 python 的一个轻量的 web 框架)

FROM python:2.7				#从 Docker Hub 上 pull 下 python 2.7 的基础镜像
MAINTAINER Angel_Kitty <angelkitty6698@gmail.com>		#显示维护者的信息
COPY . /app			#copy 当前目录到容器中的 /app 目录下
WORKDIR /app		#指定工作路径为 /app
RUN pip install -r requirements.txt		#安装依赖包
EXPOSE 5000			#暴露 5000 端口
ENTRYPOINT ["python"]
CMD ["app.py"]			#启动 app

8. 制作并发布自己的image文件

下面以 koa-demos 项目为例,介绍怎么写 Dockerfile 文件,实现让用户在 Docker 容器里面运行 Koa 框架。

作为准备工作,请先下载源码

$ git clone https://github.com/ruanyf/koa-demos.git
$ cd koa-demos

编写 Dockerfile 文件

首先,在项目的根目录下,新建一个路径排除文本文件.dockerignore,把不需要打包进入 image 文件的路径填入; 然后,在项目的根目录下,新建一个文本文件 Dockerfile,写入下面的内容:

FROM node:8.4
COPY . /app
WORKDIR /app
RUN npm install --registry=https://registry.npm.taobao.org
EXPOSE 3000

上面代码一共五行,含义如下:

FROM node:8.4:该 image 文件继承官方的 node image,冒号表示标签,这里标签是8.4,即8.4版本的 node。
COPY . /app:将当前目录下的所有文件(除了.dockerignore排除的路径),都拷贝进入 image 文件的/app目录。
WORKDIR /app:指定接下来的工作路径为/app。
RUN npm install:在/app目录下,运行npm install命令安装依赖。注意,安装后所有的依赖,都将打包进入 image 文件。
EXPOSE 3000:将容器 3000 端口暴露出来, 允许外部连接这个端口。

创建 image 文件

有了 Dockerfile 文件以后,就可以使用docker image build命令创建 image 文件了。

$ docker image build -t koa-demo .
# 或者
$ docker image build -t koa-demo:0.0.1 .

上面代码中,-t参数用来指定 image 文件的名字,后面还可以用冒号指定标签。如果不指定,默认的标签就是latest。最后的那个点表示 Dockerfile 文件所在的路径,上例是当前路径,所以是一个点。

如果运行成功,就可以看到新生成的 image 文件koa-demo了。

$ docker images

发布image文件

我们可以考虑把 image 文件分享到网上,让其他人使用。

首先,去 hub.docker.comcloud.docker.com 注册一个账户。然后,用下面的命令登录。

$ docker login

接着,为本地的 image 标注用户名和版本。

$ docker image tag [imageName] [username]/[repository]:[tag]
# 实例
$ docker image tag koa-demos:0.0.1 ruanyf/koa-demos:0.0.1

也可以不标注用户名,重新构建一下 image 文件。

$ docker image build -t [username]/[repository]:[tag] .

最后,发布 image 文件。

$ docker image push [username]/[repository]:[tag]

发布成功以后,登录 hub.docker.com,就可以看到已经发布的 image 文件。

9. docker命令大全

10. docker资源汇总