<-

Docker与容器化技术

作为开发人员,你是否曾经感叹应用程序的部署和环境配置过程的纷繁复杂?有没有遇到过在开发环境好用,但是到了测试和商场环境就不好用的情况?有没有遇到过新同事加入项目组需要花费大量的时间来配置开发环境的问题?有没有遇到过花了一整天甚至更长的时间一步一步按照配置部署文档来配置环境,但是其中却卡在中间某一个步骤上再过不去的问题?Docker了解一下。

Docker的基本概念

Docker是一个用于构建、运行和分享应用程序的平台。就像它的logo表达的那样可以将应用程序打包成一个个的集装箱把它运送到任何需要的地方。利用Docker我们可以将应用程序和它运行时所需要的各种依赖、第三方软件库、配置文件等打包在一起,以便在任何环境中都可以正确的运行。

比如我们写了一个网站用到了现在比较流行的前后端分离架构,前端使用Vue框架来构建网站的界面,后端使用Java的Spring Boot微服务框架来提供各种服务和接口,然后使用MySQL数据库来存储数据。如果没有Docker,我们可能需要在本地先安装前端Node.js环境、各种NPM依赖包、Java运行环境和SpringBoot微服务的各种第三方依赖包,以及MySQL数据库,配置各种环境变量,然后再启动这些服务网站才能正常运行起来。

如果项目规模再大一点,可能还需要配置Redis缓存,Nginx负载均衡,甚至各种微服务框架等等。如果还需要把这个网站部署到测试环境或者生产环境上,那么刚刚所有的步骤都需要在新的环境再来一遍。利用Docker我们就可以将它们打包成一个个的集装箱,只要你在开发环境中运行成功了,那么在其他环境中也一定可以运行成功。

Docker和传统虚拟机的区别

也许你听说过或者曾经使用过VMware等虚拟机软件以及Windows的WSL和Hyper-V功能。我们可以在Windows中通过WSL安装和使用Linux系统,也可以在Mac上通过虚拟机软件运行Windows和各种Linux系统。它们是完整的操作系统,和实际的Windows和Linux系统一样,可以在这个操作系统中运行应用程序。这是通过一种叫做虚拟化的技术来实现的。

虚拟化技术是一种将物理资源虚拟为多个逻辑资源的技术,它可以将一台物理服务器虚拟成多个逻辑服务器,每个逻辑服务器都有自己的操作系统、CPU、内存、硬盘和网络接口等。它们之间完全隔离,可以独立运行虚拟机。在一定程度上实现了资源的整合,可以将一台服务器的计算能力、存储能力、网络资源分配给多个逻辑服务器,实现多台服务器的功能,但是它的缺点也非常明显,每台虚拟机都需要占用大量的资源比如CPU、内存、硬盘、网络等,而且启动速度非常慢,通常需要几分钟甚至几十分钟。

而大部分的情况下,我们的一台服务器上只需要运行一个主要对外提供服务的应用程序就可以了,并不需要一个完整的操作系统所提供的所有功能。拿前面的例子来说,其实我们所需要的可能只是一个Web服务器,但是虚拟机却需要启动一个完整的操作系统,包括操作系统的内核、各种系统服务、各种工具甚至图形界面,这些我们并不需要的服务占用了大量的资源,导致了资源的浪费和启动速度慢的问题。

了解了虚拟机之后,我们再来看一下容器,这里需要注意的是Docker和容器是两个不同的概念,Docker非常的流行以至于很多人把Docker和容器混为一谈,其实Docker只是容器的一种实现,是一个容器化的解决方案和平台,而容器是一种虚拟化技术,和虚拟机类似也是一个独立的环境,可以在这个环境中运行应用程序。和虚拟机不同的是它并不需要在容器中运行一个完整的操作系统,而是使用宿主机的操作系统,所以启动速度非常快,通常只需要几秒钟,同时因为需要的资源更少所以可以在一台物理服务器上运行更多的容器。这样就可以更加充分的利用服务器的资源,减少资源的闲置和浪费。比如我们一台物理服务器上可能只能运行几个虚拟机,但是却可以运行上百个容器,这就是容器和虚拟机的一些主要区别。

镜像、容器和仓库

Docker中有几个比较重要的概念:镜像、容器和仓库。

镜像是一个只读的模板,它可以用来创建容器。容器是Docker的运行实例,它提供了一个独立的可移植的环境,可以在这个环境中运行应用程序。Docker仓库是用来存储Docker镜像的地方,最流行和最常用的仓库就是Docker Hub,它是一个公共的Docker仓库,用来集中存储和管理Docker镜像,我们可以在那里下载各种镜像,也可以将自己的镜像上传到上面,这样就可以实现镜像的共享和复用,这也是Docker非常流行的一个重要原因。

理解了这些概念也就理解了Docker的生命周期和基本原理,尤其是镜像和容器,它们是Docker的核心概念,需要对这两个概念有一个深刻的理解和认识。这对于Docker的学习和使用有非常大的帮助。

Docker的安装

Docker的安装非常简单,我们只需要在官网下载对应的安装包,然后双击即可完成安装。启动Docker之后你可以在终端或者命令行中使用Docker的各种命令,输入docker –version命令,能看到Docker的版本信息就说明Docker已经安装成功了。

Docker的体系结构是使用Client-Server架构模式,Docker Client和Docker Daemon之间通过Socket或者Restful API进行通信。Docker Daemon就是服务端的守护进程,它负责管理Docker的各种资源,Docker Client负责向Docker Daemon发送请求,Docker Daemon接收到请求之后进行处理,然后将结果返回给Docker Client。

