云效(原RDC)如何构建一个基于Maven的Java项目

最近在将公司的持续集成架构做一个系统的调整,调整过程中受到了RDC团队大量的帮助,所以利用国庆时间写了几篇RDC的分享,希望能让更多的人了解和用好RDC这个产品。

我会把我最近3个月的使用体会分成5个部分:使用RDC的动机、PHP项目集成、JS项目集成、JAVA项目集成、Docker类项目集成这5个分支来写

因为近期RDC的迭代比较频繁,所以我的分享会比较的浅,点到为止,仅供参考,目录:

1、RDC如何耦合进我们的业务

2、如何构建一个基于Composer的PHP项目

3、如何构建一个基于NodeJS的前后端项目

4、如何构建一个基于Maven的Java项目

5、RDC + 容器服务完成持续集成


一、RDC基础操作

在开始一切之前您需要熟悉RDC的一些基础操作,创建一个项目,然后在这个项目中创建一个应用,然后让这个应用关联某个代码分支。这样基础工作就完成了,我这里不再赘述了,因为比较简单,只需要注册个阿里云账号,然后去 rdc.aliyun.com 创建/加入个企业就行了。

本文所有的体验均基于【自由模式】的应用。

值得一提的是,应用代码源目前支持的是阿里云的代码仓库,基于gitlab,地址是 code.aliyun.com,从我2年的使用经验来看,还算好用,也不收费,较为靠谱。

在创建应用时,我们需要选择对应的配置

创建完应用后,进入【项目】–》【流水线】,找到刚才创建应用的【同名流水线】

点击流水线名称可以看到具体的流水线运行情况和对应节点

可以看到有4个面板:构建、日常、预发、正式。

分别对应的是:构建打包、发布到日常环境、发布到预发环境、发布到正式环境。

RDC在创建应用时自动的为你生成了一个标准模板流水线,但是我们一般用不着,所以需要对流水线进行修改,去除无用的节点,添加我们自己的配置。点击界面上的【编辑流水线】按钮就可以进入修改界面。

我们先从构建开始,所以先暂时删除日常、预发、正式这3个部署节点,仅保留构建这一个节点即可。下面的配置暂时不进行调整。删除完毕后保存流水线即可,效果如下:

至此我们已经完成了基础的准备工作,下一步就开始进行代码的构建工作了。

在开始下一步工作之前,请重新git pull一下您的代码到本地,会看到一个由RDC服务自动生成的配置文件:xxx.release 这个文件相当重要,请注意,下面将会说明如何通过此文件完成个性化构建。


二、基于Maven的Java项目构建

因为java类项目一般都通过maven来维护第三方库,并且一般会通过maven来进行构建,所以在RDC构建时需要完成依赖下载及编译的相关工作。

这里需要找到我们上一章节中提到的:xxx.release 文件,xxx代表你的应用名,所以我这里看到的文件名是:ms-autotags.release

这个文件的配置规范可以参考:https://help.aliyun.com/document_detail/59293.html

打开这个文件可以看到,已经有一些预先定义好的配置:

# 构建源码语言类型
code.language=scripts

# 应用部署脚本
deploy.appctl.path=deploy.sh

# Docker镜像构建之后push的仓库地址
docker.repo=registry.cn-hangzhou.aliyuncs.com/xxx/abced

上面的配置是不能用的,我们需要将其修改为如下内容:

# 语言类型,需要修改,否则无法调用对应的构建环境
code.language=java

# JDK版本
baseline.jdk=jdk-1.8

# 构建打包所用的maven版本
build.tools.maven=maven3.2.5

#产出物
build.output=target/ms-autotags-1.0-jar-with-dependencies.jar
# 应用部署脚本,先注释掉,暂时用不上
# deploy.appctl.path=deploy.sh

↓↓↓↓ 配置说明:

code.language=java

代表使用的是java作为代码语言类型。支持以下枚举(因为RDC经常更新,请以官方为准):

php5.6,php7.0,node6.x,node7.x,node8.x,oracle-jdk1.7,oracle-jdk1.8, oracle-jdk1.9,scripts

如果有使用过jenkins的同学,那么应该比较好理解,RDC的构建是通过Docker容器技术实现的,类似于配置好环境的jenkins构建机,RDC团队针对各种语言准备了不同的镜像作为构建宿主。


build.tools.maven=maven3.2.5

使用3.2.5版本的maven。


build.output=target/ms-autotags-1.0-jar-with-dependencies.jar

指明一个产出物,可以是目录也可以是具体的文件,比如jar包或者war包。如果执行完构建后此目录、文件不存在,则代表构建失败,无法进入工作流下一环。


简单maven项目不需要设置 build.command,除非你需要设置特别的maven打包参数或有多行打包命令。


我们已经完成了应用的创建+流水线的修改,那么我们运行一次构建试一下,只需要点击【运行流水线】按钮即可,运行后等几秒刷新一下页面,效果如下:

