Skip to content

Commit 8155ffe

Browse files
committed
Added CI/CD chapter
1 parent ab88057 commit 8155ffe

File tree

7 files changed

+117
-1
lines changed

7 files changed

+117
-1
lines changed

developer-tools/java/chapters/ch09-cicd.adoc

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,119 @@
22

33
= CI/CD using Docker
44

5+
*PURPOSE*: This chapter explains how to use Jenkins and Docker to run continuous integration and continuous delivery.
6+
7+
There are several possible approaches to run Docker builds with Jenkins:
8+
9+
. Install Jenkins on your host machine, where Docker is also installed, and run Docker commands from your build, either using one of the several Jenkins Docker plugins, or by running Docker commands from a build step
10+
. Install Jenkins on your host machine and have a Jenkins slave machine with Docker installed to run your Docker builds
11+
. Run Jenkins on Docker and use the underlying Docker installed on the host to run Docker commands.
12+
13+
NOTE: Another option is running Jenkins on Docker and do a complete Docker installation inside the Jenkins Docker container. This technique is called Docker in Docker and it is usually a bad idea. There are several discussions about the problems with this approach, like this one: http://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/ . A better approach is using Docker outside of Docker, as explained here: http://container-solutions.com/running-docker-in-jenkins-in-docker/
14+
15+
== Run Jenkins on docker
16+
17+
In this example, we will run Jenkins on Docker and use the underlying Docker installed on the host to run Docker commands. This technique is known as Docker outside of Docker.
18+
19+
First, clone the project at https://github.com/fabianenardon/jenkins-docker-demo
20+
21+
Then, in the project folder, run:
22+
23+
[source, text]
24+
----
25+
docker-compose up
26+
----
27+
28+
Wait for jenkins to start and then go to the browser and open `http://localhost:8081`. Jenkins should be running.
29+
30+
The Jenkins installation on this lab comes pre-configured. To login use the username `jenkins` and the password `jenkins`.
31+
32+
== Running Integration Tests with Docker and Jenkins
33+
34+
For this Continuous Integration demo, we will run the application described on the link:chapters/ch11-bigdata.adoc[Big Data Processing with Docker and Hadoop] chapter.
35+
36+
[NOTE]
37+
====
38+
When running integration tests, you want to test your application in an environment as close to production as possible, so you can test interactions between the several components, services, databases, network communication, etc. Fortunately, docker can help you a lot with integration tests. There are several strategies to run integration tests, but in this application we are going to use the following:
39+
40+
. Start the services with a `docker-compose.yml` file created for testing purposes. This file won't have any volumes mapped, so when the test is over, no state will be saved. The test `docker-compose.yml` file won't publish any port on the host machine, so we can run simultaneous tests.
41+
. Run the application, using the services started with the `docker-compose.yml` test file.
42+
. Run Maven integration tests to check if the application execution produced the expected results. This will be done by checking what was saved on the MongoDB database.
43+
. Stop the services. No state will be stored, so next time you run the integration tests, you will have a clean environment.
44+
====
45+
46+
Create a new job on jenkins:
47+
48+
1 . Select Freestyle project
49+
50+
image::docker-ci-cd-01.png[]
51+
52+
2 . In Source Code Management, select Git and add the repository URL: `https://github.com/fabianenardon/hadoop-docker-demo`
53+
54+
image::docker-ci-cd-02.png[]
55+
56+
3 . In Build, select Add build step and select Execute shell
57+
58+
image::docker-ci-cd-03.png[]
59+
60+
4 . In the shell Command, add these instructions:
61+
62+
[source, text]
63+
----
64+
cd sample
65+
66+
# Generates the images
67+
sudo /var/jenkins_home/tools/hudson.tasks.Maven_MavenInstallation/maven/bin/mvn clean install -Papp-docker-image
68+
69+
70+
# Starts all the services. The -p option allows multiple builds to run at the same time,
71+
# since we can start multiple instances of the containers
72+
sudo docker-compose -p app-$BUILD_NUMBER --file src/test/resources/docker-compose.yml up -d
73+
74+
# Waits for containers to start
75+
sleep 30
76+
77+
# Creates the folder we need on hdfs to test
78+
sudo docker-compose -p app-$BUILD_NUMBER --file src/test/resources/docker-compose.yml exec -T yarn hdfs dfs -mkdir /files/
79+
80+
# Put the file we are going to process on hdfs
81+
sudo docker-compose -p app-$BUILD_NUMBER --file src/test/resources/docker-compose.yml run docker-hadoop-example hdfs dfs -put /maven/test-data/text_for_word_count.txt /files/
82+
83+
# Run our application
84+
sudo docker-compose -p app-$BUILD_NUMBER --file src/test/resources/docker-compose.yml run docker-hadoop-example hadoop jar /maven/jar/docker-hadoop-example-1.0-SNAPSHOT-mr.jar hdfs://namenode:9000 /files mongo yarn:8050
85+
86+
# Run our integration tests
87+
sudo docker-compose -p app-$BUILD_NUMBER --file src/test/resources/docker-compose.yml run docker-hadoop-example-tests mvn -f /maven/code/pom.xml -Dmaven.repo.local=/m2/repository -Pintegration-test verify
88+
----
89+
90+
5 . Click on Add post-build action and select Execute a set of scripts
91+
92+
image::docker-ci-cd-04.png[]
93+
94+
6 . In Post-build Actions, select Execute shell
95+
96+
image::docker-ci-cd-05.png[]
97+
98+
7 . In the Command box, add:
99+
100+
[source, text]
101+
----
102+
cd sample
103+
sudo docker-compose -p app-$BUILD_NUMBER --file src/test/resources/docker-compose.yml down
104+
----
105+
106+
8 . Uncheck the `Execute script only if build succeeds` and `Execute script only if build fails` options, so this script will run always when the build ends. This way, we make sure to always stop the services.
107+
108+
109+
[NOTE]
110+
====
111+
. The `-p app-$BUILD_NUMBER` option allows multiple builds to run at the same time, since we can start multiple instances of the containers. We are using Jenkins $BUILD_NUMBER variable to isolate the containers. This way, each set of services will run on its own network.
112+
. We are running the commands with sudo because we are actually running the Docker socket on the host. Jenkins runs with the jenkins user and we added the jenkins user to the sudoers list in our image. Obviously, this can have security consequences in a production environment, since one could create a build that would access root level services on the host. You can avoid this by configuring the jenkins user on the host, so it will have access to the Docker socket and then run the commands without sudo.
113+
====
114+
115+
== Continuous Delivery with Docker and Jenkins
116+
117+
Continuous Delivery strategies depend greatly on the application architecture. With a dockerized application like the one in our demo, the continuous delivery strategy could be to publish a new version of the application image if the tests passed. This way, next time the application runs on production, the new image will be downloaded and automatically deployed. You can publish images with Jenkins just like you invoked all the other docker commands in the build.
118+
119+
120+

developer-tools/java/chapters/ch11-bigdata.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ image::docker-bigdata-02.png[]
164164

165165
When running integration tests, you want to test your application in an environment as close to production as possible, so you can test interactions between the several components, services, databases, network communication, etc. Fortunately, docker can help you a lot with integration tests.
166166

167-
There are several strategies to run integration test, but in this application we are going to use the following:
167+
There are several strategies to run integration tests, but in this application we are going to use the following:
168168

169169
. Start the services with a `docker-compose.yml` file created for testing purposes. This file won't have any volumes mapped, so when the test is over, no state will be saved. The test `docker-compose.yml` file won't publish any port on the host machine, so we can run simultaneous tests.
170170
. Run the application, using the services started with the `docker-compose.yml` test file.
Loading
Loading
Loading
Loading
Loading

0 commit comments

Comments
 (0)