Docker 是基于 go语言 并遵从 Apacher2.0 协议的开源应用容器引擎。
Docker 能够让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器,也可以实现虚拟化。
容器时完全使用沙箱机制,相互之间不会有任何接口,性能开销极低。
一、关于Docker
在了解Docker 之前,我们都知道虚拟机。其实虚拟机和 Docker 都属于虚拟化技术。
它们之间的区别如下:
虚拟机:通Vmware 可以虚拟化出一个新的操作系统环境,缺点是非常笨重,占用空间大,启动满。
Docker:与虚拟机相比起来,docker更加轻巧,占用空间小,启动快。
传统的虚拟机,虚拟出一套硬件,运行一个完整的操作系统,然后在这个系统上安装和运行软件。
容器内的应用直接运行在宿主主机的内核,容器时没有自己的内核,也没有虚拟我们的硬件,所以就更轻便
每个容器之间是相互隔离,每个容器内都有一个属于自己的文件系统,互不影响。

1.1、Docker 能干什么?
Docker 是一个用于开发,交付和运行的应用程序的开发平台。Docker 能够将应用程序与基础架构分开,从而可以快速交付软件。借助 Docker ,可以与管理应用程序相同的方式来管理基础架构。能够快速交付,测试和部署代码,减少编写代码和在生产环境中运行代码之间的延迟。
主要应用场景如下:
- Web 应用的自动化打包和发布
- 自动化测试和持续集成、发布
- 在服务型环境中部署和调整数据库或其他后台应用
- 从头编译或拓展现有的 OpenShift 或 Cloud Foundry 平台来搭建自己的 Paas 环境
优点:
- 能够快速地交付和部署应用,非常适合持续集成和持续交付流程(CI/CD)
- 响应式部署升级和扩缩容
- 更简单的系统运维
- 更高效地利用计算机资源
1.2、Docker 的组成部分
Docker 核心概念
- **镜像(Image):**Docker 镜像就相当于一个root 文件系统。用于创建Docker容器的模板,可以理解为一个基础的文件模板,通过镜像可以创建多个容器。
- **容器(Container):**独立运行的一个或一组应用,是镜像的运行时实体。镜像和容器的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停。每个容器的运行是相互独立、相互隔离的。
- **仓库(Repository):**仓库是存放镜像的地方,用来保存镜像。
**Docker 逻辑上由三部分组成:**Daemon(守护进程)、Rest API(API,所有客户端都通过API进行操作)、Client(客户端)

Docker 使用C/S 架构模式,Docker 的守护进程(daemon)运行在主机上,使用远程API 来管理和创建 Docker 容器。Docker 容器通过 Docker 镜像来创建。
Docker 为什么比 vm 快?
1、Docker 比 vm 更少的抽象层。
2、Docker 利用的时宿主主机内核,vm 需要 Guest OS。

在新建容器时,Docker 不需要像虚拟机一样重新加载一个操作系统内核,避免引导,虚拟机时加载 Guest OS , 是分钟级别的;而Docker 是利用宿主主机的操作系统,属于秒级。
二、Docker安装和卸载(CentOS)
如果系统上存在较旧的 Docke 版本,可以先进行卸载操作(较旧的Docke 版本称为 docker 或 docker-engine),如果已安装这些程序,请卸载它们以及相关依赖项。
1 | 卸载旧版本docker |
使用 Docker 仓库进行安装
1 | 安装所需的软件包。 |
卸载 docker
1 | 删除安装包 |
三、Docker 的使用
3.1、Docker 命令
Docker 命令可以分为以下几大类:
docker 信息、镜像命令(包含镜像信息、镜像管理)、容器命令(包含容器信息、容器管理)
3.1.1、docker 信息
1 | docker info # 显示docker 系统信息,包括版本信息,镜像信息 |
3.1.2、镜像命令
3.1.2.1、查看镜像
1 | 查看主机上的所有镜像信息 |
3.1.2.2、获取镜像
1 | 从源仓库中获取镜像(没有指定版本,默认拉起最新的版本) |
3.1.2.3、搜索镜像
1 | 搜索指定的镜像 |
3.1.2.4、删除镜像
1 | 删除镜像使用 docker rmi 命令 |
3.1.2.5、更新镜像
当镜像有需要更新的情况下,比如在一个 CentOS 容器中做了更新后,希望这些更新能够作用到镜像上面,可以通过下面的命令来解决。
1 | 如 通过 docker run -t -i CentOS /bin/bash 命令进入了一个容器,使用 apt-get update 命令来进行更新。 |
3.1.2.6、查看镜像的变更
1 | 通过 dockers history 可以查看镜像的变更历史 或者说 查看镜像的 dockerfile |
3.1.3、容器命令
当通过 docker run 来启动一个容器时,docker 运行的操作主要包括一下几个步骤:
- 检查本地是否存在指定的镜像,不存在就从远程仓库源中下载;
- 利用进行创建容器,并启动容器;
- 分配一个文件系统给容器,并在只读镜像层外面挂载一层可读写层;
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中;
- 从网桥的地址池配置一个IP地址给容器;
- 执行用户指定的应用程序;
- 执行完毕后容器被自动停止。
3.1.3.1、启动容器
1 | docker run [可选参数] image |
3.1.3.2、查看容器
1 | docker ps |
3.1.3.3、暂停容器、停止容器
1 | 暂停容器 |
3.1.3.4、启动容器、重启容器
1 | 启动容器 |
3.1.3.5、删除容器
1 | 容器在非运行状态下通过下面的命令可以进行删除 |
3.1.3.6、导出导入容器
在有些时候,我们需要将容器从一台机器迁移到另外一台机器,这时候就需要用到导入导出功能
1 | 导出容器 |
3.1.3..7、提交容器
当我们在使用容器时(如果不挂载卷),那么我们在容器上所做的修改都存储在容器中,docker 为我们提供了 docker commit 命令,可以间容器测存储层保存下来作为一个新的镜像。就是说,在原有镜像的基础上,加上容器的存储层,构成一个新的镜像。那以后运行新的镜像,就会拥有原容器的最后文件变化。
1 | 使用方法 |
–author 指定了修改的作者
–message 记录修改本次的信息
3.1.3.8、查看容器相关信息
通过docker inspect 命令可查看容器的具体信息,会以 json 格式返回容器 id、创建时间、路径状态、镜像、配置在内的信息
1 | docker inspect 容器id 或者 容器名称 |