image

可以看到执行时间、版本号、日志、操作人等信息。

如果构建失败了,可以通过构建流程—-日志详情面板看到具体的错误原因,有日志排查起来不太难,但是RDC的构建还是偏向黑盒,所以尽量熟练或在本地先把相关命令跑通后再上传到xxx.release文件里去进行RDC构建。

可以看到初始的版本号是:v0.0.1-1,如果你的构建一直失败,版本号会变成v0.0.1-3、v0.0.1-8、v0.0.1-18、v0.0.1-N。

如果你的流水线全流程跑完了,则会自动叠加一个小版本号变为v0.0.2-1,所以这种构建方式清晰明了,还算好用。


三、如何输出为一个Docker镜像

我们已经完成了代码的打包编译工作,下一步我们需要把完整的代码封装成一个Docker镜像,我们需要对xxx.release文件做如下改动:

# 语言类型,需要修改,否则无法调用对应的构建环境
code.language=java

# JDK版本
baseline.jdk=jdk-1.8

# 构建打包所用的maven版本
build.tools.maven=maven3.2.5

#产出物
build.output=target/ms-autotags-1.0-jar-with-dependencies.jar

# Docker 构建配置
docker.file=Dockerfile

# Docker镜像构建之后push的仓库地址
docker.repo=registry.cn-hangzhou.aliyuncs.com/xxx/abced

docker.tag=ci-${PACKAGE_LABEL} 

# 应用部署脚本,先注释掉,暂时用不上
# deploy.appctl.path=deploy.sh

相对于单纯的构建,如果需要生成Docker镜像则需要补充几个配置项,拆解说明如下:

docker.file=Dockerfile

指明dockerfile文件的位置和文件名,默认就是根目录下的Dockerfile文件。


docker.repo=registry.cn-hangzhou.aliyuncs.com/xxx/abced

指定你的docker镜像仓库,建议使用阿里云提供的仓库,免费,速度快,可以加速docker hub的内容,无缝对接RDC服务,地址是 dev.aliyun.com ,此处的xxx对应的是你的名称空间,abced对应的是你的镜像名称。


docker.tag=ci-${PACKAGE_LABEL}-${TIMESTAMP}

这里指定你的docker镜像的tag名,使用了环境变量进行拼接。

${PACKAGE_LABEL}代表的是包名,这个参数在流水线配置里可以改,默认是default。

${TIMESTAMP}代表的是当前时间戳,格式是:20171008224350 这种样子。

有的项目一份代码可能产生多个docker镜像就需要通过这种方式来动态生成tag名,防止覆盖,也便于回滚。

关于构建传参,可以参考这个文章: https://help.aliyun.com/document_detail/59297.html

那么此处最终生成的tag名是这样的: ci-default-20171008224350

结合仓库名和镜像名,最终会生成镜像tag地址为:

registry.cn-hangzhou.aliyuncs.com/xxx/abced:ci-default-20171008224350


四、后记

NodeJS构建 + Docker构建就说到这里,因为主要是为了介绍RDC,所以Docker部分就挑重点讲了,如何编写Dockerfile文件请自行学习。

输出成Docker镜像后,如何使用RDC部署到容器相关问题我会单独开一个文章来分享。

阿里云VPC的使用体会分享(二)

本篇主要分享一些简单的基于VPC的产品架构搭建以及搭建过程中遇到的一些问题和踩过的坑。


在《阿里云VPC的使用体会分享(一)》中我曾经介绍了EIP和SLB两种方式让VPC-ECS具备公网或部分公网能力。


本文再深入一下,介绍如何结合EIP、SLB、VPC搭建产品架构。


分享下面一个场景,以及我己的解决之道:

有些公司因为历史原因网络架构会比较复杂,业务与业务之间在不同的地域(或机房,或服务商),业务与业务之间使用公网IP完成数据交互,只允许单点入、单点出,且业务与业务间的交互使用IP白名单进行控制,这种情况下,如何使用阿里云VPC来管理公司的云上ECS资产并与其它业务完成对接

 

首先提炼几个要素:


1.需要一个统一入口,且这个入口对安全性有较高的要求。


解决方案:使用公网SLB作为统一入口,这样的好处是公网IP不能直连具体的ECS,而是通过端口监听与转发完成数据交互,且通过SLB可以弹性增减后端ECS,提高流量的抗压能力和业务稳定性。




2.需要一个统一的出口。


解决方案:统一入口已经使用SLB完成了接入,但是SLB不具备公网出口能力,这一点我在第一篇文章中已经做了说明。那么依托SLB只能完成统一公网入口的搭建,公网出口有3种方式可以实现:


①为所有的后端ECS绑定一个EIP,这样就具备了公网出口能力。问题很明显,如果后端机器大于1台,则只能做到公网出口搭建,不满足出口IP固定的需求,且为VPC-ECS绑定EIP本身具有一定的风险性。


