微服务与Docker
了解一下微服务运行所需要的容器技术,以及打造在实际生产环境中如何自动构建发布管道
11.1 Docker简介
被认为是有可能改变软件行业系统交付流程现状的最佳工具
世界领先的软件容器虚拟化平台
Linux容器(Linux Containers, LXC),它不像虚拟机那样模拟运行一个完整的操作系统,而是对进程进行隔离。或者说,Linux容器就像是一个箱子,里面放了一系列的进程,从而将这些进程与操作系统进行隔离。正因为容器是进程级别的,所以相比虚拟机有很多的优势;如
容器启动相当于启动本机上的一个进程,而且多个容器间的资源是可以共享的;
由于容器仅是进程的集合,而且仅包含所需的组件即可,因此体积占用非常小;
Linux容器是属于系统底层的一种技术,而且使用起来也不方便,所以Docker就基于Linux容器进行了封装,并提供了简单易用的容器接口。
Docker可以很方便地将软件与所需要依赖的库或组件打包整合到一个镜像文件里,然后运行这个镜像,就生成了一个虚拟容器。同时,配置好的镜像文件可以很容易地通过Docker的接口进行备份导出,上传到仓库,从而达到复用的目的
优点:·占用资源极少;·更快的启动速度;·更轻量的体积;·更好的复用性。
11.2 Docker的使用
Docker的出现可以说将DevOps(开发运维一体化)过程变得更加自动化、便捷,加速了软件和服务的交付。通过自动化持续构建工具,开发人员提交代码后,就会检测代码的变动,然后自动将新的代码构建成Docker镜像并进行部署,部署成功后直接通知测试人员进行测试
适用场景:·持续构建与持续交付;·更加自动、轻量、快捷的DevOps流程;·弹性云服务的动态扩容与缩容;·搭建微服务架构。
使用了Docker后,可以基于Tomcat镜像将WAR包复制到自定义构建的镜像中,然后直接在服务器中运行镜像即可。
11.2.1 安装
企业版EE提供了一些社区版CE没有的高级功能,如LDAP/AD用户集成、基于角色的访问控制和安全扫描等。
https://www.docker.com
安装:sudo apt-get install docker-ce
测试:sudo docker run hello-world该命令将下载一个测试镜像(hello world)并在容器中运行。
在Linux操作系统上,由于Docker守护进程始终以root用户身份运行,可以将普通用户添加到Docker分组中,省去sudo命令,Docker分组将授予等同于root用户的特权。;
添加docker分组
sudo groupadd docker
添加指定用户到分组
sudo usermod -aG docker $USER
注销并重新登录,使起效;如果是SSH远程用户,退出重登;
检测:docer run hello-world
命令使用:https://docs.docker.com/
docker:查看Docker所支持的所有命令
docker COMMAND --help:列出对应命令的相关帮助信息
11.2.2 镜像
三个概念:仓库、镜像和容器
Docker将应用程序及其依赖的库等打包到同一个文件里从而形成镜像,镜像可以包含完整的操作系统,也可以仅包含Tomcat或JDK运行环境。镜像被创建后,可以保存在本地,也可以上传到仓库,所以Docker仓库就是用于存放镜像的地方。
容器是基于镜像运行的虚拟实例,在服务器允许的情况下,可以无限创建容器。
Docker在设计时利用Union File System(联合文件系统)技术来存储镜像。Union File System是一种轻量级高性能分层文件系统,它支持对文件系统的修改作为一次提交来一层层地叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。
Union File System是镜像的基础,镜像可以通过分层来实现继承。得益于这种技术,使镜像的复用、定制变得更容易,基于基础镜像可以制作各种各样的镜像。由于镜像是通过分层存储的,在构建镜像时会一层层叠加,后一层会叠加在前一层上,因此通过Dockerfile来构建镜像时,尽量减少构建层数,每一层仅包含该层需要的东西即可。
使用Dockerfile来构建镜像:
1.列出本机镜像 docker images
指定镜像的详细信息 docker image insect [IMAGE ID]
2.从仓库拉取镜像docker pull NAME[:TAG]从仓库中选取某个镜像作为基础镜像,然后通过继承这个基础镜像来定义出适合自己使用的镜像。
TAG为镜像的标签,也可以理解为版本,一个镜像可以存在多个标签,每次构建镜像可能都会重新定义新标签。若不指定TAG,则TAG默认为latest。
在Docker中最常使用的JDK镜像是openjdk镜像,该镜像在官方仓库拥有众多的标签
3.Dockerfile文件
用来在实际应用中可能需要配置镜像内部时区、UTF-8编码及运行内存等;
Dockerfile是一个文本文件,其中包含了指令(Instruction)信息,每一条指令构建一层。因此每一条指令的内容就是描述该层应当如何构建。下面基于前面拉取的镜像openjdk:8u131-jre增加一些配置来构建我们所需要的JDK镜像。在指定目录内创建名为Dockerfile的文件,并增加如下内容:
# 基于openjdk的8u131-jre版本构建
FROM openjdk:8u131-jre
# 维护者
MAINTAINER microserv-usr
# Java环境变量
ENV JAVA_OPTS="-server -Xmx1G -Xms1G -Xmn200M -Duser.timezone=GMT+08"
# 容器运行执行命令
# 默认运行 /jar/app.jar
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -jar /jar/app.jar" ]
保存后,在Dockerfile文件所在的目录下,通过下面的命令来构建:
docker pull microserv/openjdk:1.0.0
从构建过程日志输出来看,定制镜像就是定制每一层所需要的配置、文件,而每一条指令则会将构建增加一层,而层数的多少会直接影响镜像的体积、构建速度,所以应尽量减小指令条数。
Dockerfile文件常用指令:
·FROM:指定基于哪个基础镜像构建,这个指令是必须有的。
·COPY:将构建目录上下文中的文件或目录复制到镜像内。
·ADD:和COPY性质基本一致,但比COPY更高级,比如可以指定通过网络URL进行下载。若从本地复制文件到镜像中,则推荐使用COPY。
·ENV:设置环境变量。
·ARG:效果和使用ENV命令的效果是一样的,区别是,ARG命令设置的环境在未来运行的容器中是不存在的。
·EXPOSE:暴露镜像所占用的端口,未来容器运行时所提供的服务端口。若容器中所运行的应用,如Tomcat有特定端口,建议都设置此参数,这样可以明确告诉使用者服务端口是哪个。
·RUN:执行命令行。此指令特别有用,尤其是镜像需要安装依赖、创建用户等操作,通过RUN可以很简单的向镜像内添加这些东西。但有一点需要注意,如果执行多个命令时,则尽量拼接在一层中去处理,如apt-get update && apt-get install nano。
·WORKDIR:指定工作目录。
·USER:指定容器运行所使用的用户。例如,运行Tomcat容器,可以将Tomcat指定为特定用户才允许运行。
·CMD:容器启动命令。若容器运行时需要启动某个脚本或应用,可以通过该参数进行设置,如打印字符串CMD [ “sh”, “-c”, “echo hello cmd” ]。
·ENTRYPOINT:和CMD目的一样,都是在指定容器中启动程序及参数。CMD的参数设置更像是指定了默认值,容器运行时可以覆盖参数值,而ENTRYPOINT则表示容器运行时所需要的初始参数,这些参数不可被重写覆盖。
Dockerfile文件时一些常用的指令介绍官方文档:https://docs.docker.com/engine/reference/builder/
4.上传镜像
上传镜像到仓库前,需要先到镜像仓库中申请账号密码,账号申请、镜像上传和下载都是免费的。
账号申请好以后还需要创建一个仓库组织
Docker镜像的其他常用操作还有两个。
·删除指定镜像:docker rm [REPOSITORY | IMAGEID]
·批量删除未被使用的镜像:docker rmidockerimages -aq
技巧:有时下载镜像可能会遇到下载不完整而出现None这样的一些镜像,可以通过命令docker images --no-trunc|grep none | awk ‘{print $3}’ | xargs -r docker rmi进行批量清理。
11.2.3 容器
基于某个镜像,可以创建多个容器,而且容器之间是相互隔离互不影响的,它们各自拥有唯一的ID和名字,这样能够更有效地保护各个容器能够正常运行而不受其他容器的影响。
我们可以将应用程序复制到容器内运行,也可以通过挂载宿主机上的应用程序文件来运行。通过挂载宿主机的文件到容器内部有很多好处,其中之一就是停止删除容器后所挂载的文件不会丢失,它们依然会被保留在宿主机内部。
这种挂载的行为被称为数据卷,运行容器时通过-v参数将宿主机上的某个文件或目录挂载到容器内部指定的文件或目录下,这样在容器内部就可以对挂载的文件或目录进行操作。若使用Docker部署应用到生产环境中,都推荐将相关文件目录挂载到宿主机上,如日志文件和数据文件等,避免删除容器后造成文件丢失。
docker ps:列出本机正在运行的所有容器
若查看所有,加参数-a;Exited表示该容器已退出
docker start [image…]:启动容器命令
docker restart [image…]:重启容器命令
image…表示容器名或者容器ID
docker stop [images …]:停止容器
docker rm [images …]:·删除容器
容器被删除后,除非内部文件被挂载到宿主机上,否则在容器内部修改或添加的东西都将会丢失。
docker run [options]:新建并运行容器,参数配置,如指定后台运行模式、容器名称、数据卷挂载等。
11.2.4 容器实战:MySQL
1拉取docker pul mysql:5.7
2.创建MySQL数据文件存储目录,增加相应的自定义配置文件
#设置UTF-8,避免查询乱码
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
[mysqld]
# 增加对emoji表情存储的支持
collation-server=utf8mb4_unicode_ci
character-set-server=utf8mb4
default_password_lifetime=0
# 将时区设置为东八区
default-time-zone='+8:00'
新建并运行MySQL容器:
$ docker run --name mysqldb -d \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=rootPwd2175 \
-e MYSQL_USER=mysqlusr \
-e MYSQL_PASSWORD=mysqlUsr6335 \
-e LANG=C.UTF-8 \
-v /etc/localtime:/etc/localtime \
-v /usr/local/springcloud/docker/mysql/conf.d:/etc/mysql/conf.d \
-v /usr/local/springcloud/docker/mysql/data:/var/lib/mysql \
-v /usr/local/springcloud/docker/mysql/dumps:/var/lib/dumps \
mysql:5.7
这里将所要运行容器的名称设置为mysqldb.成功后将在终端打印出容器的唯一ID。
类似于MySQL,基本上官方(具体应用的厂商)所提供的镜像都会有各种相应参数设置,如Nginx、Gitlab、Redis等。参数-d则表示指定该容器在后台运行。
另外,我们可以结合前面的知识使用Dockerfile将上面MySQL相关的配置构建成一个适合自己的基础镜像,这样以后在使用时可以免去这些配置,当然,如数据挂载目录这些配置还是不可以避免的。
运行容器命令中常用选项的说明如下:
·–name:指定容器的名称。·-d:在后台运行容器并打印容器ID,若不设置则默认在前台运行,终端退出后,容器也会跟着退出。·-p:将镜像中暴露的端口号映射到宿主机上,这个配置很重要,若镜像有特定端口而容器不映射出来,那么外网将访问不到该容器。·-e:设置环境变量。·-v:挂载宿主机文件目录到容器内部。·–link:连接某个容器,如—link mysql:mysql会在当前容器的host文件内加入名为mysql的主机,这样容器可以无须知道MySQL容器的IP就能通过别名MySQL进行连接。但有个缺点:一旦MySQL重建或重启,则容器也必须重新启动才可重新连接到MySQL上,所以当需要连接容器时一般推荐通过IP+端口的方式进行访问。
11.3 Docker与Spring Cloud微服务
Maven本身提供集成到Docker的插件,构建出来的镜像文件一般都比较大。
推介Linux Shell脚本方式,发布流程如下:
(1)预先构建好基础镜像,并推送到仓库中,发布的时候可直接复用,不用再次构建。(2)本地对所要发布的微服务应用进行编译打包,得到JAR包或WAR包。(3)使用Linux工具scp,将JAR包或WAR包上传到Docker宿主服务器上。(4)备份正在运行的项目,包括JAR包或WAR包、日志文件等(这一步可省略)。(5)使用基础镜像通过挂载数据卷方式,启动并运行微服务应用。
优势:·无须修改源码或配置。·可直接复用构建好的基础镜像来运行应用。·应用文件如JAR包或WAR包独立,不用打包到镜像中,也不用推送到仓库中。·通过集成Jenkins工具可以直接复用shell脚本来实现自动化部署。·通过Linux Shell脚本可以将应用的备份、发布动作在同一个任务内完成。
11.3.1 部署Eureka服务
以服务治理服务器的发布为例,
首先,在项目目录内创建shells目录,并在该目录下创建下面两个文件。·release-docker.sh:发布脚本,运行Docker应用,需要上传到服务器。·build.sh:用于应用的编译打包,上传到服务器,最后执行发布脚本。
release-docker.sh脚本的具体内容如下:
#! /bin/bash
# Docker容器基本信息
dockerName="servdiscovery"
dockerPort="8260"
# 挂载路径建议为绝对路径
dockerJarVolumn="/home/hucw/springcloud/${dockerName}"

