OpenShift CI/CD Concepts: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
 
(115 intermediate revisions by the same user not shown)
Line 2: Line 2:


* https://docs.openshift.com/container-platform/latest/using_images/other_images/jenkins.html
* https://docs.openshift.com/container-platform/latest/using_images/other_images/jenkins.html
* https://blog.openshift.com/cicd-with-openshift/, youtu.be demos: 65BnTLcDAJI, wSFyg6Etwx8
* https://blog.openshift.com/cicd-with-openshift/


=Internal=
=Internal=


* [[OpenShift_Concepts#CI.2FCD|OpenShift Concepts]]
* [[OpenShift CI/CD Operations]]
* [[Jenkins]]
* [[Jenkins]]
* [[OpenShift_Concepts#CICD_Support|OpenShift Concepts]]
* [[OpenShift CI/CD Operations]]


=Overview=
=Overview=


OpenShift provides a certified Jenkins container for building Continuous Delivery pipelines, which can be deployed as a pod in OpenShift. OpenShift comes with [[#OpenShift_Jenkins_Templates|standard Jenkins templates]], which are recommended to be used when implementing CI/CD pipelines.
This article aggregates concepts related to the implementation of CI/CD pipelines in OpenShift. OpenShift relies on [[Jenkins]] to execute the core pipeline logic - [[Jenkins_Concepts#Pipeline|pipeline]] is a Jenkins concept - so Jenkins is integrated with OpenShift by default. Integration details are discussed in the [[#Jenkins_Integration|Jenkins Integration]] section. CI/CD pipelines can be declared natively in OpenShift as [[OpenShift Concepts#Pipeline_Build|pipeline builds]].
 
Once deployed, Jenkins spins up two pods: the main "jenkins" pod which contains the functionality that drives the build logic, and a "jenkins-jnlp" pod that is an auxiliary service used for master/slave communication. <font color=red>Why doesn't the CI/CD project have a jenkins-jnlp pod? The service exists, maybe the pod was not needed yet? There is no container template for jenkins-jnlp.</font> The template also creates a "jenkins" service account used by the Jenkins pod to authenticate. The service account is automatically bound to the "edit" role in the target project.
 
The Jenkins pod can be collocated with the application it is intended to build, within the same project, or it can inhabit its own dedicated project and can provide CI/CD services to other projects, which share the common instance. The [[#Collocated_Jenkins|Collocated Jenkins]] section addresses aspects that are specific to a Jenkins instance that lives in the same OpenShift project with the application it services. The [[#Shared_Jenkins|Shared Jenkins]] section describes the particularities of the situation when a single Jenkins instance is shared by multiple projects.
 
<font color=red>The Jenkins instance can be left with a default [[#Build_Environment|build environment]], which is completely oblivious of OpenShift, but in this case it will attempt to run a build inside de pod and it will fail due to lack of Maven or other utilities. The alternative is to use a [[#Kubernetes_Plugin|Kubernetes plugin]] build environment, which dynamically provisions [[Jenkins_Concepts#Slave|Jenkins slaves]] on OpenShift nodes. More details are available in the [[#Kubernetes_Plugin|Kubernetes Plugin]] section.</font>
 
=Jenkins=
 
Jenkins is used by OpenShift to provide the execution engine behind [[OpenShift Concepts#Pipeline_Build|OpenShift pipeline builds]].
 
==Shared Jenkins Instance==
 
Jenkins instance(s) is/are deployed as a pod. The Jenkins pod can be deployed within the project that needs CI/CD services, or it can be deployed in a shared project, accessed by all projects that need CI/CD services. The system-wide Jenkins instance must be declared in [[Master-config.yml#Shared_Jenkins_Instance_Configuration|master-config.yaml]].
 
==OpenShift Jenkins Docker Image==


The Jenkins image intended to use with OpenShift is developed under this repository https://github.com/openshift/jenkins. The repository contains the Dockerfiles that can be used to build the image. The images are pushed to DockerHub as openshift/jenkins-2-centos7, openshift/jenkins-slave-base-centos7, openshift/jenkins-slave-maven-centos7, and openshift/jenkins-slave-nodejs-centos7 and OpenShift Container Platform integrates them with the enterprise product.
=Jenkins Integration=


===Jenkins Heap Sizing===
==Jenkins Service Initialization==


The heap sizing is calculated by the container's [[Dockerfile#CMD|CMD]] script (/usr/libexec/s2i/run) based on the OpenShift memory limit set in the deployment configuration, which propagates to the container as [[Docker_Container_Downward_API#memory.limit_in_bytes|/sys/fs/cgroup/memory/memory.limit_in_bytes]], and CONTAINER_HEAP_PERCENT.
When a project declares a [[OpenShift_Concepts#Pipeline_Build|pipeline build configuration]], OpenShift looks for a project [[OpenShift_Concepts#Service|service]] named "jenkins". "jenkins" is the default value, but the name of the service can be configured as [[Master-config.yml#serviceName|jenkinsPipelineConfig.serviceName]] in master-config.yml.


If the JVM_ARCH environment variable is set at [[CI/CD_Infrastructure_Setup#Deploy_Jenkins|installation from template]], the memory calculated as mentioned above. If not, and the memory of the container is less than 4GB, meaning max heap of 2GB, 32bit is forced to save space.
If no Jenkins service exists in the project and master-config.yml [[Master-config.yml#autoProvisionEnabled|jenkinsPipelineConfig.autoProvisionEnabled]] is set to "true", which is the default, OpenShift executes the [[Master-config.yml#templateName|jenkinsPipelineConfig.templateName]] template, which it expected to be available in the [[Master-config.yml#templateNamespace|jenkinsPipelineConfig.templateNamespace]] namespace. The default values are "jerkins-ephemeral" and "openshift", respectively. However, if the auto-provisioning is explicitly disabled, and no Jenkins service is defined in the project, a pipeline build configuration won't trigger any build, and if the build is start manually, it will just hang in the "New" state. No error message or events will be triggered. This behavior was noticed in OpenShift 3.6.


The template comes with a small metaspace, which can be increased with "JAVA_GC_OPTS="-XX:+UseParallelGC -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=40 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:MaxMetaspaceSize=384m"
<font color=red>I have never got this running, the closest I got is described in [[OpenShift_Service_Operations#Integrate_a_Service_Running_in_a_Different_Project|Integrate a Service Running in a Different Project]], but the build would not start:</font> <font color=darkgrey>Individual projects may be configured to avoid starting their own Jenkins infrastructure and use a shared Jenkins instance, typically deployed in a dedicated CI/CD project. To do that, they must declare a [[#OpenShift Concepts#Service|service]] named "jenkins" or whatever the value of master-config.yml [[Master-config.yml#serviceName|jenkinsPipelineConfig.serviceName]] service name is, which carries the endpoints of the shared Jenkins service.</font>


==OpenShift Jenkins Templates==
==Jenkins Images and Templates==


OpenShift comes with two standard Jenkins templates ("jerkins-ephemeral" and "jenkins-persistent"), both available in the "[[OpenShift_Concepts#.22openshift.22_Project|openshift]]" namespace:
OpenShift provides a certified Jenkins container image, developed under https://github.com/openshift/jenkins repository. OpenShift also comes with two standard templates that use this image to create Jenkins infrastructure objects. The "jenkins-ephemeral" and "jenkins-persistent" are available in the "[[OpenShift_Concepts#.22openshift.22_Project|openshift]]" namespace. The "persistent" Jenkins will save its state between the pod restarts, and needs a [[OpenShift_Concepts#Persistent_Volume|persistent volume]] with sufficient storage space to be available at the time of the installation.


  oc -n openshift get templates | grep jenkins
  oc -n openshift get templates | grep jenkins
  jenkins-ephemeral      Jenkins service, without persistent storage....     
  jenkins-ephemeral      Jenkins service, without persistent storage....     
  jenkins-persistent      Jenkins service, with persistent storage....      
  jenkins-persistent      Jenkins service, with persistent storage....


They can be used to deploy an "ephemeral" or a "persistent" Jenkins. The "persistent" Jenkins will save its state between the pod restarts, and needs a [[OpenShift_Concepts#Persistent_Volume|persistent volume]] with sufficient storage space to be available at the time of the installation.
Upon instantiations, the Jenkins templates create a deployment configuration for the Jenkins pod (dc/jenkins), two services (jenkins and jenkins-jnlp) and a route that makes jenkins publicly accessible as "jenkins-''project-name''.apps... The deployment configuration then creates the Jenkins pod.


==Build Environment==
==Jenkins Heap Sizing==


<font color=red>
The heap sizing is calculated by the container's [[Dockerfile#CMD|CMD]] script (/usr/libexec/s2i/run) based on the OpenShift memory limit set in the deployment configuration, which propagates to the container as [[Docker_Container_Downward_API#memory.limit_in_bytes|/sys/fs/cgroup/memory/memory.limit_in_bytes]], and CONTAINER_HEAP_PERCENT.
 
OpenShift Jenkins image comes pre-preconfigured to allow access to a Kubernetes CLI (kubectl) build environment, which uses the [[#Kubernetes_Plugin|Kubernetes plugin]] to provision Kubernetes-based [[Jenkins_Concepts#Agent|Jenkins agents]].
 
::[[Image:Jenkins_Build_Environment.png]]
 
For more details about Jenkins build environment, see: {{Internal|Jenkins_Concepts#Build_Environment|Jenkins Build Environment}}
 
</font>
 
==Pipeline==
 
An ''OpenShift Jenkins pipeline'' is a  [[Jenkins_Concepts#Pipeline|Jenkins Pipeline]] .... <font color=red>'''TODO'''</font>. OpenShift Jenkins pipeline are an essential component of the [[OpenShift Concepts#Pipeline_Build|OpenShift pipeline builds]].
 
<font color=red>'''TODO'''</font>


If the JVM_ARCH environment variable is set at [[CI/CD_Infrastructure_Setup#Deploy_Jenkins|installation from template]], the memory calculated as mentioned above. If not, and the memory of the container is less than 4GB, meaning max heap of 2GB, 32bit is forced to save space. The template comes with a small metaspace, which can be increased with "JAVA_GC_OPTS="-XX:+UseParallelGC -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=40 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:MaxMetaspaceSize=384m"


=OpenShift Jenkins Plugins=


Jenkins is ultimately the application that drives the pipeline logic so it first need to be told what to do, via its Groovy pipeline syntax, and then it needs to execute the actions, and while doing so, it needs to access and modify OpenShift resources. All these are implemented via a series of plugins, described below:


==OpenShift Plugin for Jenkins (jenkins-plugin)==


{{External|https://docs.openshift.com/container-platform/latest/install_config/configuring_pipeline_execution.html}}
This is the oldest Jenkins/OpenShift integration plugin, which executes inside Jenkins and implements a series of REST flows that interface with the OpenShift master server via its exposed API. This plugin '''does not require''' the [[oc]] binary to be present on the host that executes the plugin logic.


Pipelines can be defined in-line in the Jenkins job, or in the source code repository, in a file named "Jenkinsfile". The pipelines are written in Groovy. Jenkins drives the pipeline, but it uses OpenShift to perform the build and the deployment, by invoking OpenShift API via "openshiftBuild", "openshiftVerifyBuild", "openshiftDeploy", "openshiftVerifyDeployment", "openshiftVerifyService". Used by the [[OpenShift Concepts#Pipeline_Build|pipeline build]].
{{Internal|OpenShift Plugin for Jenkins (jenkins-plugin)|OpenShift Plugin for Jenkins (jenkins-plugin)}}


The pipeline definition starts with a node() statement.
==OpenShift Jenkins Pipeline DSL Plugin (jenkins-client-plugin)==


node('maven') {
This plugin provides a Jenkins pipeline DSL syntax for interactions with OpenShit. This plugin '''needs''' the [[oc]] binary to be present on the nodes executing the script. The plugin seems to be newer than the [[#OpenShift_Plugin_for_Jenkins_.28jenkins-plugin.29|OpenShift Plugin for Jenkins (jenkins-plugin)]]. Plugin usage and syntax details are available here:
...
}


defines a pipeline that runs inside of a Maven pod.
{{Internal|OpenShift Jenkins Pipeline DSL Plugin (jenkins-client-plugin)|OpenShift Jenkins Pipeline DSL Plugin (jenkins-client-plugin)}}


node {
==jenkins-sync-plugin==
...
}


defines a pipeline that executes in a Jenkins pod.
{{External|https://github.com/openshift/jenkins-sync-plugin}}


Possible node values: "maven", "nodejs", "custom".
This plugin keeps OpenShift [[OpenShift_Concepts#Pipeline_Build|build configuration]] and [[OpenShift_Concepts#Build|build]] objects in sync with [[Jenkins_Concepts#Job|jobs]] and [[Jenkins_Concepts#Build|builds]] managed by the OpenShift-integrated Jenkins instances.  


A pipeline consists of ''stages'', which have graphical representation in Jenkins or OpenShift UI. A stage can be used to group tasks, and they should be scoped with { and }.
The plugin insures that any changes operated on OpenShift pipeline build configuration is propagated to the Jenkins job with the same name. When an OpenShift user triggers a build based on a pipeline build configuration, the plugin starts the corresponding Jenkins job. While the Jenkins build that is associated with the job is running, any changes in the build are replicated in the corresponding OpenShift build object. The plugin also examine ConfigMaps looking for XML documents that correspond to [[#Kubernetes_Plugin|Kubernetes plugin]] pod templates, and changes the configuration of the Kubernetes plugin to add, edit or remove pod templates based on those found in the ConfigMaps. The plugin monitors changes in image streams labeled with "role=jenkins-slave" and image stream tags with a "role=jenkins-slave" annotation and updates the Kubernetes plugin pod templates accordingly.


===Pipeline Definition===
==jenkins-openshift-login-plugin==


node {
{{External|https://github.com/openshift/jenkins-openshift-login-plugin}}
  stage ("<font color=darkblue>'''Build'''</font>") {
    ...
    <font color=teal>'''openshiftBuild'''</font>
                  apiURL: 'https&#58;//openshift.default.svc.cluster.local',
                  authToken: '',
                  bldCfg: 'hello-nodejs',
                  buildName: '',
                  checkForTriggeredDeployments: 'false',
                  commitID: '',
                  namespace: '',
                  showBuildLogs: 'false',
                  verbose: 'false',
                  waitTime: ''
    <font color=teal>'''openshiftVerifyBuild'''</font>
                  apiURL: 'https&#58;//openshift.default.svc.cluster.local',
                  authToken: '',
                    bldCfg: 'hello-nodejs',
                    checkForTriggeredDeployments:
                  'false', namespace: '',
                  verbose: 'false'
    <font color=teal>'''openshiftTag'''</font>
                  ...
  }
  stage ("<font color=darkblue>'''Deploy'''</font>") {
    ...
    <font color=teal>'''openshiftDeploy'''</font> 
                  apiURL: 'https&#58;//openshift.default.svc.cluster.local',
                  authToken: '',
                  depCfg: 'hello-nodejs',
                  namespace: '',
                  verbose: 'false',
                  waitTime: ''
    <font color=teal>'''openshiftVerifyDeployment'''</font> 
                  apiURL: 'https&#58;//openshift.default.svc.cluster.local',
                  authToken: '',
                  depCfg: 'hello-nodejs',
                  namespace: '',
                  replicaCount: '1',                   
                  verbose: 'false',
                  verifyReplicaCount: 'false',
                  waitTime: ''
  }
  stage ("<font color=darkblue>'''Verify'''</font>") {
    ...
    <font color=teal>'''openshiftVerifyService'''</font> 
                  apiURL: 'https&#58;//openshift.default.svc.cluster.local',
                  authToken: '',
                  namespace: '',
                  svcName: 'hello-nodejs',
                  verbose: 'false'
  }
}


=Kubernetes Plugin=
==Kubernetes Plugin==


{{External|https://plugins.jenkins.io/kubernetes}}
{{External|https://plugins.jenkins.io/kubernetes}}
{{External|https://wiki.jenkins.io/display/JENKINS/Kubernetes+Plugin}}
{{External|https://docs.openshift.org/latest/using_images/other_images/jenkins.html#using-the-jenkins-kubernetes-plug-in-to-run-jobs}}
{{External|https://docs.openshift.org/latest/using_images/other_images/jenkins.html#using-the-jenkins-kubernetes-plug-in-to-run-jobs}}


The Kubernetes plug-in is a Jenkins extension that uses a Kubernetes cluster to dynamically provision [[Jenkins_Concepts#Agent|Jenkins agents]], use them to run builds and then dispose of them. It does do by using Kubernetes scheduling mechanism to optimize the load. The Jenkins images that ship with OpenShift comes with the Kubernetes plugin pre-installed.
The Kubernetes plugin is a Jenkins extension that uses a Kubernetes cluster to dynamically provision [[Jenkins_Concepts#Agent|Jenkins agents]], use them to run builds and then dispose of them. It does do by using Kubernetes scheduling mechanism to optimize the load. The [[#Jenkins_Images_and_Templates|Jenkins image]] that ships with OpenShift comes with the Kubernetes plugin pre-installed. The OpenShift Plugin for Jenkins allows specifying agents as [[OpenShift_Plugin_for_Jenkins_(jenkins-plugin)#Jenkins_Slave_Pods|slave pods]].
 
An example of how to configure and use the Kubernetes plugin is available here:
 
{{Internal|OpenShift_CI/CD_Operations_-_Collocated_Persistent_Jenkins_Set_Up#Use_of_Kubernetes_Plugin|Use of Kubernetes Plugin for a Collocated Persistent Jenkins}}
 
 
<font color=red>'''TODO''': deplete https://docs.openshift.org/latest/using_images/other_images/jenkins.html#using-the-jenkins-kubernetes-plug-in-to-run-jobs</font>
 
=OpenShift Jenkins Plugin=
 
{{External|https://github.com/openshift/jenkins-plugin}}
 
The OpenShift Jenkins Plugin is another Jenkins extension that exposes OpenShift-specific build and post-build actions in Jenkins:
 
::[[Image:OpenShift_Jenkins_Plugin.png]]
 
A step-by-step example of how to use the OpenShift Jenkins Plugin is available here: {{Internal|OpenShift CI/CD Operations - Collocated Persistent Jenkins Set Up|Collocated Jenkins Deployment and Set Up}}
 
=OpenShift Pipeline Plugin=
 
=Collocated Jenkins=
 
This section addresses aspects that are specific to a Jenkins instance that lives in the same OpenShift project with the application it services.
 
This is an example of a project that sets up a collocated Jenkins instance and uses it to build and deploy an application:
 
{{Internal|OpenShift CI/CD Operations - Collocated Persistent Jenkins Set Up|Collocated Jenkins Deployment and Set Up}}
 
=Shared Jenkins=
 
This section describes the particularities of the situation when a single Jenkins instance is shared by multiple projects.
 
<font color=red>'''TODO''': [[#Cross-Project_Access]].</font>
 
=Security Considerations=
 
Jenkins components need to access the OpenShift API exposed by the master for various operations: to access container images, to trigger a build, to check the status of a build, etc. so special privileges need to be assigned to the service account associated with the Jenkins deployment. By default, Jenkins authenticates to the API using the "system:serviceaccount:<''project-name''>:default [[OpenShift_Security_Concepts#Service_Account|service account]], where <''project-name''> is the name of the project the Jenkins pod runs in. The service account must be granted the "edit" role. "default" is a generic account, so in some cases it may be better to created a dedicated "jenkins" service account, to be used by the Jenkins processes: "system:serviceaccount:<''project-name''>:jenkins. The [[OpenShift_CI/CD_Concepts#OpenShift_Jenkins_Templates|standard Jenkins templates that come with OpenShift]] create the "jenkins" service account and give it the appropriate privileges automatically.
 
* <font color=red>'''TODO''': OAuth authentication: https://docs.openshift.com/container-platform/latest/using_images/other_images/jenkins.html#jenkins-openshift-oauth-authentication</font>
* <font color=red>'''TODO''': Standard authentication: https://docs.openshift.com/container-platform/latest/using_images/other_images/jenkins.html#jenkins-jenkins-standard-authentication</font>
 
==Cross-Project Access==
 
If Jenkins is configured to perform CI/CD services for other projects, the service account associated with the Jenkins pods in the Jenkins project must be granted elevated privileges in the client projects:
 
[[Oc_policy#add-role-to-user|oc policy add-role-to-user]] edit system:serviceaccount:<''jenkins-project-name''>:jenkins -n <''client-project''>
 
To list the roles associated with a service account, use [[OpenShift_Security_Operations#List_All_Project_Role_Bindings|oc get rolebindings or oc describe policyBindings]].
 
* <font color=red>'''TODO''': Cross-project access: https://docs.openshift.com/container-platform/latest/using_images/other_images/jenkins.html#jenkins-cross-project-access</font>
 
==OpenShift Login Plugin==
 
Authentication is managed by default by the OpenShift Login plugin, when the access is done via a public [[OpenShift Concepts#Route|route]]. If you intend to log into Jenkins via the [[OpenShift Concepts#Service|service]] IP, you will need to annotate the Jenkins service account with a redirect URL so that the OAuth server's whitelist is updated and it allows the login to complete.
oc annotate sa/jenkins serviceaccounts.openshift.io/oauth-redirecturi.1=http&#58;//<''jenkins_service_ip'':''jenkins_service_port''>/securityRealm/finishLogin --overwrite
 
=TO DEPLETE=
 
{{Error|Deplete anything under this.}}
 
 
 
When necessary, it scales the pipeline execution by on-demand provisioning of multiple Jenkins containers, allowing Jenkins to run many jobs in parallel. OpenShift can integrate with Git-based source code repositories. When a developer pushes code to the GIt repository, Jenkins pulls the code and performs a project build. After the build is complete, Jenkins invokes the OpenShift master node API to initiate a [[#Source-to-Image_.28S2I.29_Build|"source-to-image" (S2I) build]]. As part of the SI process, the latest project artifact is downloaded from Jenkins and included in the image that runs in the OpenShift node.
 
=Jenkins Pods and Projects=
 
Jenkins infrastructure can run in an arbitrary project, on a per-project basis, but a more common setup is to create a dedicated CI/CD project and configure it to perform CI/CD services for other "client" projects.
 
Jenkins ''slave pods'' - they are configured in Jenkins system configuration as Kubernetes pods. Jenkins executes builds in separated pods in the same project it belongs. This is possible due to the Jenkins Kubernetes Plug-in. However, the builds do not use Jenkins pod resources. The slave pods included with OpenShift are the base pod to build custom slave pods, Node.js and Maven ("jenkins-slave-maven-rhel7").
 
=Auxiliary Tools=
 
* [[OpenShift Nexus|Nexus]]
* [[OpenShift Gogs|Gogs]]
* [[OpenShift SonarQube|SonarQube]]
 
=Jenkinsfile=
 
''Jenkinsfile'' contains the definition of the pipeline that drives an [[OpenShift Concepts#Pipeline_Build|OpenShift pipeline build]], written in Groovy. It can be injected into a pipeline build configuration in two ways: [[#Inline_Jenkinsfile|inline in the build configuration]] and as a [[#Jenkinsfile_in_Source_Repository|file in the source repository]].  
 
More details about the Jenkinsfile syntax:


{{Internal|Jenkins Pipeline Syntax|Jenkins Pipeline Syntax}}
=Pipeline Logic Declaration=


==Inline Jenkinsfile==
Pipeline logic is declared in Groovy, either [[#Inline_Pipeline_Logic_Declaration|inline in the build configuration]], or as a [[#Jenkinsfile|Jenkinsfile]] stored in the source code repository.  For syntax, see {{Internal|OpenShift_Build_Configuration_Definition|Build Configuration}}


The Jenkins pipeline logic can be specified in-line in the build configuration as follows:
==<span id='Inline_Jenkinsfile'></span>Inline Pipeline Logic Declaration==


  apiVersion: "v1"
  apiVersion: "v1"
Line 254: Line 89:
     '''type''': '''JenkinsPipeline'''
     '''type''': '''JenkinsPipeline'''
     '''jenkinsPipelineStrategy''':
     '''jenkinsPipelineStrategy''':
      env:
        - name: ENV_VAR_1
          value: "..."
       '''jenkinsfile''': |
       '''jenkinsfile''': |
         //
         //
         // in-line pipeline code, more about [[Jenkins_Pipeline_Syntax|Jenkins pipeline syntax]]
         // in-line pipeline code
         //
         //
         ...
         ...


==Jenkinsfile in Source Repository==
==Jenkinsfile==
 
''Jenkinsfile'' contains the definition of the pipeline that drives an [[OpenShift Concepts#Pipeline_Build|OpenShift pipeline build]], written in Groovy. The [[OpenShift Concepts#Pipeline_Build|OpenShift pipeline build configuration]] can be written in such a way to refer to it:


  apiVersion: "v1"
  apiVersion: "v1"
Line 273: Line 113:
     '''type''': '''JenkinsPipeline'''
     '''type''': '''JenkinsPipeline'''
     '''jenkinsPipelineStrategy''':
     '''jenkinsPipelineStrategy''':
       '''jenkinsfilePath''': "jenkinsfile/path/relative/to/the/root/of/the/repository"
      env:
        - name: ENV_VAR_1
          value: "..."
       '''jenkinsfilePath''': "jenkinsfile/path/relative/to/the/root/of/the/repository/Jenkinsfile"
 
Note that 'jenkinsfilePath' must contain the relative path '''and''' the name of the file.
 
A Jenkinsfile maintained in the source code and version controlled is the preferred way of specifying the pipeline logic.
 
=Deplete=
 
{{Internal|OpenShift CI/CD Concepts TODEPLETE|OpenShift CI/CD Concepts TODEPLETE}}

Latest revision as of 18:33, 12 December 2017

External

Internal

Overview

This article aggregates concepts related to the implementation of CI/CD pipelines in OpenShift. OpenShift relies on Jenkins to execute the core pipeline logic - pipeline is a Jenkins concept - so Jenkins is integrated with OpenShift by default. Integration details are discussed in the Jenkins Integration section. CI/CD pipelines can be declared natively in OpenShift as pipeline builds.

Jenkins Integration

Jenkins Service Initialization

When a project declares a pipeline build configuration, OpenShift looks for a project service named "jenkins". "jenkins" is the default value, but the name of the service can be configured as jenkinsPipelineConfig.serviceName in master-config.yml.

If no Jenkins service exists in the project and master-config.yml jenkinsPipelineConfig.autoProvisionEnabled is set to "true", which is the default, OpenShift executes the jenkinsPipelineConfig.templateName template, which it expected to be available in the jenkinsPipelineConfig.templateNamespace namespace. The default values are "jerkins-ephemeral" and "openshift", respectively. However, if the auto-provisioning is explicitly disabled, and no Jenkins service is defined in the project, a pipeline build configuration won't trigger any build, and if the build is start manually, it will just hang in the "New" state. No error message or events will be triggered. This behavior was noticed in OpenShift 3.6.

I have never got this running, the closest I got is described in Integrate a Service Running in a Different Project, but the build would not start: Individual projects may be configured to avoid starting their own Jenkins infrastructure and use a shared Jenkins instance, typically deployed in a dedicated CI/CD project. To do that, they must declare a service named "jenkins" or whatever the value of master-config.yml jenkinsPipelineConfig.serviceName service name is, which carries the endpoints of the shared Jenkins service.

Jenkins Images and Templates

OpenShift provides a certified Jenkins container image, developed under https://github.com/openshift/jenkins repository. OpenShift also comes with two standard templates that use this image to create Jenkins infrastructure objects. The "jenkins-ephemeral" and "jenkins-persistent" are available in the "openshift" namespace. The "persistent" Jenkins will save its state between the pod restarts, and needs a persistent volume with sufficient storage space to be available at the time of the installation.

oc -n openshift get templates | grep jenkins
jenkins-ephemeral       Jenkins service, without persistent storage....     
jenkins-persistent      Jenkins service, with persistent storage....

Upon instantiations, the Jenkins templates create a deployment configuration for the Jenkins pod (dc/jenkins), two services (jenkins and jenkins-jnlp) and a route that makes jenkins publicly accessible as "jenkins-project-name.apps... The deployment configuration then creates the Jenkins pod.

Jenkins Heap Sizing

The heap sizing is calculated by the container's CMD script (/usr/libexec/s2i/run) based on the OpenShift memory limit set in the deployment configuration, which propagates to the container as /sys/fs/cgroup/memory/memory.limit_in_bytes, and CONTAINER_HEAP_PERCENT.

If the JVM_ARCH environment variable is set at installation from template, the memory calculated as mentioned above. If not, and the memory of the container is less than 4GB, meaning max heap of 2GB, 32bit is forced to save space. The template comes with a small metaspace, which can be increased with "JAVA_GC_OPTS="-XX:+UseParallelGC -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=40 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:MaxMetaspaceSize=384m"

OpenShift Jenkins Plugins

Jenkins is ultimately the application that drives the pipeline logic so it first need to be told what to do, via its Groovy pipeline syntax, and then it needs to execute the actions, and while doing so, it needs to access and modify OpenShift resources. All these are implemented via a series of plugins, described below:

OpenShift Plugin for Jenkins (jenkins-plugin)

This is the oldest Jenkins/OpenShift integration plugin, which executes inside Jenkins and implements a series of REST flows that interface with the OpenShift master server via its exposed API. This plugin does not require the oc binary to be present on the host that executes the plugin logic.

OpenShift Plugin for Jenkins (jenkins-plugin)

OpenShift Jenkins Pipeline DSL Plugin (jenkins-client-plugin)

This plugin provides a Jenkins pipeline DSL syntax for interactions with OpenShit. This plugin needs the oc binary to be present on the nodes executing the script. The plugin seems to be newer than the OpenShift Plugin for Jenkins (jenkins-plugin). Plugin usage and syntax details are available here:

OpenShift Jenkins Pipeline DSL Plugin (jenkins-client-plugin)

jenkins-sync-plugin

https://github.com/openshift/jenkins-sync-plugin

This plugin keeps OpenShift build configuration and build objects in sync with jobs and builds managed by the OpenShift-integrated Jenkins instances.

The plugin insures that any changes operated on OpenShift pipeline build configuration is propagated to the Jenkins job with the same name. When an OpenShift user triggers a build based on a pipeline build configuration, the plugin starts the corresponding Jenkins job. While the Jenkins build that is associated with the job is running, any changes in the build are replicated in the corresponding OpenShift build object. The plugin also examine ConfigMaps looking for XML documents that correspond to Kubernetes plugin pod templates, and changes the configuration of the Kubernetes plugin to add, edit or remove pod templates based on those found in the ConfigMaps. The plugin monitors changes in image streams labeled with "role=jenkins-slave" and image stream tags with a "role=jenkins-slave" annotation and updates the Kubernetes plugin pod templates accordingly.

jenkins-openshift-login-plugin

https://github.com/openshift/jenkins-openshift-login-plugin

Kubernetes Plugin

https://plugins.jenkins.io/kubernetes
https://docs.openshift.org/latest/using_images/other_images/jenkins.html#using-the-jenkins-kubernetes-plug-in-to-run-jobs

The Kubernetes plugin is a Jenkins extension that uses a Kubernetes cluster to dynamically provision Jenkins agents, use them to run builds and then dispose of them. It does do by using Kubernetes scheduling mechanism to optimize the load. The Jenkins image that ships with OpenShift comes with the Kubernetes plugin pre-installed. The OpenShift Plugin for Jenkins allows specifying agents as slave pods.

Pipeline Logic Declaration

Pipeline logic is declared in Groovy, either inline in the build configuration, or as a Jenkinsfile stored in the source code repository. For syntax, see

Build Configuration

Inline Pipeline Logic Declaration

apiVersion: "v1"
kind: "BuildConfig"
metadata:
  name: "my-pipeline-build-configuration"
spec:
  strategy:
    type: JenkinsPipeline
    jenkinsPipelineStrategy:
      env:
        - name: ENV_VAR_1
          value: "..."
      jenkinsfile: |
        //
        // in-line pipeline code
        //
        ...

Jenkinsfile

Jenkinsfile contains the definition of the pipeline that drives an OpenShift pipeline build, written in Groovy. The OpenShift pipeline build configuration can be written in such a way to refer to it:

apiVersion: "v1"
kind: "BuildConfig"
metadata:
  name: "my-pipeline-build-configuration"
spec:
  source:
    git:
      uri: "https://....git"
  strategy:
    type: JenkinsPipeline
    jenkinsPipelineStrategy:
      env:
        - name: ENV_VAR_1
          value: "..."
      jenkinsfilePath: "jenkinsfile/path/relative/to/the/root/of/the/repository/Jenkinsfile"

Note that 'jenkinsfilePath' must contain the relative path and the name of the file.

A Jenkinsfile maintained in the source code and version controlled is the preferred way of specifying the pipeline logic.

Deplete

OpenShift CI/CD Concepts TODEPLETE