- [Instructor] Now that we have Jenkins
connecting to our project on GitHub,
pulling down the source code
and running through all the stages
of getting it to a production image,
let's take some time to explore what this is doing,
the concepts behind the multi-branch pipeline,
and Jenkins files in general.
So here we see that there are one, two,
three, four, five stages in our pipeline right now.
There's basically five steps to building our product.
So, where did these come from?
Over here in my editor, I have the example project
we uncompressed earlier and have
been working on, the one we pushed to get.
In this folder, we see this folder here called Jenkins File.
Before Jenkins Files, the way to make a project in Jenkins
was to go over to Jenkins, open up the web interface
and click a lot, and that was all well and good
until you have two different branches of your project
that need to be built differently.
Well then you have to copy the job,
make a slight change, and remember
to update both sides when things
shift over time, which does get old.
So Jenkins has adopted the concept of a Jenkins file
where this file defines exactly and everything
about building this branch of this project.
It includes all the stages, all the steps,
and can have everything from getting
your project to source code into production all in one file.
That means that when there's multiple branches,
this file can be different in the multiple branches,
and can help things stay sane.
So let's take a little look.
It's written in the Groovy language,
which is a fun programming language,
and it gives you the full power of software development
in defining how your projects are deployed.
So at the top, I define a couple of
useful variables that need to be accessible
for many points in the pipeline,
and then we define some stages.
So here's the pipeline, this is the top level
data structure that says here is everything.
It consists of a bunch of stages,
as well as some instructions for where it can be run.
Since we have a dead simple Jenkins installation,
far too simple for any production use, we just put any.
It can build anywhere that is available.
This will usually include a block
restricting where it can build.
Then, under the stages part we have a series of stages.
If we look and see the first stage here
is called Checkout Source Code and Logging Into Registry.
Switching back to our project,
we see that is in fact the first stage
after the pipeline itself starts,
and then we see the second stage is Make a Builder Image,
which is the second stage here.
So each of these blocks defines one stage of the project.
We have check out the code, make the builder image,
run some unit tests in that builder image,
then build a production image,
and a bunch more stages we're
going to add in later chapters.
So this first part says once the code is checked out,
it's just going to fill in some variables for us,
it's going to fill in the current commit hash,
so we can use that in later stages
to tag builds with the get hash from which they came.
We also store a common string here,
which is the ECR registry prefix.
Let's talk a little bit about where to get this string,
'cause you're going to want to go in right here
with your editor and change this to match your account.
So back in my editor, I'm going to open up the AWS console,
click on services, go to ECS,
ECR is part of the ECS project.
Then down here, again, we're going to click on
repositories like we did earlier,
click on the example web app,
and then you can grab this string right here
off the beginning of any of them.
It's all the characters up to, but not including,
that first slash there, so it breaks down to be
my account name, and then a fixed string,
and then U.S. east one, because that's
the region I'm in, and then amazonaws.com.
So you grab this string here, copy it,
and paste it on into your Jenkins file.
A little farther down, we have the real first stage.
Let's take a moment to walk through this one.
The code here, which is written in Groovy again,
the first thing it does is include a script.
A script is a chunk of free form code
that you can use for building your project
as part of a pipeline stage, so the first
thing it's going to do is make a builder image
by calling a docker.build method,
and it's going to pass it, this string that it passes here
is the tag to put on that image that builds it.
So we take the account registry prefix
that we just defined above,
and then we put the project name after it.
Example Web App Builder.
Let me just scroll over a bit so the
whole thing fits on the screen.
Example Web App Builder, this project within our account,
and we're going to tag it with the current get hash,
again, the thing we set just above this.
The second parameter is any further arguments
you'd like to pass to the Docker build,
all strung together as one big string.
So we don't want to use the default
Docker file for this build,
we want to use our builder docker file.
So we say Dash + F, which is the Docker build argument
for specifying which Docker file to use,
and then we say dockerfile.builder,
the one we defined earlier, and dot right after it,
that says which directory should the build happen from.
And we want it to happen from the current directory.
So this stage here, when it ran in our project,
corresponds to this stage here,
and you can look at that further
by clicking on the build number,
then clicking on console output,
and see the textual output of all these stages.
And in our case here, we can see that
it built this Docker file, and then
tagged it with this Example Web App Builder,
and the current get hash.
Returning back to our Jenkins file,
we can see that in this next section
after building the image and then
pushed it with a convenient tag
just named after the get branch
so that we could look them up more easily.
And then we want to run some code inside that image.
So you can do dockerimage.inside,
which means start that image into a container,
and then run the rest of the block as
commands inside that container.
It also takes some optional arguments.
Earlier, when we did Docker Run,
we said Docker Run + Dash + V,
the current directory, and mounted it under
a directory inside our container,
and then we specified which user to run it as.
Well here, we're doing the same thing.
This is how we translate that into
Groovy code for a Jenkins file.
We say Dash + V for volume,
and we mount dollar workspace will be
filled in by Jenkins to specify the current
working directory where this job is running.
We mount it inside the container under /output.
Then, the next thing we're doing within that code block,
we're running the shell command.
Here we can just give it a shell
script with a few lines to run.
So we're going to go to the directory
where the source code can be found
and run the build tool, lein uberjar,
just like we did in the previous examples.
But now, it's part of the Jenkins file.
The next stage is very similar,
except the image is already built,
and we just want to run some tests,
so copying the same stuff down here,
we go to the directory where the
source code is, and we run the unit tests.
In the next stage where we build the production image
is actually more of the same, just a little simpler.
So we copy the same stuff down,
and we say production images, docker.build,
we're going to invoke Docker build again
and give it the same thing, except in this case,
we're passing it just Example Web App,
instead of Example Web App Builder,
because that's the name of the
registry for our production images.
We're going to tag it with the get commit hash,
and we're going to push it to the private registry.
Then we're also going to push it with the current branch.
Now, this is another environment variable
that Jenkins will fill in, that way we
can reference builds either by their exact get hash,
or the newest thing on a particular branch.
All right, and that covers it for the part of
the Jenkins file we're using so far.
We'll use the rest in later chapters.