②在VPC环境中,挑一台机器绑定一个EIP,并搭建SNAT服务(或VPN服务,原理一致,后面就不重复了),然后将VPC网络的0.0.0.0下一跳设为此ECS,用于VPC内部的流量对外转发,自建SNAT有很多种方式,我这里就不一一赘述了。
优点:无论VPC有多少个ECS,都能统一的拥有公网出口能力,且公网出口唯一、一致。
缺点:SNAT服务器本身的稳定性和会影响到整个VPC内业务稳定性,单点风险很高。


③买买买,阿里云本身提供VPC内的SNAT服务,花钱就行了,本身也不需要搭建和维护SNAT服务器,省心省力。如果你的VPC网络里指定了0.0.0.0的下一跳,则无法购买,需要先删除。


以上我提供了3种解决办法,只有适合与不适合,小型业务适合方案①,中型适合②,大型和超大型的业务适合方案③。


使用方案②和方案③最终的效果是这样的:








其实这种方式来组建VPC业务群还可以应用到一些第三方服务的对接上,比如友盟的消息推送、阿里云的短信API等,这些都是需要通过白名单验证的,VPC的统一出口可以解决白名单维护难度。


上面的方案是VPC应用中纯云端的方案,也比较简单,适合简单的业务。VPC还可以对接线下的机房,构建自己的混合云等,后面再介绍。

阿里云VPC的使用体会分享(一)

使用阿里的VPC网络已经大约有3年时间了,抽时间把相关的东西做个笔记,也算是分享吧,这里的VPC指的是阿里云的VPC服务。


首先,VPC也是分地域的,而且一个地域可以存在多个VPC专有网络,有以下的特性:


1.VPC里的ECS服务器默认不会像经典网络的ECS一样分配公网IP,它需要通过其他方式完成公网接入。


2.要求有一定的组网能力,可以通过新增交换机来划分网络区域,对使用者而言有较高的要求,并且小型用户并不是必须使用这个产品。


3.最重要的一个能力,就是安全性,因为资源池与所有其他的阿里云客户形成了逻辑硬隔离,并且结合交换机、安全组可以完成更高的安全性调配方案。


针对VPC的模式,分享几个过程性方案:


【公网暴露方案】


因为VPC默认没有公网,所以不具备接入公网的能力,无论是接收还是发送,都无法办到。那么我们在使用过程中,有几种方式可以让VPC-ECS具备访问外网的能力。


1.为某个VPC-ECS绑定一个EIP弹性公网IP,收取IP租用费+流量费,绑定后此ECS将直接暴露在公网中,具备接收与外发两种能力,与经典网络的ECS毫无二致。需要警惕黑客通过绑定了EIP的机器做跳板打穿你整个VPC网络!


2.创建一个公网SLB负载均衡,收取实例租用费+流量费,把某个(些)ECS作为此SLB的后端机器。设置好相应的监听规则,可以完成请求转发TCP/UDP都行。但是值得注意的是,通过这种方式,只能让VPC-ECS具备公网接收能力,而不具备公网外发能力,具体例子:


SLB的公网IP为:8.8.8.8,指向了VPC-ECS01这个机器,配置了端口监听8080 to 8080,那么你使用浏览器访问8.8.8.8:8080可以直接访问到VPC-ECS01的8080端口,但是VPC-ECS01本身不能向外网发送任何数据,因为SLB的特性是单向的,只是请求转发,而不像EIP那样是一个双向通道。


值得一提的是,相较于EIP的方式,通过SLB的方式完成公网暴露可以提高安全性,降低内网被攻击的可能性。局限在于VPC-ECS依旧不具备公网外发能力。


我会再写一篇讲一下VPC下一些典型的应用构建架构和更高级的公网暴露方案。

云效(原RDC)如何构建一个基于NodeJS的前后端项目

最近在将公司的持续集成架构做一个系统的调整,调整过程中受到了RDC团队大量的帮助,所以利用国庆时间写了几篇RDC的分享,希望能让更多的人了解和用好RDC这个产品。

我会把我最近3个月的使用体会分成5个部分:使用RDC的动机、PHP项目集成、JS项目集成、JAVA项目集成、Docker类项目集成这5个分支来写

因为近期RDC的迭代比较频繁,所以我的分享会比较的浅,点到为止,仅供参考,目录:

1、RDC如何耦合进我们的业务

2、如何构建一个基于Composer的PHP项目

3、如何构建一个基于NodeJS的前后端项目

4、如何构建一个基于Maven的Java项目

5、RDC + 容器服务完成持续集成


一、RDC基础操作

在开始一切之前您需要熟悉RDC的一些基础操作,创建一个项目,然后在这个项目中创建一个应用,然后让这个应用关联某个代码分支。这样基础工作就完成了,我这里不再赘述了,因为比较简单,只需要注册个阿里云账号,然后去 rdc.aliyun.com 创建/加入个企业就行了。

本文所有的体验均基于【自由模式】的应用。