使用以下命令可查看容器中的进程信息
1 | docker top 容器名 或 ID |
3.1.3.9、暴露端口、端口映射
一般来说外部机器无法直接通过网络来和容器进行通信,但宿主机可以和容器直接进行通信,因此我们可以借助宿主机来和容器进行通信。如在运行nginx 时可以将宿主机的端口和容器的端口进行映射,这样外部机器便可以通过访问宿主机从而访问到容器。
1 | 暴露端口 |
3.1.3.10、其他命令
1 | 运行容器时,设置环境变量 |
运行容器:docker run 参数 redis (镜像名称)
1 | docker run -d -p 6379:6379 --restart=on-failure:10 --name myredis redis |
3.2、Dockerfile
通常地,构建镜像有两种方式:
- 基于容器制作
- 通过Dockerfile 构建
Dockerfile 一般用于构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明。网络上的镜像难以满足现实中各式各样的需求,而Dockerfile 能够让用户个性化定制 Docker 镜像。
3.2.1、Dockerfile 格式
- Dockerfile 的整体语句就有两类:
- #头的注释
- Instruction arguments 指令 参数,一行一个指令。
- Dockerfile 的文件名首字母必须大写
- Dockerfile 指令不区分大小写,但是为了和参数区分开来,一般指令都是大写字母
- Dockerfile 指令的执行顺序是由上往下依次执行
- Dokcerfile 的第一个非注释行必须是 FROM 指令,用来指定当前制作的镜像依据的基础镜像
- Dockerfile 需要调用的文件必须跟Dockerfile文件在同一目录下,或者在其子目录下,父目录或其他目录无效
3.2.2、Dockerfile 指令
| 指令 | 说明 |
|---|---|
| FROM | 指定构建镜像的来源,基础镜像 |
| MAINTAINER | Dockerfile 作者信息 MAINTAINER name xxx@qq.com or MAINTAINER “xxx@qq.com“ |
| RUN | 在当前镜像基础上执行指定的命令 RUN 注意: Dockerfile 的指令每执行一次都会在docker 上新建一层,应该避免过多无意义层导致docker 膨胀过大。 |
| COPY | 复制指令,build 时复制,从上下文目录中复制文件或目录到容器里指定路径 COPY |
| ADD | 和 COPY 功能类似,build 时复制。 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径> |
| CMD | 类似RUN,用于运行行程序, 与RUN不同的是: CMD 在 docker run 时运行; RUN 实在 docker build |
| ENTRYPOINT | 类似 CMD,指定容器启动程序和参数 指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接的运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令,换句话说实际执行时,将变为: |
| ENV | 设置环境变量以便在后续的指令中可以使用环境变量,构建好的镜像内会存在该环境变量 ENV |
| ARG | 定义 Dockerflie 内的环境变量,仅在 Dockerfile内有效,只有在 docker build 过程中有效,镜像中不存在该环境变量 <参数名>[=<默认值>] |
| EXPOSE | 声明暴露的端口 |
| WORKDIR | 用于指定工作目录,WORKDIR 指定的工作目录,必须是提前创建好的 |
| ONBUILD | 用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。 |
| USER | 指定后续命令的用户和用户组,切换后续命令执行的用户 |
| HEALTHCHECK | 用于指定某个程序或者指令来监控 docker 容器服务的运行状态。 |
| LABEL | LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式 LABEL |
| VOLUME | 指定挂载目录 |
3.2.3、Dockerfile 的构建过程
dockerfile 是用来构建docker镜像的命令参数脚本文件
通过脚本命令生成镜像,镜像时一层层的,每个命令都是一层
在编写构建镜像脚本时,我们应该尽可能的简化命令,减少镜像的层数,同时也要压缩镜像的体积。多个命令能合成一行写的就合并为一行。
docker 构建镜像的步骤:
- 编写 dockerfile 脚本文件,指定镜像源、设置命令
- 通过
docker build -t name:tag .命令来构建镜像 - docker run 运行镜像
- docker push 发布推送镜像(DockerHub、阿里云镜像仓库)
3.3、数据管理
在docker 的应用中,我们往往需要对数据进行持久化或者多个容器之间需要对数据共享,而在必要涉及到容器数据的管理操作。容器中的数据管理操作分为以下两种方式:
- 数据卷(Data Volumes):容器内数据直接映射到宿主机环境。
- 数据卷容器(Data Volumes Containers) :使用特顶容器维护数据卷。
3.3.1、挂载数据卷
数据卷是一个可供容器使用的特殊目录,它将主机操作系统目录直接映射进容器,类型 Linux 中的 mount 行为
- 数据卷可以在容器间共享和重用,使得容器间传递数据将变得高效与方便;
- 无论是在宿主机操作还是容器内操作,对数据卷的修改操作会立马生效
- 对数据卷的更新不会影响镜像,解耦应用和数据
- 卷会一直存在,直到没有容器使用,可以安全的卸载它(即使容器被删除,宿主机数据卷还存在)。
通常在启动容器时可通过 -v,--volume 参数指令来设置容器数据卷的挂载。这样容器和宿主机直接就可以通过一个目录来同步数据
1 | 以启动 ubuntu 容器为例子 |
通过上面的尝试,指定宿主机的/home/docker/data 和容器 /home/data 目录之间建立了映射关系,无论是容器还是宿主机都可以对挂载卷进行修改操作,都可以在另一方得到呈现。
此外,宿主机的同一个目录也支持多个容器进行映射,即多个容器可以挂载在宿主机的同一个目录下,这样就可以实现多个容器之间的数据共享
3.3.2、数据卷容器
试想一下,如果我们要创建多个容器,并且这些容器之间都需要数据共享,那么如果按挂载数据卷的方式,创建一个容器就映射一次目录来实现数据卷挂载,这样岂不是很麻烦?那么是否有没有更加简便的方法来实现多容器间的数据共享呢?
答案是有的,就是通过 数据卷容器 来实现,首先创建一个数据卷容器并和宿主机建立相应的目录映射,然后在启动其他的容器时,通过命令 -volumes-from 来指定数据卷容器共享数据。
1 | -volumes-from list Mount volumes from the specified container(s) # 从一个特殊容器中挂载数据卷 |
具体操作如下图所示:
先创建数据容器,将宿主机的目录对应地和数据卷容器的目录挂载,让后启动另外的容器并指定数据卷容器,这样就可以实现在多个容器之间共享数据。