# 停止删除现有容器
echo "停止删除容器:${dockerName}"
docker stop ${dockerName} && docker rm ${dockerName}

# Docker容器运行命令
echo ""
docker run --name=${dockerName} -d \
-p ${dockerPort}:${dockerPort} \
-v ${dockerJarVolumn}/jar:/jar \
microserv/openjdk:1.0.0

echo "${dockerName}容器已启动,使用命令查看启动日志:docker logs --tail=500
${dockerName}"
release-docker.sh发布脚本是要上传到服务器上执行的,主要用来运行Docker容器。如果需要备份,则在该脚本中直接编写相关命令即可。运行的容器是基于前面所构建的基础镜像microserv/openjdk:1.0.0,在这个镜像的Dockerfile文件中定义了默认运行文件/jar/app.jar。因此我们需要将服务治理应用打包后的文件名称更改为app.jar,并通过-v参数将该文件挂载到容器中,这样容器在启动时就可以直接运行服务治理应用。另外,在该脚本中将容器所暴露的端口设置为8260,也就是服务治理应用的端口。
build.sh脚本的具体内容如下:
#! /bin/bash
# 进入脚本所在目录,然后返回项目根目录
scriptPath="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $scriptPath
cd ..

# 服务器SSH配置
sshIP=yourserverIP
sshUsr=yourUser
sshPwd=yourpass
sshPort=22

