使用Gitlab CI和Gradle持续集成Spring MVC项目到Heroku

96
liuwill
2016.04.16 18:34* 字数 1197

一直在实践持续集成相关的思想和工具,用过不少的持续集成工具,最近用到一种持续集成的pipeline,使用Gitlab和Heroku,可以通过简单的配置实现轻量级的持续集成,加速代码的开发。


简单的持续集成工作流

Github代码,目前在分支下进行开发:deploy分支链接

Gradle项目创建

首先要创建一个使用Gralde构建的Spring MVC项目,本地使用IDEA进行开发,创建一个项目之后,修改build.gradle。引入依赖的包。以下是部分重要的包

apply plugin: 'idea'
apply plugin: 'java'
apply plugin: 'war'

repositories {
    mavenLocal()
    mavenCentral()
}

dependencies {
    compile    'org.slf4j:slf4j-api:1.7.13'
    compile    'org.slf4j:slf4j-log4j12:1.7.13'
    compile    'org.slf4j:jcl-over-slf4j:1.7.13'
    compile    'org.slf4j:jul-to-slf4j:1.7.13'

    compile 'javax.servlet:javax.servlet-api:3.1.0'
    compile 'javax.servlet:jstl:1.2'
    compile    'taglibs:standard:1.1.2'
    compile    'javax.servlet.jsp:javax.servlet.jsp-api:2.3.1'

    compile('org.springframework:spring-core:4.1.8.RELEASE') {
        exclude    module:    'commons-logging'
    }
    compile    'org.springframework:spring-beans:4.1.8.RELEASE'
    compile    'org.springframework:spring-context:4.1.8.RELEASE'
    compile    'org.springframework:spring-context-support:4.1.8.RELEASE'
    compile('org.springframework:spring-aop:4.1.8.RELEASE')    {
        exclude    module:    'commons-logging'
    }
    compile    'org.springframework:spring-tx:4.1.8.RELEASE'
    compile    'org.springframework:spring-orm:4.1.8.RELEASE'
    compile    'org.springframework:spring-jdbc:4.1.8.RELEASE'
    compile    'org.springframework:spring-web:4.1.8.RELEASE'
    compile    'org.springframework:spring-webmvc:4.1.8.RELEASE'

    compile    'com.fasterxml.jackson.core:jackson-core:2.6.3'
    compile    'com.fasterxml.jackson.core:jackson-databind:2.6.3'
    compile    'com.fasterxml.jackson.core:jackson-annotations:2.6.3'
    compile    'org.freemarker:freemarker:2.3.23'

    compile    'org.apache.commons:commons-lang3:3.4'

    testCompile group: 'junit', name: 'junit', version: '4.11'
    testCompile group: 'org.testng', name: 'testng', version: '6.9.8'
}

test {
    useTestNG{
        suites testngConfigPath
        useDefaultListeners = true
    }
}

为了方便进行开发还有最后在Heroku运行,使用Jetty Runner来运行web程序相应的配置为:

configurations {
    jettyServer
}

dependencies {
    jettyServer 'org.eclipse.jetty:jetty-runner:9.3.9.M1'
}

def jettyHttpPort = 8090
task jettyServerRun(type: JavaExec,dependsOn: build) {
    main = "org.eclipse.jetty.runner.Runner"
    args = ["--port",jettyHttpPort,war.archivePath]
    classpath configurations.jettyServer
}

配置最基本的SpringMVC应用

详细配置,参看GitHub代码。

  • 创建maven的默认目录结构。
  • 在src/main/webapp/WEB-INF下面创建web.xml。
  • 在src/main/resources/config下创建Spring的mvc和context配置文件。

编写简单的控制器代码

@RestController
@RequestMapping(value = "data")
public class DataController {
    private final Logger logger = LoggerFactory.getLogger(DataController.class);

    @Autowired
    private UserService userService;

    @RequestMapping(value = "success")//, method = RequestMethod.GET
    public Map success() {
        logger.debug("DataController.success[/data/success]");

        Map resultMap = new HashMap();
        resultMap.put("status",true);
        resultMap.put("code","success");
        resultMap.put("content","数据获取成功");
        return resultMap;
    }
}

编写基本的单元测试

首先创建testng的测试集配置文件src/test/resources

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="TestAll">
    <test name="TestMVC" enabled="true">
        <groups>
            <run>
                <include name="data" />
                <include name="mvc" />
                <include name="rest" />
            </run>
        </groups>

        <classes>
            <class name="com.liuwill.test.DataControllerTest"/>
        </classes>
    </test>
</suite>

