As a software producer, you need to keep releases moving, even as you need to move your technology ahead. Transitioning your Jenkins continuous integration (CI) pipelines to a newer, optimized system can’t be a roadblock, and your enterprise can’t afford the work stoppage a rip-and-replace rework would require. We understood that deeply when we built our , JFrog Pipelines. That’s why we made it very easy to connect your current Jenkins pipelines to ones in JFrog Pipelines, so that you can extend your existing toolchain, not disrupt it. CI/CD solution Like many organizations, you’ve already invested hundreds of developer hours building many Jenkins pipelines that perform and have become integral to your software build process. Those Jenkins workhorses can continue to drive essential parts of your CI, but hand off to new workflows in JFrog Pipelines. Let’s take a look at how that’s done, to enable Jenkins and Pipelines to work together. Pipelines and the Platform Difference Pipelines is the CI/CD component of the end-to-end set of solutions for “one-stop DevOps.” Powered by Artifactory, the JFrog Platform provides everything you need to manage your organization’s , from , , and CI/CD automation. JFrog DevOps Platform software delivery artifact repositories distribution of binaries security scanning Chances are good that your Jenkins pipelines are already pushing artifacts and builds to Artifactory repositories for things like , , and . That’s because Artifactory’s enables connection with the DevOps tools you choose, including the most popular CI servers.That’s helped push Artifactory to be accepted as the industry standard for binary repository management. Go Docker Helm universal repository management JFrog Pipelines is the automation glue that helps m, Like Jenkins, it can move your software through each stage from code to build to binaries and all the way to distribution. But as part of the JFrog Platform, it’s naturally integrated with Artifactory, Xray, and Distribution, and can be administered through a for . unify all the tools in the JFrog DevOps Platfor unified permissions model fine-grained access control Pipelines also operates at enterprise scale, able to support hundreds of CI/CD pipelines through a single, central platform for all administrators and teams. Even with these compelling reasons to migrate your CI from Jenkins to Pipelines, it might not be practical to do so all at once. From Jenkins to Pipelines For this example, we have built a Go REST application that Jenkins will build, run unit tests and then push the application to a staging Docker repository. Next, JFrog Pipelines will deploy the Docker Go application from the staging repository to a cluster. We will use . Additionally, we will use Artifactory as our Docker registry. This makes it easy to promote the build to release without pushing the same build to another release registry. Kubernetes Google Kubernetes Engine (GKE) The contains our Go REST application, the Jenkins pipeline Jenkinsfile and the JFrog Pipeline YAML file. Per best practices, the pipeline infrastructure is defined in these files, too. code repository for this example Jenkins Pipeline Our Jenkins pipeline performs the initial build and testing of our application, pushing a Docker container to a repository with build information. Let’s take a look at our . The sections of the following Jenkinsfile that are important are the Publish Build Info and post stages. After Jenkins builds and tests our Go application image, we publish the build info to Artifactory. Jenkins pipeline <span = >stages { stage('Build') { steps { container('golang'){ sh ' build' } } } stage('Unit Tests') { steps { container('golang'){ sh ' test ./... -run Unit' } } } stage('Docker Build') { steps { container('docker'){ sh vglnk http://partnership-public-images.jfrog.io/goci- :latest nofollow -sizing: - ; : rgb( , , ); text-decoration: none; - : ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; } } } stage('Docker Push to Repo') { steps { container('docker'){ script { docker.withRegistry( '<a class= href= rel= = ><span = >https</span><span = >://</span><span = >partnership</span><span = >-</span><span = >public</span><span = >-</span><span = >images</span><span = >.</span><span = >jfrog</span><span = >.</span><span = >io</span></a>', 'gociexamplerepo' ) { sh vglnk http://partnership-public-images.jfrog.io/goci- :latest nofollow -sizing: - ; : rgb( , , ); text-decoration: none; - : ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; } } } } } <span = >stage('Publish Build Info') { environment { JFROG_CLI_OFFER_CONFIG = } steps { container('jfrog-cli- '){ withCredentials([usernamePassword(credentialsId: 'gociexamplerepo', passwordVariable: 'APIKEY', usernameVariable: 'USER')]) { sh sh sh sh vglnk https://jenkins.openshiftk8s.com/ nofollow -sizing: - ; : rgb( , , ); text-decoration: none; - : ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; vglnk https://partnership.jfrog.io/artifactory nofollow -sizing: - ; : rgb( , , ); text-decoration: none; - : ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; } } } }</span> }</span> style "box-sizing: border-box; color: rgb(153, 153, 153);" go go "docker build -t <a class=" " href=" example " rel=" " style=" box border box color 64 190 70 background color transparent "><span style=" box border box ">partnership</span><span style=" box border box ">-</span><span style=" box border box ">public</span><span style=" box border box ">-</span><span style=" box border box ">images</span><span style=" box border box ">.</span><span style=" box border box ">jfrog</span><span style=" box border box ">.</span><span style=" box border box ">io</span><span style=" box border box ">/</span><span style=" box border box ">goci</span><span style=" box border box ">-</span><span style=" box border box ">example</span><span style=" box border box ">:</span><span style=" box border box ">latest</span></a> ." "vglnk" "https://partnership-public-images.jfrog.io/" "nofollow" style "box-sizing: border-box; color: rgb(64, 190, 70); text-decoration: none; background-color: transparent;" style "box-sizing: border-box;" style "box-sizing: border-box;" style "box-sizing: border-box;" style "box-sizing: border-box;" style "box-sizing: border-box;" style "box-sizing: border-box;" style "box-sizing: border-box;" style "box-sizing: border-box;" style "box-sizing: border-box;" style "box-sizing: border-box;" style "box-sizing: border-box;" "docker push <a class=" " href=" example " rel=" " style=" box border box color 64 190 70 background color transparent "><span style=" box border box ">partnership</span><span style=" box border box ">-</span><span style=" box border box ">public</span><span style=" box border box ">-</span><span style=" box border box ">images</span><span style=" box border box ">.</span><span style=" box border box ">jfrog</span><span style=" box border box ">.</span><span style=" box border box ">io</span><span style=" box border box ">/</span><span style=" box border box ">goci</span><span style=" box border box ">-</span><span style=" box border box ">example</span><span style=" box border box ">:</span><span style=" box border box ">latest</span></a>" style "box-sizing: border-box; color: rgb(64, 190, 70);" false go "jfrog rt bce $JOB_NAME $BUILD_NUMBER" "jfrog rt bag $JOB_NAME $BUILD_NUMBER" "jfrog rt bad $JOB_NAME $BUILD_NUMBER \"go.*\"" "jfrog rt bp --build-url=<a class=" " href=" " rel=" " style=" box border box color 64 190 70 background color transparent "><span style=" box border box ">https</span><span style=" box border box ">://</span><span style=" box border box ">jenkins</span><span style=" box border box ">.</span><span style=" box border box ">openshiftk8s</span><span style=" box border box ">.</span><span style=" box border box ">com</span><span style=" box border box ">/</span></a> --url=<a class=" " href=" " rel=" " style=" box border box color 64 190 70 background color transparent "><span style=" box border box ">https</span><span style=" box border box ">://</span><span style=" box border box ">partnership</span><span style=" box border box ">.</span><span style=" box border box ">jfrog</span><span style=" box border box ">.</span><span style=" box border box ">io</span><span style=" box border box ">/</span><span style=" box border box ">artifactory</span></a> --user=$USER --apikey=$APIKEY $JOB_NAME $BUILD_NUMBER" Then in the post stage, we trigger JFrog Pipelines by referencing that build info in a special webhook call to the Pipelines REST API. We will talk about how this webhook is set up in JFrog Pipelines next. <span = >post { success { script { sh <span = > vglnk https://partnership-pipelines-api.jfrog.io/v1/projectIntegrations/ /hook/ nofollow -sizing: - ; : rgb( , , ); text-decoration: none; - : ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -d '{\ </span> } } }</span> style "box-sizing: border-box; color: rgb(153, 153, 153);" style "box-sizing: border-box; color: rgb(64, 190, 70);" "curl -XPOST -H \"Authorization: Basic amVmabcdefM25rMW5z=\" \"<a class=" " href=" 17 " rel=" " style=" box border box color 64 190 70 background color transparent "><span style=" box border box ">https</span><span style=" box border box ">://</span><span style=" box border box ">partnership</span><span style=" box border box ">-</span><span style=" box border box ">pipelines</span><span style=" box border box ">-</span><span style=" box border box ">api</span><span style=" box border box ">.</span><span style=" box border box ">jfrog</span><span style=" box border box ">.</span><span style=" box border box ">io</span><span style=" box border box ">/</span><span style=" box border box ">v1</span><span style=" box border box ">/</span><span style=" box border box ">projectIntegrations</span><span style=" box border box ">/</span><span style=" box border box ">17</span><span style=" box border box ">/</span><span style=" box border box ">hook</span><span style=" box border box ">\</span></a>" "buildName\":\"$JOB_NAME\",\"buildNumber\":\"$BUILD_NUMBER\",\"buildInfoResourceName\":\"jenkinsBuildInfo\"}' -H \"Content-Type: application/json\"" JFrog Pipelines Our JFrog Pipeline will trigger through the build info pushed by the Jenkins pipeline, and perform the remaining deployment and staging actions to release. To connect Jenkins to JFrog Pipelines, we must first create a in our Pipelines deployment, here called jenkins_openshiftk8s_com. This UI provides our curl webhook command above, and enables our Jenkins pipeline to trigger our JFrog pipeline. Jenkins integration JFrog Pipelines defines its . The first section of this file is our resources. These are sources and destinations of data that are used by the pipeline. In our case, we are defining our GitHub repo, a resource connected to the jenkins_openshiftk8s_com Jenkins integration, and a final BuildInfo resource to promote our release. The BuildInfo resource is used to store metadata for our build. pipeline steps in YAML BuildInfo <span style="box-sizing: border-box; color: rgb(153, 153 , 153 );">resources: - name: gociexampleGithubRepo type: GitRepo configuration: gitProvider: myGithub path: myaccount/goci-example <span style="box-sizing: border-box; color: rgb(64, 190 , 70 );"> - name: jenkinsBuildInfo type: BuildInfo configuration: sourceArtifactory: MyArtifactory buildName: goci-example/master buildNumber: 1 externalCI: jenkins_openshiftk8s_com</span> - name: releaseBuildInfo type: BuildInfo configuration: sourceArtifactory: MyArtifactory buildName: goci-example/master buildNumber: 1 </span> Our first step is a step that receives our Jenkins trigger through jenkinsBuildInfo. Bash <span style="box-sizing: border-box; color: rgb(153, 153 , 153 );">- name: start_from_jenkins type: Bash configuration: <span style="box-sizing: border-box; color: rgb(64, 190 , 70 );"> inputResources: - name: jenkinsBuildInfo</span> execution: onExecute: - echo 'Jenkins job triggered Pipelines' </span> If all goes well, we then deploy our Go REST application to our staging environment. In this case, we have a GKE cluster for this. We reference this cluster through a named gociexampleClusterCreds . We can by providing our kubeconfig data as an Integration object. Kubernetes integration integrate with any Kubernetes cluster We use the step to deploy our application using a HelmChart directory in our repo. HelmDeploy <span style="box-sizing: border-box; color: rgb(153, 153 , 153 );">- name: deploy_staging type: HelmDeploy configuration: inputSteps: - name: start_from_jenkins inputResources: - name: gociexampleGithubRepo trigger: false integrations: - name: gociexampleClusterCreds releaseName: goci-example chartPath: chart/goci-example/</span> Then we have a Bash step that waits for the Go REST application to become available. <span = >- name: wait_for_server type: Bash configuration: inputSteps: - name: deploy_staging execution: onExecute: - timeout bash -c ' [[ vglnk http://goci- .35.238.177.209.xip.io/ nofollow -sizing: - ; : rgb( , , ); text-decoration: none; - : ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; != ]]; sleep ; done' || </span> style "box-sizing: border-box; color: rgb(153, 153, 153);" 60 while "$(curl -s -o /dev/null -w ''%{http_code}'' <a class=" " href=" example " rel=" " style=" box border box color 64 190 70 background color transparent "><span style=" box border box ">http</span><span style=" box border box ">://</span><span style=" box border box ">goci</span><span style=" box border box ">-</span><span style=" box border box ">example</span><span style=" box border box ">.</span><span style=" box border box ">35</span><span style=" box border box ">.</span><span style=" box border box ">238</span><span style=" box border box ">.</span><span style=" box border box ">177</span><span style=" box border box ">.</span><span style=" box border box ">209</span><span style=" box border box ">.</span><span style=" box border box ">xip</span><span style=" box border box ">.</span><span style=" box border box ">io</span></a>)" "200" do 5 true Once our Go REST application comes up in our staging environment, we execute our staging tests. <span = >- name: staging_test type: Bash configuration: inputSteps: - name: wait_for_server inputResources: - name: gociexampleGithubRepo trigger: runtime: type: : auto: language: versions: - environmentVariables: STAGING_URL: vglnk http://goci- .35.238.177.209.xip.io/ nofollow -sizing: - ; : rgb( , , ); text-decoration: none; - : ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; -sizing: - ; execution: onExecute: - cd ../dependencyState/resources/gociexampleGithubRepo - download - test ./test -run Staging</span> style "box-sizing: border-box; color: rgb(153, 153, 153);" false image image go "1.13" "<a class=" " href=" example " rel=" " style=" box border box color 64 190 70 background color transparent "><span style=" box border box ">http</span><span style=" box border box ">://</span><span style=" box border box ">goci</span><span style=" box border box ">-</span><span style=" box border box ">example</span><span style=" box border box ">.</span><span style=" box border box ">35</span><span style=" box border box ">.</span><span style=" box border box ">238</span><span style=" box border box ">.</span><span style=" box border box ">177</span><span style=" box border box ">.</span><span style=" box border box ">209</span><span style=" box border box ">.</span><span style=" box border box ">xip</span><span style=" box border box ">.</span><span style=" box border box ">io</span></a>" go mod go Finally, if our staging tests pass, we promote the build to release. <span style="box-sizing: border-box; color: rgb(153, 153 , 153 );">- name: promote_release type: PromoteBuild configuration: targetRepository: partnership-public-images.jfrog.io status: Released comment: Passed staging tests. inputResources: - name: jenkinsBuildInfo outputResources: - name: releaseBuildInfo</span> Our JFrog Pipeline can be further extended to provide continuous delivery (CD) operations using JFrog Distribution to publish your software to end systems and JFrog Edge systems. But we will leave that to a future blog post. Keep DevOps Moving As you can see, it’s a straightforward process to connect your Jenkins pipeline to one in JFrog Pipelines. If needed, you can also . trigger a Jenkins pipeline from JFrog Pipelines Developing your software delivery toolchain from a patchwork of tools can be a time consuming and frustrating task. Using a unified toolchain like the JFrog Platform allows you to focus on your software and not the tools. But if you have existing tools, you can easily plug these into the JFrog platform and still take advantage of the JFrog Platform features. This article is written by Jeff Fry, A senior developer at JFrog.