# Docker容器基本信息
dockerName="servdiscovery"

# 编译打包
mvn clean package

# 复制JAR包到目录下
outputPath="${scriptPath}/${dockerName}";
if [ -d ${outputPath} ]; then
rm -rf ${outputPath}
fi
mkdir ${outputPath} && mkdir ${outputPath}/jar

cp ./target/*.jar ${outputPath}/jar/app.jar
cp ${scriptPath}/release-docker.sh ${outputPath}/release-docker.sh

# 删除服务器中已存在的目录
cd ${scriptPath}
appPath="~/springcloud"
ssh -p ${sshPort} ${sshUsr}@${sshIP} "[-d ${appPath}]||mkdir -p $
{appPath}"
ssh -p ${sshPort} ${sshUsr}@${sshIP} "[-d ${appPath}/${dockerName}]&&
rm -rf ${appPath}/${dockerName}"
ssh -p ${sshPort} ${sshUsr}@${sshIP} "[-d ${appPath}/${dockerName}]||
mkdir -p ${appPath}/${dockerName}"

# 将整个目录上传到服务器上
scp -r -P ${sshPort} ./${dockerName} ${sshUsr}@${sshIP}:${appPath}

# 远程执行发布命令
ssh -p ${sshPort} ${sshUsr}@${sshIP} "sh ${appPath}/${dockerName}/release-
docker.sh"
在build.sh脚本中先定义了编译发布所需要的相关变量值,如SSH配置,然后通过Maven命令对微服务应用进行编译打包。打包成功之后,将所生成的微服务应用JAR文件复制到指定目录下,并上传到服务器上,最后再远程调用执行发布脚本release-docker.sh发布应用。在该脚本中涉及较多的SSH命令操作,SSH是一种加密的网络传输协议,基本上每个Linux系统中都会有这些命令,稍加学习就可以掌握。
部署服务治理服务器:
sh ./shells/build.sh
可以登录到宿主服务器中通过命令docker logs --tail=500 servdiscovery来查看服务日志信息.
11.3.2 部署应用微服务
下面我们把用户微服务和商品微服务也部署上去。首先把service-discovery项目中的shells目录分别复制到user-service和product-service目录下,然后分别将build.sh和release-docker.sh脚本中的容器名称和端口号修改如下。
·user-service:将dockerName修改为userservice,将dockerPort修改为2100。
·product-service:将dockerName修改为productservice,将dockerPort修改为2200。
修改完毕后,分别执行微服务的build.sh脚本,可以到服务器中查看service-discovery服务的Docker日志进行确认;
docker logs --tail=500 servdiscovery
11.4 微服务与Jenkins
可以检测到微服务源码的变化,然后自动构建部署,从而以达到持续集成发布的目的呢?
一款轻量级开源的工具——Jenkins。
Jenkins是一个用Java编写的开源的持续集成工具,它提供了软件开发的持续集成服务,可用于自动执行、构建、测试、交付或部署相关任务。Jenkins可以执行基于ApacheAnt和Apache Maven所构建的项目,以及任意的Shell脚本和Windows批处理命令。同时, Jenkins也是一个高度可扩展的产品,提供了强大的插件生态环境,通过安装插件几乎能够满足任何你想要的构建任务。
11.4.1 安装Jenkins
Jenkins可以直接通过Docker安装、运行,也可以通过任何安装了Java运行时环境(JRE)的计算机独立运行。这里推荐在已安装了JDK环境的计算机上安装使用.
如果通过Docker来运行Jenkins的话,在使用过程中会产生一些问题,一方面是由于Jenkins本身的配置问题,另外一方面是在构建任务时需要依赖。比如,当所构建的前端项目需要依赖Node.js时,就需要在容器内部安装Node.js,一旦容器出现问题需要移除,那么这些在容器内部安装的依赖就会丢失,需要再次进行安装。
下载官方提供的WAR包并将其存放到对应的目录下然后运行即可。
linux下:
wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war
java -jar jenkins.war --httpPort=8080
运行后访问地址http://servip:8080
11.4.2 Jenkins配置
首先需要在Jenkins中配置JDK和Maven这两个工具。通过**“系统管理”|“全局工具配置”**命令进入配置界面;
Jenkins中的全局工具提供了两种安装方式:一种是自动安装,通过指定名称和版本,Jenkins会自动下载并安装,但安装JDK需要提供Oracle官网的账号及密码;另一种是自定义安装(在安装界面中取消勾选自动安装选项)
如果项目中还需要Git、Gradle、Docker等配置,可以自行完成。
此外,Jenkins还提供了本身的自定义配置,如工作目录、邮件通知配置等,都可以在系统管理下看到相关配置。若需要进行权限控制,比如某个用户只能看到某些任务,Jenkins也提供了完整的权限控制配置,在系统管理下的“管理用户”中就可以完成配置,配置步骤首先新建一个用户,然后转到“全局安全配置”页面进行权限分配。
Jenkins权限配置主要是授权策略,可以根据不同的授权策略控制赋予用户权限,但这种配置方式略显复杂,可以使用Role Strategy Plugin插件简化配置。
11.4.3 构建任务
1在新增构建任务前,需要先将所构建的微服务项目源码上传到Git服务器中,如GitHub。
2然后还需要增加一个MavenIntegration插件,用于构建Maven风格的项目。
安装方式非常简单,在插件管理页面中,选择Maven Integration选项,如图11-21所示,直接安装即可
3在首页单击“新建任务”按钮,填写任务名称build-productservice,并选择“构建一个maven项目”选项
单击“确定”按钮后进入项目配置界面,填写微服务源码的GitHub地址
4然后对构建触发器进行配置,所谓构建触发器是指由Jenkins主动去检测微服务源码是否有变化,一旦检测到有变化,就可以执行自动构建并部署。在该配置中有一个Poll SCM选项,意思是通过定时检查源码是否有变化,检测的标准则是SCM软件中的相应版本号,若有更新则拉取最新代码然后执行构建任务,单击该选项右侧的问号图标,会有详细说明,读者可以详细了解一下。
5在进入正式构建前,还可以增加Maven命令来检测项目源码是否可正常编译成功,只有编译成功后才可以继续往下执行具体的构建。
我们前面已经使用Shell编写了发布脚本,因此这里可以直接进行复用。不过需要进行一些改动,因为在本示例中构建的任务是直接发布微服务到Jenkins所在的服务器上,所以前面脚本中的SSH远程操作部分可以删除。为了能够兼容手工发布的方式,将新建一个文件夹build-jenkins用于存放Jenkins部署需要的脚本,而将原来的部署脚本移入到build目录下,
最终商品微服务目录结构图
修改后的build.sh脚本文件内容如下:
#! /bin/bash
# 进入脚本所在目录,然后返回项目根目录
scriptPath="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $scriptPath
cd ../../
# Docker容器基本信息
appHome="/home/hucw/springcloud"
dockerName="productservice"
dockerPort="2200"
dockerJarVolumn="${appHome}/${dockerName}"
# 编译打包
mvn clean package
# 将Jar包复制到目录下
outputPath="${scriptPath}/${dockerName}";
if [ -d ${outputPath} ]; then
rm -rf ${outputPath}
fi
mkdir ${outputPath} && mkdir ${outputPath}/jar
cp ./target/*.jar ${outputPath}/jar/app.jar
# 将整个目录复制到应用目录中
cd ${scriptPath}
cp -rf ${outputPath} ${appHome}/
# 停止删除现有容器
echo "停止删除容器:${dockerName}"
docker stop ${dockerName} && docker rm ${dockerName}
# Docker容器运行命令
echo "运行容器"
docker run --name=${dockerName} -d \
-p ${dockerPort}:${dockerPort} \
-v ${dockerJarVolumn}/jar:/jar \
microserv/openjdk:1.0.0

然后在Jenkins的Post Steps配置中使用Execute shell方式执行构建任务,其配置如图11-27所示。
单击“保存”按钮创建任务,回到任务页面后单击左侧的“立即构建”链接,将会在构建历史列表中出现构建任务进度
单击构建的进度条,查看构建日志输出;
如果构建过程中没有出现错误,会自动部署运行商品微服务的Docker容器Jenkins除了用来实现持续构建外,还有其他很多的应用场景,如iOS/Android打包平台、自动化测试持续集成等。
11.5 微服务编排
前面讲过可以通过Dockerfile创建一个属于自己的镜像,然后使用该镜像来运行一个单独的应用容器。但在实际生产中,通常一个应用需要多个微服务相互配合才能提供完整的功能。如果不进行容器间的编排,通过docker run命令方式直接启动多个容器是比较烦琐的
单独使用Docker进行微服务的集群部署是无法做到的,必须与其他工具一起配合才能够打造出高可用的集群服务。
1.Docker Compose工具
是Docker官方的开源项目,负责实现对Docker容器集群的快速编排,允许用户通过一个单独的docker-compose.yml文件将一组相关联的应用容器定义为一个项目
version: "2"
services:
mysqldb:
image: mysql:5.7
ports:
- "3306:3306"
web:
image: tomcat:8.5-jre8
volumes:
- ./webapps:/usr/local/tomcat/webapps
links:
- mysqldb

然后就可以通过docker-compose up命令来整合、启动相关的容器。
2.Docker Swarm工具
Docker官方的开源项目,负责提供Docker容器集群服务,是官方提供给云生态支持的核心方案。通过Docker Swarm项目可以将一群Docker宿主机变成一个单一的虚拟主机,从而让使用者感觉是一台容器。
Docker Swarm可以通过标准的Docker镜像来安装,而无须外部其他依赖。安装完后可通过命令创建集群并启动Swarm,然后再将其他正在运行的Docker主机逐步加入到集群中。
3.Kubernetes(K8s)工具
Google十多年大规模容器管理技术Borg的开源版本,用于容器集群管理,可以实现容器集群的自动化部署、扩容、缩容、维护等处理。
·自动化容器的部署和复制;
·随时扩展或收缩容器规模;
·将容器组织成组,并且提供容器间的负载均衡;
·很容易地升级应用程序容器的新版本;
·提供容器弹性,如果容器失效就替换它。
入门门槛稍高,首先需要理解它的一些概念,如Pod、Label、Service和Node等,然后需要学习其所提供的一套指令和配置文件