容器化技术

容器化,顾名思义就是将应用程序打包成容器,然后在容器中运行应用程序的过程。

这个过程简单来说可以分成三个步骤,首先需要创建一个Dockerfile来告诉Docker构建应用程序镜像所需要的步骤和配置,然后使用Dockerfile来构建镜像,接下来我们就可以使用这个镜像来创建和运行容器。

这里出现了一个新的概念Dockerfile。Dockerfile是一个文本文件里面包含了一条条的指令,用来告诉Docker如何来构建镜像,这个镜像中包括了我们应用程序执行的所有命令,也就是我们刚刚提到的各种依赖、配置环境和运行应用程序所需要的所有内容。

Hello Docker

首先创建一个Hello Docker文件夹在任意位置,然后使用VSCode或其他任何代码编辑器打开这个文件夹,在文件夹中我们创建一个index.js的文件,

console.log("hello docker")

然后在这个文件中输入一段代码让它能够输出一段内容到控制台。这里只是利用JavaScript进行简单的演示,并不需要了解JavaScript。在VS Code中打开一个终端,然后在终端命令行里面执行一下node index.js就可以看到成功输出了我们想要的内容。 Node.js是一个运行环境,它可以让我们在浏览器之外的地方运行JavaScript的代码,Node.js和JavaScript的关系就像Java和JRE的关系一样,如果想要运行Java程序那么就需要安装JRE,同样的如果想要在浏览器之外的环境中运行JavaScript的代码那么就需要安装Node.js。

当我们想要在另一个环境中运行这个应用程序需要执行哪些步骤呢?首先需要在这个环境中先安装好测试系统,然后需要安装对应版本的JavaScript的运行环境也就是Node.js,再把应用程序和它所依赖的第三方包和库复制到这个环境上,最后再执行一下命令来运行用程序。而有了Docker之后我们就可以把这些步骤写入到Dockerfile中,剩下的工作就交给Docker来自动完成。

回到VSCode,我们在项目的根目录下创建一个叫做Dockerfile的文件,

FROM node:14-alpine
COPY index.js /index.js 
CMD [ "node", "/index.js" ]

注意这个文件的命名是Dockerfile没有任何扩展名第一个字母D大写其他都小写,这是一个约定俗成的规范,如果不遵守这个规范那么Docker就无法识别这个文件。Dockerfile中我们需要先指定一个基础镜像,镜像是按层次结构来构建的,每一层都是基于上一层的,所以我们需要先指定一个基础镜像,然后在这个镜像的基础上添加我们的应用程序。我们可以从一个最基础的Linux镜像开始,然后在这个镜像基础上安装Node.js和我们的应用程序,或者我们也可以直接使用Node.js的镜像,因为这个镜像已经是基于Linux来构建的了,直接拿来使用就可以了。配置完运行环境之后还需要把我们的应用程序复制到镜像中,然后使用cmd命令在镜像中运行应用程序,到这里Dockerfile就编写完成了。回到终端,使用docker build -t hello-docker .,这里hello-docker是创建镜像的名字,在后面加上一个点表示当前目录也就是Dockerfile所在的目录。执行之后,我们的镜像就构建完成了。 可以使用docker images或者docker image ls命令来查看我们所有的镜像,这里你就会看到刚刚构建的镜像它的名字是hello-docker,冒号后面的Latest表示镜像的标签,也就是镜像的版本,如果不指定版本那默认就是Latest,如果你想指定版本那么就可以在镜像名字后面加上冒号和版本号。

使用docker run hello-docker命令运行实例,可以看到控制台中出现了我们刚刚输入的内容,说明我们的应用程序已经运行起来了。如果你想要在另一个环境中运行这个应用程序那么就只需要把这个镜像文件复制过去,然后执行一下刚刚的命令就可以了。也可以把这个镜像文件上传到Docker Hub或者Hubware镜像仓库中,

docker tag hello-docker thekingofcool/hello-docker
docker image push thekingofcool/hello-docker

然后任何人都可以在任何地方使用docker pull thekingofcool/hello-docker命令来下载这个镜像文件,然后运行这个应用程序。

Docker Volume

Docker容器有一个特点就是容器中的数据不会持久化,当我们创建一个容器的时候它通常以一个干净的文件系统开始,容器启动之后我们可以在容器中创建文件、修改文件。但是当容器被停止之后,容器中的所有数据都会丢失掉。如果我们想要持久化容器中的数据的话,需要用到Volume这个概念。它可以把容器中的目录或者指定路径映射到宿主机的某一个目录或者位置上,这样就可以将数据保存到宿主机的磁盘上,实现了数据的持久化。

Docker Compose

Docker Compose是由Docker官方开源的项目,是一个用来定义和运行多个Docker容器应用程序的工具。比如前面提到过的搭建一个网站使用到前端、后端、数据库甚至缓存、负载均衡等多个服务器,这些服务都是独立的,但是它们之间又有关联需要相互配合来工作。前端需要连接后端,后端需要连接数据库,这些服务之间的关联关系就是Docker Compose要解决的问题。它通过一个单独的docker-compose.yml配置文件来将这一组互相关联的容器组合在一起形成一个项目,然后使用一条命令就可以启动、停止或者重建这些服务,这样就可以非常方便地管理这些服务。

如果你的项目组中来了一个新同事,之前他可能需要半天时间去安装各种依赖和配置运行环境,现在有了Docker Compose之后,他只需要执行Docker Compose命令,就可以自动安装各种依赖和配置运行环境,然后在本地运行项目了。大大提高了开发效率,减少了沟通成本。

Happy hacking.