3.4、应用练习
3.4.1、构建一个带tomcat 的 Ubuntu 镜像
主要实现步骤有:
1、先准备好jdk、tomcat 包到指定的目录下2、touch Dockerfile 创建文件,编写命令
3、在 Dockerfile 所在的目录下通过
docker build -t name .构建镜像注意 构建命令中的
.代表的是 上下文上下文是指 Dockerfile 所在的目录,以及在构建镜像时,需要使用到宿主机文件的目录,dokcer build 知道这个命令后,会将路径下的所有内容打包。
1 | # 指定镜像源 |
最后通过 docker build -t ubuntu-tomcat:v1 . 命令构建镜像
3.4.2、Dockerfile 构建 tomcat 镜像
1 | # 指定镜像源 |
3.5、发布镜像
3.5.1、注册 Docker Hub 用户
到官网注册一个账号:https://hub.docker.com/
然后登录创建一个仓库,用来上传我们的镜像
3.5.2、本地 Linux 登录 docker
1 | 登录 |
3.5.3、给要上传发布的镜像打tab
因为推送镜像的规范是:docker push 仓库名/镜像名:镜像版本
1 | docker tab ubuntu myrespo/ubuntu:v2 |

四、Docker 网络
Docker 在启动时会首先在宿主机上自动创建一个 docker0 虚拟网桥,实际上是 linux 网桥,它在内核层连通了其它的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。
网桥:可以理解为一个软件交换机,负责挂载在其上的接口之间进行包转发。在 shell 通过 ifconfig 命令可以查看。