├── .gitignore ├── .travis.yml ├── README.md ├── _devops-workshop.yml ├── _modules.yml ├── apb ├── Dockerfile ├── apb.yml ├── playbooks │ └── provision.yml ├── requirements-travis.yml └── requirements.yml ├── devops-custom-slave.adoc ├── devops-deploy-jenkins.adoc ├── devops-deployment-envs.adoc ├── devops-env-info.adoc ├── devops-explore-openshift.adoc ├── devops-intro.adoc ├── devops-pipeline-scm.adoc ├── devops-promotion.adoc ├── devops-simple-pipeline.adoc ├── devops-webhook.adoc ├── devops-zerodowntime-automated.adoc ├── devops-zerodowntime-manual.adoc └── images ├── devops-envs-cart-build-logs.png ├── devops-envs-cart-build.png ├── devops-envs-cart-deployed.png ├── devops-envs-cart-healthchecks.png ├── devops-envs-cart-newapp.png ├── devops-envs-catalog-jdk.png ├── devops-envs-create-dev.png ├── devops-envs-dev-membership.png ├── devops-envs-dev-project.png ├── devops-explore-cert-warning-chrome.png ├── devops-explore-cert-warning-firefox.png ├── devops-explore-che-stack.png ├── devops-explore-che-terminal.png ├── devops-explore-web-login.png ├── devops-explore-web-projects.png ├── devops-intro-cd.png ├── devops-intro-coolstore-arch.png ├── devops-intro-coolstore.png ├── devops-intro-openshift-arch.png ├── devops-jenkins-catalog.png ├── devops-jenkins-login.png ├── devops-jenkins-oauth.png ├── devops-jenkins-templates.png ├── devops-pipeline-scm-diagram.png ├── devops-pipeline-scm-started.png ├── devops-promotion-build-template.png ├── devops-promotion-builds.png ├── devops-promotion-coolstore-deployed.png ├── devops-promotion-coolstore-template-params.png ├── devops-promotion-coolstore-template.png ├── devops-promotion-membership.png ├── devops-promotion-pipeline-approve.png ├── devops-promotion-pipeline-complete.png ├── devops-promotion-pipeline-diagram.png ├── devops-promotion-pipeline-manual.png ├── devops-promotion-prod-project.png ├── devops-promotion-projects.png ├── devops-promotion-select-from-project-templates.png ├── devops-promotion-select-from-project.png ├── devops-simple-pipeline-complete.png ├── devops-simple-pipeline-diagram-s2i.png ├── devops-simple-pipeline-diagram.png ├── devops-simple-pipeline-jenkins-autoprovision.png ├── devops-simple-pipeline-logs.png ├── devops-simple-pipeline-started.png ├── devops-slave-distributed-arch.png ├── devops-slave-gradle-pipeline.png ├── devops-slave-job-log.png ├── devops-slave-pod-template.png ├── devops-webhook-diagram.png ├── devops-webhook-gogs-add.png ├── devops-zerodowntime-bg-approve.png ├── devops-zerodowntime-bg-approved.png ├── devops-zerodowntime-bg-routes.png ├── devops-zerodowntime-blue-live.png ├── devops-zerodowntime-bluegreen-diagram.png ├── devops-zerodowntime-bluegreen-pipeline.png ├── devops-zerodowntime-cart-bluegreen.png ├── devops-zerodowntime-coolstore-arch.png ├── devops-zerodowntime-coolstore-bluegreen.png ├── devops-zerodowntime-edit-route.png ├── devops-zerodowntime-gogs-editor.png ├── devops-zerodowntime-green-deploy.png ├── devops-zerodowntime-green-live.png ├── devops-zerodowntime-shipping-costs.png ├── devops-zerodowntime-shipping-free.png ├── install-catalog.png ├── install-git-users.png └── install-master-url.png /.gitignore: -------------------------------------------------------------------------------- 1 | *.retry 2 | tmp/ 3 | *.log -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | sudo: required 3 | language: python 4 | python: "2.7" 5 | 6 | services: 7 | - docker 8 | 9 | before_install: 10 | - docker login -u $DOCKER_USER -p $DOCKER_PASS 11 | 12 | install: 13 | - pip install ansible 14 | - ansible-galaxy install -r apb/requirements-travis.yml 15 | - ansible-playbook apb/playbooks/provision.yml --syntax-check 16 | 17 | script: 18 | - cd apb && docker build -t openshiftapb/devops-workshop-apb:$TRAVIS_COMMIT . 19 | 20 | after_success: 21 | - export TAG=`if [ "$TRAVIS_BRANCH" == "master" ]; then echo "latest"; else echo $TRAVIS_BRANCH ; fi` 22 | - docker tag openshiftapb/devops-workshop-apb:$TRAVIS_COMMIT openshiftapb/devops-workshop-apb:$TAG 23 | - docker push openshiftapb/devops-workshop-apb:$TAG -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lab - DevOps Workshop on OpenShift [![Build Status](https://travis-ci.org/openshift-labs/devops-guides.svg?branch=ocp-3.11)](https://travis-ci.org/openshift-labs/devops-guides) 2 | 3 | * [Overview](#overview) 4 | * [Deploying the Workshop](#deploying-the-workshop) 5 | * [Deploying on Red Hat Product Demo System](#deploying-on-red-hat-product-demo-system) 6 | * [Manual Workshop Installation](#manual-workshop-installation) 7 | * [Install Lab Guides Only](#install-the-lab-guides-only) 8 | * [Running the Workshop](#running-the-workshop) 9 | * [Development](#development) 10 | 11 | ## Overview 12 | 13 | The DevOps with OpenShift Workshop provides full-stack and DevOps engineers an introduction to OpenShift and containers and how it can be used to build fully automated end-to-end deployment pipelines using advanced deployments techniques like rolling deploys and blue-green deployment. 14 | 15 | This workshop is a half-day event with a series of hands-on labs that are designed to familiarize participants with DevOps and Continuous Delivery concepts. The workshop will walk them through building an automated pipeline and how to customize Jenkins in various ways. 16 | 17 | The lab application used in this workshop is available at https://github.com/openshift-labs/devops-labs 18 | 19 | ### Agenda 20 | * DevOps Introduction 21 | * Explore OpenShift 22 | * Deployment Environments 23 | * Creating a Simple CI/CD Pipeline 24 | * Pipeline Definition as Code 25 | * Application Promotion Between Environments 26 | * Running the CI/CD Pipeline on Every Change 27 | * Zero-Downtime Deployment to Production 28 | * Automated Zero-Downtime Deployment with CI/CD Pipelines 29 | * Deploying Jenkins Manually 30 | * Creating Custom Jenkins Slave Pods 31 | 32 | 33 | | | | 34 | --- | --- 35 | | Audience Experience Level | Beginner | 36 | | Supported Number of Users | Up to 100 | 37 | | Average Time to Complete | 4 hours | 38 | 39 | ### Supplementary Content 40 | * [Lab Guide Introductory Slides](https://docs.google.com/presentation/d/1W4POTNEDAXyqXwLB_VLhaG_L19aZ1JXwjpCQUkprvqM/edit) 41 | 42 | ## Deploying the Workshop 43 | 44 | ### Deploying on Red Hat Product Demo System 45 | This workshop is typically run from RHPDS. Follow the instructions below to prepare the workshop on RHPDS. 46 | 47 | * [Order an "OpenShift Workshop" cluster on RHPDS](https://mojo.redhat.com/docs/DOC-1175640), and after the workshop is ready, log in as the cluster admin. This will provide you with an OpenShift 3.10 or 3.11 cluster, depending on what you choose. 48 | * Create a project with the name `lab-infra` (or any other name, that's just a suggestion) where the workshop infrastucture components such as Nexus, Gogs git server, lab guides, etc. will be deployed. 49 | * In the OpenShift service catalog search for "devops" and then click on the **DevOps Workshop Installer** and then click on the **Next** button. 50 | 51 | ![Search in Catalog](./images/install-catalog.png) 52 | * Enter the requested info. Note that the cluster admin username and password are required again since Automation Broker on OpenShift does not run as cluster admin (to avoid destructive behavior of course!). Also, enter the OpenShift public URL so that it is displayed in the lab guide correctly. 53 | 54 | ![Install Master URL](./images/install-master-url.png) 55 | * Enter the number of users you will have in the workshop so that Git repositories are created and pre-populated for them. 56 | ![Git Users](./images/install-git-users.png) 57 | 58 | * Then click on the **Create** button. 59 | 60 | The provisioning of the workshop will get started and it takes around 10 minutes. You will see pods popping up in the `lab-infra` project as the workshop is being provisioned. 61 | 62 | ### Manual Workshop Installation 63 | 64 | Typically you will follow the instructions above to Deploy the workshop via RHPDS. If you want to manually deploy it, follow these instructions. 65 | 66 | An [APB](https://hub.docker.com/r/openshiftapb/cloudnative-workshop-apb) is provided for 67 | deploying the DevOps Workshop infra (lab instructions, Nexus, Gogs, Eclipse Che, etc) in a project 68 | on an OpenShift cluster via the service catalog. In order to add this APB to the OpenShift service catalog, log in 69 | as cluster admin and perform the following in the `openshift-ansible-service-broker` project : 70 | 71 | 1. Edit the `broker-config` configmap and add this snippet right after `registry:`: 72 | 73 | ``` 74 | - name: dh 75 | type: dockerhub 76 | org: openshiftapb 77 | tag: ocp-3.11 78 | white_list: [.*-apb$] 79 | ``` 80 | 81 | 2. Redeploy the `asb` deployment 82 | 83 | You can [read more in the docs](https://docs.openshift.com/container-platform/3.11/install_config/oab_broker_configuration.html#oab-config-registry-dockerhub) 84 | on how to configure the service catalog. 85 | 86 | Note that if you are using the _OpenShift Workshop_ in RHPDS, this APB is already available in your service catalog. 87 | 88 | ![](images/service-catalog.png?raw=true) 89 | 90 | As an alternative, you can also run the APB directly in a pod on OpenShift to install the workshop infra: 91 | 92 | ``` 93 | oc login 94 | oc new-project lab-infra 95 | oc run apb --restart=Never --image="openshiftapb/devops-workshop-apb:ocp-3.11" \ 96 | -- provision -vvv -e namespace=$(oc project -q) -e openshift_token=$(oc whoami -t) 97 | 98 | ``` 99 | 100 | Or if you have Ansible installed locally, you can also run the Ansible playbooks directly on your machine: 101 | 102 | ``` 103 | oc login 104 | oc new-project lab-infra 105 | 106 | ansible-playbook -vvv playbooks/provision.yml \ 107 | -e namespace=$(oc project -q) \ 108 | -e openshift_token=$(oc whoami -t) \ 109 | -e openshift_master_url=$(oc whoami --show-server) 110 | ``` 111 | 112 | ## Install the Lab Guides Only 113 | 114 | Note that if you have used the above workshop installer, the lab instructions are already deployed. 115 | 116 | If you want to install only the lab guides, use the following command: 117 | 118 | ``` 119 | oc new-app osevg/workshopper:latest --name=guides \ 120 | -e CONTENT_URL_PREFIX=https://raw.githubusercontent.com/openshift-labs/devops-guides/ocp-3.11 \ 121 | -e WORKSHOPS_URLS=https://raw.githubusercontent.com/openshift-labs/devops-guides/ocp-3.11/_devops-workshop.yml 122 | oc expose svc/guides 123 | ``` 124 | ## Running the Workshop 125 | After provisioning is complete, the following components are deployed in the `lab-infra` project which is used by the workshop participants during the labs: 126 | 127 | * **Nexus Maven Repository**: http://nexus-lab-infra.apps.YOURCITY-GUID.open.redhat.com 128 | * **Eclipse Che Web IDE**: http://che-lab-infra.apps.YOURCITY-GUID.open.redhat.com 129 | * **Gogs Git Server**: http://gogs-lab-infra.apps.YOURCITY-GUID.open.redhat.com 130 | * **Lab Guides**: http://guides-lab-infra.apps.YOURCITY-GUID.open.redhat.com 131 | 132 | Note that YOURCITY is replaced with what you entered as **City or Customer** when ordering the OpenShift Workshop cluster in RHPDS. The GUID is a 4 character value that's generated, and you'll find it in the RHPDS emails or in the name of your Service listing in RHPDS. 133 | 134 | An example of the lab guides is available [here](http://devops-guides-labs.b9ad.pro-us-east-1.openshiftapps.com/). 135 | 136 | ## Development 137 | 138 | If you're doing development on the lab content, clone or fork the git repository and run the following inside the working copy directory: 139 | 140 | ``` 141 | docker run -it --rm -p 8080:8080 \ 142 | -v $(pwd):/app-data \ 143 | -e LOG_TO_STDOUT=true \ 144 | -e CONTENT_URL_PREFIX="file:///app-data" \ 145 | -e WORKSHOPS_URLS="file:///app-data/_devops-workshop.yml" \ 146 | quay.io/osevg/workshopper:latest 147 | ``` 148 | -------------------------------------------------------------------------------- /_devops-workshop.yml: -------------------------------------------------------------------------------- 1 | id: "devops" 2 | name: "DevOps Workshop with OpenShift" 3 | 4 | vars: 5 | OPENSHIFT_URL: "OPENSHIFT-MASTER" 6 | OPENSHIFT_USER: "userXX" 7 | OPENSHIFT_PASSWORD: "openshift3" 8 | OPENSHIFT_DOCS_BASE: "https://docs.openshift.com/container-platform/3.11" 9 | NEXUS_URL: "http://nexus-lab-infra.192.168.99.100.nip.io" 10 | NEXUS_INTERNAL_URL: "http://nexus.lab-infra.svc:8081" 11 | GIT_SERVER_URL: "gogs-lab-infra.192.168.99.100.nip.io" 12 | GIT_SERVER_INTERNAL_URL: "gogs.lab-infra.svc:3000" 13 | GIT_SERVER_TYPE: "gogs" 14 | GIT_USER: "userXX" 15 | GIT_PASSWORD: "openshift" 16 | PROJECT_SUFFIX: "XX" 17 | CART_ROUTE: "CART-ROUTE" 18 | CART_BLUE_ROUTE: "CART-BLUE-ROUTE" 19 | CART_GREEN_ROUTE: "CART-GREEN-ROUTE" 20 | ECLIPSE_CHE_URL: "http://che-lab-infra.192.168.99.100.nip.io" 21 | 22 | modules: 23 | activate: 24 | - devops-intro 25 | - devops-explore-openshift 26 | - devops-deployment-envs 27 | - devops-simple-pipeline 28 | - devops-pipeline-scm 29 | - devops-promotion 30 | - devops-webhook 31 | - devops-zerodowntime-manual 32 | - devops-zerodowntime-automated 33 | - devops-deploy-jenkins 34 | - devops-custom-slave 35 | - devops-env-info 36 | -------------------------------------------------------------------------------- /_modules.yml: -------------------------------------------------------------------------------- 1 | modules: 2 | devops-intro: 3 | name: DevOps Introduction 4 | devops-explore-openshift: 5 | name: Explore OpenShift 6 | devops-deployment-envs: 7 | name: Deployment Environments 8 | devops-simple-pipeline: 9 | name: Creating a Simple CI/CD Pipeline 10 | requires: 11 | - devops-deployment-envs 12 | devops-pipeline-scm: 13 | name: Pipeline Definition as Code 14 | requires: 15 | - devops-deployment-envs 16 | devops-promotion: 17 | name: Application Promotion Between Environments 18 | requires: 19 | - devops-pipeline-scm 20 | devops-webhook: 21 | name: Running the CI/CD Pipeline on Every Change 22 | requires: 23 | - devops-promotion 24 | devops-zerodowntime-manual: 25 | name: Zero-Downtime Deployment to Production 26 | requires: 27 | - devops-webhook 28 | devops-zerodowntime-automated: 29 | name: Automated Zero-Downtime Deployment with CI/CD Pipelines 30 | requires: 31 | - devops-zerodowntime-manual 32 | devops-deploy-jenkins: 33 | name: Deploying Jenkins Manually 34 | devops-custom-slave: 35 | name: Creating Custom Jenkins Slave Pods 36 | devops-env-info: 37 | name: "Appnedix: Lab Environment" -------------------------------------------------------------------------------- /apb/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM quay.io/openshiftlabs/apb-base:1.2 2 | 3 | LABEL "com.redhat.apb.spec"=\ 4 | "dmVyc2lvbjogMS4wCm5hbWU6IGRldm9wcy13b3Jrc2hvcC1hcGIKZGVzY3JpcHRpb246IEFQQiB0\ 5 | byBkZXBsb3kgcmVxdWlyZWQgaW5mcmEgY29tcG9uZW50cyBmb3IgdGhlIERldk9wcyBXb3Jrc2hv\ 6 | cCBvbiBhbiBPcGVuU2hpZnQgY2x1c3RlcgpiaW5kYWJsZTogRmFsc2UKYXN5bmM6IG9wdGlvbmFs\ 7 | CnRhZ3M6Ci0gd29ya3Nob3AKbWV0YWRhdGE6CiAgZGVwZW5kZW5jaWVzOiBbXQogIGRpc3BsYXlO\ 8 | YW1lOiAiRGV2T3BzIFdvcmtzaG9wIEluc3RhbGxlciIKICBsb25nRGVzY3JpcHRpb246ICJJbnN0\ 9 | YWxscyB0aGUgbGFiIGluc3RydWN0aW9ucyBhbmQgcmVxdWlyZWQgY29tcG9uZW50cyAoR2l0IHNl\ 10 | cnZlciwgZXRjKSBmb3IgcnVubmluZyB0aGUgRGV2T3BzIFdvcmtzaG9wIGh0dHBzOi8vZ2l0aHVi\ 11 | LmNvbS9vcGVuc2hpZnQtbGFicy9kZXZvcHMtZ3VpZGVzIgogIGNvbnNvbGUub3BlbnNoaWZ0Lmlv\ 12 | L2ljb25DbGFzczogInBmaWNvbiBwZmljb24tcHJvY2Vzcy1hdXRvbWF0aW9uIgogIHByb3ZpZGVy\ 13 | RGlzcGxheU5hbWU6ICJSZWQgSGF0LCBJbmMuIgpwbGFuczoKICAtIG5hbWU6IGRlZmF1bHQKICAg\ 14 | IGRlc2NyaXB0aW9uOiBEZXBsb3lzIERldk9wcyBXb3Jrc2hvcCBJbmZyYXN0cnVjdHVyZQogICAg\ 15 | ZnJlZTogVHJ1ZQogICAgbWV0YWRhdGE6CiAgICAgIGRpc3BsYXlOYW1lOiBEZWZhdWx0CiAgICBw\ 16 | YXJhbWV0ZXJzOgogICAgLSBuYW1lOiBvcGVuc2hpZnRfYWRtaW5fdXNlcgogICAgICB0aXRsZTog\ 17 | VXNlcm5hbWUKICAgICAgZGVzY3JpcHRpb246IEFkbWluIHVzZXIgaXMgcmVxdWlyZWQgZm9yIGNy\ 18 | ZWF0aW5nIGNsdXN0ZXIgcmVzb3VyY2VzCiAgICAgIHR5cGU6IHN0cmluZwogICAgICByZXF1aXJl\ 19 | ZDogdHJ1ZQogICAgICBkaXNwbGF5X2dyb3VwOiBPcGVuU2hpZnQgQWRtaW4gVXNlcgogICAgLSBu\ 20 | YW1lOiBvcGVuc2hpZnRfYWRtaW5fcGFzc3dvcmQKICAgICAgdGl0bGU6IFBhc3N3b3JkCiAgICAg\ 21 | IGRlc2NyaXB0aW9uOiBBZG1pbiBwYXNzd29yZCBpcyByZXF1aXJlZCBmb3IgY3JlYXRpbmcgY2x1\ 22 | c3RlciByZXNvdXJjZXMKICAgICAgdHlwZTogc3RyaW5nCiAgICAgIHJlcXVpcmVkOiB0cnVlCiAg\ 23 | ICAgIGRpc3BsYXlfdHlwZTogcGFzc3dvcmQKICAgICAgZGlzcGxheV9ncm91cDogT3BlblNoaWZ0\ 24 | IEFkbWluIFVzZXIKICAgIC0gbmFtZTogb3BlbnNoaWZ0X21hc3Rlcl91cmwKICAgICAgdGl0bGU6\ 25 | IE9wZW5TaGlmdCBNYXN0ZXIgVVJMCiAgICAgIGRlc2NyaXB0aW9uOiBUaGUgYWRkcmVzcyB0byBP\ 26 | cGVuU2hpZnQgbWFzdGVyIFVSTCB0byBiZSBkaXNwbGF5ZWQgaW4gdGhlIGxhYiBndWlkZSB0byBw\ 27 | YXJ0aWNpcGFudHMKICAgICAgdHlwZTogc3RyaW5nCiAgICAgIHJlcXVpcmVkOiB0cnVlCiAgICAg\ 28 | IGRpc3BsYXlfdHlwZTogc3RyaW5nCiAgICAgIGRpc3BsYXlfZ3JvdXA6IExhYiBHdWlkZQogICAg\ 29 | LSBuYW1lOiBpbmZyYXN2Y3NfYWRtX3VzZXIKICAgICAgdGl0bGU6IEluZnJhIFNlcnZpY2VzIEFk\ 30 | bWluIFVzZXIKICAgICAgZGVzY3JpcHRpb246IEFkbWluIHVzZXIgZm9yIGluZnJhc3RydWN0dXJl\ 31 | IHNlcnZpY2VzIChHb2dzLCBDaGUsIC4uLikKICAgICAgdHlwZTogc3RyaW5nCiAgICAgIGRlZmF1\ 32 | bHQ6ICJhZG1pbnVzZXIiCiAgICAgIHJlcXVpcmVkOiB0cnVlCiAgICAgIGRpc3BsYXlfdHlwZTog\ 33 | dGV4dAogICAgICBkaXNwbGF5X2dyb3VwOiBXb3Jrc2hvcCBJbmZyYSBTZXJ2aWNlcwogICAgLSBu\ 34 | YW1lOiBpbmZyYXN2Y3NfYWRtX3B3ZAogICAgICB0aXRsZTogSW5mcmEgU2VydmljZXMgQWRtaW4g\ 35 | UGFzc3dvcmQKICAgICAgZGVzY3JpcHRpb246IEFkbWluIHBhc3N3b3JkIGZvciBpbmZyYXN0cnVj\ 36 | dHVyZSBzZXJ2aWNlcyAoR29ncywgQ2hlLCAuLi4pCiAgICAgIHR5cGU6IHN0cmluZwogICAgICBk\ 37 | ZWZhdWx0OiAiYWRtaW5wd2QiCiAgICAgIHJlcXVpcmVkOiB0cnVlCiAgICAgIGRpc3BsYXlfdHlw\ 38 | ZTogdGV4dAogICAgICBkaXNwbGF5X2dyb3VwOiBXb3Jrc2hvcCBJbmZyYSBTZXJ2aWNlcwogICAg\ 39 | LSBuYW1lOiBnb2dzX2dlbl91c2VyX2NvdW50CiAgICAgIHRpdGxlOiBOdW1iZXIgb2YgVXNlcnMK\ 40 | ICAgICAgZGVzY3JpcHRpb246IE51bWJlciBvZiBHb2dzIHVzZXIgdG8gYmUgY3JlYXRlZAogICAg\ 41 | ICB0eXBlOiBpbnQKICAgICAgZGVmYXVsdDogMTAwCiAgICAgIHJlcXVpcmVkOiB0cnVlCiAgICAg\ 42 | IGRpc3BsYXlfZ3JvdXA6IEdpdCBTZXJ2ZXIKICAgIC0gbmFtZTogZ29nc19nZW5fdXNlcl9wd2QK\ 43 | ICAgICAgdGl0bGU6IFVzZXIgUGFzc3dvcmQKICAgICAgZGVzY3JpcHRpb246IFBhc3N3b3JkIGZv\ 44 | ciBHb2dzIHVzZXJzCiAgICAgIHR5cGU6IHN0cmluZwogICAgICBkZWZhdWx0OiAib3BlbnNoaWZ0\ 45 | IgogICAgICByZXF1aXJlZDogdHJ1ZQogICAgICBkaXNwbGF5X2dyb3VwOiBHaXQgU2VydmVyCiAg\ 46 | ICAgIA==" 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | COPY playbooks /opt/apb/actions 55 | ADD requirements.yml /opt/apb/actions/requirements.yml 56 | RUN ansible-galaxy install -r /opt/apb/actions/requirements.yml -f 57 | RUN chmod -R g=u /opt/{ansible,apb} 58 | USER apb 59 | -------------------------------------------------------------------------------- /apb/apb.yml: -------------------------------------------------------------------------------- 1 | version: 1.0 2 | name: devops-workshop-apb 3 | description: APB to deploy required infra components for the DevOps Workshop on an OpenShift cluster 4 | bindable: False 5 | async: optional 6 | tags: 7 | - workshop 8 | metadata: 9 | dependencies: [] 10 | displayName: "DevOps Workshop Installer" 11 | longDescription: "Installs the lab instructions and required components (Git server, etc) for running the DevOps Workshop https://github.com/openshift-labs/devops-guides" 12 | console.openshift.io/iconClass: "pficon pficon-process-automation" 13 | providerDisplayName: "Red Hat, Inc." 14 | plans: 15 | - name: default 16 | description: Deploys DevOps Workshop Infrastructure 17 | free: True 18 | metadata: 19 | displayName: Default 20 | parameters: 21 | - name: openshift_admin_user 22 | title: Username 23 | description: Admin user is required for creating cluster resources 24 | type: string 25 | required: true 26 | display_group: OpenShift Admin User 27 | - name: openshift_admin_password 28 | title: Password 29 | description: Admin password is required for creating cluster resources 30 | type: string 31 | required: true 32 | display_type: password 33 | display_group: OpenShift Admin User 34 | - name: openshift_master_url 35 | title: OpenShift Master URL 36 | description: The address to OpenShift master URL to be displayed in the lab guide to participants 37 | type: string 38 | required: true 39 | display_type: string 40 | display_group: Lab Guide 41 | - name: infrasvcs_adm_user 42 | title: Infra Services Admin User 43 | description: Admin user for infrastructure services (Gogs, Che, ...) 44 | type: string 45 | default: "adminuser" 46 | required: true 47 | display_type: text 48 | display_group: Workshop Infra Services 49 | - name: infrasvcs_adm_pwd 50 | title: Infra Services Admin Password 51 | description: Admin password for infrastructure services (Gogs, Che, ...) 52 | type: string 53 | default: "adminpwd" 54 | required: true 55 | display_type: text 56 | display_group: Workshop Infra Services 57 | - name: gogs_gen_user_count 58 | title: Number of Users 59 | description: Number of Gogs user to be created 60 | type: int 61 | default: 100 62 | required: true 63 | display_group: Git Server 64 | - name: gogs_gen_user_pwd 65 | title: User Password 66 | description: Password for Gogs users 67 | type: string 68 | default: "openshift" 69 | required: true 70 | display_group: Git Server 71 | -------------------------------------------------------------------------------- /apb/playbooks/provision.yml: -------------------------------------------------------------------------------- 1 | - name: devops-workshop-apb playbook to provision the application 2 | hosts: localhost 3 | gather_facts: false 4 | connection: local 5 | vars: 6 | master_url: "kubernetes.default" 7 | openshift_master_url: 8 | openshift_admin_user: 9 | openshift_admin_password: 10 | openshift_token: 11 | openshift_user_format: userX 12 | openshift_user_password: openshift 13 | project_suffix: "X" 14 | github_account: openshift-labs 15 | github_ref: ocp-3.11 16 | gogs_gen_user_count: 100 17 | gogs_gen_user_format: user%d 18 | gogs_gen_user_format_display: userX 19 | gogs_gen_user_pwd: openshift 20 | infrasvcs_adm_user: adminuser 21 | infrasvcs_adm_pwd: adminpwd 22 | roles: 23 | - role: ansible.kubernetes-modules 24 | install_python_requirements: no 25 | - role: ansibleplaybookbundle.asb-modules 26 | 27 | tasks: 28 | - name: login as super user with token 29 | shell: "oc login {{ master_url }} --token={{ openshift_token }} --insecure-skip-tls-verify=true" 30 | when: 31 | - openshift_token is defined 32 | - openshift_token is not none 33 | - openshift_token|trim() != "" 34 | 35 | - name: login as super user with pwd 36 | shell: "oc login {{ master_url }} -u {{ openshift_admin_user }} -p {{ openshift_admin_password }} --insecure-skip-tls-verify=true" 37 | when: > 38 | openshift_token is not defined or 39 | openshift_token is none or 40 | openshift_token|trim() == "" 41 | 42 | - name: extract app route suffix 43 | block: 44 | - openshift_v1_route: 45 | name: dummy 46 | namespace: "{{ namespace }}" 47 | state: present 48 | spec_to_kind: Service 49 | spec_to_name: dummy 50 | spec_port_target_port: 8080 51 | register: dummy_route 52 | - set_fact: 53 | apps_hostname_suffix: "{{ dummy_route.route.spec.host|regex_replace('^dummy-' + namespace + '\\.(.*)$', '\\1') }}" 54 | - openshift_v1_route: 55 | name: dummy 56 | namespace: "{{ namespace }}" 57 | state: absent 58 | 59 | - import_role: 60 | name: openshift_sonatype_nexus 61 | vars: 62 | project_name: "{{ namespace }}" 63 | nexus_image_version: 3.12.1 64 | nexus_max_memory: 6Gi 65 | 66 | - import_role: 67 | name: openshift_gogs 68 | vars: 69 | project_name: "{{ namespace }}" 70 | gogs_route: "gogs-{{ namespace }}.{{ apps_hostname_suffix }}" 71 | gogs_image_version: 0.11.34 72 | gogs_admin_user: "{{ infrasvcs_adm_user }}" 73 | gogs_admin_password: "{{ infrasvcs_adm_pwd }}" 74 | gogs_password: "{{ gogs_gen_user_pwd }}" 75 | gogs_generate_user_count: "{{ gogs_gen_user_count }}" 76 | gogs_generate_user_format: "{{ gogs_gen_user_format }}" 77 | 78 | - import_role: 79 | name: openshift_workshopper 80 | vars: 81 | project_name: "{{ namespace }}" 82 | workshopper_content_url_prefix: "https://raw.githubusercontent.com/{{ github_account }}/devops-guides/{{ github_ref }}" 83 | workshopper_workshop_urls: "https://raw.githubusercontent.com/{{ github_account }}/devops-guides/{{ github_ref }}/_devops-workshop.yml" 84 | workshopper_env_vars: 85 | OPENSHIFT_URL: "{{ openshift_master_url }}" 86 | PROJECT_SUFFIX: "{{ project_suffix }}" 87 | COOLSTORE_PROJECT: coolstore{{ project_suffix }} 88 | GIT_SERVER_URL: gogs-{{ namespace }}.{{ apps_hostname_suffix }} 89 | GIT_SERVER_INTERNAL_URL: gogs.{{ namespace }}.svc.cluster.local:3000 90 | OPENSHIFT_PASSWORD: "{{ openshift_user_password }}" 91 | OPENSHIFT_USER: "{{ openshift_user_format }}" 92 | GIT_USER: "{{ gogs_gen_user_format_display }}" 93 | GIT_PASSWORD: "{{ gogs_gen_user_pwd }}" 94 | OPENSHIFT_APPS_HOSTNAME: "{{ apps_hostname_suffix }}" 95 | ECLIPSE_CHE_URL: http://che-{{ namespace }}.{{ apps_hostname_suffix }} 96 | NEXUS_URL: http://nexus-{{ namespace }}.{{ apps_hostname_suffix }} 97 | NEXUS_INTERNAL_URL: http://nexus.{{ namespace }}.svc.cluster.local:8081 98 | 99 | - import_role: 100 | name: openshift_eclipse_che 101 | vars: 102 | project_name: "{{ namespace }}" 103 | che_version: "6.7.1" 104 | multi_user: true 105 | route_suffix: "{{ apps_hostname_suffix }}" 106 | keycloak_admin_user: "{{ infrasvcs_adm_user }}" 107 | keycloak_admin_pwd: "{{ infrasvcs_adm_pwd }}" 108 | install_java_oc_stack: true 109 | 110 | - import_role: 111 | name: openshift_jenkins 112 | vars: 113 | update_jenkins_templates: true 114 | jenkins_template_disable_admin_monitors: true 115 | deploy_jenkins: false 116 | jenkins_max_cpu: 2 117 | jenkins_max_mem: 2Gi 118 | 119 | - name: create temporary git directory 120 | tempfile: 121 | state: directory 122 | prefix: projects-git 123 | register: git_dir 124 | 125 | - name: unarchive projects source archive 126 | unarchive: 127 | remote_src: yes 128 | src: "https://github.com/{{ github_account }}/devops-labs/archive/{{ github_ref }}.tar.gz" 129 | dest: "{{ git_dir.path }}" 130 | 131 | - name: init cart-service git repository 132 | shell: | 133 | git init 134 | git add . --all 135 | git config user.email "developer@rhdevops.com" 136 | git config user.name "developer" 137 | git commit -m "Initial add" 138 | args: 139 | chdir: "{{ git_dir.path }}/devops-labs-{{ github_ref }}/cart-spring-boot" 140 | 141 | - name: create cart-service git repositories 142 | uri: 143 | url: http://gogs-{{ namespace }}.{{ apps_hostname_suffix }}/api/v1/user/repos 144 | method: POST 145 | body: '{"name": "cart-service", "private": false}' 146 | body_format: json 147 | user: "{{ item }}" 148 | password: "{{ gogs_gen_user_pwd }}" 149 | status_code: 200,201 150 | force_basic_auth: true 151 | with_sequence: start=1 end={{ gogs_gen_user_count|int }} format="{{ gogs_gen_user_format }}" 152 | when: gogs_gen_user_count|int > 1 153 | ignore_errors: true 154 | 155 | - name: push cart-service to git repository 156 | shell: "git push -f http://{{ item }}:{{ gogs_gen_user_pwd }}@gogs-{{ namespace }}.{{ apps_hostname_suffix }}/{{ item }}/cart-service.git master" 157 | args: 158 | chdir: "{{ git_dir.path }}/devops-labs-{{ github_ref }}/cart-spring-boot" 159 | with_sequence: start=1 end={{ gogs_gen_user_count|int }} format="{{ gogs_gen_user_format }}" 160 | when: gogs_gen_user_count|int > 1 161 | 162 | - name: Install Catalog Build templates in openshift namespace 163 | command: oc create -f https://raw.githubusercontent.com/{{ github_account }}/devops-labs/{{ github_ref }}/openshift/coolstore-build-template.yaml -n openshift 164 | 165 | - name: Create Images in openshift namespace 166 | command: oc new-app coolstore-builds -p MAVEN_MIRROR_URL=http://nexus.{{ namespace }}.svc.cluster.local:8081/repository/maven-all-public -p GIT_URI=https://github.com/{{ github_account }}/devops-labs.git -p GIT_REF={{ github_ref }} -p BUILD_TAG=prod -n openshift 167 | 168 | # track workshop deployment 169 | - import_role: 170 | name: workshop_deployment_tracker 171 | vars: 172 | apps_hostname_suffix: "{{ apps_hostname_suffix }}" 173 | workshop_type: devops -------------------------------------------------------------------------------- /apb/requirements-travis.yml: -------------------------------------------------------------------------------- 1 | - src: siamaksade.openshift_sonatype_nexus 2 | version: 1.1.0 3 | name: openshift_sonatype_nexus 4 | 5 | - src: siamaksade.openshift_gogs 6 | version: 1.1.0 7 | name: openshift_gogs 8 | 9 | - src: siamaksade.openshift_workshopper 10 | version: 1.2.0 11 | name: openshift_workshopper 12 | 13 | - src: siamaksade.openshift_eclipse_che 14 | version: 1.2.0 15 | name: openshift_eclipse_che 16 | 17 | - src: siamaksade.openshift_jenkins 18 | version: 1.3.0 19 | name: openshift_jenkins 20 | 21 | - src: openshift_labs.workshop_deployment_tracker 22 | version: 1.0.1 23 | name: workshop_deployment_tracker 24 | 25 | - src: ansible.kubernetes-modules 26 | 27 | - src: ansibleplaybookbundle.asb-modules 28 | -------------------------------------------------------------------------------- /apb/requirements.yml: -------------------------------------------------------------------------------- 1 | - src: siamaksade.openshift_sonatype_nexus 2 | version: 1.1.0 3 | name: openshift_sonatype_nexus 4 | 5 | - src: siamaksade.openshift_gogs 6 | version: 1.1.0 7 | name: openshift_gogs 8 | 9 | - src: siamaksade.openshift_workshopper 10 | version: 1.2.0 11 | name: openshift_workshopper 12 | 13 | - src: siamaksade.openshift_eclipse_che 14 | version: 1.2.0 15 | name: openshift_eclipse_che 16 | 17 | - src: siamaksade.openshift_jenkins 18 | version: 1.3.0 19 | name: openshift_jenkins 20 | 21 | - src: openshift_labs.workshop_deployment_tracker 22 | version: 1.0.1 23 | name: workshop_deployment_tracker 24 | -------------------------------------------------------------------------------- /devops-custom-slave.adoc: -------------------------------------------------------------------------------- 1 | ## Creating Custom Jenkins Slave Pods 2 | 3 | In this lab you will get familiar with creating custom slave container images for running distributed builds on OpenShfit. 4 | 5 | #### Background 6 | 7 | As more teams adopt continuous integration and continuous delivery there will be more demand and load for the Jenkins server. Although adding more CPU and memory to the Jenkins container helps to some extent, quite soon you would reach a breaking point which stops you from running more Jenkins builds. Fortunately Jenkins is built with scalability in mind and supports a master-slave architecture to allow running many simultaneous builds on slave nodes (workers) and allow Jenkins master to coordinate these builds. This distributed computing model will allow the Jenkins master to remain responsive to users, while offloading automation execution to the connected slave. 8 | 9 | image::devops-slave-distributed-arch.png[Jenkins Master-Slave Architecture] 10 | 11 | 12 | This master-slave architecture also allows creating separate slaves with specific build tools installed such as Maven, NodeJS, etc instead of having all the build tools installed on the master Jenkins. The user can then instruct Jenkins master to run the build job on a specific slave that has the appropriate build tools and libraries installed. 13 | 14 | The official Jenkins image provided by OpenShift includes the pre-installed https://wiki.jenkins-ci.org/display/JENKINS/Kubernetes%2BPlugin[Kubernetes plug-in] that allows Jenkins slaves to be dynamically provisioned on multiple container hosts using Kubernetes and OpenShift. 15 | 16 | To facilitate the using of the Kubernetes plug-in, OpenShift Container Platform provides three images suitable for use as Jenkins slaves: 17 | 18 | * Base slave 19 | * Maven slave 20 | * NodeJS slave 21 | 22 | The base image for Jenkins slaves pulls in both required tools (headless Java, the Jenkins JNLP client) and generally useful ones (including git, tar, zip, nss among others) as well as running the slave agent. 23 | 24 | The certified Jenkins image provided by OpenShift also provides auto-discovery and auto-configuration of slave images by searching for these in the existing image streams within the project that it is running in. The search specifically looks for image streams that have the label role=jenkins-slave. When it finds an image stream with this label, it generates the corresponding Kubernetes plug-in configuration so you can assign your Jenkins jobs to run in a pod running the container image provided by the image stream. 25 | 26 | Note that this scanning is only performed once, when the Jenkins master is starting. 27 | 28 | After Maven, Gradle is one of the popular build tools for Java projects. Let’s build a new slave image to enable Jenkins to run Gradle builds. 29 | Due to similarities between Maven and Gradle, the simplest way to start is to create a Dockerfile and build upon the Maven slave image. Here is the content of the https://github.com/openshift-labs/devops-labs/blob/ocp-3.11/solutions/lab-10/Dockerfile[Dockerfile on GitHub] for building the Gradle slave image: 30 | 31 | [source,shell] 32 | ---- 33 | FROM openshift3/jenkins-slave-maven-rhel7 34 | ENV GRADLE_VERSION=4.9 35 | USER root 36 | RUN curl -skL -o /tmp/gradle-bin.zip https://services.gradle.org/distributions/gradle-$GRADLE_VERSION-bin.zip && \ 37 | mkdir -p /opt/gradle && \ 38 | unzip -q /tmp/gradle-bin.zip -d /opt/gradle && \ 39 | ln -sf /opt/gradle/gradle-$GRADLE_VERSION/bin/gradle /usr/local/bin/gradle 40 | RUN chown -R 1001:0 /opt/gradle && \ 41 | chmod -R g+rw /opt/gradle 42 | USER 1001 43 | ---- 44 | 45 | You can build the docker image on OpenShift by creating a new build from the Git repository that contains the Dockerfile. OpenShift automatically detects the Dockerfile in the Git repository, builds an image from it and pushes the image into the OpenShift integrated image registry: 46 | 47 | [source,shell] 48 | ---- 49 | $ oc project ci 50 | $ oc new-build https://github.com/openshift-labs/devops-labs.git#ocp-3.11 --name=jenkins-slave-gradle-rhel7 --context-dir=solutions/lab-10 51 | $ oc logs -f bc/jenkins-slave-gradle-rhel7 52 | ---- 53 | 54 | You can verify that an image stream is created in the _CI/CD Infra_ project for the Jenkins Gradle slave image: 55 | 56 | [source,shell] 57 | ---- 58 | $ oc get is 59 | 60 | NAME DOCKER REPO TAGS 61 | jenkins-slave-gradle-rhel7 172.30.1.1:5000/ci/jenkins-slave-gradle-rhel7 latest 62 | jenkins-slave-maven-rhel7 172.30.1.1:5000/ci/jenkins-slave-maven-rhel7 latest 63 | ---- 64 | 65 | The image is ready in the registry and all is left is to add metadata to the image stream so that Jenkins master can discover this new slave image by assigning the label `role=jenkins-slave` to the image and also optionally annotate it with `slave-label=gradle` to specify the slave name which is by default the name of the image. 66 | 67 | [source,shell] 68 | ---- 69 | $ oc label is/jenkins-slave-gradle-rhel7 role=jenkins-slave 70 | $ oc annotate is/jenkins-slave-gradle-rhel7 slave-label=gradle 71 | ---- 72 | 73 | When Jenkins master starts for the first time, it automatically scans the image registry for slave images and configures them on Jenkins. Since you use an ephemeral Jenkins (without persistent storage) in this lab, restarting Jenkins causes a fresh Jenkins container to be deployed and to run the automatic configuration and discovery at startup to configure the Gradle slave image. When using a persistent Jenkins, all configurations would be kept and be available on the new container as well and therefore the automatic scan would not get triggered to avoid overwriting user configurations in Jenkins. In that case, you can configure the Gradle jenkins slave by adding a *Kubernetes Pod Template* in Jenkins configuration panel. 74 | 75 | Delete the Jenkins pod so that OpenShift auto-healing capability starts a new Jenkins pod: 76 | 77 | [source,shell] 78 | ---- 79 | $ oc delete pod -l name=jenkins 80 | ---- 81 | 82 | When Jenkins is up and running again, you can login into Jenkins using your OpenShift credentials then *Manage Jenkins -> Configure System*. Scroll down to the Kubernetes section and notice that there is a Kubernetes Pod Template defined automatically for the Gradle slave image your created. 83 | 84 | image::devops-slave-pod-template.png[Kubernetes Pod Template] 85 | 86 | You can instruct Jenkins to run a pipeline using a specific slave image by specifying the slave label in the `node` step. The slave image label is either the image name or if specified, the value of `slave-label` annotation on the image stream. The following is a simple pipeline definition that clones the Cart service from the Git repository and then builds it using Gradle. Note that Cart service supports both Maven and Gradle as build systems: 87 | 88 | [source,shell] 89 | ---- 90 | pipeline { 91 | agent { 92 | label 'gradle' 93 | } 94 | stages { 95 | stage('Build') { 96 | steps { 97 | git url: "http://{{GIT_SERVER_INTERNAL_URL}}/{{GIT_USER}}/cart-service.git" 98 | sh "gradle build" 99 | } 100 | } 101 | stage('Test') { 102 | steps { 103 | sh "gradle test" 104 | } 105 | } 106 | } 107 | } 108 | ---- 109 | 110 | Create an OpenShift Pipeline that embeds the above pipeline definition. Click on *Add to project* in the CI/CD Infra project and then *Import YAML/JSON*. Paste the following YAML script in the text field and then click on *Create*. 111 | 112 | [source,shell] 113 | ---- 114 | apiVersion: v1 115 | kind: BuildConfig 116 | metadata: 117 | name: gradle-pipeline 118 | spec: 119 | strategy: 120 | jenkinsPipelineStrategy: 121 | jenkinsfile: |- 122 | pipeline { 123 | agent { 124 | label 'gradle' 125 | } 126 | stages { 127 | stage('Build') { 128 | steps { 129 | git url: "http://{{GIT_SERVER_INTERNAL_URL}}/{{GIT_USER}}/cart-service.git" 130 | sh "gradle build" 131 | } 132 | } 133 | stage('Test') { 134 | steps { 135 | sh "gradle test" 136 | } 137 | } 138 | } 139 | } 140 | type: JenkinsPipeline 141 | ---- 142 | 143 | In the _CI/CD Infra_ project, click on *Builds -> Pipelines* on the left sidebar menu and then click on *Start Pipeline* button on the right side of *gradle-pipeline*. A new instance of the pipeline starts running using the Gradle slave image. 144 | 145 | image::devops-slave-job-log.png[Pipeline Log] 146 | 147 | image::devops-slave-gradle-pipeline.png[OpenShift Pipeline with Gradle] 148 | -------------------------------------------------------------------------------- /devops-deploy-jenkins.adoc: -------------------------------------------------------------------------------- 1 | ## Deploying Jenkins Manually 2 | 3 | In this lab you will learn how to deploy a Jenkins server manually on OpenShift. 4 | 5 | #### Background 6 | 7 | In previous labs, you used the auto-provisioning capability of OpenShift to deploy a Jenkins server automatically when you created a CI/CD pipeline using the certified Jenkins container image which is provided by OpenShift. 8 | 9 | Although very useful, sometimes you might want to have more control over Jenkins deployment and where it will be deployed. In those scenarios, you can disable the {{OPENSHIFT_DOCS_BASE}}/install_config/configuring_pipeline_execution.html[auto-provisioning] feature and deploy Jenkins manually using the provided templates or with other means. 10 | 11 | #### Deploy Jenkins 12 | 13 | Go to OpenShift Web Console, click on the logo to see the list of projects. Create a new project for Jenkins by clicking on *New Project* in OpenShift Web Console 14 | 15 | * Name: `ci-{{PROJECT_SUFFIX}}` 16 | * Display Name: `CI/CD Infra` 17 | 18 | Click on the *Browse Catalog* button and then on the *CI/CD* category. 19 | 20 | image::devops-jenkins-catalog.png[OpenShift Catalog] 21 | 22 | The two available templates deploy the Jenkins server but differ in their storage strategy, which affects whether or not the Jenkins content persists across a pod restart. A pod may be restarted when it is moved to another node, or when an update of the deployment configuration triggers a redeployment: 23 | 24 | * _Jenkins Ephemeral_ uses ephemeral storage. On pod restart, all data is lost. This template is useful for development or testing only. 25 | * _Jenkins Persistent_ uses a persistent volume store. Data survives a pod restart. To use a persistent volume store, the cluster administrator must define a persistent volume pool. 26 | 27 | For this lab, click on *Jenkins Ephemeral* template. If you don't have this template in your service catalog, then use the *Jenkins Persistent* template. 28 | 29 | You can customize the Jenkins properties such as service name, admin password, memory allocation, etc through the parameters in the web console. We can leave all of the default values, so just click on *Create* to deploy Jenkins. 30 | 31 | OpenShift deploys a Jenkins pod and also creates a service and route for the deployed container. 32 | 33 | Click on the Jenkins route in order to open the Jenkins Console. You will again need to accept the certificate. The Jenkins image that is provided by Red Hat uses an OAuth integration with OpenShift. 34 | 35 | image::devops-jenkins-login.png[Jenkins Login] 36 | 37 | Click *Login with OpenShift* and you will be taken to the OpenShift login screen. Use your OpenShift credentials and log in. You will then be prompted to allow Jenkins service account to access your account information: 38 | 39 | * Username: `{{OPENSHIFT_USER}}` 40 | * Password: `{{OPENSHIFT_PASSWORD}}` 41 | 42 | image::devops-jenkins-oauth.png[Jenkins OAuth Access] 43 | 44 | Click *Allow selected permissions*. 45 | 46 | In order to use this Jenkins server to perform actions on _Dev_ and _Prod_ projects, you need to assign the Jenkins service account edit role in the _Dev_ and _Prod_ projects. 47 | 48 | [source,shell] 49 | ---- 50 | $ oc policy add-role-to-user edit system:serviceaccount:ci-{{PROJECT_SUFFIX}}:jenkins -n dev-{{PROJECT_SUFFIX}} 51 | $ oc policy add-role-to-user edit system:serviceaccount:ci-{{PROJECT_SUFFIX}}:jenkins -n prod-{{PROJECT_SUFFIX}} 52 | ---- 53 | 54 | Your Jenkins server is ready now. -------------------------------------------------------------------------------- /devops-deployment-envs.adoc: -------------------------------------------------------------------------------- 1 | ## Deployment Environments 2 | 3 | In this lab you will learn about deployment environments in software delivery lifecycle and deploy the application into these deployment environments. 4 | 5 | #### Background 6 | A deployment environment describes a distinct space for an application to run during a particular stage of a CI/CD pipeline. Typical environments include development, test, stage, and production, for example. In this lab you will create _Dev_ and _Prod_ deployment environments for the CoolStore application which is deployed throughout this session: 7 | 8 | * *Dev Environment*: this environment is used during development of the Cart service and every change made by developers gets deployed into this environment. Other services e.g. Cart and Inventory would have also their own dedicated _Dev_ environments which allows the developers to write code and test their service without disrupting other teams. If the changes made pass the automated tests, the code will be deployed into the _Prod_ environment. 9 | * *Production Environment*: the live environment for the entire _CoolStore_ webshop with all services deployed and serving requests to customers. Any interruption in this environment would directly affect the customers. 10 | 11 | A _Project_ in OpenShift is a mechanism to scope applications in a cluster and is the central vehicle by which access to resources is managed. A project allows users to organize and manage their applications in isolation from other users. Users must be given access to projects by administrators, or if allowed to create projects, automatically have access to their own projects. Granular access control and network traffic policies for projects in OpenShift makes them a suitable way for modeling deployment environments that fulfil the collaboration, networking and isolation requirements. 12 | 13 | In this lab, you will create the _Dev_ deployment environment and deploy the Cart service into this environment. _Cart_ service is developed in Java using the Spring Boot framework. 14 | 15 | In the current lab, in order for you to become familiar with both the OpenShift Web Console and the OpenShift command line interface (CLI), every step is explained via both the Web Console and CLI which you can choose based on your preferences. Either way leads to the exact same result. 16 | Let’s start with with creating the _Dev_ deployment environment and deploying the Cart service. 17 | 18 | #### Create Project via OpenShift Web Console 19 | 20 | In OpenShift Web Console, click on the *Create Project* button in order to create a new project, enter the following details and click on *Create* button: 21 | 22 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 23 | 24 | * Name: `dev-{{PROJECT_SUFFIX}}` 25 | * Display Name: `Cart Dev` 26 | 27 | image::devops-envs-create-dev.png[Create Dev Project, width=360] 28 | 29 | The Dev deployment project for the Cart service is created now and is ready for the Cart service to be deployed. 30 | 31 | image::devops-envs-dev-project.png[Dev Project] 32 | 33 | By default, the current user who created the project is the _admin_ for this project. The OpenShift cluster admins or the project admins can define granular access control on the project and control how can view, modify or deploying applications in each project. This is particularly essential for example when you want developers to be able to view the _Prod_ environments and get debug information without allowing them to modify the state of those environments. In order to review the access control on the _Dev_ project, click on *Resources -> Membership* on the left sidebar menu. Note that the current user has the _admin_ role. 34 | 35 | image::devops-envs-dev-membership.png[Project Access Control, width=800] 36 | 37 | Now, let’s deploy the Spring Boot application, Cart service, into the Dev environment. OpenShift supports deploying containerized apps in three different ways and allows developer to pick the process that is most suitable for their projects: 38 | 39 | * From application source code 40 | * From application binary (e.g. app.jar) 41 | * From docker images 42 | 43 | OpenShift introduces a mechanism called {{OPENSHIFT_DOCS_BASE}}/architecture/core_concepts/builds_and_image_streams.html#source-build[Source-to-Image (S2I)] which is a tool for building docker container images. It produces ready-to-run images by injecting application source into a container image and assembling a new image. The new image incorporates the application runtime base image and built source code and is ready to use with the docker run command. The application base runtime might be various language runtimes such as Java, Ruby, NodeJS, Python, etc or middleware runtimes such as Apache Tomcat, JBoss EAP, etc. 44 | 45 | S2I can also take application binaries such as JAR, WAR or EAR files as input and build a new docker image for the application combined with the application runtime. 46 | 47 | If you already have a process in-place for building docker images, OpenShift allows you to point to the ready docker images and deploy them as is on the platform. 48 | 49 | In this lab, you will use the S2I mechanism for building the Cart service from source code. Since Cart service is based on Spring Boot, you only need the Java language runtime for running this service and therefore you will use the certified OpenJDK application runtime which is provided in OpenShift out-of-the-box. Click on *Browse Catalog* to open the service catalog. The catalog shows the list of available language and application runtimes, services as well as templates. A template describes how to build, configure and deploy a set of containers in a reproducible manner. OpenShift templates simplify composing complex multi-container applications and makes it easy to recreate and configure complete applications from scratch by deploying a template. 50 | 51 | Enter _jdk_ in the text field in order to find the *Red Hat OpenJDK 1.8* language runtime, and then click on the one that shows https://www.oracle.com/java/duke.html[duke, the java mascot]. 52 | 53 | image::devops-envs-catalog-jdk.png[OpenJDK Base Image, width=800] 54 | 55 | Now that you have chosen the Java language runtime, you can enter the URL to the Cart service application source code to specify it as an input to the S2I process. Click *Next* and enter the following in the text fields: 56 | 57 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 58 | 59 | * Name: `cart` 60 | * Git URL: `http://{{GIT_SERVER_INTERNAL_URL}}/{{GIT_USER}}/cart-service.git` 61 | 62 | image::devops-envs-cart-newapp.png[Deploy Cart Service, width=800] 63 | 64 | Click on *advanced options* to review advanced options for setting memory and cpu limits, environment variables, scaling and more when deploying an application. In this lab, similar to most development teams a Maven artifact repository (e.g. Sonatype Nexus and Artifactory) is used for managing Maven artifacts. Add the following environment variable under *Build Configuration* to specify the Maven repository manager URL to be used during the build phase: 65 | 66 | * Name: `MAVEN_MIRROR_URL` 67 | * Value: `{{NEXUS_INTERNAL_URL}}/repository/maven-all-public` 68 | 69 | Note that the Maven repository manager URL is an internal URL and is not accessible externally. Click on *Create* button and then on *Continue to the project overview.*. 70 | 71 | All required resources are created in order to build and deploy the Cart service in the Dev project. OpenShift provides an out-of-the-box load-balancer which is automatically updated to route traffic to Cart service when the container is deployed and ready to receive traffic. 72 | 73 | In the project overview, the Cart service S2I build process is running to build first the application JAR file and then a docker image by layering the JAR file on the OpenJDK base image. 74 | 75 | image::devops-envs-cart-build.png[Create Cart Service, width=900] 76 | 77 | You can see the build logs as build is making progress. If you want to see the full logs, click on *View Log* link to see the build logs in a larger window. You can click on the *Follow* link to follow the logs in the browser. 78 | 79 | image::devops-envs-cart-build-logs.png[Build Logs, width=900] 80 | 81 | When the build finishes and the application docker image is created, the docker image is pushed by default to OpenShift internal registry and then deployed to OpenShift. Builds also support pushing the built image to other image registries outside OpenShift. 82 | 83 | image::devops-envs-cart-deployed.png[Create Cart Service, width=800] 84 | 85 | OpenShift uses {{OPENSHIFT_DOCS_BASE}}/dev_guide/application_health.html[container health checks] to detect and handle or heal unhealthy containers which is not set yet on the deployed Cart service. OpenShift runs the following probes to manage the container and application health: 86 | 87 | * _Liveness Probe_: a liveness probe checks if the container is still running. If the liveness probe fails, OpenShift restarts the container 88 | * _Readiness Probe_: a readiness probe determines if a container is ready to service requests. If the readiness probe fails, OpenShift removes that container from the list of endpoints in the service load-balancer. A readiness probe can be used to signal the service load-balancer that even though a container is running, it should not receive any traffic. 89 | 90 | There are multiple ways to check a container liveness and readiness. You can define an HTTP URL, a command to execute in the container or a TCP socket to connect to. Click on *cart* deployment to see the deployment configuration for the Cart service. Alternatively, you can click on *Applications* → *Deployments* from the left-side menu and then on *cart*. Click on *Action* menu button and then *Edit Health Checks* to configure HTTP liveness and readiness probes for the Cart service. 91 | 92 | * Type: `HTTP` 93 | * Path: `/health` 94 | * Port: `8080` 95 | * Initial Delay: `15` 96 | 97 | image::devops-envs-cart-healthchecks.png[Create Cart Service, width=900] 98 | 99 | Wait till the Cart service is re-deployed with the new health check configurations and then verify that the Cart service is functioning by pointing your browser to the Cart service REST endpoint. 100 | 101 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 102 | 103 | Alternatively, you can use the `curl` command to verify that the Cart service is functioning: 104 | 105 | [source,shell] 106 | ---- 107 | $ curl http://{{CART_ROUTE}}/health 108 | 109 | {"status":"UP","diskSpace":{"status":"UP","total":10725883904,"free":9970741248,"threshold":10485760},"refreshScope":{"status":"UP"},"hystrix":{"status":"UP"}} 110 | ---- 111 | 112 | Note that Cart is a REST service and does not provide any web page at the root of the application. 113 | 114 | #### Create Project via OpenShift CLI 115 | 116 | You can perform the same steps as above using the OpenShift CLI commands. Start with creating the _Dev_ project: 117 | 118 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 119 | 120 | [source,shell] 121 | ---- 122 | $ oc new-project dev-{{PROJECT_SUFFIX}} --display-name="Cart Dev" 123 | ---- 124 | 125 | You can now create the Cart service by specifying the language runtime base image, the source code repository and a name for the service: 126 | 127 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 128 | 129 | [source,shell] 130 | ---- 131 | $ oc new-app java:8~http://{{GIT_SERVER_URL}}/{{GIT_USER}}/cart-service.git \ 132 | --name=cart \ 133 | --build-env=MAVEN_MIRROR_URL={{NEXUS_INTERNAL_URL}}/repository/maven-all-public 134 | 135 | --> Found image 56cfa0a (6 weeks old) in image stream "openshift/java" under tag "8" for "java:8" 136 | 137 | Java Applications 138 | ----------------- 139 | Platform for building and running plain Java applications (fat-jar and flat classpath) 140 | 141 | Tags: builder, java 142 | 143 | * A source build using source code from http://{{GIT_SERVER_URL}}/{{GIT_USER}}/cart-service.git will be created 144 | * The resulting image will be pushed to image stream "cart:latest" 145 | * Use 'start-build' to trigger a new build 146 | * This image will be deployed in deployment config "cart" 147 | * Ports 8080/tcp, 8443/tcp, 8778/tcp will be load balanced by service "cart" 148 | * Other containers can access this service through the hostname "cart" 149 | 150 | --> Creating resources ... 151 | imagestream "cart" created 152 | buildconfig "cart" created 153 | deploymentconfig "cart" created 154 | service "cart" created 155 | --> Success 156 | Build scheduled, use 'oc logs -f bc/cart' to track its progress. 157 | Application is not exposed. You can expose services to the outside world by executing one or more of the commands below: 158 | 'oc expose svc/cart' 159 | Run 'oc status' to view your app. 160 | ---- 161 | 162 | The Cart service is accessible by default within OpenShift. You can update the built-in load-balancer in OpenShift to route traffic to the Cart service by exposing the internal Cart service: 163 | [source,shell] 164 | ---- 165 | $ oc expose svc/cart 166 | route "cart" exposed 167 | ---- 168 | 169 | You can also view the build logs as the build is running: 170 | 171 | [source,shell] 172 | ---- 173 | $ oc logs bc/cart -f 174 | ---- 175 | 176 | And finally, define the `/health` HTTP URL as the liveness and readiness probes for the Cart service: 177 | 178 | [source,shell] 179 | ---- 180 | $ oc set probe dc/cart --readiness --liveness --get-url=http://:8080/health --initial-delay-seconds=15 181 | ---- 182 | -------------------------------------------------------------------------------- /devops-env-info.adoc: -------------------------------------------------------------------------------- 1 | ## Appendix: Environment Info 2 | 3 | You find all urls, hostnames, usernames and passwords that are needed during the 4 | labs in this page. Note that the urls are also embedded inside each lab instructions. 5 | 6 | **OPENSHIFT** 7 | 8 | Address: {{ OPENSHIFT_URL }} + 9 | 10 | Username: `{{ OPENSHIFT_USER }}` + 11 | Password: `{{ OPENSHIFT_PASSWORD }}` + 12 | 13 | IMPORTANT: Replace `{{ PROJECT_SUFFIX }}` with the id given to you by the instructor 14 | 15 | **GIT SERVER** 16 | 17 | Web: http://{{ GIT_SERVER_URL }} 18 | 19 | Username: `{{ GIT_USER }}` + 20 | Password: `{{ GIT_PASSWORD }}` + 21 | 22 | **NEXUS MAVEN REPOSITORY** 23 | 24 | Web: {{ NEXUS_URL }} 25 | 26 | **ECLIPSE CHE IDE** 27 | 28 | Register an account on Eclipse Che using an email address. 29 | 30 | Web: {{ ECLIPSE_CHE_URL }} 31 | 32 | **OPENSHIFT DOCS** 33 | 34 | Web: {{ OPENSHIFT_DOCS_BASE }} -------------------------------------------------------------------------------- /devops-explore-openshift.adoc: -------------------------------------------------------------------------------- 1 | ## Explore OpenShift 2 | 3 | In this lab you will get familiar with OpenShift Web Console and OpenShift CLI and gain some experience interactive with an OpenShift cluster. 4 | 5 | #### OpenShift CLI 6 | 7 | You can use the terminal on your workstation for running the OpenShift CLI commands, provided you {{OPENSHIFT_DOCS_BASE}}/cli_reference/get_started_cli.html[download the OpenShift CLI] and add it to your path. 8 | 9 | You might be familiar with the Eclipse IDE which is one of the most popular IDEs for Java and other 10 | programming languages. https://www.eclipse.org/che/[Eclipse Che] is the next-generation Eclipse IDE which is web-based 11 | and gives you a full-featured IDE running in the cloud. You have an Eclipse Che instance deployed on the OpenShift cluster 12 | which you can use during these labs for creating files and running OpenShift CLI commands. 13 | 14 | Eclipse Che: {{ECLIPSE_CHE_URL}} 15 | 16 | Register on Eclipse Che with any email and the same username as your OpenShift username, and the log in. 17 | 18 | In the Eclipse Che dashboard, select the **Java with OpenShift CLI** stack and then click on **Create** button, and **Open** button to create and open a workspace for yourself. 19 | 20 | image::devops-explore-che-stack.png[Eclipse Che - Create Workspace] 21 | 22 | It might take a little while till your IDE workspace is setup in the browser. You can now use the **Terminal** window 23 | in Eclipse Che to run any OpenShift CLI command. 24 | 25 | image::devops-explore-che-terminal.png[Eclipse Che - Terminal] 26 | 27 | In order to login, you can use the `oc` command and then specify the server that you want to authenticate to. Issue the following command: 28 | 29 | [source,shell] 30 | ---- 31 | $ oc login {{OPENSHIFT_URL}} 32 | ---- 33 | 34 | Enter *Y* to use a potentially insecure connection. The reason you received this message is because we are using a self-signed certificate for this workshop, but we did not provide you with the CA certificate that was generated by OpenShift. In a real-world scenario, either OpenShift certificate would be signed by a standard CA (eg: Thawte, Verisign, StartSSL, etc.) or signed by a corporate-standard CA that you already have installed on your system. 35 | 36 | Once you issue the `oc login` command, you will be prompted for the username and password combination for your user account. Replace XX with the username given to you by the instructor: 37 | 38 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 39 | 40 | * Username: `{{OPENSHIFT_USER}}` 41 | * Password: `{{OPENSHIFT_PASSWORD}}` 42 | 43 | Projects are a top level concept to help you organize your deployments. An OpenShift project allows a community of users (or a user) to organize and manage their content in isolation from other communities. Each project has its own resources, policies (who can or cannot perform actions), and constraints (quotas and limits on resources, etc). Projects act as a "wrapper" around all the application services and endpoints you (or your teams) are using for your work. You can see the list of projects you have access to using the following command: 44 | 45 | [source,shell] 46 | ---- 47 | $ oc get projects 48 | ---- 49 | 50 | Now you can create a project: 51 | 52 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 53 | 54 | [source,shell] 55 | ---- 56 | $ oc new-project explore-{{PROJECT_SUFFIX}} 57 | ---- 58 | 59 | When using OpenShift CLI, you can specify in which project the command should be executed using the `-n` switch. If not specified, OpenShift will run the command in the active project. You can switch between active projects using the `oc project` command: 60 | 61 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 62 | 63 | [source,shell] 64 | ---- 65 | $ oc project explore-{{PROJECT_SUFFIX}} 66 | 67 | Now using project "explore-{{PROJECT_SUFFIX}}" on server "{{OPENSHIFT_URL}}". 68 | ---- 69 | 70 | #### OpenShift Web Console 71 | 72 | OpenShift ships with a web-based console that will allow users to perform various tasks via a browser. To get a feel for how the web console works, open your browser and go to the following URL: {{OPENSHIFT_URL}} 73 | 74 | Since the security certificates used for securing your OpenShift cluster are self-generated and self-signed, your browser will not trust them by default and will show a security warning similar to the following: 75 | 76 | image::devops-explore-cert-warning-firefox.png[Firebox Untrusted Certificate] 77 | 78 | In Chrome browser, click on *ADVANCED* and then *Proceed to ... (unsafe)* to trust the certificates. In Firefox browser, click on *Advanced* button, then *Add Exception...* and then confirm trusting the certificate by click on *Confirm Security Exception*. 79 | 80 | The first screen you will see is the authentication screen. Enter in the following credentials: 81 | 82 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 83 | 84 | * Username: `{{OPENSHIFT_USER}}` 85 | * Password: `{{OPENSHIFT_PASSWORD}}` 86 | 87 | image::devops-explore-web-login.png[OpenShift Login] 88 | 89 | After you have authenticated to the web console, you will be presented with a list of projects that your user has permission to work with. 90 | 91 | When you click on the *explore-{{PROJECT_SUFFIX}}* project, you will be taken to the project overview page which will list all of the routes, services, deployments, and pods that you have running as part of your project. There’s nothing there now, but in the following labs you will create deployments and other resources in your projects. 92 | 93 | You can delete a project (and other resources) using the `oc delete` command. You won’t need the *explore-{{PROJECT_SUFFIX}}* project in the following labs and therefore you can clean up your environment by removing it: 94 | 95 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 96 | 97 | [source,shell] 98 | ---- 99 | $ oc delete project explore-{{PROJECT_SUFFIX}} 100 | ---- 101 | -------------------------------------------------------------------------------- /devops-intro.adoc: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | In this section we will give an overview of DevOps, Continuous Integration and Continuous Delivery concepts which are required throughout this session. 4 | 5 | #### What is DevOps? 6 | DevOps is a combination of development and operations principles in order to create a culture that emphasize communication, collaboration, and cohesion between the traditionally separate developer and IT operations teams. Rather than seeing these as two distinct groups who are responsible for their specific tasks but don’t really work together, the DevOps methodology recognizes the interdependence of the two groups. By integrating these functions as one team or department, DevOps helps an organization deploy software more frequently, while maintaining service stability and gaining the speed necessary for more innovation. 7 | 8 | In a DevOps environment, cross-functionality, shared responsibilities, and trust are all promoted. 9 | 10 | #### Continuous Everything 11 | 12 | DevOps essentially extends the continuous development goals of the Agile movement to continuous integration and continuous delivery. 13 | Continuous Integration is the practice of constantly merging development work with a main line of code (e.g. master branch) so that changes can be tested and make sure they work with all other changes. The goal is to test the code as often as possible in order catch issues early in the development phase. In the continuous integration process, automated tests such as unit tests play an important role and are essential for a functioning continuous integration process. 14 | Continuous Delivery is the natural extension of Continuous Integration, an approach in which teams ensure that every change to the system is releasable, and release any version with the push of a button. Continuous Delivery aims to make releases simple so that we can deliver as frequently as needed and get rapid feedback on what customers care about. 15 | 16 | Continuous Deployment is the most advanced evolution of continuous delivery and advocates automatic release of every change into production without human intervention after it has been successfully tested and verified in the process. Although interesting, few organization are ready today to automatically deploy changed to production. Nevertheless, Continuous Deployment should be a goal for every team to build sufficient trust in the process to be able to automatically deploy a class of changes into production. 17 | 18 | image::devops-intro-cd.png[Continuous Delivery and Continuous Deployment] 19 | 20 | #### Jenkins CI Engine 21 | 22 | Jenkins is a self-contained, extensible, open source automation server which can be used to automate all sorts of tasks such as building, testing, and deploying software. Although Jenkins was first popular as a continuous integration engine, its usage domain soon expanded to other areas such as Continuous Delivery pipelines due to its sheer popularity. Jenkins enjoys a very active community which has built out hundreds of plugins to extend Jenkins to automate almost anything. Jenkins provides support for all popular source code management systems (SCM) , popular build tools, as well as testing frameworks and report generators. 23 | The latest major release of Jenkins included a powerful Continuous Delivery pipeline support using a Groovy Domain Specific Language (DSL) which is referred to as _Pipeline as Code_. 24 | 25 | #### OpenShift Container Platform 26 | OpenShift is a container application platform from Red Hat that builds on top of docker and Kubernetes to to let you easily and quickly build, develop, and deploy containerized applications in nearly any infrastructure, public or private. OpenShift is optimized for continuous application development and multi-tenant deployment. OpenShift adds developer and operations-centric tools on top of Kubernetes to enable rapid application development, easy deployment and scaling, and long-term lifecycle maintenance for small and large teams. 27 | 28 | image::devops-intro-openshift-arch.png[OpenShift Architecture] 29 | 30 | OpenShift builds a developer-centric workflow around Docker containers and Kubernetes runtime concepts. There are few concepts you need to be familiar with when using OpenShift: 31 | 32 | _Container_: Linux containers are lightweight mechanisms for isolating running processes so that they are limited to interacting with only their designated resources. 33 | 34 | _Image_: a binary that includes all of the requirements for running a single container, as well as metadata describing its needs and capabilities. 35 | 36 | _Image Registry_: a service for storing and retrieving docker-formatted container images. A registry contains a collection of one or more image repositories. 37 | 38 | _Pod_: one or more containers deployed together on one host, and the smallest compute unit that can be defined, deployed, and managed. 39 | 40 | _Image Stream_: lets you easily tag, import, and publish docker images from the integrated image registry in OpenShift. 41 | 42 | _Build Config_: allows you to launch docker builds, build directly from source code or application binary, or trigger Jenkins Pipeline jobs whenever an image stream tag is updated. 43 | 44 | _Deployment Config_: allows you to redeploy whenever a new image becomes available. 45 | 46 | _Service_: an internal load balancer which identifies a set of pods in order to proxy the connections it receives to them. Backing pods can be added to or removed from a service arbitrarily while the service remains consistently available, enabling anything that depends on the service to refer to it at a consistent address. 47 | 48 | _Route_: make it trivial to expose your Kubernetes services via a public DNS name. 49 | 50 | _Template_: describes a set of objects (pods, build configs, deployment configs, etc) that can be parameterized and processed to produce a list of objects for creation by OpenShift. 51 | 52 | As an administrator, you can enable your developers to request new Projects which come with predefined roles, quotas, and security controls to fairly divide access. 53 | 54 | #### CoolStore Application 55 | 56 | CoolStore is a fully functional online shop application for selling Red Hat merchandise products and is used in the following labs to build and deploy through the CI/CD pipeline. 57 | 58 | image::devops-intro-coolstore.png[CoolStore Webshop] 59 | 60 | CoolStore is built using multiple Java frameworks and Node JS and follows the microservices style of architecture. Each microservice in CoolStore is developed, deployed and managed independently and is responsible for a single functionality in the online shop. A high-level architecture view of the CoolStore application follows: 61 | 62 | image::devops-intro-coolstore-arch.png[CoolStore Architecture] 63 | 64 | In this lab session, you will create a Continuous Delivery pipeline to automate test and deployment of the Cart service for every code and configuration change all the way to production. 65 | -------------------------------------------------------------------------------- /devops-pipeline-scm.adoc: -------------------------------------------------------------------------------- 1 | ## Pipeline Definition as Code 2 | 3 | In this lab you will get familiar with definine a pipeline as code and manage its versions via a version control system. 4 | 5 | #### Background 6 | Although it is convenient to embed a Jenkinsfile into an OpenShift Pipeline and edit it directly in the OpenShift Web Console, there is no history of changes made to the pipeline through the UI. Furthermore, switching back and forth between multiple versions of the pipeline becomes challenging with an embedded Jenkinsfile. Therefore, it is generally considered a best practice to create a Jenkinsfile and check it into the source control repository in order to manage its versions and history of changes applied to it. 7 | 8 | Using OpenShift Pipeline, you can store Jenkinsfiles in a Git repository and reference it in the JenkinsPipeline buildconfig. Whenever the pipeline starts running, OpenShift fetches the latest version the references Jenkinsfile from the Git repository and adjusts the pipeline steps accordingly. In this lab you will create an OpenShift Pipeline with the Jenkinsfile stored in a Git repository. 9 | 10 | Although CI/CD is a fairly new in many organizations, teams have been building Continuous Integration flows for a long time and have invested lots of time improving and refining that process. For Java projects, the CI flow generally moves around building the application JAR/WAR/EAR, running the unit-tests suits and integration tests and if successful, releasing the application binaries into a repository manager like Sonatype Nexus and Artifactory. In this lab, you will modify the pipeline in order to extend existing CI processes and build upon the Maven build and test flow that exists in many development teams. 11 | 12 | The following diagram shows the pipeline stages. For the sake simplicity, pushing the artifacts to an artifact repository is not included in this pipeline however you can include that using the https://jenkins.io/doc/pipeline/steps/nexus-artifact-uploader/[Nexus Artifact Uploader Plugin] for Sonatype Nexus and https://jenkins.io/doc/pipeline/steps/artifactory/#artifactoryupload-upload-artifacts[Artifactory Plugin] for Artifactory. 13 | 14 | image::devops-pipeline-scm-diagram.png[Pipeline Diagram] 15 | 16 | #### Pipeline from Git Repository 17 | 18 | Let’s start with cloning the `cart-service` Git repository where you will store the `Jenkinsfile`: 19 | 20 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 21 | 22 | [TIP] 23 | ==== 24 | If you are using Eclipse Che, click on **Import Project...** and then enter the Git url 25 | as the `URL` and click on **Import**. Make sure to replace your username and password in the 26 | Git url: 27 | 28 | http://{{GIT_USER}}:{{GIT_PASSWORD}}@{{GIT_SERVER_URL}}/{{GIT_USER}}/cart-service.git 29 | 30 | Choose **Java > Maven** as the project type and click on **Save**. 31 | 32 | You can now right-click on the **cart-service** project and click on **New > File** to create the `Jenkinsfile` 33 | ==== 34 | 35 | [source,shell] 36 | ---- 37 | $ cd 38 | $ git clone http://{{GIT_SERVER_URL}}/{{GIT_USER}}/cart-service.git 39 | $ cd cart-service 40 | $ touch Jenkinsfile 41 | ---- 42 | 43 | Open the created `Jenkinsfile` in a text editor and paste the following pipeline definition in the editor, and then save the `Jenkinsfile`: 44 | 45 | [source,shell] 46 | ---- 47 | pipeline { 48 | agent { 49 | label 'maven' 50 | } 51 | stages { 52 | stage('Build App') { 53 | steps { 54 | sh "mvn clean package -s src/main/config/settings.xml" 55 | } 56 | } 57 | stage('Integration Test') { 58 | steps { 59 | sh "mvn verify -s src/main/config/settings.xml" 60 | } 61 | } 62 | stage('Build Image') { 63 | steps { 64 | script { 65 | openshift.withCluster() { 66 | openshift.withProject() { 67 | openshift.startBuild("cart", "--from-file=target/cart.jar").logs("-f") 68 | } 69 | } 70 | } 71 | } 72 | } 73 | stage('Deploy') { 74 | steps { 75 | script { 76 | openshift.withCluster() { 77 | openshift.withProject() { 78 | dc = openshift.selector("dc", "cart") 79 | dc.rollout().latest() 80 | timeout(10) { 81 | dc.rollout().status() 82 | } 83 | } 84 | } 85 | } 86 | } 87 | } 88 | stage('Component Test') { 89 | steps { 90 | script { 91 | sh "curl -s -X POST http://cart:8080/api/cart/dummy/666/1" 92 | sh "curl -s http://cart:8080/api/cart/dummy | grep 'Dummy Product'" 93 | } 94 | } 95 | } 96 | } 97 | } 98 | ---- 99 | 100 | Notice that you don't have to use Git to clone the code repository in the pipeline anymore. The reason for that is that Jenkins has to clone the given code repository for fetching the pipeline definition, `Jenkinsfile`, and if the code for the application is also in the same repository then there is no need to clone the code, again. 101 | 102 | You need to push the Jenkinsfile to the Git repository in order to make it available on the Git server. Enter your Git username and password if asked: 103 | 104 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 105 | 106 | * Username: `{{GIT_USER}}` 107 | * Password: `{{GIT_PASSWORD}}` 108 | 109 | [source,shell] 110 | ---- 111 | $ git add Jenkinsfile 112 | $ git commit -m "Added cart pipeline" 113 | $ git push origin master 114 | ---- 115 | 116 | You can now create an OpenShift Pipeline and refer the pipelines Git repository to pull the Jenkinsfile and execute it 117 | 118 | [source,shell] 119 | ---- 120 | $ oc project dev--{{PROJECT_SUFFIX}} 121 | $ oc new-build . --name=cart-pipeline-git --strategy=pipeline -e NEXUS_URL={{NEXUS_INTERNAL_URL}} 122 | ---- 123 | 124 | Click on *Builds -> Pipelines* on the left sidebar menu. A new instance of the *cart-pipeline-git* pipeline has started running using your Jenkinsfile from the Git repository. 125 | 126 | image::devops-pipeline-scm-started.png[Pipeline from Git Repository] 127 | -------------------------------------------------------------------------------- /devops-promotion.adoc: -------------------------------------------------------------------------------- 1 | ## Application Promotion Between Environments 2 | 3 | In this lab you will learn about application promotion between deployment environment and promote services from _Dev_ environment to the _Prod_ environment. 4 | 5 | #### Background 6 | 7 | The CI/CD pipelines we created so far operate solely in the Dev environment. In this lab, you will extend the pipeline to promote the Cart service to the Production environment where it runs alongside other services that together build the CoolStore online shop. It is essential to build the application and the container image only once and use the same container image throughout the pipeline to guarantee that the same container image is tested and verified to be of acceptable quality for deploying in the Prod environment. 8 | 9 | #### Creating the Production Environment 10 | 11 | Go to project list in OpenShift and click on *New Project* for the Prod deployment environment for the CoolStore application: 12 | 13 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 14 | 15 | image::devops-promotion-prod-project.png[Production Project, width=340] 16 | 17 | Now you should see the _Dev_ and _Prod_ projects in the OpenShift Web Console, as well as via CLI: 18 | 19 | image::devops-promotion-projects.png[Projects, width=340] 20 | 21 | [source,shell] 22 | ---- 23 | $ oc get projects 24 | ---- 25 | 26 | #### CoolStore Webshop in Production Environment 27 | 28 | You can use an OpenShift template to deploy the CoolStore application services in the _Prod_ environment. An {{OPENSHIFT_DOCS_BASE}}/dev_guide/templates.html[OpenShift template] describes how to build, configure and deploy a set of contains in a reproducible manner. Note that normally, the container images for _Web UI_, _Coolstore GW_, _Catalog_ and _Inventory_ services are already built by respective teams and are available in the OpenShift integrated container registry. The CoolStore template would then just pull these images and deploys and configures them in the _Prod_ environment. 29 | 30 | image::devops-intro-coolstore-arch.png[CoolStore Architecture] 31 | 32 | In this lab, however, you are the whole team! Therefore you should build the images for once so that you can use them for the rest of the lab and deploy them in the production environment. 33 | 34 | Install the following template so that you can deploy the production images from the registry. 35 | 36 | [source,shell] 37 | ---- 38 | $ oc project prod-{{PROJECT_SUFFIX}} 39 | $ oc create -f https://raw.githubusercontent.com/openshift-labs/devops-labs/ocp-3.11/openshift/coolstore-deployment-template.yaml 40 | ---- 41 | 42 | You can go ahead and deploy the CoolStore application in production. In the _Prod_ project, click on *Add to project* and *Select from Project*. Choose the *CoolStore Deployments* template and then *Next* and again *Next*. 43 | 44 | If you remember, the Cart route hostname was generated for you in the *Cart Dev* project with the format: `cart-dev-{{PROJECT_SUFFIX}}.`. Specify the *Hostname Suffix* in the form by replacing `cart-dev-{{PROJECT_SUFFIX}}` in that generated format with `prod-{{PROJECT_SUFFIX}}`, so that the value of *Hostname Suffix* would be `prod-{{PROJECT_SUFFIX}}.` 45 | 46 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 47 | 48 | image::devops-promotion-coolstore-template-params.png[CoolStore Template - Parameters] 49 | 50 | Click on *Create*, and then on *Continue to overview*. You will notice that all services, including Cart are deployed in _Prod_ environment. 51 | 52 | image::devops-promotion-coolstore-deployed.png[CoolStore Webshop Containers] 53 | 54 | Let's promote Cart container image that is running in the _Dev_ environment to _Prod_ environment. The reason for doing so is to guarantee that the container image that runs in Prod environment is the same image that is running and has been tested in the Dev environment. 55 | 56 | You can use the `oc tag` CLI command for promoting images between environments. 57 | 58 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 59 | 60 | [source,shell] 61 | ---- 62 | $ oc tag dev-{{PROJECT_SUFFIX}}/cart:latest prod-{{PROJECT_SUFFIX}}/cart:prod 63 | 64 | Tag cart:prod set to dev-{{PROJECT_SUFFIX}}/cart@sha256:ee898ec51ab7bbce53ff41425683a3e5db98a4fe835a30ca1452b6a6d59ea1bd. 65 | ---- 66 | 67 | The above command promotes the `cart:latest` container image which is the latest image build of the Cart service in the _Dev_ environment, to the _Prod_ environment and names it `cart:prod`. As soon as the cart image is promoted to the _Prod_ environment, the Cart container gets automatically deployed. As new Cart service container images are built, the _Prod_ environment remains intact until you promote the new image builds to the _Prod_ environment after sufficient testing. 68 | 69 | When the Cart service is ready, click on the Web UI route url and verify that CoolStore online shop is working correctly. If the product list is not displayed correctly, refresh the page a few times. 70 | 71 | image::devops-intro-coolstore.png[CoolStore Webshop] 72 | 73 | #### Automated Application Promotion 74 | 75 | Now that you are familiar with the concept of application promotion between environments, let's automate the promotion process via the CI/CD pipeline you created in previous labs. Furthermore, deployment in Prod environment is a critical step that not all organizations are ready to automate yet. Therefore, you can introduce a manual step in the pipeline to allow a release manager to manually approve or reject a Prod deployment. The following diagram shows the updated pipeline stages: 76 | 77 | image::devops-promotion-pipeline-diagram.png[Application Promotion in CI/CD Pipeline] 78 | 79 | Open the `Jenkinsfile` you added to the pipelines Git repository and add the following stages for manual approval and promotion to _Prod_ environment after the _Component Test_ stage in the pipeline: 80 | 81 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 82 | 83 | [source,shell] 84 | ---- 85 | stage('Promote to Prod') { 86 | steps { 87 | timeout(time:15, unit:'MINUTES') { 88 | input message: "Approve Promotion to Prod?", ok: "Promote" 89 | } 90 | script { 91 | openshift.withCluster() { 92 | openshift.tag("dev-{{PROJECT_SUFFIX}}/cart:latest", "prod-{{PROJECT_SUFFIX}}/cart:prod") 93 | } 94 | } 95 | } 96 | } 97 | ---- 98 | 99 | Note that the manual approval process is usually integrated into the existing IT workflow management systems such as ServiceNow, JIRA Service Desk, BMC Remedy, etc so that authorized roles can approve the deployments to Prod environment from their own dashboards. In this lab, you will use Jenkins UI directly for approving the image promotion. 100 | 101 | Push the modified `Jenkinsfile` to the Git repository and enter your Git username and password if asked: 102 | 103 | * Username: `{{GIT_USER}}` 104 | * Password: `{{GIT_PASSWORD}}` 105 | 106 | [source,shell] 107 | ---- 108 | $ cd ~/cart-service 109 | $ git add Jenkinsfile 110 | $ git commit -m "Added image promotion to the pipeline" 111 | $ git push origin master 112 | ---- 113 | 114 | The Cart pipeline now spans over multiple projects and performs actions in both Dev and Prod environments. When a person performs an action in OpenShift such as creating a build or deploying a container, they have to first authenticate to OpenShift using their credentials. However, when an application or container e.g. Jenkins server wants to perform actions on OpenShift, there are no regular user credentials to be used for authentication. `Service Accounts` in OpenShift provide a flexible way to control access without sharing a regular user’s credentials in those scenarios. Every container requires a service account to run on OpenShift and unless specified otherwise by default they run with the project-scoped `default` service account which is created and assigned automatically to each container when they get deployed. 115 | 116 | Although most containers use the `default` service account in their projects, the Jenkins template used to deploy Jenkins server creates and uses a service account with the name `jenkins` (instead of `default`) to simplify controlling Jenkins server access to resources without impacting the permissions of other containers. 117 | 118 | Just like regular accounts, every service account has a name which follows a specific format: `system:serviceaccount::`. `` is the project name in which the service account is created and `` is the name of the service account. Given the above, the name of the service account used to run the Jenkins container is `system:serviceaccount:dev-{{PROJECT_SUFFIX}}:jenkins`. 119 | 120 | The very same way that roles are assigned to regular user accounts, they can be assigned to service accounts to authorize an application or a container to give them access to other projects. Since the Jenkins server now tags an image in the Prod environment, you should give permissions to the Jenkins service account to perform that action. 121 | 122 | Use the OpenShift CLI to assign the _Dev_ project’s Jenkins service account the `edit` role in the Prod project: 123 | 124 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 125 | 126 | [source,shell] 127 | ---- 128 | $ oc policy add-role-to-user edit system:serviceaccount:dev-{{PROJECT_SUFFIX}}:jenkins -n prod-{{PROJECT_SUFFIX}} 129 | ---- 130 | 131 | Alternatively you can use the OpenShift Web Console by clicking on *Resources -> Membership* on the left sidebar menu in the _Prod_ project. Click on *Service Accounts* tab and then on *Edit Membership*. Fill the text fields and then click on *Add* and then *Done Editing*. 132 | 133 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 134 | 135 | * Name: `jenkins` 136 | * Project: `dev-{{PROJECT_SUFFIX}}` 137 | * Role: `edit` 138 | 139 | image::devops-promotion-membership.png[Project Access Control] 140 | 141 | You are all set to run the new pipeline. In the _Dev_ project, click on *Builds -> Pipelines* on the left sidebar menu and then click on *Start Pipeline* button on the right side of *cart-pipeline-git*. A new instance of the *cart-pipeline-git* starts running using the updated `Jenkinsfile` in the Git repository. 142 | 143 | #### Manual Approval 144 | 145 | The pipeline builds and deploys the Cart service in the Dev project and then pauses at the manual approval stage to allow controlling the deployment flow into the _Prod_ environment. 146 | 147 | image::devops-promotion-pipeline-manual.png[Manual Approval in CI/CD Pipeline] 148 | 149 | Since use of ServiceNow or other IT Workflow systems is out of the scope of this lab, you will Jenkins to approve the production deployment. Click on *Input Required* which takes you to the Jenkins login page which is integrated with OpenShift OAuth authorization server. Login with your OpenShift credentials. 150 | 151 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 152 | 153 | * Username: `{{OPENSHIFT_USER}}` 154 | * Password: `{{OPENSHIFT_PASSWORD}}` 155 | 156 | image::devops-promotion-pipeline-approve.png[Approve Promotion to Production] 157 | 158 | Click on *Promote* to approve promoting the Cart container image from Dev environment to production environment. 159 | 160 | Upon approval, the pipeline continues and promotes the Cart container image from the _Dev_ environment to the _Prod_ environment and deploys it in the _Prod_ environment. 161 | 162 | image::devops-promotion-pipeline-complete.png[Application Promotion in CI/CD Pipeline] 163 | 164 | Congratulations! You have now an end-to-end pipeline that tests, builds and deploys every change that successfully finishes the pipeline into the Prod environment after being approved by the release manager. 165 | -------------------------------------------------------------------------------- /devops-simple-pipeline.adoc: -------------------------------------------------------------------------------- 1 | ## Creating a Simple CI/CD Pipeline 2 | 3 | In this lab you will learn about OpenShift pipelines and create your first pipeline on the platform. 4 | 5 | #### Background 6 | 7 | OpenShift has built-in support for CI/CD pipelines by allowing developers to define a https://jenkins.io/solutions/pipeline/[Jenkins pipeline] for execution by Jenkins automation engine. The build can be started, monitored, and managed by OpenShift in the same way as any other build types e.g. S2I. 8 | Pipeline workflows are defined in a Jenkinsfile, either embedded directly in the build configuration, or supplied in a Git repository and referenced by the build configuration. In this lab, you will create a pipeline using the embedded scenario. 9 | 10 | The first time a project defines a build configuration using a pipeline strategy, OpenShift instantiates a Jenkins server to execute the pipeline. This Jenkins server is based on a {{OPENSHIFT_DOCS_BASE}}/using_images/other_images/jenkins.html[certified Jenkins container image] which is provided by OpenShift and has the necessary plug-ins pre-configured. Subsequent pipeline configurations in the project share this Jenkins server. Furthermore, if user has already created a Jenkins server, the same Jenkins server is used for executing the pipelines. 11 | 12 | Note that OpenShift can also use a Jenkins engine running outside the OpenShift platform (e.g. on a separate VM or on AWS EC2) for executing the pipelines. For further details refer to the {{OPENSHIFT_DOCS_BASE}}/using_images/other_images/jenkins.html[OpenShift Pipeline Jenkins Plugin] docs. 13 | 14 | Jenkinsfile is a text file that contains the definition of a Jenkins Pipeline and is created using a https://jenkins.io/doc/book/pipeline/syntax/[scripted or declarative syntax] in Groovy language. Although an understanding of Groovy is helpful for building pipelines, it is not a requirement in order to work with Pipeline. The following shows a basic pipeline using the Jenkinsfile declarative syntax which takes the code from the Git repository, builds the code and then runs the integration tests against it: 15 | 16 | image::devops-simple-pipeline-diagram.png[Simple CI/CD Pipeline] 17 | 18 | [source,shell] 19 | ---- 20 | pipeline { 21 | agent { 22 | label 'maven' 23 | } 24 | stages { 25 | stage('Build') { 26 | steps { 27 | git url: 'http://{{GIT_SERVER_URL}}/{{GIT_USER}}/cart-service.git' 28 | sh 'mvn package' 29 | } 30 | } 31 | stage('Test') { 32 | steps { 33 | sh 'mvn verify' 34 | } 35 | } 36 | } 37 | } 38 | ---- 39 | 40 | Running builds, especially large builds, frequently requires a lot of resources and quite soon surpass the available resources on the Jenkins server. Jenkins supports a master-slave architecture in order to be able to scale and run many builds and pipelines simultaneously. A slave is a Jenkins worker instance that is configured to offload build jobs (e.g. pipeline execution) from the master. In a master-slave setup, a number of slave instances are configured for the Jenkins master and the master distributes running builds between the slaves instances based on the build tools and others configurations available on each slave instance. 41 | 42 | The Jenkins certified image on OpenShift is pre-configured to {{OPENSHIFT_DOCS_BASE}}/using_images/other_images/jenkins.html#using-the-jenkins-kubernetes-plug-in-to-run-jobs[dynamically create Jenkins slave containers] when running OpenShift pipelines. The `agent { labe 'maven' }` statement instructs Jenkins to dynamically deploy a Jenkins slave container which is configured for running Apache Maven builds and execute the pipeline on that container. Dynamic provisioning of the Jenkins slave containers allows running many builds in parallel on OpenShift without overloading the Jenkins master. 43 | 44 | Although one can use OpenShift CLI in the pipeline definition to interact with OpenShift, OpenShift Pipelines also provide a set of easy to use building blocks via the https://github.com/openshift/jenkins-client-plugin[OpenShift DSL Jenkins Plugin] which simplify performing actions against OpenShift deployments. You will use this plugin in the next section. 45 | 46 | #### Creating an OpenShift Pipeline 47 | 48 | Now let’s create an OpenShift Pipeline that builds and deploys the Cart service that was deployed in the _Dev_ project in the previous lab. This pipeline has three stages: _Build_, _Deploy_ and _Test_. The _Build_ stage triggers the Cart service S2I build in order to get the latest version of the source code from the source repository and build a docker container image form it. The _Deploy_ stage deploys the built container image to a container and the Test stage runs a smoke test to make sure the Cart service is up and running. 49 | 50 | image::devops-simple-pipeline-diagram-s2i.png[Simple CI/CD Pipeline with S2I] 51 | 52 | The following is a OpenShift Pipeline in YAML format which has a Jenkinsfile script embedded in it. 53 | 54 | [source,shell] 55 | ---- 56 | apiVersion: v1 57 | kind: BuildConfig 58 | metadata: 59 | name: cart-pipeline 60 | spec: 61 | strategy: 62 | jenkinsPipelineStrategy: 63 | jenkinsfile: |- 64 | pipeline { 65 | agent any 66 | stages { 67 | stage('Build') { 68 | steps { 69 | script { 70 | openshift.withCluster() { 71 | openshift.withProject() { 72 | openshift.startBuild("cart").logs('-f') 73 | } 74 | } 75 | } 76 | } 77 | } 78 | stage('Deploy') { 79 | steps { 80 | script { 81 | openshift.withCluster() { 82 | openshift.withProject() { 83 | dc = openshift.selector("dc", "cart") 84 | dc.rollout().latest() 85 | timeout(10) { 86 | dc.rollout().status("-w") 87 | } 88 | } 89 | } 90 | } 91 | } 92 | } 93 | stage('Test') { 94 | steps { 95 | sh "curl -s -X POST http://cart:8080/api/cart/dummy/666/1" 96 | sh "curl -s http://cart:8080/api/cart/dummy | grep 'Dummy Product'" 97 | } 98 | } 99 | } 100 | } 101 | type: JenkinsPipeline 102 | ---- 103 | 104 | Notice the URL for referring to the Cart service in the _Dev_ environment. {{OPENSHIFT_DOCS_BASE}}/architecture/additional_concepts/networking.html[OpenShift has a built-in DNS] so that the services can be reached by the service DNS, regardless of the external URL. This simplifies referring to services since the service DNS in an environment does not change. The URL pattern for services is `..svc`. 105 | 106 | Click on *Add to project* in the _Dev_ project and then *Import YAML/JSON*. Paste the above YAML script in the text field and then click on *Create*. 107 | 108 | Click on *Overview* in the OpenShift Web Console, and see that a Jenkins server container is being deployed in the _Dev_ project. 109 | 110 | image::devops-simple-pipeline-jenkins-autoprovision.png[Jenkins Auto-provisioning] 111 | 112 | When you deployed Cart service, the deployment is configured to automatically initiate a new deployment everytime a new version of the Cart container image is available. When using pipelines, you might want the pipeline to control when a deployment should happen independent of whether an updated Cart container image is available. In order to do that, you can change the automatic deployment to manual on the Cart deploymentconfig using OpenShift CLI: 113 | 114 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 115 | 116 | [source,shell] 117 | ---- 118 | $ oc project dev-{{PROJECT_SUFFIX}} 119 | $ oc set triggers dc cart --manual 120 | ---- 121 | 122 | All set. Let’s give the Cart pipeline a try! Click on *Builds -> Pipelines* on the left sidebar menu and then click on *Start Pipeline* button on the right side of *cart-pipeline*. A new instance of the pipeline starts running. 123 | 124 | image::devops-simple-pipeline-started.png[OpenShift Pipeline] 125 | 126 | Click on *View Log* to see the pipeline logs as it’s being executed. The link takes you to the Jenkins Pipeline Job that is created and managed by OpenShift for executing this pipeline. Since the security certificates used for securing your Jenkins server are self-generated and self-signed, your browser will not trust them by default and will show a security warning. In Chrome browser, click on *ADVANCED* and then *Proceed to ... (unsafe)* to trust the certificates. In Firefox browser, click on *Advanced* button, then *Add Exception...* and then confirm trusting the certificate by click on *Confirm Security Exception*. 127 | 128 | Although Jenkins can use its own authorization, the Jenkins images in OpenShift is configured by default to integrate with and use OpenShift OAuth authentication. Log in into Jenkins using your OpenShift credentials: 129 | 130 | * User: `{{OPENSHIFT_USER}}` 131 | * Password: `{{OPENSHIFT_PASSWORD}}` 132 | 133 | After login, you will be redirected to the pipeline job logs. After a little while, the Cart pipeline completes successfully, all green. 134 | 135 | image::devops-simple-pipeline-complete.png[OpenShift Pipeline] 136 | 137 | Congratulations! You just created and ran your first CI/CD pipeline. Welcome to the world of DevOps! 138 | -------------------------------------------------------------------------------- /devops-webhook.adoc: -------------------------------------------------------------------------------- 1 | ## Running the CI/CD Pipeline on Every Change 2 | 3 | In this lab you will learn about webhooks and how to automatically run the changes through the pipeline everytime there is a change in the application source repository. 4 | 5 | #### Background 6 | 7 | Manually starting the CI/CD pipeline does not really scale when there are more than a single developer working with the code repository. Continuous Delivery needs to ensure that every change (code or configuration) to the application is releasable and requires every change to go through the pipeline and verify if it can be release into production. 8 | 9 | Since manually click on *Start Pipeline* every time someone commits code or configuration to the Git repository is not possible across an entire development team, you can use Git Webhooks mechanism to trigger the pipeline (and any other builds in OpenShift) automatically every time there is a change in the Cart service Git repository. 10 | 11 | image::devops-webhook-diagram.png[Git Webhook] 12 | 13 | #### Adding a Webhook 14 | 15 | In the _Dev_ project, click on *Builds -> Pipelines* on the left sidebar menu and then on *cart-pipeline-git*. You can see the history of pipeline runs and how long the took to run. Click on *Configuration* tab where you can see the pipeline configuration such as which Git repository it uses to pull the Jenkinsfile, etc. Copy the *Generic Webhook URL* to the clipboard by clicking on the copy icon next to the URL. This is the webhook URL that the Git repository should invoke on every change in order to trigger the pipeline. 16 | 17 | Go to Gogs web by pointing your browser at Gogs URL and login using your credentials: 18 | 19 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 20 | 21 | * Gogs URL: `http://{{GIT_SERVER_URL}}` 22 | * Username: `{{GIT_USER}}` 23 | * Password: `{{GIT_PASSWORD}}` 24 | 25 | Click on *cart-service* under *My Repositories* to go to the repository overview. Click on *Settings* and then *Webhooks*. Currently no webhooks are defined on _cart-service_ repository. Click on *Add Webhook* and choose *Gogs*. Paste the pipeline webhook URL you copied in previous steps into the *Payload URL* text field and click on *Add Webhook*. 26 | 27 | image::devops-webhook-gogs-add.png[Add Webhook] 28 | 29 | Now for every push to the *cart-service* Git repository, Gogs would make a REST call to OpenShift APIs at the given URL to trigger the pipeline. You can verify that the webhook works correctly by clicking on the webhook you just created from the list of webhooks and then on the *Test Delivery* button. 30 | -------------------------------------------------------------------------------- /devops-zerodowntime-automated.adoc: -------------------------------------------------------------------------------- 1 | ## Automated Zero-Downtime Deployment with CI/CD Pipelines 2 | 3 | In this lab you will get learn how to automate deployments into production without the need for a service window and down time. 4 | 5 | #### Background 6 | 7 | In the previous labs you deployed and tested a code change directly in production without requiring downtime or a service window. Zero downtime deployments is an invaluable capability when building CI/CD pipelines in order to allow more frequent deployments in production without the need to go through cumbersome and bureaucratic processes for getting a change into production. 8 | 9 | The manual blue/green deployment you followed in previous lab, is fun but not scalable for larger teams with many code commits per day. In this lab, you will automate blue/green deployment by integrating it into the Cart CI/CD pipeline. In that case, every time a change is committed to the code repository, the CI/CD pipeline would takes the code, build it and if successful in the Dev environment, promotes it into the inactive Cart container (the container that does NOT receive any production traffic) in the Prod environment. If the tests are successful in the Prod environment and after the release manager manually approves the Prod deployment, the CI/CD pipeline makes the new version live by switching the router and sending all traffic to the newly deployed container. 10 | 11 | image::devops-zerodowntime-bluegreen-pipeline.png[Blue-Green in CI/CD Pipeline] 12 | 13 | #### Blue-Green Deployment via CD/CD Pipeline 14 | 15 | Open the Jenkinsfile you added to the pipelines Git repository in a text editor and replace its content with the following: 16 | 17 | [source,shell] 18 | ---- 19 | def tag,altTag 20 | 21 | pipeline { 22 | agent { 23 | label 'maven' 24 | } 25 | stages { 26 | stage('Build App') { 27 | steps { 28 | sh "mvn clean package -s src/main/config/settings.xml" 29 | } 30 | } 31 | stage('Integration Test') { 32 | steps { 33 | sh "mvn verify -s src/main/config/settings.xml" 34 | } 35 | } 36 | stage('Build Image') { 37 | steps { 38 | script { 39 | openshift.withCluster() { 40 | openshift.withProject() { 41 | openshift.startBuild("cart", "--from-file=target/cart.jar").logs("-f") 42 | } 43 | } 44 | } 45 | } 46 | } 47 | stage('Deploy') { 48 | steps { 49 | script { 50 | openshift.withCluster() { 51 | openshift.withProject() { 52 | dc = openshift.selector("dc", "cart") 53 | dc.rollout().latest() 54 | timeout(10) { 55 | dc.rollout().status() 56 | } 57 | } 58 | } 59 | } 60 | } 61 | } 62 | stage('Component Test') { 63 | steps { 64 | script { 65 | sh "curl -s -X POST http://cart:8080/api/cart/dummy/666/1" 66 | sh "curl -s http://cart:8080/api/cart/dummy | grep 'Dummy Product'" 67 | } 68 | } 69 | } 70 | stage('Promote') { 71 | steps { 72 | script { 73 | openshift.withCluster() { 74 | openshift.withProject("prod-{{PROJECT_SUFFIX}}") { 75 | def route = openshift.selector("route", "cart").object() 76 | def backends = [] 77 | backends.add(route.spec.to) 78 | backends.addAll(route.spec.alternateBackends) 79 | def svc = backends.find {it.weight == 100} 80 | tag = svc.name == "cart-green" ? "blue" : "green" 81 | altTag = svc.name == "cart-green" ? "green" : "blue" 82 | 83 | openshift.tag("dev-{{PROJECT_SUFFIX}}/cart:latest", "prod-{{PROJECT_SUFFIX}}/cart:prod-${tag}") 84 | openshift.selector("dc", "cart-${tag}").rollout().status() 85 | } 86 | } 87 | } 88 | } 89 | } 90 | 91 | stage('End-To-End Test') { 92 | steps { 93 | script { 94 | sh "curl -s -X POST http://cart-${tag}.prod-{{PROJECT_SUFFIX}}.svc:8080/api/cart/dummy/444434/1" 95 | sh "curl -s http://cart-${tag}.prod-{{PROJECT_SUFFIX}}.svc:8080/api/cart/dummy | grep 'Pebble Smart Watch'" 96 | } 97 | } 98 | } 99 | 100 | stage('Approve Go Live') { 101 | steps { 102 | timeout(time:15, unit:'MINUTES') { 103 | input message: "Approve Promotion to Prod?", ok: "Promote" 104 | } 105 | script { 106 | openshift.withCluster() { 107 | openshift.withProject("prod-{{PROJECT_SUFFIX}}") { 108 | openshift.set("route-backends", "cart" , "cart-${tag}=100", "cart-${altTag}=0") 109 | } 110 | } 111 | } 112 | } 113 | } 114 | } 115 | } 116 | ---- 117 | 118 | The above pipeline makes the following changes compared to the previous lab: 119 | 120 | * _Promote_ stage is made aware of blue/green deployments 121 | * _Approve_ stage is postponed till all tests are complete in the Prod environment 122 | * _Go Live_ stage flips the router to send traffic to the new deployment 123 | 124 | Notice that in the Promote stage, the pipeline retrieves the Cart route to check which version (blue or green) is receiving production flow and promotes the new Cart docker image to the inactive image which does not receive any product traffic. The Pipeline DSL is a Groovy syntax which is powerful for creating complex scenarios and enables dynamic decision making during pipeline execution similar to above. 125 | 126 | Save the Jenkinsfile and push it to the Git repository and enter your credentials: 127 | 128 | * Username: `{{GIT_USER}}` 129 | * Password: `{{GIT_PASSWORD}}` 130 | 131 | [source,shell] 132 | ---- 133 | $ cd ~/pipelines 134 | $ git add Jenkinsfile 135 | $ git commit -m "Added blue-green deployment to the pipeline" 136 | $ git push origin master 137 | ---- 138 | 139 | The purchase reports from CoolStore online shop show that reducing the minimum order to 40$ has had minimal effects on conversion rate which seem to be attributed to increased competition online. Pricing department has requested to reduce the minimum order to 20$ and evaluate the conversion rate after a week. Let’s push this change to production via the automated blue/green deployment in the pipeline. 140 | 141 | Point your browser to the Git server web URL: 142 | 143 | * Git Server URL: `http://{{GIT_SERVER_URL}}` 144 | * Username: `{{GIT_USER}}` 145 | * Password: `{{GIT_PASSWORD}}` 146 | 147 | In the *cart-service* repository, browse to the promotion service at `src/main/java/com/redhat/coolstore/service/PromoService.java`, click on the pencil icon to open `PromoService.java` in the web editor and set the minimum order to 20$. The `PromoService.java` should look like this after the edit: 148 | 149 | [source,java] 150 | ---- 151 | //PROMO: if cart total is greater than 20, free shipping 152 | if ( shoppingCart.getCartItemTotal() >= 20) { 153 | ... 154 | } 155 | ---- 156 | 157 | Click on *Commit Changes* button to commit the new shipping promotion rule to the Git repository. Go back to OpenShift Web Console and in the _Dev_ project, click on *Builds -> Pipelines* on the left sidebar menu and wait until pipeline pauses at the *Approve Go Live* stage. 158 | 159 | 160 | image::devops-zerodowntime-bg-approve.png[Approve Go Live in Deployment Pipeline] 161 | 162 | At this stage, a new version of the Cart service is deployed in the Prod environment as Cart Blue which does not receive any production traffic yet. Note that if you have executed the Cart CI/CD pipeline multiple times, Cart Green might be the inactive deployment in your environment. 163 | 164 | After deployment is ready, verify that the new minimum order for free shipping is working correctly in the inactive container by adding 1 smartwatch to the test shopping cart : 165 | 166 | CAUTION: Replace the Cart route with routes in your project 167 | 168 | [source,shell] 169 | ---- 170 | $ curl -X POST http://{{CART_BLUE_ROUTE}}/api/cart/FOO/444434/1 171 | {"cartItemTotal":24.0,"cartItemPromoSavings":0.0,"shippingTotal":0.0,"shippingPromoSavings":-2.99,"cartTotal":24.0,"shoppingCartItemList":[{"price":24.0,"quantity":1,"promoSavings":0.0,"product":{"itemId":"444434","name":"Pebble Smart Watch","desc":"Smart glasses and smart watches are perhaps two of the most exciting developments in recent years. ","price":24.0}}]} 172 | ---- 173 | 174 | Notice that the shipping cost is zero since the total order is above the 20$ minimum order. Click on the Web UI route URL and add a Pebble Smart Watch to your shopping cart. As expected, the shipping cost is not zero. 175 | 176 | Now that the new minimum order rule is verified in the new version of Cart service in the Prod environment, you can approve the *Go Live*. Go back to *Builds -> Pipelines* and click on *Input Required* and then *Promote* to approve the Go Live. Add a Pebble Smart Watch to your shopping cart again and verify that shipping is now free in the live version. 177 | 178 | image::devops-zerodowntime-bg-approved.png[Deployment Pipeline Complete] -------------------------------------------------------------------------------- /devops-zerodowntime-manual.adoc: -------------------------------------------------------------------------------- 1 | ## Zero-Downtime Deployment to Production 2 | 3 | In this lab you will get familiar with production deployments without requiring any downtime or service windows. 4 | 5 | #### Background 6 | 7 | Although you have automated the build and deployment of the Cart service all the way from development to production, every time the pipeline performs the deployment in production the service is unavailable for the period it takes for the Cart container to start up. This might be acceptable for certain services however an unavailable service for an online shop equalis lost orders and revenue specially during shopping seasons like Christmas. 8 | 9 | Zero downtime deployments refers to a number of deployment pattern that allow deploying to production environment during work hours without a need for service windows and without causing any disruption for the live services. Blue-Green and Canary Release are two popular patterns that are often used to achieve zero downtime deployments. 10 | 11 | Canary Release refers to deploying a new version of your app into production parallel to the live version and redirectly only a fraction of production traffic to the new version. After verifying that the canary deployment works correctly, incremental more production traffic is switched to the canary version until it serves 100% of the production traffic. Canary Release allows you to test the application directly in the production with subset of users so that in case of failure, only a small user set will be affected. 12 | 13 | In Blue-Green deployment approach you also have two parallel production environments but at any point in time only one of them is active and receives the production traffic, for example the blue one. When you deploy the new version of the application in production, you deploy into the inactive environment, green in this example, and after ensuring that the new version works correctly in production you switch the router so that all incoming production traffic goes to the green environment, making the blue one idle. 14 | 15 | Blue-green deployment also enables you to be able to quickly rollback to the previous version. if anything goes wrong with the new version after the switch, you can switch back the router the blue version. You still need to manage transactions and database changes when deploying new versions of your application however there are other patterns to specifically deal with those issues separately for example depending on your environment and application design, you might be able to feed transactions to both environments so that the blue environment acts as a backup or run the application in read-only mode before doing a switch. 16 | 17 | image::devops-zerodowntime-bluegreen-diagram.png[Blue-Green Deployment] 18 | 19 | #### Blue-Green Deployment 20 | 21 | In this lab, you will perform a Blue-Green deployment to push a code change into production without requiring any downtime. 22 | For a Blue-Green deployments, you need two production environments running in parallel. Since the CI/CD pipeline in this lab builds and deploys the Cart service, instead of two _Prod_ environment for the entire CoolStore application, you can run two parallel containers for the Cart service: Cart Blue and Cart Green. 23 | 24 | image::devops-zerodowntime-coolstore-arch.png[Blue-Green Deployment - CoolStore] 25 | 26 | 27 | Start with tagging the `cart:prod image` into a blue and green version so that we can update one without affecting the other one and the deployed container that is based on that: 28 | 29 | CAUTION: Replace `{{PROJECT_SUFFIX}}` with the number provided to you by the instructor. 30 | 31 | [source,shell] 32 | ---- 33 | $ oc project prod-{{PROJECT_SUFFIX}} 34 | $ oc tag cart:prod cart:prod-blue 35 | $ oc tag cart:prod cart:prod-green 36 | ---- 37 | 38 | You need to create two deployment configs as well, one based on the `cart:prod-blue` and another based on `cart:prod-green` image. Also two services that send traffic to the containers deployed by each of the Blue and Green deployment configs. These services and deployment configs are identical to the currently deployed cart service however use the newly tagged images instead. The Cart route will then point to the Cart Blue or Cart Green service in order to send the production traffic to the appointed container. 39 | 40 | image::devops-zerodowntime-coolstore-bluegreen.png[Blue-Green Deployment - CoolStore] 41 | 42 | In order to create the blue and green Cart service and deployment configs, we can export the current Cart service and deployment configs as YAML or JSON, modify them and then deploy the modified definitions. Use the `oc export` CLI command to export the Cart service and deploymentconfig: 43 | 44 | [source,shell] 45 | ---- 46 | $ oc get svc/cart dc/cart -o yaml --export > ~/cart-blue.yaml 47 | ---- 48 | 49 | Open the `cart-blue.yaml` file in a text editor and replace all occurrences of `cart` with `cart-blue`. After replacement, make sure the referenced image tag is `cart:prod-blue` which you created in the previous steps: 50 | 51 | [source,shell] 52 | ---- 53 | - imageChangeParams: 54 | automatic: true 55 | containerNames: 56 | - cart-blue 57 | from: 58 | kind: ImageStreamTag 59 | name: cart:prod-blue 60 | namespace: prod-{{PROJECT_SUFFIX}} 61 | type: ImageChange 62 | ---- 63 | 64 | Alternatively if you are a bash aficionados, use the `sed` command for the replacement: 65 | 66 | 67 | **Linux** 68 | 69 | [source,shell] 70 | ---- 71 | $ sed -i "s/cart$/cart-blue/g;s/cart:prod/cart:prod-blue/g" ~/cart-blue.yaml 72 | ---- 73 | 74 | **Mac** 75 | 76 | [source,shell] 77 | ---- 78 | $ sed -i .bak "s/cart$/cart-blue/g;s/cart:prod/cart:prod-blue/g" ~/cart-blue.yaml 79 | ---- 80 | 81 | 82 | The Cart blue service and deployment config definition is ready. You can create the Cart green service and deployment config definitions by duplicating `~/cart-blue.yaml` to `~/cart-green.yaml` and replacing all occurrences of `blue` with `green`: 83 | 84 | [source,shell] 85 | ---- 86 | $ sed "s/blue/green/g" ~/cart-blue.yaml > ~/cart-green.yaml 87 | ---- 88 | 89 | You are all set to create the blue and green services and deployment configs for the Cart service: 90 | 91 | [source,shell] 92 | ---- 93 | $ oc create -f ~/cart-blue.yaml 94 | $ oc create -f ~/cart-green.yaml 95 | ---- 96 | 97 | Now that the Cart Blue and Cart Green deployment and services are defined, you can deploy those containers in the the Prod environment. Click on *Applications -> Deployments* and then on *cart-blue*. Deploy the Cart Blue service by clicking on the *Deploy* button. Go back to the list of deployments and click on *cart-green*, and then *Deploy* button to also deploy the Cart Green service. 98 | 99 | The Cart Blue and Green containers will be deployed alongside the previous Cart container. 100 | 101 | image::devops-zerodowntime-cart-bluegreen.png[Cart Blue Service and Cart Green Service] 102 | 103 | You created the Cart blue and green services but the route is still pointing to the old container instead of either blue or the green container. 104 | Click on *Applications -> Routes* on the left sidebar menu and then click on *cart* route. Notice that it is currently pointing at the cart service. Click on *Actions* → *Edit* from the top-right menu. You can create a blue/green route by clicking on *Split traffic across multiple services* and adding `cart-blue` and `cart-green` services with 100 and 0 weight respectively to send all traffic to the cart-blue service and then click on *Save*. You can {{OPENSHIFT_DOCS_BASE}}/dev_guide/routes.html#routes-load-balancing-for-AB-testing[split the traffic] coming to a route across multiple backend services via weighting however in this lab you only need the `cart-blue` and `cart-green` services. 105 | 106 | image::devops-zerodowntime-edit-route.png[Edit Route] 107 | 108 | Split routes in OpenShift enables other deployment patterns such as Canary Release and A/B testing as well by specifying other weight ratios on the services for example: 109 | 110 | * 10/90: to send 10% of production traffic to the new container for Canary Release 111 | * 50/50: to send 50% of traffic to the new container for A/B Testing 112 | 113 | image::devops-zerodowntime-bg-routes.png[Route Traffic Split] 114 | 115 | image::devops-zerodowntime-blue-live.png[Route Traffic Split] 116 | 117 | The blue/green deployment setup is complete now. Clean up the Prod environment by removing the Cart service and deploymentconfig since you will be using the green and blue versions instead. 118 | 119 | [source,shell] 120 | ---- 121 | $ oc delete svc/cart dc/cart 122 | ---- 123 | 124 | You can also expose the `cart-blue` and `cart-green` services as their own dedicated routes in order to facilitate testing even though these routes won’t be used by the CoolStore application. 125 | 126 | [source,shell] 127 | ---- 128 | $ oc expose svc/cart-blue 129 | $ oc expose svc/cart-green 130 | $ oc get routes 131 | ---- 132 | 133 | Verify the routes are working using the `curl` command: 134 | 135 | CAUTION: Replace the urls with routes in your project 136 | 137 | [source,shell] 138 | ---- 139 | $ curl http://{{CART_ROUTE}}/api/cart/dummy 140 | $ curl http://{{CART_BLUE_ROUTE}}/api/cart/dummy 141 | $ curl http://{{CART_GREEN_ROUTE}}/api/cart/dummy 142 | ---- 143 | 144 | Showtime! Let’s perform your first blue/green deployment. Point your browser to Git server web URL and log in (you should be already logged in by now!) with your credentials: 145 | 146 | * Git server: `http://{{GIT_SERVER_URL}}` 147 | * Username: `{{GIT_USER}}` 148 | * Password: `{{GIT_PASSWORD}}` 149 | 150 | Click on *cart-service* under *My Repositories* to go to the repository overview. Browse to the promotion service at `src/main/java/com/redhat/coolstore/service/PromoService.java` which is responsible for calculating order promotions depending on the total amount of products a customer has added to their shopping cart. 151 | 152 | [source,java] 153 | ---- 154 | public void applyShippingPromotions(ShoppingCart shoppingCart) { 155 | if ( shoppingCart != null ) { 156 | //PROMO: if cart total is greater than 75, free shipping 157 | if ( shoppingCart.getCartItemTotal() >= 75) { 158 | shoppingCart.setShippingPromoSavings(shoppingCart.getShippingTotal() * -1); 159 | shoppingCart.setShippingTotal(0); 160 | } 161 | } 162 | } 163 | ---- 164 | 165 | Notice that the minimum order for free shipping is currently 75$. In order to match a competitor website, you want to change the promotion rules and reduce the minimum to 40$. Click on the pencil icon to open `PromoService.java` in the web-based editor. 166 | 167 | image::devops-zerodowntime-gogs-editor.png[Gogs Web Editort] 168 | 169 | Change the minium order to 40$. The `PromoService.java` should look like this after the edit: 170 | 171 | [source,java] 172 | ---- 173 | //PROMO: if cart total is greater than 40, free shipping 174 | if ( shoppingCart.getCartItemTotal() >= 40) { 175 | ... 176 | } 177 | ---- 178 | 179 | Click on *Commit Changes* button to commit the new shipping promotion rule to the Git repository. As soon as the change is committed to the Git repository, the Cart CI/CD pipeline gets automatically triggered via the webhook you defined in the previous lab and starts building the change and pushing it through Dev and Prod environments. Click on *Builds -> Pipelines* on the left sidebar menu and wait until pipeline pauses at the _Approve_ stage. The Cart pipeline promotes the Cart container image to the Prod environment by tagging it as `cart:prod`. However you have changed the production topology in Prod environment to blue/green deployment and therefore the application promotion process also needs adapt the new topology which you will do in the next lab. 180 | 181 | In this lab, you can manually promote the image to Prod environment instead of the automatic promotion via the CI/CD pipeline. Click on *Input Required* and then click on *No* button to reject the deployment. Use `oc tag` CLI command to promote the newly built Cart container image to the green Cart deployment which is currently inactive and does not receive any production traffic. 182 | 183 | [source,shell] 184 | ---- 185 | $ oc tag dev-{{PROJECT_SUFFIX}}/cart:latest prod-{{PROJECT_SUFFIX}}/cart:prod-green 186 | ---- 187 | 188 | Go to CoolStore Prod project in OpenShift Web Console and notice a new deployment is taking place: 189 | 190 | image::devops-zerodowntime-green-deploy.png[Cart Green Deployment] 191 | 192 | After deployment is ready, verify that the new minimum order for free shipping is working correctly in the green container by adding 2 smart watches to the test shopping cart: 193 | 194 | CAUTION: Replace the Cart route with routes in your project 195 | 196 | [source,shell] 197 | ---- 198 | $ curl -X POST http://{{CART_GREEN_ROUTE}}/api/cart/FOO/444434/2 199 | {"cartItemTotal":48.0,"cartItemPromoSavings":0.0,"shippingTotal":0.0,"shippingPromoSavings":-4.99,"cartTotal":52.99,"shoppingCartItemList":[{"price":24.0,"quantity":2,"promoSavings":0.0,"product":{"itemId":"444434","name":"Pebble Smart Watch","desc":"Smart glasses and smart watches are perhaps two of the most exciting developments in recent years. ","price":24.0}}]} 200 | ---- 201 | 202 | Notice that the shipping cost is zero since the total order is above the 40$ minimum order. However the change is still not live and invoking the production endpoints for the Cart service should still have the 75$ minimum order. Click on the Web UI route url and add 2 Pebble Smart Watches to your shopping cart. As expected, the shipping cost is not zero. 203 | 204 | image::devops-zerodowntime-shipping-costs.png[CoolStore Shopping Cart] 205 | 206 | Now that the new minimum order rule is verified in production, you can switch the router to send 100% of traffic to the Cart green service which includes the new promotion rules and 0% traffic to the Cart blue service. 207 | 208 | [source,shell] 209 | ---- 210 | $ oc set route-backends cart cart-green=100 cart-blue=0 211 | ---- 212 | 213 | image::devops-zerodowntime-green-live.png[Cart Green Live] 214 | 215 | Go back to CoolStore add 2 Pebble Smart Watches to your shopping cart and then go to the shopping cart. Happy Shopping! Shipping is free now for this order. 216 | 217 | image::devops-zerodowntime-shipping-free.png[CoolStore Shopping Cart] 218 | 219 | When using blue/green deployments, rolling back to a previous version is as simple as changing the traffic weights to send 100% of traffic to the previous version (blue service in this case) and 0% to the new version (green service in this case). 220 | -------------------------------------------------------------------------------- /images/devops-envs-cart-build-logs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-envs-cart-build-logs.png -------------------------------------------------------------------------------- /images/devops-envs-cart-build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-envs-cart-build.png -------------------------------------------------------------------------------- /images/devops-envs-cart-deployed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-envs-cart-deployed.png -------------------------------------------------------------------------------- /images/devops-envs-cart-healthchecks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-envs-cart-healthchecks.png -------------------------------------------------------------------------------- /images/devops-envs-cart-newapp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-envs-cart-newapp.png -------------------------------------------------------------------------------- /images/devops-envs-catalog-jdk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-envs-catalog-jdk.png -------------------------------------------------------------------------------- /images/devops-envs-create-dev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-envs-create-dev.png -------------------------------------------------------------------------------- /images/devops-envs-dev-membership.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-envs-dev-membership.png -------------------------------------------------------------------------------- /images/devops-envs-dev-project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-envs-dev-project.png -------------------------------------------------------------------------------- /images/devops-explore-cert-warning-chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-explore-cert-warning-chrome.png -------------------------------------------------------------------------------- /images/devops-explore-cert-warning-firefox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-explore-cert-warning-firefox.png -------------------------------------------------------------------------------- /images/devops-explore-che-stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-explore-che-stack.png -------------------------------------------------------------------------------- /images/devops-explore-che-terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-explore-che-terminal.png -------------------------------------------------------------------------------- /images/devops-explore-web-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-explore-web-login.png -------------------------------------------------------------------------------- /images/devops-explore-web-projects.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-explore-web-projects.png -------------------------------------------------------------------------------- /images/devops-intro-cd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-intro-cd.png -------------------------------------------------------------------------------- /images/devops-intro-coolstore-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-intro-coolstore-arch.png -------------------------------------------------------------------------------- /images/devops-intro-coolstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-intro-coolstore.png -------------------------------------------------------------------------------- /images/devops-intro-openshift-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-intro-openshift-arch.png -------------------------------------------------------------------------------- /images/devops-jenkins-catalog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-jenkins-catalog.png -------------------------------------------------------------------------------- /images/devops-jenkins-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-jenkins-login.png -------------------------------------------------------------------------------- /images/devops-jenkins-oauth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-jenkins-oauth.png -------------------------------------------------------------------------------- /images/devops-jenkins-templates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-jenkins-templates.png -------------------------------------------------------------------------------- /images/devops-pipeline-scm-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-pipeline-scm-diagram.png -------------------------------------------------------------------------------- /images/devops-pipeline-scm-started.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-pipeline-scm-started.png -------------------------------------------------------------------------------- /images/devops-promotion-build-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-promotion-build-template.png -------------------------------------------------------------------------------- /images/devops-promotion-builds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-promotion-builds.png -------------------------------------------------------------------------------- /images/devops-promotion-coolstore-deployed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-promotion-coolstore-deployed.png -------------------------------------------------------------------------------- /images/devops-promotion-coolstore-template-params.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-promotion-coolstore-template-params.png -------------------------------------------------------------------------------- /images/devops-promotion-coolstore-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-promotion-coolstore-template.png -------------------------------------------------------------------------------- /images/devops-promotion-membership.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-promotion-membership.png -------------------------------------------------------------------------------- /images/devops-promotion-pipeline-approve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-promotion-pipeline-approve.png -------------------------------------------------------------------------------- /images/devops-promotion-pipeline-complete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-promotion-pipeline-complete.png -------------------------------------------------------------------------------- /images/devops-promotion-pipeline-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-promotion-pipeline-diagram.png -------------------------------------------------------------------------------- /images/devops-promotion-pipeline-manual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-promotion-pipeline-manual.png -------------------------------------------------------------------------------- /images/devops-promotion-prod-project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-promotion-prod-project.png -------------------------------------------------------------------------------- /images/devops-promotion-projects.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-promotion-projects.png -------------------------------------------------------------------------------- /images/devops-promotion-select-from-project-templates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-promotion-select-from-project-templates.png -------------------------------------------------------------------------------- /images/devops-promotion-select-from-project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-promotion-select-from-project.png -------------------------------------------------------------------------------- /images/devops-simple-pipeline-complete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-simple-pipeline-complete.png -------------------------------------------------------------------------------- /images/devops-simple-pipeline-diagram-s2i.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-simple-pipeline-diagram-s2i.png -------------------------------------------------------------------------------- /images/devops-simple-pipeline-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-simple-pipeline-diagram.png -------------------------------------------------------------------------------- /images/devops-simple-pipeline-jenkins-autoprovision.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-simple-pipeline-jenkins-autoprovision.png -------------------------------------------------------------------------------- /images/devops-simple-pipeline-logs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-simple-pipeline-logs.png -------------------------------------------------------------------------------- /images/devops-simple-pipeline-started.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-simple-pipeline-started.png -------------------------------------------------------------------------------- /images/devops-slave-distributed-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-slave-distributed-arch.png -------------------------------------------------------------------------------- /images/devops-slave-gradle-pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-slave-gradle-pipeline.png -------------------------------------------------------------------------------- /images/devops-slave-job-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-slave-job-log.png -------------------------------------------------------------------------------- /images/devops-slave-pod-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-slave-pod-template.png -------------------------------------------------------------------------------- /images/devops-webhook-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-webhook-diagram.png -------------------------------------------------------------------------------- /images/devops-webhook-gogs-add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-webhook-gogs-add.png -------------------------------------------------------------------------------- /images/devops-zerodowntime-bg-approve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-zerodowntime-bg-approve.png -------------------------------------------------------------------------------- /images/devops-zerodowntime-bg-approved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-zerodowntime-bg-approved.png -------------------------------------------------------------------------------- /images/devops-zerodowntime-bg-routes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-zerodowntime-bg-routes.png -------------------------------------------------------------------------------- /images/devops-zerodowntime-blue-live.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-zerodowntime-blue-live.png -------------------------------------------------------------------------------- /images/devops-zerodowntime-bluegreen-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-zerodowntime-bluegreen-diagram.png -------------------------------------------------------------------------------- /images/devops-zerodowntime-bluegreen-pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-zerodowntime-bluegreen-pipeline.png -------------------------------------------------------------------------------- /images/devops-zerodowntime-cart-bluegreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-zerodowntime-cart-bluegreen.png -------------------------------------------------------------------------------- /images/devops-zerodowntime-coolstore-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-zerodowntime-coolstore-arch.png -------------------------------------------------------------------------------- /images/devops-zerodowntime-coolstore-bluegreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-zerodowntime-coolstore-bluegreen.png -------------------------------------------------------------------------------- /images/devops-zerodowntime-edit-route.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-zerodowntime-edit-route.png -------------------------------------------------------------------------------- /images/devops-zerodowntime-gogs-editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-zerodowntime-gogs-editor.png -------------------------------------------------------------------------------- /images/devops-zerodowntime-green-deploy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-zerodowntime-green-deploy.png -------------------------------------------------------------------------------- /images/devops-zerodowntime-green-live.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-zerodowntime-green-live.png -------------------------------------------------------------------------------- /images/devops-zerodowntime-shipping-costs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-zerodowntime-shipping-costs.png -------------------------------------------------------------------------------- /images/devops-zerodowntime-shipping-free.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/devops-zerodowntime-shipping-free.png -------------------------------------------------------------------------------- /images/install-catalog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/install-catalog.png -------------------------------------------------------------------------------- /images/install-git-users.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/install-git-users.png -------------------------------------------------------------------------------- /images/install-master-url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openshift-labs/devops-guides/8f93f5c80772add2595427ce11aeaf73350cad95/images/install-master-url.png --------------------------------------------------------------------------------