然后,编写测试集成测试代码,检查Controller代码是否正确
@WebAppConfiguration(value = "src/main/webapp")
@ContextConfiguration(locations = {"/config/spring-mvc.xml","/config/spring-context.xml" })
public class DataControllerTest extends AbstractTestNGSpringContextTests {
@Autowired
private WebApplicationContext wac;

private static String URI = "/data/success";//RESTurl.searchPersonalFile;
private MockMvc mockMvc;

@BeforeClass(groups = {"context","data"})
public void setup() {
    this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}


@Test(groups = {"data"})
public void testSuccess() throws Exception {
    System.out.println("Load List Json");
    mockMvc.perform(MockMvcRequestBuilders.get("/data/success").accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value("success"))
            .andDo(print());
    System.out.println("测试控制器 DataController:");
}

}

创建Gitlab项目,并配置自动化构建

这里可以自己下载一个Gitlab社区版,搭建自己的git私有仓库,也可以使用gitlab提供的服务,这里使用gitlab提供的服务,首先需要创建Gitlab账户,如果不想从头注册,可以使用Google或者Gitbhub账号进行登录。

然后创建本地Git项目,然后将代码上传到gitlab:

git config --global user.name "liuwill"
git config --global user.email "liuwei_will@qq.com"

cd existing_folder
git init
git remote add origin 项目的git地址
git add .
git commit
git push -u origin master

完成以上步骤之后,代码就会添加到远程仓库,但是这个时候并不会开始自动化构建项目,还需要配置一个支持构建规则的Runner环境来运行构建。具体配置参看官方文档,如果像本例一样使用官方提供的Gitlab仓库的话,可以使用官方提供的默认Runner.


Runner的面板


有了构建环境的Runner之后,就可以添加Gitlab CI的配置文件.gitlab-ci.yml在代码库中,然后上传代码,开始构建

image: java:openjdk-8

stages:
  - test
  - deploy

before_script:
  - apt-get update -y
  - apt-get install gradle -y

test_async:
  stage: test
  script:
   - gradle test --info
  tags:
    - docker

staging:
  type: deploy
  script:
    - apt-get update -qy
    - apt-get install -y ruby-dev
    - gem install dpl
    - dpl --provider=heroku --app=$HEROKU_APP_NAME --api-key=$HEROKU_API_KEY
  only:
    - deploy
  tags:
    - docker

在执行git push之后,gitlab ci就会自动开始进行构建,通过配置deploy属性,还可以直接将代码部署到Heroku中,目前还没有集成测试过该功能。


构建的面板

将代码部署到Heroku

Heroku提供了非常方便的功能,只要通过简单的配置,就可以通过git push直接一键将代码部署到heroku应用中,而且可以非常方便的和其他的ci工具进行集成,下面先介绍一下如何在本地直接将代码部署到Heroku的步骤,然后在将Gitlab CI和Heroku集成起来实现完成的持续集成。部署基于Gradle构建的代码到Heroku的方法,可以参看官方提供的教程.

首先要下载安装Heroku的工具包,Windows版的下载地址
发布的步骤如下:

  • 在项目的根目录下执行heroku login,使用heroku注册的邮箱和密码登录;
  • 执行heroku create工具包会进行一些默认的配置的,包括添加远程仓库heroku,可以是执行heroku git:remote -a appName
  • 运行git push heroku master将要发布的分支推送到heroku提供的操作;如果要使用非master分支,那么执行git push heroku deploy:master
  • 设置web应用的规模,heroku ps:scale web=1
  • 执行heroku open就会在浏览器中打开部署好的页面
  • 开始运行之后,通过heroku log --tail可以查看日志

要在heroku上运行程序,还需要配置Procfile和专用的gradle task,告诉heroku怎样才能将程序运行起来

web: java $JAVA_OPTS -jar build/dist/jetty-runner-9.3.9.M1.jar --port $PORT build/libs/WebFrontTemplate-1.0.jar
task copyJettyJars(type: Copy) {
    from configurations.jettyServer
    into 'build/dist' // 目标位置
}

task stage{
    dependsOn "build","copyJettyJars"
}

另外,heroku可以支持直接link到github,然后直接从github抓取代码来运行.

集成Gitlab CI和Heroku

首先需要在Heroku的控制面板上创建一个新的app,然后从manage account获取账户的API KEY.
然后,在Gitlab的项目配置中,设置两个变量HEROKU_APP_NAME和HEROKU_APP_KEY,对应Heroku的api key和创建的应用的名称;


heroku-apikey.png


然后在yaml文件中增加一个新的Job:staging,push代码到gitlab仓库,然后等待构建完成,就可以从Heroku的app站点访问成功部署的应用。大功告成!


gitlab-success.png

heroku-success.png

开发技术