值得一提的是,应用代码源目前支持的是阿里云的代码仓库,基于gitlab,地址是 code.aliyun.com,从我2年的使用经验来看,还算好用,也不收费,较为靠谱。

在创建应用时,我们需要选择对应的配置,如下图:

image

创建完应用后,进入【项目】–》【流水线】,找到刚才创建应用的【同名流水线】

image

点击流水线名称可以看到具体的流水线运行情况和对应节点,如下图:

image

可以看到有4个面板:构建、日常、预发、正式。

分别对应的是:构建打包、发布到日常环境、发布到预发环境、发布到正式环境。

RDC在创建应用时自动的为你生成了一个标准模板流水线,但是我们一般用不着,所以需要对流水线进行修改,去除无用的节点,添加我们自己的配置。点击界面上的【编辑流水线】按钮就可以进入修改界面。

image

我们先从构建开始,所以先暂时删除日常、预发、正式这3个部署节点,仅保留构建这一个节点即可。下面的配置暂时不进行调整。删除完毕后保存流水线即可,效果如下:

image

至此我们已经完成了基础的准备工作,下一步就开始进行代码的构建工作了。

在开始下一步工作之前,请重新git pull一下您的代码到本地,会看到一个由RDC服务自动生成的配置文件:xxx.release 这个文件相当重要,请注意,下面将会说明如何通过此文件完成个性化构建。


二、基于NodeJS的前后端项目构建

因为node类项目一般都通过NPM来维护第三方库,并且一般会通过webpack来进行构建、合并、压缩,所以在RDC构建时需要完成依赖包下载及webpack编译的相关工作。

这里需要找到我们上一章节中提到的:xxx.release 文件,xxx代表你的应用名,所以我这里看到的文件名是:ms-autotags.release

这个文件的配置规范可以参考:https://help.aliyun.com/document_detail/59293.html

打开这个文件可以看到,已经有一些预先定义好的配置:

# 构建源码语言类型
code.language=scripts

# 应用部署脚本
deploy.appctl.path=deploy.sh

# Docker镜像构建之后push的仓库地址
docker.repo=registry.cn-hangzhou.aliyuncs.com/xxx/abced

上面的配置是不能用的,我们需要将其修改为如下内容:

# 语言类型,需要修改,否则无法调用对应的构建环境
code.language=node8.x

#构建命令
build.command=sh build.sh

# 应用部署脚本,先注释掉,暂时用不上
# deploy.appctl.path=deploy.sh

↓↓↓↓ 配置说明:

code.language=nodejs

代表使用的是nodejs作为代码语言类型。支持以下枚举:

php5.6,php7.0,node6.x,node7.x,node8.x,oracle-jdk1.7,oracle-jdk1.8, oracle-jdk1.9,scripts

如果有使用过jenkins的同学,那么应该比较好理解,RDC的构建是通过Docker容器技术实现的,类似于配置好环境的jenkins构建机,RDC团队针对各种语言准备了不同的镜像作为构建宿主。


build.command=sh build.sh

这一行的意思是,使用一个特定的脚本来进行自定义构建,因为构建有时候需要处理的东西很多,一行命令解决不了,所以需要一个自定义构建脚本,此处我设置的脚本在代码根目录下,创建一个build.sh脚本。如果你的构建只有1句话,可以直接写在“=”号后面,使用自定义脚本是为了更清晰和更灵活。

↓↓↓↓ build.sh脚本内容:

echo "##### npm to taobao"
npm install -g cnpm --registry=https://registry.npm.taobao.org

echo "##### cnpm install --save"
cnpm install --save

echo "##### cnpm build"
cnpm run build

逐句解释:

npm install -g cnpm --registry=https://registry.npm.taobao.org

使用npm的中国全量资源,cnpm由淘宝维护,国内最快的镜像站点。切换的目的就是为了构建快一些,因为RDC目前暂时不支持海外构建,所以不改可能会导致构建很慢。


cnpm install --save

最核心的一句话,安装所有第三方库依赖,这一句执行后如果正确,就会生成node_modules文件夹了。也意味着如果你使用开源框架,你的angularjs、vue等框架就安装成功了。


cnpm run build

这句话是使用webpack完成打包工作,前端项目通常是生成dist文件夹,此文件夹为项目的产出物。


我们已经完成了应用的创建+流水线的修改,那么我们运行一次构建试一下,只需要点击【运行流水线】按钮即可,运行后等几秒刷新一下页面,效果如下:

image

可以看到执行时间、版本号、日志、操作人等信息。

如果构建失败了,可以通过构建流程—-日志详情面板看到具体的错误原因,有日志排查起来不太难,但是RDC的构建还是偏向黑盒,所以尽量熟练或在本地先把相关命令跑通后再上传到xxx.release文件里去进行RDC构建。

可以看到初始的版本号是:v0.0.1-1,如果你的构建一直失败,版本号会变成v0.0.1-3、v0.0.1-8、v0.0.1-18、v0.0.1-N。

