在没有 Docker 的时代,咱们会使用硬件虚拟化(虚拟机)以提供隔离。这里,虚拟机经过在操做系统上创建了一个中间虚拟软件层 Hypervisor ,并利用物理机器的资源虚拟出多个虚拟硬件环境来共享宿主机的资源,其中的应用运行在虚拟机内核上。可是,虚拟机对硬件的利用率存在瓶颈,由于虚拟机很难根据当前业务量动态调整其占用的硬件资源,所以容器化技术得以流行。其中,Docker 是一个开源的应用容器引擎,让开发者能够打包他们的应用以及依赖包到一个可移植的容器中,而后发布到任何流行的 Linux 机器上。nginx
Docker 容器不使用硬件虚拟化,它的守护进程是宿主机上的一个进程,换句话说,应用直接运行在宿主机内核上。由于容器中运行的程序和计算机的操做系统之间没有额外的中间层,没有资源被冗余软件的运行或虚拟硬件的模拟而浪费掉。git
Docker 的优点不只如此,咱们来比较一番。github
特性 | Docker | 虚拟机 |
---|---|---|
启动速度 | 秒级 | 分钟级 |
交付/部署 | 开发、测试、生产环境一致 | 无成熟体系 |
性能 | 近似物理机 | 性能损耗大 |
体量 | 极小(MB) | 较大(GB) |
迁移/扩展 | 跨平台,可复制 | 较为复杂 |
Docker 由镜像(Image)、容器(Container)、仓库(Repository) 三部分组成。web
Docker 的镜像能够简单的类比为电脑装系统用的系统盘,包括操做系统,以及必要的软件。例如,一个镜像能够包含一个完整的 centos 操做系统环境,并安装了 Nginx 和 Tomcat 服务器。注意的是,镜像是只读的。这一点也很好理解,就像咱们刻录的系统盘其实也是可读的。咱们可使用 docker images
来查看本地镜像列表。docker
Docker 的容器能够简单理解为提供了系统硬件环境,它是真正跑项目程序、消耗机器资源、提供服务的东西。例如,咱们能够暂时把容器看做一个 Linux 的电脑,它能够直接运行。那么,容器是基于镜像启动的,而且每一个容器都是相互隔离的。注意的是,容器在启动的时候基于镜像建立一层可写层做为最上层。咱们可使用 docker ps -a
查看本地运行过的容器。shell
Docker 的仓库用于存放镜像。这一点,和 Git 很是相似。咱们能够从中心仓库下载镜像,也能够从自建仓库下载。同时,咱们能够把制做好的镜像 commit 到本地,而后 push 到远程仓库。仓库分为公开仓库和私有仓库,最大的公开仓库是官方仓库 Dock Hub,国内的公开仓库也有不少选择,例如阿里云等。ubuntu
笔者认为,Docker 对开发流程的影响在于使环境标准化。例如,原来咱们存在三个环境:开发(平常)环境、测试环境、生产环境。这里,咱们对于每一个环境都须要部署相同的软件、脚本和运行程序,如图所示。事实上,对于启动脚本内容都是一致的,可是没有统一维护,常常会出问题。此外,对于运行程序而言,若是所依赖的底层运行环境不一致,也会形成困扰和异常。windows
如今,咱们经过引入 Docker 以后,咱们只须要维护一个 Docker 镜像。换句话说,多套环境,一个镜像,实现系统级别的一次构建处处运行。此时,咱们把运行脚本标准化了,把底层软件镜像化了,而后对于相同的将要部署的程序实行标准化部署。所以,Docker 为咱们提供了一个标准化的运维模式,并固化运维步骤和流程。后端
经过这个流程的改进,咱们更容易实现 DevOps 的目标,由于咱们的镜像生成后能够跑在任何系统,并快速部署。此外,使用 Docker 的很大动力是基于 Docker 实现弹性调度,以更充分地利用机器资源,节省成本。centos
哈哈,笔者在使用 Docker 过程当中,还发现了一些很棒的收益点,例如咱们发布回滚的时候只须要切换 TAG 并重启便可。还好比,咱们对环境升级,也只须要升级基础镜像,那么新构建的应用镜像,自动会引用新的版本。(欢迎补充~~~)
如今,咱们须要安装如下步骤安装 Docker。
注册账号:在 https://hub.docker.com/ 注册帐号。 下载安装
官方下载地址:(Mac): https://download.docker.com/m...
阿里云下载地址(Mac): http://mirrors.aliyun.com/doc...
阿里云下载地址(Windows):
http://mirrors.aliyun.com/doc...
安装指南
这里,双击刚刚下载的 Doker.dmg 安装包进行安装。
安装完成后启动, Mac 顶部导航栏出现了一个图标,经过菜单能够进行 docker 配置和退出等操做。
官方指南:https://docs.docker.com/install/ 阿里云指南(Linux):https://yq.aliyun.com/articles/110806?spm=5176.8351553.0.0.468b1991jdT95t
设置加速服务
市面上有不少加速服务的提供商,如:DaoCloud,阿里云等。这里,笔者使用的是阿里云。(注意的是,笔者操做系统是 Mac,其余操做系列参见阿里云操做文档)
右键点击桌面顶栏的 docker 图标,选择 Preferences ,在 Daemon 标签(Docker 17.03 以前版本为 Advanced 标签)下的 Registry mirrors 列表中将https://xxx.mirror.aliyuncs.com
加到"registry-mirrors"的数组里,点击 Apply & Restart 按钮,等待 Docker 重启并应用配置的镜像加速器。
阿里云操做文档:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
查看版本
至此,咱们已经安装完成了。这里,咱们来查看版本。
docker version
查看结果,以下所示。
咱们做为实干派,那么先来搭建一个 Web 服务器吧。而后,笔者带你慢慢理解这个过程当中,作了什么事情。首先,咱们须要拉取 centos 镜像。
docker run -p 80 --name web -i -t centos /bin/bash
紧接着,咱们安装 nginx 服务器,执行如下命令:
rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
安装完 Nginx 源后,就能够正式安装 Nginx 了。
yum install -y nginx
至此,咱们再输入 whereis nginx 命令就能够看到安装的路径了。最后,咱们还须要将 Nginx 跑起来。
nginx
如今,咱们执行 ctrl + P + Q 切换到后台。而后,经过 docker ps -a 来查看随机分配的端口。
这里,笔者分配的端口是 32769 ,那么经过浏览器访问 http://127.0.0.1:32769 便可。
大功告成,哈哈哈~
如今,咱们来理解下这个流程。首先,咱们输入 docker run -p 80 --name web -i -t centos /bin/bash
命令会运行交互式容器,其中 -i
选项告诉 Docker 容器保持标准输入流对容器开放,即便容器没有终端链接,另外一个 -t
选项告诉 Docker 为容器分配一个虚拟终端,以便于咱们接下来安装 Nginx 服务器。(笔者备注:Docker 还支持输入 -d
选项告诉 Docker 在后台运行容器的守护进程)
Docker 会为咱们建立的每个容器自动生成一个随机的名称。事实上,这种方式虽然便捷,可是可读性不好,而且对咱们后期维护的理解成本会比较大。所以,咱们经过 --name web
选项告诉 Docker 建立一个名称是 web
的容器。此外,咱们经过 -p 80
告诉 Docker 开放 80 端口,那么, Nginx 才能够对外经过访问和服务。可是,咱们的宿主机器会自动作端口映射,好比上面分配的端口是 32769
,注意的是,若是关闭或者重启,这个端口就变了,那么怎么解决固定端口的问题,笔者会在后面详细剖析和带你实战。
这里,还有一个很是重要的知识点 docker run
。Docker 经过 run 命令来启动一个新容器。Docker 首先在本机中寻找该镜像,若是没有安装,Docker 在 Docker Hub 上查找该镜像并下载安装到本机,最后 Docker 建立一个新的容器并启动该程序。
可是,当第二次执行 docker run
时,由于 Docker 在本机中已经安装该镜像,因此 Docker 会直接建立一个新的容器并启动该程序。
注意的是,docker run
每次使用都会建立一个新的容器,所以,咱们之后再次启动这个容器时,只须要使用命令 docker start
便可。这里, docker start
的做用在用从新启动已存在的镜像,而docker run
包含将镜像放入容器中 docker create
,而后将容器启动 docker start
,如图所示。
如今,咱们能够在上面的案例的基础上,经过 exit
命令关闭 Docker 容器。固然,若是咱们运行的是后台的守护进程,咱们也能够经过 docker stop web
来中止。注意的是,docker stop
和 docker kill
略有不一样,docker stop 发送 SIGTERM 信号,而 docker kill 发送SIGKILL 信号。而后,咱们使用 docker start
重启它。
docker start web
Docker 容器重启后会沿用 docker run
命令指定的参数来运行,可是,此时它仍是后台运行的。咱们必须经过 docker attach
命令切换到运行交互式容器。
docker attach web
Docker 提供了很是丰富的命令。所谓一图胜千言,咱们能够从下面的图片了解到不少信息和它们以前的用途。(能够直接跳过阅读,建议收藏,便于扩展阅读)
官方阅读连接: https://docs.docker.com/engin...
还记得笔者在文章开头介绍的「镜像、容器和仓库」吗?Docker 的仓库用于存放镜像。咱们能够从中心仓库下载镜像,也能够从自建仓库下载。同时,咱们能够把制做好的镜像从本地推送到远程仓库。
首先,笔者先引入一个知识点:Docker 的镜像就是它的文件系统,一个镜像能够放在另一个镜像的上层,那么位于下层的就是它的父镜像。因此,Docker 会存在不少镜像层,每一个镜像层都是只读的,而且不会改变。当咱们建立一个新的容器时,Docker 会构建出一个镜像栈,并在栈的最顶层添加一个读写层,如图所示。
如今,咱们能够经过 docker images 命令查看本地的镜像。
docker images
这里,对几个名词解释一下含义。
那么,若是第一次咱们经过 docker pull centos:latest
拉取镜像,那么当咱们执行 docker run -p 80 --name web -i -t centos /bin/bash
时,它就不会再去远程获取了,由于本机中已经安装该镜像,因此 Docker 会直接建立一个新的容器并启动该程序。
事实上,官方已经提供了安装好 Nginx 的镜像,咱们能够直接使用。如今,咱们经过拉取镜像的方式从新构建一个 Web 服务器。首先,咱们经过 docker search
来查找镜像。咱们获取到 Nginx 的镜像清单。
docker search nginx
补充一下,咱们也能够经过访问 Docker Hub (https://hub.docker.com/)搜索仓库,那么 star 数越多,说明它越靠谱,能够放心使用。
如今,咱们经过 docker pull nginx 拉取最新的 Nginx 的镜像。固然,咱们也能够经过 docker pull nginx:latest
来操做。
docker pull nginx
而后,咱们建立并运行一个容器。与前面不一样的是,咱们经过 -d 选项告诉 Docker 在后台运行容器的守护进程。而且,经过 8080:80
告诉 Docker 8080 端口是对外开放的端口,80 端口对外开放的端口映射到容器里的端口号。
docker run -p 8080:80 -d --name nginx nginx
咱们再经过 docker ps -a
来查看,发现容器已经后台运行了,而且后台执行了 nginx 命令,并对外开放 8080 端口。
所以,经过浏览器访问 http://127.0.0.1:8080 便可。
经过上面的学习,笔者相信你已经对 Docker 使用有了一个大体的了解,就比如咱们经过 VMware 安装了一个系统,并让它跑了起来,那么咱们就能够在这个 Linux 系统(CentOS 或者 Ubuntu ) 上面工做咱们想要的任何事情。事实上,咱们还会常常把咱们安装好的 VMware 系统进行快照备份并实现克隆来知足咱们下次快速的复制。这里,Docker 也能够构建定制内容的 Docker 镜像,例如上面咱们使用官方提供的安装好 Nginx 的 Docker 镜像。注意的是,咱们经过基于已有的基础镜像,在上面添加镜像层的方式构建新镜像而已。
总结一下,Docker 提供自定义镜像的能力,它可让咱们保存对基础镜像的修改,并再次使用。那么,咱们就能够把操做系统、运行环境、脚本和程序打包在一块儿,并在宿主机上对外提供服务。
Docker 构建镜像有两种方式,一种方式是使用 docker commit
命令,另一种方式使用 docker build
命令和 Dockerfile
文件。其中,不推荐使用 docker commit
命令进行构建,由于它没有使得整个流程标准化,所以,在企业的中更加推荐使用 docker build
命令和 Dockerfile
文件来构建咱们的镜像。咱们使用Dockerfile 文件可让构建镜像更具有可重复性,同时保证启动脚本和运行程序的标准化。
如今,咱们继续实战。这里,咱们把一开始搭建的 Web 服务器构建一个镜像。首先,咱们须要建立一个空的 Dokcerfile 文件。
mkdirdockerfile_test
cddockerfile_test/
touchDockerfile
nanoDockerfile
紧接着,咱们须要编写一个 Dockerfile 文件,代码清单以下
FROM centos:7 MAINTAINER LiangGzone "lianggzone@163.com" RUN rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm RUN yum install -y nginx EXPOSE 80
最后,咱们经过 docker build
命令进行构建。
docker build -t="lianggzone/nginx_demo:v1" .
如今, 咱们来经过 docker images
看下咱们的新镜像吧。
哇,咱们经过编写一个 Dockerfile 文件顺利构建了一个新的镜像。这个过程简单得让人没法相信。如今,让咱们来理解一下这个全过程吧。首先, FROM centos:7
是 Dockerfile 必需要的第一步,它会从一个已经存在的镜像运行一个容器,换句话说,Docker 须要依赖于一个基础镜像进行构建。这里,咱们指定 centos 做为基础镜像,它的版本是 7 (CentOS 7)。而后,咱们经过 MAINTAINER LiangGzone "lianggzone@163.com"
指定该镜像的做者是 LiangGzone,邮箱是 lianggzone@163.com。这有助于告诉使用者它的做者和联系方式。接着,咱们执行两个 RUN 指令进行 Nginx 的下载安装,最后经过 EXPOSE 80
暴露 Dokcer 容器的 80 端口。注意的是,Docker 的执行顺序是从上而下执行的,因此咱们要明确整个流程的执行顺序。除此以外,Docker 在执行每一个指令以后都会建立一个新的镜像层而且进行提交。
咱们使用 docker build
命令进行构建,指定 - t
告诉 Docker 镜像的名称和版本。注意的是,若是没有指定任何标签,Docker 将会自动为镜像设置一个 lastest 标签。还有一点,咱们最后还有一个 . 是为了让 Docker 到当前本地目录去寻找 Dockerfile 文件。注意的是,Docker 会在每一步构建都会将结果提交为镜像,而后将以前的镜像层看做缓存,所以咱们从新构建相似的镜像层时会直接复用以前的镜像。若是咱们须要跳过,可使用 --no-cache
选项告诉 Docker 不进行缓存。
Dockerfile 提供了很是多的指令。笔者这里特别整理了一份清单,建议收藏查看。
官方地址: https://docs.docker.com/engin...
RUN
、 CMD
、 ENTRYPOINT
三个指令的用途很是相识,不一样在于,RUN
指令是在容器被构建时运行的命令,而CMD
、 ENTRYPOINT
是启动容器时执行 shell 命令,而 RUN 会被 docker run
命令覆盖,可是 ENTRYPOINT 不会被覆盖。事实上,docker run
命令指定的任何参数都会被看成参数再次传递给 ENTRYPOINT 指令。CMD
、 ENTRYPOINT
两个指令之间也能够一块儿使用。例如,咱们 可使用 ENTRYPOINT 的 exec 形式设置固定的默认命令和参数,而后使用任一形式的 CMD
来设置可能更改的其余默认值。
FROM ubuntu ENTRYPOINT ["top", "-b"] CMD ["-c"]
ADD
、 COPY
指令用法同样,惟一不一样的是 ADD
支持将归档文件(tar, gzip, bzip2, etc)作提取和解压操做。注意的是,COPY
指令须要复制的目录必定要放在 Dockerfile 文件的同级目录下。
镜像构建完毕以后,咱们能够将它上传到 Docker Hub 上面。首先,咱们须要经过 docker login
保证咱们已经登陆了。紧接着,咱们使用 docker push
命令进行推送。
docker push lianggzone/nginx_demo:v1
这里,咱们了解下它的使用,格式是 docker push [OPTIONS] NAME[:TAG] ,其中,笔者设置 NAME 是 lianggzone/nginx_demo,TAG 是 v1。 (笔者注:推送 Docker Hub 速度很慢,耐心等待) 最后,上传完成后访问:https://hub.docker.com/u/lian...
远程仓库:阿里云
同时,咱们也可使用国内的仓库,好比阿里云。首先,在终端中输入访问凭证,登陆 Registry 实例。若是你不知道是哪一个,能够访问 https://cr.console.aliyun.com...。
docker login --username=账号 registry.cn-hangzhou.aliyuncs.com
如今,将镜像推送到阿里云镜像仓库。其中, docker tag [IMAGE_ID] registry.cn-hangzhou.aliyuncs.com/[命名空间]/[镜像名称]:[版本] 和 docker push registry.cn-hangzhou.aliyuncs.com/[命名空间]/[镜像名称]:[版本]
命令的使用以下所示。
docker tag 794c07361565 registry.cn-hangzhou.aliyuncs.com/lianggzone/nginx_demo:v1
docker push registry.cn-hangzhou.aliyuncs.com/lianggzone/nginx_demo:v1
最后,上传完成后访问:https://cr.console.aliyun.com...,如图所示。
这里,附上我整理的 Dockerfile 的仓库。后面,笔者会陆续更新用到的一些经常使用文件,欢迎 star 关注。
https://github.com/lianggzone...
写在末尾
【服务端思惟】:咱们一块儿聊聊服务端核心技术,探讨一线互联网的项目架构与实战经验。同时,拥有众多技术大牛的「后端圈」你们庭,期待你的加入,一群同频者,一块儿成长,一块儿精进,打破认知的局限性。
更多精彩文章,尽在「服务端思惟」!