Rob Harris
2018-04-11 2a3d5b496e72d6a067d1bbc3512e33dbb711becf
commit | author | age
74d1f1 1 # The Manual Menace
0f4d08 2
74d1f1 3 > In this lab learners will use Ansible to drive automated provisioning of Projects, Access Control, Git, Jenkins and Nexus
D 4
5 _____
0f4d08 6
D 7 ## Learning Outcomes
8 As a learner you will be able to
74d1f1 9
D 10 1. Run the OpenShift Applier to automate creating cluster content
11 1. Create and admin project namespaces in OpenShift
12 1. Deploy commonly used applications to support the development process
0f4d08 13
D 14 ## Tools and Frameworks
15
74d1f1 16 * [GitLab](https://about.gitlab.com/) - Community driven Git server now with integrated DevOps Toolchain.
D 17 * [Nexus](https://www.sonatype.com/nexus-repository-sonatype) - Repository manager for storing lots of application types. Can also host `npm` and `Docker` registries.
18 * [Jenkins](https://jenkins.io/) - OpenSource Build automation server. Highly customisable with plugins.
19 * [Ansible](https://www.ansible.com/) - IT Automation tool used to provision and manage state of cloud and physical infrastructure.
20 * [OpenShift Applier](https://github.com/redhat-cop/openshift-applier) - Community driven Git server
0f4d08 21
74d1f1 22 ## Big Picture
D 23 This exercise begins with an empty Cluster
24 > TODO - add big picture here...
25
26 _____
0f4d08 27
D 28 ## 10,000 Ft View
74d1f1 29 > This lab is aimed at the creation of the tooling that will be used to support the rest of the Exercises. The highlevel goal is to create a collection of project namespaces and populate them with Git, Jenkins & Nexus.
D 30
31 If you're feeling confident and don't want to follow the step-by-step guide these highlevel instructions should provide a challenge for you:
32
4bf3e6 33 2. Clone the repo `https://github.com/rht-labs/enablement-ci-cd` which contains the scaffold of the project.
92099a 34
74d1f1 35 2. Create `<your-name>-ci-cd`, `<your-name>-dev` and `<your-name>-test` project namespaces using the inventory and run them with the OpenShift Applier to populate the cluster
92099a 36
D 37 2. Use the templates provided to create build and deployment configs in `<your-name>-ci-cd` for. Templates are on a branch called `exercise1/git-nexus` && `exercise1/jenkins`:
74d1f1 38     * Nexus
D 39     * GitLab
92099a 40     * Jenkins (using an s2i to pre-configure jenkins)
D 41
74d1f1 42 2. Commit your `enablement-ci-cd` repository to the GitLab Instance you've created
92099a 43
D 44 2. Burn it all down and re-apply your inventory proving config-as-code works. 
0f4d08 45
D 46 ## Step by Step Instructions
bd7806 47 > This is a structured guide with references to exact filenames and explanations.
0f4d08 48
bd7806 49 ### Part 1 - Create OpenShift Projects
d28811 50 > _Using the OpenShift Applier, we will add new project namespaces to the cluster which will be used throughout the exercise._
D 51
2a3d5b 52 3. Clone the scaffold project to your local machine and pull all remote branches for use in later labs. Open the repo in your favourite editor.
bd7806 53 ```bash
2a3d5b 54 $ git clone https://github.com/rht-labs/enablement-ci-cd && cd enablement-ci-cd
RH 55 ```
56 Followed by;
57 ```
58 $ for branch in `git branch -a | grep remotes | grep -v HEAD | grep -v master`; do
59    git branch --track ${branch#remotes/origin/} $branch
60 done
0f4d08 61 ```
D 62
bd7806 63 3. The project is laid out as follows
D 64 ```
65 .
66 ├── README.md
67 ├── docker
68 │   └── jenkins-slave-node
69 ├── inventory
70 │   ├── group_vars
71 │   │   └── all.yml
72 │   └── hosts
73 ├── jenkins-s2i
74 │   ├── configuration
75 ├── params
76 │   └── project-requests-ci-cd
77 ├── requirements.yml
78 └── templates
79         └── project-requests.yml
80 ```
81  * `docker` folder contains our jenkins-slave images that will be used by the builds.
82  * `jenkins-s2i` contains the configuration and plugins we want to bring jenkins to life with
83  * `params` houses the variables we will load the templates with
84  * `templates` is a collection of OpenShift templates
85  * `inventory/group_vars/all.yml` is the collection of objects we want to insert into the cluster.
86  * `requirements.yml` is a manifest which contains the ansible modules needed to run the playbook
87 Open the `inventory/group_vars/all.yml` file; you should see a some variables setup to create the `ci-cd` namespace. This calls the `templates/project-requests.yml` template with the `params/project-requests-ci-cd` parameters. We will add some additional content here but first let's explore the parameters and the template
88
92099a 89 3. Open the `params/project-requests-ci-cd` and replace the `<YOUR_NAME or initials>` with your name to create the correstponding projects in the cluster. 
1c9328 90 ![new-item](../images/exercise1/ci-cd-project-namespace.png)
bd7806 91
2a3d5b 92 3. Create another two params files for `params/project-requests-dev` & `params/project-requests-test`. Add `NAMESPACE=<YOUR_NAME>-dev` & `NAMESPACE_DISPLAY_NAME=<YOUR-NAME> Dev` to `params/project-requests-dev`. Add `NAMESPACE=<YOUR_NAME>-test` & `NAMESPACE_DISPLAY_NAME=<YOUR-NAME> Test` to `params/project-requests-test`.
bd7806 93
D 94 3. In the `inventory/group_vars/all.yml` file; add the new inventory items for the projects you want to create (dev & test) by adding another object to the content array. You can copy and paste them from the `ci-cd` example and update them accordingly eg
95 ```yaml
1c9328 96     - name: <YOUR_NAME>-dev
D 97       template: "{{ inventory_dir }}/../templates/project-requests.yml"
98       template_action: create
99       params: "{{ inventory_dir }}/../params/project-requests-dev"
100       tags:
101       - projects
102     - name: <YOUR_NAME>-test
103       template: "{{ inventory_dir }}/../templates/project-requests.yml"
104       template_action: create
105       params: "{{ inventory_dir }}/../params/project-requests-test"
106       tags:
107       - projects
bd7806 108 ```
1c9328 109 ![project-request-yaml](../images/exercise1/project-request-yml.png)
bd7806 110
D 111 3. With the configuration in place; install the OpenShift Applier dependency
112 ```bash
113 $ ansible-galaxy install -r requirements.yml --roles-path=roles
114 ```
115
116 3. Apply the inventory by logging into OpenShift and then running 
117 ```bash
118 $ oc login -p <password> -u <user> <cluster_url>
92099a 119 $ ansible-playbook roles/openshift-applier/playbooks/openshift-cluster-seed.yml -i inventory/
bd7806 120 ``` 
D 121
1c9328 122 3. Once successful you should see an output similar to this ![playbook-success](../images/exercise1/play-book-success.png)
bd7806 123
D 124 ### Part 2 - Nexus and GitLab
da55a5 125 > _Now that we have our Projects setup; we can start to populate them with Apps to be used in our dev lifecycle_
bd7806 126
92099a 127 4. In the `enablement-ci-cd` repo, checkout the templates for Nexus by running
da55a5 128 ```bash
92099a 129 $ git checkout exercise1/git-nexus templates/nexus.yml
D 130 ```
131 The tempate contains all the things needed to setup a persistent nexus server, exposing a service and route while also creating the persistent volume needed. Have a read through the template; at the bottom you'll see a collection of parameters we will pass to the template.
132
133 4. Add some parameters for running the template by creating a new file in the `params` directory. 
134 ```bash
135 $ touch params/nexus
da55a5 136 ```
D 137
92099a 138 4. The essential params to inclue in this file are: `params` directory. 
D 139 ```bash
140 VOLUME_CAPACITY=5Gi
141 MEMORY_LIMIT=2Gi
142 ```
143
d28811 144 4. Create a new object in the inventory variables called `ci-cd-deployments` and populate it's `content` is as follows remembering to swap `<YOUR_NAME>-ci-cd` for the namespace you created previously
92099a 145 ```yaml
1c9328 146   - object: ci-cd-deployments
D 147     content:
148     - name: "nexus"
149       namespace: "<YOUR_NAME>-ci-cd"
150       template: "{{ inventory_dir }}/../templates/nexus.yml"
151       params: "{{ inventory_dir }}/../params/nexus"
152       tags:
153       - nexus
92099a 154 ```
1c9328 155 ![ci-cd-deployments-yml](../images/exercise1/ci-cd-deployments-yml.png)
92099a 156
D 157 4. Run the OpenShift applier, specifying the tag `nexus` to speed up it's execution.
158 ```bash
159 $ ansible-playbook roles/openshift-applier/playbooks/openshift-cluster-seed.yml \
160      -i inventory/ \
1c9328 161      -e "filter_tags=nexus"
92099a 162 ```
D 163
1c9328 164 4. Once successful; login to the cluster and navigate to the `<YOUR_NAME>-ci-cd`. You should see Nexus up and running. You can login with default credentials (admin / admin123) ![nexus-up-and-running](../images/exercise1/nexus-up-and-running.png)
92099a 165
D 166 4. Now lets do the same thing for GitLab to get it up and running. Checkout the template provided by running
167 ```bash
168 $ git checkout exercise1/gitlab-nexus templates/gitlab.yml
169 ``` 
170 Explore the template; it contains the PVC, buildConfig and services. The DeploymentConfig is made up of these apps
171  - Redis (3.2.3)
172  - PostgreSQL (9.4)
173  - GitLab CE (v10.2.3)
174
175 4. Add a new params file in the `params` folder called `gitlab`
176 ```bash
177 $ touch params/gitlab
178 ```
179
180 4. Open the `params/gitlab` file and add the following params
181 ```
182 LDAP_BIND_DN=uid=<BIND_USER>,ou=People,dc=<YOUR_DOMAIN>,dc=com
183 LDAP_USER_FILTER=(memberof=CN=YourGroup,OU=Users,DC=<YOUR_DOMAIN>,DC=com)
184 LDAP_PASSWORD=<BIND_USER_PASSWORD>
185 LDAP_HOST=<LDAP_HOST>
186 LDAP_BASE=ou=People,dc=<YOUR_DOMAIN>,dc=com
187 LDAP_LABEL="<LDAP_DESCRIPTION>"
188 GITLAB_ROOT_PASSWORD=<GITLAB_ROOT_USER_PASSWORD>
189 GITLAB_DATA_VOL_SIZE=2Gi
190 POSTGRESQL_VOL_SIZE=1Gi
191 APPLICATION_HOSTNAME=<GITLAB_URL>
4feb7f 192 NAMESPACE=<YOUR_NAME>-ci-cd
92099a 193 ```
D 194 where the following need to be replaced by actual values:
195     * `<BIND_USER>` is the user used to query the LDAP
196     * `<BIND_USER_PASSWORD>` is the password used when querying the LDAP
197     * `<YOUR_DOMAIN>` is the domain the LDAP is hosted on
198     * `<LDAP_HOST>` is fqdn of the LDAP server
199     * `<LDAP_DESCRIPTION>` is the description to be used on the sign-in header for GitLab eg "Name LDAP Login"
200     * `<GITLAB_ROOT_USER_PASSWORD>` is the root user for GOD access on the GitLab instance eg password123
201     * `<GITLAB_URL>` is the endpoint for gitlab. It will take the form `gitlab-<YOUR_NAME>-ci-cd.apps.<ENV_ID>.<YOUR_DOMAIN>.com`
d28811 202 <p class="tip">
D 203 Note - some of the values here for the LDAP will be provided by your tutor.
204 </p>
92099a 205
D 206 4. Create another object in the inventory `all_vars.yml` file to run the build & deploy of this template. Add the following and update the `namespace:` accordingly
207 ```yaml
1c9328 208     - name: "gitlab"
D 209       namespace: "<YOUR_NAME>-ci-cd"
210       template: "{{ inventory_dir }}/../templates/gitlab.yml"
211       params: "{{ inventory_dir }}/../params/gitlab"
212       tags:
213       - gitlab
92099a 214 ```
D 215
216 4. Run the OpenShift applier, specifying the tag `gitlab` to speed up it's execution.
217 ```bash
218 $ ansible-playbook roles/openshift-applier/playbooks/openshift-cluster-seed.yml \
219      -i inventory/ \
1c9328 220      -e "filter_tags=gitlab"
92099a 221 ```
D 222
1c9328 223 4. Once successful; login to the cluster and navigate to the `<YOUR_NAME>-ci-cd`. You should see GitLab up and running. ![gitlab-up-and-running](../images/exercise1/gitlab-up-and-running.png)
4feb7f 224
D 225 4. Navigate to gitlab. You can login with using your cluster credentials using the LDAP tab displaying your `<LDAP_DESCRIPTION>` from previous steps
226
1c9328 227 ![gitlab-ui](../images/exercise1/gitlab-ui.png)
4feb7f 228
d28811 229 4. Once logged in create a new project called `enablement-ci-cd` and mark it as internal. Once created; copy out the `git remote add origin ...` instructions for use on the next step.
1c9328 230 ![gitlab-new-project](../images/exercise1/gitlab-new-project.png)
D 231 <p class="tip">
d28811 232 Note - we would not normally make the project under your name but create an group and add the project there on residency but for simplicity of the exercise we'll do that here
1c9328 233 </p>
D 234
235 4. Commit your local project to this new origin by first removing the existing origin (github) where the the project was cloned from. Remember to substitute `<YOUR_NEW_GIT_PROJECT>` accordingly
236 ```bash
237 $ git remote remove origin
238 $ git remote add origin <YOUR_NEW_GIT_PROJECT>
239 $ git add . 
240 $ git commit -m "Adding git and nexus config"
241 $ git push -u origin --all
242 ```
bd7806 243
D 244 ### Part 3 - Jenkins & s2i
d28811 245 > _Create a build and deployment config for Jenkins. Add new configuration and plugins to the OCP Stock Jenkins using s2i_
D 246
1c9328 247 5. Add the Jenkins Build & Deployment configs to the `enablement-ci-cd` repo by merging the contents `exercise1/jenkins` in
D 248 ```bash
249 $ git checkout exercise1/jenkins templates/jenkins.yml
250 ```
bd7806 251
1c9328 252 5. Add the Jenkins Build & Deployment configs to the `enablement-ci-cd` repo by merging the contents `exercise1/jenkins` in
D 253 ```bash
254 $ git checkout exercise1/jenkins templates/jenkins.yml
255 ```
256 The Jenkins template is essentially the standard persistent jenkins one with OpenShift.
257
258 5. As before; create a new set of params by creating a `params/jenkins` file and adding some overrides to the template and updating the `NAMESPACE` value.
259 ```bash
260 MEMORY_LIMIT=8Gi
261 VOLUME_CAPACITY=5Gi
262 JVM_ARCH=x86_64
263 NAMESPACE=<YOUR_NAME>-ci-cd
264 JENKINS_OPTS=--sessionTimeout=720
265 ```
266 5. Add a `jenkins` variable to the ansible inventory underneath the git and nexus ones. Remember to replace `<YOUR_NAME>` with the appropriate value.
267 ```yaml
268     - name: "jenkins"
269       namespace: "<YOUR_NAME>-ci-cd"
270       template: "{{ inventory_dir }}/../templates/jenkins.yml"
271       params: "{{ inventory_dir }}/../params/jenkins"
272       tags:
273       - jenkins
274 ```
275 This configuration if applied now; it will create the deployment configuration needed for Jenkins but the `${NAMESPACE}:${JENKINS_IMAGE_STREAM_TAG}` in the template won't exist yet.
276
277 5. To create this image we will take the supported OpenShift Jenkins Image and bake into it some extra configuration using an [s2i](https://github.com/openshift/source-to-image) builder image. More information on Jenkins s2i is found on the [openshift/jenkins](https://github.com/openshift/jenkins#installing-using-s2i-build) github page. To create an s2i configuration for jenkins, check out the pre-canned configuration source in the `enablement-ci-cd` repo
278 ```bash
279 $ git checkout exercise1/jenkins-s2i jenkins-s2i
280 ```
281 The structure of the jenkins s2i config is 
282 ```
283 jenkins-s2i
284 ├── README.md
285 ├── configuration
286 │   ├── build-failure-analyzer.xml
287 │   ├── init.groovy
288 │   ├── jenkins.plugins.slack.SlackNotifier.xml
289 │   └── jobs
290 │       └── seed-multibranch-job
291 │           └── config.xml
292 └── plugins.txt
293 ```
294  * `plugins.txt` is a list of `pluginId:version` for Jenkins to pre-install when starting
295  * `./configuration` contains content that is placed in `${JENKINS_HOME}`. A `config.xml` could be placed in here to control the bulk of Jenkins configuration.
296  * `./configuration/jobs/*` contains job names and xml config that jenkins loads when starting. The seed job in there we will return to in later lessons.
d28811 297  * `build-failure-analyzer.xml` is config for the plugin to read the logs and look for key items based on a Regex. More on this in later lessons.
1c9328 298  * `init.groovy` contains a collection of settings jenkins configures itself with when launching
D 299
300 5. Let's add a plugin for Jenkins to be started with, [green-balls](https://plugins.jenkins.io/greenballs). This simply changes the default `SUCCESS` status of Jenkins from Blue to Green. Append the `plugins.txt` file with 
301 ```txt
302 greenballs:1.15
303 ``` 
304 ![green-balls.png](../images/exercise1/green-balls.png)
305 Why does Jenkins have Blue Balls? More can be found [on reddit](https://www.reddit.com/r/programming/comments/4lu6q8/why_does_jenkins_have_blue_balls/) or the [jenkins blog](https://jenkins.io/blog/2012/03/13/why-does-jenkins-have-blue-balls/)
306
307 5. Before building and deploying Jenkins; add git credentials to the s2i by either adding them to the `template/jenkins.yml` and `params/jenkins` or for simplicity just replace the `<USERNAME>` && `<PASSWORD>` with your ldap credentials.
308 <p class="tip">
d28811 309 Note in a residency we would not use your GitCredentials for pushing and pulling from Git, A service user would be created for this.
1c9328 310 </p>
D 311 ```groovy
312 gitUsername = System.getenv("GIT_USERNAME") ?: "<USERNAME>"
313 gitPassword = System.getenv("GIT_PASSWORD") ?: "<PASSWORD>"
314 ```
315
316 5. Add a new params file in the `params` folder called `jenkins-s2i`
317 ```bash
318 $ touch params/jenkins-s2i
319 ```
320
d28811 321 5. Open the `params/jenkins-s2i` file and add the following content; replacing variables as appropriate. 
1c9328 322 ```
D 323 SOURCE_REPOSITORY_URL=<YOUR_ENABLEMENT_REPO>
324 NAME=jenkins
325 SOURCE_REPOSITORY_CONTEXT_DIR=jenkins-s2i
326 IMAGE_STREAM_NAMESPACE=<YOUR_NAME>-ci-cd
d28811 327 SOURCE_REPOSITORY_USERNAME=<YOUR_LDAP_USERNAME>
D 328 SOURCE_REPOSITORY_PASSWORD=<YOUR_LDAP_PASSWORD>
1c9328 329 ```
D 330 where 
d28811 331     * `<YOUR_ENABLEMENT_REPO>` is the full path clone path of the repo where this project is stored (including the https && .git)
D 332     * `<YOUR_NAME>` is the prefix for your `-ci-cd` project.
333     * Explore some of the other parameters in `templates/jenkins-s2i.yml`
334     * `<YOUR_LDAP_USERNAME>` is the base64encoded username builder pod will use to login and clone the repo with
335     * `<YOUR_LDAP_PASSWORD>` is the base64encoded password the builder pod will use to authenticate and clone the repo using
336 You can use `echo -n '<YOUR_LDAP_PASSWORD>' | openssl base64` to encode your username and password accordingly.
337 <p class="tip">
338 Note in a residency we would not use your GitCredentials for pushing and pulling from Git, A service user would be created for this.
339 </p>
1c9328 340
D 341 5. Create a new object `ci-cd-builds` in the ansible `all.yml` to drive the s2i build configuration.
342 ```yaml
343   - object: ci-cd-builds
344     content:
345     - name: "jenkins-s2i"
346       namespace: "<YOUR_NAME>-ci-cd"
347       template: "{{ inventory_dir }}/../templates/jenkins-s2i.yml"
348       params: "{{ inventory_dir }}/../params/jenkins-s2i"
349       tags:
350       - jenkins
351 ```
352
353 5. Commit your code to your GitLab instance
354 ```bash
d28811 355 $ git add .
1c9328 356 $ git commit -m "Adding Jenkins and Jenkins s2i"
D 357 $ git push
358 ```
359
360 5. When your code is commited; run the OpenShift Applier to add the config to the cluster
361 ```bash
362 $ ansible-playbook roles/openshift-applier/playbooks/openshift-cluster-seed.yml \
363      -i inventory/ \
364      -e "filter_tags=jenkins"
365 ```
366
d28811 367 5. This will trigger a build of the s2i and when it's complete it will add an imagestream of `<YOUR_NAME>-ci-cd/jenkins:latest` to the project. The Deployment config should kick in and deploy the image once it arrives. You can follow the build of the s2i by going to the OpenShift console's project
D 368 ![jenkins-s2i-log](../images/exercise1/jenkins-s2i-log.png)
bd7806 369
d28811 370 5. When the Jenkins deployment has completed; login (using your openshift credentials) and accept the role permissions. You should now see a fairly empty Jenkins with just the seed job
92099a 371
d28811 372 ### Part 4 - Jenkins Hello World 
D 373 > _To test things are working end-to-end; create a hello world job that doesn't do much but proves we can pull code from git and that our balls are green._
374
375 6. Log in to Jenkins and hit `New Item` ![new-item](../images/exercise1/new-item.png).
376
377 6. Create a freesyle job called `hello-world` ![jenkins-new-hello-world](../images/exercise1/jenkins-new-hello-world.png).
378
379 6. On the Source Code Management tab; add your `enablement-ci-cd` git repo and hit the dropdown to add your credentials we baked into the s2i on previous steps`` ![jenkins-scm-git](../images/exercise1/jenkins-scm-git.png).
380
381 6. On the build tab add an Execute Shell step and fill it with `echo "Hello World"` ![jenkins-hello-world](../images/exercise1/jenkins-hello-world.png).
382
383 6. Run the build and we should see if pass succesfully and with Green Balls! ![jenkins-green-balls](../images/exercise1/jenkins-green-balls.png)
384
385 ### Part 5 - Live, Die, Repeat
386 > _TOOD - improve & flesh out this section ...._
387
388 7. Commit your code to the new repo in GitLab
389
390 7. Burn your OCP content to the ground
391
392 7. Re-apply the inventory!
0f4d08 393
74d1f1 394 _____
D 395
0f4d08 396 ## Extension Tasks
d28811 397 > _Ideas for go-getters. Advanced topic for doers to get on with if they finish early. These will usually not have a solution and are provided for additional scope._
0f4d08 398
92099a 399  - Add more secure access for Nexus (ie not admin / admin123) using the automation to drive secret creation
1c9328 400  - Add a SonarQube persistent deployment to the `ci-cd-deployments` section.
D 401  - Add `jenkins.plugins.slack.SlackNotifier.xml` to `jenkins-s2i/configuration` to include URL of Slack for team build notifications and rebuild Jenkins S2I
0f4d08 402
74d1f1 403 _____
D 404
0f4d08 405 ## Additional Reading
D 406  > List of links or other reading that might be of use / reference for the exercise