如果你的流水线全流程跑完了,则会自动叠加一个小版本号变为v0.0.2-1,所以这种构建方式清晰明了,还算好用。


三、如何输出为一个Docker镜像

我们已经完成了代码的打包编译工作,下一步我们需要把完整的代码封装成一个Docker镜像,我们需要对xxx.release文件做如下改动:

# 语言类型,需要修改,否则无法调用对应的构建环境
code.language=node8.x

#构建命令
build.command=sh build.sh

# Docker 构建配置
docker.file=Dockerfile

# Docker镜像构建之后push的仓库地址
docker.repo=registry.cn-hangzhou.aliyuncs.com/xxx/abced

docker.tag=ci-${PACKAGE_LABEL} 

# 应用部署脚本,先注释掉,暂时用不上
# deploy.appctl.path=deploy.sh

相对于单纯的构建,如果需要生成Docker镜像则需要补充几个配置项,拆解说明如下:

docker.file=Dockerfile

指明dockerfile文件的位置和文件名,默认就是根目录下的Dockerfile文件。


docker.repo=registry.cn-hangzhou.aliyuncs.com/xxx/abced

指定你的docker镜像仓库,建议使用阿里云提供的仓库,免费,速度快,可以加速docker hub的内容,无缝对接RDC服务,地址是 dev.aliyun.com ,此处的xxx对应的是你的名称空间,abced对应的是你的镜像名称。


docker.tag=ci-${PACKAGE_LABEL}-${TIMESTAMP}

这里指定你的docker镜像的tag名,使用了环境变量进行拼接。

${PACKAGE_LABEL}代表的是包名,这个参数在流水线配置里可以改,默认是default。

${TIMESTAMP}代表的是当前时间戳,格式是:20171008224350 这种样子。

有的项目一份代码可能产生多个docker镜像就需要通过这种方式来动态生成tag名,防止覆盖,也便于回滚。

关于构建传参,可以参考这个文章: https://help.aliyun.com/document_detail/59297.html

那么此处最终生成的tag名是这样的: ci-default-20171008224350

结合仓库名和镜像名,最终会生成镜像tag地址为:

registry.cn-hangzhou.aliyuncs.com/xxx/abced:ci-default-20171008224350


四、后记

NodeJS构建 + Docker构建就说到这里,因为主要是为了介绍RDC,所以Docker部分就挑重点讲了,如何编写Dockerfile文件请自行学习。

输出成Docker镜像后,如何使用RDC部署到容器相关问题我会单独开一个文章来分享。

云效(原RDC)如何构建一个基于Composer的PHP项目

最近在将公司的持续集成架构做一个系统的调整,调整过程中受到了RDC团队大量的帮助,所以利用国庆时间写了几篇RDC的分享,希望能让更多的人了解和用好RDC这个产品。

我会把我最近3个月的使用体会分成5个部分:使用RDC的动机、PHP项目集成、JS项目集成、JAVA项目集成、Docker类项目集成这5个分支来写

因为近期RDC的迭代比较频繁,所以我的分享会比较的浅,点到为止,仅供参考,目录:

1、RDC如何耦合进我们的业务

2、如何构建一个基于Composer的PHP项目

3、如何构建一个基于NodeJS的前后端项目

4、如何构建一个基于Maven的Java项目

5、RDC + 容器服务完成持续集成


一、RDC基础操作

在开始一切之前您需要熟悉RDC的一些基础操作,创建一个项目,然后在这个项目中创建一个应用,然后让这个应用关联某个代码分支。这样基础工作就完成了,我这里不再赘述了,因为比较简单,只需要注册个阿里云账号,然后去 rdc.aliyun.com 创建/加入个企业就行了。

本文所有的体验均基于【自由模式】的应用。

值得一提的是,应用代码源目前支持的是阿里云的代码仓库,基于gitlab,地址是 code.aliyun.com,从我2年的使用经验来看,还算好用,也不收费,较为靠谱。

在创建应用时,我们需要选择对应的配置,如下图:

image

创建完应用后,进入【项目】–》【流水线】,找到刚才创建应用的【同名流水线】

image

点击流水线名称可以看到具体的流水线运行情况和对应节点,如下图:

image

可以看到有4个面板:构建、日常、预发、正式。

分别对应的是:构建打包、发布到日常环境、发布到预发环境、发布到正式环境。

RDC在创建应用时自动的为你生成了一个标准模板流水线,但是我们一般用不着,所以需要对流水线进行修改,去除无用的节点,添加我们自己的配置。点击界面上的【编辑流水线】按钮就可以进入修改界面。

image

我们先从构建开始,所以先暂时删除日常、预发、正式这3个部署节点,仅保留构建这一个节点即可。下面的配置暂时不进行调整。删除完毕后保存流水线即可,效果如下:

image

至此我们已经完成了基础的准备工作,下一步就开始进行代码的构建工作了。

