本文主要内容:
- 使用Jenkinsfile进行管道配置
- 管理第三方凭证
- 集成Jenkins测试报告
- Poll 和hook构建触发器
- 建立 pull 请求
首先,让我们谈谈持续集成(CI)。CI是一种流行的开发实践,尽可能确保软件高质量且可部署。
要采用CI,需要做好一些关键工作:
- Git等SCM系统
- CI服务器(如Jenkins)
- 自动化测试
- 一些良好的团队CI实践–使你可以缩短构建时间,立即修复损坏的构建,频繁提交并保持较小的更改
所需工具:
运行 Jenkins
Jenkins是开源的,开发人员可以将其用于持续集成,持续交付和持续部署。它来自Hudson,这是2004年Sun Microsystems用Java编写的CI服务器。
Jenkins Pipeline 是插件,你可以用它来自动构建,测试和部署的套件。你可以在Jenkinsfile中使用特定语法定义管道,你可以在 Pipeline-as-code 模型中将其提交到项目的存储库中。
为了快速入门,请从Docker HYub中提取Jenkins镜像:
docker pull jenkins/jenkins:lts
然后启动一个Jenkins容器:
docker run \ -p 8081:8080 \ -p 50000:50000 \ --name my-jenkins \ -v jenkins_data:/var/jenkins_home jenkins/jenkins:lts
在上面的命令中,我们将Jenkins端口8080映射到主机端口8081,并将Jenkins端口50000映射到主机端口50000。我们还在host文件夹中定义了Jenkins home的存储卷jenkins_data。
当容器启动时,将运行初始安装,Jenkins将记录管理员密码:
Jenkins initial setup is required. An admin user has been created and a password generated. Please use the following password to proceed to installation: b518968d266d41d3beb0abef50834fa7 This may also be found at: /var/jenkins_home/secrets/initialAdminPassword
复制密码,然后登陆http://localhost:8081进行初始设置。
粘贴管理员密码,然后继续。
设置过程将使你可以选择自定义要添加的插件。
选择Install Suggested Plugins并继续。
等待安装完成。
设置管理员用户数据并继续。
由于这是一项测试,请保留默认的Jenkins URL(http://localhost:8081/)并完成它。
我们准备创建第一个Jenkins管道。
Okta OIDC身份验证的简单应用
我们将使用Jenkins通过Okta OIDC身份验证自动化构建简单的Java应用程序,因此让我们首先使用Spring Intializr 创建该应用程序:
curl https://start.spring.io/starter.zip -d dependencies=web,okta \ -d language=java \ -d type=maven-project \ -d groupId=com.okta.developer \ -d artifactId=simpleapp \ -d name="Simple Application" \ -d description="Demo project for Jenkins CI test" \ -d packageName=com.okta.developer.simpleapp \ -o simple-app.zip
解压缩文件:
unzip simple-app.zip -d simple-app cd simple-app
如果你还没有Okta开发者帐户,请执行Okta Maven插件创建一个(免费!)并在应用程序中配置身份验证:
./mvnw com.okta:okta-maven-plugin:setup
你应该看到以下输出:
First name: Jimena Last name: Garbarino Email address: *** Company: *** Creating new Okta Organization, this may take a minute: OrgUrl: *** Check your email address to verify your account. Writing Okta SDK config to: /home/indiepopart/.okta/okta.yaml Configuring a new OIDC, almost done: Created OIDC application, client-id: ***
检查你的电子邮件,然后按照说明激活你的Okta帐户。
Maven插件将在src/main/resources/application.properties中生成OIDC客户端ID,密钥和发行者URL 。因为我们将在公共代码库(如-GitHub)用于CI测试时,所以将凭据复制到其他位置,然后从属性文件中删除它们。
如果你已经拥有Okta Developer帐户,请登录并创建一个新应用程序:在“应用程序”页面上,选择 Add Application 。在“创建新应用程序”页面上,选择“ Web”。给你的应用起一个令人难忘的名称,然后将其添加http://localhost:8080/login/oauth2/code/okta做为“ 登录”重定向URI。
复制发行者(你可以在 API > Authorization Servers 下找到它),客户端ID和客户端密钥,以备后用。
添加一个REST Controller
创建一个GreetingController类以在登录时向用户打招呼。
package com.okta.developer.simpleapp; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.oauth2.core.oidc.user.OidcUser; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class GreetingController { @GetMapping("/greeting") public String greet(@AuthenticationPrincipal OidcUser user){ return "Hello " + user.getEmail(); } }
使用Maven Spring Boot插件测试应用程序:
OKTA_OAUTH2_CLIENT_ID={youtOktaClientId} \ OKTA_OAUTH2_CLIENT_SECRET={yourOktaClientSecret} \ OKTA_OAUTH2_ISSUER={yourOktaDomain}/oauth2/default \ mvn spring-boot:run
转到http://localhost:8080/greeting。该应用程序应重定向到Okta进行登录:
登录后,应用程序应显示问候响应:
Hello jimena@***.com
为创建一个GitHub 公共存储库,simple-app并按照说明推送现有代码。
git init git add . git commit -m "initial commit" git remote add origin https://github.com/<your-username>/simple-app.git git push -u origin master
Jenkins Pipeline和Jenkinsfile
在Jenkins仪表板中,选择Create New Jobs,设置simple-app为项目名称,然后选择Pipeline作为项目类型。
在下一个屏幕中,选择选项卡 Advanced Project Options 。从右侧的下拉菜单中,选择GitHub + Maven以获取我们将要自定义的Jenkinsfile模板。
将管道脚本复制到Jenkinsfile文件中。更新GitHub地址并为构建设置Okta凭证。还要更改Maven命令。
pipeline { agent any environment { // use your actual issuer URL here and NOT the placeholder {yourOktaDomain} OKTA_OAUTH2_ISSUER = '{yourOktaDomain}/oauth2/default' OKTA_OAUTH2_CLIENT_ID = credentials('OKTA_OAUTH2_CLIENT_ID') OKTA_OAUTH2_CLIENT_SECRET = credentials('OKTA_OAUTH2_CLIENT_SECRET') } stages { stage('Build') { steps { // Get some code from a GitHub repository git 'https://github.com/<your-username>/simple-app.git' // Run Maven on a Unix agent. sh "./mvnw -Dmaven.test.failure.ignore=true clean package" // To run Maven on a Windows agent, use // bat "mvn -Dmaven.test.failure.ignore=true clean package" } post { // If Maven was able to run the tests, even if some of the test // failed, record the test results and archive the jar file. success { junit '**/target/surefire-reports/TEST-*.xml' archiveArtifacts 'target/*.jar' } } } } }
我们正在使用environment管道语法的指令来定义OKTA_*构建所需的变量。该指令支持credentials()帮助程序从Jenkins环境中检索值。
然后,在请求项目构建之前,我们需要在Jenkins中设置Okta托管凭据。
将推Jenkinsfile送到公共存储库。
在 Advanced Project Options 中,对于“管道定义”,选择 Pipeline script from SCM 并完成存储库信息:
- SCM:GitHub
- 资料库URL: https://github.com/%3Cyour-username%3E/simple-app.git
- 凭证:无
- 分支说明符:\ * / master
- 脚本路径:Jenkinsfile
单击“ 保存”创建项目。
凭证管理
Jenkins允许你安全地存储第三方应用程序的凭据,从而使Pipeline项目方便地与第三方服务的交互。让我们添加Okta身份验证的凭据。
在Jenkins控制台中,转到左侧菜单上的 Credentials ,然后选择 global 。
为创建一个“ Secret text ”凭证OKTA_OAUTH2_CLIENT_ID,单击 Add Credentials ,然后选择以下选项:
- Kind: Secret text
- Scope: global
- Secret: {yourOktaClientID}
- ID: OKTA_OAUTH2_CLIENT_ID
注意:替换{yourOktaClientID}为你的实际 Client ID 。
对OKTA_OAUTH2_CLIENT_SECRET执行相同的操作。
注:存储Jenkins的密钥和拉取代码分支请求不应该一起使用。
现在我们准备构建该项目。转到simple-app并选择Build Now。转到 Build History 并选择构建#1。然后选择 Console Output 选项以监视任务。
添加 controller 测试
GitHub和Maven的Jenkinsfile模板已经集成了测试报告,并可以从构建摘要中对其进行访问。
让我们在应用程序中添加一个控制器测试以验证此功能。
将spring-security-test依赖项添加到pom.xml:
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency>
创建一个新类src/test/java/com/okta/developer/simpleapp/GreetingControllerTest.java:
package com.okta.developer.simpleapp; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.oauth2.core.oidc.OidcIdToken; import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser; import org.springframework.security.oauth2.core.oidc.user.OidcUser; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import java.time.Instant; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; @AutoConfigureMockMvc @WebMvcTest @ContextConfiguration(classes={GreetingController.class}) public class GreetingControllerTest { private final static String ID_TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9" + ".eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsIm" + "p0aSI6ImQzNWRmMTRkLTA5ZjYtNDhmZi04YTkzLTdjNmYwMzM5MzE1OSIsImlhdCI6MTU0M" + "Tk3MTU4MywiZXhwIjoxNTQxOTc1MTgzfQ.QaQOarmV8xEUYV7yvWzX3cUE_4W1luMcWCwpr" + "oqqUrg"; @Autowired private MockMvc mvc; @Test void testGreet() throws Exception { OidcIdToken idToken = createOidcToken(); this.mvc.perform(get("/greeting") .with(authentication(createMockOAuth2AuthenticationToken(idToken)))) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(content().string("Hello user@email.com")); } private OAuth2AuthenticationToken createMockOAuth2AuthenticationToken(OidcIdToken idToken) { Collection<GrantedAuthority> authorities = new ArrayList<>(); authorities.add(new SimpleGrantedAuthority("ROLE_USER")); OidcUser user = new DefaultOidcUser(authorities, idToken); return new OAuth2AuthenticationToken(user, authorities, "oidc"); } private OidcIdToken createOidcToken(){ Map<String, Object> claims = new HashMap<>(); claims.put("groups", "ROLE_USER"); claims.put("email", "user@email.com"); claims.put("sub", 123); OidcIdToken idToken = new OidcIdToken(ID_TOKEN, Instant.now(), Instant.now().plusSeconds(60), claims); return idToken; } }
将更改推送到存储库并安排新的构建。完成后,你可以在全局或包级别查看测试结果:
轮询变更
管道支持多种类型的触发器来安排构建。其中之一会定期轮询SCM系统(GitHub)进行更改。如果存在新的更改,它将重新触发管道。Jenkinsfile中的triggers指令配置了构建触发器:
pipeline { agent any // poll every 15 minutes triggers { pollSCM('H/15 * * * *') } environment { ...
触发器类型pollSCM具有cron表达式,该表达式将管道配置为每15分钟轮询GitHub。
注意:要在Jenkins中安装触发器,必须在推送更新的Jenkinsfile之后首先计划从Jenkins进行手动构建。
多分支管道
多分支管道( Multibranch Pipeline)项目会自动发现分支的管道,并可用于验证拉取请求。GitHub插件提供了验证功能,CloudBees提供文档。你已安装了建议的插件,因此让我们逐步进行配置。
在Jenkins仪表板中,转到 New Item ,键入项目名称,然后选择 Multibranch Pipeline 。然后,在配置表单中,转到Branch Sources并选择GitHub。选择选项 Repository Scan 。在 Owner 字段中,设置你的GitHub用户,然后选择要扫描的存储库。为了简化此测试,我们已经创建了一个公共存储库,因此我们可以跳过GitHub凭证设置。
选择 Scan Multibranch Pipeline Triggers ,选中 Periodically if not otherwise run ,然后将5分钟设置为间隔。
单击 Save 以添加新项目。
触发构建
README.md在simple-app项目的根文件夹中创建一个文件:
# Simple Application with Okta OIDC Authentication Clone the project and run the application with Maven: ```shell git clone https://github.com/<your-username>/simple-app.git cd simple-api OKTA_OAUTH2_CLIENT_ID={youtOktaClientId} \ OKTA_OAUTH2_CLIENT_SECRET={yourOktaClientSecret} \ OKTA_OAUTH2_ISSUER={yourOktaDomain}/oauth2/default \ ./mvnw spring-boot:run ```
为更改和拉取请求创建一个分支。在下一次定期扫描中,Jenkins将为拉取请求创建作业。
git checkout -b add-readme git add README.md git commit -m "added readme" git push origin add-readme
GitHub Branch Source插件,还允许你使用项目类型为“ GitHub Organization”来基于GitHub组织的存储库结构创建一个项目。对于此类项目,该插件将根据配置的标准将所有或部分存储库扫描并导入为作业(job)。
GitHub Hook 触发器
Jenkins有一个GitHub插件,可在收到有关推送更改和拉取请求的通知后触发构建。通过GitHub Webhooks,当事件触发时,GitHub会通过HTTP POST发送到Jenkins webhook的配置URL。收到POST后,Jenkins将简单地对SCM进行内部轮询。
你可以在GitHub上手动配置Jenkins Hook的URL,或者Jenkins本身可以根据配置管理项目的Hook。对于托管模式,你还必须配置对GitHub的身份验证,如果你在GitHub中启用了双重身份验证,Jenkins将无法进行身份验证。
GitHub Webhooks的使用要求Jenkins必须可从互联网访问。该插件的文档还提到了hook网址是所有仓库独一无二的,但没有提及对发送方所需要的任何一种认证。使用此功能之前,应先评估文档中列出的其他安全隐患。
译文链接: https://dzone.com/articles/using-jenkins-and-java-for-continuous-integration
登录后评论
立即登录 注册