apiVersion: template.openshift.io/v1 kind: Template labels: template: bluegreen-pipeline message: A Jenkins server must be instantiated in this project to manage the Pipeline BuildConfig created by this template. You will be able to log in to it using your OpenShift user credentials. metadata: annotations: description: This example showcases a blue green deployment using a Jenkins pipeline that pauses for approval. iconClass: icon-jenkins tags: instant-app,jenkins name: bluegreen-pipeline objects: - apiVersion: build.openshift.io/v1 kind: BuildConfig metadata: annotations: pipeline.alpha.openshift.io/uses: '[{"name": "${NAME}", "namespace": "", "kind": "DeploymentConfig"}]' creationTimestamp: null labels: name: bluegreen-pipeline name: bluegreen-pipeline spec: strategy: jenkinsPipelineStrategy: jenkinsfile: |- try { timeout(time: 20, unit: 'MINUTES') { def appName="${NAME}" def project="" def tag="blue" def altTag="green" def verbose="${VERBOSE}" node { project = env.PROJECT_NAME stage("Initialize") { sh "oc get route ${appName} -n ${project} -o jsonpath='{ .spec.to.name }' --loglevel=4 > activeservice" activeService = readFile('activeservice').trim() if (activeService == "${appName}-blue") { tag = "green" altTag = "blue" } sh "oc get route ${tag}-${appName} -n ${project} -o jsonpath='{ .spec.host }' --loglevel=4 > routehost" routeHost = readFile('routehost').trim() } openshift.withCluster() { openshift.withProject() { stage("Build") { echo "building tag ${tag}" def bld = openshift.startBuild("${appName}") bld.untilEach { return it.object().status.phase == "Running" } bld.logs('-f') } stage("Deploy Test") { openshift.tag("${appName}:latest", "${appName}:${tag}") def dc = openshift.selector('dc', "${appName}-${tag}") dc.rollout().status() } stage("Test") { input message: "Test deployment: http://${routeHost}. Approve?", id: "approval" } stage("Go Live") { sh "oc set -n ${project} route-backends ${appName} ${appName}-${tag}=100 ${appName}-${altTag}=0 --loglevel=4" } } } } } } catch (err) { echo "in catch block" echo "Caught: ${err}" currentBuild.result = 'FAILURE' throw err } type: JenkinsPipeline triggers: - github: secret: "${GITHUB_WEBHOOK_SECRET}" type: GitHub - generic: secret: "${GENERIC_WEBHOOK_SECRET}" type: Generic - apiVersion: v1 kind: Secret metadata: name: ${NAME} stringData: database-admin-password: ${DATABASE_ADMIN_PASSWORD} database-password: ${DATABASE_PASSWORD} database-user: ${DATABASE_USER} - apiVersion: route.openshift.io/v1 kind: Route metadata: name: blue-${NAME} spec: to: kind: Service name: ${NAME}-blue - apiVersion: route.openshift.io/v1 kind: Route metadata: name: green-${NAME} spec: to: kind: Service name: ${NAME}-green - apiVersion: route.openshift.io/v1 kind: Route metadata: name: ${NAME} spec: alternateBackends: - name: ${NAME}-green weight: 0 to: kind: Service name: ${NAME}-blue weight: 100 - apiVersion: image.openshift.io/v1 kind: ImageStream metadata: annotations: description: Keeps track of changes in the application image name: ${NAME} - apiVersion: build.openshift.io/v1 kind: BuildConfig metadata: annotations: description: Defines how to build the application name: ${NAME} spec: output: to: kind: ImageStreamTag name: ${NAME}:latest postCommit: script: npm test source: contextDir: ${CONTEXT_DIR} git: ref: ${SOURCE_REPOSITORY_REF} uri: ${SOURCE_REPOSITORY_URL} type: Git strategy: sourceStrategy: env: - name: NPM_MIRROR value: ${NPM_MIRROR} from: kind: ImageStreamTag name: nodejs:${NODEJS_VERSION} namespace: ${NAMESPACE} type: Source triggers: - github: secret: ${GITHUB_WEBHOOK_SECRET} type: GitHub - generic: secret: ${GENERIC_WEBHOOK_SECRET} type: Generic - apiVersion: v1 kind: Service metadata: annotations: service.alpha.openshift.io/dependencies: '[{"name": "${DATABASE_SERVICE_NAME}", "namespace": "", "kind": "Service"}]' name: ${NAME}-blue spec: ports: - name: web port: 8080 targetPort: 8080 selector: name: ${NAME}-blue - apiVersion: apps.openshift.io/v1 kind: DeploymentConfig metadata: annotations: description: Defines how to deploy the application server name: ${NAME}-blue spec: replicas: 1 selector: name: ${NAME}-blue strategy: type: Rolling template: metadata: labels: name: ${NAME}-blue name: ${NAME}-blue spec: containers: - env: - name: DATABASE_SERVICE_NAME value: ${DATABASE_SERVICE_NAME} - name: MYSQL_USER value: ${DATABASE_USER} - name: MYSQL_PASSWORD value: ${DATABASE_PASSWORD} - name: MYSQL_DATABASE value: ${DATABASE_NAME} - name: MYSQL_ROOT_PASSWORD value: ${DATABASE_ROOT_PASSWORD} image: ' ' livenessProbe: httpGet: path: /pagecount port: 8080 initialDelaySeconds: 30 timeoutSeconds: 3 name: nodejs-postgresql-example ports: - containerPort: 8080 readinessProbe: httpGet: path: /pagecount port: 8080 initialDelaySeconds: 3 timeoutSeconds: 3 resources: limits: memory: ${MEMORY_LIMIT} triggers: - imageChangeParams: automatic: true containerNames: - nodejs-postgresql-example from: kind: ImageStreamTag name: ${NAME}:blue type: ImageChange - type: ConfigChange - apiVersion: v1 kind: Service metadata: annotations: service.alpha.openshift.io/dependencies: '[{"name": "${DATABASE_SERVICE_NAME}", "namespace": "", "kind": "Service"}]' name: ${NAME}-green spec: ports: - name: web port: 8080 targetPort: 8080 selector: name: ${NAME}-green - apiVersion: apps.openshift.io/v1 kind: DeploymentConfig metadata: annotations: description: Defines how to deploy the application server name: ${NAME}-green spec: replicas: 1 selector: name: ${NAME}-green strategy: type: Rolling template: metadata: labels: name: ${NAME}-green name: ${NAME}-green spec: containers: - env: - name: POSTGRESQL_USER valueFrom: secretKeyRef: key: database-user name: ${NAME} - name: POSTGRESQL_PASSWORD valueFrom: secretKeyRef: key: database-password name: ${NAME} - name: POSTGRESQL_DATABASE value: ${DATABASE_NAME} - name: POSTGRESQL_ADMIN_PASSWORD valueFrom: secretKeyRef: key: database-admin-password name: ${NAME} image: ' ' livenessProbe: httpGet: path: /pagecount port: 8080 initialDelaySeconds: 30 timeoutSeconds: 3 name: nodejs-postgresql-example ports: - containerPort: 8080 readinessProbe: httpGet: path: /pagecount port: 8080 initialDelaySeconds: 3 timeoutSeconds: 3 resources: limits: memory: ${MEMORY_LIMIT} triggers: - imageChangeParams: automatic: true containerNames: - nodejs-postgresql-example from: kind: ImageStreamTag name: ${NAME}:green type: ImageChange - type: ConfigChange - apiVersion: v1 kind: Service metadata: annotations: description: Exposes the database server name: ${DATABASE_SERVICE_NAME} spec: ports: - name: postgresql port: 5432 targetPort: 5432 selector: name: ${DATABASE_SERVICE_NAME} - apiVersion: apps.openshift.io/v1 kind: DeploymentConfig metadata: annotations: description: Defines how to deploy the database name: ${DATABASE_SERVICE_NAME} spec: replicas: 1 selector: name: ${DATABASE_SERVICE_NAME} strategy: type: Recreate template: metadata: labels: name: ${DATABASE_SERVICE_NAME} name: ${DATABASE_SERVICE_NAME} spec: containers: - env: - name: POSTGRESQL_USER valueFrom: secretKeyRef: key: database-user name: ${NAME} - name: POSTGRESQL_PASSWORD valueFrom: secretKeyRef: key: database-password name: ${NAME} - name: POSTGRESQL_DATABASE value: ${DATABASE_NAME} - name: POSTGRESQL_ADMIN_PASSWORD valueFrom: secretKeyRef: key: database-admin-password name: ${NAME} image: ' ' livenessProbe: initialDelaySeconds: 30 tcpSocket: port: 5432 timeoutSeconds: 1 name: postgresql ports: - containerPort: 5432 resources: limits: memory: ${MEMORY_MYSQL_LIMIT} volumeMounts: - mountPath: /var/lib/mysql/data name: ${DATABASE_SERVICE_NAME}-data volumes: - emptyDir: medium: "" name: ${DATABASE_SERVICE_NAME}-data triggers: - imageChangeParams: automatic: true containerNames: - postgresql from: kind: ImageStreamTag name: postgresql:${POSTGRESQL_VERSION} namespace: ${NAMESPACE} type: ImageChange - type: ConfigChange parameters: - description: The name assigned to all of the frontend objects defined in this template. displayName: Name name: NAME required: true value: nodejs-postgresql-example - description: The OpenShift Namespace where the NodeJS and postgresql ImageStreams reside. displayName: Namespace name: NAMESPACE required: true value: openshift - description: Version of NodeJS image to be used (14-ubi8, or latest). displayName: Version of NodeJS Image name: NODEJS_VERSION required: true value: 14-ubi8 - description: Version of PostgreSQL image to be used (12-el8, or latest). displayName: Version of PostgreSQL Image name: POSTGRESQL_VERSION required: true value: 12-el8 - description: The exposed hostname that will route to the Node.js service, if left blank a value will be defaulted. displayName: Application Hostname name: APPLICATION_DOMAIN - description: The URL of the repository with your application source code. displayName: Git Repository URL name: SOURCE_REPOSITORY_URL required: true value: https://github.com/openshift/nodejs-ex.git - description: The reference of the repository with your application source code. displayName: Git Repository Ref name: SOURCE_REPOSITORY_REF required: true value: master - description: Password for the database admin user. displayName: Database Administrator Password from: '[a-zA-Z0-9]{16}' generate: expression name: DATABASE_ADMIN_PASSWORD - displayName: Database Name name: DATABASE_NAME required: true value: sampledb - description: Username for postgresql user that will be used for accessing the database. displayName: postgresql Username from: user[A-Z0-9]{3} generate: expression name: DATABASE_USER - description: Password for the postgresql user. displayName: postgresql Password from: '[a-zA-Z0-9]{16}' generate: expression name: DATABASE_PASSWORD - description: Maximum amount of memory the Node.js container can use. displayName: Memory Limit name: MEMORY_LIMIT required: true value: 512Mi - description: Maximum amount of memory the postgresql container can use. displayName: Memory Limit (postgresql) name: MEMORY_MYSQL_LIMIT required: true value: 512Mi - displayName: Database Service Name name: DATABASE_SERVICE_NAME required: true value: postgresql - description: Password for the database admin user. displayName: Database Administrator Password from: '[a-zA-Z0-9]{16}' generate: expression name: DATABASE_ROOT_PASSWORD - description: Set this to the relative path to your project if it is not in the root of your repository. displayName: Context Directory name: CONTEXT_DIR - description: Github trigger secret. A difficult to guess string encoded as part of the webhook URL. Not encrypted. displayName: GitHub Webhook Secret from: '[a-zA-Z0-9]{40}' generate: expression name: GITHUB_WEBHOOK_SECRET - description: A secret string used to configure the Generic webhook. displayName: Generic Webhook Secret from: '[a-zA-Z0-9]{40}' generate: expression name: GENERIC_WEBHOOK_SECRET - description: The custom NPM mirror URL displayName: Custom NPM Mirror URL name: NPM_MIRROR - description: Whether to enable verbose logging of Jenkinsfile steps in pipeline displayName: Verbose name: VERBOSE required: true value: "false"