在开始下一步工作之前,请重新git pull一下您的代码到本地,会看到一个由RDC服务自动生成的配置文件:==xxx.release== 这个文件相当重要,请注意,下面将会说明如何通过此文件完成个性化构建。


二、基于NodeJS的前后端项目构建

因为node类项目一般都通过NPM来维护第三方库,并且一般会通过webpack来进行构建、合并、压缩,所以在RDC构建时需要完成依赖包下载及webpack编译的相关工作。

这里需要找到我们上一章节中提到的:==xxx.release== 文件,xxx代表你的应用名,所以我这里看到的文件名是:ms-autotags.release

这个文件的配置规范可以参考:==https://help.aliyun.com/document_detail/59293.html==

打开这个文件可以看到,已经有一些预先定义好的配置:

# 构建源码语言类型
code.language=scripts

# 应用部署脚本
deploy.appctl.path=deploy.sh

# Docker镜像构建之后push的仓库地址
docker.repo=registry.cn-hangzhou.aliyuncs.com/xxx/abced

上面的配置是不能用的,我们需要将其修改为如下内容:

# 语言类型,需要修改,否则无法调用对应的构建环境
code.language=node8.x

#构建命令
build.command=sh build.sh

# 应用部署脚本,先注释掉,暂时用不上
# deploy.appctl.path=deploy.sh

↓↓↓↓ 配置说明:

code.language=nodejs

代表使用的是nodejs作为代码语言类型。支持以下枚举:

php5.6,php7.0,node6.x,node7.x,node8.x,oracle-jdk1.7,oracle-jdk1.8, oracle-jdk1.9,scripts

如果有使用过jenkins的同学,那么应该比较好理解,RDC的构建是通过Docker容器技术实现的,类似于配置好环境的jenkins构建机,RDC团队针对各种语言准备了不同的镜像作为构建宿主。


build.command=sh build.sh

这一行的意思是,使用一个特定的脚本来进行自定义构建,因为构建有时候需要处理的东西很多,一行命令解决不了,所以需要一个自定义构建脚本,此处我设置的脚本在代码根目录下,创建一个build.sh脚本。如果你的构建只有1句话,可以直接写在“=”号后面,使用自定义脚本是为了更清晰和更灵活。

↓↓↓↓ build.sh脚本内容:

echo "##### npm to taobao"
npm install -g cnpm --registry=https://registry.npm.taobao.org

echo "##### cnpm install --save"
cnpm install --save

echo "##### cnpm build"
cnpm run build

逐句解释:

npm install -g cnpm --registry=https://registry.npm.taobao.org

使用npm的中国全量资源,cnpm由淘宝维护,国内最快的镜像站点。切换的目的就是为了构建快一些,因为RDC目前暂时不支持海外构建,所以不改可能会导致构建很慢。


cnpm install --save

最核心的一句话,安装所有第三方库依赖,这一句执行后如果正确,就会生成node_modules文件夹了。也意味着如果你使用开源框架,你的angularjs、vue等框架就安装成功了。


cnpm run build

这句话是使用webpack完成打包工作,前端项目通常是生成dist文件夹,此文件夹为项目的产出物。


我们已经完成了应用的创建+流水线的修改,那么我们运行一次构建试一下,只需要点击【运行流水线】按钮即可,运行后等几秒刷新一下页面,效果如下:

image

可以看到执行时间、版本号、日志、操作人等信息。

如果构建失败了,可以通过构建流程—-日志详情面板看到具体的错误原因,有日志排查起来不太难,但是RDC的构建还是偏向黑盒,所以尽量熟练或在本地先把相关命令跑通后再上传到==xxx.release==文件里去进行RDC构建。

可以看到初始的版本号是:v0.0.1-1,如果你的构建一直失败,版本号会变成v0.0.1-3、v0.0.1-8、v0.0.1-18、v0.0.1-N。

如果你的流水线全流程跑完了,则会自动叠加一个小版本号变为v0.0.2-1,所以这种构建方式清晰明了,还算好用。


三、如何输出为一个Docker镜像

我们已经完成了代码的打包编译工作,下一步我们需要把完整的代码封装成一个Docker镜像,我们需要对==xxx.release==文件做如下改动:


# 语言类型,需要修改,否则无法调用对应的构建环境
code.language=node8.x

#构建命令
build.command=sh build.sh

# Docker 构建配置
docker.file=Dockerfile

# Docker镜像构建之后push的仓库地址
docker.repo=registry.cn-hangzhou.aliyuncs.com/xxx/abced

docker.tag=ci-${PACKAGE_LABEL} 

# 应用部署脚本,先注释掉,暂时用不上
# deploy.appctl.path=deploy.sh

相对于单纯的构建,如果需要生成Docker镜像则需要补充几个配置项,拆解说明如下:

docker.file=Dockerfile

指明dockerfile文件的位置和文件名,默认就是根目录下的Dockerfile文件。


