陈惠超的博客Github

Docker 入门介绍

2019-09-28#技术#Docker

Docker 场景
以前端最熟悉的 Node 写 Blog 项目为例: 你一个人一股脑写完了前端 React + 后端 Node.js + 数据库 Mongodb。当你要把项目部署到服务器的时候,大家可以思考下有哪些事情需要做的?
1.
对于 React 项目而言,nginx 是少不了的。所以你需要下载一个 nginx。不同的操作系统官网都提供了对应的下载方法,只需要跟着下载,然后更改 nginx.conf 配置文件。
2.
对于后端 api 服务,需要安装 Node.jsMongodb,以及其他需要的服务。Mongodb 安装完还得配置。
3.
…其他配置
对于大部分前端同学而言,如果不是经常折腾服务器的话,前面这一通部署下来,已经累得够呛了。 如果这项目需要第二台服务器、第三台服务器上部署?是不是又得把上面的操作的步骤重新再走一遍? 是不是觉得心都要碎了。
这时候 Docker 的作用就体现出来了。
Docker 是什么
Docker 是使用 Go 开发,基于 Linux 内核的 cgroup,namespace,以及 AUFS 类的 Union FS 等技术,对进行进行封装隔离,属于操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其他的隔离的进程 ,因此也称其为容器。
下面这张图是 Docker 的架构图。
既然Docker属于操作系统层面的虚拟化技术,那么他跟传统虚拟化方式有何不同呢?我们来看两张图。
从上面两张图可以看出:传统虚拟机技术是虚拟出一套硬件后,在这硬件上面运行一个完整的操作系统。然后在该操作系统再运行所需应用进程。 而容器内的应用进程直接运行于宿主的内核。容器本身没有自己的内核,而且也没有进行硬件模拟。
因此容器要比传统虚拟机来得更加的轻便。
Docker 的优势
更高效的利用系统资源
Docker 无需硬件模拟、运行完整操作系统,开销小,系统利用率高。相同配置的主机,可以运行更多数量的应用。
更快速的启动时间
传统虚拟机启动服务时间往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核,无需启动完整操作系统。 因此可以做到秒级、甚至毫秒级的启动时间。
一致的运行环境
开放过程中一个常见的问题是环境一致性的问题。Docker 提供了除内核外完整的运行时环境,确保了应用运行环境一致性。
代码在我本地是好的 这句话将成历史。
Docker基本概念
Docker其实非常简单。就三个概念 * 镜像 image * 容器 container * Docker Registry
理解了这三个概念后,再学一些基本的操作命令,你就可以为项目写 Dockerfile 了。 #### 镜像 Image
镜像是一个特殊的文件系统。除了提供容器程序运行时所需要的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如数据卷、环境变量、用户名等)。镜像不包含任何动态数据,镜像内容在构建后不会被改变。
容器 Container
镜像和容器的关系,就像是类和实例的关系。镜像是静态的定义,容器则是镜像运行时的实体。 容器是有生命周期的。可以被创建、启动、停止、删除、暂停。 容器的实质其实是进程。但与直接在宿主环境执行的进程不同,容器进程运行与属于自己的独立的命名空间.因此容器可以拥有自己的 root 文件系统、自己的网络配置,自己的进程空间、甚至自己的用户 ID 空间。 前面说到镜像是不包含动态数据的。所有的数据都应该在容器上进行操作,利用数据卷、或者绑定宿主目录。
Registry
Docker Registry 就是类似 Github 的一个服务,你可以把你在本地生成的镜像推送上去。这样就可以在其他服务器直接该镜像进行使用,也可以把镜像公开,让别人也使用。 一个 Docker Registry 中可以包含多个 仓库 (Repository);每个仓库可以包含多个标签 Tag;每个标签对应一个镜像。 每个镜像可以用 tag 来指定具体版本的镜像。不打 tag 则默认 latest。 同样的,Docker 官方提供了私有 Registry 服务,也可以搭建私有 Registry 服务。
镜像加速
跟 npm 一样,有时候也会存在国外 Docker 镜像服务比较慢,所以催生了一批过来镜像服务。
比如 DaoCloud 镜像市场、阿里云镜像库等。
Docker 常用操作
镜像基本操作
拉取镜像
docker pull nginx
Plain Text
也可以指定 tag
docker pull nginx:latest
Plain Text
列出镜像
docker image ls [option]
Plain Text
删除本地镜像
docker image rm [options]
Plain Text
容器基本操作
前面说过容器是有生命周期的,可以被创建、启动、停止、删除。容器的基本操作也就是这几个。
启动容器
启动容器有两种方式,一种是基于镜像新建一个容器并启动。另外一种是将处于终止状态下的容器重新启动。
由于 Docker 实在是太轻量级了,所以大部分情况都是随用随创建,不用就删掉。
docker run nginx-demo -P
Plain Text
run 有一些常用的参数:
-P 参数表示随机端口映射。用于映射容器内部端口到主机的端口
-p 指定端口映射。格式为:主机端口:容器端口。比如 8083:80
-d 后台运行容器。
--name 指定容器名称。
当使用 docker run 命令去创建容器时,Docker 后台运行的操作是:
检查本地是否存在指定的镜像,不存在就从公有仓库下载
利用镜像创建并启动一个容器
分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
从地址池配置一个ip地址给容器
执行用户指定的应用程序
执行完毕后容器被终止
查看容器
docker ps // 查看当前运行的容器 docker ps -a // 查看所有容器,包含已终止的容器
Plain Text
终止容器
docker contaier stop containerid
Plain Text
启动容器
可以对已经终止的容器进行重新启动
docker container start containerid
Plain Text
删除容器
docker container [name] rm [-f]
Plain Text
上面是删除单个容器,也可以删除全部处于终止状态的容器
docker container prune
Plain Text
讲了上面的一些基本操作,我们就可以来看一个简单的 nginx 例子。
起一个 名为 mynginx 的 nginx 容器
docker run --name mynginx -d -P nginx
Plain Text
这就是最简单的一个例子了。
那问题来了?如果我们要更改 nginx 的配置呢?
这就要说到 Docker 数据管理了。
Docker 数据管理
Docker 管理数据有两种方式:
数据卷(volumes)
挂载主机目录
数据卷
数据卷是一个可供一个或者多个容器使用的特殊目录。他具有以下的特征
在容器之间共享和重用
对数据卷的修改会立马生效
对数据卷的更新不会影响容器
数据卷默认一直存在,即使容器被删除。
可以通过 docker 命令来创建数据卷。
docker volume create my-local-vol // 创建数据卷 docker volume ls // 查看所有数据卷
Plain Text
也可以查看具体数据卷的信息:
docker volume inspect my-local-vol
Plain Text
创建完数据卷后,就可以在启动容器的时候使用 --mount 将其挂载到容器里。
以前面 nginx 为例:
docker run --name mynginx -d -P --mount source=my-local-vol,target=/test nginx
Plain Text
挂载主机目录
无需创建数据卷,直接将本地主机的目录挂载到容器里。
docker run --name mynginx -d -P --mount type=bind,source=./nginx/default.conf,target=/etc/nginx/conf.d/default.conf nginx
Plain Text
上面命令就会启动一个挂载了本地nginx.conf 配置文件的 nginx 容器。
Dockerfile
前面说到镜像可以从 Docker Hub 中拉取。还有一种方式也可以构建镜像:Dockerfile。
Dockerfile 就是一个文本文件,包含了一条条的指令,用于描述如何构建镜像。
以之前我写的一个node为例:
FROM node:carbonCOPY . /wakatime-syncWORKDIR /wakatime-syncRUN npm install \&& npm install pm2 -g \&& npm run buildCMD ["pm2-runtime", "start", "pm2.json"]
Plain Text
FROM 用于指定基础镜像
COPY source target 复制文件.将当前目录所有文件复制到 容器内 /wakatime-sync 这个目录。如果目标路径不存在,会自动创建
WORKDIR 指定工作目录,指的就是当前目录。如果当前目录不存在,会自动创建。
RUN 用于执行命令行命令。这里我们用于执行 npm 命令。
CMD 用于启动容器的命令。前面说过,容器是进程。既然是进程,就需要指定所运行的程序及参数。这里是指定 pm2 作为容器的运行程序
Dockerfile 其他指令
ADD 高级的复制文件
ENV 设置环境变量
VOLUME 定义数据卷
EXPOSE 暴露端口
更多 Dockerfile 查看官方提供的 Dockerfile最佳实践
Docker Compose
Docker Compose 属于 Docker 三剑客中的一个。负责实现对 Docker 容器集群快速编排。
就像前面说的那个项目,用的就是 Docker Compose 进行编排的。一个项目通常是需要多个容器相互配合。比如Web项目,除了需要 nginx 容器本身,还需要后端运行的容器、数据库容器、甚至是负载均衡容器。
如果不通过 Docker Compose 的话,你就需要手动去管理各个容器之间的关联,这样不高效也不方便。
Compose 恰好满足这样的需求,它允许用户通过一个单独的 docker-compose.yml 模板文件来定义一组相关联的应用容器为一个项目(project).
Compose 最重要的两个概念
服务 service:一个应用的容器。比如一个 nginx 容器就是一个 service
项目 project:由一组关联的应用容器组成的一个完整业务单元。比如前面演示的那个项目,就是属于 Project,下面掌管着多个 service。
对此我写了一个小小的demo,用于演示 docker-compose 的用处。
Github 地址: docker-demo。 该 demo 演示了如果通过 docker-compose 来组织管理一个典型的包含前端(React)+ 后端(Node.js)+ 数据库(Mongodb)的应用。
参考资料