diff --git a/multi-cluster-spring-boot/Jenkinsfile b/multi-cluster-spring-boot/Jenkinsfile new file mode 100644 index 00000000..f3a0e106 --- /dev/null +++ b/multi-cluster-spring-boot/Jenkinsfile @@ -0,0 +1,156 @@ +openshift.withCluster() { + env.NAMESPACE = openshift.project() + env.SKOPEO_IMAGE = openshift.selector( 'is/jenkins-slave-image-mgmt' ).object().status.dockerImageRepository + env.APP_NAME = "${env.JOB_NAME}".replaceAll(/-?pipeline-?/, '').replaceAll(/-?${env.NAMESPACE}-?/, '') + echo "Starting Pipeline for ${APP_NAME}..." + def projectBase = "${env.NAMESPACE}".replaceAll(/-dev/, '') + env.STAGE1 = "${projectBase}-dev" + env.STAGE2 = "${projectBase}-stage" + env.STAGE3 = "${projectBase}-prod" +} + + +pipeline { + + agent { label 'maven' } + + stages { + + stage('Code Build') { + steps { + git url: "${SOURCE_CODE_URL}" + sh "mvn clean install -q" + } + } + + stage('Image Build') { + steps { + echo 'Building Image from Jar File' + sh """ + set +x + rm -rf oc-build && mkdir -p oc-build/deployments + for t in \$(echo "jar;war;ear" | tr ";" "\\n"); do + cp -rfv ./target/*.\$t oc-build/deployments/ 2> /dev/null || echo "No \$t files" + done + """ + script { + openshift.withCluster() { + openshift.startBuild("${APP_NAME}", "--from-dir=oc-build", "--wait", "--follow") + } + } + } + } + + stage ('Verify Deployment to Dev') { + steps { + script { + openshift.withCluster() { + def dcObj = openshift.selector('dc', env.APP_NAME).object() + def podSelector = openshift.selector('pod', [deployment: "${APP_NAME}-${dcObj.status.latestVersion}"]) + podSelector.untilEach { + echo "pod: ${it.name()}" + return it.object().status.containerStatuses[0].ready + } + } + } + } + } + + stage('Promote to Stage') { + steps { + script { + openshift.withCluster() { + openshift.tag("${env.STAGE1}/${env.APP_NAME}:latest", "${env.STAGE2}/${env.APP_NAME}:latest") + } + } + } + } + + stage ('Verify Deployment to Stage') { + steps { + script { + openshift.withCluster() { + openshift.withProject("${STAGE2}") { + def dcObj = openshift.selector('dc', env.APP_NAME).object() + def podSelector = openshift.selector('pod', [deployment: "${APP_NAME}-${dcObj.status.latestVersion}"]) + podSelector.untilEach { + echo "pod: ${it.name()}" + return it.object().status.containerStatuses[0].ready + } + } + } + } + } + } + + stage('Promote to Prod') { + agent { + kubernetes { + label 'promotion-slave' + cloud 'openshift' + serviceAccount 'jenkins' + containerTemplate { + name 'jnlp' + image "docker-registry.default.svc:5000/${NAMESPACE}/jenkins-slave-image-mgmt" + alwaysPullImage true + workingDir '/tmp' + args '${computer.jnlpmac} ${computer.name}' + ttyEnabled false + } + } + } + steps { + script { + openshift.withCluster() { + + def localToken = readFile('/var/run/secrets/kubernetes.io/serviceaccount/token').trim() + + def secretData = openshift.selector('secret/prod-credentials').object().data + def encodedRegistry = secretData.registry + def encodedToken = secretData.token + def registry = sh(script:"set +x; echo ${encodedRegistry} | base64 --decode", returnStdout: true) + def token = sh(script:"set +x; echo ${encodedToken} | base64 --decode", returnStdout: true) + + openshift.withProject("${STAGE2}") { + def imageRegistry = openshift.selector( 'is', "${APP_NAME}").object().status.dockerImageRepository + echo "Promoting ${imageRegistry} -> ${registry}/${STAGE3}/${APP_NAME}" + sh """ + set +x + skopeo copy --remove-signatures \ + --src-creds openshift:${localToken} --src-cert-dir=/run/secrets/kubernetes.io/serviceaccount/ \ + --dest-creds openshift:${token} --dest-tls-verify=false \ + docker://${imageRegistry} docker://${registry}/${STAGE3}/${APP_NAME} + """ + } + + } + } + } + } + + stage ('Verify Deployment to Prod') { + steps { + script { + openshift.withCluster() { + def secretData = openshift.selector('secret/prod-credentials').object().data + def encodedAPI = secretData.api + def encodedToken = secretData.token + env.API = sh(script:"set +x; echo ${encodedAPI} | base64 --decode", returnStdout: true).replaceAll(/https?/, 'insecure') + env.TOKEN = sh(script:"set +x; echo ${encodedToken} | base64 --decode", returnStdout: true) + } + openshift.withCluster( env.API, env.TOKEN ) { + openshift.withProject("${STAGE3}") { + def dcObj = openshift.selector('dc', env.APP_NAME).object() + def podSelector = openshift.selector('pod', [deployment: "${APP_NAME}-${dcObj.status.latestVersion}"]) + podSelector.untilEach { + echo "pod: ${it.name()}" + return it.object().status.containerStatuses[0].ready + } + } + } + } + } + } + + } +} diff --git a/multi-cluster-spring-boot/README.md b/multi-cluster-spring-boot/README.md new file mode 100644 index 00000000..667e7b82 --- /dev/null +++ b/multi-cluster-spring-boot/README.md @@ -0,0 +1,176 @@ +# A Sample OpenShift Pipeline for a Spring Boot Application + +This example demonstrates how to implement a full end-to-end Jenkins Pipeline for a Java application in OpenShift Container Platform. This sample demonstrates the following capabilities: + +* Deploying an integrated Jenkins server inside of OpenShift +* Running both custom and oob Jenkins slaves as pods in OpenShift +* "One Click" instantiation of a Jenkins Pipeline using OpenShift's Jenkins Pipeline Strategy feature +* Promotion of an application's container image within an OpenShift Cluster (using `oc tag`) +* Promotion of an application's container image to a separate OpenShift Cluster (using `skopeo`) +* Automated rollout using the [openshift-appler](https://github.com/redhat-cop/casl-ansible/tree/master/roles/openshift-applier) Ansible role. + +## Prerequisites + +In order to run this pipeline, you will need: + +* Two (2) OpenShift clusters, version 3.5 or greater + * In this document, we will refer to the first cluster as *_Dev_* and the second as *_Prod_*. +* Ansible installed on your machine + +## Automated Quickstart + +This quickstart can be deployed quickly using Ansible. Here are the steps. + +1. Clone [this repo](https://github.com/redhat-cop/container-pipelines.git) +2. `cd container-pipelines/multi-cluster-spring-boot` +3. Run `ansible-galaxy install -r requirements.yml --roles-path=roles` +4. Log into your _Prod_ OpenShift cluster, and run the following command. + ``` + $ oc login + ... + $ ansible-playbook -i ./applier/inventory-prod/ roles/casl-ansible/playbooks/openshift-cluster-seed.yml + ``` +5. One of the things that was created by ansible is a `ServiceAccount` that will be used for promoting your app from _Dev_ to _Prod_. We'll need to extract its credentials so that our pipeline can use that account. + ``` + TOKEN=$(oc serviceaccounts get-token promoter -n multicluster-spring-boot-prod) + ``` + The Ansible automation for your _Dev_ cluster will expect a parameters file to be created at `./applier/params/prod-credentials`. It should look something like this: + ``` + $ echo "TOKEN=${TOKEN} + API_URL=https://master.example.com + REGISTRY_URL=docker-registry-default.apps.example.com + " > ./applier/params/prod-credentials + ``` +6. Now, Log into your _Dev_ cluster, and instantiate the pipeline. + ``` + $ oc login + ... + $ ansible-playbook -i ./applier/inventory-dev/ /path/to/casl-ansible/playbooks/openshift-cluster-seed.yml + ``` + +At this point you should have 3 projects deployed (`multicluster-spring-boot-dev`, `multicluster-spring-boot-stage`, and `multicluster-spring-boot-prod`) with our [Spring Rest](https://github.com/redhat-cop/spring-rest.git) demo application deployed to all 3. + +## Architecture + +The following breaks down the architecture of the pipeline deployed, as well as walks through the manual deployment steps + +### OpenShift Templates + +The components of this pipeline are divided into two templates. + +The first template, `applier/templates/build.yml` is what we are calling the "Build" template. It contains: + +* A `jenkinsPipelineStrategy` BuildConfig +* An `s2i` BuildConfig +* An ImageStream for the s2i build config to push to + +The build template contains a default source code repo for a java application compatible with this pipelines architecture (https://github.com/redhat-cop/spring-rest). + +The second template, `applier/templates/deployment.yml` is the "Deploy" template. It contains: + +* A tomcat8 DeploymentConfig +* A Service definition +* A Route + +The idea behind the split between the templates is that I can deploy the build template only once (to my dev project) and that the pipeline will promote my image through all of the various stages of my application's lifecycle. The deployment template gets deployed once to each of the stages of the application lifecycle (once per OpenShift project). + +### Pipeline Script + +This project includes a sample `Jenkinsfile` pipeline script that could be included with a Java project in order to implement a basic CI/CD pipeline for that project, under the following assumptions: + +* The project is built with Maven +* The `Jenkinsfile` script is placed in the same directory as the `pom.xml` file in the git source. +* The OpenShift projects that represent the Application's lifecycle stages are of the naming format: `-dev`, `-stage`, `-prod`. + +For convenience, this pipeline script is already included in the following git repository, based on our [Spring Boot Demo App](https://github.com/redhat-cop/spring-rest) app. + +https://github.com/redhat-cop/spring-rest + +## Manual Deployment Instructions + +### 1. Create Lifecycle Stages + +For the purposes of this demo, we are going to create three stages for our application to be promoted through. + +- `multicluster-spring-boot-dev` +- `multicluster-spring-boot-stage` +- `multicluster-spring-boot-prod` + +In the spirit of _Infrastructure as Code_ we have a YAML file that defines the `ProjectRequests` for us. This is as an alternative to running `oc new-project`, but will yeild the same result. + +``` +$ oc create -f applier/projects/projects.yml +projectrequest "multicluster-spring-boot-dev" created +projectrequest "multicluster-spring-boot-stage" created +projectrequest "multicluster-spring-boot-prod" created +``` + +### 2. Stand up Jenkins master in dev + +For this step, the OpenShift default template set provides exactly what we need to get jenkins up and running. + +``` +$ oc process openshift//jenkins-ephemeral | oc apply -f- -n multicluster-spring-boot-dev +route "jenkins" created +deploymentconfig "jenkins" created +serviceaccount "jenkins" created +rolebinding "jenkins_edit" created +service "jenkins-jnlp" created +service "jenkins" created +``` + +### 4. Instantiate Pipeline + +A _deploy template_ is provided at `applier/templates/deployment.yml` that defines all of the resources required to run our Tomcat application. It includes: + +* A `Service` +* A `Route` +* An `ImageStream` +* A `DeploymentConfig` +* A `RoleBinding` to allow Jenkins to deploy in each namespace. + +This template should be instantiated once in each of the namespaces that our app will be deployed to. For this purpose, we have created a param file to be fed to `oc process` to customize the template for each environment. + +Deploy the deployment template to all three projects. +``` +$ oc process -f applier/templates/deployment.yml --param-file=applier/params/deployment-dev | oc apply -f- +service "spring-rest" created +route "spring-rest" created +imagestream "spring-rest" created +deploymentconfig "spring-rest" created +rolebinding "jenkins_edit" configured +$ oc process -f applier/templates/deployment.yml --param-file=applier/params/deployments-stage | oc apply -f- +service "spring-rest" created +route "spring-rest" created +imagestream "spring-rest" created +deploymentconfig "spring-rest" created +rolebinding "jenkins_edit" created +$ oc process -f applier/templates/deployment.yml --param-file=applier/params/deployment-prod | oc apply -f- +service "spring-rest" created +route "spring-rest" created +imagestream "spring-rest" created +deploymentconfig "spring-rest" created +rolebinding "jenkins_edit" created +``` + +A _build template_ is provided at `applier/templates/build.yml` that defines all the resources required to build our java app. It includes: + +* A `BuildConfig` that defines a `JenkinsPipelineStrategy` build, which will be used to define out pipeline. +* A `BuildConfig` that defines a `Source` build with `Binary` input. This will build our image. + +Deploy the pipeline template in dev only. +``` +$ oc process -f applier/templates/build.yml --param-file applier/params/build-dev | oc apply -f- +buildconfig "spring-rest-pipeline" created +buildconfig "spring-rest" created +``` + +At this point you should be able to go to the Web Console and follow the pipeline by clicking in your `multicluster-spring-boot-dev` project, and going to *Builds* -> *Pipelines*. At several points you will be prompted for input on the pipeline. You can interact with it by clicking on the _input required_ link, which takes you to Jenkins, where you can click the *Proceed* button. By the time you get through the end of the pipeline you should be able to visit the Route for your app deployed to the `myapp-prod` project to confirm that your image has been promoted through all stages. + +## Cleanup + +Cleaning up this example is as simple as deleting the projects we created at the beginning. + +``` +oc delete project multicluster-spring-boot-dev multicluster-spring-boot-prod multicluster-spring-boot-stage +``` diff --git a/multi-cluster-spring-boot/applier/inventory-dev/group_vars/seed-hosts.yml b/multi-cluster-spring-boot/applier/inventory-dev/group_vars/seed-hosts.yml new file mode 100644 index 00000000..c56deb65 --- /dev/null +++ b/multi-cluster-spring-boot/applier/inventory-dev/group_vars/seed-hosts.yml @@ -0,0 +1,31 @@ +openshift_cluster_content: +- object: projects + content: + - name: "create environments" + file: "{{ inventory_dir }}/../projects/projects.yml" + file_action: create +- object: deployments + content: + - name: "deploy jenkins" + template: "openshift//jenkins-ephemeral" + params: "{{ inventory_dir }}/../params/jenkins" + namespace: multicluster-spring-boot-dev + - name: "create prod cluster credential" + template: "{{ inventory_dir }}/../templates/cluster-secret.yml" + params: "{{ inventory_dir }}/../params/prod-credentials" + namespace: multicluster-spring-boot-dev + - name: "deploy dev environment" + template: "{{ inventory_dir }}/../templates/deployment.yml" + params: "{{ inventory_dir }}/../params/deployment-dev" + - name: "deply stage environment" + template: "{{ inventory_dir }}/../templates/deployment.yml" + params: "{{ inventory_dir }}/../params/deployment-stage" +- object: builds + content: + - name: Apply Image Build" + namespace: "multicluster-spring-boot-dev" + template: "https://raw.githubusercontent.com/redhat-cop/containers-quickstarts/master/jenkins-slaves/templates/jenkins-slave-image-mgmt-template.json" + params: "{{ inventory_dir }}/../params/build-slave-dev" + - name: "deploy build pipeline to dev" + template: "{{ inventory_dir }}/../templates/build.yml" + params: "{{ inventory_dir }}/../params/build-dev" diff --git a/multi-cluster-spring-boot/applier/inventory-dev/hosts b/multi-cluster-spring-boot/applier/inventory-dev/hosts new file mode 100644 index 00000000..7f325c4b --- /dev/null +++ b/multi-cluster-spring-boot/applier/inventory-dev/hosts @@ -0,0 +1,2 @@ +[seed-hosts] +localhost ansible_connection=local diff --git a/multi-cluster-spring-boot/applier/inventory-prod/group_vars/seed-hosts.yml b/multi-cluster-spring-boot/applier/inventory-prod/group_vars/seed-hosts.yml new file mode 100644 index 00000000..87240fd3 --- /dev/null +++ b/multi-cluster-spring-boot/applier/inventory-prod/group_vars/seed-hosts.yml @@ -0,0 +1,13 @@ +openshift_cluster_content: +- object: projects + content: + - name: "create environments" + file: "{{ inventory_dir }}/../projects/projects-prod.yml" + file_action: create + - name: "create promoter account" + file: "{{ inventory_dir }}/../projects/promoter-sa.yml" +- object: deployments + content: + - name: "deply prod environment" + template: "{{ inventory_dir }}/../templates/deployment.yml" + params: "{{ inventory_dir }}/../params/deployment-prod" diff --git a/multi-cluster-spring-boot/applier/inventory-prod/hosts b/multi-cluster-spring-boot/applier/inventory-prod/hosts new file mode 100644 index 00000000..7f325c4b --- /dev/null +++ b/multi-cluster-spring-boot/applier/inventory-prod/hosts @@ -0,0 +1,2 @@ +[seed-hosts] +localhost ansible_connection=local diff --git a/multi-cluster-spring-boot/applier/params/build-dev b/multi-cluster-spring-boot/applier/params/build-dev new file mode 100644 index 00000000..de786644 --- /dev/null +++ b/multi-cluster-spring-boot/applier/params/build-dev @@ -0,0 +1,5 @@ +APPLICATION_NAME=spring-rest +NAMESPACE=multicluster-spring-boot-dev +PIPELINE_REPOSITORY_URL=https://github.com/etsauer/container-pipelines.git +PIPELINE_REPOSITORY_REF=multi-cluster-promotion +PIPELINE_REPOSITORY_CONTEXT_DIR=multi-cluster-spring-boot diff --git a/multi-cluster-spring-boot/applier/params/build-slave-dev b/multi-cluster-spring-boot/applier/params/build-slave-dev new file mode 100644 index 00000000..e69de29b diff --git a/multi-cluster-spring-boot/applier/params/deployment-dev b/multi-cluster-spring-boot/applier/params/deployment-dev new file mode 100644 index 00000000..c13fb0f4 --- /dev/null +++ b/multi-cluster-spring-boot/applier/params/deployment-dev @@ -0,0 +1,5 @@ +APPLICATION_NAME=spring-rest +NAMESPACE=multicluster-spring-boot-dev +SA_NAMESPACE=multicluster-spring-boot-dev +READINESS_RESPONSE=status.:.UP +READINESS_PATH=/health diff --git a/multi-cluster-spring-boot/applier/params/deployment-prod b/multi-cluster-spring-boot/applier/params/deployment-prod new file mode 100644 index 00000000..1f4db956 --- /dev/null +++ b/multi-cluster-spring-boot/applier/params/deployment-prod @@ -0,0 +1,5 @@ +APPLICATION_NAME=spring-rest +NAMESPACE=multicluster-spring-boot-prod +SA_NAMESPACE=multicluster-spring-boot-dev +READINESS_RESPONSE=status.:.UP +READINESS_PATH=/health diff --git a/multi-cluster-spring-boot/applier/params/deployment-stage b/multi-cluster-spring-boot/applier/params/deployment-stage new file mode 100644 index 00000000..326a8b1b --- /dev/null +++ b/multi-cluster-spring-boot/applier/params/deployment-stage @@ -0,0 +1,6 @@ +APPLICATION_NAME=spring-rest +NAMESPACE=multicluster-spring-boot-stage +SA_NAME=jenkins +SA_NAMESPACE=multicluster-spring-boot-dev +READINESS_RESPONSE=status.:.UP +READINESS_PATH=/health diff --git a/multi-cluster-spring-boot/applier/params/jenkins b/multi-cluster-spring-boot/applier/params/jenkins new file mode 100644 index 00000000..e29bc258 --- /dev/null +++ b/multi-cluster-spring-boot/applier/params/jenkins @@ -0,0 +1 @@ +MEMORY_LIMIT=1.5Gi diff --git a/multi-cluster-spring-boot/applier/projects/projects-prod.yml b/multi-cluster-spring-boot/applier/projects/projects-prod.yml new file mode 100644 index 00000000..2cd0a889 --- /dev/null +++ b/multi-cluster-spring-boot/applier/projects/projects-prod.yml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: List +items: +- kind: ProjectRequest + apiVersion: v1 + metadata: + name: multicluster-spring-boot-prod + creationTimestam: null + displayName: MultiCluster Pipeline - Prod diff --git a/multi-cluster-spring-boot/applier/projects/projects.yml b/multi-cluster-spring-boot/applier/projects/projects.yml new file mode 100644 index 00000000..9c3b81e8 --- /dev/null +++ b/multi-cluster-spring-boot/applier/projects/projects.yml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: List +items: +- kind: ProjectRequest + apiVersion: v1 + metadata: + name: multicluster-spring-boot-dev + creationTimestam: null + displayName: MultiCluster Pipeline - Dev +- kind: ProjectRequest + apiVersion: v1 + metadata: + name: multicluster-spring-boot-stage + creationTimestam: null + displayName: MultiCluster Pipeline - Stage diff --git a/multi-cluster-spring-boot/applier/projects/promoter-sa.yml b/multi-cluster-spring-boot/applier/projects/promoter-sa.yml new file mode 100644 index 00000000..76616d0a --- /dev/null +++ b/multi-cluster-spring-boot/applier/projects/promoter-sa.yml @@ -0,0 +1,24 @@ +--- +apiVersion: v1 +kind: List +items: +- apiVersion: v1 + kind: ServiceAccount + metadata: + name: promoter + namespace: multicluster-spring-boot-prod +- apiVersion: v1 + groupNames: null + kind: RoleBinding + metadata: + creationTimestamp: null + name: edit + namespace: multicluster-spring-boot-prod + roleRef: + name: edit + subjects: + - kind: ServiceAccount + name: promoter + namespace: multicluster-spring-boot-prod + userNames: + - system:serviceaccount:multicluster-spring-boot-prod:promoter diff --git a/multi-cluster-spring-boot/applier/templates/build.yml b/multi-cluster-spring-boot/applier/templates/build.yml new file mode 100644 index 00000000..b1667b5a --- /dev/null +++ b/multi-cluster-spring-boot/applier/templates/build.yml @@ -0,0 +1,113 @@ +apiVersion: v1 +kind: Template +labels: + template: generic-java-jenkins-pipeline +metadata: + annotations: + description: Application template for JWS applications built using a Jenkins Pipeline + iconClass: icon-tomcat + tags: tomcat,tomcat8,java,jboss,xpaas,jenkins-ci + version: 1.2.0 + name: generic-java-jenkins-pipeline +objects: +- kind: "BuildConfig" + apiVersion: "v1" + metadata: + labels: + application: ${APPLICATION_NAME} + name: "${APPLICATION_NAME}-pipeline" + namespace: "${NAMESPACE}" + spec: + source: + type: Git + git: + uri: ${PIPELINE_REPOSITORY_URL} + ref: ${PIPELINE_REPOSITORY_REF} + contextDir: ${PIPELINE_REPOSITORY_CONTEXT_DIR} + triggers: + - type: "GitHub" + github: + secret: ${GITHUB_WEBHOOK_SECRET} + - type: "ConfigChange" + strategy: + type: "JenkinsPipeline" + jenkinsPipelineStrategy: + jenkinsfilePath: ${PIPELINE_SCRIPT} + env: + - name: SOURCE_CODE_URL + value: ${SOURCE_CODE_URL} + - name: SOURCE_CODE_BRANCH + value: ${SOURCE_CODE_BRANCH} + - name: SKIP_TLS + value: "true" +- apiVersion: v1 + kind: BuildConfig + metadata: + labels: + application: ${APPLICATION_NAME} + name: ${APPLICATION_NAME} + namespace: "${NAMESPACE}" + spec: + output: + to: + kind: ImageStreamTag + name: ${APPLICATION_NAME}:latest + source: + binary: {} + type: Binary + strategy: + sourceStrategy: + from: + kind: ImageStreamTag + name: ${IMAGE_STREAM_TAG_NAME} + namespace: ${IMAGE_STREAM_NAMESPACE} + type: Source +parameters: +- description: The name for the application. + name: APPLICATION_NAME + required: true + value: basic-spring +- description: The namespace to deploy into + name: NAMESPACE + required: true +- description: Git source URI for application + name: PIPELINE_REPOSITORY_URL + required: true + value: https://github.com/redhat-cop/container-pipelines.git +- description: Git branch/tag reference + name: PIPELINE_REPOSITORY_REF + value: "master" +- description: Path within Git project to build; empty for root project directory. + name: PIPELINE_REPOSITORY_CONTEXT_DIR + value: +- description: Path within Git project pointing to the pipeline run script + name: PIPELINE_SCRIPT + value: Jenkinsfile +- description: Git source URI for application + name: SOURCE_CODE_URL + required: true + value: https://github.com/redhat-cop/spring-rest.git +- description: Git branch/tag reference + name: SOURCE_CODE_REF + value: "master" +- description: GitHub trigger secret + from: '[a-zA-Z0-9]{8}' + generate: expression + name: GITHUB_WEBHOOK_SECRET + required: true +- description: Generic build trigger secret + from: '[a-zA-Z0-9]{8}' + generate: expression + name: GENERIC_WEBHOOK_SECRET + required: true +- description: Namespace in which the ImageStreams for Red Hat Middleware images are + installed. These ImageStreams are normally installed in the openshift namespace. + You should only need to modify this if you've installed the ImageStreams in a + different namespace/project. + name: IMAGE_STREAM_NAMESPACE + required: true + value: openshift +- description: Image stream tag for the image you'd like to use to build the application + name: IMAGE_STREAM_TAG_NAME + required: true + value: redhat-openjdk18-openshift:1.1 diff --git a/multi-cluster-spring-boot/applier/templates/cluster-secret.yml b/multi-cluster-spring-boot/applier/templates/cluster-secret.yml new file mode 100644 index 00000000..ed9ddbdc --- /dev/null +++ b/multi-cluster-spring-boot/applier/templates/cluster-secret.yml @@ -0,0 +1,35 @@ +apiVersion: v1 +kind: Template +labels: + template: cluster-credentials-secret +metadata: + annotations: + description: Cluster Credential Secret + tags: secret + version: 1.0.0 + name: cluster-credentials-secret +objects: +- apiVersion: v1 + stringData: + api: ${API_URL} + registry: ${REGISTRY_URL} + token: "${TOKEN}" + data: + kind: Secret + metadata: + name: ${SECRET_NAME} + type: Opaque +parameters: +- description: The name for the application. + name: SECRET_NAME + required: true + value: prod-credentials +- description: The API URL + name: API_URL + required: true +- description: The Registry Route URL + name: REGISTRY_URL + required: true +- description: Service Account Token + name: TOKEN + required: true diff --git a/multi-cluster-spring-boot/applier/templates/deployment.yml b/multi-cluster-spring-boot/applier/templates/deployment.yml new file mode 100644 index 00000000..b981ae5c --- /dev/null +++ b/multi-cluster-spring-boot/applier/templates/deployment.yml @@ -0,0 +1,145 @@ +apiVersion: v1 +kind: Template +labels: + template: basic-spring-boot +metadata: + annotations: + description: Application template for JWS applications built using a Jenkins Pipeline + iconClass: icon-tomcat + tags: java,spring + version: 1.2.0 + name: basic-sprint-boot +objects: +- apiVersion: v1 + kind: Service + metadata: + annotations: + description: The web server's http port. + labels: + application: ${APPLICATION_NAME} + name: ${APPLICATION_NAME} + namespace: ${NAMESPACE} + spec: + ports: + - port: 8080 + targetPort: 8080 + selector: + deploymentConfig: ${APPLICATION_NAME} +- apiVersion: v1 + id: ${APPLICATION_NAME}-http + kind: Route + metadata: + annotations: + description: Route for application's http service. + labels: + application: ${APPLICATION_NAME} + name: ${APPLICATION_NAME} + namespace: ${NAMESPACE} + spec: + host: ${HOSTNAME_HTTP} + to: + name: ${APPLICATION_NAME} +- apiVersion: v1 + kind: ImageStream + metadata: + labels: + application: ${APPLICATION_NAME} + name: ${APPLICATION_NAME} + namespace: ${NAMESPACE} +- apiVersion: v1 + kind: DeploymentConfig + metadata: + labels: + application: ${APPLICATION_NAME} + name: ${APPLICATION_NAME} + namespace: ${NAMESPACE} + spec: + replicas: 1 + selector: + deploymentConfig: ${APPLICATION_NAME} + strategy: + type: Recreate + template: + metadata: + labels: + application: ${APPLICATION_NAME} + deploymentConfig: ${APPLICATION_NAME} + name: ${APPLICATION_NAME} + spec: + containers: + - env: + - name: JWS_ADMIN_USERNAME + value: ${JWS_ADMIN_USERNAME} + - name: JWS_ADMIN_PASSWORD + value: ${JWS_ADMIN_PASSWORD} + image: ${APPLICATION_NAME} + imagePullPolicy: Always + name: ${APPLICATION_NAME} + ports: + - containerPort: 8778 + name: jolokia + protocol: TCP + - containerPort: 8080 + name: http + protocol: TCP + readinessProbe: + exec: + command: + - /bin/bash + - -c + - curl -s 'http://localhost:8080${READINESS_PATH}' + |grep -iq '${READINESS_RESPONSE}' + terminationGracePeriodSeconds: 60 + triggers: + - imageChangeParams: + automatic: true + containerNames: + - ${APPLICATION_NAME} + from: + kind: ImageStreamTag + name: ${APPLICATION_NAME}:latest + type: ImageChange + - type: ConfigChange +- apiVersion: v1 + groupNames: null + kind: RoleBinding + metadata: + creationTimestamp: null + labels: + template: basic-tomcat-template + name: jenkins_edit + namespace: ${NAMESPACE} + roleRef: + name: edit + subjects: + - kind: ServiceAccount + name: ${SA_NAME} + namespace: ${SA_NAMESPACE} + userNames: + - system:serviceaccount:${SA_NAMESPACE}:${SA_NAME} +parameters: +- description: The name for the application. + name: APPLICATION_NAME + required: true + value: jws-app +- description: The namespace to deploy into + name: NAMESPACE + required: true +- description: Name of a service account that can deploy to this project + name: SA_NAME + required: true + value: jenkins +- description: Namespace of service account that can deploy to this project + name: SA_NAMESPACE + required: true +- description: 'Custom hostname for http service route. Leave blank for default hostname, + e.g.: -.' + name: HOSTNAME_HTTP +- description: 'URI to check for app health' + name: READINESS_PATH + required: true + value: '/' +- description: 'String value expected back from readiness check' + name: READINESS_RESPONSE + required: true + value: 'Hello World!' diff --git a/multi-cluster-spring-boot/requirements.yml b/multi-cluster-spring-boot/requirements.yml new file mode 100644 index 00000000..26d57cb7 --- /dev/null +++ b/multi-cluster-spring-boot/requirements.yml @@ -0,0 +1,8 @@ +# This is the Ansible Galaxy requirements file to pull in the correct roles +# to support the operation of CASL provisioning/runs. + +# From 'casl-ansible' +- name: casl-ansible + scm: git + src: https://github.com/redhat-cop/casl-ansible + version: v3.7.1