docker.repo=registry.cn-hangzhou.aliyuncs.com/xxx/abced

指定你的docker镜像仓库,建议使用阿里云提供的仓库,免费,速度快,可以加速docker hub的内容,无缝对接RDC服务,地址是 dev.aliyun.com ,此处的xxx对应的是你的名称空间,abced对应的是你的镜像名称。


docker.tag=ci-${PACKAGE_LABEL}-${TIMESTAMP}

这里指定你的docker镜像的tag名,使用了环境变量进行拼接。

${PACKAGE_LABEL}代表的是包名,这个参数在流水线配置里可以改,默认是default。

${TIMESTAMP}代表的是当前时间戳,格式是:20171008224350 这种样子。

有的项目一份代码可能产生多个docker镜像就需要通过这种方式来动态生成tag名,防止覆盖,也便于回滚。

关于构建传参,可以参考这个文章: https://help.aliyun.com/document_detail/59297.html

那么此处最终生成的tag名是这样的: ci-default-20171008224350

结合仓库名和镜像名,最终会生成镜像tag地址为:

registry.cn-hangzhou.aliyuncs.com/xxx/abced:ci-default-20171008224350


四、后记

NodeJS构建 + Docker构建就说到这里,因为主要是为了介绍RDC,所以Docker部分就挑重点讲了,如何编写Dockerfile文件请自行学习。

输出成Docker镜像后,如何使用RDC部署到容器相关问题我会单独开一个文章来分享。

云效(原RDC)如何耦合进我们的业务

最近在将公司的持续集成架构做一个系统的调整,调整过程中受到了RDC团队大量的帮助,所以利用国庆时间写了几篇RDC的分享,希望能让更多的人了解和用好RDC这个产品。

我会把我最近3个月的使用体会分成5个部分:使用RDC的动机、PHP项目集成、JS项目集成、JAVA项目集成、Docker类项目集成这5个分支来写

因为近期RDC的迭代比较频繁,所以我的分享会比较的浅,点到为止,仅供参考,目录:

1、RDC如何耦合进我们的业务

2、如何构建一个基于Composer的PHP项目

3、如何构建一个基于NodeJS的前后端项目

4、如何构建一个基于Maven的Java项目

5、RDC + 容器服务完成持续集成


一、现有架构梳理

在没有切入RDC之前,我们公司的持续集成主要是通过以下的方式进行全流程:

应用环境: 基于Docker集群。

代码存储: 存放在 code.aliyun.com,阿里基于gitlab搭建。

构建打包: 使用Jenkins来进行构建。

上线发布: 部分通过Jenkins发布,部分通过自定义脚本实现。

我们之前的开发方式是基于微服务的方式进行开发,所以虽然按项目进行人员分组,但是具体的开发、测试、运维智能都是面向微服务,导致了代码分支的管理上有更严格的要求。我们的每一个代码库(服务,也可以理解为应用)都分为3个分支 dev、rc、release ,含义如下:

dev 开发分支: 主要用于工程师们日常开发后的合并归总,比如基于dev创建一个新分支 dev-hanmeimei 用来存放员工韩梅梅的相关代码,当韩梅梅开发完成后,提交合并到dev分支即可。原则上不直接修改dev分支的内容,防止出现污染和冲突。dev里的代码会自动的发布到日常测试环境,进行测试。

rc 预发分支: 当dev分支的内容通过测试后,从dev合并到rc,然后进行线上测试,完成预发。此分支也不可进行人为干预和修改,只接受合并请求。

release 线上分支: 正式代码,rc线测完成后合并到release分支,此分支也不可进行人为干预和修改,只接受合并请求。有一种特殊情况支持直接干预,比如线上出现了很严重的bug,再走一遍合并流程已经太迟了,直接拉release分支创建一个release-bug分支,然后把bug修复完成后直接与release合并。

_1


二、下面说说我们的在上述的这一套架构中遇到的问题:

因为各种各样的原因,我们已经使用上述的架构大约18个月以上了,所以积累下的问题特别的多,有些问题忍忍也就过去了,有些问题却逐渐带来了严重的影响。

1.成本问题

先从代码管理方式来说,因为我们的代码管理模式是dev—>rc—>release的方式,需要一层层的进行合并,而我们不能向所有技术人员开放所有分支的合并权限,那就意味着需要至少有一个人来进行代码的审查及合并工作,这是一个人力成本的问题。

然后说说硬件投入,我们之前的jenkins服务一共有3个机器组成,1个管理,2个构建。这一套2核4G内存大概一年15000元左右,对公司来说属于必要成本,谈不上贵,但也不算便宜。

随着使用逐渐发现,特定时间的代码push频率提高,原有的构建机器出现资源争抢,后来就改成了错时构建(不侦听push),每5分钟一次,对效率有着轻微的影响。

2.管理问题

