持续集成和持续部署(CI/CD)是一个过程,在这个过程中,开发人员经常将代码变化合并到源代码库,然后触发代码构建,运行安全扫描,运行测试,然后部署应用程序。通过采用DevOps文化、工具和流程,这一过程的自动化使企业能够在不影响质量的情况下更频繁地发布。有各种工具可以实现CI/CD过程的自动化,可以很容易地集成到DevOps部署管道中。在这篇博文中,我们将讨论如何使用Jenkins来自动化CI/CD流程,以构建、测试和部署运行在Open Liberty上的云原生Java应用程序。由于CI/CD过程是由Git中的源变化触发的,这也被称为DevOps的GitOps方法。
Jenkins是一个流行的开源自动化服务器,它有数百个插件,可以帮助你把它集成到现有的DevOps管道中。下图显示了一个Jenkins部署管道的简单架构,它在单个Kubernetes环境中构建和部署Jakarta EE和MicroProfile应用程序。当Git仓库中的代码发生变化时,GitHub将触发Jenkins来构建代码,运行JUnit测试,然后对构建的代码进行SonarQube静态代码分析扫描。然后Jenkins生成一个以Open Liberty为运行时的应用程序的Docker容器镜像,将该镜像保存到Docker容器仓库,然后用Trivy扫描该镜像。然后,Jenkins通过使用CLI命令触发部署,将Docker容器镜像部署到Kubernetes。
在这篇博文中,我将假设你对Git、Docker和Kubernetes有基本了解。我还将假设Jakarta EE和MicroProfile的应用代码存储在GitHub中。我将使用Docker Hub来存储Docker容器镜像,并将容器化的应用程序部署到IBM云Kubernetes服务。
安装和配置Jenkins以建立云原生Java应用程序的CI/CD
在你的Jenkins容器镜像的基础镜像上,或在Jenkins控制器(Jenkins主机)上安装带有以下插件的Jenkins:
-
Maven,用于构建java代码
-
Pipeline,用于创建Jenkins流水线作业
-
多分支扫描Webhook触发器,用于创建Jenkins流水线类型的工作,将代码的所有分支从Git拉到Jenkins。
-
Docker或类似的Podman,用于构建和推送容器镜像
-
Kubernetes,以使用Kubernetes模板
Jenkins使用Jenkins流水线脚本构建运行在Liberty上的Java应用程序代码。脚本可以直接在你的Jenkins主机(也称为Jenkins控制器)上运行。如果应用程序需要大量的内存,你可能需要使用Jenkins代理作为作业执行环境。关于有关设置Jenkins代理的更多信息,请参见使用Jenkins代理。
编写Jenkins流水线脚本
在创建DevOps管道时,坚持基础设施即代码(IaC)的概念是一个好的做法。用管道脚本创建Jenkins作业是IaC的一个好例子。
你可以通过以下方式之一来编写Jenkins管道代码。
- 作为管道代码直接写在Jenkins UI中并存储在Jenkins控制器(主机)上。这是一种有用的入门方式。在这种情况下,你需要对Jenkins实例进行备份,以保存流水线代码,因为代码是作为Jenkins实例的一部分存储的。
- 作为纯文本在Git中的Jenkinsfile(纯文本文件),并将其映射到Jenkins。这更有利于确保你的配置始终处于版本控制之下。如果你有针对不同环境的特定构建和部署配置,比如开发、暂存和生产,你可以为每个环境创建一个单独的Jenkinsfile,并将其存储在该环境特定的Git仓库分支中。在这种情况下,你可以使用 "流水线 "或 "多分支流水线 "类型的作业。
在Jenkins上用Open Liberty构建云原生Java应用程序
下面的流水线示例代码构建了你的Java应用程序代码,将其打包成Docker容器镜像,并将容器镜像推送到远程容器镜像仓库,如Docker Hub或你企业内的同类仓库:
pipeline {
agent any
stages {
stage('Build') {
steps {
checkout([$class: 'GitSCM', branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[credentialsId: ‘<git token>, url: 'https://github.com/liberty/app.git']]])
sh '''
mvn -U package
docker login <remote-docker-image-repository-url> -u "${USERNAME}" -p “${PASSWORD}”
docker build -t liberty-$<code identifier>:$<docker image version> .
#eg: docker build -t liberty-app:v1.0 .
docker tag liberty-$<code identifier>:$<docker image version> <remote-docker-image-repository-url>/<docker-repo-name>/liberty-$<code identifier>:$<docker image version>
#eg: docker tag liberty-app:v1.0 docker.io/someid/liberty-app:v1.0
docker push <remote-docker-image-repository-url>/<docker-repo-name>/liberty-$<code identifier>:$<docker image version>
#eg: docker push docker.io/someid/liberty-app:v1.0
'''
}
}
}
}
其中:
-
git-token是你从Github账户生成的个人访问令牌。
-
remote-docker-image-repository-url是Docker镜像库的位置。
-
username是你在Docker镜像仓库的用户名。
-
password是你在Docker镜像仓库的密码。
-
docker-image-version是你的Docker镜像的版本号,一个唯一的标识符。
使用由Liberty Starter生成的Dockerfile或Containerfile,或者按照Open Liberty Images中描述的模式来构建你的容器镜像。Containerize指南是一个有用的资源,它详细介绍了如何为在Liberty上运行的应用程序创建一个容器镜像。
对于静态代码分析,你可以使用SonarQube社区版。SonarQube的Jenkins客户端设置细节见SonarScanner for Jenkins。下面的Maven命令示例用Maven打包代码并运行SonarQube扫描。
mvn package verify sonar:sonar -Dsonar.projectKey=sampleapp -Dsonar.host.url=http://localhost:9000 -Dsonar.login=<generated-login-key>
对于扫描容器镜像(出于安全目的),您可以使用Trivy。该扫描提供了开源JAR文件的漏洞细节,这些文件在构建应用程序时用于解决依赖关系。下面的Docker命令针对你的容器镜像运行Trivy。
docker run aquasec/trivy image docker.io/<docker-repo>/liberty-app:v1.0
其中:
- docker-repo是包含你的镜像的Docker容器库的名称。
用Open Liberty向Kubernetes部署云原生Java应用程序与Jenkins
为了简单起见,我将在Jenkins管道作业中使用命令行(CLI)代码,将带有Open Liberty的Jakarta EE和MicroProfile应用部署到Kubernetes。你也可以使用其他工具,如Helm、Travis CI和CircleCI。
在你的管道代码中,在一个新的阶段添加这些CLI命令。下面的流水线示例代码从CLI连接到IBM云,然后连接到在里面运行的Kubernetes集群,然后它运行所有与Kubernetes部署相关的配置。
ibmcloud login --apikey $IBM_CLOUD_API_KEY -g $IBM_CLOUD_RSGRP
ibmcloud ks cluster config --cluster $CLUSTER-ID
kubectl config current-context
kubectl create -f deploy/deployment.yaml #( simple k8s deployment command )
kubectl create -f deploy/service.yaml #( simple k8s service creation command )
kubectl create -f deploy/route.yaml #( simple k8s route creation command )
确保你的Kubernetes配置文件与你的Jenkinsfile存储在同一个Git仓库中,在一个名为deploy
的子目录下。还要确保Kubernetes部署配置文件中的Docker镜像名称根据Dockerfile中的容器镜像名称/标签进行更新(手动更新,如果需要在运行时改变,则以编程方式更新)。
当Jenkins检查出Java应用代码进行代码构建时,所有的Kubernetes配置文件也被下载到Jenkins工作区,这样Jenkins就可以运行IBM云和Kubernetes命令,连接到Kubernetes集群并部署应用。
有关其他命令,请参见Kubernetes文档。
用Jenkins对云原生Java应用进行QA测试
除了在代码构建阶段运行JUnit测试用例外,Jenkins可以在部署云原生Java应用后自动触发功能和集成QA测试用例。
在Jenkins作业中配置测试用例并手动测试。在 "构建触发器 "下的 "远程触发构建 "部分创建一个远程作业标识符认证令牌。通过使用远程rest API调用,从Docker "入口 "文件中触发这个测试用例,该调用使用这个认证令牌作为标识符。
例如,在终端运行以下命令:
curl -I -u <auth-token> https://<jenkins-host>/job/<job-name>/build?token=<remote-job-identifier-authentication-token>
你可以用Postman生成一个认证令牌(auth-token),使用Jenkins的登录凭证。
Kubernetes监控工具
你可以使用以下Kubernetes命令来检查应用程序或集群的日志以及内存和CPU的使用。
kubectl logs ..
cat /sys/fs/cgroup/cpu/cpuacct.usage (after connecting to k8s pod)
cat /sys/fs/cgroup/memory/memory.usage_in_bytes (after connecting to k8s pod)
你可以将不同的应用程序与Kubernetes集成在一起,以坚持日志和使用统计,如Prometheus和Grafana。
Liberty通过使用Prometheus和Grafana,可以很容易地收集和可视化系统和应用程序的指标,以便进行观察。你可以在这里列出的资源中找到指导和更多细节。
总结
你可以用很多方式配置你的DevOps管道。这篇博文快速介绍了如何使用Jenkins建立一个简单的CI/CD管道,在Liberty上构建和部署你的云原生Java应用。