因为开发负责的服务/应用不一样,从企业内部管理的角度来说,不可能给所有开发人员开启所有代码仓库的权限,那必须要有人对开发、测试人员的git权限进行维护,这一点其实很痛苦。人员离职、入职时需要把某些员工移入仓库,移出仓库,还有时需要提权/降权。我们一直没能解决这个问题,都是人肉维护git权限,比较累,效率也很低。

3.效率问题

之前说过,我们有专人对代码的合并进行审查和管理,但是因为快速迭代,导致每天会频繁的审查和接受合并。从代码安全性角度来说这是不得已而为之的一件事,低效,但是安全。

另外,在版本发布时,有些版本是自动发布的,有些产品比较重要,需要手动进行发布。这样一来,发布也需要牵扯一些精力,这个权限不可能下放给工程人员,但是放在PM或者PL手里又产生了大量的流程时间成本,目前没有很好的解决,还是人肉处理,比较累。


三、带着问题出发,通过RDC完成持续集成

留意到阿里云的RDC产品主要是之前使用过阿里云的另一个产品CRP(据说今年即将停止维护了),他同样支持类似jenkins的功能,而且无需自己提供服务器。

一开始没完全切换到CRP的原因是我们的业务需要Docker部署,CRP到中后期才对Docker完成支持,而那时我们已经切换到jenkins上去了,所以就搁置了。

1.通过RDC有效降低成本

RDC是一个阿里云提供的云服务,目前是免费的,未来即便商业化,应该也会大幅度低于自建系统的成本,不用特别担心。

它直接打通了阿里云Code可以完成触发构建。

不需要自备额外的机器进行构建。仅此一项对我来说一年至少节省1.5万元。

之前公司使用禅道等一些产品管理需求、BUG、文档等,接入RDC后它自带项目和产品管理,节约了办公这块的成本,且支持钉钉接入,手机使用还是蛮方便的。

2.通过RDC解决管理问题

代码仓库的权限问题一直使我们公司的心病,因为人员离职/入职导致需要调整每一个仓库的权限。同时我们又是微服务架构,导致一个应用可能会有N个仓库,调整起权限来简直是心累。

庆幸的是,我们公司一直是全员通过钉钉办公,而RDC支持对接钉钉及其组织架构。那么通过RDC+钉钉我们做到了下面这些事情:

1.只需要在钉钉里维护员工入职、离职即可,离职后相关项目权限自动就没了。(省心+1)

2.在RDC里为你的阿里云Code代码仓库分好git组,然后把对应的钉钉用户丢到某个组下即可完成批量授权/降权。(省心+2)

RDC接入钉钉这个功能,我和RDC&CRP团队喊了快1年,总算是支持了,这也是我觉得RDC一定能更好用的一个主要原因,产品多了、业务复杂之后你才能体会到内部管理时的碎片化有多痛苦,而RDC+钉钉我觉得能有效缓解这种痛苦。

3.通过RDC解决效率问题

通过RDC可以完成整个持续集成的工作流,并且RDC的最新版本已经可以自定义流水线了,可以有针对性的完成构建、自动部署、手动部署、开关式部署。

一些不太重要的业务,在流水线里设置成自动发布,一些比较重要的业务设置成手动发布。而且未来发布相关的操作很可能在钉钉里就能直接完成,这样一来其实已经减少了大量的中间流程,变相提高了效率。

重要的是,可以针对性的设置多个流水线,相当灵活,而且现在的构建和部署自由度很高。

另外,钉钉聊天记录可以直接转RDC的项目需求,我觉得这个功能简直好用到突破天际。


四、备注

开篇就说到这里,主要是聊一聊我们自己公司遇到的一些问题,以及为什么选择RDC。

上面写的东西,可能有一部分大家能找到共鸣,也可能看完不知所云,因为每个团队遇到的问题是不同的,感受和痛点也不同。

我不是要向大家推销RDC这个产品,那是阿里云团队的事情,我也不觉得RDC是完美的,仅仅是因为我们选择了RDC进行持续集成相关的工作,把这个过程分享给大家,仅供参考。

后面的几个分享中偏技术性多一些,主要介绍一下构建过程中遇到的一些小坑及应对方式。

记一次WIN10权限问题导致的程序开发故障

前两天用.NET写了个命令行工具,主要是读取本地磁盘上的文件,然后生成对应的XML文件。

原理上并不复杂,代码寥寥数百行,但是却遇到一个很致命的问题,程序运行的极慢极慢,处理一个文件并生成XML文件的过程需要30秒到几分钟。

一直以为是自己的代码有问题,反复检查了好久。

最后突然想到,是不是在WIN10下非管理员权限大量产生IO会被系统拒绝或审查?

紧接着尝试了一下,直接使用管理员权限运行程序,速度飞快,0.1秒不到就完成一个文件了。

这件事上,吸取经验教训,开发人员真的应该换换环境,老在WIN7、CentOS6这些系统上开发,会忽略最新版本的操作系统特性。