CI/CD in Production with Jenkins – Complete DevOps Course

#CI/CD #DevOps #Jenkins #DevSecOps #Kubernetes #Maven
💬 Chat with this Video
Ask anything about this video…
Welcome to this comprehensive CI/CD course designed to take you from foundational concepts to production-grade implementations. Over the next 17 and a half hours, you will gain a solid real world understanding of modern DevOps workflows using Jenkins as the automation server. You will work through nine hands-on projects culminating in a complex dev sec ops mega project. By the end of this course, you will have the skills and context required to build, secure and operate reliable software delivery systems in any professional environment. Hello, I am Varun Jooshi and I welcome you to cloud with VJOS where we talk about cloud DevOps and everything in between. What you are about to watch is a fully consolidated CI/CD master class bringing together 11 lectures and over 17 and 1/2 hours of structured in-depth learning into a single video. This video is for anyone who wants one complete place to understand how CI/CD actually works in production without jumping between disconnected tutorials. This is not just a Jenkins course. This is a CI/CD first masterass with Jenkins used as the primary orchestrator. We start from absolute basics and move step by step towards advanced production grade CI/CD implementations. Every concept is introduced with context. So you understand not just what you are doing but why it is done that way in real engineering teams. While Jenkins is the main tool used most of what you will learn here is orchestrator agnostic. The concepts apply equally to GitHub actions, GitLab CI and other modern CI/CD platforms. Once these fundamentals are clear, switching tools becomes super easy. This master class is designed as a complete end toend learning journey. You will walk through nine hands-on CI/CD projects and the course concludes with a dev sec ops mega project that runs for nearly 3 hours and 40 minutes. In this final project, we bring everything together in a production style setup. So you can see how real CI/CD systems are actually built and operated. All demos in this course are intentionally chosen to reflect real world scenarios. There are no toy examples and no artificial workflows. What you see here closely mirrors the patterns, decisions and tradeoffs used in real production environments. Some ideas are repeated intentionally. CI/CD foundations are critical and repetition helps these concepts stay with you when you start applying them in real projects. Along with the video, you will have access to a well-maintained GitHub repository that goes hand inhand with the lecture. These notes contain the exact YAML files, Jenkins files, configurations, and commands used during the demos. More than just notes, think of this repository as a written companion or transcript of everything we are learning. So you always have one place to revisit and revise concepts. I have intentionally kept the notes structured day-wise instead of merging everything into a single large readme. This makes it easier to navigate, practice and revise without confusion. The repository link is available in the description. For completeness, I have also retained the original intro and outro of each lecture. So you can easily map sections of this long video back to the corresponding notes. This course is not meant to be watched passively. I strongly encourage you to practice every lecture along with me. Try to understand the why behind what you are doing. Not just commands or configuration. break things, fix again, experiment with variations. This process is what makes the learning stick for the long term, especially in CI/CD and DevOps where real understanding comes from hands on work. The more you engage with the demos, the more confident you will feel when applying these concepts in real production environments. Before starting this course, you should have basic understanding of Docker and Kubernetes. Everything else is covered from the ground up. In this video, we begin by building strong CI/CD fundamentals. You will first understand how modern software delivery works, how SDLC has evolved and why build automation and CI/CD exist in real world teams. From there we break down CI/CD end to end covering how pipelines work, how branching strategies are applied in production and how code moves from commit to deployment. Once the foundation is clear, we move into Jenkins. You will learn what Jenkins is, how it fits into the CI/CD ecosystem and how to install and run it using Docker. We start with freestyle jobs and gradually go deeper working with parameters, git branches and tags, triggers, and chronbased automation so you understand how Jenkins is actually used dayto-day. With that base in place, we move into hands-on projects. You will build, push and deploy applications using Jenkins. First with freestyle jobs and then with Jenkins pipelines. From there we move into production style CI/CD by working with multibranch pipelines, GitHub pull requests and real branching workflows used by engineering teams. The course then expands beyond Jenkins itself. You will learn where build tools like Maven fit into the DevOps workflow and how they are used inside real CI pipelines. We then introduce Sonar Cube to bring in dev sec ops practices covering code quality security scanning and enforced quality gates inside CI/CD pipelines. All of this come together in dev sec ops mega project where we build a production style setup using a multi-AZ Amazon EKS cluster integrated with Jenkins Maven TV sonar cube Amazon ECR and GitHub. We close the course by covering Jenkins shared libraries showing how teams move from copy paste pipelines to reusable maintainable production grade CI/CD design. Your feedback genuinely matters to me. If this course helps you in production, clears your interviews or strengthens your CI/CD fundamentals, I would love to hear about it. And if you feel something is missing or unclear, tell me that too. I read the comments and reply. Your feedback directly influences how future content is shaped. By the end of this master class, you will not just know Jenkins, you will understand how CI/CD works in real world and how to apply it confidently in production. If this course helps you, liking the video, subscribing to the channel, or leaving a comment goes a long way in supporting the work and helping it reach more learners. If you would like to support the channel further, consider joining as a channel member. I don't lock content behind pay walls, so membership is simply a way to back the free learning I share with everyone. So with all of that said, let's get started and I wish you all the very best. Hi, I am Vun Jooshi and welcome to day one of our Jenkins basics to production course. In this very first lecture, we are setting the stage by covering the fundamentals every DevOps and S sur engineer must know before touching Jenkins. And here is the agenda for today's lecture. Firstly, we will discuss the phases of software development life cycle SDLC. How modern software moves from idea to production. Next, we will discuss waterfall and the agile DevOps model. Why we shifted from big bang releases to continuous delivery. Then we'll move on to compiled versus interpreted languages. What happens to your code before it runs. Next we will discuss the key building blocks which are artifacts, runtime and dependencies. And finally the build process which is of extreme importance for us DevOps engineers both for containerized and non-containerized workloads. So you understand how applications actually get prepared for production. By the end of this session, you will have a production level understanding how software is built and deployed which will make everything we do with Jenkins later far more clearer. So let's get started. Phases of SDLC. Firstly, SDLC is software development life cycle. And this is what we will use. What you see on screen is what we use in agile and devops model which is the latest and the greatest one. So now I want you to understand that there are millions of applications that are around the globe. Are all the applications adhering to this SDLC framework? No, it is not that. But whether an application adheres to all these phases depends on the maturity of the application. So if I talk about an enterprisegrade application like Amazon.com or Netflix.com, they would definitely be adhering to the SDLC process. Now SDLC at large is not a tool. It is not something that you can purchase. It's an ideology. An ideology that you must have in your application if you want your application to have the latest and greatest modern design. Hence, SDLC is a logical framework which defines how you should be developing your application. And in this lecture we will start by discussing the different phases in SDLC. Now like I said SDLC is not a tool. It is a framework. But within the phases of SDLC, you will of course be using different tooling. For example, if I talk about the first phase, this is requirement gathering. What would requirement gathering? What are the tools that I would use in requirement gathering? I would be using Microsoft Teams, Zoom or WebEx for meetings. I could be using Excel or Microsoft Office in general to prepare my documentation. I could also be using tools that I would use to create my diagrams for example diagrams.net or eraser.io etc etc. So what I'm trying to tell you is in each of these phases you will be leveraging different tools but SDLC at a very high level is just a framework. Now let's discuss the first point requirement gathering. What happens here? As the name implies this is the place where you gather everything you can about the application. Now when I talk about an application there are two things that we talk about. First is functional and second is non-functional. Now what are functional requirements? Functional requirements are what the system should do. For example, if we are developing a banking application, then it should be able to show users their account balance, their passbook. They should be able to check if they can apply for a loan, if they are eligible for a loan. They should be able to calculate interest rates and so on. That is the functional requirement from a banking application that they should be able to do these things. Then what are nonfunctional requirements? Now nonfunctional requirements are anything that are not directly application. For example, what should be the infrastructure on which this application must be deployed? Whether we have to adhere to any compliance standards or not. What will be the RTO and RPO for my application? What will be the DR strategy for my application? What will be the availability requirements for my application? These are nonfunctional. So functional are essentially anything that your developers will be coding for the application to work properly and non-functional are anything that will be supporting your application. For example, the underlying hardware will be helping my application to run. So underlying hardware is a non-functional requirement. I hope functional and non-functional is clear to you. Then third point is compliance and security standards. Now at this point of time I want to differentiate between security and compliance. Security is a subjective term for organization A. Security implies not allowing port 22 to the outside world. Not allowed at all. For organization B. Security could mean allowing port 22 but only from a specific public IP. Both of these are security requirements and these are subjective. So security in general is subjective. For one organization or for one application something could be secure and for another something could not be secure. But when I talk about compliance, compliance is dealt with different compliance standards. So if I say my application is compliant to GDPR, then my application must meet the requirements that are laid out in GDPR. Now GDPR is a popular compliance standard when I talk about Europe. So in the requirement gathering section itself you decide what all are the compliance standards that your application must adhere to. Now these compliance standards could be PCI, DSS, GDPR, ISO 27,01 even HIPPA. If you are doing insurance within your banking application then you must also adhere to HIPPA. So in the requirement gathering phase I am just saying that these are the compliance standards I must adhere to. I am not defining how we will adhere to them. I am just saying we must be adhering to compliance standards. Similarly we must have a DR. Now how that DR is achieved we don't know yet. We want high availability but how that high availability will be achieved we don't know that all those things will be done in the design phase which we'll discuss next. Now before I move to design let's also see plan for reliability and environments. Now in the requirement gathering phase itself we decide how many environments do we need. Do we need just dev staging and prod or do we also need a QA or a testing environment as well? So all these things are decided in the requirement gathering phase. Now once all these things are collected your program manager would be the person who would be overseeing everything and will be working with different project managers that are part of that project and then you folks your devops architects your application architects your developers will be participating in these meetings and you will have documents that will have all the requirements. Then there is the design phase. Now design phase is architecture and API contracts. Here is where you define how you will achieve whatever was defined in the requirement gathering phase. Now I want you to clearly know that these phases are for both developers and devops. It is not just the DevOps team who will be participating in all these phases because we are talking about taking an idea to running software. So when I talk about creating an application, it is not just DevOps. You will also have developers here. So design is essentially how the system should function and interact. Second point is testability and observability built in. Now in this phase itself you will design for everything. So be it your observability posture, security posture, testing posture, high availability, DR here you will be defining how you will achieve whatever was gathered in the requirement gathering phase. So security and branching policies. Now you know that whenever we talk about developing a software you know that the entire code is contained in some sort of source control source control like GitHub or GitLab and there are native products available from cloud providers as well. And just a small note here AWS has discontinued its source control service which was AWS code commit. So you will have to go elsewhere if you are on AWS. You can be using something like GitLab, Bitbucket or GitHub. And what will be the branching policy who all will be the collaborator. So all these things are done in the design phase itself. And then the next phase is development. Now development is the phase where the actual work starts. First is branching strategy and code review. So whenever developers are writing the code, they will be writing in their local machines and then they will be pushing the changes to your central repository. Second is local builds and unit tests. So developers will be performing local builds and unit tests. What are unit tests? We will see them in a little while. Shift left security. Now firstly let's understand what is shift left. Now previously what used to happen was the security was only dealt with when we were deploying the application or when the application was completely deployed. But now we are adhering to the shift left approach. Why we are saying it shift left? Because if you go from 1 to 8 you are going left to right. Previously it was security was applied here or here but now we are saying shift left from the requirement gathering phase itself start thinking about testing security and automation. Hence even when the developers are developing SAS and SCA are still performed. What is SAS? SAS ST is static application security testing and SCA is software composition analysis. Now when the code is being written the code is static and that is why static testing is performed. When the application is in running state then we perform something called DAT. DAT is dynamic application security testing. So static scanning when the code is being written. So developers are in their idees and these static testing tools are integrated within the IDE and then when the application is running you have something called DA ST and we'll be seeing that shortly. Now there are tools that are popular. So if you want to perform static testing then you have sonar cube which can test your code. you have check marks for DAT, you have OASP, ZAP and there are plenty of tools that are available at your disposal. Then the last point is pre-commit hooks and feature flags. Now what are pre-commit hooks? Pre-commit hooks are local guardrails that enforces code quality security even before the code is pushed to your GitHub repository or to your choice of source control. Now let's talk about the fourth phase that is the build phase. Now I want you to understand that when I talk about build and deployment phase, these are of paramount importance when you are releasing a new version of an application or when you are deploying the application for the very first time. So in this section we will briefly talk about the build stage and then we will zoom in into this as we progress with this lecture. Now first point is compile and package code. So whenever you have a source code it is in raw format. You must compile it and then package it. And once you do this packaging you receive something called an artifact. So whenever you are packaging a software then the output that you receive is called an artifact. See do not limit your imagination here. So whenever you are building something whatever the result of that is is known as an artifact. So even if you are building a container image the container image that you receive is also an artifact. So whatever is the result of that build stage produces some output and that output is called artifact. Second is reproducible build pipelines. Now if you have a stringent process for build then whatever your artifact is in your local machine the artifact will work fine in your production pipelines as well in your development pipelines as well. For example, if I'm creating a container image and I run that container image onto my laptop that has Docker engine, it will work and any machine that has Docker engine installed all over the internet, that container image will behave the same way in that machine because the underlying Docker engine was the only requirement for that container image to run as a container anywhere. Similarly, if your artifact is received in one machine, that artifact should be reproducible. So, whatever results that you see in your local machine, you should also see those results in your production and dev pipelines. Here that is what we mean by reproducible build pipelines. Next point is artifact registry storage. So whatever your output you receive from the build phase that output should be stored in some sort of registry. So when I talk about container images you have different image registries that are available that you can use to store your images. You can use docker hub you can use AWS's elastic container registry and so on. when I talk about application artifacts. So application artifacts are predominantly the artifacts that you receive post building applications source code and that output can be stored also in a registry. Now there are different sort of registries for them. For example, you can use Nexus or JROG registries to save your artifacts or you can also use native tooling that is made available by the cloud provider. Next point is supply chain security. In parenthesis you see Sbombs and Sbombs means software bill of materials. Now software bill of materials they comprise of everything that is used to build a software. It could be your image, it could be your application, it could be your artifact etc etc. So essentially this line implies all the supply chain must be secure. So if there is code you should be using SAS and dashed. If there is container you should be using static and dynamic scanning. So what is static and dynamic scanning when I talk about containers? So if your container image is there in a registry then your container image must be scanned. If you have a running instance of that container image that is if you have running containers then you should be scanning your containers as well and this is also called runtime scanning. So if I am talking about your containerized workloads, there should be a two-step scanning mechanism. First, scanning should happen for your container images. Second, the scanning should also happen for your running containers. And there are multiple tools available for this. I will let you explore Trivy, Anor, Sneak and so on. Then the next phase is testing phase and in parentheses you see continuous. Now testing is also adhering to shift left approach when we are talking about modern SDLC. So right from the development phase the testing is ongoing which is why you see in the second point we have unit tests mentioned here. Now let's understand what testing means and what are different types of testing that you will see in your day-to-day work. Now testing in general implies testing something whether it is working as expected or not. That is testing. So for example, if I want to test whether my connection to the internet is working or not, I'll try to ping google.com and if it works, I'll know that my connection to the internet works. Now let's see what testing means when we talk about a software. First is unit and integration test. And I want you to take example of the same banking application that we have been talking about. So unit testing is my banking application could have several functionalities. It could be used to check your account balance. It could be used to check your passbook. It could be used to apply for loan and so on. So this application can be divided into different units. And that is what unit testing means. Unit testing means testing different units of your application. So if I want to test let's say account statement, I will see whether the user will be able to log in and check its account statement. So that is called unit testing. Now what is integration testing? Integration testing is how your application behaves when two or three components come together. So if I want to check my account balance along with my passbook then [snorts] these two components of the application must work together. Hence when you are testing multiple components of an application it is called integration testing. Essentially how the application behaves when multiple components come together. Second is performance and load test. Performance implies how the application is behaving. What are the metrics? what is the speed at which the requests are catered and load tests are how my application is behaving when there is let's say 90% load on my application then in testing itself you have security scans you have SAS and DAST you see there is no stage or phase named security because security must be in mind from point 1 through8 so you should be taking care of security testing and automation in all the stages of your SDLC. So security scans we have already discussed SAS and dashed. Then there is pen testing. Pen testing is penetration testing and these this testing is typically performed once in 3 months or once in 6 months or once in a year. Pentesting involves knowing how the application will behave when there is an attack for example. Then the last one is smoke and regression suites. Now smoke testing is a quick testing. So if let's say you released an application, you quickly see whether the application is accessible or not. This is a simple smoke testing. Regression testing is you test the application thoroughly. whether all the functions that my application was supposed to perform are being performed by the application or not. So regression is a thorough testing. Now let's move to deployment. Now in deployment we know how the deployment should be. You first will be deploying into dev stage and then that will be graduated to staging and then that will be graduated to prodage and we'll be discussing this in greater detail as we progress with this course. Second is progressive delivery strategies. There are multiple delivery strategies like blue green canary. What you use depends on what strategy was finalized in your design stage. Now next is infrastructure as code. So you should be using tools like terraform, helm, anible to do the deployment and configuration. The next is roll back and roll forward playbooks. Roll back is how you will roll back the application. You should have strategies in place. Roll forward is if let's say you have deployed the application and you can correct the error quickly. How should you be doing that? that is called roll forward. Then next is operate and maintain and this is the operations phase of the application. So here you will be dealing with monitoring and alerting. So you should have an observability posture that will ensure you can operate and maintain the application properly and you will be patching the resources, upgrading the resources. You will be taking care of the DR in case something fails you will be restoring it from the backup incident response and scaling. All these things will happen in the operations phase. And the last one is feedback and improve. I want you to know that this is a critical phase. This is where you collect the mistakes that you have made over the past. You make a collection of that and then you also take feedback from the users. Users will be telling you what features do they want, what else would they like to see in the application, what are the problems that you are facing. And then you as well as devops folks would have proper observability posture to know what all are the metrics that were not behaving properly. So you will take that into account. You will be discussing those things with your development teams and all these things will be jotted down in feedback and improvement section. And once you have done that then you will again move to the requirement gathering phase. You will collect whatever you have gathered. You will again design and this process will go on. No application is perfect. This process continues till the application is alive. That is what modern application development looks like. Now before we move ahead, I quickly want to discuss waterfall model and the agile model. So when it came to waterfall it was sequential phases feedbacks came late risky big bang releases. So what used to happen was a work was given to a software development team. They would continue working for 4 months, 6 months over a year and then they will go to their client to show them what they have built. And the client most times would have said I didn't ask for this sort of application. You have not done it right. Then the entire process had to be repeated. So this resulted in risky releases and this was not acceptable. So that is where agile and devops come into picture. In DevOps you make small frequent updates with rapid feedback. Hence the deployments are safer. You discuss with your clients that this is what we are going to do and then you deploy it. If you take example of big e-commerce website like amazon.com, they would be pushing hundreds of changes per day. >> [snorts] >> And why they can do that? They can do that because first they are using the agile and devops model for SDLC. So what I'll do is I'll take you to the GitHub repository of this course and here I am. I'll go to Jenkins basics to production. I will go to day one here. And in day one I want to discuss waterfall versus agile. And here you can see the differences. Clearly delivery big bang release at the end small frequent incremental releases. When we talk about agile DevOps feedback comes late feedback is continuous here. Flexibility is rigid hard to adapt once requirements set. This one is adaptive. Risk is higher. Issues found late are costly. In the agile and devops methodology we say fail fast. fail fast in development so that we know this code or this application is not working as expected. You fix those changes, you again deploy, you again deploy until you fix the problem permanently. So that is how agile and devops work. Team collaboration siloed. This is crossf functional. So dev, QA and operations all work together. examples year-long banking system projects agile devops Netflix Amazon deploying updates daily I hope this section is clear to you now let's move on to next section that is programming languages now firstly I want to take a moment to explain you why I want you to know these things see you as devops and s engineers will be working with applications all the time you will be deploying them you will be rolling back and so on. Hence you must understand what programming languages are used when we talk about applications and how these programming languages are segregated. And I will tell you if you do not understand this you will not be able to understand automation tools that are used in the build phase of SDLC and the ownership of build phase is with DevOps folks. So let's understand programming languages. When I talk about programming languages, they can be categorized into two. Compiled and interpreted. Now let's discuss compiled languages first. Translated before execution to machine code or to byte code. So if I talk about compiled languages, let's understand what these are. Compiled languages requires some sort of compilation. Now what that compilation will do is it will take the source code and it will convert that source code into a nonhuman readable format. Now that nonhuman readable format could be machine code or it could be byte code. So if I talk about C, C++ and Go, they use machine code. If I talk about Java and C they use byte code. So when I talk about machine code, they do not require any runtime. What is runtime? I'll come to it. But when I talk about byte code, a runtime is required. For example, if you have a Java application, then you would need JVM for that Java application to work properly. Which is why you would have seen that if you install anything that requires Java underneath, you first must install the Java runtime which is JVM. Now before I start explaining this, let's understand these terms. What are these? First is artifact. Like I told you before, artifact can be thought of as a build output. Now that build output can be dot jar. When I talk about Java, it can be war. War is also associated with Java. It can be.exe or it could also be a Go binary. Now what are runtimes and interpreters? These are execution engines. Example JVM, Net CLR, Python, NodeJS. No, Python and NodeJS are interpreted languages. But I will explain a small thing right here. So when I deploy a Java application then I require a JVM runtime and if I am running a Python application then I will need a Python interpreter. Similarly if I'm running a NodeJS application I would require a NodeJS interpreter. Now we will discuss this deeply in a later section but for now I just want you to have a basic understanding. Then there is middleware for extra app services. Now there are specific formats that are related to Java that are war and ear you don't see here but we'll discuss that in a little while. Now they require special app services. Now these apps could be Tomcat, JBoss or Web Logic. Now what exactly is middleware? Middleware is a layer of software that sits between the application code and the runtime and we will see this in a little while. Then at the very last it is dependencies. Now dependency could be any dependency. If I'm having an application, my application could be dependent on a configuration file. It could be dependent on a specific version of something. Hence, anything on which my application depends on can be thought of as dependencies. What I want to do is I will take some time to specially discuss Java. And why I am doing that? Because Java and Python are the most popular programming languages that you as DevOps folks will be dealing with. So if I move to the right of the screen then the artifact format for Java could be jarw and year. Now firstly needs runtime all of these require JVM runtime but only war and ear require a middleware. Mostly you will see jar. So you will not be deploying a middleware. But in case your application requires Tomcat, Jboss or Web Logic then you would be generating artifacts in war and ear format. JAR is simple Java archive. WAR is web application archive. E is enterprise archive. And as the name implies this is used in enterprisegrade environments. And you can read the GitHub notes if you want to know more about this. But for now I will leave this here because this is the highle information that you need. The key point here is when you are talking about jar you don't need a middleware but with war and ear you need a windowware but JVM is required in all these three formats. now requires build stage and in parenthesis you see compiler plus tools. Now when I talk about compiled languages as the name implies compiled languages they require a compiler that is what we understand. So compiler will convert the source code into nonhuman readable code which is machine code or byte code and machine code is for these languages. Bite code is for Java and C. Now I will move to the left of my screen. So there are different compilers for different compiled languages. For Java the compiler is called Java C. For C it is GCC C lang C++ this. Go this. There are build tools at your disposal. Now we will see why these build tools are needed later but for now I want you to understand that build tools do not just invoke compilers they handle dependencies packaging tests and artifact publishing. See if you have written your source code in Java then there could be multiple dependencies that must be handled for your source code. If you are on Mac, you have homebrew which is a package manager for your Mac. Similarly, these build tools act as package managers and they resolve the dependencies that are there in your code. For example, Maven is a popular build tool for Java. [clears throat] And this build tool will not just invoke the compiler, it will handle the dependencies, packaging, testing and even artifact publishing. And we understand that artifact is the result of a build output. So Maven and Gradel are popular build tools and we understand this artifact format could be jarw and e dot class is not widely used. It is a very niche use case. Then there is C and you can read about what are the compilers and what are the common build tools. But here I am telling you that when I talk about build tools, build tools are not just for compilation. They can do a lot more than compiling a compiled language. Now let's move to the right of the screen to see other points. Faster execution CPU direct. Now why there is faster execution? This machine code that is non-human readable or byte code can be easily understood by the CPU. But just a caveat here, bite code runs on a runtime like JVM. So there is some sort of translation that this JVM does before sending the inputs to the CPU. But at large compiled languages are faster than interpreted languages. Now portability. If I talk about containerized, we know that containerization in general is best for portability because you package everything that the application needs in the container image and wherever that container image runs, your software will run there. But when it comes to non-containerized these artifacts are specific to OS and CPU plus they need correct runtime and if there is a mismatch between these then the software will not run properly and this is understood. So if for example a Java application is designed for Mac and I try to run it on Windows, it will not work. So the it is OS and CPU dependent plus needs correct runtime. What if I am trying to run an application in a machine that does not have JVM? It will not work there or maybe it needs a specific version of JVM then also it will not work. Now the key point is code is hidden. So as we understand that these tools the build automation tools like Maven for Java will convert the source code into byte code and if it does that then that code cannot be read by humans because it is binary only. Now examples of compiled languages are Java, C, C++, Go, Rust and there are plenty more. Now let's discuss interpreted languages executed by interpreter at runtime. So understand previously when we were discussing compiled the source code was compiled into a nonhuman readable format but here these are not compiled prior. What happens is you write the code and then there is a interpreter that does the execution line by line. So there is no explicit build step here. Previously there was a build step which is why we had automation tool come into picture and do the build for us. In interpreted there is no build step and the execution is line by line by the interpreter. Portability, containerized workload, of course they are portable, but non-containerized workloads, for example, if you are trying to run a Python application in your laptop, then your laptop must first have a Python interpreter and all the dependencies must also be met. So for example, if your application requires Flask framework of Python, then that must be installed. version mismatch and if you already have flask maybe you do not have the version that is needed by my application. So the version mismatch risk is always there. Now this is an important point code visible. So if you have a Python application when you share that application with your user then the code is visible to them. Examples of interpreted languages are Python, NodeJS, Ruby. Now let's move to the next section. See, I want you to know that you as DevOps engineers will not just be deploying resources onto containerized workloads. You will also be deploying resources or your applications onto non-containerized workloads. Now in this section I want to give you a flavor of how compiled and interpreted languages will behave in both of these environments. And I am telling this specifically from the point of view of the build step. Let's scroll down. First let's see what happens to the containerized world and we are talking about compiled languages first and we know compiled languages there is a build step where you do the compilation and what is compilation changing the source code into a nonhuman readable format. So first you see source code then here you have tools like Maven, Gradel, make for different programming languages. Maven and Gradel are predominantly used for Java. So let's say our source code is in Java. Here we have Maven. Maven did all the things for us. So Maven handled the dependencies, packaging, testing and then finally artifact publishing. That is what you see here. Then the artifact was generated and let's say the artifact was generated in dot jar format. What is the next step? We are talking about containerized workload. So when when we talk about containerized workloads in the next step we'll be creating a docker file. Now here is the docker file. What I'm saying in this docker file is from open jdk. Why I am mentioning open jdk? Because understand for this jar to run I need the JVM runtime and open JDK is the base image that has that JVM runtime available which is required by my jar file and in this step I am copying the app dot jar file and here in step two I am building the container image. And once the container image is built using this docker file, we can finally deploy it as container. Now I want you to clearly know that when I'm talking about containerized workloads, it is a twostep build. First I am building the code and then I am building an image. So here when Maven was used to publish this artifact, I copied this artifact in my docker file and then an image was created which had this artifact. Now let's see how non-containerized workloads behaves when we talk about compiled languages. Here everything remains the same. It is just we do not have a docker file. We are deploying onto a VM. But this VM must have everything that this needs. Now what do we need? Firstly, we need a runtime. If we are deploying a Java application, we need a JVM runtime. Then second is middleware. Now if we were receiving the output in war format then we would also require a middleware and that middleware could be your Tomcat or Job Boss. Now that we have this understanding let's see how interpreted languages will behave like Python. So if I move here I have containerized workloads and here I have interpreted languages. See the source code is this and I'm directly moving to the creation of docker file. There is no build step that involves compilation or packaging. What I am doing is I am saying this docker file from Python 3.11. Here why I am using the base image of Python because I know for my Python application to run it requires an interpreter. And why is interpreter required? So if I move here, we learned here that when I talk about interpreted languages, they require an interpreter at runtime. That is why if you want to run any Python-based application in your laptop, your laptop must have a Python interpreter. So I'm saying from this and this image will have the Python interpreter. I'm saying copy source. So I'm copying the source code into my docker file and the resultant container image will have this source code and here I'm installing the dependencies. I'm saying pip install-r requirements.ext text and this file will essentially have all the packages that I use and pip is the package manager for Python which will install all the dependencies and I'll have my image build here and then I can deploy. Now let's contrast this with how non-containerized workloads will behave. So here I have the source code. Now the source code could be in any interpreted language. Here it is let's say py for python. Now we deploy it onto the vm and here are the must have interpreter must be there. So this vm must have python dependencies. Dependencies should have been installed using pip npm or gem. pip is for python. npm is for NodeJS and gem is for Ruby. Last one is isolation. Now this is an important piece. Okay. Venv is virtual environment for Python. NVM is node version manager. RBNV is Ruby environment. I want you to know that there could be multiple applications deployed onto your VM. One application might require a specific version of Python. Another application might require a different version of Python. In that scenario for Python, you can use virtual environment. Now, what this will do is this will allow you to have different versions of Python for different applications and similarly you can do this for NodeJS and Ruby as well. I hope you have understood this. Now before I let you go, I want you to know one more thing. You understand that the build process is automated and build process is automated using automation tools like Maven, Gradel or for C you have make, CMake and so on. So what if these build automation tools were not there. So for compilation it is fine. You could have done the compilation but what about dependencies? What about packaging? What about tests? What about artifact publishing? This would have been a chore for you. So if I move to my GitHub repository, what I have done is I have one section where I am defining why build automation matters and it is there because you don't have to have that classic problem works on my machine. So whatever artifact you generate are reproducible, traceable and environment agnostic whenever you are using build automation. So you want whatever artifacts are generated should work the same way in dev staging and prod. And this has version logged as well. So results are predictable and safe to promote. Now before I let you go, I want you to know one thing. We have discussed SDLC and these are the phases of SDLC that we discussed. I want you to understand that there must be some tool which could help us with these all things. What is that tool? And the tool that will help us with all these things are CI/CD tools. And in the next lecture, we will explore this in a detailed way. So for now, that's a wrap for day one of our Jenkins basics to production series. Today we laid the foundation by breaking down SDLC phases, contrasting waterfall with agile, exploring compiled versus interpreted languages and understanding artifacts, runtime dependencies and build processes. In the next lecture, we will zoom into continuous integration, testing, delivery, and deployment and then start connecting the dots on why Jenkins is such a popular choice for automation. If you have any questions, feel free to ask in the comment section and I will reply. If this helped, do consider liking, sharing, and subscribing. It will mean a lot to me. Thank you very much. Hi, I am Varun Jooshi and welcome to day two of our Jenkins basics to production course. In this lecture, we will first discuss Git and how teams collaborate with commits, branches and pull requests. Next, the continuous practices, continuous integration, testing, delivery, deployment and monitoring. Then the two production styles you will often see git flow-based branching and trunkbased branching and how promotions flow from feature to dev to stage to production. Finally we place Jenkins in that path as the orchestrator and reinforce the principle build once promote by digest. This lesson uses simple visuals and concise theory that sets upcoming Jenkins demos. Please give it your full attention. Together with day one, it forms the base for the rest of the course. By the end, you will understand the path from a push to a production release and exactly what Jenkins automate. Let us begin. So let's start with Git branching the essentials for CI/CD. What exactly is Git? Git is a version control for code. Now I want you to imagine that you are a developer and you are writing code and also testing it in your own laptop. You wrote a code, you tested it, then you performed few more changes and you tested it. Then you performed few more changes but this time the testing failed. Now you want to revert to the previous stage. How do you reach that code? Now if you are maintaining four versions of the code, I do not want you to manage four files, one file for each version. We want some way via which I just have to manage one file and there is some system that is ensuring that the history of important junctures in the development phase of my application are captured properly. And this is where git comes into picture. And whatever I'm saying the junctures of your application that you want to be saved, these are called comets. So essentially a comet is a local snapshot of changes. For example, if you have 10 commits, you essentially have 10 local snapshots of those changes and you can go back to the snapshot that you want to work with. That is how git simplifies this. And you see here DVCS. This stands for distributed version control system. That is what git is. Why are we calling it distributed? Firstly because you have the entire code base in your laptop and then you also have a code base in somewhere remote. Vun why do I need the code base to be in remote? Because what you want is collaboration reviewing and CI. We will come to CI later which is continuous integration. But if you want your fellow developers to collaborate with you, then you must have a centralized location from where the code can be accessed by all your team members. That is why we are saying this system is distributed. You have your changes locally and then you also have a remote where your code base is also being managed and anyone who wants to collaborate or review your code can do it from the remote. But Warun, what if I am doing some changes and those changes are not yet reflected in the remote? Then wouldn't the other developers who are accessing that code will be accessing a previous version? Yes, you are right. That is why you have something called push. So if you have written a code and you want your teammates to see what is the latest change that you have done in the code then you will do a push send local commits to the remote and what if a new developer has joined your team. So if you see in this diagram here, you have developer one and developer two is the person who has recently joined your team and your team is working on application one which I have spelled wrong here. This is a repository for application one and we are calling it remote. We call this local. Whatever you are doing in your laptop is local and whatever is happening in that remote is called remote and that remote location what are the possibilities for that remote location we'll see in a little while. But if developer 2 joins and developer two wants to see what is happening in the codebase of application one, dev two can perform a get clone first and then if developer two wants to see the recent changes whatever dev one is pushing or any other developer is pushing then dev2 can just perform a get pull and he will have the latest changes available. in the local copy that is being maintained in his laptop. But Warun what if developer 2 has some changes to propose? The same what dev one is doing. Dev2 will perform the changes and push it so that all the other developers can see the changes that are being sent to the remote by dev 2. As simple as that. This is what git is doing for you. Now in this lecture I won't be covering the commands because we'll be doing thorough demos as we move ahead with this course. This lecture is purely conceptual because I want your foundations to be so strong that rest of the lectures are a cakewalk for you. Now the next is where to host your git repos. Understand that when you are sending changes to your remote, you want that remote to be highly available because you cannot trust your laptops because your laptop is not highly available. If your laptop crashes, God forbid, your data is gone. Hence, you cannot just rely on your laptop when you are talking about a critical application. You have a remote and that remote must have provisions that allows high availability and they must have an SLA so that you as developers and DevOps engineers know what should you expect from the platform that is hosting your git repository. Now application one repo that you see here this is known as a repository when we are talking about git. Now there are various options you have github you have gitlab and azure repos. So you can always use the functionalities provided by your cloud provider as well. But I want you to know that AWS code commit and GCP's CSR are legacy for new teams. If you are existing users, you may use it for some time I believe, but eventually you will have to migrate if you want to leverage any new features that other competitors are providing. So you have two options here. cloud hosts which are GitHub, GitLab, Bitbucket and there are more of course then there are provider suites which only Azure is there which is now providing Azure repos then there is selfhosted if you do not want a public service like GitHub GitLab you can have it privately you can create a GitLab CE or ei Garrett all these allow you to use selfhosted repository hosting platforms. I want you to understand one thing. If you are self-hosting, you must ensure that your solution is highly available. Now let's talk about what are branches in Git. A named line of work. If you see here, there is a main line and main line is the one that has all your code right now. Let's assume that. And then if you want to introduce a new feature in your application, for example, if I'm managing a banking application and I want to add a new feature which will allow users to top up their loan, then what I will do is I will create a feature branch and that feature branch I will name loan. Now I want you to know from this stage itself that you can have multiple feature branches. If you are introducing multiple features, you can have multiple feature branches and in each feature branch there could be multiple developers working. So broaden your imagination from this stage itself. So that whatever we learn fits in and main is equal to the source of truth. So if I go to my GitHub repository, I'm going to my browser here and you see we have this Jenkins basics to production GitHub notes where I am capturing all the nodes for this lecture and you see I have a branch here that is named main. Now some call it main, some call it master but typically you will see it main and often this name persists. You do not rename this to something else just for consistencies sake and then you can create multiple branches if you have a requirement for that. When you are working with a production grid application you will often see there are multiple feature branches created based on your requirement. And again do not limit your imagination. I only have main here. There are certain implementations where you will see there is a dev branch, there's a stage branch, there is a release branch, there is a prod branch and so on. It is what your application architect decides and then based on that you work on that project and again you could see multiple branches based on specific applications. Then what is a PR? What is an MR? Firstly, they both mean the same thing. There is a lot of confusion. PR is pull request. MR is merge request. And I prefer the term merge request. But GitHub is more popular. Hence PR term is more popular. But I like MR more because it conveys the message within its full form itself that what it is doing. What is a merge request doing? For example, you were working on your feature branch here. You created your feature branch from this stage. You performed your changes. You performed your commits. This was your first commit. Then this was your second comet. And then you performed your respective commits. And then you decided I want this feature to get merged with the main branch because now my application is ready to test whatever feature I was working on with the main application. So you perform a merge because I want you to understand at this stage itself that feature branch does not hold the full code. Your full code right now is in the main branch. You cannot perform end to end testing of this until and unless you merge it with your main branch. And once that merge is performed, then you can test the entire application along with the feature that you have recently introduced. Now here is a catch. Should I be allowed to perform a merge in the main without any tests? No, you should not be allowed. Hence, you have the concept of protected branches and status checks. So, what happens is whenever I say a branch is protected, there are certain rules in that branch. And a rule that you would often see is a push is not allowed to these sort of branches. I cannot directly perform a get push in the main branch because main branch has a rule that prohibits anyone to perform a push or a force push. only PRs are allowed or only MRS are allowed and even before the merge is allowed, there are certain checks that are run to ensure whatever I am doing, whatever I am introducing in the main branch will not break the existing functionality of the main branch. If my changes were to disrupt the existing application, then what good are my changes? And this is the main branch that caters my production. I do not want anyone to walk in and merge to my main until and unless I perform certain checks. That's why you see here PRs only, no direct pushes, requires reviews. Now in case you are deploying to your production then you might want that someone manually reviews it and I use the word might and you will learn as you progress with this course why I am saying you might need a manual review here. Last is CI must pass and be up to date. Now imagine a scenario with me. So here is my feature loan. Let's say developer one was working here. Developer one opened a PR and then there is a developer two who was working in let's say some another feature and developer two also raised a PR because she was also done with her work. But what happens is let's say her PR got executed first because she was making a small change and then this branch had a new commit and that commit is here. Let's say I'll copy this. I'll paste this. There is a new commit. So from my PR's perspective I'm not dealing with the latest commit of the main. Hence this is not a valid design which is why I'm saying here CI must pass and be up to date branch must be up to date. So whatever I am doing should be done with the latest commit in main and latest commit that is successful because this merge will only happen when all the CI checks will be performed. And if you are hazy about these things, do not worry. I have a diagram later in this section which will help you solidify these concepts. Just create a mental picture right now. Whatever we are discussing, we will be discussing it diagrammatically as I progress with this lecture. Now last is why are we studying it? If the topic of the lecture is CIC CD, firstly whenever there is a push or a PR, there is a CI build that starts and we will dissect this why this matters as we look into the nitties and gritties of the CI process. CI is continuous integration status gates the merge and what is this status? This status is status checks. I will only allow this PR to be approved when my PR status is green. And what on what all things does the PR status depend? It could depend on whether the CI run was successful or if there is a specific file in a specific location. There could be hundreds of permutations and combinations based on which I will approve this PR. Lastly, CD promotes the build artifacts to dev stage broad as you might understand. So, there are two terms CI and CD and in the subsequent section we will be zooming into these terms. I hope you have a good understanding of how git fits into the larger picture. If not, do not worry. We will learn more as we progress with this lecture. So, I'll scroll down and this is what I want to discuss now. CI and CD, continuous integration and CD is continuous delivery or deployment. But I also want to discuss two more terms that are continuous testing and continuous monitoring. These two also work from start to end. There is also continuous security because we want everything that we are doing is secure. So whenever we are doing certain steps in CT we also integrate certain security level checks so that the application that we are deploying using the pipeline is secure to run in production. So with that information let's start this discussion of continuous practices in DevOps 10,000 ft overview. I want you to understand these things at a very high level. so that rest of the lecture is easy to understand. First is continuous integration. The first is build and test every push PR automatically. Now, right away I want you to think of two things. When I'm saying push and PR, that implies I'm talking about a git repository, right? And when I'm talking about build and test, I am talking about the build stage. And if you remember while we were discussing the build stage in our previous lecture, we know what happens in the build stage. If I talk about interpreted languages and you want to deploy your code onto let's say a containerized environment, then your build will be a two-step process. First, you will be compiling the language. Let's say if it is Java, you will be let's say creating an artifact in dot jar format and then you will be creating a container image out of that. So the build is essentially a two-step process. In interpreted it is just a one-step process. You take the code and you create your container image and then there are plenty of other things that are performed that are related to security. So when I talk about continuous integration, I want you to understand that whatever happens with your git repository and whatever happens in the building stage is called continuous integration. The question then becomes why we are calling it continuous integration because every change that you are performing in your git repository is automatically built, tested and integrated the moment it is shared. So understand these points. Second is fast checks enforce merge protection on the branch. Now it is not that everything that is pushed will be built. There will be certain parameters, certain rules that will be in place. Only if those rules are met only then the build will start. So we will see what those rules are later in this section. And as I just told you compiling, unit testing, quick security, dependency scans, all of these things will happen in the continuous integration stage itself. What are the tools that are used in this stage? Jenkins, GitHub actions, GitLab CI. Do not worry. Once we finish this section, I'll tell you how the story is staged from CI to CM. Then we have continuous testing. Now I want you to clearly know that testing happens across the pipeline and we know these are just logical constructs. These could be happening at all stages. If I talk about monitoring, monitoring happens from start to finish. Can you say that monitoring only happens in this part of the pipeline? No. And same applies for testing and security. And we saw that in day one as well. Whenever we are talking about a continuous design, testing, security, automation, monitoring, all these things, they are happening on every stage of the pipeline and hence at every phase of SDLC. Of course, you cannot perform monitoring when it comes to requirement gathering. You cannot perform security at this stage. But again all these things all these logical constructs are kept in mind whenever we are discussing any phase of the SDLC. Then let's come back here and the next point is ads integration API UI performance security suites. Now at this stage itself I want you to know that testing can be thought of as two-phased process. Okay. First phase is pre-eploy when you have your artifact with you. Your artifact could be the container image or your jar file or any other artifact that results from your build. Firstly, you want means to test that artifact. Then when your application runs using that artifact post you have done the deployment, you want that also be tested. So first you are checking the static things and then you are checking the things that are running. So when I talk about testing you have both of these you have s when I talk about anything pre-eploy and post deploy you have dashed and other related tests for example you cannot perform integration API UI performance tests until and unless the application is running but security suites the vulnerabilities you can start doing these sort of tests from the very beginning itself from the point where developer is writing the code because you know like we discussed in our day one's lecture that there are plugins that are in your idees that are ensuring the code that you are writing is not vulnerable or it is not using any dependencies that possess vulnerabilities. So runs premerge, pre-eploy and post deploy. Last is there are different tools that could be used to do these things. JUnit, TestNG, Cyprus, JMeter and so on. There are plenty more. You will learn about all these as we progress with this course. Then I talk about continuous delivery. And before I start this discussion, I want to differentiate between continuous deployment and continuous delivery. Now continuous delivery is anything that requires manual approval before deploying. So when you think about continuous delivery, think of a person that is there to approve human approvals and gate. So human intervention is there before deployment. Whenever we are talking about continuous delivery then what is continuous deployment? When there is no human intervention that is no human is approving anything before deployment. Now you must be thinking but Vun that's a bad thing. No that's not a bad thing. If there are no humans involved, then you must ensure that your CI, your testing and your deployments in staging and development are so well rehearsed that you do not require anyone to approve before your code is deployed onto production. So again when I talk about continuous deployment auto deploys to prod again prod is the key word. If you are auto deploying to staging or you are auto deploying to development it is not continuous deployment continuous deployment implies when you are deploying the code without manual intervention in production environment. I hope that clarifies any doubts that you had between delivery and deployment. So let's read the pointers now. Keep main always deployable with versioned artifact. That makes sense. And I told you this briefly in the previous stage. Your main should only hold the code that can be easily deployed. Then promote the same artifact across environments. Important point. So for example in development stage if I have a build that resulted in the container image then you should be using the same container image in the staging and in the prod environment. So essentially you did the build of the container image only once and then the same build was promoted onto staging then promoted onto production. So I want you to keep these definitions in mind and again if anything is not making sense right now do not worry we have a diagrammatic section where we'll understand all these things step by step. Next is human approval gates before production that we have already discussed. There are tools that will help you with this. Jenkins pipelines, GitHub actions, GitLab, CICD and then if I talk about continuous deployment, there is auto deploy to prod when all checks pass. This is we have discussed progressive delivery, you have to choose what is your deployment strategy, whether you want to use Canary, whether it is blue green feature flags and so on. And as we progress, I'll discuss all these three briefly. Then there is rapid roll back on failed health signals. You would want to roll back if something goes bad and there must be processes in place that will help you do the same. There are different tools that can be used with continuous deployment and those tools are Argo CD, Flux, Spinacer and there could be more. Argo CD is a popular tool which I will also cover in my channel. Maybe the next course will be on Argo CD itself. Then lastly I want to discuss continuous monitoring. Now we know observability has three pillars. There is metrics, logs and traces. And observability can be thought of from two perspectives. There is an infrastructure perspective where your Kubernetes clusters, your servers, all these things come into picture and then there is application perspective. Now application perspective will cover anything that is application specific that is application performance monitoring is there from applications perspective. So you would want to have all these three things so that you can properly judge the health of your application and your infrastructure. Now we discussed this in detail in our Kubernetes observability section. I will link that lecture as well. If you want to know deeper about observability then you can definitely watch that lecture. So you should be able to visualize health of your application and your infrastructure. Detect regressions trigger incident response. So this is part of your ITSM process. You should have these things in place to ensure that your application and infrastructure is in good health. Tools there is Prometheus, Graphana, Elastic Stack, Data Dog, New Relic. There are many tools and then there are offerings from cloud providers as well. Azure has Azure monitor logs. AWS has the cloudatch suite, X-ray and so on. All these things can be used for APM and also for infrastructure observability. Now if I have to stitch this entire story, CI proves a change is safe to merge. We know that and we will dissect this more as we progress. TT widens the safety net because that is where the testing is being performed. TD keeps releases always ready. CDP that is continuous deployment ships automatically continuous monitoring watches everything and informs the next change. Now what why and what of Jenkins? What is Jenkins doing here? Jenkins is your orchestrator. It is an automation server which will do whatever you ask Jenkins to do. If you ask Jenkins to pick code from location A, paste it to location B, it will do that for you as well. But we leverage Jenkins with CICD and this entire lecture will tell you how. So as we progress we will see where Jenkins fit and why in my opinion this tool must be learned by any aspiring CI/CD engineer. So let's come below before I start discussing the pipeline I want to discuss branching strategies and I want you to know that we are not talking about environments here. environments as in we are not talking about your development environment or your prod environment here we are talking about branches. So when I say gitflow based CI/CD it works on the premise of environment branches. Now environment branches as in there could be multiple feature branches and there will be a dev branch, a stage branch and a prod branch. And as you understand the code will be promoted. First the developer will do the changes in the feature branch. Then a PR will be created to the dev branch and from dev branch the code will be promoted to the stage branch. And from stage branch the code will be promoted to the prod branch. And similarly codes from these respective branches will be deployed to the respective environments. For example, code from the prod branch will be deployed onto the prod environment. Code from the dev branch will be deployed onto the dev environment. So keep this in mind. The second one is trunkbased. Now trunk based is you have multiple feature branches but there is only one main branch and that main branch is the single source of truth. So what happens is there are multiple checks which allows you to deploy code from that one single main branch to different environment. So you can use that single branch to deploy the code onto the dev environment to the stage environment and to the prod environment. But Wun how does it help? Isn't there a rule of thumb that I can use? The rule of thumb is if your changes are very frequent. So if I talk about a busy application that sees 100 changes per day, 50 changes per day, then they would probably be using this approach because this is used when you want to fasttrack everything. And Git flow is typically used h when you have a stable application. Maybe you are performing changes once a week or twice a week and so on and again these things are not written in stone. You could be starting with this strategy even when you are performing change once a week or once a month. It is dependent on application and these are not the only two strategies branching strategies that you would be using. you would see others as well but 90 95% of the projects would be using these two branching strategies which is why I want to discuss these and again once you understand these two rest of the branching strategies will become a cakewalk for you so let's quickly read these points multiple longived environment branches we have just learned that dev stage pro lines and then you have feature branches CI triggers PR are between environment branches. I just told you that in the introduction itself and let's contrast whatever we have read with trunkbased single trunk main as is the source of truth short-lived feature branches only and then you have the main branch where a PR is created CI triggers PR into main merge result that's fine build only happens once this is interesting okay so when you are using multiple branches then also So the artifact that is generated artifact as in the container image or the jar file or both they are only generated once in both of these scenarios and I do not want to explain this to you right now we'll explain this in the diagram section governance strong reviews approvals and traceability now since we are using different branches for different purposes for different environments it is self-explanatory that this approach approach has stringent controls and is good when it comes to traceability. But having said that, do not think of trunkbased as any less. The checks are lean. But again, it depends on what you configure it to have. So for example, maybe when you are deploying changes to dev, you do not have those many checks. But when it comes to prod, you have a checklist of 150 checks that must be performed. So that makes trunkbased really secure. So it depends on how you have configured your CI server to interact with these branches or how you have configured your CI server to perform the checks. But all tools have you integrated with your automation server which will ensure how and when the changes are deployed onto your production staging and dev workload. So the control is in your hands. How you configure will determine what level of governance each of these approach will have. If you do not have any governance in gitflow based then again this will create chaos. It's not that if you use this there will be no chaos because unmanaged pipelines are a nightmare for a devops engineer. The next point is tradeoff more merges branch drift risk tradeoff is needs small PRs solid tests and we'll see this in the diagram. use cases, regulated apps, release trains, use cases, microservices, SAS, rapid delivery. Now, here is the mental note. This is important. The first line is important. In both styles, you build once and promote the same artifact. So, the artifact is not generated three times for different environments. It is only generated once. Then there is gitflow uses environment branches. Promotions are PRs between branches. Dev stage prod that deploys that artifact. Trunkbased keeps all the code in the main branch. Promotions update environment configurations. For example, there will be a different configuration for dev and there will be different configuration for stage and pro so on to deploy that artifact. No environment branch merges. So there is only one branch main that is the source of truth. Then there are multiple feature branches. Now let's discuss gitflow based CI/CD environment branches. So we will first be discussing git flow where we have three branches like I talked dev stage and prod and we have multiple feature branches. Here first I'm going to show you the transition from feature to dev and then in the next diagram we'll see how the artifacts or how the code gets promoted from dev to stage. Firstly flow will be feature first then to dev then to stage then to prod. This is I'm calling a beginner's flow because I have not added all the bells and whistles here. There are many more functionality that could be leveraged but I promise you if you understand this flow whatever flows that we are discussing in today's lecture any CI/CD pipeline and from after this lecture itself you will be able to make sense of those because these concepts are the foundations. So let's see what we have here. We have a developer here. developer has written the code. Developer commits. Now commit happens in the local branch and then when you do the push it is only then the code goes to the remote. So developer performs a push to the feature topup loan. And again like I discussed before I am calling this top up loan because let's say this developer is working on a feature that will allow users to top up on their loan. For example, if they have a two lakh loan right now they can increase that to 2.5 lakhs. Second step is opens PR to dev. Again I told you that this developer cannot directly push to dev because dev branch is a protected branch and you see a lock symbol here. Again I want you to clearly know that all the feature branches that gets created these are the branches where your developers would work. So they will be able to push directly onto only these branches and rest of the branches they will not be able to directly push because they are protected branches. Now as soon as a PR is open to dev a CI runs. Now understand we are not saying that the PR gets gets approved or whatever was here is merged onto the dev. We are saying a CI runs and this is your CI pipeline. And here are the rules that decide when can this change be merged with dev. Firstly, this is a protected branch. It says that PRs only no direct commits. This part we understand. And then there's a second point that says require status checks to pass. And here our status check is only one that is CI must be green. So what I am saying is when I run this CI pipeline only when this CI pipeline gets successfully executed and I have a green here only then merge PR into dev. If this fails then tell the developer that fix the errors that you see in the logs and then repush and the CI will rerun. So we are clearly saying do not approve the PR until and unless the CI is green and if the CI is green then merge the changes onto dev. So let's see what is happening now. Here what happens is CI tests dev plus feature dev is unchanged. So what this will do is it will take the changes that the feature branch has and it will take the latest commit from the dev and run this CI pipeline. If I want to know how this feature will impact my application or how this feature will integrate with my application or whatever I have coded will it at first integrate with the app code or not I need to test this with the latest commit in the dev because that is the main application. So when I do that what this CI will do is it will only perform the changes on the feature plus it will take the the code that is in the dev branch and dev remains unchanged. Now we know what CI pipeline will do. It will check out first from the GitHub repository. It will check out the code and then it will build and test it. I want you to know that Jenkins is orchestrating all of these. You will be configuring how to reach your GitHub repository in Jenkins. You will be configuring what tests to perform, what builds to perform in your Jenkins. You will be defining where to deploy in your Jenkins. So Jenkins is the orchestrator that will make everything happen for you. So in the third step we perform this then the status of the PR it will either be green or it will be red. If it is red let's say if the build fails because of XYZ error then the merge will be blocked and the developer will have to fix the code repush and rerun the CI. If it succeeds, we will do the merge and we are also deploying it onto our compute. Now I want you to know this compute could be your Kubernetes cluster. This compute could be your virtual machine or this compute could be serverless. I am saying all these three here because at this stage of your learning I do not want to bombard you. But in next section in the next diagram we will make this specific to Kubernetes because it will involve more nuts and bolts again. So let's read what is happening. CI runs on the PR tests dev plus feature. Green enables the merge. Red blocks it until you push a fix. So until and unless this is green the PR will not be merged into dev. After merge you may autodeploy to the dev environment. Now I want to introduce something that will help you in designing and thinking in a better way. When I talk about dev environment you can use a blue color there. If I talk about stage, you can use yellow there because staging environment denotes pre-pro and it is like handle with care and then prod is typically denoted by green color which implies success, stable and live. So if there are any errors or something that is denoted by red like you see here. So keep these colors in mind. So if you are creating any diagrams use blue for dev, amber or yellow for stage and green for broad. Now that we have understood this step, let's see what happens when we try to go from dev to stage with the help of next diagram. Okay. Now I am calling this a promotion PR. Here we are moving from dev to stage deploy before merge flow and I will explain what this means in a little while and like I told you in the previous section that we'll now be using a Kubernetes cluster hence you only see a Kubernetes cluster here and now let's see what is happening in this diagram. So first is what happened in the dev build. So I oversimplified this by saying that you can deploy into any environment and that is how you would be handling projects. There could be applications which will be deployed onto virtual machines. There will be applications that will be deployed onto serverless and so on to Kubernetes as well. But now we will focus on a Kubernetes cluster. If this were done for a for an application that is supposed to be containerized then let's see what all steps would be performed in the dev state. So here I'm saying what happened in dev build. So the first is build once and push. So what would have happened in the build phase is once the application artifact was received let's say it was a Java application. And if you are not understanding these terms, go and watch day one. Okay. So you have dot jar and based on dot jar, you created a container image and you push that onto an image registry. Now that image registry could be GitHub container registry which I am using or it could be your cloud native solution. So what we have done is understand that we are calling this repository banking loans and then we have something like this here and what are these now typically when you see the tagging convention here this is the commit ID so commit ID is whatever you would have received here that commit ID along with the version of the application so let's say this was version 1.4.3 of the application. Hence, I have written both of these the commit ID and the version of the application. Another point is capture digest immutable. Now I want you to clearly know that if you have not enabled tag immutability in your image registry then anyone can push another image with the same tag and it will overwrite your existing image and that is not something you want. And even if you have tag immutability, it is still recommended that you use image digests when you want to pull a certain image. Warun, what do you mean by that? If you see here, I just want you to concentrate on this point right now. I'm saying the image is this at the rate sha and there is an image digest here. So in production implementations, in enterprise implementations, you will always be using digests when it comes to container images. You will not be using tags in enterprise production environments. Now why is that? The reason number one is these image digests or simply called digests are immutable. You cannot change them. And I want to demonstrate this to you. I'll go to my iterm. And if I press ls, you see I have a docker file here in day2. And if I cat on this and it's a simple docker file. We are saying just from this and echo hello from image. Now let's do one thing. Let's make an image out of it. So I will write docker build- t. I will call this cloud with vos. so that I can quickly push it forward slash let's call it loans and here let's say the commit ID was 777 yt let's say this is the commit ID let's add two more digits here so this is the commit ID now I'll do one more thing here I'll add hyphen t and then I will write here version 144.3 let's say and then I will again add hyphen t. I will paste that again and this time I will write v 1.443 and then I will add a dot because I want to tell that my docker file is present in the current working directory and this is my build context. I want you to clearly know that I am creating a single image here and I am adding three tags to that image. Tag number one is of my commit hash. Tag number two is of my commit hash along with the version of the application. And then the third tag should just be of the version of the application. Let me just quickly correct this. So I will remove this. And the third tag is of just the version of the application. But Vun, why are you creating three tags? So let's understand this. When I talk about version tags, these are used by a product QA and support so that they can map incidents to a release quickly. So these are great for change logs and dashboards. If I talk about let's say commit tag which you see here, this one is a commit tag because here is the commit ID. Then these are used by developers and sRes so that they can map an image to the exact commit. So if you see this you exactly know which commit was done to create this version of application because you would see what changes were made to the code and the entire codebase when you see that comet. Now what is this combined tag used for? Now combined tag is best for both in one glance. You get to know the version as well and you get to know the commit ID as well. But in my opinion creating this tag is of paramount importance because you see both the things at one place version at one place and also the commit ID so that you can directly check what was the code like when you were in this version of application because you have the commit ID with you. Now let's get to the crux of it and build this image. I'll press enter and this has started building the image and it will tag this as well. So if I run docker images, I see that there are three tags associated with my image. The point I want you to concentrate on is the image ID. So understand the contents of all these tags is the same. Hence the image ID that you see is also the same. Now image ID is not same as digest. You will only get the image digest when you push this to your image registry. So my image registry here is docker hub. So let me push this to docker hub so that I can show you the image digest as well. So I'll write docker push. I will write hyphen a. I'll tell you what hyphen a will do. And here I will write cloud with varosh and it is loans. Now what this will do is this will push all the tags to dockerhub. I'll press enter and this has started doing its job and along with this this command will also show me what is the image digest. So let's wait for that. And you see all these digests are same. And if you want to look at it docker images um I'm forgetting it is hold on digest docker image hyphen h I want to grab for digest sorry docker images h yeah it is digests hold on docker images digests and here I can name my image cloud with varosh loans I want to check it for this. So if you see the digest is exactly the same. So even if someone changes these tags, if I do not have let's say tag immutability enabled then this digest will always remain the same and this digest is same because all these tags they are holding the same content. Even if there is a slight change in the image this digest will change. So understand this point in production scenarios you will always be using digest to pull the images. So let's go back to our browser and I want to show this to you in the dockerhub console as well. So I'll refresh this. I'm in the repositories. I'm in my cloud with VJOS account and you see the loans is here. I'll click on this and if I go to tags you see I have three tags. version tag. There is the commit tag and then I have a combine tag here. But all of these they have the same digest. And if I click on this I will get to see the entire digest. And this is the format of the digest. If I write this and then at the rate this digest then it will pull this image itself. So I hope this point is understood. Now capture the digest publish manifest.json Vun why are we doing this? So in the build stage you are building an image. I want you to understand and this happened in the dev build. Okay in the dev build now we are just promoting dev to stage. Now in the dev build understand that we built an image and our registry could be holding multiple images. How do we tell the deployment part of our CI/CD that you have to use this image for deployment? There must be a file which will have all the information that my Jenkins can use to deploy my application and that information can be provided using a file. And that is why in the dev stage itself when the build happened and my our Jenkins which is our CI/CD pushed the container image to our image registry which is GHCR in our example it created this file for us. Now this file can be created anywhere. It could be in your S3 bucket. It could be in a GitHub repository or it could be part of the PR request. But I want you to know that your Jenkins server should have access to that file because once Jenkins server have access to this file, Jenkins would know what to deploy because like I said there will be plethora of images in your image registry which could have multiple digests but we want to aim for the digest that we are looking for. And here you see I have added all this information the time tags the all the tags commit sha version digest and the repository. So I hope this makes sense to you. All this happened in the dev stage itself in this stage itself but I did not want to complicate things that is why I didn't show these things here. So now let's see what actually happens. So first is opens promotion PR to stage. We are calling this a promotion PR. There we were just calling it a PR. Mind the nuances. Look for the nuances. Opens promotional PR to stage. Now as soon as the PR is opened CI runs it is like before itself. Now when will the deployment happen? So let's see what are the branch protection rules and what should happen for the code to merge successfully. When will the PR be approved? So firstly PR only no direct pushes. Second is dev run green for the promoted commit. So this pipeline should have been successful only then you can move that artifact or that code to the staging stage. So that's what we are saying dev run green for the promoted commit up to date with base include latest stage and I told you this the stage should be up to date like we discussed before there should be no commits that were performed after this PR request was created in the stage branch. Fourth is require these statuses to pass. What is pre-flight? Pre-flights are part of the CI itself. Then there is pre-flight config deploy to stage. Pre-flight manifest as in this manifest must exist. So CI is ensuring we will only merge this when there is a pre-flight manifest and this is the manifest. Pre-flight config. What is pre-flight config? It is these things. For example, Helm lint should be successful. Helm template should be successful. All these are performed in the CI stage itself. And only when all these are successful, then the PR is merged. Then we are saying deploy to stage, stage smoke, stage integration. All these tests we have discussed before. Lastly, once all these are successful, then I want at least one person to review this. It could be your TL, it could be the QA team or it could be the owner. Understand this manual review process is optional. Some might not have this. Now I am not sure whether you have noticed it or not but here we have the deployment step before the PR merges and when we were discussing feature to dev flow we had this at the very last. Now first I want to explain you why this is the case when I'm talking about staging. Staging is like prepro. Whatever is there in prepro, you want those things to be extremely perfect. You want the deployment to be successful. What if the CI pipeline succeeds but the deployment failed and the merge was performed? We don't want that. We want to only perform the merge when the deployment is also successful. So it makes sense because staging is pre-pro and production of course will adhere to the same design. So only perform the merge once continuous integration is green and the CD is also green that is continuous deployment or delivery. Both of these things must be green for my merge PR into stage to be successful. But Vun why is it like this when it comes to feature branch? Firstly I want you to know there is something called fast feedback. The primary goal of the feature to dev flow is to get new code from multiple developers integrated into a single shared environment as quickly as possible. Now waiting for a full deployment to succeed before merging here would create a merge queue. If deployment fails, the PR stays open because understand there are multiple developers who are working in their respective feature branches blocking the next developer who wants to merge their code. Hence in this scenario you would often see that the merge is performed before the deployment stage because again development is there to perform testing left right and center. There will be multiple PRs that will be raised for dev branch compared to devto stage or stage to prod. Another thing is catching failures early. It's meant to be a place where things might break. So it's okay if my deployment fails after the merge as long as the developer who caused that havoc is ready to fix those things. So here the agenda is fail fast and recover faster. That's the reason why you do deployment at the very last. Okay. Now let's continue with this discussion. Now if I talk about CI pipeline here we are doing three things pre-flight, deploy and post deploy. So whenever CI pipeline is created the first step is pre-flight and we know what are the pre-flight steps. Manifest.json should be reachable that is here. Now it could be hosted in different platforms like I told you S3, GitHub or it could be also part of your PR's description and I want you to know that whenever you create a PR provide proper description in your PRs okay what this will do what is the expectation and all of these things second is image must be pullable by digest so all these things CI will verify config renders cleanly now you could be using Helm, you could be using customize. So you would apply those testings in the CI phase itself because you do not want those things to fail when you are in deployment stage. You want to fail fast if at all you are supposed to fail. Here we are saying Helm upgrade install loans. We are upgrading this and you see what are the variables that we have defined. Variables are defined from the manifest.json. Here we are using jQuery. If you have seen the JSON path lecture in our Kubernetes series then this will make sense to you. We are quering this manifest and finding what is the value of image. The value of image is this. What is the value of digest? The value of digest is this and based on this the whole image along with the digest is formulated and you have a deployment. So these things are checked pre-flight. Now the deploy phase refer details from manifest.json all the details are here. Deploy to stage by digest with stage config only. And what is the stage config that will be saved in your values hyphen stagey? So all things are connected. Now I want you to concentrate on the parenthesis as well. No rebuild. So it is not that staging will have its own rebuild and then prod will have its own rebuild. Nothing like that. Whatever was built was built in this stage itself. And that same artifact is being promoted to stage and being promoted to prod. So image is this one by digest not tag. I'm stressing on this point. Use digests in enterprise production grade implementations. Then next is post deploy only things that need a live stage and I discussed this briefly. There are certain tests that needs to be performed in the live running environment and that can only be performed once the deployment is done. So here the smoke test smoke test is quickly checking whether the website is accessible. You are able to login. You are able to click on the tabs or not. All these things are part of post deploy checks and configuring whether your readiness probes your livveness probes and all these things are successful and they check your application application paths application ports all of these things can be checked in this stage and then small integration text one two happy path so if you are applying for a loan are you able to proceed that's one happy path second happy path could be if you want to download your statement are you able to do that that second happy path and there could be several happy parts that you want to verify when you are testing this small integration as in how are two parts of your application behaving. All these things will be performed post deploy. What if there is a failure? In that case you should be able to roll back helm roll back or whatever you are using you should be able to roll back and once the roll back is successful you again fix it on dev build new digest and repromote and then finally let's say all of these things succeeded the CI succeeded properly then the deployment will be done and only when the deployment is successful the PR status will be screen and the merge will be performed. So whatever was in dev stage is now part of your staging code and then if the something is wrong the merge is blocked you fix indev new digest repromote and that's the entire process you follow now let's see what I want to discuss next so next is stage to prod versus dev to stage I want you to know that when you are dealing with stage stage and prod environments. Then when you talk about stage, stage part is heavier post deploy. Okay. But when you have a production application running, it is more heavier on the pre-eploy stages. So pre-eploy is you will have more checks in your CI when it comes to prod when compared with stage because in production you do not want to perform so many tests in your running application because staging is prepro these environments in enterprise applications are similar if not same. So whatever configuration is there in your staging environment is also there in the production environment. So when you have a running application it is suggested in prod you mellow down your testing because you have already performed all that testing in your staging stage but have pre-eploy tests they are more when I talk about the prod stage so I only wanted to talk about this when it comes to the promotion from stage to prod rest I will quickly read it for you but they are pretty much similar if not name of what we discussed just now. Promotion PR references stage proven digest we know plus commit and version. We have seen this no rebuilds promote the same artifact by digest. So whatever container image was created in the dev is used in stage and also in prod. Third is broad branch stricter PRs only approvals config validated. For example, here we only had one manual approver. In the stage to prod part, you could have two or three manual approvers, one your team lead, another your QA lead and then there could be one that is your change manager. So all these things must be in place. CI pre-flights manifest reachable digest pullable both of these we have already discussed then here is flags off so whenever you talk about deploying an application or upgrading an application there are two perspectives there is an infrastructure perspective and then there is an application perspective now we must have means in both of these to control how the upgrade is performed. So when I talk about a production application, you would let's say you are using canary based approach for your upgrades. Now Canary is you gradually roll out the changes for example first only for 20% of the users then 60% of the users and then let's say 100% of the users. So this is how canary is performed and at infrastructure layer you could be performing these at your load balancer controller level or you could be having your service mesh which is helping you with canaries and eventually your deployments will be handling the traffic. So that is how you will cater it from an infrastructure perspective. But how about application? Now when I talk about infrastructure, you cannot control how the new feature is behaving. From infrastructure, you can control the entire application that that entire application will only receive 20% of the traffic first. The upgraded version will receive only 20% of the traffic and then 60 and then 100 and so on. Whatever your permutation and combination is. But when it comes to that specific new feature, you do not have any control over it from an infrastructure perspective. But when I talk about applications, modern applications, what they will do is they will typically release the new version of the application with the flags off. Now flags off, what will this do is this will disable the new feature when you first deploy the application. So first it they will test how the application is behaving with that feature disabled. If the application works fine only then the flags are enabled and these flags are still enabled in a staggered way. So first only 30% of the users will be use able to use that feature then another 50% then 100% and so on. This can differ application to application organization to organization. But what I want you to understand is these things can be controlled from both infrastructure and application level. But from infrastructure you cater to the entire application but application teams can do this per feature level as well. So that is what flags off means. So when you are deploying application onto production you will typically have flags off but in staging these flags are often on at the beginning itself and again you can test various permutations and combinations in staging as well because these things are specific to project application organization. The next is cautious rollout. In cautious rollout you have canaries. Canaries we have already discussed. Blue green is you have two environments and you deploy to the new environment and the previous environment can then be used to deploy the next version of the application. So you maintain two full versions of your infrastructure. So for example, if you are using Kubernetes, then you will have two Kubernetes clusters. When you upgrade your application, you will upgrade that onto the second Kubernetes cluster and your traffic, your users will be served from the second Kubernetes cluster and once there is another release of your application then you would again be using cluster one to run your upgraded version. So this continues this approach is costly but if your availability requirements are like that then you can also use blue green. Canaries is the one which is most popular. In Canaries the shift is gradual. So first 10% of the users will be served with the new version then 30 then 50 then 100. Now what I'm saying is guarded by SLOs's. The strategy in both stage and prod will be same. For example, the strategy in stage will still be Canary, but in staging, you would be deploying it for 40% of the users, then 60%, and then 100%. But in production, you could first be only deploying for 10% of the users, 20%, then 50, then 60, then 80, then 100. So you are more conservative with your percentages when it comes to production post deploy checks health synthetics brief dwell period this we have already discussed responsibility split and we saw this at the very first stage is heavier post deploy prod is heavier pre-eploy if signal fails auto roll back fix and repromote so this is all there was to get flowbased CI ICD. Now let's see what happens when you are dealing with trunkbased CI/CD feature. As we understand from our previous discussions that in this you have main branch that is your source of truth and then you have multiple feature branches where your developers will be working. I want you to know here the source of truth is only main. That is why you see the main branch is being used to deploy onto different environments. Dev in blue, yellow in stage and green in prod. So let's see how this works. So developer commits and pushes. As soon as the push happens, PR is opened and then CI runs. As we know here is the CI. CI will be performing the checkout, build and test. And based on the results of this PR a merge will happen. And you can see here what all things are performed by our CI. It's build succeeds, unit tests are performed, lint format clean, quick security scans, up to date with mains. Now I have deliberately chosen different level of things when it comes to CI but you could be doing all these in others diagrams as well. But I wanted to give you what all are your options so that you understand in a better way. Then we have a PR stage. Here is the result. So if it is green, if all these succeed, build, unit, lint, security scans, up to date, the build succeeds only then the merge will happen. And once the merge happens on the main then you can publish it. Understand that the publishing part is called as continuous delivery, continuous deployment. If there are no approvals that are taken in this stage. Now I want to explain postmerge actions on the main build package once publish image plus digest example this also publish manifest. Now I want you to know that you would be using tools like Helm and customize to do your deployment. So those things are carried forward from the previous discussions that we have done thus far. So here what we are saying is auto deploy no approval in dev stage there is no approval. So reads manifest.json JSON. This is what will happen when the deployment will be done in the dev environment. The manifest will be read and who is reading the manifest? It is your Jenkins server, your automation server that is doing this. It will read the manifest.json deploy by digest and perform smoke and health check whether the application is working fine or not. Health is your readiness and livveness probes. Smoke tests are whether you are able to access the application or perform basic functionality in the application or not. Second is once this is successful we are saying that we can deploy the same digest in the QA environment. But I want you to know that here when will this be run? When there will be a promotion job plus approval. Now approval is as I told before it is optional but typically you would see in staging stages there is approval your TL or your QA will be approving your request. So stage here is deploy same digest perform integration contract API UI plus performance security and we have already discussed all these tests in our day one's lecture and finally so when you are deploying to the production cluster there will be first be a promotion and these things will be taken care by your Jenkins server itself there will be two approvals your approvers could be your change manager your TL your application owner and so on. So these are the steps that will be performed for deploying it to the prod environment. We'll be deploying the same digest again that is the important piece. We are using the same artifact for deployment in multiple stages cautious rollout plus SLO guardrails ready roll back. Now if I want to summarize this PRCI proves the merge then the merge happened build once on main promote that exact digest through dev stage prod with increasing confidence. I want you to know that if it was deployed in dev and that failed. I want you to know that merge has already happened then you must fix the problem in your main. Your developers must be equipped to fix this immediately. Which is why when you are using this sort of design, your testing, your CI is very stringent. It takes care that everything is in place before the actual deployment takes place. But again let's say if your application requires GPU then you must ensure that in CI stage itself you are pulling your deployment environment to see whether those nodes are available or not. So you have to think like that if you are adhering to this design then testing must be extremely stringent. I hope you have understood this and then finally I want to discuss why and what of Jenkins and I'll just read through these points because we have already understood these points throughout this lecture. Jenkins Y and what it is open-source automation server per CI and CD runs pipeline as code from your repo and we have seen all these things in action in our diagrams again automation server not just for CI/CD it can also do CT it can do any automation that you want Jenkins to do there are plethora of plugins available for Jenkins which can help you integrate various AWS, Azure or GCP services and you can leverage those why teams use it portable and extensible with with rich plugins. Gates merges with green red status checks fits git flow and trunk based workflows. We have just seen these enables build once promote the same digest and we have also seen this how it usually runs. We will be discussing these things in detail that what are the patterns that you can use for Jenkins how Jenkins will scale when there are plethora of jobs running in parallel so we'll see all these things what it isn't Jenkins is not a gith host a registry or a monitoring tool it is an orchestration engine it is an automation server alternatives and compliments now if you have a githops based workflow then you will often see that Jenkins works in conjunction with your Argo CD, Flux or your any other tooling similar to that. But there are alternatives to Jenkins like GitHub actions GitLab CI. That's all I wanted to cover. That wraps up day two of Jenkins basics to production course. Today we reviewed Git and branching essentials. Decoded the continuous practices. Compared Git flow and trunkbased strategies, walked the promotion flow from feature to dev to prod and reinforced build once promote by digest. You also saw how Jenkins orchestrates builds and promotions. In the next lecture, we'll install Jenkins and run our first pipeline. If you have any questions, feel free to ask them in the comment section and I will reply. If you have any questions, feel free to ask them in the comment section and I will reply. If this helped, do consider liking, sharing, and subscribing. It will mean a lot to me. Thank you very much. Hi, I am Vun Jooshi and welcome to day three of our Jenkins basics to production course. In today's lecture, we will clarify what Jenkins is and why it matters. Then we will compare installation options across environments so you know what fits the lab versus enterprise. Next, we will go hands-on with Jenkins installation with Docker. Finally, we will create a freestyle job to run commands, archive artifacts and see built-in environment variables in action. So, let's get started. What is Jenkins? Jenkins is an open-source automation server and open-source is the keyword here. So when I talk about Jenkins, Jenkins is communitydriven and this falls under the umbrella of continuous delivery foundation also called CDF. So like when we were discussing Kubernetes, Kubernetes is open-source communitydriven and it sits under the umbrella of CNCF. Jenkins is also communitydriven but it sits under the umbrella of continuous delivery foundation CDF. Now Jenkins is CI/CD orchestrator that will help you in all the stages of your application. It will help you in the coding part. It will help you in the build phase, package phase, test phase and deploy phase. And again I want you to understand that orchestrator is someone that is connecting the dots. For example, when you are deploying an application, there is an infrastructure architect, there is a DevOps architect, then there is an application architect and so on. And then there is a chief engineer. Chief engineer is the one who connects all the dots together to give a proper end toend solution. Similarly, Jenkins is an orchestrator which is connecting all the dots for you. For example, at all of these phases, you will have different tooling that will be helping your application. If I talk about code, you will be using git and you will also be using a git host, git host like GitHub, Bitbucket, GitLab, etc. When I talk about build, you will be using different tools here. You would be using docker if you are generating container image as an artifact. You could be using maven gradal ant which helps you in the build phase of java application. Similarly when it comes to package you can use maven to package a java application. When it comes to test you will be using different tooling for test as well. You will be using tools that can perform s that is static application security testing. Then you will have tools that will help you with DAST that is dynamic application security testing. Similarly, when it comes to deploy, you could be using Helm, you could be using customize or you could be just be deploying to plain EC2 instances. Each of these stages have their own tools. So what I want you to understand is Jenkins is not replacing these tools. What Jenkins is doing is it is acting as an orchestrator which will connect all these different tools to deliver your application. So that is why we are calling Jenkins a CI/CD orchestrator. Third is pipelines as code. And whenever you see something as code, I want you to imagine version control. So with Jenkins whatever pipelines that we write as in your pipeline can have one stage two stage 10 stage it depends on your application. So what you can do is you can code those stages into something called a Jenkins file. And once you have that Jenkins file, you can version control that Jenkins file. So that as you progress with your infrastructure, as you progress with your pipeline, you can see the evolution of your pipeline. So for example, how was my pipeline when application one was introduced? Now 5 years down the line my application has so many bells and whistles. How does my pipeline file looks like? So that helps you understand the pipeline evolution as well. Next is rich plug-in ecosystem. Now see, I just said that Jenkins is an orchestrator. But I want you to understand if Jenkins is creating a container image for you, then Jenkins must have a tool that helps in creating a container image. And we know Docker is one tool that can help you with that. So if you are expecting Jenkins to create container images for you then Jenkins must have docker installed. Similarly if you want Jenkins to check out code from your git host then Jenkins must have g installed so that it can interact with your remote. So in that scenario, git must be installed in your Jenkins. So understand if you want Jenkins to do something, if you want Jenkins to deploy using Helm, then Jenkins must have Helm configured. Similarly, we talk about rich plug-in ecosystem. So plugins are something that helps Jenkins integrate with other tooling. For example, if you want to push an image into AWS's ECR, then Jenkins has a plug-in that will help you do the same. If you want to use AWS's secrets manager, then you have a plug-in that will help Jenkins interact with the secrets manager. So, I want you to create that picture in your head right now. So if you want your Jenkins to integrate with some notification engine then there must be a plug-in that you can install in Jenkins and that plug-in can help you interact with your notification service. So Jenkins has a rich plug-in ecosystem get workflow friendly. What is this? So let's go to day two. In day two, what we said? We said that developer will perform a commit. Then developer will raise a PR to dev and as soon as this PR is raised, the continuous integration will run. Essentially, Jenkins will trigger. How is this possible that when you are raising a PR in your GitHost like GitHub, it will trigger Jenkins that is running in your on premises? How is that possible? It is possible because whenever there is a PR created, you can configure your GitHost to send a web hook and based on that web hook, Jenkins will trigger the pipeline. That is why we are saying get workflow friendly. Whatever happens in your GitHost, for example, GitHub, if there is a collaboration request or there is a review or there is a PR, then you can configure your GitHost to send a web hook to Jenkins and Jenkins based on that can trigger the pipeline. extremely powerful and you will see this in production used a lot. Whenever there is a PR created a Jenkins pipeline is automatically triggered. Next is free core enterprise option. So at the very core, Jenkins is free as we know it is open-source, but there are enterprise options and cloud bees is an organization that is a major backer of Jenkins. You can have support taken from cloudbes. If you want Jenkins support, now I want you to know at this stage itself whenever you are using an OSS application or software in your environment to run your production application, then you should always take enterprise support for that and not just OSS. So if you are on AWS, you are running an enterprise application on AWS, then also you would pretty much always have business support from AWS because there are services whose control plane is sort of hidden from you. If I talk about transit gateway, you just see the software level things. What if you want to know deeper insights? Then you will have to involve AWS support for that. Similarly, if you are using Jenkins, which is open-source, and you are stuck somewhere, your only troubleshooting option would be to surf the web. But what if you do not get an answer? You want an enterprise support of Jenkins? If you are running an enterprise application with Jenkins, now how it usually runs, it runs anywhere and we'll explore the installation options soon. Docker, VM, bare metal, Kubernetes clusters and so on, controllers and agent. So this is an important point. The installation that we will do right now at this stage of this course will be using only one machine and that one machine or one container will be acting as both controller and agent. So what are these controllers and agents? Think of them as control plane and data plane. Control plane is the part where you configure what the system must do and those tasks are achieved by the data plane. So data plane has agents and the control plane instructs the agents on what to do. And what is that these agents will be doing? These agents will be running pipeline. For example, if you have 10 agents, maybe five agents are supposed to work when you are dealing with the pipelines associated with application one and the next five agents are supposed to work when there are pipelines run associated with application two. Then the next one is credentials and policies. I want you to know that there is a store that you can use within Jenkins to store your credentials. You can do that. But in enterprises, you would often see that your Jenkins pipelines are integrated with third-party tools. Now, these third party tools could be your Hashi Corp vault or it could be the native secrets management service that is provided by major cloud provider. For example, you can integrate AWS's secrets manager. Now, why would you want to do that? I want you to know that if Jenkins is deploying something onto Kubernetes, then Jenkins must have credentials to authenticate with your Kubernetes cluster. Where do you save that data? You must have secure means to access your Kubernetes cluster. If you are deploying something onto traditional VMs, then you would want to have SSH keys to access that VM over SSH. Where do you save your SSH keys? Or if you are accessing anything using tokens, where do you save those tokens? Hence you must have means in place via which you can save these secrets information securely. Often times you would see third party plugins are integrated so that you can leverage such tools. Now that we have this understanding let's move to the installation section. Jenkins installation options. There are plenty of these. Let me tell you when it comes to docker containers this is the option that you would use when you are doing labs in development environments and in small teams. So it is the quickest way for labs and PC's portable consistent across all the operating systems and that is the flexibility that containers will give you. Let's say you have everything configured. You can create an image out of that running container and then distribute that image if anyone wants to replicate your Jenkins architecture. So containers give you that flexibility. Lightweight we know that cons persistent scaling needs extra design and this is true. So if you are using Docker Swarm, there is not an intelligent plug-in yet that can help you scale. And what do I mean by scale? I told you that there is a controller and then there are agents. So when there are jobs that do not yet have agents associated with them, then what the controller will do? Controller will spin up more agents. And where are these agents living? So if I talk about the Kubernetes style Jenkins, then these agents will be running in the pods. If I talk about VM and bare metal, these agents will be running in the VMs. If I talk about Docker container environment and if I'm using Docker Swan, they would be running as Docker containers. So what I'm saying is there is not a proper fullfledged plug-in that can help you scale those agents in docker swarm. Hence you would not see this used in enterprises but we will be using it for testing in the early stages of our course. Then let's talk about VM bare metal. Let's say you are running on premises and you want to run your Jenkins but Vun how will I ask my controller to spin up agents in my on premises environment so what you have is you have plugins available from VMware open stack and so on that you can leverage so that when controller demands agents it can spin virtual machines that will run those agents. Now, ideally, one agent is equal to one virtual machine. So, for example, let's say you are running 10 pipelines. All those 10 pipelines can be run by a single agent or you can distribute the work by spinning multiple agents. Now, I don't want to explain this in much detail right now because in the demo section, this will make much more sense. So once we move to demos for this which will come later in this course then we'll understand this deeply but for now I want you to keep this in mind that whenever there are more and more and more pipelines in your Jenkins implementation you can have scaling at Jenkins as well. It is not that once you install Jenkins onto a single VM that single VM is all you have. your controllers can spin up more agents based on the load on Jenkins. So when you use a VM, it's a good enterprise fit best for compliancedriven stable scale environments. Now another question that comes to mind is support. If you want to take support, there is cloudbes and there are other organizations that can give you enterprise level support for your Jenkins server. So you can always take that and I would recommend to take them if you are running an enterprisegrade application in Jenkins. Next is Kubernetes. Jenkins on Kubernetes. Firstly, I want to tell you right away that do not think that this is the best solution. No, it is not. The best solution depends on what the requirement is. If for example whatever you are deploying you are deploying onto traditional VMs that implies that client or that application doesn't even have a Kubernetes cluster. Will it make sense to propose Jenkins on Kubernetes to that client? Not at all. So in that scenario VM could be a good choice. But if the client already has a Kubernetes cluster, then deploying Jenkins onto Kubernetes is a good option. So your solution to a problem should not be based on the most fancy and latest tech available at your disposal. It should be based on the requirement of the client. And this is not just for Jenkins. This is applicable for the entire IT universe. Do not design solutions based on what is the latest and greatest available. Always design based on what is the need of the client. You have to be costconscious. But if the client requires high availability, you need to tell them that dear sir, high availability is directly proportional to the dollar sign. So if you want me to design an environment that will never ever break then you have to shell some dollars. So let's get back to this topic again. So Kubernetes Jenkins on Kubernetes. So cloud native scalable enterprise ready consider operational complexity. Now if you are not running Kubernetes and you just spin up a cluster to run Jenkins then of course it's an operational complexity best for cloudnative organizations needing elastic scale again here as well the fun remains the same when controller wants to spin up more agents you will see more Jenkins pod running in your cluster now these two options are kind of niche so if let's say you just migrated to the cloud and you spawned a Jenkins server there. Now you have two options either you can spin up a virtual machine and then configure Jenkins yourself and then maybe later take Jenkins support but you also have an option where you can go to the marketplace of your respective cloud provider and search for managed Jenkins that is also available here. So this talks about that you can use that. Now this is cloudb's enterprise jenkins. Now cloudb's calls it cloudb's cia. So what they do is there are two things. First is support. Now if you are already running Jenkins you can go to cloudbes and tell them that I want support from you and they will support you whenever there is a break fix in your Jenkins environment. That's one use case. Another use case is there is cloudb's CI which is based on Jenkins but they have add extra bells and whistles that can help you make your Jenkins environment have different policy controls and compliance toolings. So this can help you with multi-team multicontroller agent management and I will let you explore this further but what I mean is instead of Jenkins you have cloudbi cloudbi also uses Jenkins under the hood but they have added few more features that are specially useful for enterprises so if you want you can check that out. So the crux of this is if you are running enterprise application on Jenkins then you should ideally have enterprise support for your Jenkins and if you already have a Kubernetes cluster you could deploy your Jenkins onto Kubernetes. If you do not have a Kubernetes cluster or if for XYZ reason you want your Jenkins environment to be separate from the Kubernetes cluster then you can also choose this option. Now there are scenarios when you might not want to deploy Jenkins in the same cluster where your application runs and we will see those scenarios as we progress with this course. Now let's go to the CLI and install Jenkins. So first I'll go to my GitHub notes here. I will go to Jenkins basics to production. And if you are finding this series helpful, I would highly encourage you to, you know, if you are liking my content, like the video, subscribe to the channel and you can always start the repository if this is helping you. Now I'll go to day three. Now here I will click on lab setup and then I'll first copy this command and then I'll tell you what is going on. I'll go to the terminal. I will paste it here. What I'm saying is docker run-d is run in the background. Name of the container will be Jenkins. Restart is unless stopped. So what I'm saying is if I manually stop this container then keep it stopped. But if I let's say restart the docker engine in my map then you should automatically restart Jenkins container as well. hyphen p is the port mapping 8080 to 8080. So I'm saying the host port on my docker host when someone hits that you take them to the container port 8080. And what is listening on port 8080? Jenkins is running in my container that is listening on port 8080. And then again hyphen p 50,000 to 50,000. So the host port 50,000 in my docker host is listening and it will send the request to the 50,000 port in container. So what is this used for? At later stage in this course we'll be using agents. Agents use 50,000. Hence I have kept it here for the sake of completeness. Hyphen V. What we are saying is create a named volume called Jenkins home and map that to forward slash whereward/jenkins home in the container. Warun what is Jenkins home? Jenkins home is something that you must preserve at all times because this is the directory which is holding all data. Jenkins the pipelines you are configuring the plugins you are adding all of those things are saved here. Now if something is that critical automatically you should be thinking how should I back that up. So you should be backing this up. If you are deploying your Jenkins in a containerized environment and your orchestrator is Kubernetes, then you should be storing this in a PVC and that PVC should be coming from a block storage or from a file storage but this must be preserved. If you are running Jenkins on a VM environment, then you should be storing this onto a block storage or onto a file storage. Next is hyphen E. E is defining the environment variables. We are saying the environment variable TZ which is for time zone. The value for that is Asia Kolkata. And I am doing this so that the logs I see makes sense to me because I am in India. Then Jenkins forward/jenkins LTS. What is this saying? This is saying that I want you to use a repository that has the name Jenkins and the tag is LTS. I will press enter now and this will create the Jenkins container for me. So if I run docker ps I see my machine has a single container running and that container is named Jenkins. Now I said that anything that hits on port 8080 on my docker host should be mapped to port 8080 in the container. And I told this in my docker course that whenever someone is accessing your docker host first there is docker host then there is the container. And you mention these ports in the same way. First there is docker host and then there is the container port. they are not always the same. Hence, this distinction is important to know which is the docker host port and which is the container port. So, my docker host is listening on port 8080. So, I'll go to my browser and I will access local host on port 8080. I'll press enter. Voila. I see Jenkins is here. And it says to unlock Jenkins take the password from this path. So let me copy this path. I will go to my terminal here. I will run docker exec. Name of the container is Jenkins. And I want born again shell which is bash. I'll press enter. And here I can see my credentials. Before I do that, I do not like this bland terminal prompt. So let me make this colorful. I'll press enter. This is now colorful. Let's copy that path again. I'll copy this and then I will cat on this path. And it shows me the password. I will copy this. I'll go to my browser. I'll paste this. I'll press enter. And this is asking me to customize Jenkins. Now either I can install suggested plugins or I can select the plugins and install them. I will for this demo click on install suggested plugins. Now while this is getting started, let's wait. Okay, let's do one thing. Let's understand what this is doing. So these all are the plugins that are being installed. So what is folders? Folders is there to you know to put your jobs into respective folders. OASP markup formatter. This is for HTML pages. Then there is build timeout. If there is a faulty build, you do not want that build to run till infinity. There must be a timeout. For example, if you know your pipeline will run in 30 minutes. You will set a build time out of 45 minutes, 15 minutes buffer. Hence, build timeout allows you to configure that value. These all are plugins. Okay. Timestamper whatever we are doing in console there will be a timestamp associated with our actions and this timestamper plug-in is helping with that workspace cleanup and this is a system utility task and gradal these are specific to Java pipeline is the plug-in that allows you to create pipelines in Jenkins GitHub branch source this is specific to GitHub pipeline GitHub Groovy libraries again associated with GitHub pipeline graph view. This is cosmetics. This will help you see your pipelines in a graphical view. Git, as we know, this is our source control system. SSH build agents. These are used when you want to SSH into virtual machines. Matrix authorization strategy. This pertains to authorization. As the name implies, LDAP is lightweight directory access protocol. This is used for SSO single sign on email extension as the name implies. If you want to send emails to someone, this extension can help you with that. Mailer again associated with mails. Dark theme is what we all love. Let this complete. Credential bindings injects credentials into builds. Okay. Now it is saying create first admin user. So let's call this user cloud with varosh and then I'll set up a password and full name is varun jooshi and email address is abc the ratexyz.com because I don't want to use this feature right now. I will click on save and continue. Now instance configuration. Now this is the Jenkins URL. Now this Jenkins URL is important because when you are implementing an enterprisegrade Jenkins then this Jenin URLs can be carried forward to your emails. So for example if some job has failed and your fellow members want to see the error logs then they can just click on Jenkins URL along with you know the full path and they will be right away taken to the Jenkins screen. So this is important to configure but right now since we have deployed it onto the local host that is our machine we will leave it at this save and finish start using Jenkins and let's the first thing that I want to do is enable dark mode so that we do not go blind. So I'll hover over my user icon click on appearance and then I can choose dark and apply. I'll save this and this is the welcome screen of Jenkins. You will see this and first is create a job. We'll be using this but I want to give you a small tour. I'll click on settings here and here is where you will be spending a lot of time as a Jenkins administrator. You see here you can provide credentials. Then there is credentials. Then there is security. Here is users. There are many options. I will let you explore that because each line under the main heading tells you what this thing is doing. But in today's lecture, we'll be concentrating on tools and maybe plugins as well. This is nodes add remove your agents and so on. So let's do one thing. Let's directly create a job so that we know the basics right. So I'll click on create a job. Here I have multiple options. I can create a multibranch pipeline folder pipeline and freestyle project with this lecture. I want to start with a freestyle project. I'll name this intro freestyle. I'll press okay. And this has created a job. Now it is asking me to configure that job. Intro freestyle configuration. Here description you always should be giving for production jobs. For now, I will skip this. For now, I will skip all of these. Source code management. I do not want that. I'll let none be selected. Then these are the triggers. Like I told you, how will a Jenkins pipeline get triggered? There is poll SCM as well. SCM as in source code management. Here your Jenkins can pull your git host like GitHub after let's say an hour or so to check if there is some work for that pipeline that is also possible. Then there is GitHub hook trigger. This is the one that we discussed the web hook build periodically. It's a chron job build after other projects are built. This is like chaining. If that project is completed then you start this job. Then you have trigger builds remotely example from scripts. We will be using none of them here because we will be running our job. We'll be triggering our job using manual method that is by clicking the mouse button on build. Now then here are certain environments that you can set. We'll also leave this for now. Here is what I want to do in today's lecture. I want to click on add a build step. You see there are multiple options to choose from. What I will do is I'll click on execute shell. So if I go to my Jenkins container first. Okay, let's go here. I will clear my screen. I will click on cat etsy and then I will check OS release. And this will show me the OS statistics for my container. Now I want to do another thing. I will go here and here I have execute shell. So what I will write here is I will write cat oscos release and then I will click on apply and then I will save this. My job is saved. A simple intro freestyle job. Here I have multiple options but what I want to do is I want to click on build now. I'll click on build now. This will start the build process for this job. And here are the builds history. And you see number one build of this job is successful. So what we are calling these multiple runs are we are calling them builds. So if I click on build now again I see a build two is created and build two I have multiple options with build two either I can click on it to see those options or I can click on this tiny drop-down and here again I have multiple options. I can delete this build edit build information but what I am concentrated on right now is console output. I will click here. Voila. And this is giving me the same thing that I saw here. So then the question becomes are both of these same. I want you to understand that execute shell in Jenkins whatever we configured here. So this was the job we were on. And if I click on configure I will go back to the same screen where we configured the job. So we added execute shell as a build step. And then we wrote cat this here. Now this is a non-interactive shell and this shell is on the assigned node. Additionally, it is in this workspace. What is the workspace? We will see what that workspace is, how to explore that. But for now understand this is a non-interactive shell in a specific workspace. And that workspace is of this job that we have created. And here is your actual shell. This is an interactive shell in the containers default working directory or the users. So I hope that thing is clear. Now at this stage itself I want to show you one more thing that will clarify how this is different than this. So if I write print env here and I press enter you see all the environment variables that are defined in this container. So if you see this is the one that I just defined you know to make the prompt colorful and this is the environment variable that we set while we were creating this container. Now when I ran catoss release this also gave me the same output as execute shell gave. But now what I want to do is I want to add here print env. And I want to save this and then I want to click on build now. A build now will create a third build. And what I'll do is I'll go to the console output. And you see here I have so many more environment variables. You see build ID is three because I am in the third build. Job base name is intro freestyle. This is the name of our job. So I want you to clearly understand the distinction between execute shell that we used here and what is the shell that is of the container. Now, Vun, what are these environment variables that are specific to this? So, if you click on this link, the list of available environment variables and you see here, these are all the environment variables that are available at your disposal. Now, why are these environment variables important? These are important for traceability. Now imagine if your job has failed and you saw the logs you would want to know to which build these logs belong to which job this logs belong. Hence build number build ID job name all these are important and you should be knowing these things. So whenever you are let's say creating a Jenkins job you should always think to implement these environment variables somewhere so that you can correlate to which job this artifact belongs to. So if I'm creating a container image, I may want to tag that container image with the job name or the build number so that I know exactly which build within my job was used to create that container image. So I always want to know which artifact resulted from which build. Hence using these environment variables will help you. For example, node name. Maybe I want to know on which Jenkins agent this job ran. Hence, I would want to have node name. So, based on requirement, we can always use this. Now, again like the example I gave you, maybe when a job fails, I want to send an email and that email can have the build URL so that whenever someone clicks on that URL, they directly land on the build page. And as we progress with this, we will explore more of these environment variables. But this is an important concept. That's why I introduced these so early. So let's go back to our GitHub notes and I will scroll down and let's use these environment variables. So I have these here. So I'll quickly copy this. I will go to our job, the job that we created. And here I will remove all of these and I'll paste this here. And then I will save this. And I want to show this to you what we are doing. So we are saying the workspace name here. We are echoing the workspace. The build we are echoing the job name along with the build number. Then we are echoing the node on which this job ran. So I will click on save and then I will click on build now. And we see the build number four has completed. I'll click on console output. And you see here workspace is where Jenkins home. And where is Jenkins home? Jenkins home is in the volume that resides in our docker host and we have mapped that onto our container. That's why it is said you externalize this. So if for example this container fails then I will map the same volume and I will get my all jobs back and here is the name of the job and then you see here is the node on which this job was run. It's a built-in node and then the workspace is this we have already seen. Now in the build part we said the job name and the build number. So the job name is intro freestyle and the build number is fourth. You see here it is the fourth build. Now let's see what we want to do next. So if I scroll down. So print env I have already shown this to you. This is again I will let you do this. It is echo report for this build number into build report. So this is like generating an artifact. We are generating an artifact for this build. So let's do this because I want to show you one more thing related to this. So I will go to the same job. You can create a new job as well. I'll click on configure and here I will come down. I will paste this here. I will apply this and then I will save this. So see what is it is doing. It will be echoing this a build number and then that output will be directed to build report.ext. And where is this? We have not specified any absolute path. So let's see where this file gets created. And if you are guessing it is the workspace then you are absolutely right. So let's click on apply save and then I will click on build now. And there is a fifth build. Now if I go to the console output you see build this this total four files are there. Build report exists there. Now what is there? It is here. So let's go to our terminal. I will cd into workspace. Then intro freestyle. I'll press here ls and you see build-en report is here. So if I c this file you will see report for build 5 because this is our build 5 and we invoked the build 5 variable here. And if I go here you can see that we defined here that we want the build number for whatever build this is and this was build five. So I hope that is clear and there is one more thing I want to show before I let you go. I will click here and then let's click on configure again but this time what I want is I don't want anything like this. Let's close this. Let's delete this step. Let's go to add build step and I will click on invoke tople maven target. So here what we'll be doing is Maven as we learned in our day two is a build automation tool that is used for Java. Here our goal is to just know the version and version is simple like we do here get - version it's simple. So we get the version of git when we do this. So here when you do MVN that is for Maven - version then you should see the version of Maven but my machine does not have Maven installed which is why I see command not found. So if I go back here I have written version here. Now let's do one thing. I will click here. I will open this in new tab. So I have the settings open in new tab. I will go to the tools section and here. So I'll scroll down here. I will add Maven and it is asking what do you want to name this. So I will call this Maven cloud with V Josh so that it is identifiable for me that I created this then install automatically that is fine and here you can choose the version of Maven that you want to install. I will click on apply and then I will save this. Now this essentially will tell Jenkins to install Maven. Again there are two ways to do this. I could have installed it directly on my container because I want Maven to be there if I want to run Maven specific commands. So there are two ways. One is I use apt to install it. Other way is I use tools section here to let Jenkins do that internally. So if you go to the GitHub repository, I have explained both of these methods and I would encourage you to give them a read. So I'll come here and then I'll click on apply save. I want to show you one thing. I'll click on build now and this should fail and this has failed. Now why has this failed? I'll show you the reason. It's saying same Maven is not found. It's something related to that. So let's do one thing. I will go here and I will click on configure again. I'll scroll down. So I added this Maven but I did not define which Maven's installation I want to use. So if I click on the drop-down, I have to choose Maven that I just configured. So I selected that. Now I'll click on apply and save. And if I run this again, this should now give me the version of Maven. So it has succeeded. Now if I click here, console output and you see Apache Maven 3.91 is installed in this machine. Now you would be thinking Wun which one should I use? I would encourage you to use this tools part because this allows you to configure multiple versions of Maven and then in your job you can call the version that you want to use. Now you now War Vun which one to use? So firstly I want you to know that when you use this method you have the flexibility to have multiple Maven versions. So if you go here you can click on add Maven and add a different version of Maven and you can call that within your job like we did. So we named it Maven cloud with VJOS and we called it you can name it something else and then call it but when it comes to your apt if you install it on the container then you are tied to a specific version. Now of course there are ways around it but it increases the complexity. So if you wish to use multiple versions of Maven then this is the best place to configure Maven or any other tool that you see in the tools list. Before I let you go I want to cover one more quick thing. So if I go to my diagrams Jenkins roles and responsibilities there is Jenkins administrator. This is the person who will be configuring Jenkins who will be ensuring that Jenkins is backed up. all the plugins are up to date. The patching of the Jenkins node and so on will be responsibility of Jenkins administrator and Jenkins administrator is typically part of the DevOps teams. But who are the owners for Jenkins jobs? Who will be creating the pipelines in Jenkins? Now these could also be your developers and of course DevOps engineers are also here and QA teams. The crux of this is your developers may also need access to Jenkins because they want to test and build their pipeline. So keep these things in mind. That is all I wanted to cover in this lecture. That's wrap for day three. We installed Jenkins in Docker, reviewed practical install choices for lab and enterprise and built a freestyle job that printed environment details, archived artifacts, and validated different installation options. You now know how Jenkins runs commands, where state lives, and how to make tools available the right way. Next up in day four, we will move to pipelines Jenkins files in Jenkins. If you have any questions, feel free to ask them in the comment section and I will reply. If this helped, do consider liking, sharing, and subscribing. It will mean a lot to me. Thank you very much. Hi, I am Vun Jooshi and welcome to day four of our Jenkins basics to production course. Today we will look inside Jenkins home to understand what's stored and what you should back up. We will then improve our freestyle jobs. We will add parameters, pick a branch from Git, set up triggers, pull SCM and web hooks and create a nightly job that makes small report and cleans the workspace. We will keep it practical, easy to audit, easy to repeat and safe on disk space. This lecture will build the foundations of whatever complex pipelines we will be creating as we progress with this course. So let's get started. So let me go to the terminal. from the past lecture. We have a Jenkins container created and we will be using the same container for all the demos that we'll be doing as part of this lecture. And as you can see our Jenkins is exposed on port 8080. So what I'll do is I'll go to my browser and I'll just type localhost 8080. And here you see our Jenkins and it did not ask me for the credentials because I clicked on keep me signed in. Here is the job that we created the last time. So what today I want to do is I first want to explore Jenkins home. So let's exec into our Jenkins container. Docker exec it. Jenkins is the name of my container and I want to run bash. And this is not Kubernetes. So this will not come here. I'll press enter. And here I am in the Jenkins container. So before we discuss anything, let's see what exactly is the variable Jenkins home. So let's echo Jenkins home. And what you see here is Jenkins home resides in this directory. Now, right off the bat, I want you to know that anything that is inside this should ideally be backed up somewhere because even if your Jenkins instance, your Jenkins controller crashes for XYZ reason, it can read the data once you reattach the previous volume. So, keep this backed up. Now let's cd into this directory and see what all files and folders exist in this directory. So I'll go here. I will press ls-lr. We will not be discussing all of these but we will be discussing the critical ones. For example, let's first take the files that I want to discuss. So config.xml, XML. This is your global Jenkins configuration. Then you see Jenkins location configuration. So this will have your Jenkins base URL. I want you to concentrate on a few things. You see Hudson in a lot of places. What exactly is Hudson? Now previously Jenkins was known as Hudson when it was developed by Sun Micro Systemystems but in 2011 Hudson as a project was handed over to the community to the Jenkins community let's say and then they renamed it to Jenkins and since then we have known this as Jenkins now even today few of the code still has Hudson in it and they have not changed it which is why you will see Hudson mentioned in some of the places. Now let's discuss rest of the things you have war here. War is a directory as we understand from our past lectures that when we talk about Java the packaging formats could be earwar and so on. So war is typically used when you are talking about a web application and Jenkins in itself is written in Java. And you must be thinking but Vun we are accessing this over HTTP. Where is the web server? Now I want you to know that this war has a built-in web server and this web server typically is Jetty. Now there is secret dot key secret key not so secret all these things are used for encryption and decryption plugins will hold your plugins users will hold the users that are being created in your Jenkins tools will hold tools like git maven that we install using the manage Jenkins section secrets as the name implies will hold all your credentials. Then you have logs which will hold the logs, updates, all the updates. Most of this is selfexplanatory. Now there are two directories that I want you to concentrate on. First is jobs. Second is workspaces. Now I want you to think of these as control plane and data plane. And in our past lecture we briefly discussed about it. When we are dealing with production implementations of Jenkins, you will have a control plane and that control plane will not be running any jobs that will just be saving the critical information. So if I talk about a typical control pin which is also called controller you will see that it will have all these directories and the files that you see here but it will not have workspace because workspace is a scratch space that is created to execute your pipeline. So in production implementations all of these you will see are part of the control plane node because these are holding the information about Jenkins and is also storing the jobs. I am saying storing the jobs. I'm not saying executing the jobs. The executing part is offloaded to the data plane. And what is the data plane? The data plane has agents. Now these agents could be virtual machines or containers that are running your pipelines or that are running your jobs. So understand jobs are created as part of the control plane and you will see all the jobs created as part of the control plane and whatever execution is performed that execution is performed in the workspace directory. So in our current implementation of Jenkins, we have a merged control plane and data plane which is why you see a workspace directory and workspace directory is the directory where a scratch space is created so that our pipeline can run. So if my pipeline or my job is creating a container image then that container image will be created in the workspace directory. And since we are using a collapsed design if we create a container image right now as part of our pipeline you will see that the workspace directory will have the job name and inside that job name you will see the container image. But if this job were to be executed by an agent by a data plane that is a separate component in that scenario you will see that that container image is generated and created in that agent node itself not in the control plane. Now I want you to know that it is imperative that you have backed up your jobs. So all of jobs that you create in Jenkins should be backed up. Hence I recommended Jenkins home should be backed up. Now I want to discuss the control plane and data plane in a little detail and as we progress with this course we will see demos in which we will be leveraging agents to run our job. So let's go to the diagrams and I'll scroll down and here there is a control plane and then there is a data plane. Control plane is also known as controller. If I talk about data plane there are agents. Now these agents could be like I mentioned virtual machines or they could be containers. Each agent can have a single executor or they can have multiple executors. Now understand it this way. If my agent has a single executor and this is something that you define and we'll see this in detail later. So if I have one exeutor that implies this agent can run one job at a time. If I have two executors that implies this agent can be running two jobs at the same time. So it is defining the parallelism. Then let's talk about the controller that is the control pane stores. So jobs, builds, artifacts, credentials and plugins. I should not mention artifacts here and I'll let you know why I'm saying this. So all these are part of the control plane. So whatever directories and files that you saw in Jenkins home excluding the workspace will typically be seen in the controller. Orchestrates Q should scheduleuling labels security UI API. Now what are labels? We'll see in a while. But understand that the control plane is the orchestrator. Now I want you to contrast this with Kubernetes. In Kubernetes you had the control plane. Control plane was the brain of the cluster and then there is data plane. Data plane is the one that is running your jobs. Similarly in Jenkins control plane is the brain and then there is a data plane that is used to execute your jobs. Understand in Kubernetes as well your control plane could also be running your app workloads but that is not a recommended design. Control plane should just be running control plane component. Similarly in Jenkins we are right now using a collapsed design where our control plane and data plane is handled by the controller itself. But as we progress we'll improve this architecture. So the key takeaway is the control plane is the orchestrator. So executors is equal to zero in production. No builds here. So nothing builds in the control plane. Backup Jenkins home upgrades and configs live here. Dispatches work to agents receives results and logs. As simple as that. Now let's understand what are labels. I want you to know that for certain jobs I might require an agent that has Java installed and for certain jobs I might require an agent that has Python installed. And for some I might need docker installed because I'm creating a container image. So I can have a vast variety of job types that have certain dependencies on which those jobs can run on which agents those jobs can run and labels help you achieve that. For example, if I have a label associated with an agent that this agent is supposed to run this sort of jobs, then that label can be used when the job demands that specific requirement. So then let's talk about data plane run build steps. It is understandable that this executes your job. Provides capacity via executors as we discussed. Advertise capabilities with labels. Now what capabilities? Capabilities as in do I have Python installed? Do I have Docker? What kind of resources I have? Maybe you have certain labels for highMP compute agents. Those agents are running your strenuous jobs which run for let's say 15 20 minutes. In that scenario, you will label them accordingly. So, broaden your imagination and do not just limit yourself to think that labels are just dealing with Python or Docker or Java is installed or not. These labels could be based on maybe SSD disk. This agent has SSD installed. So, if you want to process something extremely fast, then use the agents with these labels. Anyway, ephemeral or static, these agents can be created based on demand. For example, I need to execute three jobs and that those three jobs require three containers that is ephemeral based on need or I can have few agents always running. So that as soon as my job kicks in, as soon as my pipeline starts, I have agents to process that job or pipeline. and they can scale horizontally based on the number of jobs that are pending. Next is keep clean. I told you that workspace is a scratch space created to execute the job. So whatever artifact your job is generating and what are these artifacts? These artifacts could be the container image that was generated or this could be your packaged code. Maybe you have your Maven acting in your build step and that Maven is compiling first the source code into byte code for Java and then you are packaging that into jar format and in that scenario jar becomes your artifact. Once your build is done, maybe you are creating a file and that file upon creation is used to store the build information. For example, what's the tag of the container image that was created, what's the digest, what is the timestamp and so on. Your agent's storage could be filling very fast if your jobs are continuously generating artifacts and you are not cleaning them. In that scenario, you should have jobs that are cleaning your workspaces. Now, I want you to clearly know that once the artifact is generated, you won't keep that artifact in your agents. You will be storing them somewhere. Say for example, if I'm generating a container image in my build step, then I would want that container image to be stored in an image repository like ECR. If I'm generating certain packages, I would want those packages to be stored in let's say Nexus or JROG Artifactory. If I'm generating certain files, maybe I want those files to be stored in an object storage like S3 or blob or maybe file storage like EFS. So before cleaning up workspaces, keep these things in mind that certain artifacts that are generated require permanent storage somewhere. So you should be pushing those artifacts before performing a cleanup. And in today's lecture in the last demo we will be seeing how to do that when you are dealing with a freestyle job. Now I hope you have a good understanding of Jenkins home. With this understanding let's directly go to the demos. So I will go to my browser. I will create a new item and let's call this mini demos and it's a freestyle project. I will click on okay. Previously we did some basic stuff but today I want this to be a little closer to production. I'm not saying exactly like production because of certain reasons and as we progress with this course we will learn those things. But for now, I want these five demos that we'll be doing today, mini demos to create the base for you so that you have an understanding that okay, Jenkins can do this, Jenkins can do that as well. Oh yeah, can it connect with my SCM? Yes, it can. What will happen when it connects and so on. So this will give you a taste of Jenkins as a whole and how you would be using this in production and as we progress we'll be creating realistic pipelines that are used in production and what we have learned thus far will form the base of it. So now without further ado let's get started. This project is parameterized. What does parameterized mean? parameters allow you to prompt users for one or more inputs that will be passed into the build is an important point here. Now how this is important for example let's say if I am running this pipeline for dev then do not perform any testing and this can be done using parameters. What if you have three environments and you want to deploy your artifact onto only stage that can be achieved using parameters. So let's see an example and see how these work. So if I click on add parameter there are a lot of options available. Few of them we'll be exploring in this lecture and few of them as we progress with this course. So first let's choose boolean. And what is boolean? It can either be true or it can be false. So what I will parameterize is I will run tests. And here I will check set by default. And when I check set by default, run tests will always be true. Again, right now we will not be performing any actual tests. I just want you to picture. Imagine what you could be doing in production implementations. When we are dealing with production, we will do run tests and if it is yes, there will be actual tests performed. Maybe you are scanning your image for vulnerabilities. Maybe you are performing some sort of unit testing and so on. Right now it is just flavor. As we progress, we'll see more. So I will create a parameter called run tests and I will check it set by default so that this is true by default and then I will click on add parameter. Here I will add choice parameter as the name implies. This will give you choice whether it is dev, whether it is stage, whether it is prod or whether it is the main branch, whether it is the dev branch and so on. Another choice could be do you want to deploy this now or do you want to deploy it 10 minutes later and so on. Broaden your imagination. So I will click on choice parameter and my choice parameter would be env so that my users have a choice whether you want to run this build for dev or you want to run this for stage or you want to run this for prod. That's it. Once I have done this, I will scroll down and here we'll do the same thing. I'll click on add build step and I will click on execute shell. Now again I wanted to execute something substantial and I also did not want to waste time typing everything for you. So what I'm doing is I will just paste what I have and then we will walk step by step on what is happening here. I'm saying echo run test is equal to run test and based on what you have defined true or false this will fill that environment is equal to env. So what we are saying here is environment is whatever you supply while running this pipeline or your job this will come here then I am echoing something I'm saying report for build number this should be sent to a file called report env.ext text. I want you to clearly know that we are generating an artifact. Anything that results from a build can be thought of as an artifact. So here the artifact is a file. We are saying if run tests is equal to true then echo running tests then you sleep for 1 second and echo. Okay. Then we are saying if you are not running the test for example if run tests value is false then you echo skipping tests as simple as that then we are closing the if else now I will save this okay let's see one thing before we progress I will go to my Jenkins I will press ls here I will cd into workspace I will press ls now see that you do not see anything in the workspace because I have not yet executed it. So this job does not need a workspace right now. Workspace as I told you is a scratch space which will only be there once you run something. We have not run the job yet. But if I go one step back and then I cd into jobs and I press ls, you see mini demos here because I saved the job that I created. And once I run this, I should see the workspace directory also has something. So let's build with parameters. Previously, you only saw build here. As soon as we parameterized this job, you see build with parameters. Let's click here and you see there is a default tick in run test because we set to the default and default is true when it comes to running tests in our scenario. Environment we said environment is a choice parameter which is why if I click this I get the choice. Now I will choose stage here. You can choose anything that you want. And then I can click on [clears throat] build. And this has started building. Let's see what happens. The build has succeeded. That's why you see a green tick here. I can click here and then I can check the console output or I can just click here and then click on console output. But before I show you this, I want to run ls here. You see now workspace has something for us. This is mini demos. And if I cd into mini demos, you see the artifact that was generated is here reporty- stage. Why stage? Because we said environment. And while running this job, we said the environment is stage. If I cat this file, I will see the contents that we asked this to have. And again I want you to clearly know if I go here if I click on configure we are using some builtin variables as well and you can access those built-in variables from here. I have just added the build number. So if I go here and I search for build you will see that there is a variable build number which I have leveraged. And since this is the first build you see here report for build number one here another thing I want you to understand these are typically what you would add in your script so that you as administrator and rest of your folks clearly know under which build number under which g commit and we'll come into git in a little while under which job this something was executed. So if I search for job, there are variables that you can use that are specific to job. For example, job name, job base name and so on. As we progress, we'll using most of these variables in this course. So now let's go to mini demos and see the output of the job that we just ran. And this is a simple output. It is echoing whatever we said and the job has successfully completed. Now let's move to demo two. And what is our demo two? In demo two we will be using git SCM plus branch as a parameter. So let's get started with this. So I will use the same project that we created. I'll use the same job that we created and that job is mini demos. I will just configure it as per our requirement. So what I will do is I will first close this boolean parameter. I will also delete this choice parameter. Then I will click on add parameter. And this time I will add a string parameter. And string will allow you to pass a string while you are running this. Previously we used boolean. So for that the options are just true or false. But for string parameter you can supply the value that's in your mind. Maybe you want to supply the name of the branch. The name of the branch is production. So you will type production while running this build. If you are running that build for development, you will type development as part of that. So here what I am defining is a branch. Let's say I'll write branch here. The default value for branch that I want to keep in my build is main. And I'll show you why we are using this. And then I want to concentrate on source code management. Previously we have been using none but this time I want this to connect to my git system to my source control. and which source control you should be using in production implementations. You will always be using private repositories. That goes without saying your application code will be in a private repository. And if you choose private repository, you will have to supply credentials. But I do not want to discuss anything credentials in this lecture. Hence we'll be using public repository to see how you can connect to it. So I will just go to cloud with varosh and then I will choose the repository Jenkins basics to production. I can simply copy the URL from here or I can copy the URL from here. I will copy it. I'll come here and it is asking what is the repository URL. I will just quickly paste it here. Since this is a public repository, I do not have to provide any credentials. I also want you to know that whatever steps we are doing in any of these demos, they are well documented in the GitHub repository so that you can do it along with me as I progress with this lecture. Now here what I will add is I will add branch here. Now what this will do is it will fill this branch based on whatever branch I specify while running this job. Important point to understand. So we have parameterized this so that while running the job user has the option to supply the branch name. Now if I do not want that I can hardcode the branch name here itself. So I will scroll down and then again in this execute shell step we will type something. I'll just quickly copy what I want the message to be here. I will select it all and I will paste it. Simple. I'm echoing built from branch this. Then I'm running a command get version. Then I'm running echo latest commit. And then I'm printing the git log. I only want the latest commit here which is why I'm running get log one line and I have added hyphen n1 which will give me the first result which is the latest commit and doublepipe is true. So what is this doublepipe? So let's spend some time here. Okay. So if let's say you have command a and then you have command b. What this says is run B only if A failed. So if A failed then B will run. Then Vun why this is useful here. So whenever you are running scripts what happens by default is if you are running any commands what happens by default is if this command fails for example then the upcoming command will not be run. So let's say if this weren't here and if this failed for some reason then this command would not have run but we want all the commands that are there in our execute shell step to run which is why we have added this true here. So even if this fails the next command will run and the next command is true and whenever you are running true that will result an exit code of zero which is what we want that is successful. The command ran successfully and the next command will execute. Another thing is if we are here I want to also discuss this. If you see A and and B, this implies run B only if A succeeded. So this is also you could see in certain scripts. Now this is important to understand which is why I have used it deliberately because I know for a fact that if we run this this will be successful but you will often see this sort of design in production implementations as well. Now that we have understood this, let's see what is happening. Then I have I'm echoing Jenkins variables are git branch that I am using. I'm using a Jenkins variable. This is not something that I have defined. This is available at my disposal. So if I go here and I search for get branch then you see this is defined by Jenkins. This is built-in variable. Then get commit. This is also a built-in variable. I'll click on save. Then I will click on build with parameters. As expected, it is asking me to supply a branch name. And if I supply a wrong branch name, let's say main with a spell error. If I click on build, this will fail because understand my repository does not have any branch with the name m a i n. It does have a branch that has the name main but it does not have any other branch. So ideally this should fail and it did and it is saying your branch does not exist something along the same line. So let's fix this. I will go to this and I will click on this job and then let's say build with parameters and this time let's keep it main. And if I click on build this time the job will succeed. So let's wait for this. And if I click here, if I go to console output, what is this? Get version, get config, get ref barse, get config, get checkout. And I want you to notice one thing. Okay, let's go to configure again. The first command that we were running is echo built from branch. Correct? And if I scroll down, echo built from branch starts from here. Whatever happened here, we didn't explicitly ask for this to happen. Then why was a checkout performed? I want you to clearly understand that Jenkins always performs this get checkout phase automatically when SCM is configured. So if I go here to my iterm and then I am in the workspace mini demos. If I press ls what is this? It cloned everything in my public repository. But I did not have a get clone step explicitly mentioned. So understand this behavior. When you are using SCM, there are certain steps that are automatically performed by default and cloning is one of them. And if I go back here, then it is running the commands that I specified. get version get log one line and so on. So if I run git log just plain git log it will tell me everything about few of the last commits. If you see here today I performed one commit where I updated day four and if I add one line this will give me a succinct output. So if I do this and add one line this will give me a shorter output. it will not show me the author date and so on. And if I want only for a specific commit, not the specific comet, if I want it for the latest commit, I can do hyphen n1. It will just give me the hash for the latest commit. So I hope this is understandable. This is part of get. But I just wanted to show this to you. I hope this is understood. Let's now do one thing. Let's go to the next demo. And I go to my diagrams. And the next demo is pole SCM trigger no web hooks. Now you must be thinking what is pole SCM. So let's go to our browser. I will go to configure. We'll edit the same job. We do not need this. We the project is not parameterized. We do not. Yes, we do need this. But here what I will do is I'll change this to blank so that it can perform the build on any branch that is available and that is typically main in our example because if I go to my repository the main is the only one that exists. I will scroll down and this time I will choose poll SCM. Now pole SCM what this will do is it will pull the SCM that is your git host every interval that you specify here. Let's say if we specify every 2 minutes then it will pull the SCM every 2 minutes. Understand? It will do the polling. It will not run the job every 2 minutes. So for example, if it pulled at 10:00 a.m., it will pull again at 10:2. It will again pull at 10:4 and so on. But it will not run the pipeline every time. But if it pulled and there was a push or there was a commit, it will trigger. But there must be something for it to trigger. If there have been no commits, then this will not trigger. It will only trigger when it has something to do. So in the poll SCM section, what I will do is let me just quickly copy that. I am copying this here. Now this is saying run every 2 minutes. Now if you are aware with chron expressions I have chron tab guru opened here. If you supply this this implies this chrome expression will run whatever is specified every 2 minutes. So if I go here I have specified h as well. Now what is h? Now this is specific to jenkins. What this is doing is H spreads schedules by hashing the job name. So each job gets its own predictable minute slot instead of everyone firing at the same time. Now imagine if you have multiple jobs and all those jobs are triggered frequently. In that scenario, you will load the Jenkins and the GitHost at exactly the same time. You may not want that which is why H is used. So if I remove this H, you would see that Jenkins will also give me a suggestion that use this if you want proper balancing. So I'll add age and I will then add forward slash. Then I will come below and here I will add a simple logic. I'll copy and I will paste it here. And here I'm just typing echo pollingdriven build get log on one line. I want to get the latest three commits. And then again double pipe true. We understand why we are using this. Although there is no command that is running after this. So I want you to understand one more thing here. Why would you use pole SCM when you can simply configure web hooks? Web hooks we will see later. What web hooks will do is whenever there is let's say a commit or a push or whatever you have configured in that scenario a web hook will be created and delivered to your Jenkins so that your Jenkins can run the pipeline. Understand whenever you commit github or your gith host will deliver something to your Jenkins a payload to your Jenkins saying that you should trigger the pipeline. That is one scenario. But what we are discussing here is here our Jenkins is pulling the gith. Now why would you use this? You would use this in highly secured and governed environments where you do not want any entity any entity that is outside to access your Jenkins server. So inbound you have not allowed you have only allowed outbound to your gith host so that your Jenkins server is the only one that is initiating the connection. So in secure environments you would often see this being used or they would have the gith host in the same subnet itself as in completely private so that you can also use web hooks in that scenario. Now that we have this understanding let's save this and then build this now. So you see this has succeeded and it will not run again. You will not see seven after 2 minutes here. Build number seven. That's because we have not commit anything into our repository. We do not have any changes there. Now that we understand this, let's move to the next demo. Demo four, web hook trigger. Now I want you to clearly know that I am using a container which has a private IP address. I'm accessing the same on localhost which of course will not be accessible by GitHub or any git host but I wanted to touch on this so that you can understand this theoretically and once we move to the advanced demos we will see web hook triggers as well. So I will go to my browser and then I will configure this job. I will scroll down and here instead of poll SCM I will use GitHub hook trigger for get SCM polling and here I can just write some dummy data and that is echo triggered by web hook branch is git branch and you know git branch is a defined environment variable get log n I want to see the latest commit and then you have true here. What I will now do is I will take you to GitHub. So if I go to my this repository and I go to settings and then I go to web hooks. So here I can configure a web hook. I can click on add web hook. It will say me give me the payload. So payload will typically be https slashward slash. Here you will have your domain name or your public IP address and then I will correct the spelling. It is your and then after this I can you know just have the GitHub web hook. That's it. You will typically have this here and here you would choose application JSON and then a secret here. Remember that use HTTPS in production implementations and we'll see that as we progress with this course. And here you can choose whatever you want for the trigger of this web hook. Which events would you like to trigger this web hook? Now just push events, send me everything or let me select individual events. So you have so many options at your disposal. You can trigger it when a PR was created. You can trigger it when there are merge groups. Whatever you see here, you can use. So here is the pull request. This is widely used and then you the default is just with pushes. So for this demo let's you can choose just the push event and I am not creating this web hook because that will hold no meaning right now because this path I do not have right now but you get the idea. So if I come here I can just save this and then I can trigger it manually right now. But in production implementations whenever let's say there is a PR this pipeline or this job will trigger automatically. Now with this understanding let's see what is the console output. Whatever we asked is displayed here and here you see the branch name is main. That is what we are using when we talk about our repository. We only have one branch here. Now let's move to demo five. And demo 5 is the one where we'll be doing cleanup. So here we'll be creating a job that is supposed to clean up the workspace. So I'll go to the browser. I will go to this job. I will configure it. And now what I will do is I will have a schedule. So what I will do is I will come below and here I will use another thing. I will use build periodically. I'm saying you must run this job at 1:30 a.m. every day. So if I come here to the chron guru, I can have one here. So this says at 1:30 you run this job. And if I come here, I can fill this as well. Let's do one thing. Let me copy this. what I want to run. I want to copy this and then I will paste it here. So right now I am not performing any cleanup. I just want to show this to you for I'm just echoing nightly maintenance on this node and the node that we are using is called built-in. We are running our jobs in the controller itself. Echo workspace is this. And then I am sending this information to report.ext. Hence report.ext becomes our artifact. I will save this. I will run this build now. And if I go to my terminal now, I press I will hit Q. And then if I do ls, I see there is a report.ext here. And you also see a get clone was performed. And why was this performed? If I go to my browser and I go to configure here, then you will see we have not yet removed this part. So get checkout is automatically performed for us even though we are not using it here but since we had it here we selected SCM get which is why the clone is being performed and you see this here. So if I cat report you will see that I have whatever I echoed in the the workspace for this is where Jenkins home workspace mini demos. Now what I want is I want to add parameters that will clean up this workspace. So let me do that. I will add it here. And what we are saying is echo backing up artifact. So what will happen is in actual production implementations you will have here docker push commands or you will be pushing your artifacts or your files into their respective places and then you will start the cleanup. So understanding this is critical. You won't clean up without saving the artifacts somewhere external or somewhere where they are safe. So I'll save it and then I will click on build now. Now essentially what will happen is it will clear the workspace and why it will clear the workspace because we have defined at the very last rmf workspace. So if I go back to that location, I press ls, I do not see anything now because we have performed the cleanup of the workspace. So that is all I wanted to cover in this lecture. That wraps up day four. You saw how Jenkins store state and you upgraded freestyle jobs with typed parameters, traceable git checkouts, event chron triggers, and safe cleanup after archiving. You now have a solid foundation to move from ad hoc jobs to reliable CI. Next up in day five, we will step into pipelines, Jenkins file, parallel stages and promotion patterns. If you have any questions, feel free to ask them in the comment section and I will reply. If this helped, do consider liking, sharing and subscribing. It will mean a lot to me. Thank you very much. Hi, I am Varun Johi and welcome to day five of our Jenkins basics to production course. Today we will make Jenkins actually ship an application. We will set up Docker outside of Docker which is also called D O D. So our Jenkins container can use the hosts Docker engine. We will add credentials safely and then build, push and deploy a tiny flask app end to end. So let's get started. Now on the left you see what we have and on the right what we want. Before explaining this diagram I want you to understand that we have a Jenkins container. that Jenkins container is running commands for us and we have seen that we were able to run commands specific to git we were able to run commands specific to Maven and so on. So any commands that we were able to run that binary was available to our Jenkins container or we configured that binary using tools section in manage Jenkins. So essentially what I'm trying to convey is whatever tools that we are using with Jenkins those tools are somewhere available to our Jenkins container. So if in this lecture we want to build images and we want to push those images to a container registry then we must have an OCI compliant tool in our Jenkins container so that we can build container images and then push them onto container registries. For us the tool of choice here is Docker. You could use any other tool that can be used to create OCI compliant container images like builda, canico and so on. But in this lecture, what we will do is we will configure docker in our Jenkins so that we can use docker to create OCI compliant container images. Let's see how we are going to achieve that. So on the left you see what we have. We have a docker host and docker host is essentially my laptop and in that laptop I have installed docker desktop which is why I am able to run containers and you see this is a Jenkins container here and I am able to access Jenkins container from any browser in my laptop. As soon as I access local host on port 8080, this is understood because I am forwarding anything that is coming on my local hosts port 8080 to my Jenkins container and that's how Jenkins is accessible and whenever I am running any docker specific commands then docker cli in my laptop is interacting with the docker demon and That is how I am able to run any docker specific command. So if I go to my terminal here and if I run docker ps then I see that there is a single Jenkins container that is running in my docker host and I know this because I can run docker specific commands and why I can run this because I have docker cli and docker demon configured in my docker host or in my laptop because I installed docker desktop. top. So the crux is docker CLI interacts with docker demon to run docker specific commands. Then what is where run docker.sockwaron and why have you mentioned it here? So if I talk about a Linux machine there could be multiple processes in that machine and if one process wants to speak to another process they can use something called a socket file. Now socket file when being used they bypass the TCP IP part. So essentially what you do is you communicate between these two processes using a socket file and extension to these socket file is sock. So essentially when docker CLI is interacting with docker demon and they can be thought of as two processes and these two processes are part of docker desktop at a very high level and when these two processes docker cli wants to interact with docker demon it is using this specific file. So this is the architecture we have. Now what we want to do is we want to install Docker in our Jenkins container so that we can run docker specific commands. Now one way to do that is I install the entire thing into this Jenkins container and entire thing is I installed Docker CLI along with the Docker demon and once I do that I can run Docker specific commands and I I can also run containers but I want to take a different approach. Now if I had installed both CLI and demon into this Jenkins container then that architecture is called dcker in docker. So essentially if I would have done that then I could create containers within this container. That's pretty cool. But in this lecture I do not want to do d i n d. What I want to do is d o d and d o d stands for docker outside of docker. Now what happens in this is you just install docker cli in the jenkins container then vun if I am creating a container image and I do not have docker demon installed then how would that work? this will work because what you do is you just install this docker CLI and you instruct this docker CLI to communicate with the docker demon that is installed onto the docker host. So essentially what we are doing is whenever I do this whenever I run this sort of architecture then there are two docker clis that can interact with my docker demon. The first one is the one that is installed in Docker host which is hello the obvious. And then second we have this docker CLI that we will install onto the Jenkins container. And if this Docker CLI runs Docker PS it will see this output right now. And if this Docker CLI runs Docker PS, it will also see the same output. Why? because they both are using the same docker demon and docker demon you will also hear people call it docker d. So if they are using the same docker demon then they will see the same output. So this is what we are going to do. But there is one more point that I want to cover and that point is for this docker CLI to communicate with this docker demon I must be sharing this file with my Jenkins container because docker cli by default looks for this file when it wants to interact with the docker demon. If it doesn't find this file this will not able to do that interaction. So what we want to do in this lecture first is we want to mount this file as a volume onto our Jenkins container then install Docker CLI so that this Jenkins container can interact with the docker demon that is installed in our docker host. So you now clearly understand what do is and what d is. So d in summary is when this Jenkins container has both docker cli and docker demon and d o is when you just have docker cli and this docker demon is shared between your docker host and your Jenkins container. As simple as that. So with this understanding what we have to now do is we have to delete the existing container we have and we have to recreate this container by adding additional volume. So let's do this. So I'll go to my CLI. I will first docker stop Jenkins and then docker rm jenkins. Now we will not have to do the installation the whole thing again because like I mentioned before we have externalized Jenkins home and Jenkins home is where everything Jenkins is available. So we will be using the same volume that we had before. So I'll just paste the command here and everything that I'm doing today or any lecture I have in this channel. Everything is available in the GitHub notes so that you can follow step by step along with me. So here I'm saying docker run-d run in the background. Name of the container is Jenkins. Restart is unless stopped. So if I restart my docker then you restart this container as well because I only want you to not restart it if I have deliberately stopped this container. Then I'm saying hyphen p port put forwarding anything that hits on port 8080 send it to 80080 on my container. This is for my agents. We are not using them. Here is the important piece. So this Jenkins home already has what we have configured thus far. We are just mounting this onto this path in our new container. And this is the interesting piece. This is the second named volume that we are mounting. Here we are saying v run docker.sock. Find this and map this onto vr run docker.sock. As simple as that. Here I'm defining the time zone and I want to use the Jenkins image which is the latest. So I'll press enter and this will create the Jenkins container for me. So if I go to my browser and I access local host on port 8080, then I will see my Jenkins container up and running and the previous jobs that were there in my Jenkins installation are still there because all of this is stored in Jenkins home and we used the same volume, the named volume that was used before. So I'll go to my terminal again and I want to show you something. So what we will now do is I will docker exec it and Jenkins is the container I want to exec into and I want a bash here. So I am logged into my Jenkins container. So if I run ls-l v where run docker doss sock I press enter you see the ownership of this file is with root but we are logged in with our Jenkins user I want to mention one thing while practicing for this lecture I already added others as readrite so you see this is your owner then you have group and then you have everyone else that is others. So others also have readrite. So for me this is okay. But if you are running this you will have to run chod triple 6 on this file so that when Jenkins user tries to access this file it can access it. So if I press enter operation is not permitted. What I will do is I will exit from here and then I will do the same but this time I will login into my Jenkins container as user root. So I'll press enter then. And now I want to run this command again. So if I run this, it will not make any difference for my specific installation. But if I do ls-l and I type this path here. Let me remove this. So what I will see is this has the others have readride and you should also see this. So run this command in your installation as well. So once I have done this I will again exit from this container. And now what I want to do is I want to install docker cli in my Jenkins container. So again what I will do is I will again login as root. I will do this and I will clear my screen so that we have more real estate and then I will go to the GitHub repository of this course and I'll scroll down install Docker CLI inside the Jenkins container. I will click on this and then you see this is what you can use to install Docker CLI. So I will just use this one here and I will go here and I'll paste this here. I'll press enter and this will install Docker CLI for me. Now we can exit this. Remember we have given our Jenkins user access to v run docker.sock file. So I'll exit it and then I will log with a normal user. And that is what you should be doing when you do not need root user when you do not need the highest privilege then login using a normal user. And that this is not just applicable for Jenkins but as a principle in the IT industry. Whenever you are using Linux boxes login with the user that has only the required privileges. So I'll go here. I'm logged in as Jenkins. Now I'll clear my screen. And if I run docker version now, voila, I see docker version is 28.4.0. And this is the build. And why I can run this command? Because I installed docker cli. And that docker cla is interacting with the docker demon installed in my docker host. So if I run this command in my terminal dockery- version, then you will see the same output. You are seeing the same output because both of these are interacting with essentially the same docker demon docker d. So the build is also same 465 and you see 465. So I hope this concept is understood. Now comes the interesting thing. If I run docker ps, I see I see the same Jenkins container because like I told you the docker demon is common. So now that we have this understanding, let's see what we have to demo in this lecture. So I will go back to my diagrams and I will scroll down and this is what we are going to do. So let's see what is happening in this diagram. We have Jenkins at the very top. Jenkins is the orchestrator that will ensure all of these things are done seamlessly. All the steps are done one by one. And before I start with this demo, I want to tell you one thing. I did this demo six seven years back when I was learning these tools and with advancements few of the things have changed. But when I completed this project, when I completed this demo, I was so exuberant that wow, I created a container automatically. The code came from somewhere, the build happened somewhere, the deployment happened somewhere else. So this was a very cool feeling for me and I hope once you do this demo, you will have the same feeling. So let's get started. So the first step is what we are going to do is we'll be creating a private repository and we'll be using GitHub for that and you can use any git host but we'll be creating a private repository because that is what you will see in production and if you have configured private repository then you will have to configure credentials because that is how Jenkins will access your repository and what will we have in that repository? We will have our source code and we'll have our docker file. Once that is done, we'll ask Jenkins to build container image for us using the command we know docker build. And why will Jenkins be able to run this command? Because we have just configured docker in our Jenkins container. Docker cli to be specific. Then in the next step, we will push this image. Now understand we will be pushing this image to docker hub. To push this image to docker hub jenkins must have the credentials for docker hub. Only then it will be able to push into the docker hub account named cloud with vjos. So we'll be configuring the credentials using the available Jenkins plug-in. And why I say available because while we were configuring Jenkins when we were installing Jenkins, we selected an option which said install the recommended plugins which is why most of the plugins that we'll be using in this lecture are already there. And then we will be finally once the container image is pushed we will be creating a docker container using that image. So this is end to end from creation from code to deploy. So we are doing everything we are taking out the source code the CI part we are building it we are pushing it and then finally we are deploying it and then at the very last we'll perform a quick smoke test. What is quick smoke test? Smoke test is just checking whether the application is able to perform the basic functionalities it is supposed to perform. For example, we will just check whether our application is accessible via the browser or not. So I hope you have an idea of what we are going to do. So let's get started. So I will go to my browser. I will go to dashboard of Jenkins. I will close this one and then I will come at the very last here and then I will create a new item and this time as well we'll be creating a freestyle project but do not worry in the next lecture we'll be converting whatever we are doing here into a pipeline that is Jenkins file so do not worry that stage is about to come we are moving step by step so that we can cover everything so let's come here and let me name this job. So let's call this cloud with varos and then I will add d o d and then I will add flask because it is a flask application that we'll be building. So I'll be showing you the code in a while. So for now just select freestyle and we'll click okay. Now here I will select git but we do not have a repository yet. So let's create a repository. I'll go at the very top and then from here I will choose cloud with varosh and then here I will choose create a new repository here and then new and what do I want to call my repository I will call it cloud with vjoy private repo I will not give any description let's keep it like that this is not public this is private so ensure you change this cloud with VarJosh private repo. I will click on create repository. This will create the repository. I will add a few files into this repository. So what I can do is upload an existing file here. I will click on choose your files and then I will go to Vun Jooshi here courses Jenkins basics to production day five under the Python directory. I have three files here. I will just open them. Do not worry what is inside them. We'll see that in a little while. So all these three files are being uploaded. I will click on commit changes. And you see my private repository has three files. Now I have these files but I want some means via which Jenkins can access my git repository, my private git repository. So I will go here. I will click on settings here and I'll scroll down. I will go to developer settings personal access token pat tokens classic. Let's use them. I already have one. This is the one that I'm using for this courses GitHub repository. So I'll create a new token generate new token classic. And here I will type Jenkins GitHub integration so that I know what is this used for. I will give the repo level privileges. And let's keep the access for 7 days. And I will click on generate token. So here is the token that is generated. Ensure you keep this token somewhere safe. After this lecture before uploading this video, I will delete this token. So it is fine that I'm sharing this right now. So I'll copy this and then I will paste this token in my browser so that I can use it later. Then I will go here and then I will type the repo URL first. So I'll go here and then I will go to the repository that I just created CWVJ private repo. I will go to code. I will copy this. I will go to my Jenkins now and I will paste this URL here. And as soon as I do it, this will give me an error that you have to provide some credentials. And I have not created any credentials for it. So if I click on the drop-down, I don't see any credentials. So I will click on add here and go to Jenkins. This is fine global credentials. And then it is asking me what type of credentials do you want to create. Now for this one, I will just click on username and password for now. Username is not something we have right now. We do have but we are using PAT personal access tokens to access our private repository. So we can provide any username. This will be used as a dummy. So for this I will just write CW VJ GitHub so that I know that I created this username for GitHub. Then I will go to password and in the password section is where I have to provide this token. So I will provide this token here and then I have to give it some ID. So I will call it GitHub pat. So keep this name meaningful because it is via ID that you will call your credential. So give this an identifiable name. So I will click on add. Once I do that, I will see in the drop-down there is cloud with VJOS - GitHub. That was the username that I specified. Then you see the token here. If I click this, this should just work. You see that error, that red error is now vanished. So I will come down and here we have the master branch and in GitHub what you see a main branch. So I'll just remove this and blank for any we have only one branch that is main. So this will be taking action onto that branch. I will scroll down. I will scroll down. Now here what I want to do is add build step and add build step I will use the same execute shell. But before I do anything else let's go to Visual Studio Code and see what are we going to configure. So I have three things in the Python directory. There is app. py, there is a docker file and then there is a requirements.ext. So first let's explore our code. Our code is written in Python which is using the flask framework and this is the framework that you can use for web apps. When it comes to Python, it is a very simple code which will just print the message welcome to cloud with VJosh tip is built with flask shipped by Jenkins running in docker and then we are exposing our application on port 5000. So this is where I am defining that my application my python application is going to listen on port 5,000. And then let's see the requirements.ext. Now what happens is when you are dealing with a production grid implementation you mention all the packages that are required by your application in a different file that is called requirements.ext so that all the packages can be found in one place that okay this application requires these all packages. Now our Python application only requires flask which is why you only see flask here. So let's go to the docker file and understand what we are doing here. We are saying from python this this is the base image that we are using. Of course it's a python application which is why we are using slim python image. Then I'm saying work diir is / app. Essentially what we are saying is whatever commands that I run next you run them in this directory. It is defining the current working directory for this. In the next instruction that is the copy instruction we are copying the requirement.ext to work diir. So if I write this this is the present working directory and which is the present working directory it is forward/ app. In the next instruction that is run. We know that run is used to install or run any commands that you want to run. So here we are using pip. What is pip? pip is a package manager for python. We are saying pip install no cache directory r and this is the requirement.ext from where you can fetch the packages that I want you to install. Now I want you to know that whenever you are creating container images, your aim is to have everything in that container image that is required by your application and nothing else. So for example, when you use pip for installing something, you have the download cache and so on. So here what I'm saying is discard the cache only install this. So this will install flask. Then I am using the copy instruction. Copy instruction is used to copy the code to the /app directory and that is what app. py and app. py has my code and then I'm saying expose 5,000. This is a documentary instruction which is saying the application that we are building listens on port 5,000. And finally I am running python application. I'm saying python run app. py run the code that is in app. py as simple as that. Then I also have a dot docker ignore and you can see what all things are here. So this is what my git has. Now I want you to clearly know that we discussed in the last lecture that if you go to where Jenkins home and if I do ls then whatever jobs we are creating those jobs will be stored here and whenever you run that job so the build happens in a scratch space and that scratch space is work space. So whenever I perform this get check out here. So for example I have written this here. So whenever I'm using this plug-in what this plug-in will do is it will perform a get checkout. So it will clone whatever is there in my repository in the workspace. So essentially if I cd into workspace you will soon see when I run this there will be a new workspace with the name whatever is the name of this cwvj double o flask will be created for us. Now let's come to the meteor part that is execute shell. So I will copy and paste commands and I will explain you step by step. I wanted this to be complete which is why I'm not typing every command that will make this lecture extremely long. So let's not do that. So I will copy the first command that I want to run and I will paste it here. Now read what we are doing. Docker login uses injected environment variable. Understand like I told you before we will be running docker specific command. We'll be performing docker push. And for that to happen clearly what we want to do is we want to perform a docker login. But Warun what are these? You have not created any credentials for docker hub yet. So let's do that and then we'll come back to this step again. So I will scroll up here. I will say yeah environment. In the environment section I will choose use secret text or files. I'll click on this and I'll click on add binding and here I will be choosing username and password separated. Okay. So the username variable is let's type docker hub user here and then what is the password variable? Docker hub. If you're not getting this just hold on we'll look into it. And password and here it is saying which credentials you want to choose. Now this I am creating for Dockerhub. But remember in the step here we created credentials for GitHub. We did not create credentials for Docker Hub. So let's do that. I'll click on this and open this in new tab. I'll go here. I will go to credentials and here I will click on this and then I will click on this and here I will click on add credentials and the username is now here you will have to enter the username of your specific docker hub account. So my username in docker hub is cloud with varosh which is why I am typing cloud with varosh. You will have to type your own. And I think I forgot to explain this scope. The scope global implies the jobs can also use these credentials. If you keep it to system, only your Jenkins controller that is your control plane and your nodes that is your data plane. Your agents can only use these credentials. But we want our jobs to use these credentials. Hence, I have selected global here cloud with VJOS. And then here I will add my password as well. I will type the password for my docker hub. And then ID I will give it a ID that I want. Let's call this docker hub because this is what I will see in the GUI. So now cloud with varos is the username. Here I have typed the password. I have the ID as dockerhub. I will click on create now. So we have the credentials for both GitHub and DockerHub. So let's go to our pipeline again and then I will scroll down. And here you see specific credentials. I do not see that yet. So let me do one thing. I'll just quickly I'll just copy this one so that I have to type less and then I will close this. I will click on add. Add username and password separated. So you can also have co-joined depending on your requirement but I want to specify user and password separate which is why I'm choosing separated. So here the username variable is docker hub user and the password is dockerhub pwd. So what we are saying is when we are running this pipeline we will call these using this variable. Now I will tell you why this is helpful in a little while. And then here which password do I have to use? This is for GitHub. I want to choose cloud with VJOS here. Cloud with VJOS is my username for Docker Hub. So I will come down now. Now let's see what we are doing here. Understand that when you are using this what happens is Jenkins credential binding injects this and this at runtime and masks them in the console output. So when you are using this variables you will not be seeing what your passwords are in your console output and that is what you want. Imagine if you were to type your password here. Ctrl Ctrl + V. If you were doing this, my username for let's say Docker Hub is Vun and then my password is let's say VUN. Then you would see all these in your console output. We do not want that. Hence these bindings, whatever binding that we just created bindings, this will help us redact our passwords. You will just see asterisk when you see the console output log. Even when I am running echo this password, you will not see this. So these won't be displayed. The values for this won't be displayed. But you might be thinking then Wun why are you using this format? Those this format is what is recommended by Docker. You must be thinking why I am not using this because I could have used the password using this format and Vun you have just said that the passwords are redacted. So we can use this right and you can of course you can use this but the recommendation from docker is whenever you are using any passwords use this format. So you echo this and docker login you ask this command to take it from standard input and this is the standard input. So I hope this is understood. Now let's move to the second part. So understand this builds first step was docker login. Now let's see what is the second step. The second step here is image naming. I am creating two variables here. The first variable is image and image is we know this is the path and you could omit docker.io because we are using docker to run our containers and default image path has docker.io already added. I could have started this from cloud with varosh and let's do that. Let's do that and while you are practicing you can add this. So I'm saying image the image variable has the value cloud with vos cwvj flask. So this is what the name of the repository is and this is my account name tag I am saying concentrate on this thing. I am not supplying the tag manually. I have variableized it and I am saying use the inbuilt variable called build hyphen number for my image tag. So understand whenever you see your image in docker hub let's say with tag nine you would know this image resulted from build number nine in your Jenkins. So try to connect the dot and as you progress with this course we will see what are other ways to integrate tags what all other methods you can use and anyone if you are just watching this lecture you can get the information about built-in variables from here. So these are all the built-in variables that Jenkins provide you. So if I run build hyphen number you see build number the current build number such as 153 an example. So when we run this for the very first time, this pipeline, this Jenkins job for the very first time, it will have the build number one. So that is image naming for you. And then the third step is this one. I'll paste it here. And what is the third step? We are saying build and push exact tag plus latest for convenience. Now understand we are just echoing building image. Then I'm writing docker build t. I am creating two tags. The first tag is image colon tag and this will take the values from here and we have defined these values here and then I am adding one more tag and which is latest and why you are doing this warun understand that if someone tries to pull the image without supplying any tag then by default the latest is added and if you do not have latest in your container registry then that will error out. So for convenience of other developers whenever you are creating a container image you add the latest tag as well so that if someone tries to pull the image without supplying any tag then they do not face any error. They get whatever you have pushed as the latest tag. So every time you create a new version you also create a latest tag. Now again in some of the projects you might see that latest tag is not at all available. So that developers will have to provide the exact tag that they want to fetch. And in our previous lectures we have also discussed in production you would see instead of tags in place of tags right now we are using the build number but it is the image digest on the basis of which the images are pulled and that's a discussion for a different lecture. So for now understand we are providing two tags here. Now let's see what is the fourth step and in this step I'm doing few more things. Once the image is built I'm also pushing it. So here is the pushing command. So I'm saying docker push this. Docker push this. And why will I be able to push this? I will able to push this because I've already logged into my docker hub. This is extremely critical for you to understand. This push will fail if your credentials do not work. So let's come down and add point number four. Four is just deploying. So let's come here and I will add this and deploy on the docker host. D O D echo deploying docker pull docker rm this. Now in case you have a container that is already running with this name then this command will remove it. It is for convenience. And then in the next step, I'm saying docker run-d name. This is the name of the container. And then I want to expose my container on port 5,000 in the docker host. And that will hit on container port 5,000 where my application is listening. So I hope this is connecting all your dots. So if I go back and the last step I want to add is the fifth step is this. Let's add this. I will save this and then let's click on build now. So if I click here and I go to console output, this is showing me live what is happening. Understand we have the git step which is why it is performing a g check out and see it's saying echoing echo logging into docker hub logging into docker hub then echo see it did not show us the password we wrote echo dockerhub password but it did not show the password here which is the reason we used the binding plug-in then it is saying login succeeded image is equal to cloud with var this tag is one. Why is this one? This is one because this is build number one and we asked it to tag our images based on the build number. And if I scroll down, it is running docker build- t it is building that image. Then if I scroll down, you see all this process when you create docker images and then you create a container out of that. So all of these things you will see here and see docker push. Now we are pushing. So that implies our login was successful. It is pushing and then it says docker push this. If I scroll down layer already exists. Scroll down. Then it is finally deploying step deploying docker pull cloud with vjo this pulling from this. And if I scroll down docker remove this this it says error response from damon. no such container because container with this name was not there in my docker installation right now. So then I'm finally running this container and I added a sleep 2 seconds. Now it is saying hit http localhost 5000 to see the application. So I can right click on that open link in new tab and here it is localhost 5000. Welcome to cloud with VJosh built with flask shipped by Jenkins running in docker. That is how cool Jenkins is. You have successfully not just build an application, you have deployed it onto docker host and this is just the beginning. Imagine if you want to deploy it onto Kubernetes, you just provide the credentials and the information about your Kubernetes cluster and it will deploy onto Kubernetes. So this lays the foundation of whatever we are going to discuss. So I hope you are watching these lectures in sequence for everything to connect. So now what I will do is I want to show you a few more things. I will go here whatever logs we have seen. So these are the logs. I would encourage you to see all these logs and compare them with the commands that we have run. So I'll go to my CLI here. I am in the workspace. I'll hit ls. And yeah, now you see there is a workspace for this created. So I will cd into cloud with this directory. I'll press ls. And you see whatever was there in my GitHub repository is here. And if I run docker images, you will see that the image that we just created, we tagged it with different tags. Tag one and then the latest tag. You see these here. If I go to my browser and I go to my docker hub, I click on refresh. Here we will see cloud with varosh flask is here. So if I click here you will see there are two tags which are available latest and one and you see the digest is the same. The digest is same because the contents of both these tags are the same and we discussed this in I think day two of this series. So I hope all of these things are making sense. Now what I want to do is I want to also clean up this directory once this is successful. So what I can do is I can add one more step. Uh we discussed about cleaning up the workspace in the previous lecture. Correct? So I want to do just that. So I'll click on configure. And now understand this will also so if I append this I want to append this cleanup step. And if I do this, this will also create a new build. So if I add this and I save this and I run this again, what it will do is it will create one more image for me. But it will also clean up my workspace and that is what I want for now. So let's click on save and see what it is doing. Cleaning workspace. We saw this in the past lecture as well. We are using a built-in variable that is workspace and we are just asking the current workspace. just clean this after you are done. So I'll save this. I will just click on build now and this will again build this image and this time you will see the tag is two. So let's wait for it. And this is the reason if I go to configure again now I added this step because we know that this container would already be there but this command will first remove that and then redeploy the container with tag 2. So let's go here and then let's go to the console output here and it is deploying. It's in the final steps and it has successfully deployed. So interesting thing is now I want to go to item hit ls you don't see anything because we have cleaned up our workspace and a few important things are if I go one step back and I hit ls whatever credentials I'll go one more step back if I press ls whatever credentials we have saved they are saved in this file they use both encoding and encryption so you will not see them in plain text but know that they are saved here. So even if you delete this Jenkins instance you recreated you will see your credentials are still safe because they are part of Jenkins home. That is all I wanted to cover in this lecture. So that wraps up day five. You configured DOD, used Jenkins credentials, no secrets in the script, built a Docker image, pushed it to private registry and deployed it on the host using pinned tag for traceability. You now have a clean reproducible CI flow you can extend. Next in day six that is project two, we will refactor this into a pipeline which is also known as Jenkins file. If you have any questions, feel free to ask them in the comment section and I will reply. If this helped, do consider liking, sharing, and subscribing. It will mean a lot to me. Thank you very much. Hi, I am Varun Jooshi and welcome to day six of our Jenkins basics to production course. Today we will take the day five freestyle flow and refactor it into a clean Jenkins file. We will map stages, check out, build, push, deploy, test, use environment variables and credentials safely and add practical touches like post actions, a deploy info.ext artifact for traceability and workspace cleanup. you will leave with a production shaped pipeline that's versioned in git and easy to evolve. So let's get started. So before I start this lecture, what I will do is I will go to my GitHub notes and I want to show you the prerequisites for this lecture. I will open this one and then I'll go to day six. I will use the table of contents to go to prerequisites. I will zoom in a little. See this is day six where we are upgrading the project that we did in day five and that project was done using a freestyle job and today we are upgrading the same job into a Jenkins pipeline. Hence I would urge you to do watch day five to get that understanding. And apart from that we also looked into docker outside of docker and compared it with dd that is docker in docker. So this day day five can be seen as a cicd project that will take you from basics to production. So I would recommend you watch day five and once you have done that let's get started with day six. Now before I start this one, I want to take you to my diagrams and show you what we are going to build so that it develops your interest from the word go. So this is what we are going to deploy. You see Jenkins at the very top. Jenkins is our orchestrator. I wanted this project to be production grade. So here we'll be leveraging a private git repo. This private repo will be hosting our source code and the docker file. Then we will be building a container image container image using docker build. After that we will push the build image to our image registry or container registry which will be docker hub. Next, we'll be deploying our container image onto a docker host. And finally, we are going to test our application. And this is called a smoke test. Smoke test typically mean that you check whether the website is accessible and may check the most basic functionality. So in our scenario, we will just be trying to access our website from the browser. So all these steps we'll be doing via Jenkins pipeline. I want you to know that there are certain steps which will warrant us to use credentials because if you are trying to access something external, something private, you will have to supply credentials. In this pipeline, we'll have to provide the credentials for the git repository and our git repository is hosted in the gith host named GitHub. And then we'll need credentials to push the container image that we'll build out of the docker file that's in our private repository. We'll have to push that. And for that as well we'll require credentials for docker hub for the account cloud with varos. So we will do all these things. So let's get started. So I'll take you straight to the genkins console that is localhost 8080. I'll go here. I will click on new item. And here I'm going to name my job flask pipeline. And once I do that, I'll click on pipeline and I will create click on okay. Understand that we were working with a freestyle project until now. But today we are going to discuss the pipeline. Hence the item the job that I'm creating is of type pipeline. I'll click on okay. And you see something similar like we saw in freestyle job. We have these. Then we have triggers. And then we have the interesting part. We have the pipeline. Define your pipeline using Groovy directly or pull it from source control. So what it is trying to tell you is when you are writing a pipeline, you have two options. You can either write your entire PI pipeline in here in this screen or you can pull that pipeline or you can pull that pipeline script from SCM. Now in production implementations you would always be using pipeline script from SCM. You will not be writing your pipelines here. But since we are just learning to walk right now not run we will start with pipeline script and then we will convert the same script into SCM. It's just a click nothing more I promise. Now that we have this basic understanding let's try to learn the pipeline syntax. Now for that I will take you to Visual Studio Code so that we have proper color coding while we practice this. I'll right click here new file and I'm going to call this file Jenkins file. And why I'm naming this this way at least as of now is so that I get proper color coding. Now you could name this anything for practicing but as we progress with this lecture you will understand what is the significance of naming something Jenkins file. With that understanding let's write our first pipeline. I will start with pipeline. This is the top level block. I'll zoom in a little. This is a top level block that you will always see at the very top. I'll hit one space and then I will add a curly brace. I want you to concentrate on the color coding of the curly braces. Right now the curly braces are white which implies they are associated with the pipeline block. Next I will write agent any. Now understand when you are running a Jenkins job your job must be executed somewhere and in Jenkins architecture jobs are executed by agents and here I'm saying use any available agent more on this in a little while now then I have to add what we want to do so if I take you back to the diagrams What you see here is we are performing all these steps and all these steps can be thought of as stages. There is a check out stage, there is a build stage, push stage, deploy stage and test stage. Similarly, when you are writing pipeline, understand all of these things will happen under the pipeline. So it makes sense to have those things inside the pipeline block. But you can have that inside the pipeline block. But at a very high level, what are these things? These things are stages. And this is stage one, stage two and so on. So what I will write next is I will just write stages here. And I will again open a curly brace. And as soon as I did that, you see there is a color coding. It is pink. It tells me anything within the stages block must be contained within this pink curly braces. I will press enter. And then inside stages, I will have to mention what all stages are there. in my stages section. What is my stage one? What is my stage two? And so on. So what I'll write here is stage. I will open a parentheses and then I will write checkout because my first stage is checkout. If I go here, this is my first stage. Now that I have added my first stage, there would be certain steps that I need to perform within that stage. So if something is within this stage, then I will have to define that something here. So what I will do is I will come here and I will add a curly brace again and I will press enter. Now what is inside this stage? Inside this stage there are certain steps that I need to perform. So as the name implies I will just write steps here and inside the steps block there will be steps. So I will have to again start a curly brace and press enter and then I will write what is the step that I need to perform. So for now let's just write echo checking out from private repo and I'll close the single quotes. So the crux is this is the pipeline curly brace. It ends here. Then there is a stages curly brace. It ends here. Then there is a stage curly brace that ends here. Then there is a steps curly brace that ends here. So try to create that mental picture. There is pipelines at the very top then in the pipeline you will have multiple stages and within those stages you will have your steps. So as long as you understand the foundational concepts these things are a cake work for you. Now understand that whatever that we are doing is being done inside a pipeline. Hence you will see anything that we do will be written within the pipeline block. And I want to tell you one more thing at this stage itself because I know you will understand that. So I will go here. I quickly want to show you. Yeah. So here is the pipeline block required top level block. And right now we have mentioned agent is any. So any as in any available node understand in our architecture right now there is as we have discussed before there is a control plane in Jenkins and then there is a data plane. Control plane is essentially the controller and it is the controller where you create jobs and then controller will ask different agents or different data plane nodes to take action and execute those jobs. So jobs are created in the controller and they are supposed to be executed in the agent. Now and we have discussed this before. Okay, if you are not understanding this, watch the past lectures. In our architecture, the control plane and data plane is consolidated. So we have a single Jenkins container that is doing everything for us both the controller part and also the executor part. Hence I have written agent any and this will pick up any available agent and that available agent is our Jenkins controller itself. So if I go here if you see this second bullet I have mentioned what is the agent label docker. Now understand in an architecture where you have multiple agents how do you call the agent that is supposed to perform docker related task? You add labels to your agents and we'll see this later as we progress with this course. But for now understand that you can have multiple agents and those agents will have labels associated with it. And why do we need labels? For example, if I'm executing a pipeline that requires Docker installed, then I will use an agent that has Docker installed. If I'm running a Maven related build for Java, then I will choose an agent that has a label Maven so that my job can be executed in that agent because that agent has all the prerequisites that are required by my Maven job. As simple as that. So what I will now do is I will get back to our pipeline, the code of our pipeline. I will copy this thing. I will take you back to the browser and then let's go to our job and here I will paste whatever we have written right and then I will save this and you see something different here this time you have a stages section as well and stages is what we call these things all these steps that we have performed here these can be thought of as stages and whatever you define in the stages section within your Jenkins pipeline will be displayed as stages on this screen. And how cool is that? You can see whatever you have done in that stages console. So let me first build this job so that I see the stages being populated. So it is here. Now let's go to stages. The first build is successful. I will click on stages and you see how good this output is. It is saying number one build. This only had one stage which was check out. It started here. It ended here. Only one stage was there which was checkout. And that stage was successful which is why you see a green tick here. And if I click on this green tick it will take me to the part where we executed something. And here we executed check out from private repository. We just echoed this. Hence you only see this step. So here is the stage and here are the steps. Now understand as you increase your stages all of these will be displayed here. And when you click on that stage you can see the steps right here. You can see what failed. You can see what was done as part of that stage. So I really like this screen. This gives me a very good view of my entire pipeline and rest of the things are pretty basic like we have seen before. If I click here, I can go to console output and see that this job was running in a node Jenkins and then it was finished successfully. And this is what we echoed checking out from private repository. Now that we have this basic understanding, we understand what the syntax looks like. Let's go and add a few more stages. Understand that if I look at it, this is stage and this stage has steps. This stage ended here. Understand that here is the stage is the cyan curly brace and this cyan curly brace ended here. And whatever stage you create must be created within the stages block. That is understandable. So whatever stage you create as long as they are inside the stages block you are good. So I will copy this stage and then I will add this stage here. This is stage two, stage three, stage four, stage five. As simple as that. But I will have to name my stages properly. This stage I will call build. This stage I will call push. And then next we are calling deploy. And after deploy we will have test. We have test here. And now let's also update these. I will write this is the build step. I'll add an exclamation mark for effects. I will copy this. I will add this here, here and also here. And then I will write this is the push step. This is the deploy step and this is the test step. So now we have a pipeline that has five stages. And let me zoom out a little so that you can see everything at one place. So we have this pipeline which has five stages and I'm telling you ultra honestly if you have understood this this structure you have understood pipelines there is nothing more I promise rest when we add the steps that we want to add those are just commands and we'll walk them step by step so if you understood this you are good with Jenkins pipeline I will copy this and then I will again go back there. I will go to this job. I will click on configure and here I will paste whatever I have. I will click on save and I will build it. Now the job has completed successfully. But this time the stages would look pretty nice. You see build number one is here. Build number two is here. And this is our build two. So if I click here, it will take me to this awesome view. I can see all my stages. If I want to see what happened in which stage, I just click on that stage and it will tell me this is the build step, push, this is the push step, deploy, this is the deploy step and so on. This is super cool. And then I will go here and I'll show you the console output. And this is also what is expected. Now we have this understanding. So let's start with making this pipeline really awesome at what it does. So I'll go to Jenkins basics to production repository. I will go to day five because day five has the commands that we ran the last time. So I want to use the same commands because we are doing the same thing. We are just doing it with the pipeline. And I also want to explain you the application that we are deploying once more. So that if someone is watching only this lecture they have this understanding. So first I will copy this quickly and then I will go to Visual Studio Code. I will just create a new file here and I will call it test.yamel. I have the YAML extension so that the cosmetics are good. Nothing else. I'll just paste it here and then I will right click on it and I'll write split to write. But before that I wanted to explain the code that we have with us. Just give me a moment. And if I let's rename it to something else okay just test because I don't like this red. Anyway, so now let's understand what is happening in our code. So for anyone who does not know what we are deploying. So this is app. py. In app. py we are just creating a simple application python application that uses the flask framework. And then what we are doing here is we are just saying welcome to cloud with varosh built with flask shipped with Jenkins running in docker and our application once deployed will be listening on port 5000. understand that I have coded my application to listen on port 5,000. Then I want to show you the docker file. In the docker file, I'm saying use the python 3.11 slim image. Then I'm saying working directory is / app. This implies that whatever commands I'm going to run next, all those commands must be run in this app directory. This becomes the working directory. Then I'm copying requirements.ext. What is inside requirements.ext is the information of all the packages that are required by my application. So if I go to requirements.ext, I just have flask and I'm mentioning the version for it. Flask because flask is a web framework in Python which is used by web applications. I'll go to docker file again and here I'm copying the requirements text file. I'm copying it in the working directory which is this one. Then I'm saying run pip install-r requirements.ext. Now understand that I am saying here you want to use requirement.ext to install the packages and I'm mentioning here no cache diir. This signifies that whatever download logs or whatever anything else apart from the flask framework that is generated you just discard that and why I'm discarding that because we want our container images to be as small as possible which is why I'm mentioning no cache diir pip as we know is a package manager for python then we are copying our code app py which is here into our /app directory. Then we are just mentioning this for documentation purposes. This won't actually make our application listen on port 5,000. We are saying expose 5,000 so that DevOps admins would know when they look at the docker file that this application yeah it listens on port 5,000. Then we are finally running our Python application by providing a command instruction python app.py py app. py is the name of our file that has the code. This is a simple code that we are deploying. So I'll just close this and let's start building our docker file here. I will go to view and I will just quickly word wrap this so that we can see everything. Now first step is check out. understand that we will have to provide some credentials for this pipeline to check out our code. So how do we provide credentials? So let's go to our browser and then go to our Jenkins console. I'll go to this job and see what I am doing. There is a pipeline syntax here. I'm right clicking on it and I'll click on open link in new tab. I'll go here and this is a very cool place to be. This will help you generate certain things that you want in your pipeline and we will explore this as we progress. But you see you can generate so many things as we progress with this lecture. We'll be using a lot of these and let's start this by using git git. We are providing the credentials for git which is why I'm using this. Now why is this useful? So anything that you want your pipeline to do you can have certain automated ways via which you can embed those things into your Jenkins pipeline. And this is one way the snippet generator will help you learn the pipeline script code which can be used to define various steps. And in this step what we would want to do is we would want to perform a get checkout which is why we are here to generate the pipeline script for that. So here it is saying what is your repository URL. So I will go here. I will go at the very top and here I want to go to cloud with vj. I already have a private repository created from the past lecture. If you do not know how to do that, watch the previous lecture. Otherwise, just open your private repo. And this is my private repository. It already has the docker file app. pyre requirements.ext. Okay. I will click here. I will get the URL. I'll copy this. And then I will come here. I will paste this URL. The branch I want is main. Okay. And since it is a private repository, it is giving this because I'm not yet provided the credentials. So I will come here. I already have added the credentials for GitHub. If you do not know how to do that, go to the previous lecture and watch that. We created a personal access token known as PAT and then added those credentials in our Jenkins GUI. So watch that lecture and do that. So here I will choose this cloud with VJOS - GitHub and then include polling. Understand that we are not polling any repository right now. We'll be manually running this job. So for now I will just unselect this and then you see include in change log. So when change log is true, Jenkins records the SCM changes, any changes that you do between this build's checkout and the previous build checkouts for that job. So I would recommend you to check this so that you have all the changes with you. And then I will simply click on generate pipeline script. It has generated the script for me. I just have to copy it from here and I will go to my visual studio code and within the step I will remove this echo and I will add that step and then for just cosmetics what I will do is I will bring this URL down so that we can see everything at one place. I will just make it a little bigger this one. And you see get branch main credentials ID is this and then poll is false like we supplied and the URL of the repository is this. So understand in the previous lecture if we were writing any shell scripts to do that with pipeline we are just using this to provide the details about our private repository and I'll also go to view and word this so that we can see everything at one place. Now that we have done this let's add the build step. Now what were we doing in the build step? we were building our container image. So what I will do is here is the command that we use to build our container image this one. So what I will do is I will copy this command and I will simply paste it here. What I will also do is I will add sh here and then I will close this single quote. But warun what is this sh? Now sh tells Jenkins to run a shell command on the agent. So it is asking the agent that whatever I'm giving in this step you have to execute that using a shell. Understand when we were doing the freestyle job the commands that we were writing were already in the block that was named execute shell. So the agent was automatically executing those commands in the shell. But here this is the pipeline syntax. We have to explicitly tell the pipeline syntax that whatever I'm typing now must be executed in shell. That is why we have added sh. Now pipeline also has many built-in steps. What are built-in steps? These are built-in steps. Hence here we did not have to invoke any shell. understand that you could perform these things using shell as well. You could provide the credentials using shell but we do not want to do that for things that are built into Jenkins and hence we have used the thing that is built into Jenkins in this step. So I will summarize this. SH tells Jenkins to run a shell on the agent. Pipeline has many built-in steps like get archive arc artifacts. We'll see all these as we progress. There is with credentials. But when you need to run a CLI like docker, you use SSH. Now understand if this were Windows, you would be using BAT or PowerShell, not SH. I hope this is understood. But another thing that is worrying me right now is image tag. All these are variables. Where are the values for these variables? We will provide them. But for now, let's see what we want to do in the push step. Now in the push step, we have docker push this and this. I will copy this. I will come here. In the push step, I will paste these here and I will make this cosmetically fine and I will add sh here single quote single quote. Then here I will write sh single quote single quote. So now we understand what we are doing here. We are pushing the image and we have to pick these values from somewhere and that somewhere we'll define shortly. Let's go to the deploy step. So what are we doing in the deploy step? These are the things. I will copy all of these and then in the deploy stage I will just paste those right and then I will move this here. I will also move this here. And then here I will write sh single quote single quote sh single quote single quote sh single quote single quote and we discussed in the last lecture what these double pipes mean. These mean that only run this command if the first command fails. So we are doing this so that our pipeline does not fail if this does not succeed. Let's do one more thing. We have to define the environment variables. And where do we define that? There are two ways to do it. Here we are using our variables in three stages. We are using it in the build stage. You see image and tag here. We are using it in the push stage. You see image and tag here as well. And we are also using this in the deploy stage. So we have two options. either I can define environment variables per stage or I can define them for the entire pipeline. If I define it for the entire pipeline then all the stages can use them. If I define it only within a stage then only that stage will have access to those environment variables. But here there are three stages that will require that environment variable. So let's define the environment variables at the pipeline level itself. So that all the stages can consume them. So I will come here. I will add one more block and this block is called environment. And this is the way you define environment variables. I'll start a curly brace as with all the steps we have seen in the past. I'll press enter and within this environment block I will be defining my environment variables. So what are my environment variables? These are my environment variables. I will paste them here and then I will explain you what these are doing and we discussed them in the previous lecture as well. So image is my dockerhub account is cloud with varosh and there the repo name will be cloud with varosh flask and what will be the tag tag will be the build number. So we are tagging our image with the build number. Now let's come to the last step. Last step is stage is test. what we want to do in the test stage. I just want to do this. So I will copy this and I will paste this here and then let's come here and I will just move it here and let's add a semicolon and then here as well. This is shell right? So I will write this and then I will close this here. Now there is one more thing that we have to do here. I have just written push but where are the credentials? How will this push to docker hub if I do not provide the credentials in this stage? So let's provide the credentials now. So I will go to my browser and previously we used the pipeline syntax for git. This time I want to use it to generate credentials for my docker hub. So the sample step I wish to use is called with credentials. Here is with credentials. Bind credentials to variables. Understand when we were working with the GUI in the freestyle job, we chose under the bindings section which credential we wish to use. So similarly here as well you have with credentials that are used to bind credentials to variables. What are the variables? We will see it in a little while. Here I'm saying with credentials bind credentials to variable bindings. I will add the bound binding username and password separated and we have seen this in the past. Here I will write docker hub user is the variable that I want you to use. and then dockerhub_pwd is the password credentials. Both of these credentials belong to my dockerhub account. So I can choose any. I'll choose this one. And that's it. I have entered the username variable is this. The password variable is this. The credentials that I want you to associate are these. I'll just click on generate pipeline. So it is saying with credentials username password docker hub password variable dockerhub password username variable dockerhub user understand that this is the credential ID. So I will copy this and then I will go to my pipeline code here. I will go under the steps under the push step because that is where we want our credentials to be. I will just paste that block here and understand that whatever we are now performing those things are to be performed within the with credentials block because both of these commands will be using the credentials that are here. Understand? Now there is one more step that I have to do that is we'll see in a little while but for now let's cut this from here and add it here and it will make much more sense to you once I add that command as well. So I will come here and if I scroll up here is the login command. So I will copy this to login. I will add this here. SH and then let's bring them in one line. So now within the with credentials block, I'm starting the with credentials block with this dark pink. And then I'm closing it. This is purple I believe. Anyway, so I'm starting this here and closing this here. And all the commands that are to be run within this with credentials block are here. Now what we are doing we have discussed this in the past lecture as well. We are echoing our docker hub password and then we are using docker login - u. We are defining the variable. So this is the variable docker hub user and then we have docker hub password which is being picked from here and then we are performing a docker push. So what we are doing is we have tagged this image with two different tags. You can see here this there is a latest tag and then there is a tag that we have defined as environment variable. So we are doing these things now. That's it. We are done with this. We don't have to do anything else. So if I copy this entire thing, okay, and I go here to my Jenkins console, I will go to my pipeline. I will go to configure and then I'll paste that code here and let's quickly see that we have everything. This is a tag. Checkout stage. Yes, build is this. Push is this. We have the credentials here for git as well. We have everything that we want here. We have also supplied the credentials. Credentials ID is this. This looks good. Push also looks good. Deploy is also fine and in the deploy stage we are just first we are pulling the image then we are removing if there is any existing container even if this command fails we have true here so that the next command will run and next command is docker run this one we are running a container in the background and we know on which port our application is listening and finally we are doing the testing as well so I'll save this I will click on build now and our job is running and you can go to the console output and see where it failed. It has failed. So let's come down and see where did it fail. Push skipped due to earlier failure. Docker build- t this this latest docker not found. Why is this docker not found? Hold on. Let's go to our terminal. Docker execit. The container that I want to exec is Jenkins. And I want a bash there. And here if I write docker docker not found. But we have oh I recreated this container. So I did not install docker cli yet. So let me install that. So if you have performed the steps that were part of day five then you should be good otherwise just follow along with me whatever I'm doing. So I'll go here. I will go to cloud with var Josh here. Then I will go to Jenkins basics to production day five. It's a simple step when you have documented everything. I will scroll down and here is where I want to install Docker CLI. To install Docker CLI, I will have to run these commands. I will just copy them from here. I will go to my terminal and I'll paste that. Some troubleshooting, right? Failure writing output to destination. What destination? I'll have to do this as root user. Hold on. I'll exit. And then here in this exact command I will just add hyphen u root user is root I want to login with and then I can just paste the command. I'll press enter. And if you have any confusions about this what we are doing just watch the previous lecture. Okay. Okay. Docker CLI is installed. What I will now do is I will exit from here and then I will again exec and then this time I will run docker. Okay. So now docker is installed. So let's go to our job again and I will come here and then let's come here and I'll click on build now. It will start the build again. Let's click here and see the console output now. Okay, this looks good now. Things are working. It is pushing the docker image. Let me also open hub.doccker.com. sign in and here less than a minute ago you see a push was just performed. So let me zoom in a little by our Jenkins. So I will go here and then the job has finished successfully. I don't want to show you the logs from here. I want to go to the stages in pipeline. You see how good this is. It is saying that your third build failed. And if I click here, you know, it will tell me what was the problem. It is giving the error right here. Docker not found. And we troubleshooted that. We understood that Docker CLI was not installed. Which is why we are receiving this error. So if I go to push deploy test, these stages were not invoked from build. The pipeline was directly ended. So this is a good thing to do. So here itself I can go to build two, build three, build four is the one which was successful for us. Now each step whatever we asked Jenkins to do all those steps were performed in each stage. So here you see the cloning was done. Then I move to build. In build stage our container image was built. If I go to the push stage, this is where our container image was pushed to our image registry which was docker hub. And in this deploy step, we deployed a container. And you see this is the container ID. If I go to test here, you can see echo this. Hit this to see the app. So if I right click on it, open link in new tab. Voila. This is our application. and welcome to cloud with varos built with flask shipped with Jenkins and running in docker. So we have now gotten a very good understanding of the pipeline syntax and how do you do these kind of things using pipeline. Now I do not want to finish this lecture here. I want to improve this pipeline further. So let's do that. Firstly, let's use I'll go to the browser and then I'll go to this flask pipeline. I'll click on configure. And this time what I want to do is I want to use pipeline script form from from SCM. And this time I want to use pipeline script from SCM. So I'll click here. And you see the box where we were typing the pipeline just vanished because we have now said that the file that you use for the pipeline is stored in SCM. And here it is saying what is your source control? I'm saying my source control is get. Now it is asking me the URL. understand that by default what you will name your pipeline file is Jenkins file. Okay. So that is why in the script path you see Jenkins file is populated by default and let's keep it Jenkins file and you will see most of the projects will do this. Now if they have three different pipelines for dev, prod stage then they might name their files like Jenkins dev, Jenkins prod and so on but Jenkins file as a word is pretty much always there and I'm not saying you cannot name it anything else. I'm just saying it's a good practice to keep Jenkins file. Now if I move up understand that there must be some repository where I'm storing this Jenkins file right and I again have two options here either I can store my Jenkins file in the same repository where my code and docker file is or I can host my Jenkins file in a different repository. Typically you will host your Jenkins file with the application code itself with your docker file and the application code itself. So in this lecture we are going to adhere to that strategy. So here it is asking me the repository URL. I will come here. I will copy this URL. I will first let me close this and then I will paste this URL here. The credentials that I wish to use for my GitHub are cloud with var GitHub and then this is fine. This is fine. This is fine. That's it. But Vonun, where is the Jenkins file? Jenkins file we'll have to upload in the private repository. Right? We are saying you Jenkins pick the Jenkins file from the GitHub repository. So now we'll have to create a Jenkins file and put that file in the repository so that when we initiate this build, Jenkins just picks that file from our source control and builds our project. Right? So let's click on save here. This is now saved. Now let's start building our Jenkins file. Now conveniently I have initially named this Jenkins file so that our job gets easier. Understand we do not need a checkout stage now because hello we have defined whatever we had to define for checkout in the GUI. Remember we defined all the things here. So let's just entirely remove this stage and understand this stage started with a cyan curly brace and finished with a cyan curly brace. So just look at the curly braces when you want to remove something so that you do not mess up your groovy syntax. So I will just remove this from here and then the checkout stage is removed. We are starting from the build stage. Now there are certain improvements that we want to do in this pipeline and I want to show you what those improvements are. The first is use pipeline script from SCM. We have already seen that. Now understand you can always add post actions in your pipeline. What happens on success? What happens on a failure? And what happens if there is success or failure? You can define these things in post actions. So what I will now do is I will define certain post actions for my job as well. So what I will do this time is I will copy a certain section and I will paste that section. So I'll come down. So understand that we have to add the post actions. These are the stages. stages started here and stages ended here. The pink curly brace follow that we have to define post actions. These post actions are for the pipeline itself. We are not defining these per stage. We are not defining this for any stage. We are defining it for the pipeline. Understand the distinction. Post actions in this lecture we are defining for the pipeline. Hence I will have to define at the pipeline level. And what is the pipeline level? Pipeline level starts at this curly brace. The white curly brace. So whatever I am defining now should be within this white curly brace. Not within the curly brace of stages. It must be in the curly brace of white of the pipeline. And hence I will come here and I will paste that. And now what we are saying is and this I have just changed the way it looks. Okay, it's the same thing. You can also do it like this. It's just I want you to be familiar of different ways you will see this pipeline. So what I'm saying is post post actions success echo build this is succeeded failure echo build this failed always echo build finished this is as simple as that now you can have various post actions you might want to send emails and so on and as we progress we will do those things but for now I just want you to know that you can have these post actions as well. So we have added this post action. Let's go to the diagrams and see what we want to do next. Generate a deployin info.ext file and archive it. What is the significance of deployin info.ext? I want you to know that whenever you are building something, you want certain information to be captured in a file and maybe that file is used by a different tool or by Jenkins to deploy your artifacts. So for now I will leave it here itself. In day two's lecture, we understood that this file is generated and this is kept somewhere in the object storage or in the file storage somewhere that Jenkins has access to it. And once Jenkins has access to it, Jenkins can pick the details from this file and deploy your infrastructure. We'll see how that works later. But for now, I just want you to understand the generation part and how this archiving works. So for now, what I will do is I will just copy this part and paste it. Just give me a moment. I'll go to my Jenkins file. And I want this file to be part of the deploy stage. So what I will do is I'll copy it and then I will come here and then I will paste it. I've pasted a bunch of information. So this remains the same what we were doing. Okay, we have not changed anything here. What we have added is we have added this section this. So what we are doing here is we are creating a file that is named deploy info and this build number and we are saying that this file will have the build number. It will have the image name. It will have the commit ID, the branch, the time and the URL. And then in the last step we are saying that once this file is created you archive this file. And I'll tell you what archiving means in a little while. But for now, see this archived artifact. This this this I'll tell you how to generate this. For this as well, you just copy this name. Whatever name you want the file to have. And then you go to pipeline syntax generator. Here I hold on here. I will go to the pipeline syntax generator. I will and this is the sample step. We wish to use archive artifacts files to archive. I will just put the file name here. I will go to advanced and here I can fill in the details. For example, I want fingerprint all archived artifact. So what this means is I will tell you later but when you want to deploy the same artifact across multiple stages and we'll do that later in this course then you can fingerprint all your archived artifact and then I will simply click on generate pipeline syntax and you see this has generated this for us. You just have to copy this and you paste it in your pipeline script nothing more it's as simple as that. Now Jenkins true tells Jenkins to compute and store a unique hash of fingerprint for the archived file and that is what we have said using fingerprint true and follow sim links false if you go here you can read about it by disabling this option all symbolic links found in the workspace will be ignored and it's all right for us to ignore that at this stage now let's see what is the final improvement that we want to do clean the workspace at the very end. And if I go to the pipeline syntax generator, I will just go here and here I will search for clean workspace, delete workspace when build is done. I will click here and here I can go to advanced and it will show you what all you want to do. So clean this workspace when success unstable failure not built aborted. In any circumstance we are saying just clean the workspace. I will click on generate pipeline script and this is the only step that you have to do for this. So let's do one thing. If you remember in the past lecture in the freestyle job we cleaned the workspace as well. So here too we will do that. So I will go to my visual studio code and I will come down and I want to add one more stage at the very last and that stage will be doing the cleanup for me. So I will come here and then I'll come here. I will go here and then I will add a stage. And in this stage what I want to do is clean up and I will close this. And then what are the steps for this stage? I will open a curly brace. I will write steps here and then I will again open a curly brace. And this is where I want that step to be added. And I told you whatever is builtin can be added directly. And that is what we have done. If I scroll up with credentials which was builtin, I added that directly. I did not have to write any SSH for that. So for this two, I have just added cleanup workspace. And once the cleanup is done, then we will run the post action. So I'll save this file. Now I will have to add this Jenkins file to my SCM. So I will go to my private repository. Here it is day six. Oh, not day six. It is my private repository. I will go to add file, upload file and then I will click on choose your file and then here I can choose Jenkins file. I will choose this file. It is uploading that file here and then commit changes. It will commit the file here. Now let's come to Jenkins and run our pipeline. So I will go to this flask pipeline. I will click on build now. Oh, it has failed right away. Let's see the console output. Oh, pardon me. Let's go back. Let's see what the problem is. If I scroll down, I have this master selected and we don't have a master branch. The branch that we have is main. So, I will come here. I will just remove this. I'll I can leave it blank. It will pick any or I can just write main here. I will save this and let's run it again. Oh, it has failed again. Column 9 stage. Oh, I have to add a space. I believe space I have not added. That's the magic of doing things live, right? I will go here. I'll have to first save it. Understand that I have to upload the file again with the changes. I could have done the changes here itself, but anyway. So, I will upload the file again. I'll choose the file. And this one is the file. And then I will click on commit changes. I'll come here. Pipeline build. Now it has failed again. Stage cleanup. Hold on. I think there is something wrong with this. Oh, I think this does not matter having you know space or no space. Stage. Oh. Oh. Oh. Oh. Do you get what the problem is? This part the stage part should have come after the cyan curly brace. Why? See interesting. So you have stage test here. Okay. Test stage started here. This cyan curly brace finished here. So I should have that stage here. Right? So that was the problem. I did it wrong. Now understand this is closing here. Then there is a cyan curly brace. This cyan curly brace where does this belong to? This cyan curly brace belongs to this. Where is this pink curly brace? This pink curly brace belongs to the stages itself. So our this stage the last stage that we added the cleanup stage must be in the stages itself. We messed up the curly braces the last time. I hope now it is corrected thoroughly. So I will go to this screen, add file, upload file, and then let's choose the Jenkins file. I'll commit my changes. What's wrong? I'll refresh. Processing your file. Jenkins file is here. This was committed now. Okay. So I will go to my pipeline now. And then let's build it now. Okay. This time it is taking some time. So I'm hoping things are falling in place. Let's go here. Go to console output. Okay, it has moved to this step which implies things are steady. This console output we have already seen multiple times. I want to show you something different. Let's go to stages and let's see this live or rather click on this and let's see what is happening. You can see all the logs here and you see it is moving step by step. Okay, the deploy stage has come. We are in the deploy stage. Archived artifact has failed. Now, why has this failed? Doesn't match anything. No artifacts found that match the file pattern. Deploy configuration error. Why is this? We are picking the artifact from Oh, hold on. And here I have artifact is this. And here let's run this again because this is deploy build number text doesn't match anything. How can you say it does not match anything? Let me quickly verify because what I have done is day six has this actual file. Okay. And we are doing the same thing. I tested this in my lab and it worked just fine. But I don't have follow sim link here and I have this in my first let me run this again and then we'll run it without that sim link thing. Um I don't think that will cause a problem but I want to just check it. I'm running this again and in the meantime let's edit our Jenkins file to not have that thing. So I'll go to Jenkins file. I'll click on edit and I'll not edit it until my pipeline has moved to a certain step. If I go to stages, it's nine. The push is happening. So I will scroll down here and then I want to remove this thing. Fingerprint was true. Fingerprint true. That's it. Let's see what is happening with the job. Ninth one. The deploy failed. Archive artifact. Okay, this point is failing. So, let me quickly commit these changes and if this works, I'll have to see why this sim link part was causing the problem. I will now come again here and then I will build. Now I'll go to flask pipeline. I'll go to stages push stage. And another thing I want to add is I could have run my pipeline from a you know from a stage as well. So maybe if my file did not have a problem but problem occurred somewhere else I could start my pipeline from the push stage from the deploy stage. So you have those options and I'll show you once this build is done. Now we are at the deploy stage. Deploy info. Why is this happening? Maybe it's the double quotes. Let me add double quotes here. That's the only thing. And then let's try to run this again. It was the double quotes, man. I was using single quotes here. I had to use double quotes. And I'll add in a video ticker what was the actual problem. But at least at this time double quotes fixed the problem for us. We were using single quotes before. So anyway, so the text the test has succeeded. The cleanup has happened. Workspace cleanup and post actions. You see all these things. Build 11 finished. Build 11 succeeded. You do not see the failure notice because the build has not failed. So if I go to the previous build, build build 10 in post actions, you would have build 10 failed and of course the finished part. Now I wanted to show you that right if I go to let's say the latest build 12 11 that has succeeded you can rerun the pipeline from a certain stage. So restart from stage and then you can supply from which stage you want to restart that build. So that is one thing that I wanted you to know. So if you come to status, you have this deploy info 11 and we named it to so that it also has the build number. So build 11 was successful. If I click here and zoom in, you will see all the build information. You see the first seven digits of the commit ID. If I come here, if I go to this private repository and then you see the commit ID 95, it starts with 95, ends with 33. So if I come here, it starts with 95 and ends with 33. The first seven digits. So you see all the information that we added here is available. I want to show you one more thing. If I go to my terminal and I go to where Jenkins home, if I go to workspace and I press ls, you see there is a workspace for our flask pipeline. But that workspace will be empty because we have performed a cleanup action as well. So if I press ls, you don't see anything in this workspace. Now let's do one thing. Let's go one step back and one more step back. If I hit ls, you know all our jobs get stored here in jobs directory. So if I go to this jobs directory, press ls. I go to cd, the name of our job was flask pipeline. If I press ls again, I want to go to cd builds and then ls. I want to go to cd 111. I want to go to the build number 11. If I press ls, I see an archive directory here. And if I go to this directory, you will see that this has the file that we just generated cat deploy do.file. Now why this is here under under the archive directory? Because we archived this using this step here. We said that archive this file which is why it was available for you. Understand when you clean up the workspace it is important before you do that you make your files you make your artifact available somewhere external where you can use them or store them for future use. Now I think if I go to my browser now I go here and you see all of and here was the fingerprint part that I was talking about. We said fingerprint is true. So you can view the fingerprint. If I come here, if I click here, it is telling me this is the fingerprint. The file has been used in the following places. Now understand if this file is used again and again the fingerprint will remain same and you can track that history here. It is good for traceability. Now finally let's do one thing. Let's access our URL. I'll go to 11 and then I will go to no let me go to stages and then I want to go to post actions and in post actions I not in post actions I want to go to test and in test I want to open this URL and you see our app welcome to cloud with varos built with flask shipped with Jenkins running in docker so I think that is all I wanted to cover that wraps up day six you converted a working freestyle job into a pipeline, wired in secure credentials, produced an archived deploy metadata and kept your workspace tidy with cleanup. You now have a repeatable Jenkins file foundation you can extend with parameters, conditionals, and parallel stages. Next time we will iterate further with branchbased logic and promotion patterns. If you have any questions feel free to ask them in the comment section and I will reply. If this helped do consider liking, sharing and subscribing. It will mean a lot to me. Thank you very much. Hi, I am Vun Jooshi and welcome to day seven of our Jenkins basics to production course. Today we will take our day six pipeline and evolve it into multibranch pipeline that autodiscovers branches and PRs builds the right job be it the branch job or PR job and keeps main releasable in a trunkbased workflow. But before we do all these demonstrations, we will first understand what are multibranch pipelines and why they are so powerful. We will wire up an MVP to a private GitHub repository, open PR, manually rescan, and use our shared Jenkins file to build, push, and deploy a dockerized Python application. So without further ado, let's get started. Multi-branch pipelines. It is a Jenkins job type that scans your SCM and automatically creates a child pipeline for every branch PR or tag. Let's break this definition. Firstly, I want to highlight that multibranch pipelines are not a concept that is just limited to Jenkins. You have these things in GitHub actions and GitLab CI built in. So in here in Jenkins you create a multibranch pipeline job. But when you talk about GitHub actions or GitLab CI you have the liberty of defining these things within the YAML itself. So the concepts that we are going to learn today are not just limited to Jenkins. Now let's dissect this definition. It's a Jenkins job type that we understand that scans your SCM. SCM is source code management and in our scenario the SCM would be GitHub. So what we are saying is it's a Jenkins job type that will scan my SCM and automatically is the keyword creates a child pipeline for every branch PR or tag. Now your repository can have multiple branches. What we are saying here is based on how many branches you have or how many PRs are there in your repository or what are the tags that there are in your repository. It will automatically create a child pipeline. So with this definition what we understand is multibranch pipeline is an umbrella term and that job type may have multiple pipelines within itself. So up until now we were dealing with single pipeline jobs. We had a pipeline job. We defined the branch on which that pipeline job will be applicable and that pipeline job used to do its job. But here what we are saying is we have a multibranch [clears throat] pipeline job that will be applicable for all the branches or PRs or tags in your repository. As simple as that. And all of these things will be done by Jenkins automatically. You do not have to define the branches. You do not have to call out the PRs. You do not have to call out the tags. Now what are branches? What are PRs? What are tags? We have seen this before but a oneliner wouldn't harm. So let's say we have a main branch. In the main branch is our primary code which is always releasable. So now a requirement came in where we have to introduce a loan feature in our banking application. So what our developers will do is they will create a new branch. They will not touch the main because the main is protected. They will create a feature branch and they will start working on this code. Understand that when this feature branch was created, we were on this stage. So whatever the code was there for the application up till this point will be available to this feature loan branch. Now our developers will start working on the loan feature. That is what a branch will do for you. It's a separate line of work. It is your own copy of the code where you make changes. Then what is a PR? PR is let's say developers are now happy with the code. They have performed multiple pushes in the feature branch. They have performed multiple testings and now they are satisfied with the entire code. So what they choose to do is they choose to merge whatever they have done into the main branch. And to perform that merge they will have to raise a PR. Why a PR Vun? Why can't I push directly to the main branch? Often in production, you will see main branches or any of your release branches are protected. You cannot directly push onto those branches. So, what you do is you raise a PR. PR is a pull request. It can be thought of as a merge request. When this PR is raised, a certain checks are performed. And if those checks are successful, the merge successfully happens. And this is what you see here. And what are tags then? Now understand that tags are just releasable versions of your application. For example, if my application is running version 1.1, then 1.1 becomes my tag because the commit that is associated with version 1.1 is a releasable version. Now let me explain that to you in simple terms. For example, let's say your main has 10 merges. So 10 PRs that were approved. Now each of those PR could represent a version of your application. So tag essentially is a version of your application. So all those 10 comets that you see here could represent a tag or a handful of those comets can be thought of as a tag. So again in simple terms tag is just versioning version one this tag version two this tag version three this tag and it tags associate your releases with the commits on which those versions were decided or those tags were decided. What we are saying here is when you are dealing with a multibranch pipeline, multibranch pipeline can trigger a job can trigger a build based on branches, based on PRs and based on tags and as we progress with this lecture we will learn more about these things. So now that we have a highle understanding of multibranch pipelines, let's see these pointers. Reposiatordriven CI mirrors branching model autocreates jobs per branch. So this is what we understood. If you create 10 branches, there will be 10 CIS that will be created for you. There will be 10 CIS that will run for you. And we will see how this works in the demonstration. The second point is Jenkins file first builds only references containing Jenkins file per branch or PR. So understand this point. I could have 10 branches. I may not want multibranch pipelines to be running on a specific branch. How do I do that? What I do is I do not put any Jenkins file there. So what I'm trying to convey to you is for a branch to be selected for the CIA there must be a file named as Jenkins file. So if I have this feature loan branch and I do not supply this Jenkins file in this branch then Jenkins multibranch pipelines will not be acting on that branch. So multibranch pipeline will always be looking for branches or PRs or tags that have Jenkins file available and this is the default name. You have the liberty, you have the option to choose a custom name as well. But as I always say, you should be sticking to the standards so that anyone who looks at your work can simply judge that yes, this is the Jenkins file. Third pointer is fast feedback pushes and PR updates trigger CI. Now imagine as soon as a feature loan branch is created locally and then as soon as it is pushed to the remote, your CI will run automatically because your Jenkins job detected that there is a new branch in the remote and how it detects how it works is a different story altogether. Right now I just want you to concentrate on as soon as there is a new branch available and that new branch has the Jenkins file Jenkins will take action. If you have a multibranch pipeline job next is life cycle automation via web hooks creates and retires job. Now it is up to you how you want to pull your SCM. Now maybe as soon as a new branch is created, a web hook is delivered to Jenkins and based on that web hook, Jenkins will run the pipeline job on your newly created branch. Or Jenkins could be pulling your SCM every 15 minutes, 60 minutes, 1 minute, 1 day and so on based on your requirement. And if it sees there is something new, there is a PR or there is a branch or there is a tag that has the Jenkins file, it will run the CI the pipeline on that branch PR or tag lower blast radius. And again in life cycle automation you have web hooks and you have polls. you can pull the SCM and then there is a third option that is you manually perform that scan. So that is also there. The next point is lower blast radius isolate builds keep main clean and this is the beauty. So what happens is whenever I have a feature loan branch for example here my job will only concentrate on this part of the code main will always be releasable and when I raise a PR for the merge then we'll have new checks so that the merge that happens here is also releasable and the next point is scales with teams it is obvious. So if I have multiple teams, they can create multiple branches and as soon as they create their branch, as soon as they push their branch to the remote, we know a CI will kick in. As long as Jenkins file is available in that branch, then autodiscovers. We already understand it will either pull or it will deliver a web hook. that is autodiscovers and prunes short-lived branches. So retires jobs in this point and prunes short-lived branches in this point. I want to relate these things to you. So understand you have a feature loan branch. You perform your changes and you are sure your changes work fine. Not you are sure that there is automatic builds that happen the pipeline that runs that tells you that it is green your code works you raise a PR and PR gets approved and let's say it is merged once that PR is merged do you really think there is a need for this feature loan branch no right you don't need this branch once the work is done then you can delete this branch because I no longer need this. And understand as soon as this gets deleted, my Jenkins will know that I was working on a branch called feature loan that had Jenkins file, but I don't see that branch anymore. So, let me also retire the job that was created for that specific branch. And that is what this means. Retires jobs. And here prunes short-lived branches feature. Once the CI succeeds will be auto deleted. Now I hope multibranch pipelines are understood and in the demo you will understand them more deeply. But here is one more thing I want to mention. In trunkbased CI/CD MVP is the glue feature buck fix branches stay small like we saw here. As soon as the work is done, you run the CI and the PR gets approved and the branch is removed. If there are failures, then the developers will again be working and then the same process will repeat. But the crux is and we have learned this in day two of our course. When I talk about trunkbased CI/CD, I want things to be super fast. My developers, they push the changes, the CI runs. If the changes are okay, the merge happens and everything is hunky and dory. So the failure or the success happens frequently and fast so that the main is always releasable. So let's read this definition again. In trunkbased CI/CD MBP multibranch pipeline is the glue feature buck fix branches stay small PRs get tested automatically and main stays releasable. Now if you have any doubts I would request you to go back to day two and see what is trunkbased CI/CD. Essentially in one line the source of truth is the single trunk main and then there are multiple feature and bug fix branches that will take over. Understand that in this lecture we discussed so many workflows. So if you have not watched day two, if you are not watching this series in sequence then if you already understand these concepts it is all right. But if you want to brush up, if you want to learn maybe something new, then I would request you to watch this series in sequence. So in day seven, I'm back here. So this is all about multibranch pipeline. Now what I want to show you is a production flow so that whatever we have discussed in theory makes sense. So once we discuss this production workflow after that we will go to the demo so that you first understand how the flow looks like in production and then you implement that flow with me. So the heading for this is trunkbased CI/CD multi- branch flow. So the diagram is numbered. We will see what happens in each step. So just to let you know green color here represents the main branch and main branch is the one that should always be releasable and we are discussing trunkbased CI/CD. So point number one is let's say a requirement came in wherein your TL was asked that you have to change the font of the UI. The UI is no more appealing to the users. we have to use some sort of comic science font or aial font to make it beautiful. Your TL took that input and assigned that task to a developer that improve the UI font. So what will that developer do? That developer will create a new branch and understand since we are introducing a new feature in a way we are improving something in a way we named it feature. If there was a problem that we were fixing we would have called this bug fix and then whatever bug we were fixing. Here we are just making an improvement. We are introducing a new feature so to speak. So we named our branch accordingly. We called it feature forward slash UI font. That's step number one. Now why did the developer not modify this directly? Firstly, it is not permitted because this is a protected branch. And secondly, we all know this is a best practice that you create a new branch and then work on that. This new branch whatever you see here will hold all the code that was available up till this point because it is at this point that this branch was created. Now if there is a new something here a new comet here then this branch will not have any information about it because this branch was created after this comet. Now there are ways to get around that. You can you have features like rebase, merge and so on. We'll see them later but for now understand that this branch will hold all the code up till this point. Then step number two is push branch job. Now let's say our developer worked on the UI feature. Our developer worked on locally and we all know first the developer will work locally and developer is now satisfied. So now what will the developer do? Developer will push this branch onto the remote and this branch will already have a Jenkins file and since this already has a Jenkins file and the developer has pushed it onto the remote and let's say the remote is GitHub Jenkins will detect that runs on each push. Now that could be web hook or it could be a scan and the scan could be a polebased scan or a manual scan. Then what happens is compile we all know what compile is. Compilation is a process of converting the source code to machine code and machine code if the compiler based languages are C, C++ or Go and to byte code. bite code is applicable when you are dealing with Java or C. So essentially compilation is a process of converting the source code into machine or byte code. Again we have discussed these things in detail in day one and day two of these lectures. So do check that out. Now only compiler based languages will have the compilation stage and it is not something that you have to do manually. There are tools, there are automation tools, there are build tools available at your disposal which can perform this compilation for you. Like there is a maven for Java. Then you have unit test. Now what are unit tests? They run small pieces of your code, maybe a function or a class inside the test program. No server or app deployment needed. So understand this point. Unit tests can be performed when the application is not running. However, if I contrast this with integration tests that we'll see later, these tests warrants the application to be in running state. So, unit tests can be performed when the application is not deployed. So, they can be performed on your code. Now, Vun, but how will I perform unit test? Again, I mentioned that there are build tools available at your disposal. These build tools, they have certain plugins or add-ons that will help you perform these unit tests. And like I said before, there is Maven in Java which you can integrate unit test into. And then there are various other tools like Maven will have this JUnit CMake with Google test and there are different tools that can perform these unit tests. For example, JUnit is for Java, Unity is for C, G test for C++, G test is Google test. Then you have pi test for Python. You have to know these things at a very high level at least at this stage if this is the beginning of your CI/CD journey because as you deal with specific projects that deal with specific languages your understanding will deepen because there is no point memorizing these things if you are not using it daily in your CI/CD pipelines because we humans tend to forget things that we don't work in everyday life. So for now just take this as a dump on onto you and once you progress with your learnings these things will be in your fingertips. Then in this stage itself so first we set compilation then unit test then there is linting. What is linting? Linting is a process of statically analyzing your source code for any stylistic or programmatic errors. Maybe there are unused variables, there are suspicious null checks or there is inconsistent formatting. So linting will detect all those things and will tell you. Then the last one that I want to discuss is coverage. Now let's say you have 100 lines of code but the tool that you are using for let's say code scanning only scans 80 lines. So your coverage is just 80%, and I should not use the word just because for most of these checks to pass, the coverage should at least be 80%. So if you if your tool that you are using for your code analysis, only scanned 80 lines of your code, only tested 80 lines of your code, then your coverage is 80%. So code coverage is an important parameter. A lot of pipelines will fail if the code coverage is less than 80%. So keep these things in mind. Then package plus build container image. Understand we are not deploying anything right now. We are just performing packaging plus building container images. No deploy is happening. Now I have written this based on what I have seen in general but each pipeline is different. Each project is different. So do not limit your imagination. Maybe you are performing some more tests in this stage. What I am showing you is a blueprint that you will often see in production. Then you have publish artifact metadata sbomb. Let's dissect these terms. What is artifact? We know anything that results from a pipeline build is an artifact. So if you are receiving a file, that file is an artifact. If you are receiving a container image, that container image is an artifact. If you are receiving a jar file after building a Java application, then dot jar is your artifact. So in this point, we are saying we will publish the artifact. Now what is publishing the artifact? A artifact like container image can be published into your image registry. An artifact like jar can be stored in your artifactory. Or if there is a file that resulted from the build, maybe I have a file that lists down the commit ID, the hash and all these things, then that file maybe needs to be stored in a central location and that central location could be your S3 bucket or your EFS file storage or it can also be GitHub. So here we are just saying you will publish the artifact and metadata. So what is SBOM? SBOM is software bill of materials. So your application could be using multiple things. For example, if I'm developing a banking application, I might require a calculator. Now I do not want my developers to start writing the code for a calculator because there are plenty of well-known libraries for calculating stuff for calculator. I my developers would instead use that library. Now why use a library? Because libraries they ease your job. They reduce development cost, improves reliability especially if you are using a well-known library and it saves time. So your developers if they are working on the core banking application they could be leveraging plenty of libraries and their application can have multiple dependencies. So everything related to your application your application constitutes of multiple chunks. all these chunks sbomb will list everything. So the textbook definition of sbomb is it is essentially a formal detailed inventory of all the components libraries and dependencies used to build a piece of software. So it can be thought of as an inventory. So this is what happens in this stage and this stage as you see here typically should be finished within 5 minutes. Now why the time constraints are important? Understand that while this feature is built, we want everything to be fast here. When you are dealing with trunkbased CI/CD, you do not want jobs to run for 30 minutes, 20 minutes. You want the entire pipeline to be completed within the minimum possible time because there will be other features on which developers are working. Now if you are working here then you do not want multiple pipelines to be running in parallel. You want these things to be sequential. At least you should be trying that things do not run in parallel because if things run in parallel then there could be merge conflicts and so on. We will see a few scenarios where we'll talk about this. But for now, aim to trim your pipelines to run at the minimum time possible. It should consume the minimum time possible. The third step is let's say the branch job succeeded. Now why we are calling this a branch job? Because your developer worked on a branch and pushed it. Okay, so we are calling that a branch job. Next we have a PR job. Now why a PR job? If the branch job succeeded then what your developer will do is your developer will open a PR and as soon as a PR is opened a PR job gets triggered but Warun why a PR job will get triggered understand what we learned here Jenkins multibranch pipelines will scan your branch PR and tag so here it ran a job when a branch was pushed Here it will run the pipeline when a PR is created. Now the tasks that are performed in this and in here are different. Understand? So here we are performing some more testing. What we are saying is triggers on PR open or update. If a PR is open or PR is updated, it will trigger a PR job. runs light SAS and SAS is static application security testing plus dependency scans. Now dependency scans on codes and manifest. So example if you are dealing with Maven you will have pom.xml. If you're dealing with Python you will have requirements.ext. What it will do is all these files they have the dependencies of the application or the packages that are required. That's why it is called a dependency scan. So what dependency scan will tell you? It will give you a graph that this is your application. This is the dependencies and these dependencies have these vulnerabilities. Now how the vulnerabilities? vulnerabilities because there are tools that can compare the dependencies that your application uses with a vulnerability database so that it can tell you that this is how vulnerable or how not vulnerable your application is. Now you do not have to do this manually. Okay, there are tools that can be leveraged for this tools like sneak trivi. You can integrate these tools with your pipelines. If you learn about dev sec ops in future then you will understand more about these tools because these tools are specific to security vulnerability management and so on. But as DevOps engineer I'm not saying that you should not know about these things. Maybe you should not know about these things as deep as a dev sec ops engineer. But at a very high level, you should understand what these tools are. But if you are a senior DevOps admin, you will be expected to implement these tools as well. Maybe you do not know those things as deep as your security engineers, your devs sec ops engineers, but you are still expected to configure these tools. The next one is deploy ephemeral preview. I am not saying deploy onto staging, development or production. I'm saying deploy onto ephemeral. Now why is this deployment necessary? So whatever testing we have performed thus far, be it your compilation unit test, lints, coverage and here SAS dependency scans, we have performed these things in a static code. But there are certain things that cannot be done until and unless the application is in running state. Which is why to perform certain tests, we want the application to be running. And here in the PR job, we are deploying that application onto an ephemeral hardware. Now that ephemeral hardware or that ephemeral part could be a different name space in Kubernetes or if you're dealing with traditional it could be an ephemeral virtual machine where this code is deployed. Why we are saying it ephemeral? We are saying it ephemeral because this will be tiered down if the PR job completes successfully. If it doesn't complete successfully, then you may choose to not tear it down and troubleshoot the problem and then make changes in your code so that it gets deployed onto the ephemeral environment successfully. But for now, understand that ephemeral environment is supposed to be tiered down once the application is deployed successfully or if it is not deployed successfully, it is your decision on how you want to deal with it. Then what happens once the code is deployed onto an ephemeral environment? You perform integration and smoke tests. What are these tests? These tests will tell you whether the basic functionality of the application works fine or not. If you are in a banking application, whether users are able to check their account statement. So this becomes a smoke test or quickly tell you whether the application is accessible or not. So these minimal tests which can be performed quickly are integration or smoke test. So these are performed once these are successful then the code is merged with the main and we'll look into that. So this ephemeral environment is tiered down upon PR closure or PR completion. Now that the PR job has completed successfully, we can successfully merge this with main. Now there are certain things that also happen before this merge is performed. So there are these tests which I already told you. All required checks green that must be there and let's say all of these completed successfully including deploy succeeded in the ephemeral environment. Let's say that was also successful. Next is enforce required checks. These are the required checks plus up todate with base. Now what is up to date with base? That's what I just told you. Imagine this branch feature UI font was created at this stage. Correct? Now what if there was a new commit here? This was a new commit here. In that scenario, this branch will not have the changes that were part of this commit. And this commit was resulted let's say from a new feature on which a different developer team was working. So we are at loss because we are not working with the latest code here. In that scenario the PR it will not be merged with main because we do not have the latest code with us. Now in this scenario you could rebase or merge with this new one and then rerun your pipeline. That is why I said your pipelines should be running extremely fast because if you are running your pipeline and your pipeline is taking 10 minutes to run but there is a different PR raised which just takes 3 minutes to run then your pipeline is already stale because your pipeline your branch does not have the latest code that is here. You are still working with the old code. Hence enforce required checks plus up to date with base is important. If read fix push rerun PR job and that part we already understand. Now once this gets merged understand that merge will result in a new comet in the main pipeline in the main branch. And if there is a change, Jenkins will rerun the pipeline in the main branch. If something is not connecting right now, do not worry. In demo, all of these things will make sense. So in the fifth point, we are saying merge to main main pipeline runs on merge reuse signed artifact image. So like I discussed in the previous lectures that you only build once and then you promote the same artifact. So the container image essentially is only build once and then it is pushed to ephemeral to stage to production and so on and then deploy to dev stage verify promote with approvals. Now I told you that there is a single line that is releasable. This is the main branch. So you could be first deploying onto the dev environment from this main. understand the difference between these branching strategies. Okay. So if you were dealing with gitflow based branching then you would have dev branch, prod branch, prepro branch and so on. But we are talking about trunkbased CI/CD. In trunk based CI/CD it is only the main branch that holds the code and then this main branch deploys to all the different environments. your dev environment, your stage environment or your prod environment. Then the sixth step is get host autodeletes source branch if enabled. So once this merge is performed successfully like we discussed before this will be deleted. Jenkins will also prune the job because it does not see that branch anymore. I hope this makes sense to you. Now we will do a demo that will connect any dots that remain to be connected. So let's scroll down and this is what we are going to do. So let me quickly explain this to you what we are going to do. Jenkins multibranch pipeline flask docker demo. So what we'll be using is we'll be using a private GitHub repository. Multibranch pipeline will be created in Jenkins and then we'll be performing manual scans for now. Don't worry as we progress we'll configure web hooks and all those fancy things. It is just one click and you can configure those. No biggie. Right now we'll be performing manual scans. So our step zero would be to create an MVP job multibranch pipeline job. We'll define the job and then we'll set up the credentials because we know we are connected to a private GitHub repository. Our Jenkins must have those credentials. So we already have those credentials saved from our past lectures. We'll be using the same. Then we'll be scanning our private repository and our private repository must have our Jenkins file for the scan to be successful because Jenkins file must be there. Then we'll run main baseline build. Understand? I told you the pipeline will detect the main branch quickly and it will run the job. And the same will happen when we move to the next step of the process. There will be a new pipeline job created automatically for us when we create new branches. So in step number one, then we'll be creating a branch. In step number two, we'll be dealing with a branch job. Here we will be building an image pushing it to the registry. We'll be deploying a container on port 5000. We'll also have a file generated deploy info which will contain the details about that build. We'll be archiving that file. If you have been with me since day one, you understand that the workspace that gets created is temporary. You have the option to clean up that workspace. But if you archive something that gets stored in the jobs directory in Jenkins home and that place is there to store your artifacts as well along with your job. So here in this step we'll be archiving deploy info. In step number three, we will be raising a PR in GitHub. So I should also tell what was happening in step one. In step one, we create a branch and then we create a branch called feature UI and then we edit the code. We make some changes. We add a line in the UI like actual development will work and then we will push that branch. And as soon as you push that branch, step number two will kick in. And we have already discussed what happens in step two. And once step two is successful, we will move to step three. And step three is we will raise a PR in GitHub. And as soon as Jenkins detects there is a PR, Jenkins will run a PR job as well. In step number four, we will see that we'll merge the PR because the checks are green. We'll merge that. And in the fifth point, the main deploy will happen because here the PR is approved in this step. Once the PR is approved, the main will have a new commit. The main will have the new commit. Then Jenkins will detect it. Jenkins will detect it and runs this CI again. So it will detect the merge, build, push, deploy, archive, test on main and we will verify. This can be thought of as a smoke test. We'll verify that our application is accessible or not. And here in the sixth step we'll be doing a cleanup in GitHub we'll autodelete the feature branch and in MVP in the Jenkins side the prune retired branch jobs or workspaces. So whatever was created temporary for example for the new feature branch will be pruned because the feature branch will no longer exist in GitHub. So we'll be doing all of these things in this demo. So let's get started and before I do that I'll take you to the GitHub repository for this course. Now I have already created this cloud with VJOS private repository and we created that I think in day five where we did the first demo. I'll let you do that. If you do not have this repository just create a private repository and upload these files. What are these files? You can find in the repository for this lecture. So this lectures repository is day seven. In day seven you have a Python directory. Just upload everything that you see here in the private repository that you create. Now what happens in this? I want to quickly show that to you. There is a docker file here and that docker file is simply using the python 3.11 slim base image. The working directory is forward/ app requirements. We are just installing one package that is flask because our Python application uses the flask framework. We are running pip install flask and then we are copying our code to the working directory which is / app. We are exposing our application on port 5,000. Remember it is port 5,000 on which our application listens. And as we all know this expose is just for documentation purpose. it will not open port 5,000 in your application. You'll have to do that. And we have done that and I'll show that to you. Then we are finally running the application. So this is our docker file. Then we have our app. py. This is our code. Our code is just saying welcome to cloud with varos. Tip is built with flask shipped by Jenkins running in docker. And here we are saying our application listens on port 5,000. As simple as that. And this is the main piece. This is our Jenkins file which we have constructed. It has various stages. It has a push stage where we are pushing the built container image. Then we are in this stage deploying this container image. If I come down then in this step itself we are creating a deploy info file which will have the build number, the image, we'll have the repo name and the tag. We'll have the commit ID, get commit ID. We'll have the branch and so on. Then we are finally deploying this image onto our Docker host. And Docker host in my scenario is my Mac machine. And then lastly, we are performing a cleanup. There are also certain post actions that we are performing. On success, we are echoing this. On failure, we are echoing this. And no matter if it is success or failure, we are echoing the job is finished. It's a simple Jenkins file. And if you do not right now know how to create Jenkins file, I would urge you to watch this series in sequence because we learned this in day five, day six and so on. So now that we have this understanding, let's go to the Jenkins screen. I'm in the homepage localhost 8080. In here I will just click on new item. And what I want to name this is MVP flask. And let me zoom in a little. Here I will choose multibranch pipeline. Creates a set of pipeline projects according to detected branches in one SCM repository. In one SCM repository I'll click here. I will click on okay. And display name I will leave blank. Description I will leave blank. And here is the important piece. I see branch sources. Now what is the source of your branch? I could choose git. I could choose single repository and branch or I could choose GitHub. Now why do I see GitHub? You see GitHub under branch sources? Because GitHub branch source plug-in is installed. If you are using any other source control then you should check the branch source plug-in for your git host. So I will click on GitHub and this will give me all the options related to GitHub. So what I will do is first I will paste the URL. I'll go to my private repository because hello URL is important and that's how Jenkins will be scanning my repository. So I will copy this name. I will come here. I will paste this here. And if I click on validate, this won't be successful because this is a private repository. I must provide credentials, right? So, we already added credentials for our GitHub. If you do not have the credentials right now, go to GitHub, create a personal access token, and then add those credentials. If you do not know how to do it, I recommend you watch the previous lecture. So, I'll click here. and then I'll click on validate and this should succeed. Credentials. Okay, this is what you want to see. Now I will scroll down behavior. Now this one is important. Discover branches. What is your strategy? First one is exclude branches that are also filed as PRs. Now this is the recommended option. And what this says is build the branch until PR exists then build the PR job to avoid the duplicate. So let's understand it diagrammatically what we are saying. I'll go to draw.io. Okay. And what we are saying here is so you have create you have pushed a branch. If there are pushes in the branch you keep building those pushes. Okay. And that's understandable. Now once my push is succeeded once my branch job let's say is succeeded I would want to raise a PR right and once there is an opened PR you stop running the branch job and that is what we want what we want is if there is a branch job let's say you pushed a branch and that branch also had the Jenkins file so your Jenkins will detect it and it will run the branch branch job. That is what you want. Let's say your branch job failed. You pushed again and this time your branch job failed again. So you pushed the changes third time and this time your branch job succeeded. Okay. Once your branch job succeeded, you raised a PR and as soon as you raise a PR, your PR job starts. You do not want when a PR job is raised if someone else pushes to this there should be a branch job run. You don't want that. If a PR exists, you do not run a branch job for me. As simple as that. And that is what we want. And understand when this PR job is closed, the PR that you raised is closed, you can again push and run the brand jobs. But understand if this PR job is successful most of the times you would want the branch to get autodeleted in that case it does not matter right. So what you want is you want this setting exclude branches that are also filed for PR. So in this option what will happen is build the branch until a PR exists. As simple as that. Then build the PR job to avoid duplicates. Second one says only branch that are also filed as PRs. Now this is saying build branches only when they have a open PR. Now be careful with this because it will not build in generic pushes. So if you are pushing to your branch it will not build. It will only build when the PR is raised. So essentially this part will not be there at all. only this part will be there because it is only running when there is a PR job that exists. The last one is all branches build every branch simple but can double the builds when PRs exist and that's understandable. So I hope this makes sense and also I have explained these pointers in the GitHub repository as well. So go to that GitHub repository and revise these concepts. Next one is discover pull requests from origin. Now let's see what are our options here. So here we will choose the recommended one and then discover pull requests from origin. The selected one is the current pull request revision. Now this says only build my code. So for example, whatever code was here, just build that code. So build the PR tip essentially. The next option is merging the pull request with the current target branch revision. Now this says your code plus the current main. But Wun, why is this important? Understand? If I just build this, the PR may fail because there could have been a new commit here. If I build this and then I try to merge this, the merge will fail because it is not up to date with the main because there has been a new commit since this branch was created. What I want you to do, Jenkins, is I want you to test my code plus I want you to see what will happen when this merges with this the current one the current main. So you check with this option merging the pull request with the current target branch revision. So you test my code with the current main revision so that I know if I try to merge with this one how will my code behave. So essentially this is telling you beforehand what will happen if you try to merge this with the main right now. It will give you the proper perspective because it will take your PR tip and the head tip. Last one is if you have enough compute resources, I would suggest to always use this both the current pull request revision and the pull request merged with the current target branch revision. So what this will do is this will verify both the views. First it will run on your code only this one. then it will run on your code plus the current main tip which is this one. Now why this is important? Again I'm saying if this commit was not there then you might not need any of these things. But what if someone performed a new commit and your branch is no longer the latest. In that scenario you would want to test what will happen if I try to merge it right now. And if you try with this one, my results would be successful. And if you know these will be successful, then you perform your rebase and merge and whatever you want. But this will tell you beforehand what will happen if you try to merge with the current main tip with the latest main right now. And this is the latest main. So this will only come once the merge is successful. So this is essentially your merge commit once the PR is successful. So I'll remove this. I hope all of these makes sense to you. I will choose this one. And if you go to GitHub here, I have explain all of these things both current and main. What will happen? Two builds per PR update. Head and merge. Here you will see a synthetic merge. And this merge whatever happens is a synthetic merge. It's a temporary merge because understand a merge will have to be performed to see what will happen if this merges with this one. What will happen now for this to happen? It won't actually merge your code. It will perform a synthetic merge, a temporary merge to see what will happen and it will tell you the results for that. So I hope this makes sense. Now let's go back to our Jenkins job. I will choose this here and discover pull request from forks. You will not be dealing with forks when you talk about enterprise private repository. So I will not discuss that but I will encourage you to read about this as well in the GitHub notes. So I'll keep this at default. I'll also keep this at default. Here I will property strategy all branches get the same properties. I'll keep this as is here. Build configuration by Jenkins file. So this is important. Jenkins file path. You can choose a new file as well. Uh a custom file name as well. But I will leave it to Jenkins file and it is present directly in the root of my repository. So that it is not inside any path. I'll come down. Discard old builds. I will let it be selected. Scan multiple pipeline triggers. If you were pulling your SCM, you could use this and at which interval you want to pull that you have different options you can choose from here. So I will deselect this because we will be running the pipeline manually. Appearance this is fine this is fine. Shared libraries we have not discussed sharable libraries right now. Pipeline libraries we'll see that later but for now let's save this. And I want you to concentrate and see what happens. I'll click on save. And it has automatically started scanning my repository. This is so cool folks. Now see checking branch main. Jenkins file found met criteria scheduled build for branch main. It automatically did this. And if you see here, let me show that to you later. One branches were processed. Checking pull request. Zero pull requests. It has started detecting. Finished examining this. Finished branch indexing. It took 3.7 seconds. Finished. Success. Now let's go here and no let's go to this page. Here is MVP flask. This is what we created. This is at the very top. This is has a new icon as well for the multibranch pipeline. If I click here, it has sub jobs. And if you see here, if I if I you see this one, this one has some new options. Scan repository now, scan repository log, multibranch pipeline events. But this is the pipeline job that it has created for the main branch. Why I know that? Because this is under the branch section and here is a pull request section. So if I go to branches section, you see how this looks like. This looks like exactly like the pipeline job we created in the previous lecture. So that's what I said. Mbp is an umbrella term. Then you can have multiple jobs inside it based on your branches and pull request. Now since we only have main right now, you only see main and we don't have any PRs created which is why you see zero here. I'll click on main and you see here is the deploy artifact that we generated and then here are the different stages of our pipeline and if you see it has taken action on main and ran the complete pipeline the deploy is also successful. So if I access local host on port 5000 then I will see my application is accessible. Welcome to cloud with varos built with flask shipped by Jenkins and running in docker and if I go to hub.docker.com and let me sign in quickly and till this happens I want to take you to the CLI and here let me run docker ps you see a container was created a minute ago and that is when we ran our pipeline. So if I go to my browser again and here you see cloud with VJO flask it was pushed 2 minutes ago and if I go here the tag that is being assigned if I go here there is there was a latest tag there is tag number one and one is the build ID which is why you see this here. I hope the dots are getting connected and this will only connect if you have been through the past lectures and you understand what our Jenkins file is doing. Now let's go back to Jenkins screen and we have seen this. Now let's do this flow. Now let's go to the diagrams and I'll show you what we want to do now. Now we want to create this branch. Okay. So let's go to our CLI first. I want you to know that I am in Jenkins basics to production directory. Firstly, let's go to day 7. Okay, I'll go to day 7 and I'll clear my screen. And here what I want to do is I want to clone my private repository. Understand that I won't be able to push to a private repository until I provide credentials. So in the first step we will clone the repository and I can only clone a private repository if I provide the credential. So let me do that. I will paste this here. Now do not worry. I will be deleting this personal access token later. For now I'm just showing this to you so that you can also follow along. Get clone origin. Now most of you would have seen that origin is named remote but I don't like that I want things to be detectable. If I see this name I should be able to identify to which private repository this name point to which is why I have named my origin flask private. I have not kept it to the default which is remote. Now if you go to the GitHub repository of this lecture, if I go here and if I go to the top and then from here I go to first one and if I scroll down then you would see that all the instructions that I am following you can find all these instructions here. Okay. So just follow along all of these steps with me so that it solidifies your understanding. So I'll go to the terminal. I'll press enter. Now as soon as I do it, I think my token has expired. So hold on. Let me do one thing. I'll press Ctrl C. So more learning for you. So I will go to my GitHub repository and then let me do one thing. I will scroll up. I will go here and then I will go to settings. I'll open this in new tab and then I will go to developer settings. Here I will go to personal access tokens tokens classic and here I will click on create new token. Uh I'll choose the classic one and here I will use my pass key. I'll touch my finger and then I'll call this Jenkins delete me because I'll delete it after this lecture valerity 7 days repo and then I will click on generate token and then I will copy this token and then I will paste this onto the command where I will be running this. I will paste this and then let's close this. I will now paste that command along with the new token here. And this is cloning and the cloning is successful. If I press ls now, I will see cloud with var private repo. So let's go inside this and I'll again clear my screen. Now I will run get remote. This will show me that flask private is your remote. So whatever push I will perform will be performed into this repository. So if I run get remote v, you run it with caution because this will show you your personal access token as well. So it will show me where exactly we are pushing. So if I run get branch L, this will show me that I am currently working on the main branch. understand that as a developer I won't be working on the main and I will not be able to push directly on the main because main is often protected. My main right now is not protected because anyone can push onto it but as we progress with this lecture I will show you how to protect it. Now let's do one thing. I will create a new branch. I will write get branch feature UI and then if I run get branch-l we'll see that feature UI is created but we are currently working on the main branch because asterisk is against the main branch. So what I want to do is I want to switch to a branch called teacher UI. Now a lot of folks also use checkout but I prefer to use switch and if you have any confusions a small homework for you check out the difference between git switch and get checkout and tell that to me in the comment section. So we have checked out feature branch. So if I run git branch l you will see the feature UI is now green and it also has an asterisk. And if I run ls, you see all our files are here. Now we want to make changes into this file like actual developers will do. vim app. py. I'll press enter. I will go in the insert mode. I will exit the insert mode. Then I'll press the dollar sign to move. At the last of this line, I will go into insert mode. I will add a comma here and then I will come here. I will write UI here is equal to this is my new UI. How do you like it? So this is what I have added. Now your developers will be actually modifying the code and doing some fancy cool things. So do not let that thing that the flow will be any different. the flow will just be the same. We are modifying the code of our small little Python flask application in actual production as well. The flow would be same. I will hit escape and then I will press shift ZZ to save this. Now that this is saved, I will hit get status. This will tell me that dear friend, you have modified app. py do you want to commit these changes? And yes, I want to commit these changes. First, I will use get add app. py. I'll press enter. Then I will run get commit- m and then I will write the commit message. Now this commit message should always be useful. So I will write updated UI to have a new line. And once I have done this, I will close this. I will press enter. Now if I run get status, you won't see that file here anymore. And if I cat on our code, you will see that we have the new line. Understand that the modified code is right now in your feature branch. It is not in your main branch. So if I get switch main and I cat app. py then you will see the old code. Understand? And we are not disturbing the main we are working on the feature branch which is why only the feature branch will have our code. So once our feature branch has the modified code we have committed that already. Now what we can do is we can push this onto our remote and we already know if I hit get remote you see that flask private is already there. Now what I will do is I will write get push. Our credentials are already added. We added that in the cloning step. I will write get push flask private. This is our origin. I will name it appropriately flask private. And where do I want to push it? Which branch? And the branch is the same. I'll have feature UI. So whatever changes that we did were only there in our local system. Those changes are not there in our remote. Our remote only has main right now. But now we want our main to also have feature UI branch. So I'll press enter. And this will start doing the push. The push has happened. So if I run get branch here, it will show you that there are two branches which is fine. But if I now hit get branches a I think it will show me all the branches it is also showing these are available locally and if I talk about remote has feature UI and main and feature UI is there because we just pushed it. If you would have run this command before pushing then you would see only main listed here. But now that there are two branches, it is showing both feature UI and main. And you see here feature UI had recent pushes 2 seconds ago. Compare and pull. We won't be doing anything right now. I will hit refresh. And if I check here, you see feature UI is here. And if I go to the code of feature UI, it will have the new code UI. This is my new UI. How do you like it? And that is what we wanted. But if I go to our main branch, like I showed you before, our main branch will still have the old code which does not have that UI line in it. Okay. Now there is a main branch for which Jenkins has already performed the build. So if I go to this you see main it has already built and we also tried to access and it worked fine. What I want you to understand is based on the diagram, what we saw before was as soon as our private repository was scanned, a job for this main was triggered. And if I go to my browser again, you see the branch name main exists here. So what we just did was we pushed our feature branch into our repository. That is why you see a main here and also the feature UI. Understand that this branch job that you see here, this should now trigger. Why this should trigger? This should trigger because we have a new branch and that branch is called feature UI. The CI should start for this branch. Now since we are not using web hooks what I will do is I'll come here and I will click on scan repository. Now when it scans it will see that there is a new branch and that new branch has the Jenkins file. So what I should now do is I should also build that branch. And what I want you to observe is you are not telling Jenkins anything. MVP is taking action automatically based on what it sees in your repository. We are scanning it manually right now. But imagine if you were using web hooks here which we will later in this course. You will not have to do anything. All these tasks will be automated for you. So if I hit refresh now, you see there is a feature UI here. Understand what we learned. The jobs can be triggered. These pipelines can be triggered based on PRs, branches or tags. So branches we have already seen for main and for feature. This pipeline got triggered automatically. Essentially child jobs were created for main and for feature. And in the next step we will raise a PR PR for what Warun we'll be raising a PR for feature to get merged into main. And we will see that once we do that the pipeline also gets triggered and this time this child pipeline will not be part of this branches it will be part of pull requests because we will be raising a pull request for that. So now this has completed. Understand that right now we are using the same Jenkins file for everything. But when you are in production like we learned in this diagram, you will have certain tests in the branch job. You will have some different tests in the PR job and so on. As we progress we with this course we will see those things. But for now I wanted you to understand the multibranch pipeline concept which is why I have kept the pipeline simple. In upcoming lectures of this course we will modify our Jenkins file to do different tasks at different stages. So for a branch job there will be different tasks. For PR there will be different tasks and so on. For now we are doing the same tasks. So I will go back here and this time I'll go back to the browser and you see this job has completed. So now if I go to this tab you see what is being displayed right now is the code that was in main and main did not [laughter] have the UI line. So what I will now do is I will hit refresh. understand that whatever we have been deploying all of these are being deployed in my docker host and my Jenkins file at the very last has a line which first deletes the existing container and then recreates the container and this time when it recreated the container it used the code that was there in the feature UI branch and the feature UI branch had the code that had the UI line. So if I go to this feature branch UI and I go to app py this has the code which has UI. This is my new UI. How do you like it? Which is why you see it here. Understand that our main branch still has the old code. So if I go to my main branch, the code there is still this. It does not have that UI line. But I want you to understand as we progress as we progress with this lecture. We will reach this stage where we will be merging to the main and when we reach that stage you will see that your main also has the modified code. So we'll see that as we progress. So for now you saw that a branch job was automatically created for feature UI. So let's go back to the diagram and see what we want to do next. So step two is done. Step three is create a PR. So let's open a PR. So I will go to my browser. I will go to this repository cloud with VJOS private repo. And here I see compare and pull request. So let's raise a pull request. You can either click here or you can go to the pull request section and click on new pull request. I will use this one. I will click here. Add a title update UI to have a new line. I want you to know that have good titles which can be easily identified because when you go to the Jenkins UI under the pull request, the job that will be created will have the same name as the title of the pull request. So keep that name helpful. Updated UI to have a new line. I'll just add cloud with VJO so that it can be identified easily. You can have detailed descriptions when working in production. You must have detailed descriptions so that your peers, your collaborators can understand what this engineer was trying to do. I will just write description here so that we have something here. Otherwise, you can even have markdown language. So, you can have bold, italics and so on. So I will click on create pull request. Understand that right now a pull request has been created. We have not merged it. But what we learned when a PR will be seen in the repository the Jenkins will trigger. So it we have not configured web hooks. So what I will now do is I'll click on scan repository now. And as soon as I click here, we should see that it should identify that there is a pull request created in the private repository and I should take action. And I see something is happening here. So let's hit refresh. Understand this is extremely critical. You see there are two things here. But Wun, we just created a single PR. Why do I see both? Read carefully. This is the title we gave. And in parentheses, this one has head and this one has merge. And I want to take you back to how we configured what did we say in the PR section. Discover pull request from origin. We said we want you Jenkins to build both the things. I want you to build my feature branch and then I also want you to perform a temporary merge wherein you tell me what will happen if I merge this PR with the main right now and that is exactly what it is doing. It has created a synthetic merge. It will not actually merge your code. It's just a synthetic merge, a test merge, a temporary merge so to speak. So it will just give you what will happen when in future you will be merging that. And I chose this option because this will tell me beforehand before even I try to click on merge pull request. It will tell me beforehand that Warun your merge could have problems or it could be successful. Both options are there. So that is why you see you raised a single PR and there were two jobs that were created for you. So let's go back here. Let's go to PR. But why has this head job failed? Head job is the one that is being run for on our code. That is the feature branch. The PR that we just erased from the feature branch. And then this is for the synthetic merge. So the PR had failed. Now there is a reason for this failure and I along with you want to dissect this so that you understand. I deliberately chose this option to show you how two jobs will come here. So we have learned that point. Now I want to tell you why there is an error. So let's click here and if I go to stages I can see that deploy stage had a problem. So if I click here and if I click here it is saying docker error response from Damon conflict the container name this already in use this this this you have to remove or rename that container to be able to reuse that name but Vun why have we not received this error thus far and the answer to that question is let me take you back to my private repository so that I can show that to you because That's extremely critical for you to understand. See my code. If I go to day seven, I have this Jenkins file here as well. If I I don't have it here. Let's go to day six. Day six has the Jenkins file. I'll upload the Jenkins file in day seven as well. So if you see my Jenkins file in the deploy stage, what I am also doing is I am removing this container. I'm saying if there is a container with this name, you remove that. But why did we face an error? We faced an error because both of these jobs ran simultaneously. They tried to deploy a container simultaneously and only one succeeded. The one that finished a fractions of seconds before and the second job did not have time to run this command. It happened so fast which is why you only see one container being deployed. And if I go to my CLI and I run docker ps, you see there is only one container that was created 3 minutes ago. The deployment for this container failed. And for you the job could fail for head or the job could fail for the synthetic merge. It does not matter. But now you understand why one of these jobs failed. I also want you to clearly know that we are deploying onto the same docker host in actual production. Maybe the branch job will have different steps and it will be deploying to somewhere else. Maybe the PR job will be deploying to a different nameace in Kubernetes or they are deploying onto the same nameace with just different names for the pods. understand that these things are project specific. In this lecture, I want to concentrate on MBP, multi-branch pipeline, how the deployment part is done, what different steps each could have. We will see as we progress with this course. So now that we have the understanding why this failed, the PR the second job failed. Let's go to the GitHub UI and see what messages do we have here. So I'll hit refresh here and then it says one failing three successful check and we know which one is failing. The PR head is failing. So which is what we see here. The PR job the head that has failed. And if I come here so it is saying the branch job succeeded. The PR merge job also succeeded. This get guardian security checks. I did not configure that. This is automatically available by GitHub. What this will do is it will scan your repository to see if there are any secrets that you have committed by mistake. And you all must know that it is a best practice to never ever commit your sensitive information in your GitHub repository even if it is private. So now we see an option to merge this pull request. We could merge it. What I want to do is I want to do this cleanly. So let's do one thing. I will go here. I'll go to configure. Now that we have learned what happens when both of these are selected, let's just change this to the current pull request derivation. I will save this. Okay. And then I will go to my GitHub repository. And this time I will hit get branch. Let's see. We are in the feature UI branch. I will hit vim app. py. And this time I will add one more line here. I will go at the very last. I could have used the dollar sign as well. And let's write here we modified it again. Okay, I'll save this one. I will write get add app. py. Then I will write g committ-en m added one more line to the UI and then I will close the double quotes. So I'll press enter. I will write get push flask and I want to push this to the feature UI branch. I'll press enter and this has done the push. Now if I go back to the CLI, I see if I hit refresh, I see there is a pull request. Understand what we learned. When there is an open PR, the branch job will not run. Which is why I don't see a new job here. I just pushed it to the feature branch, but I don't see a branch job. But what I see is a PR job. Why a PR job? Because we chose that option. understand everything is connected. So if I open this to the new tab, I go here, I go to configure and if you see this, we said that exclude branches that are also filed as PRs. So we have a PR open. We did not close the PR, which is why you see a pull request RAM. So if I refresh this now, you see this is my new UI. How do you like it? we modified it again. So if I go here again, I want to do one more thing. Now we said that there is also an option via which we can delete the feature branches once the merge is successful. So if I click on merge pull request right now this will not delete my feature branch automatically because I have not configured that. So let's also configure that. So I will go to settings here and in the settings I will scroll down and here you see these things are for pull requests. So what I will choose here is automatically delete head branches. After pull requests are merged you can have head branches deleted automatically. So in our scenario as soon as we click on merge the pull request our feature branch will be deleted automatically. I want to show you one more thing. So while we are at it, let's also protect our branch. Now I am using a freeware version of GitHub. I don't have an enterprise version which is why I can just enable that feature but I cannot enforce it. So if you have the pro version, of course you can enforce it and I'll show you how to configure it. But then it will not be applicable for me because I'm running a freeware version. So I'll click on add classic branch protection rule here. I want that protection rule to be applicable for main and I want require a pull request before merging. When enabled all commits must be made to a nonprotected branch. In our scenario the nonprotected branches feature UI or any feature or buck fix branch that is created. Our protected branch is only one which is we have specified here. You can specify multiple branches. You can have different patterns. Maybe you are calling your main release or production. It depends on your naming strategy. For us, it is main. I will uncheck required approvals. And then as you can read non-protected branches and submitted via a pull request before they can be merged into a branch that matches this rule and for us it is main. I will scroll down and I will encourage you to read all of these options and then you can read it here. Your protected branch rules for your branch won't be enforced on this private repository until you move to GitHub team or enterprise organization account. So I want you to keep this in mind. So let's go to the pull requests and in this screen I will merge it. I'll go here and now I will scroll down. I will click on merge pull request. Uh you have to have a proper commit message here. I will click on confirm merge and I have done the merge. Pull request successfully merged and closed. And let's notice two things. First is we want the feature to be deleted. We enabled that thing. So it should be deleted automatically. And second I want to see a branch job here because understand the main just had a new commit. So if I go to my draw.io, we have merged to main. So we are here. There is a new commit in the main branch. Jenkins should automatically scan that and do the deployment of the new container for us. And we know that container will also display the same message. So let's go here. I will hit refresh. I'll have to scan a repository now. and it will detect that main just had a new change, a new commit. Last success was 20 minutes ago. Let's hit refresh. Oh, it's something is already running. Uh if I go here and you see main has started again. It is in progress. So if I go here, a build two has started. And if I go to hub.docker.com, docker.com we will see the resultant image here itself. So if I hit refresh the code has not yet deployed because the pipeline is still running but I want to show you the other thing that we did. So I will scroll up I will go to my repository one branch our feature UI branch folks is automatically deleted. So if I go here, I don't see anything. But I want to show you an interesting thing. Now if I go to app. py, this has our new code. Now understand the main did not have the new code until and unless a successful merge was performed. Now that our merge was successful, you see there is the modified code here UI. This is my new UI. How do you like it? We modified it again. So I hope all these dots are getting connected. And this will have the same message even if this deployment succeeds. And it has succeeded. Our Docker hub should have an image with the build number because that is what we specified in our Jenkins file. We said our images should have this tag. So image and tag. This tag is the build number. So if I go here, if I sign in, I don't know why I get signed out again and again. I think I clicked on keep me signed in. Anyway, so if I go here, if I go to tags, you see there is a latest tag because hello, that is what we specified. We were pushing two tags. One is the latest tag and there is another tag and this tag had the build number. Since the build number for this one is two, which is why you see the pushed image has two as a tag. I hope all the dots are getting connected. So what we saw is if I go back to our diagram in step zero we created an MVP then we saw the main was automatically considered for the pipeline the job ran for the main branch then we created a new branch we pushed that new branch to our GitHub repository and then what we saw is a branch job was triggered then once we raised a PR a PR job was triggered and Then once we performed the merge, our code was merged with the main and then finally a cleanup was performed. Our feature branch was deleted from GitHub. In MVP also the retired jobs were pruned. And if I go back here in the Jenkins, if I go to this one, you see last success was 3 minutes 36 seconds back. And there are zero pull requests now because all those pull requests are now pruned because there are no existing pull requests in my GitHub repository. And right now my repository only has the main branch. So if I click scan repository now, nothing will happen because there has been no new commit and we have not pushed any new branch. I hope all the dots are connected. That wraps up day seven. We set up multibranch pipelines, configured branches, PR discovery, ran builds via manual scans, and used our Jenkins file to build, push, and deploy the Flask app on port 5000. Then we opened a PR, merged to main, rescanned, and verified the running container and updated code. In the next lecture, we will talk about Jenkins agents. If you have any questions, feel free to ask them in the comment section and I will reply. If this helped, do consider liking, sharing and subscribing. It will mean a lot to me. Thank you very much. Hi, I am Vun Jooshi and I welcome you to cloud with VJosh. In this lecture, we are going to look at Maven from a DevOps engineers lens. We will start with compiled versus interpreted languages. Then see why build tools exist and where Maven fits. From there we will install Maven create a project with demo 1 and really unpack pom.xml life cycles, phases, plugins and goals. Then we'll also look into repositories and what are their roles. We will also touch on parent and superom briefly so you see how real enterprise projects are wired. Finally in demo two we will run a full flow build with Maven in Jenkins and run the app as a docker container. By the end of this lecture you will be able to read any pom.xml XML understand what Maven is doing in the CI and fix common Maven build issues with a DevOps mindset. With that said, let's get started. So before we talk about Maven, I think it makes sense for you to first understand programming languages at a very high level because these are the languages for which build tools are used. For some of them build tools are used and for some of them build tools are used but they are used from a different lens. So to understand that deeply let's first understand compiled versus interpreted languages. Now compiled languages are the languages which require translation. So for example, if I have the code with me, that code first must be converted into a machine readable format and that machine readable format could be converting that source code into machine code or into byte code. So when you are converting the source code into machine code, this is primarily done for languages like C, C++ and Go. If I talk about converting the source code to byte code, then this is generally done for Java, C and so on. Now I am using the word converting but I should use the word compiling. The source code for compiled languages requires compilation. So when I talk about machine code, it is CPU native. So if I talk about languages like C, C++, Go, any code that is written in that language, the application for that can be directly deployed into your operating system. Of course, you will need certain libraries, but when I talk about modern applications, they have everything inbuilt. So, they just need to be installed onto your OS and once that is done, they can run just fine. But when I talk about compilation which results in the conversion to byte code in that scenario you require a runtime and that runtime for Java language is JVM. Now JVM is not the only runtime that can be used for Java. anything that converts the source code into JVM byte code and the languages for that are also Kotlin, Scala and Groovy. JVM as the runtime can be used for that. Now this is too much of information. I understand that you will need all this information because while you are working with these languages, you will have to understand how they run and how the compilation for them work. Now we will see this briefly as we progress with this lecture about JVM. So for now just understand in compiled languages you translate the source code. You compile the source code from a human readable format to a format that is understandable by machines and that format is either machine code or byte code. So compiled languages requires build stage and that is obvious. So if I want my language to be converted into to be compiled into machine code or byte code then I require a build stage and in that build stage I will perform that conversion. Hence when I talk about compiled languages they will always require a build tool and one function of that build tool will always be compiling and hence compiled languages always require a build tool that will do compilation for them. Next is faster execution. CPU direct compiled languages are often faster when compared with interpreted languages. Code hidden binary only. That is true. So once your source code gets compiled, it gets compiled into dotclass or dot jar. And there is packaging also. And we'll dissect these terms as we progress with this lecture. But the resultant artifact that you deploy onto your operating system or you deploy that onto your Kubernetes platform that code is hidden. You just see the binary and you cannot perform that reverse conversion. Examples of compiled languages are Java, C++, Go, Rust, etc. Now, this is not a comprehensive list. There are many more languages and I will let you see what those are. Then let's talk about interpreted languages. These languages do not require any compilation. So when I talk about build tools, they are still needed for interpreted languages but they do not have to perform compilation. But Warun if I do not have to perform compilation then why do I need a build tool? Why do I have a point here that says may still benefit from build stage? That is because you still have to do dependency management and dependency management is not an easy job like we will see as we progress with this lecture. So for now understand that interpreted languages they also require a build tool. They are typically slower. Now previously they the interpretation you was performed line by line by the interpreter. So these were really slow but now modern advancements they are not that slow but they are still slow when compared with compiled languages code visible. So if you have a Python script or a JavaScript you would essentially share the whole code if you want to ship that application. Anyone who wants to deploy that application, you will have to share that code. Which is why it is said the code is visible. If you have worked with AWS Lambda, then you would see that if you are using Python to write your automation, you have to share the entire script. There is no way to share a binary, which you would do when I talk about compiled languages. Now before I wrap up this section, I want to quickly discuss what are the build tools that are often used. So if I talk about Java, the build tool that is very famous for Java is called Maven. And the second one that you could also see in production is Gradel. And as we progress with this lecture, we will learn more about Maven because the lecture is called Maven for DevOps. Then for C and C++ there are other build tools. But for now I want you to understand that when I talk about compiled languages they require a compilation stage. And for compilation to be performed there must be a compiler that is performing that role. If I talk about Java that compiler is Java C. And the artifact format. What is an artifact? artifact is anything that results from a build. For example, if you are building a container image using docker commands, then the resultant container image is an artifact. Similarly, if I talk about programming languages, if I'm compiling something, anything that results from that, that could be class file, dot jar file, war file, dot ear file. When I talk about Java, this is called an artifact. So, anything that results from a build is an artifact. Let's read what is written here. Build tools don't just invoke compilers. Now, with this definition, you could be thinking that build tools are just used for compilation. But it is not like that. They do so much more. They handle dependencies. And this is an important task. For example, if I'm writing a banking application, then I would of course need a calculator to calculate the interest rates or to calculate the loans and so on. But I will not ask my developers to write the code for calculator. What they would do is they would use a well-known library so that they do not have to write the code for calculator again. And that library when used becomes a dependency. So a crisp definition for dependency is anything on which your application depends. Now that could be a library, that could be a configuration file or an IP address. So anything on which your application depends is a dependency. Now when I talk about build tools, they will handle dependencies for you. For example, if my application depends on a calculator library, then my build tool will fetch that library for me. And not just that, maybe that calculator library in turn depends on another library. So that will also be taken care by my build tool. And this is called transitive dependency. One dependency depends on another dependency. That is called a transitive dependency. Not just compilation and handling dependencies. Build tools will also do packaging, testing and artifact publishing for you. Vun, what is artifact publishing? Packaging is packing your application source code into jar.class orwar. And these are just formats of your artifact. So if you are working with a Java application you would typically see jar being used but war and ear could also be seen. War is for web apps ear is for enterprise. Then packaging is that but what is artifact publishing? Understand that when you generate your container images you are uploading those container images somewhere right and that somewhere is typically your image registry. It could be docker hub or it could be any cloudnative offering that you are leveraging. When I talk about artifacts that are result of build container images are one. Second could be dot jar and dotwar. These artifacts can also be published and they are often published. But warun where are they published? Where are they uploaded? For container images we have image registries container registries. But when I talk about these artifacts, these are often stored in solutions like Sona type nexus JROG artifactory or you could also be leveraging any artifact storage provided by your cloud provider. So for now what I want you to take away is build tools don't just invoke compilers. They handle dependencies, packaging, tests and artifact publishing. With that understanding, let's see what I want to discuss next. Why and what of build tools automate source to artifact conversion reliably. We have seen this. Resolve dependencies including transitive chains. For example, if my application depends on A but A depends on B and B depends on C and C depends on D and E, then my build tool will take care of everything, not just immediate dependency but also any transitive chains, lock versions for reproducible builds. Now what happens is when I want you I want you to understand this or contrast this with containerization. So I'm saying lock versions for reproducible build. So whenever you are creating a container image you use a docker file and in that docker file you provide the version of the base image that you wish to use and every time you build the container image that version is used. Similarly when I talk about build tools they also lock versions. So they have a file often times where you provide these are the versions of dependencies that I wish to use and you must install the same version while I am building my software or application and not just compiled languages even interpreted languages. If I talk about Python, Python, you use a package manager called pip. And pip is the one that is taking care of your dependencies. With pip you have a file called requirements.ext. With Python, you use a file called requirements.ext. And this file will have all the versions of the dependencies that you wish to use along with your application. Hence the build tools once you provide your inputs will freeze the version that your application requires for the dependencies. Hence we are saying lock versions for reproducible builds. So whoever is building your application or whoever is building your software, they already know that the application that I am building right now requires these dependencies and this is the version of these dependencies. Hence wherever that application is built, it builds and performs the same way. Compile or prepare code consistently. And we have already discussed this. Not just this, build tools will also run tests for you. And these tests could be unit tests or integration tests. Llinters. Linting is a process in which you check your code for errors, bugs, style issues before it runs. And it will also point out any unused variables. And then there are of course security scans. So your build tools are capable of performing all these things. Now there are plenty of build tools available. In this lecture we'll be discussing Maven. But understand if you are using any other build tools, they may offer similar functionality for different languages. For example, Maven is primarily used for Java. Although it can be used for other languages but primarily it is used for Java. Hence, Maven is capable of performing all these things. Now, your build tool may not be able to perform a certain functionality. But understand that at large, at a very high level, build tools are expected to perform the functionalities that we are discussing in this lecture. But this lecture is specifically for Maven. So whatever I'm saying for build tools that is applicable for Maven for sure for other build tools you may have to check the documentation. Next is package and publish reproducible artifacts and this we have already discussed packaging and publishing. Packaging is converting your source code into jar.war or any other format. So if I if you look at here see maybe out.exe file maybe ordll files whatever is an artifact whatever packaging format your languages support the build tools will be able to package your source code in that format and then publish. As we already know, publish is essentially uploading your artifact into a central repository so that other team members can also use it. And the next one is eliminate environment drift and manual errors. And this is self-explanatory. If you have defined everything in your build tools, specifically the versions, then it eliminates environment drifts and manual errors. Why elim eliminate environment drifts? because your application is going to run the same way in all the environments because you have defined the versions that your application is supposed to use for dependencies. Hence everything is streamlined. So all these functionalities are performed by your build tools. Now here is a typical build automation steps. First is download resolve dependencies then compile. If I talk about interpreted languages, this step won't imply for them. But for compiled languages, there will be a compiled stage. Then you will be running tests. Now tests could be unit tests. Unit tests implies checking certain parts of your application individually. It could be checking a class or a method and so on. Integration test requires your application to be running. So you check whether the functionality is working between let's say two smaller chunks of the application. So if I'm dealing with a banking application maybe I want to see whether from the account statement section I can go directly to my account details. So all these things are part of integration testing. Then there are static checks and scans. We have already discussed lint s. SAS is static application security testing. Then you have license checks. You have sbombs and we'll see that as we progress with this lecture. At the very last you package jar war binary and then there could be one more step which is deploy. And deploy is same as publish. Here when we are talking about build tools deployments typically does not mean deploying onto kubernetes or onto a virtual machines. I'm saying typically because there are build tools for example even Maven you can use this to deploy onto a Tomcat server but that is generally not seen these days but my point is there could also be deploy but that deploy is essentially uploading your artifact onto a central repository like we have repository for container images you have repositories for your artifact storage as as well. So I hope you have a clear understanding of why we need build tools and what are build tools. With that solid understanding, let's see what I want to discuss next. What is Maven? Maven is Apache's build and project management tool for JVM. Understand I am not saying Java, I am saying JVM. Now I told you the source code when I talk about Java the source code is converted into JVM byte code. So any language for which the source code is converted into JVM byte code and those languages are Kotlin, Scala, Groovy and Java. So all these four languages you can definitely use Maven as a automated build tool for these languages. So Java is a language, JVM is a runtime. So all these languages like Java, Scala, Kotlin, Groovy, they will require a JVM runtime underneath to run properly. And you would have heard these terms when you are deploying Java applications. The machine must have JRE. JRE is Java runtime environment and that's directly related to JVM. So the next point is widely used for Java, Kotelane and Scala project but predominantly you will see Maven being used for Java. Interesting fact you can even use Maven for C, C++, Python and so on. However, you do not do that because Maven specializes in Java. And why you can do that? Here you see a point. plugins handle testing and all these things. So, Maven has plugins. As long as there is a plug-in for C, there's a plug-in for C++, you can use Maven for those languages. Having said that, there are specialized tools, specialized build tools that are used for C, C++, Python and other languages. However, Maven can also be used but it is not recommended you do that. Then pom pom.xml is the single source of truth. Now as we go ahead with this course we will understand that pom.xml is the single source of truth. So every dependency that your application uses the details about your application that is available in pom.xml. Next point is conventions over configuration keep projects simple and consistent. Now Maven says that we adhere to conventions over configuration. So you as a Maven user will not have to configure everything. We as Maven will give you a proper structure of the project. Now what is the structure of the project? I mean the project structure, the directory structure. Maven defines that structure and as we progress we will see that structure. Now I want you to understand if you would have to configure everything you know where source lives, how to compile, how to run tests, where to put outputs, what to name them, which repos to use and in what order to run steps. That is the configuration you avoid by following conventions. Which is why we say maven is conventions over configuration. Next is plugins handle testing, coverage, policies, packaging, etc. Now if I talk about Maven, there is a plug-in that is doing all the tasks for you. Compiling, there is a compiler plug-in. If you are doing unit test, there is a surefire plug-in. If you are doing integration tests then you have a failsafe plug-in. If you are doing coverage then you have Jakokco. Now coverage is the code coverage. So for example if you have 100 lines of code and you are only testing 80 lines of code then your code coverage is 80%. So you have a plug-in that can do that for you and that plug-in is Jakokco. So if you are checking for policies you can use enforcers. If you want sbomb, there is a plug-in called cyclone DX for that. Now see, I am mentioning a lot of plug-in names. As DevOps engineers, if you are in your learning phase, starting phase, do not get intimidated by these terms. As you progress with your learnings, these terms will start making sense to you. And not just when you deal a project that has Java, all these terms will be frequent in your daily language, daily communication. So you will remember these terms. But do not think that there are so many plugins, there are so many tools. It takes time to learn. It takes time for a plant to grow. Keep patient. Be at it. Be consistent. and all these terms, all these tools will start making sense and you will be able to connect all these. So just be at it. Next is produces reproducible artifacts integrates cleanly with CI/CD pipelines. As we have discussed before, you define versions at a single place and that single place in Maven is pom.xml XML and as long as anyone is using that pom.xml along with your source code, they will be able to generate exactly the same artifact as you are in your personal laptop. They will be able to do that in the CI server or in their personal laptops as long as they have your source code and the pom.xml. The next one is Ant versus Maven versus Gradel. Now Ant is legacy now. It was used before Maven existed. Now in ANT, you had to configure everything and you have to write your steps manually and so on. So it was configuration. But in Maven it is conventions over configuration. And then there is Gradel. Gradel provides you flexibility. Now 80% of the Java projects I have dealt with were using Maven. So I wanted to check what are the stats. So I looked at Chad GPT and Chad GPT said that 60 to 70% of Java projects are built using Maven and 30 to 40% of Java projects are built using Gradel. Now Gradel provides more flexibility and it is predominantly used with Android. So with Android applications you would often see gradal being used but in my experience I have personally dealt with Maven more at least in 80% of the Java projects that I have been part of. Now we understand what is Maven. So I do not want to bombard you with another theory part. Now let's go to the CLI and install Maven. So what I will do is I will go to my browser and I already have created one EC2 instance. This is T3 micro and it is based on Ubuntu latest Ubuntu. And let's power this on. So I have not configured anything. I have just created the instance and I've stopped it. Now we will copy the address and SSH into this. So if I go to my terminal, if I run ls here, I not this screen, this one. Yeah, if I run ls here, I'm in the SSH folder. I already have the keep required for this instance here. And I will be using this key to login into my instance. So let's go back to the browser. I will click on connect. I will simply just copy this SSH command. I will paste this command here. I've already given this appropriate permissions and let me show that to you. If I run ls-la then you would see that this key that I am using it has strict permissions only read and write are with the owner and the owner is vun Johi yours truly. So I will just copy that again and I will paste it here. I will press enter and this will connect me to this instance. Now I would suggest you to rename this instance to Maven like I have done. I will you can check the command to do that in the GitHub repository. It is host name. Ctl can be used to change the host name. I've called it Maven for simplicity. Now let's first install Java. So I will go to my browser and then here I will go to the GitHub notes for this lecture. I will go to installing Maven here and then here is the download guide for Maven. I will open it. I will zoom in a little. So we will be installing the latest version of Maven which is 3.9.11. This one and it says that Maven 3.9 plus requires JDK 8 or above to execute. Okay. So let's keep that in mind. What I will do is I will right click here and I will copy the link. Copy link address. I will copy this oft.gz. Now I have specifically chosen to install this into an EC2 instance so that everyone can follow along with me. So I would encourage you to spin up an instance and follow along with me. So I will go to my terminal and here first I will run sudo apt update and this will update my index. Once this is done I will write sudo apt search I will search for open jdk. Now when I do this search I see jre I see JDK. But in here what we want to do friends is we want to install JDK not JRE. JRE is Java runtime environment and it is installed when you want to run Java applications. But we are builders, we are DevOps engineers. What we want to do is we want to build Java applications and then run it. So hence we will be installing open JDK. JDK is Java development kit. This along with the JRE also includes the compiler which we will be using while compiling our application. So let's do one thing. I will be using version 17 for Java. So if I run this, hold on. If I run 17 here, if I add 17 here, then it will tell me all versions of Open JDK that are 17. So what I want to install is this one. Open JDK this one. So what I will do is sudo apt install. I will add that and then I will add here Y for yes. And this will install Java on my machine. So once the installation is done, I can run java - version to check the version of java that is installed. So if you see we have java 17.0.16 installed. And if I run java c-en version, java c is java compiler, it will show me that the compiler version that you are using is 17.0.16. And if you remember when we were discussing our build tools, we said that the compiler that is often used for Java is Java C, which is why you see Java C was automatically installed when we installed JDK Java development kit. Now I want to install Maven. So I could have just written sudo apt install Maven Y. Now if I do that the life cycle of Maven that I install will be governed by apt okay the package manager for my Ubuntu system. But if I install Maven using a binary like I showed you we copied the path of the binary. If I use a binary to install Maven then I own the life cycle of that tool. So the install, the upgrade, the roll back, the cleanup, everything will be done by me manually or I could automate that process. So often when you are dealing with these external tools like Maven, Sonar Cube, you would see that these are also installed in /OP. Now /OP is for optional packages. So you would typically see that these tools are installed there. But I will leave that decision to you. I am using a binary so that I can also teach you a few more Linux concepts while we are learning Maven. So I will not run this command and in this lecture itself when we move to the last demo we will be using this command to install Maven. But for now I want to show you the binary method and why we are running Java is why we installed Java first is Maven requires Java. So if you see here JDK8 or above is required. So if I copy this link again, I will copy link address. I will go back to my terminal and I will clear my screen for better visibility. I will cd into opt then I will write sudo wget and this is the file I want to get. So if I run ls you see that tar.gz is downloaded. I will use sudo tar - x for extract, v for verbos, z for gzip and f for files in this file. So that our tar.gz is extracted. So once I run ls I see that the file is extracted. Now what I can do is I can delete this one because I don't need it. I will run sudo rm rf. It is apache and there is a hyphen bin. I'll press enter and I will run ls. Now this is deleted. I just have this here. So what I can now do is I can cd into Apache. I what I will now do is I will rename this for simplicity. So I will use move mv Apache and then I will call it just Maven and I will also have to add a pseudo here. I'll add pseudo. I will rename this file. Once it is renamed I can go into Maven. And if I do ls, I can see that there is a bin directory and inside bin directory there is the executable that we want to run. So if I go to if let's say I add bin mvn - version then I can see the version of maven. But if I just run mvny-en version, this command will fail because my shell will not be able to recognize mvn. Previously, it ran because I provided the complete path of my executable. Complete path of my executable. In Linux operating system, if I run SSH, SSH works for me. It works because SSH binary is available in the path that my OS is searching for executing any binary. So if I run which SSH, it will tell me that SSH is located in USR bin. And if I echo the path variable which tells Linux operating system that you have to search these paths in order to find any binary. So if I press enter, you see user bin is here and user bin is also here. So all these paths that are searched by the OS are separated using a colon here. So for SSH we are searching this but for MVN MVN is available in /op maven and we don't see that here. So we should be adding that path in our path variable so that when we execute mvn it can run without us specifying the full path like this. So let's do it. So what I will do is I will go to my users bash rc file. So I will write vim and then I want to go to bash rc here. And then once I'm here I'll press shiftg to come at the very last. I will press i to go in the insert mode. And then what I will do is I will write export. And this is how you define environment variables. And then here I will write path is equal to now what is the path for me? I do not want to remove that path all together. What I want to do is I want to append the existing path. So what I will say is my dear friend you first take the path that you already have right now and what I want you to add is I just want you to add /op/maven /bin in that path and then I will close this and once I'm done with this I will hit escape I will press shift zz to save this now I will source this file so that it refreshes and then my shell knows about it. I will write bash rc. Now this is source. Now if I type which mvn now it is telling me your maven is located here. And if I run maven - version now it will tell me the version of maven as well because now my system recognizes the maven binary because we have added the path for this binary in our path variable. So if I echo path now you see I have to put a space here you will see that opt maven bin is available here. So I hope this makes sense. Now we have installed Maven. Now let's go into building our project. The first project that we want to build. I'll clear my screen. I will come to my home directory and ls. I don't have anything here. So I will go to my browser and I will go to my GitHub nodes. And then this is the demo that I want to do. I'll zoom in a little. I will open this now. See firstly I told you that Maven is convention over configuration. So what we want right now is we want a structure and a simple source code. So what we will be doing in this lecture is we will be using something that is provided by Maven to us. So if I scroll down you see that you can create your own first project and you can use this command to do that. So what I will right now do is I will just copy this command. I will copy a format that is much more easy for you guys to understand. So let me go to my terminal and here I will paste it. Now before I run this I want to explain this to you. MVN archetype generate. Firstly what is archetype? Now archetype is project template. Now project template will give you the directory structure. It will also give you the pom.xml. You do not have to write pom.xml from the very scratch. There are multiple archetypes available. You can use based on your requirement. So this will provide you a skeleton that you can use for your maven and that's pretty awesome. You don't have to write pom.xml from the very scratch. So we are using a very basic archetype that is generate. So what is an archetype? An archetype is a project template. So you start with a runnable skeleton. Now what are the fields that we are defining here? Hyphen D can be thought of as part of the syntax. Then we are providing the group ID. Now group ID we will discuss this in detail much later but for now just understand it's the reverse DNS of your website. For example, if my website is cloudwithvos.com then my group ID will be com.cloudwithvos. Artifact ID is my app. Now understand if cloud with varosh has multiple projects then how do I identify those projects because there is a group under which all those projects reside but which project I want to use that is what is provided by artifact ID. So group ID is the let's say the grouping and artifact ID is which entity in that group you want to deal with. Here I'm just saying my app. Then archetype artifact ID. Now this is the artifact ID of the archetype that you wish to use. So like I told you there are multiple archetypes available and the artifact ID for that one is Maven archetype quickart. This is the ID that we wish to use. Now there could be multiple other archetype artifact ids which would result in a different pom file or a different source code but the source code that we will be using is part of the archetype quick start then this is the version of this 1.5 and this is pretty much self-explanatory interactive mode is false so I will press enter and once I do that this will create a project structure for me. So if I press ls now you see that my app is there. Now I will cd into my app and I'll clear my screen. I'll press ls. You see two things here. src and pom.xml. So let's run tree command. I don't have tree installed. So sudo apt install tree y. Now what this will do is this will install tree and tree is a fantastic utility that will tell you the directory structure. So if I clear my screen, I run tree here, it will tell me that this directory has pom.xml and this also has source and source has this hierarchy and test has this hierarchy. So firstly I want you to know that you as DevOps engineers will not be writing pom.xml from the very scratch. I hope that relieves you a little. And then the source part also it is not you who will be writing this src directory. This contains the actual code. So main here contains the code and test here holds the tests that will be performed here we have created it but in actual production applications these things will be part of your SCM. So when I say your pom.xml XML and SRC will be in SCM. The first thing that should come to your mind is these files should not have any credentials, any secrets, any keys because even if you are in a private repository, you should never commit your secrets onto SCM. So first thing is you will be storing these in your version control. So it could be your GitHub, GitLab or any other version control system. Now we have briefly discussed about pom.xml. pom.xml is the main Maven file for your project. It is the file that is the single source of truth for Maven. It tells Maven your project's identity, libraries, dependencies, build steps. Maven reads this file to build, test, package and deploy your app the same way every time. So understand this file is extremely critical. So let's do one thing. I will cat into pom.xml. So this is as expected in XML format. So I want to explain this file to you line by line so that you can easily understand what happens in pom.xml as DevOps engineers. Now you would be thinking Vun if we are not writing this file we do not have ownership of this file then why should we understand this? You want to understand this because at times most of the build failures will be directly related to pom.xml. Essentially if your build is failing there is something tricky or something going on in your pom.xml. So until and unless you as DevOps engineers understand pom.xml XML because the CI/CD ownership is with you. You are the one who will be integrating different plugins in the pom.xml. Your developers will be writing the most of it. But if you are using a plug-in for security testing, if you are using a plug-in for something else, those plugins would be added by you in the pom.xml. So you want your pom.xml XML to be error-free and you as DevOps engineers can only ensure that once you understand the pom.xml file to begin with. So here it is in a black and white format. So what I have done is I'll take you to Visual Studio Code. I have copied this pom.xml exactly like you see here to this screen so that I can explain the pom.xml. Now before I start explaining pom.xml XML. I feel it is imperative you first understand XML. So I will just take 5 10 minutes to tell you basic XML and then we can start with pom.xml. So XML, JSON and YAML are all textbased format for structuring and exchanging data. Though XML is a markup language with tags. Now what are tags? We'll see that later. While JSON and YAML use key value style structures and you are wellvered with YAML because most of the DevOps tools use YAML and if you have done CKA uh and if you search my channel you can see JSON path lecture if you don't know JSON you can learn more about it there. But for now we know what XML is. Now let's understand this structure. Now, XML uses something called elements. So, what you see here, this is an element. This is an element. This is an element. Then, Waron, what is an element? Element is something that starts with a tag and then closes with a tag. So, for this element, this is the starting tag and this is the closing tag. for this element. This is the starting tag and this is the closing tag. Now closing tag has a forward slash in it. That is how you identify it. Now this is one element. Vun why is this one element? So see this element starts with project. This is the starting tag and this ends with project which is the closing tag. So entire this is also an element. Then vun how do I differentiate? So project here is a parent element and then whatever you see here the indentation follow the indentation this this this all of these are child element. Similarly, if I talk about this properties element, then whatever you see inside it is child element of the properties parent element. So this is pretty basic and you would have seen something similar when we talked about YAML or JSON as well. You see this starting tag is simple but this starting tag has these things as well in them. Now anything that is there in the starting tag these are called attributes. Now this project tag has three attributes. Now you do not have to understand this deeply because it's just touch and go. You uh you will rarely be playing with these. These things are pretty much this constant in uh you know pom.xmls. I'm just telling this to you for your understanding. And what you see in here this is called text. So this element has this text under it. Now this is all you want to know about XML. Now with that understanding let's start discussing form.xml. Now this is the basic structure that you would see. This is the root element. Whatever you see at the very top, this is called the root element. And that's understandable. This one is the root element. And then you have these things model version will pretty much always be 4.0.0. What I have done is I have added comments in this XML. And the format in which you add comments in XML is this. So any comments that you want to have can be under this. It's pretty funky but that is what it is for you. So you have to add comments like this. And you can see here pom model version fixed at 4.0.0 for Maven 3 and 4. So that's why I said it will pretty much always be four in whatever projects you are dealing with. Then the most important part is G A V. And we call these GV coordinates. So when we talk about any location on our mother earth, we talk about coordinates. So if you want to reach there, these are the latitude and longitude and if you reach there, you will reach that specific destination. So essentially coordinates are address for a specific location on earth. Right? Similarly, if I talk about GAV coordinates in Maven, these uniquely identify a dependency or a project. We will dissect this definition as we move ahead. Now, GAV is used to uniquely identify a project or dependency whether it is in your local or remote. What is local and remote? to understand. If you talk about container images, at times the container images are available in your nodes and at times they are available in image registries and then you pull it from there. Correct? Same concept here. You can have your artifacts or your dependencies locally or you can have them in a remote location. So GAV is uniquely identifying your project or dependency. But Vun why are you using project and dependency interchangeably? Understand my Maven project could depend on another Maven project and if my project my Maven project depends on another Maven project then how do I reference that another project? I reference that using GAV because I know for a fact that these GAV coordinates are unique for any project or any dependency. For example, if there is a MySQL dependency, it will have a group ID. It will have a artifact ID. And once you provide these things along with the version only, then your Maven instance will be able to resolve that or fetch that. So if you do not provide version for your dependency for example, then Maven will not fall back to latest. It will not fetch it. So providing these coordinates, GAV coordinates, project coordinates are of utmost importance. So now that we understand this, let's dissect G, A and V. So here the group ID we have already discussed it's reverse of your DNS. So here the example that we are using it's com.mmy company.app. Then artifact ID is module name. Now see understand it this way your organization could be dealing with multiple microservices correct in that scenario what you can do is let's say you are talking about application one so let's copy this so that you understand it in a nice way so I will copy this I will come here I'll paste it here let's take care of the indentation as well let's do one thing Let's call this com dot cwj app. Now this is for app one let's say. Now if this is for app one, app one could be consisting of multiple microservices and then I could name that artifact ID app 1/ payments and then another one I could name app one hyphen orders. I want you to clearly understand that when you are dealing with an application, your application could be a single application that only has one pom.xml like this one or you could be dealing with an application that has multiple pom.xmls. Why multiple pom doxmls? Because each micros service will have its own pom.xml. like I showed you here. If you are dealing with this, then you will have one micros service with this, another micros service for orders, another micros service for uh let's say wish list and this holds true not just for microservices but for also your pom.xml. So the number of microservices is directly proportional to the number of pom.xmls that you have had. Now the group ID this depends on how you want to keep it. Maybe you have it for per application or maybe you have it for your entire application stack. If your applications are not microservices then you could have just app here and then one pom.xml could be for app one. Another pom.xml could be for app 2 and so on. So create that mental picture in your head. So now that we understand both of these, let's talk about version. Version is simply the version of your application. But Warun, why do I see a snapshot here? Now versions can be of two types. They can be releases or they can be snapshots. When we are talking about releases, releases, think of them as production. They are immutable. they do not change. But when I talk about snapshots, snapshots are that is work under construction. So the development is still ongoing whenever I am talking about snapshots. So in essence when someone is developing it, understand that they will be pushing it as well. Then how do I ensure other developers that are using this snapshot they always have the updated snapshot with them? Now that something is governed by something called update policy. So I'll take you back to the GitHub repository and if I scroll here you see snapshot versus releases. The refresh rules for these snapshots are defined in update policy. Now that can be always, daily, you can specify an interval or never. If you build your application at a regular interval in a day, then I would suggest you to choose always and daily. If you just build once a day and these things are subjective. I will let you choose what is best for your use case. Now let's go back to our Visual Studio Code. Now let's discuss these. Now name is a display name. Now this is typically same as the artifact ID but you can have a different name like this. What it will do is this name will appear in all your reports and logs. So ideally you should keep this same as artifact ID. But if your artifact ID is not descriptive enough then you can have a different name here. URL. Now this does not necessarily mean a publicf facing URL. This URL could point to your repository or it could point to your documentation or it could point to the wiki. So if you are dealing with let's say a microservices design you this pom.xml XML belongs to a payment micros service then within your organization you will have the link of the private let's say GitHub repository that holds the code and pom.xml for this specific micros service. Now let's scroll down what you see here is properties maven properties buildtime placeholders not OS environment variables. Now do not mix this with the con concept of environment variables but they function kind of in a similar way. So what happens is whenever you are defining your dependencies you have the right to not define the version in the dependency section but ask the dependency section to refer the properties section when they want to check the version of a certain dependency. Now Vun why is this useful? So imagine in production implementations your pom.xml could have hundreds of dependencies. It is futile. It is not worth your time to search for those dependencies and maybe change the version. What you can do is you can directly come to the properties section, check the version that you wish to change and change it here because anyway the dependencies are referencing the properties section to fetch the version. So let me show this to you. I'll go to the browser and then I will scroll down. Here you see properties and you see what I have done is these two properties are built in. So for example there is no dependency that is referencing these properties explicitly implicitly under the hood Maven is using them but for you to understand what I have done is I have added two more lines here you see I have added two more properties one is spring boot version 3.3.4 and then there is a JUnit version which is 5.11.0 zero. Now, how do I reference this? In the dependency section, if I scroll down, you see in the version section, I want you to clearly understand that whenever we are talking about a dependency or a project, what is the thing that uniquely identifies them? It is the group ID, the artifact ID and the version. This is the GV coordinates. So, keep this in mind. Version, supplying version is important. If you do not specify any version here then this will fail because Maven will not automatically choose the latest version. It will just fail. So you must provide the version of the dependency that you wish to use. So here we are saying when you want to check the version for this dependency you go to the properties section and check for spring boot version. And here it is spring boot version. If you want to check the version for this dependency, you go to junit.ver version and here is junit.v and it will pick 5.11.0 based on what we have defined in the properties section. So you would often see that properties section is used heavily in production implementations. Now let's go back to our visual studio code and understand what is dependency management and dependency. Right off the bat, I want you to clearly understand that dependency management is not downloading any dependencies for you. It is just there to tell the version of the dependency that you have not specified in the dependency section. So for example, if you have not specified the version for a dependency in the dependencies section itself like you see here there is no version here version tag here then it will check with the dependency management section. So that is what dependency management is doing. So in a single line. So dependencies what actually gets pulled into your project. Dependency management is the version rule book used only when dependency doesn't specify its own version. So here you see both of these dependencies they have not specified its version which is why dependency management section is referenced. Now, now you might be thinking, Vun, I see JUnit Jupiter API here and I see JUnit Jupiter PAMS here, but I do not see an artifact ID with a same name. I just see that you are referencing something called JUnit bomb. You are importing something called JUnit bomb. It does not have these names. Then how will this work? Here I want to explain the difference between Sbomb and Maven bomb. So you see it's a JUnit bomb. Here Sbomb is something that we discussed in our Jenkins lectures, CI/CD lectures where we learned that SBOM is software bill of material. This will hold everything that your software is using. Any library, any dependency that your software is using is part of SBOM. And sbomb is good because it tells you that these are the libraries that you are using and some of these libraries require licenses. So you may have to pay someone to use these libraries. So sbomb will tell you things like this whether there are any vulnerabilities in the dependencies that you are using in the libraries that you are using. So sbomb is good for that. Do not confuse sbomb with maven bomb. Maven bomb says that whatever I am downloading this has everything about that specific thing. So here junit bomb will have the version information. I'm not saying it is a dependency. It is downloading some dependency. It is downloading a dependency with a specific version. No, I'm saying junit bomb will have the versions of everything JUnit. So here we are using JUnit Jupiter params and here we are using JUnit Jupiter API. So this JUnit bomb will have the versions of all these dependencies and we know for a fact if a dependency is not defining a version it will not be downloaded. What it will do is this dependency will check the JUnit bomb and it will find the version that is to be used for JUnit Jupyter API and the version that is to be used for JUnit Jupiter params and it will use it. So a bomb is essentially a collection of all the versions that are specific to that something and that something here is Junit. Now another thing I want you to understand is the type is pom and here the scope is test. Now this type is fine a pom we are calling it pom because it just has the version information. The default is jar here type for dependencies or for dependency management. But we are saying pom because this junit bomb will just hold the versions not the actual dependencies. We have discussed this at stretch. Okay. Now the scope is just import and the scope here is test and we will now see what scope means. So let's go back to our GitHub notes and again I would encourage you to go and read the GitHub notes. Whatever I am discussing is there in the GitHub notes. You see here dependency management bombs. It is the versions version rule book. So if I scroll down we have already discussed these. Now I want to discuss scope. Now see when you are building a project you will be performing different things. You will be compiling, you will be testing, you will be running the application and so on. Now you don't want that whatever was generated during the test should be available in at runtime or during compilation. Right? because it is unnecessarily increasing the attack surface because you must choose the narrowest scope that fits to reduce size and attack surface. You choose the scope that is needed for that specific dependency. Now what it is a switch that defines which class paths the dependency appears on. bundling depends on project packaging and plug-in. So let's see what I mean by this. Let's see this with an example. So if I am using a dependency called JUnit Jupiter params and JUnit API here I have defined the scope as test which is a good practice because I don't want this dependency to be available at runtime. I don't want that. And if I would have not defined this scope, the compile scope would have been taken. And in compile scope, the dependencies available in the compile part as well, in the test part as well, in the runtime part as well. I don't want that at all. I just want the dependency to be available for the stage it is needed. If I'm performing testing, then it should be only available for the test class path. If I scroll down, I would again encourage you to read all of these. Now, let's discuss the last part here. This last part is about plugins. Now, when I talk about Maven, it is plugins that are doing the actual work for you. So, be it your build, be it your compile, test or package, whatever work is being done is done by plugins. Now in this section in plug-in management section you just pin the version of plugins that are to be used. So you see if I'm talking about compiling then the version of the compiler that should be used is 3.13. If I'm talking about tests shorefire plug-in the version is this. If I'm talking about packaging packaging to jar format then the plug-in that I want to use is this. And the version that should be used is 3.4.2. As simple as that. Now you have a good understanding of pom.xml. With this understanding, let's see what I want to discuss next. Now next is another theory session. I'm sorry for that. But see, until unless you understand the theory, the demos will not make sense. So we will have to do that as well. So I'll scroll down and I want to discuss build life cycle phases plugins and goals. Maven follows a life cycle made of ordered phases. At each phase plugins goal perform the actual work. Okay. Now like I told before plugins are the ones that are actually doing all the leg work for you. So life cycle is divided into three parts. Okay. So if I talk about life cycle, there is a default life cycle, there is a clean life cycle and there is a site life cycle. Now each life cycle has different phases. This one has 23, this one has three and this one has four. So if I take you to the documentation, if I go to GitHub documentation and then I scroll down. So there are 23 phases in the default life cycle but we only discuss the ones that are mostly used. So if you want to see all the phases then you can refer this link and this will show you all the phases that are there in the default life cycle. So there are so many phases. What I want you to understand is let me go back to draw.io. If you run the test phase, it will also run the compile phase and validate phase. If you run the deploy phase, it will run all the phases that are before deploy. So it works like this. If you run verify, then it will run all these phases before verify. So it is if you go to the documentation, if you run test phase, then all these will be run by default. So all the previous phases of the phase that you are running will be run when you run a phase. I hope that makes sense. Now first phase is validate. Now again I want you to know that life cycle and phases these are logical concepts. Okay? These are just concepts. They are not doing the actual leg work. Actual leg work is done by plugins. And we'll see how that works. So this is self-explanatory. Validate phase it will validate your pom.xml. Compile phase will compile your main source code intoclass. Then there is test. It will run tests. Package it will package it into jar war. Integration test will in execute integration tests. Verify run post package checks and quality gates. Install. These two are important and these are relevant to the architecture that Maven uses for storing information. Now we have not discussed about repositories yet but for now just understand that there could be a local repository and then there could be a remote repository. With that understanding let's understand these definitions. Install will publish the artifact. Publishing the artifact implies uploading the artifact to the local repository. The for example, if I have installed Maven onto my Ubuntu EC2 instance, then it will just upload or publish the artifact in the local repository. And where that local repository is, we'll see that later. But for now just understand install part deals with local repository and deploy part deals with remote repository. So in deploy part you publish the artifact to a remote repository. Then we talk about the clean life cycle. As the name implies it is required for cleaning. Now vun why do I need cleaning? and you need cleaning and this cleaning is relevant to the artifact that is being generated. Now understand when you already have the source code you can use Maven commands to generate an artifact out of that and once that artifact is generated and you have done the upload of that artifact you don't want that artifact to stay there right that can be deleted because if you want that again you can again generate that artifact because you already have the source code and how this is all done we will see that but for now understand that cleaning deals with cleaning of the artifacts that are generated. So artifacts as in dot jar or war and it is specifically also telling you the directory. So right now when we saw the project structure for my app you saw there was pom.xml and there was src. So if I run ls you saw pom.xml and src. Whenever you do a build, whenever you do a packaging for example, you would see that a new directory gets created called target and this target directory holds the artifact for you. So that is what we are saying here. Remove outputs from previous builds. Now there are certain tasks that you can perform pre-clean and then there are certain tasks that you can perform post clean. So these are just referencing them. Then there is the last life cycle called the site life cycle which has four phases. Now this deals with the site documentation about the site generation. So there are different phases here. Pre-sight site posts site site deploy. I have written about them in the GitHub repository. For us DevOps engineers these two phases are of utmost importance. though we should also know about this. So for now I will let you read about this and let's see more about these phases. Now what did I tell you? These phases are not the ones that are actually doing the leg work. So if I go to my terminal and I clear my screen I will just run maven validate. Okay. And I'm running maven validate because validate is a phase. Understand? I am running a phase. I'll press enter. And this will validate my project structure and my pom.xml and will give me an output which is okay. And as you know if I now run maven compile it will run the compile but it will also run validate because the previous phase automatically gets executed. So this is understandable but I also said that these phases are not actually doing any leg work. Leg work is actually done by your plug-in. So let's go to the GitHub repository and I want to show that to you. If I scroll down, yeah, this is the chart that I want to show you. If I talk about the default phase. So whenever you are writing MVN compile for example then behind the scenes the plug-in that is being used is Maven compiler plug-in and now I want you to correlate. So if I go to my visual studio code and if I scroll down we defined the version of Maven compiler plug-in as well here 3.13 just for your information so that you can correlate these things. So if I go back whenever I'm running mvn compile under the hood this plug-in is being used and a plug-in can have multiple goals. When you run mvn compile it is the compiler plugins compile goal that is being triggered. So this is the only thing that you want to take away from this. When you are running a phase, a phase will be supported by a plug-in. And that plug-in can have multiple goals and when you run MVN compile, the compiler plugins compile goal gets executed. So a plug-in a tool Maven can use and that plug-in could be compiler testr runner packager deployer and you have seen these plugins here right shorefire plug-in now if it is maven compiler plug-in it will be just called compiler if you have maven shorefire plug-in it will just be called shorefire for simplicity and if I come here if I run let's say mvn test or let's say mvn package if I run mvn package package then Maven JAR plug-in gets used and the JAR plugins JAR goal is invoked again if you are running MVN test compile then also the compiler plug-in is used but this time compiler plugins test compile goal is used so understanding this is very important when you are dealing with plugins plugins can have multiple goals and based on which phase you have run that goal is execute. And now someone is thinking we have just run mvn compile. So let's run this command as well. So let me go here and I will run ls and let's run mvn compile. And if I run mvn compile and press enter you know that when compilation runs a previous phase automatically gets run and that previous phase is validate. So if I go to my diagrams, if I'm running mvn compile, we know validate automatically runs. And if you have to see the extensive list here, if I go here, if you run compile, all of these things are getting done. Okay, but we have not explicitly mentioned them because we are only dealing with the most used phases. But understand when you are running compile, all these are also getting executed. But the interesting part that I want to show you is if I go to this if I run mvn compiler compile then only compilation will be done. The previous phases will not run. Why? Because I am directly invoking a goal. I'm directly executing a goal. I'm saying just compile. But if you run mvn compile it will also validate it will also run all the other phases like you saw before. So what I will do is if I run ls now you see there is a target folder created. So if I run mvn clean now what it will do is mn clean this a spell error mvn clean it will just delete the target folder. So if I press ls it is just so show showing source again. So let's run mvn compiler compile. And if I run this, this will not perform any validation. This will just run this goal. And it will be evident from the output you see. And if you see this output just compiler is here, right? And if I scroll above, if I see the output for MVN compile, you see resources is also there because it is explicitly showing that if I go to my browser, if I go here, then you see there is something related to resources that also runs when you run the phase. But this time we only ran a goal which is why you only see compile here. So understanding these nuances are important because this somehow decreases the time your pipeline takes to run. For example, if I were to run MVN install, then all these phases will run. But if I am sure that MVN install will work just fine, then why not just run a goal with a plug-in that will just publish the artifact to local repository. So understand why there are features why there are functionalities available you would be using them based on your requirement. So for example if you run mvn deploy it will run all the previous commands but what if you run mvn deploy deploy it will only deploy it will not perform all these steps. So keep these things in mind. Now that we have this understanding, I want to take you back to a demo. So I will go to my terminal. And here we have already seen few commands. We have seen mvn validate. We have seen mvn compile. And now what I want to show you is mvn. So first let's run tree. I'll run tree. And this shows me that target has classes. And you see this hierarchy. This is done based on whatever was there in our pom. So app my company com and if I go here app my company com. So this directory structure is taken care by maven itself. We did not have to do anything there. So here what I will now run is I can run java. I want to run this application. So I will run java class path. Now where is my class located? So I know that it is target and in target we have classes and inside classes what I want you to do is I want you to run this com dot my company dot app and here I want to run dot app this one okay I am specifying a target and then I will press enter and there is a spelling error it should be company And if I press enter, you see hello world. And that is what this application is supposed to do. And what I can also do is I can run MVN package. And what will MVN package do? See, we do not see a jar file yet. We see a dot class because what we ran before was MVN compile. What MVN compile will do for you is it will change your source code into class. But what MVN package will do is we learned it here package will convert your source code into jar war or whatever format you define for us it is jar. So if I run mvn package it will create dot jar file for me. So let's run this and once this is run I'll run tree again and you see in the target itself there is my app one. You see what format this is adhering to. We have defined this in our GAV itself. So if I go here, this is the 1.0 - snapshot. 1.0 - snapshot. And this my app is coming from here. I hope all this is making sense to you. Now if I want to run this jar, what I can do is I can write java - cp. And this time my target is previously our target was classes but this time my location of this is in in the targets directory I want to go to my app dot jar and then I will just specify the same thing com dot my company dot app dot app. Now this might feel a little off to you if you are not from development background but whenever you are running a Java application this is how you run Java application. So it is once you start working you will understand these things. If I press enter this is saying hello world. Now let's run mvn install. Now what MVN install would do is it will publish the artifact onto your local repository. But Warun where is the local repository and it is here. It is pointing to your local repository. It is saying that whatever artifact you have generated right now that artifact has been published onto the local repository. If I would have run mvn deploy then it would have published the artifact onto a remote. But have we defined a remote yet? We haven't. Right? So if I here run ls and I supply this then of course you would see that there is a snapshot file there and along with the snapshot it also has pom and some xml metadata as well in this location. So for now mvn install we have seen. Now let's run mvn deploy. mvn deploy will fail because we have not defined a remote where this artifact could be published. Now I want to show you a few more things. So mvn clean as we know will clean up our target directory. So if I run ls I don't see target anymore. I usually in projects what you would see is two phases are called simultaneously. So mvn clean will be called first and then install will be called. So what it will do is it will first clean the target directory and then it will run mvn install. So this is a step-by-step process. First mvn clean will run then mvn install will done run. And we know for a fact that mvn install will again recreate this / target directory. So if we run this then if I press ls you would see that /ashtarget is again created for you and mvn clean as we know will again remove this. Now we can also run mvn site this will generate the site data for you and if you run tree after running this let's first run ls then I will run tree so that you can see what all things are generated with the site. So ls if I do tree then you see in the target the side data is also created for us. Now I will let you explore this. Now that we have gotten this understanding let's go and understand repositories. So if I go here what is a repository? Repository stores artifacts and metadata. And when I showed you the local repository just now, you saw that there were files with extension.com. There were files with the name metadata in it. And there were also artifacts. What were the artifact? The artifact that we saw was ajar snapshot version. And that is what our palm was intended to generate. So repository is a place where we store artifacts. That point is clear. On the right of your screen, what you see is a local repository and then remote repositories. Local repository is maintained in the machine that has Maven installed. So in my demo my EC2 instance had Maven which is why a local repository was there and local repository is in the M2 directory that we already know from our previous demo. But Wun why are remote repositories needed? Now understand when you are downloading certain dependencies, your application may require dependencies that are not available within your machine which are not available in the local and why they are not available in the local. Understand that the local repository is supposed to cache whatever dependencies are needed by your project. So first the dependencies must be fetched from somewhere remote and once they are fetched they can be cached into your local repository. Your local repository is there to speed up your builds. Now you might be thinking what are the examples of remote then remote could be Maven central. Now, Maven Central will hold the most popular, you know, public dependencies that can be leveraged by anyone. And similarly, your project could also be using that the example that I gave you before. For example, if I'm using a library that has the logic for calculator, then that logic can of course be found in Maven Central. So, let me show that to you. So if I go to my browser and I write Maven central here then I should see MVN repository central. So yeah this is the repository. So if I search for let's say my SQL then I will see my SQL connector is this one. Let's see my SQL connector for Java. So let's click here. And if I click here it is saying that category is JDBC drivers. And if I go to any of the versions that I wish to use, let's go to 8.0.33. Then it will tell me how can I use this dependency. So if I add this in my pom.xml, then it will fetch this specific dependency from maven central. Now will it always fetch from from maven central? It depends on what are your precedents. Now precedence we will see in a little while. But for now I hope you got the idea. So let's go back here. Now remote can be of multiple types. I will tell you the most popular remotes that I have seen. First is Maven central. You pretty much will always have that and this is something that is configured in your super pom. What is super? We will see it in a little while. Then you have vendor repos. Let's say you are using a custom application. Now custom application will also have let's say custom dependencies which that vendor has specifically created for that application. Now that you are using that application and building that application, you would want to use those dependencies as well. So such dependencies are fetched from vendor repositories. You could be using vendor repositories or could not be using vendor repositories. It depends on what is your use case. Whether you are using a custom application, building a custom application whose pom fetches dependencies from somewhere remote. So that is one option from somewhere remote that is a vendor repository. Then the third type you would see is company managed and this is something that you will see 100% of the times when you are dealing with production implementations. Companymanaged repositories are the repositories that are company specific. So for example you know that these five dependencies most of my project use then you will upload those dependencies in your company managed repository. Now company managed repositories may have access to internet or they may not have access to internet depending on how tightly governed your environment is. If for example your company managed repository doesn't have access to internet then all the dependencies that are required by your application you will pre-download those dependencies onto your company managed repository. Now what are the examples of company managed repositories? You would have heard of sonata type nexus. Sona type nexus is a popular choice. Then another popular choice is JROG's artifactory. If you are onto a cloud provider, you could be using the native repository provided by your cloud provider. So in summary, repositories can be categorized into two local and remote. Local is something that is available in the instance where Maven is running and local will cache any dependencies that were downloaded from outside so that your next builds can run in a speedy way. So caching enables faster repeatable offline builds. Then remotes can be of three types in general. There is central repository that is configured via superom. Then you have vendor repos. Now these are optional depending on your sort of deployment. But you would pretty much always see company managed repositories. Now that we have this basic understanding, let's go to the next slide so that we can deeply understand what a production grade architecture looks like. Here I have just given you the definitions of local and remote. Let's see how production implementations may look like. So this is the production flow with match all mirror. So images on the left can be ignored for now. Let's concentrate on this diagram. Like the previous diagram, we have the same number of components. There also we had a total of four repositories. Here also we have a total of four repositories. 1 2 3 and four. Now this one is local. What we have configured here is we are telling our Maven for any dependency that you want to resolve, you reach out to the mirror and mirror will know what to do. So for example, let's say I'm fetching a dependency. If mirror has it, mirror will hand over that dependency to Maven. If let's say mirror doesn't have it, then you as the administrator of this mirror would have defined how to get the dependencies that you do not have stored. So that mirror could be reaching out to vendor repos or it could be reaching out to central repository to resolve that dependency. But understand in this scenario your mirror must have means to resolve that dependency. Now why I'm using the word must is because of this asterisk. Let's see why this matters. So what we are saying is any request that is generated you just send it to the mirror maven and mirror will help you out. Now mirror if it has it will give the dependency otherwise it will fetch it from here. But if you have not configured your mirror to fetch the dependencies from central and vendor repos then your command will fail. Maven will not reach out to Maven central if you are using an asterisk here because what you are essentially telling Maven is mirror has all my answers. You reach out to mirror and then mirror will reach out to the required repos to fetch the dependency. But if you have not configured your mirror like that and you are using asterisk then the dependency resolution will fail. Now I want to explain two more things. There are two things. There is downloading dependencies and then there is uploading artifacts. So for downloading dependencies, we just learned what the architecture may look like. But what about uploading dependencies? Uploading your artifacts. How do you do that? And you might be thinking, why do I want to upload my artifacts? Veron, you want to upload it because other projects could be using your artifact. Maybe the project two that Vun is working on requires the artifact that project A has generated. Again understand that these artifacts what are these? These are JAR files. These are war files. These are ear files. And what are these dependencies? These dependencies are also these JAR files. These ear files. These war files that your project might need. So keep your mind open to understand these things. So the answer to why publish and why publish is when you run MVN deploy your artifact is published onto a remote repository. So why publish? You publish jars so that other applications other services or other teams can use them as dependency in their project and they can reliably pull them from remote repositories. And the concept is same as container images. you build once push the container image to a container registry image registry and anyone who needs can pull and use that image. Similarly, we have the concept of artifacts here. Artifacts are uploaded and anyone who wants to use that artifact can use it. Now, upload could also be of two types. You know, you have two versions release and snapshot. So both of these repositories they are contained in the Nexus or JROG itself. I've shown them outside so that you can bifurcate it easily. So any release version is added here. Any snapshot version is added here. And these both are part of this your Nexus or JROG itself. So now let's move to the left and see how these things are configured. Firstly I want you to pay attention to this part. What I'm saying here is in home directory of the user you have M2 folder and there you have settings.xml. So if I go to my terminal and I go one step back and if I hit ls- a you see there is an M2 folder. If I run ls on M2 directory I don't see a settings.xml. So you will have to create this settings.xml. Now another option is this setting. If I create settings doxml here, that will be specific to this Ubuntu user. But what if I want a global configuration? Firstly, I wouldn't suggest having a global configuration because if you have a global configuration, then all your users can access your global configuration. So for example, right now I have user Ubuntu. But next let's say I create a user Romesh. That user Romesh will also have access to this settings.xml. XML and you might not want that. Hence, what I suggest is only your Maven user or your CI server should have access to settings.xml. So, you create this onto the user that you will use for Maven. So here our user is Ubuntu which is why you see in my diagram I have created this settings.xml XML in the home directory of Ubuntu user and I have defined a mirror here. So what I am saying is I have an asterisk here. Anything any dependency you want to resolve you send it to the mirror and the mirror will have the information on what to do with that. Then if you see my pom.xml in pom.xml I'm defining my deploy targets. I'm saying that if you want to deploy releases, you go to Maven releases. This one nexus.example.com repository Maven releases. If you are deploying snapshot versions, then you go to the same path but at the very last replace with snapshots and you will be storing them here. Now understand that pom.xml will be part of your source control. So it will be pushed onto your you know GitHub, GitLab and your version control systems. Hence you do not want to store credentials into your pom.xml. So the recommendation is you store your credentials in your user in your user's home directory that is supposed to be used for maven and that is exactly what we have done here. If we would have defined this globally then all the users would have access to this file and we do not want that. Hence I recommended have this details have the mirror and the you know credentials for the remote repository for your mirror repository in your settings.xml which is part of the home directory of the user that is used for Maven. I hope this is clear. Now I want to go to the GitHub repository and show you a few more things. So if I go here, this is what we have already discussed. Here you have what is a repository and here you can see and I have given all the recommendations that you can use here. Mirror, declared remote, what is mirror and we have defined that here as well. Deploy versus resolve whatever we have discussed just now I have defined it here as well. Now C this is the picture that I have in the diagrams A B this is also what I have in the diagrams. Now this is C. So if you are not using match all mirrors then you would supply your remotes like this. You have defined the first remote is this and second remote is this and they are checked in this order. Now you see I have mentioned the order here. Why this order matters? So firstly whenever a dependency resolution is taking place your Maven will first look at the local if it is not in the local repository then it will go to mirrors. Now if you have configured a specific mirror now you would configure a specific mirror if you also intend to define your remotes like this. Okay, then it will go to the mirror and then it will go to the declared remotes in order. And if none of those have those dependencies, it will go to central maven central. But the scenario where your mirror has an asterisk. This order is local will go to mirror. If mirror doesn't have an answer, it will not go to maven central automatically. You should configure your mirror in such a way that if mirror you don't have it then the dependency can be fetched from the vendor repose or from the central repository. So I hope that makes sense and you understand this order part two. Now let's go to the browser and see what I want to discuss next. I want to discuss superom and parent. So firstly super pom. Now we have been using archetype to generate our source code and the structure. But who is providing this structure? Who is providing the access to the Maven central? We have not configured our Maven to reach out to Maven center. But it is automatically depending uh downloading dependencies as we have seen. We have not defined any reporting structure or we have not defined any sensible defaults. So all these things are coming from a superpom. Every pom.xml you write implicitly inherits from Maven's superpom. So it can be thought of as a default pom bundled inside Maven. It defines global defaults. For example, all of these. So now you know how important is super pom and why it is used. But what is parent pom? So before defining parent pom I want to give you an example. Let's say you have an application that uses 10 microservices. Now if you have 10 microservices you would have 10 pom.xmls. Now let's say each micros service that your application uses has 50 dependencies. So 50 dependencies implies you have a total of 500 dependencies. And if 50 dependencies per microser, let's say 30 of those dependencies are same for all the microservices. Now understand GAV parameters coordinates are must for all your dependencies. Now does that make sense to define all the versions for you know 50 dependencies that are used across your application in 10 microservices. you will have to have you know each dependency will have a version number not not sane right and even if you have what you can also do is you can have a properties section in your pom.xml XML and that property section can define the version and then your dependencies can refer that that also works but if you have to change any version let's say if you have to change the version of one of the dependencies then you will have to make changes at 10 different places in 10 different poms that's understandable but what if I could centralize every version that is needed into a central file called parent pom that is what parent pom does for you parent pom pom will parent pom can be used as a version repository. So it can hold all the versions that are needed by your dependencies and your child poms all those 10 microservices can refer to this parent pom to check the versioning information for any of the dependencies. Now how that makes your life easier? If you have to change a version, you just change it in the parent palm and the child palms can automatically refer that parent pom. So let's see how that works. And parent pom is just another pom you own that child projects inherit from. In production, it is used to centralize dependency management like we just saw. Shared versions, bombs, pin plug-in management, set common repositories, properties, enforce organizationwide rules, Maven enforcers. These are advanced concepts. I'm not discussing them. But as you progress with your Maven learnings, I will let you explore these as you move with enterprisegrade projects. Now we have an understanding of parent pom and super pom. I want to show you the structure of parent pom. So here is the parent pom cloud with varos parent. So if I go to my child pom I am saying that spring boot starter all your versions come from parents spring boot bomb. So as we have discussed before bomb here is the type bomb and we are fetching this and this will have the details about all the versions that are associated with spring boot. I hope this makes sense to you. Now I want to go on to demo two build with Maven in Jenkins and run as a docker container. So whatever we have been running right now we have been running manually. Now what I want to do is I want to deploy the same application. I want to create a docker file and then I want to containerize it and then I want to run that container in my docker host. So let's see how we are going to do it. Firstly, I have a Jenkins container running in my Docker host. And that Jenkins container I created as part of my Jenkins basics to production course. You can create a Jenkins container by following the steps that I have defined here. If you are interested in day three, I believe we discussed the complete installation of Jenkins. And in day five, we configured DOD that is Docker outside of Docker. And if you want to learn more about it, you can watch day five and day three of my Jenkins series. So I will be using a container that I already have created. So if I go to my terminal, I'll go here and I will just close this. I will just shut this instance down. P sudo init. And then I will come here. So whatever we are doing in this demo will be done in the Jenkins container itself. We do not need anything else. So I will run docker ps. You see there is a Jenkins container. I will write docker exec and hyphen u root. I will tell you what I'm doing. I will write Jenkins and then I will run bash. Firstly I [snorts] want you to know that I am going to install Maven in my Jenkins. Now why do I need to install Maven? Understand Jenkins can only run Maven specific commands if I have Maven installed in my Jenkins server. I could have installed Maven in my Jenkins container or I could also use a Maven plug-in in Jenkins but plug-in I don't want to use right now. I will be using Maven directly installed in my Jenkins container so that my Jenkins container can run Maven specific command. So I will run apt update first and once this is done I will run apt install maven y. I will run maven version. This will tell me that I am using version 3.8.7 of maven. Remember when we installed the binary we had 3.9.11. This one has a previous version because the repositories that are added for my apt in this container may not have the latest version right now. And as we progress apt update will have the latest available version. But these are always slower. That is why I said if you want the latest and greatest and if you want complete control, you should install it using a binary. Now that we have Maven installed, let's exit our container. And if I run docker ps, I see that Jenkins container is still running. So let's go to our browser and see what I want to do next. So Maven version, these commands we have done as part of step one. As part of step two, we have to create a freestyle job called Maven job. So let's do it. So I'll access my container on local host port 8080. And then I will click on new item. Here I will name it Maven job and this is a freestyle job. I will click okay and I'll scroll down. Add build step. I want to execute shell. That's what I'm saying. And what is that you want to execute warun? So let's see that in our notes. So if I come here this is exactly what I'm going to do. I am telling step by step what Jenkins you should be doing. Understand Jenkins is our automation server. Previously whatever commands we were running we were typing those commands onto our EC2 instance that had Maven installed. But now we are integrating Maven with our CI. So whatever steps we want to do, we will tell our CI server and because our CI server has Maven installed, it will run all those steps successfully. So in the first step, we are doing what we did back in our virtual machine. We are just generating a sample code. Then we'll be cding into my app and then we'll be running clean package. So first we'll be cleaning and then we'll be creating a jar file. So that is what the output will be. Hyphen B is for batch mode non-interactive good for CI logs. Then build the jar clean work space. Skip tests for speed. So right now we want it to be fast which is why we are skipping tests. And this I have kept deliberately here so that you know you can use certain flags with the phases with the maven phases to skip certain things and that is how you skip tests and there are various things you can skip and I will let you explore those things yourself. Then I am creating a docker file. I am using JRE now. I'm not using JDK. I'm using JRE because I just need the runtime. I do not need Java compiler here because the compilation part will be done by Maven in this step itself. And then it will generate this artifact which I am copying to my /app/app.jar as app.tjar. So in this step I'm saying use this image working directory is / app. Whatever next commands you run will be applicable on this command. Then I'm saying copy in from the target folder. Remember when we were running mvn package and then we ran ls there was a target folder created and that target folder had our artifact here as well. The same thing it is just we are running these things in our Jenkins container in an automated fashion. Then lastly we are running the command that we ran before java class path we are specifying forward/appjar because here is our artifact and then we are saying com.mmy company.app.app and this is what we did before as well. Then we are creating a docker ignore file. You can see what we are doing here. And then in the fourth step we are creating a container image. We are associating a tag called local because we are not pushing this container image anywhere. We are just building this locally. At the very last we are echoing container output below docker run. We are running a container from that image. So essentially what we are saying is you run the container and as soon as it runs you remove it once it has done its job. Understand that our container is just supposed to say hello world and containers do not run 24 + 7. They just stop when they have done what they are supposed to do. Our container here is just supposed to say hello world and once it has said that it will stop and we are saying don't stop it you just remove it which is why we have added hyphen rm flag. Now when you are dealing with web applications you want to run them 24 + 7 and which is why you have engineext process or any other web process which continues to run which is why those containers run 24 + 7. So here is what we are going to do. So I will scroll up. I'll copy this. I'll go to my job and I will paste this here. I will save this and then I will say build now. And this will start building this. So if I go here I can go to console output and this will show me what are the steps being performed and these are pretty much the same which were performed when we were working with our virtual machine. So the point that is interesting is this is where the docker image was created and if you see here if I scroll down naming the docker image this one was done done and here docker run - rm -ame is this and this is the image that you should be using and here you see the output hello world. Now instead of container being in stopped state we have removed it. So if I go to my terminal and I run docker ps here you only see this even if I add a you only say see this Jenkins container. But what I can now run is I can run docker images and this will show me all the images in my machine. And here you see cloud with vjo java hello local and this was created a minute ago by whatever we have defined in our Jenkins job. So I hope all these things are making sense to you. That is a wrap for this lecture. In this lecture we took Maven from basics to production. You saw the difference between compiled and interpreted languages. Why we need build tools and what Maven actually does under the hood. We created a project, walked through pom.xml, understood life cycles, phases, plugins, goals, and looked at repositories, super pom, parent pom, and finally wired everything into Jenkins plus Docker. If this helped you see Maven the way a DevOps engineer should, do like the video, drop your questions in the comments. The GitHub repo and commands are linked in the description so you can replay the demos on your own machine. I will see you in the next one. Thank you. Hi, I am Varun Jooshi and I welcome you to cloud with VJosh where we discuss cloud DevOps and everything in between. In this lecture, we are going to look at dev secc ops from a DevOps engineers lens and understand how security actually fits inside a real CI pipeline. We will start with why and what of DevSec Ops then break down key terms you hear everywhere. SAS, dash, code quality, SCA and Sbomb. From there we will jump into what Sonar cube really is, its role in modern pipelines and walk through an end toend production grade dev sec ops flow. Then we will get hands-on. We will install Sonar Cube on an EC2 instance. Walk through the Sonar Cube console and architecture. Then provision a separate EC2 for Jenkins and install Maven and Docker. Finally, we will put everything together and run a full dev sec ops demo with Sonar Cube, Maven and Jenkins. So you see exactly how code quality, code security checks and CI triggers in real life. The GitHub repo linked in the description has detailed explanations and stepbystep demos for everything we cover. Replay the labs on your own setup. And if it helped, please do start the repository. With that being said, let's get started. Now before I start this lecture, I first want to visit the GitHub repository for this lecture so that I can tell you what are the prerequisites for this lecture. So I will go here. I will zoom in a little YouTube standalone lectures and from here I'll click on lectures and then I will go to sonar cube that is lecture for today. Now if I scroll down, I'll use the clickable table of contents to go to the prerequisites. And here you see there are three prerequisites. The first one is modern SDLC. Now we have discussed this deeply in a different series, a series where I am covering Jenkins and CI/CD in greater depth. So we covered modern SDLC and also CICD. I would request you to watch both of these lectures because this will give you the foundations and once your foundations are clear whatever we are discussing in this lecture and understand that dev sec ops sonar cube all of these are extensions of DevOps and until and unless you understand the life cycle of DevOps you will not be able to make sense of this lecture. So in this lecture we cover modern SDLC and if I give you a glimpse of it this this is it and here you see we have covered SDLC then we have covered different programming languages and then we have also covered how are these different when deployed onto different environments. So how they behave when you deploy them onto containerized versus non-containerized environments. So this lecture is of utmost importance and then the next lecture is again the CI/CD lecture. Here I explained different terms. We started from the very basics that how git works a very highlevel view of that and then we moved on to different continuous practices that you would see branching strategies. Then we looked at different production workflows which you will see this is git flow based. Then we discussed what's the promotion strategy. Then we moved on to trunkbased CI/CD pipelines. So watch these two lectures. And then the third prerequisite for this lecture is you must understand Maven. Now I have a detailed tutorial on Maven in this channel itself. The links for that is here. Why this lecture is needed? In the demo section of today's lecture, what we will do is we will be running a fullfledged production grade pipeline demo wherein we will be integrating Maven with our pipeline and Maven has plugins that we will be using and those plugins are the ones that help us integrate Maven with Sonar Cube. Hence, if you do not understand Maven, which is a popular build tool used for Java language, then this lecture will not make sense. So, watch all these three lectures and if you have already done so, then let's get started with this lecture. So the first thing that I want to discuss is why dev secc ops late checks cause release failures and rework. Now let's say you have normal CI/CD pipelines. You do not have security integrated with your pipelines yet. Late checks cause release failures and rework. Now imagine if you are using a security tool and that security tool is running when you are deploying the application or right before when the application is deployed and it finds certain vulnerabilities. Will it make sense to again start from the very scratch and remove those vulnerabilities? It does not make sense. That is why whenever we are discussing about CI/CD pipelines and especially security in CI/CD pipelines, we always say shift left. And what does shift left imply? If this is the flow and we are saying shift left, what that means is if you are performing security analysis in deployment stage, then move it to testing. If you are performing in testing then you should be performing them in build too. If the security is part of build then it should be part of development too and so on. Hence what we are saying is whenever we talk about security we should be taking care of security in all the phases of SDLC of the DevOps life cycle. Wun but how do I take care of security in the requirement gathering phase there is no tool that you would use in the requirement gathering phase but what my intent is whenever I'm gathering requirements for my application I should be always thinking about security if my application teams come to me and tell me that varun we would like to have our application deployed onto containers then my mind should automatically start working that how do I perform security testing not just for my container images but also for my running container. So my mind should be working in that direction from the phase of requirement gathering itself and then in each phase security should be given utmost importance. Previously it was not done like that. Security was part of late checks. But for the past 5 10 years industry has come to realize that without security their pipelines or their workloads are futile. Hence now everyone is taking care of security. They are adhering to shift left approach. Next is manual reviews are slow, inconsistent and unoduditable. And that is obvious. If you are not performing your security scans as part of your CI/CD pipelines, then you are essentially doing that manually. And when you do something manually, what happens is the integration doesn't work as smoothly. Let's say you are performing static scans of your container images. But what I want is my pipeline should not move to the next step until and unless that scan is successful. But how do my pipeline know about that? My pipeline will know only about that when I have integrated that security tooling with my pipelines or I have an automated way via which I can tell my pipeline that you must fail if that security scan fails because on its own a security tool will just tell you that this does not work or this has vulnerabilities but you as devops Ops engineer must ensure that if something is failing or if something is detecting vulnerabilities then your pipeline should also fail or there must be something logged into your pipeline that this something has vulnerabilities. Now you take care how [snorts] you are configured to take care of it and who will configure it? It is us DevOps engineers who would be configuring it. Last one is hidden risks accumulate in code and dependencies. I want you to understand that your application is not just the application code. Your application could be depending on several other things. Maybe it depends on Google for authentication. Maybe it is dependent on third-party libraries for some functionality. If I am designing a banking application and my banking application requires a calculator, I will not ask my developers to write code on how to do calculations. I will use an existing third-party library for that. And when you start using libraries for your entire application stack and these they do not have a specified count. For example, if I have a banking application, I might be using hundreds of libraries and it is impossible for me to keep track of all those 100 libraries and as soon as your application progresses, there are new versions of libraries also available. So, you must be taking care of all these things. So if you do not have security integrated within your CI/CD pipelines, then these dependencies possess hidden risks. Now that we have this basic understanding, let's understand what is dev Sec. So if you are already a DevOps engineer and you have some sort of security in your CI/CD pipelines then your pipelines already adhere to the principles of dev sec ops. Now I'm not saying your pipeline is as mature as it should be. What I'm saying is if you have introduced some component of security then you have already integrated security with your CI/CD pipelines or with your DevOps flows. Another thing I want you to clearly understand that whenever I'm talking about dev sec ops, DevOps, SDLC, these are not tools, okay? These are not products that you can buy. These are methodologies. These are practices that you must apply when you are designing, building, testing, deploying and even operating an application. So there are of course different tools that are available at your disposal to achieve the dev secc ops culture or to achieve the devops culture but in itself these are just methodologies. Now which tools you should be using for dev sec ops which tools you should be using for devops it depends on your application requirements. So what DevOps SDLC they do is they provide you a cultural framework that this is the way things should be done and as long as you adhere to these principles you are free to bring in any tools that you want. So in single line dev secops is integrating security tools with your DevOps practices. As simple as that. It is a software engineering approach that integrates security practices into every phase of SDLC and the DevOps life cycle. And you can see SDLC defines the what and why for your application and the DevOps life cycle focuses on how to deliver reliably. Now DevOps focuses on how to deliver reliably. What is the focus of DevSec Ops? Dev Sec Ops focuses on how to deliver it reliably and securely. Because when you integrate security with your DevOps life cycle, you are essentially stepping into the dev sec ops realm of things. Security integrated across plan code, build and deploy. That is what we discussed. Automated checks in CI/CD on every push or PR. So whenever you are creating a PR let's say to merge your feature with your main then there are automated security checks that are taking place. And what are these security checks? Where do they plug in in a production flow? We will look into all of these things in a little while. This gives us clear ownership across developers security and operations. Now you could be working in a team where is a different cloud team, there's a different DevOps team, there's a different dev sec ops team and then there's a different security team in general. So if you have integrated dev sec ops tools into your pipelines appropriately, then you will have clear ownership. For example, if let's say your container scan is failing, I for sure know that this must be looked by my dev sec ops team. So this provides clear ownership. Now that we have this understanding, I want to discuss key dev sec ops terms and concepts that you will hear in your day-to-day communication. I want to start with SAS. SAS is static application security testing. Now, as soon as I hear static, I know that these are the security testings that are being performed onto a sitting code and that sitting code could be in my IDE or that code could be inside a binary or an executable. So static scan of source byte code or binaries for vulnerabilities that is what SAS will do. Now the topic of this lecture is sonar cube. So if I go to visual studio code here and I go to extensions here and then I search for sonar cube you would see that there is an extension available that will perform SAS for me. And if you can see it mentions the same in detail here. And there are multiple others tools. If I write check marks, check marks will also have a tool that will do SAS for me. Beat vulnerabilities with more secure code. There is another extension. Check mark SAS is a check marks ID extension that enables scanning and retrieving results and so on. So there are tools that can perform SAS for you. Again when I talk about SAS, DAST, Esbomb, SCA, code quality checks, these are again methodologies or practices. These are not tools. There are tools that can perform SAS. There are tools that will help you with dash. There are tools which will help you with these, these and these. So for now the clear understanding I want you to have is these are just umbrella terms. There are different tools that work under this umbrella to achieve these. Now let's talk about SAS. We already know it is static scanning. It will find SQL injections, hard-coded secrets, insecure APIs and so on. SQL injections are maybe your application has an input stream and in that input stream the malicious user or the malicious machine tried to modify your back end and your back end is your database which is SQL then where it runs early in CI and integrates with ids. We have already seen that there are different extensions that are available for ids and we are also saying that they run early in CI. Now imagine when you are building let's say a Java application that Java application will result in an artifact and let's say that artifact is intar format. So you would want something to scan that artifact for any vulnerabilities. That is where your SAS tool fit. They scan your code, your binaries for vulnerabilities. Now, the first two tools in all the sections are the most popular ones. So, you would often see sonar cube and check marks in production environments. If your application is containerized, then you could also see sneak and trivi as part of your SAS tools. Then let's talk about dash. DAST is dynamic application security testing. Now dynamic means it is performed on applications that are running and these tests are typically performed using HTTP. So you will have an end point on which your application is exposed and that is the entry point for these tests. Tests running application by simulating real attackers. So it is looking to exploit your application to see what are the loopholes, what are the parts that can be exploited by malicious actors, targets, runtime issues such as XSS, injection, authentication, bypasses. Where will you run DAST? You will run dash predominantly in your staging or pre-pro environments because you do not want a full-fledged dash to be running alongside your production application. That does not make sense because production application has your real users accessing your application. You don't want to overburden your application by performing a full-fledged dash in production. So what you would typically see is dash is performed majorly extensively I would say in prepro or staging and when I talk about prod environments you will still see a passive or minimal dash running there are different tools first is oasp zap burp suite these two are the most famous ones and if you have containerized workloads you would also see sneak dash is being used for dash fast and there is sneak that is also used for fast. So understanding the difference fast is for your static code dash is for your running code. Then let's talk about code quality checks. Now the first thing that I want want to mention here is code quality talks about the quality of code. It is not talking directly about anything security. It is talking about the quality of code. How is your code written? So if I I have I want to explain this to you in general terms. If I want to go from point A to B and I can go from point A to B straight. But there is another way to reach point B via C D E. If I take that longer route, does that make sense? No. Right? If I want to go from A to B, I'll go directly. If I am taking the longer route that decides the quality I am using. So similarly if I talk about software if you have multiple duplicates in your code. If you are doing the same things and calling different functions for that then all these things deteriorate the quality of your code. Another thing is maybe your code has defined multiple variables which are not being used anywhere. So that says the quality of that code is not good. If something can be achieved in 10 lines of code and you are using 50 lines of code then that is a code quality issue. So in summary code quality checks maintainability, complexity, duplication, naming and dead code. Now second point is code quality checks helps reduce technical debt and prevent future regressions. Now technical debt is shortcuts in code or design which are taken to move fast now and that makes the code harder [clears throat] and slower to change later. So these are technical debts. Then you have code quality checks helps prevent future regressions. Now what is regression? Regression is to return to a previous and less advanced state. So how code [snorts] quality helps here is it helps in keeping code clear, tested and well reviewed so old bugs do not reappear. Now again I want you to know that code quality just deals with the quality of your code. It does not directly pertains to security. It pertains to how well your code is written. And understand that it is important that your code quality is good because you can have certain rules in your sonar cube or code quality tools which will prevent lowquality code from going into production. So where you would perform code quality IDE CI or linting analysis and quality gates. Now what is linting? linting are static checks which will flag style formatting or simple correctness issues before code runs. Now where you would perform code quality checks, you would perform them in your IDEs and also in your pipelines and we'll see exactly at which stage of pipelines do these methodologies fit into dependency scanning or SCA. Now SCA is software component analysis. Now with the expanded form you can imagine that it will tell you all the things your software is comprised of. So for example if I have a banking application and my banking application has 100 libraries. I'm using 100 libraries in that banking application. What will SCA do is it will tell me what all libraries I am using and then it will tell me are there any vulnerabilities in my library. So it scans third-party libraries for known vulnerabilities and licensing. Now since it is a software component analysis, it will also give me the licenses that are being used. Now I want you to know that I could be using 100 libraries and maybe 50 of those libraries are open- source but rest of them they have a price associated with them. So dependency scanning tools will tell you that. Understand they are called dependency scanning tools for a reason because they work on the vulnerabilities in your dependencies. Understand that SAS was used for your static code. Dependency scanning is used to find out the vulnerabilities in your thirdparty libraries that your application is using. And this was used to find vulnerabilities in your code. Matches dependency versions against CVE and license databases. Now what is CVE? CVE is common vulnerabilities and exposure. And there is a database central database for these things. What dependency scanning tools will do is it will compare the application versions that you are using with this CVE database to tell you that these these these are the libraries that have vulnerabilities and you as application developer or DevOps engineer will have to fix those vulnerabilities. And next one is where you would run this during build and CI continuous dependency scanning runs. There are tools available for this. Sneak and trivia are the most popular ones. Now at this stage I want to tell you that SBOM is an extension of SCA. Okay. But fundamentally their primary purpose is different. So when I talk about SCA or dependency scanning, the primary purpose for them is to list out the vulnerabilities that are there in your third party libraries. The primary purpose of SBOM is to give you a machine readable inventory listing components, versions, and licenses. Understand? Dependency scanning was actually performing a scan and telling you about vulnerabilities in your third party libraries. Whereas SBOM is just giving you an inventory. It is just telling you that these are the 100 libraries that you are using and this is the version of it and this is the licensing for this and these are rest of the components that your application is using. So it is just fetching the inventory. So for example, if I talk about AWS cloud, I could have a script that fetches me all the EC2 instances that are running. But I could also have a script that fetches the instances and also deletes the instances that are in powered off state. So these two things are different. Similarly, if I talk about dependency scanning, it is actually finding the vulnerabilities for you in your third party libraries whereas Esbomb is just giving you the version of those libraries in short and then you see licensing is there in both of this. Now this is an overlap of course but I said primary function of SCA is scanning third party libraries and primary function of SBOM is to give you machine readable inventory of the third party libraries version that you are using and the expanded form for SBOM is software bill of material generate sbombs in CI and attach to artifacts enable postrelease rescans when new CVS are published. Now understand if you didn't have ESBOM then you will have to run the scan on the running application or onto the artifact that was generated. For example, if you are working with a Java application, then when there was new releases in the CVE, when the CVE database was updated, you would have to compare your application with the new database to check out if there are vulnerabilities in your application, right? You will have to compare that with your jar or maybe if you are if you have a running application, then you will have to check there. But if you have sbomb and sbomb is already there in your let's say artifact registry then you can directly compare that CVE database with your sbomb and get to know whether there are any vulnerabilities with your running application or not. That is how sbomb helps. But again I want you to know that if your application at runtime is installing certain softwares or using certain libraries then sbomb will not detect them. SBOM will only detect those things that were generated at the time when artifact was generated because sbombs are typically generated when you are creating an artifact. For example, if if you are creating a container image, you can associate an SBOM with it. Or if you are creating a dot jar, you can associate an SBOM with it where generated at buildtime like I just mentioned and attached to artifact or images. Next is formats. Now, SPDX, Cyclone DX tools that you use are sift and cyclone DX plug-in. Now these are the formats in which sbombs are generated and these are the tools that generate these sbombs. Now in summary SAS is static code checks, IDE plus CI, SCA is dependency scanning, SCS software component analysis. Then you have SBOM inventory of component software bill of material. DAT is dynamic application security testing. It is performed during your runtime. It provides you with runtime security. Code quality is equal to maintainability checks ID plus CI. Now I want to emphasize on one thing again that code quality is not directly security related. It just tells you how is the quality of code. So keep that in mind and I will tell you why this distinction is important as we progress with this lecture. Now I want to discuss Sonar Cube. What is Sonar Cube? It is a continuous inspection platform that automatically analyzes source code for bugs, security vulnerabilities, code quality issues and test coverage, enforcing consistent standards across CI/CD pipelines. So essentially whatever key terms that we discussed before we mentioned SAS we mentioned code quality we did not mention code coverage but we did mention both of these. So if I move to these concepts, SAS and code quality is something that Sonar cube will help you with and how it helps. We will see it practically as well. But let's first understand that what is code coverage. So at a very high level we know that Sonar Cube will help us with three main things. Code coverage, fast and code quality. So let's quickly understand what is code coverage. Now let's say you have written 100 lines of code. And when you are testing you are only testing 80% of it. Then your code coverage is 80%. So as simple as that code coverage is how much [snorts] of your code is tested to work properly. Again mark my words. I said how much of your code is tested to work properly. I did not mention anything about security. So if your code is supposed to perform oneplus 1, if it can perform oneplus 1 properly and you have tests defined to test that then your code coverage is 100%. But oneplus 1 testing is not security. right here as well. If you are performing code coverage, it will tell me how much of your code is tested to work properly. It is not telling me that your 80% code is fine when it comes to security. It is not saying that. Next is CI runs tests coverage reporters generate reports cube imports. Now this is a critical distinction. Now let's understand this first. So narcube I said has three main functionalities. This functionality is directly related to security. Okay, this is security static application security testing. But when I talk about code quality or code coverage now these are not direct security related things. Sonar cube can perform code quality because it is scanning your code. When it comes to code coverage, tonar cube does not perform the code coverage itself, what it does is it depends on other tools to provide that report to it. And once that other tool has provided that report to sonar cube, then sonar cube can decide whether this code adheres to your code coverage rules or not. For example, if I have set my code coverage to 80%. And there is an external tool that is sharing the code coverage report with Sonar Cube, then Sonar Cube can judge whether your code is adhering to the standard that we have set or not. And based on that it can also fail the pipeline but in itself sonar cube cannot generate coverage report. So that is what we are saying here. CI runs tests. Coverage reporters generate reports. Sonar cube imports. Next is enforce minimum coverage on new code via quality gates. That is what I just discussed. So when you are working with sonar cube, what you can do is you can create something called quality gates. Now quality gate is something that stands as a guard. So if your code coverage is let's say not 80% then that gate will not open and if that gate will not open then your code cannot move to the next step and next step could be the staging stage. So it cannot proceed further and you can have your pipelines fail if the sonar cube quality gate condition is not met and we will see this in the demo section. Common tools are Jakoko. Jakokco the expanded form is Java code coverage. So you will use that for Java. There is an bull that you can use for JavaScript. There is coverage.py that you can use for Python. Now I want to discuss SAS from a different lens. Now why different lens? Because here I want to define certain terms for you and these terms are simple and once I give you a oneliner you will have this in your memory for a very long time. So let's see what it is. First is static code analysis to find vulnerabilities, security hotspots and security sensitive bugs before production. Firstly, what is a vulnerability? Now vulnerability is a security flaw that an attacker can exploit. As simple as that. Now your software can have multiple vulnerabilities and then those vulnerabilities can have different categories. But if I have to define it in one line then vulnerability is a security flaw that can be exploited. What is a security hotspot? Security hotspot is something insecure that is there in your code. Now that something insecure is not impacting the functionality of the application but it is a security risk. For example, if I have secrets in my code, that is not impacting the functionality of my application. My application would still work fine, but it is a security hotspot. It is a security flaw. So, in summary, security hotspot is a code that might be risky and needs human review. Now, why I say might be risky? Now there is a chance that you are internally using a private CA to sign your certificates and that is how your application is meant to be. In that case that security hotspot can be ignored. Next is security sensitive bugs. Now when I talk about bugs, bugs have typically the highest priority to be fixed. Now if you have a bug, bug implies something that causes application to not behave as expected. So fixing bugs have the highest priority. Here we are saying SAS can also detect security sensitive bugs before production. Next is categorizes findings by type and severity. So sonar cube can do all these things that we discussed here and then it can also categorize finding by types and severity for prioritization runs in PR's CI to shift security left and this is what we will see in the demo. Now let's discuss code quality. Code quality at a very high level we know tells us whether the code is well written or not. Now first is detects code smells and duplication. Now what is code smell? Code smell is a poorly written code that makes changes harder. Duplication as we all know duplication is you are repeating the same part again and again. You could also create a function for that. So that is duplication. So sonar cube will detect these things primarily about maintainability, readability and technical debt. So sonar cube can help with code quality because sonar cube will tell you how good is your code when it comes to maintainability and readability. Last one is enforcable via quality gates to prevent regressions. Now all of these things that Sonar Cube is somehow administering, Sonar Cube has the ability to have a gate that if these things are not met, then your quality gate will fail or pass. For example, let's say if your code coverage is not 80%, then I won't open the gate. Hence, the quality gate that we mentioned here briefly will fail. I know I have given you a theory bombardment. You have had different terms thrown at you and I understand it could be overwhelming for few of you. So that's why what I now want to do is I want to describe an end toend production dev sec ops life cycle so that you know what fits where and when you know what fits where you can of course at least participate in any dev sec ops discussion with ease and I assure you if you understand this flow you can have security related discussions with your dev seccops teams. in ease and this will pave the way for any of you who aspire to be a dev sec ops engineer. Now let me zoom this properly so that whatever I want to convey is in the same screen. Now the first line is end to end production dev seccops flow Java plus Maven. So in this flow we are dealing with Java language along with Maven which will be used as the build tool for Java. Now the pipeline that you see here is platform agnostic. So GitLab, Jenkins or GitHub actions or whatever you are using this flow is platform agnostic. This is essentially the methodology the thought process that is behind DevSec. The key point in dev sec ops as we understand now is security. How do we integrate security at each stage? So that is what we will be doing in this workflow. The first point is check out from private repository. Now that is what will happen always. Your production code will be stored in a private repository and from there you will be checking that code out. Now if I talk about a containerized application, your repository will have source code that is obvious. If I talk about Java, it will be your src and then pom.xml and it will also have the docker file. Docker file will be used to create a container image and then it will be pushed onto a central image registry and then containers will be created using that image. Second point is triggered by push or pull request. Now you will never in my opinion see any production pipeline getting triggered on a push. Typically your main branches or your you know production branches are protected. So you can only raise a pull request. For example, you are working on a feature branch and once you have done your work, what you would do is you have performed your pushes, what you would do is you would create a pull request and as soon as your pull request is created, your pipeline will trigger. The second step is build plus test. Now before I start this discussion, I want to talk about testing in general. So if I talk about testing, there are two parts to testing. There is functional testing and then there is security testing. And often people will just say testing and you based on the communication will have to understand whether that person is talking about functional testing or security testing. And as you spend time in this industry, you will understand these things. No biggie. But I wanted to give this distinction to you right here so that it eases the terminologies that are thrown at you. Okay. So testing there is functional testing. Now functional testing implies whether my application is working or not working as expected. Okay. It does not deal with security at all. Second is security testing. Now security testing is something that deals with security. So you will have methodologies like SAS, DAS, SCA, SBOM here and security testing also deals with supply chain. So if I talk about SBOM, what is SBOM? It will tell you what your software is comprised of the versions. SCA will tell you vulnerabilities that your libraries will have. So they also deal with supply chain. So two things functional testing and security testing. So when I talk about code coverage, code coverage is part of functional testing. It is not doing anything security. So I hope this distinction is clear. Now that you understand this, let's move to the right of the screen. So I'll make this here. And then second point is build plus test CI phase. Now first thing is see if I talk about Java there are first testing frameworks that must be defined by your developers in the code. First is those testing frameworks and JUnit and testNG that you see here are those testing frameworks that must be there in the code and then what all are the tests that are to be performed using that framework must also be defined by your developers only then these testing tools will work. So for example, if I have a Maven plug-in and that Maven plug-in is let's say called Shorefire, that shorefire plug-in will only be able to perform unit tests if my developers have defined a testing framework like JUnit and under that they have defined what tests are to be performed. So it is important for you to understand this. Now there are two types of testing that I have mentioned here unit and integration and I think I should have explained it in this screen itself. Functional testing checks overall whether the function your application is working or not. And then there are some bifurcations. Unit testing will check certain classes in your program certain sections in your program whether they are working or not. So unit testing is you check different chunks of of your application separately. Integration testing as the name implies integrate things. So it will check whether the process as a whole is working properly or not. Maybe you want to check if I click on account statement whether it is taking me directly into my account summary page or something of that sort. whether the components in your application are integrated properly or not. Smoke testing is simple testing. It will just tell you whether the application is accessible or not. So if you have used tools like curl and postman, they are used for smoke testing. So this is this. Now when I talk about this second stage, we talked about unit testing and integration testing. So if I talk about Maven, Maven has different plugins that can be leveraged to perform unit testing and integration testing. Surefire is the plug-in that is used to perform unit testing, but it can only perform unit testing if you have defined a framework in your code along with the tests that are to be performed. So fail safe is a Maven plug-in that is used to perform integration testing. But integration testing again can only be performed if you are using a testing framework like JUnit. Along with that you have also defined the tests that are need to be performed. So the first section of this is defined by your developers in the code. The second section the plug-in that you have to use the plug-in that are called is typically with your DevOps engineers and we have discussed this in our Maven lecture but I will also touch this in the second point. Now second point is once these things are defined second is you would typically run MVN verify. Now if I take you to my browser and if I go here, we know that MVN verify is a part of the default life cycle in Maven. Now if you have not seen Maven lecture, pause this right now and watch that otherwise this will not make sense to you. So if I am running the verify phase then all the phases that are before verify 23 phases are there in the default life cycle. All of these will run. This is important to understand. So when you are running verify, you see there integration test will also run. If I scroll up, test compile will also run. Test will also run. So verify will at the very last will also package your application and once your application is packaged, it can also run integration test. But again I want you to understand one thing extremely clearly that unit tests can be performed in an application that is not running. But when I talk about integration tests, integration tests cannot be performed in a stopped application. And why is that? So unit testing is testing a particular class or a particular section of your code. But when it comes to integration, it is checking your running application. For integration testing, you want the application to be running. So that's the crux of it. So when you run MVN verify, all these things are performed and you also have a package like you see here. JAR is with you. So let's go back to the diagram again. And now Jakokco records code coverage for Sonar Cube. Now there are plugins that have performed these tests. Now there is Jakokco plug-in that will collect this report and this report will then be delivered to Sonar Cube. That is how Sonar Cube can perform code coverage for you. Now again I want to clarify one thing like I mentioned integration testing would warrant your application to be in running state. But Vun, we have not deployed your application anywhere. How is it possible to perform integration testing? So if you have been part of our Maven lecture, I think we have discussed that there as well. There is an ephemeral environment that is created. In that ephemeral environment, the application is deployed and then integration testing is performed. Now let's talk about the third part that is run SCA and generate Sbomb. And as you can see we are using tree to run SCA and to generate sbomb we are using sift again you see fail is equal to stop pass is equal to continue. If this fails we can fail the pipeline. Again whenever we are discussing this fail or pass okay in these three steps primarily I want you to clearly know that the tool will just give you the report whether to fail the pipeline or not is your responsibility. Now of course there are ways via which I can integrate sonar cube with my pipeline so that if sonar cube quality gate is failing my pipeline also fails but that is something that I will configure. So I want you to know that if you want your pipeline to fail upon any of these failures then you must be configuring your pipeline to fail when these tools are not giving you expected results. Now what are expected results? For example, maybe for your application critical vulnerabilities should not be there. But if high severity vulnerabilities are there, you can still pass the pipeline. But for a different banking application, they don't want a single vulnerability. So for them even a low vulnerability is a vulnerability and it should fail the pipeline. So you should understand these things. If SCA is scanning a library and that library does not have a valid license in that case as well you fail the pipeline but you fail the pipeline with logs. You tell them that you are using ABC library and ABC library does not have a valid license. So understand you can fail the pipeline based on the inputs received from the tools that you have configured at each stage. This stage this stage and this stage another thing I want to highlight is here I am just concentrating on security. If your Maven or test integration if your pom.xml is not written clearly then also this could fail. If you are not running proper commands for containerizing your application then also this could fail but I am discussing about security related failures right now nothing else here run SCA you have sneak dependency check during build generate sbomb and persist with artifact persist with artifact is the key point here I want you to clearly understand that at this stage itself we already have the artifact Fact we have run MVN verify and if I go back to my browser you know MVN verify will also run MVN package and if we have run MVN package we already have the dot jar file with us. So the artifact is already available and if we have the artifact then of course we can have sbomb with us and the next is sonar cube analysis. And you see here this is the icon for sonar cube. Here we have a quality gate. We are saying if sonar cube analysis if we if the quality gate fails then you stop the pipeline. If it passes then you continue. Now the first point is imports Jakoco coverage reports. Remember here we generated our Jakokco reports and here Sonar cube is taking an input. Now only when this coverage report is shared Sonar cube can fail or pass the pipeline based on coverage. If you do not have Jako core or any other means to provide Sonar cube with this code coverage report then Sonar Cube could care less in its own. it cannot perform these code coverage analysis. Second is sonar cube will perform SAS and code quality checks. Next is enforces quality gates before packaging and we have seen this here is the part where we are packaging our application. Now I want you to concentrate here. Okay, build I am saying docker image mvn jar jar. I should have run mvn package here, right? But I'm running running mvn jar jar. Why is it? And do I even have to run any maven command here? So let's first understand this. So if I run mvn package then I will have an artifact with me. Right? But why to run mvn package? Because if I run mvn package all these phases will run again. I don't want that. I only want a jar file. So what I can do is if you have been through the Maven lecture the phase for package is I can just run MVN jar jar. This will just invoke the jar plug-in with the jar goal and this will just generate the jar file for me and that is what I want. Right? Then I should run mvn jar jar. But another thing that comes to my mind is why do I run mvn jar jar? I already have the artifact because I ran MVN verify here. Now until and unless any of these stages are changing my artifact in some way, I don't have to run anything here again related to Maven, [clears throat] I can just use the artifact that was generated here. And this brings me to an extremely critical point. The first responsibility of DevOps engineers or DevSec Ops engineers, the lines are blurred now. Everyone is expected to know security. So I'll continue saying DevOps. The point is the primary goal of DevOps engineer is to reduce the time it takes for the CI/CD pipeline to run while ensuring whatever things that are needed are performed. So if you do not have to run MVN jar jar and if it decreases the runtime of your pipeline by even 1 second then remove it. Don't keep things that will delay your pipelines unnecessarily. So here I will select this MVN jar jar. Come here and I will strike this out. So we are not running MVN jar jar anymore and we have understood the reason why we are not running and then we are building an image. We are tagging the image for registry upload. In the next stage that is push image, we are pushing the image onto a central image registry and I have taken ECR here that is elastic container registry from AWS and understand along with container image as well. You can upload sbomb. I do not have a demo for this but I will let you explore how do you push both image and sbomb and any OCI compliant image registry like docker hub elastic container registry or other native registries provided by different cloud providers they would support the upload of sbomb along with your container image. So feel free to explore this point further. Next point is deploy to staging. Now understand we are first deploying to staging and what you should now think is oh my application is now running so there must be dashed performed. So we have discussed code quality and SAS is performed here SCA and SBOM is performed here and now we want to perform DS. So automated application deployment that's fine. Prepro tests run on deployed endpoints. That's also fine. Here is the actual magic that is happening. We are running dash and smoke tests. Now what is dashed? We know dast will point at your HTTP endpoints the entry points to your application and it will test whether anything in your application can be exploited or not. and OASP zap or burp suite for dynamic checks. You would use curl postman to perform smoke test for app readiness. Now again like I told you before a full-fledged dash will run in the staging and then once the code is promoted from staging to production there is a quality gate. So first the code will only proceed if the dash has successfully completed and if the dash fails the pipeline fails and that is something that you will have to configure. OASP zap will not know that that it has to fail your pipeline you will have to write the logic for that. If OASP zap is saying application has critical vulnerabilities I cannot move forward then you must have your application pipeline also fail. Now let's say your application is hunky and dory and it is promoted to production. Now in production you would be using canary or whatever your rollout strategy is. It could be blue green, it could be canary, AB testing. There are plenty. So you could have any of those. And then here you will be running only minimal dash and that is also called passive dash. And at the last step here you see OASP zap and there is continuous monitoring. OASP zap is there because you could be running minimal dash plus you will have your VAF. VA waf is your web application firewall for your application and different observability tools. Now I want you to clearly know that DAST is not an antivirus or anti-malware. Okay, you will still need an anti-malware or antivirus in your virtual machines or in your containers. What DAT is doing, DAST is checking for any exploits that your running application has and these are tested using attackers. How attackers would exploit your application? They will enter your application using the entry point of your application. It is typically your HTTP endpoint and that is how dash is performed. But again a full-fledged dash is performed in the staging. But when I talk about actual production then a minimal dash is performed. Now this is the entire dev sec ops flow. Now I promise you I promise you there is nothing outside this in dev secop. There could be different tools that are available at your disposal but at a very high level if you have understood these terms I assure you you can talk to anyone security centric about dev sec ops how flow works. Now of course there are deeper integrations for that you will have to study more but at a very high level you are at a very good place to watch any dev sec ops project and understand what is happening and you all know I always aim for making the foundations strong and foundations can only be made strong once you know in detail what these things are doing because Doing demos in my opinion is easy. What is hard for most of the people is understanding the underlying concepts. And once you understand the concepts, then doing demos are of course extremely easy. Now with that being said, I have a request. So if you are enjoying the channel and learning something new from me, I would really encourage if you could like the video. You know, leave a comment. Even if it is just a high, it helps. YouTube likes that and share it with your colleagues. I have recently opened channel memberships at a very nominal cost. If you want to support the channel, please consider joining. Now with that small advertisement, let's start with the next section. Sonar cube architecture. Now before I discuss this, let's go to the GitHub documentation and let's first create some Sonar cube. Let's do some labs because too much theory will bore you, right? So let's go to lab one. So we have done this production flow and you can visit the GitHub notes. It has details of whatever we are discussing. Okay. So now let's do sonar cube lab. So I'll go to my AWS console. I already have logged in and I'm in Ohio region. I'll click on launch instance here. I will Okay, good. This is what we all wanted. So we are signed in. I'm in the launch instance section. Let's call this Sonar Cube. I want to use Ubuntu. Let's use 24.04. Then here, see I have AWS credit. So if I click here you see I have some credits and if you have created a new account you would also get credits for close to 180 days and under that free credits you are not entitled to use any of these instances. You can only use a certain section of instances for and they have done enough. So the maximum instance size you can have is 2 vCPUs and 8 GIB and this is more than enough for most of the DevOps tools that you would be encountering. I'm not talking about a IML but for DevOps these are sufficient and for our use case I will be choosing C7 flex large. Now you could maybe get away with T3 small for Sonar Cube and Jenkins but I would encourage you to use this if you can. So I'll click here and I have already created a key pair. That key pair is called cloud with VJO SJ Ohio. I scroll down. I want to use an existing security group. So I have two security groups here. One is called Jenkins and one is called launch wizard one. So I will use launch wizard one for sonar cube and we'll use that one for the Jenkins EC2 instance. Now the rules that this security group has are pretty simple. I'm just allowing port 9,000 and port 22. So if I go here, this is the default. Yeah. Launch wizard one. So Narcub SG the security group name is launch wizard one. So if I scroll up the inbound rules for this one is I'm allowing port 22 for SSH and 9,000 is on which sonar cube UI listens. And similarly we'll see Jenkins when we come to Jenkins. Then I'll go back here and rest looks good to me. This one I will change it to 20 GI and I will click on launch instance. I'll go to instances and while this is initializing I will click here instance actions and I'll go to image and templates launch more like this and this one I will call Jenkins okay and yeah this one is fine this one is fine this is also fine this is also fine here the security group that I want to choose is Jen Jenkins, right? And if I show you the Jenkins security group, it also has the same thing. So, it is allowing port 22 and port 22 is being used by me to SSH into Jenkins and 80080 will be used to access Jenkins UI. Now I want you to know that when Jenkins interact with sonar cube and you know it will because Jenkins will be you know uploading the reports that are generated from Jakokco to sonar cube. It will be uploaded on port 9,000 and we have already allowed port 9,000 in our sonar cube instance. So that should be fine. So here I will also click on launch instance. Now let's go to instances here in the Sonar Cube instance. I'll just quickly refresh this one. And in Sonar Cube, I'll click on connect. Oh, it's still initializing. So let's allow it some time. The checks have passed. Now let me click on connect. I'll [clears throat] go to SSH client. And here I will just copy this one. So if I go to my terminal, I have already downloaded the key. I'm in SSH folder. And this is the key that I want to use. And if you see, I only have 60 permissions for this key. Now, if you don't have that, fix the permissions. And then you can directly access. Oh, let me I'll have to recopy it. I'll go here. I'll copy this. And then I will paste this here. Now, I'll press enter. And this should work. And now I see are you sure you want to continue connecting? So this is I will use to fu that is trust on first use. I'll say yes and I will then clear my screen so that we have more real estate. Then I will go to my GitHub notes and we will follow rest of the steps from there itself. Now here I said 22.04 but you can use the latest version as well. So if I scroll down we have already done this. uh we have allowed these ports. We have connected and now we want to change the host name. I'm changing the host name so that it is easy for us. I'll paste this here and it will change the host name for me. Then I want to also change the time zone so that we can see the logs and relate to them properly. And if I now type date, you will see that it is showing me today's date. And then if I scroll down now I want to install Java. Now you can install Java 21 as well but I have been working with Java 17 for a very long time and I always click on Java 17 but you can use Java 21 as well. There is no problem with that. I will copy this one and then I will paste this. And I think Java 17 is deprecating in March 2026 if I'm not wrong. You press here and then I'll press enter. So what we are doing is understand that here we are installing JRE. JRE is Java runtime. We are not installing JDK. We are installing Java JRE because Sonar Cube is an application that uses Java. We are not developing or building any application in this server which is why we are installing JRE. Now why this is important? This is important because when we go to Jenkins there we will be installing JDK. Why JDK? Because there we'll be building our application using Java compiler. Hence we'll be installing JDK at that point. Now the fourth step is install Postgress SQL and create DB for sonar cube. Now when you are dealing with sonar cube you can you know install it without a database and underneath I mean not without a database but without an external database and it would be using H2 database internally and H2 database is fine for testing and development purposes but I wanted this demo to be as close to production as possible which is why we will be configuring a postgress SQL Now for this demo I am configuring Postgress SQL in the same VM that is running Sonar cube but in production you would often configure it onto a different VM or you could also be using a service like Amazon RDS that is a cloud managed service for that. So let's start with installing Post SQL. So I will copy this and this will install Post SQL along with common extensions. I will paste this here. Let it run and then I will go back here. I will enable Postgres SQL so that whenever there is a reboot this service automatically gets started and then next we will start post SQL. Yeah, let's start post SQL and then we can quickly check the status as well. Yeah, status looks fine. It is active. Now let's do one thing. What we will do is we will go into psql and configure the database. So understand that right now we are in shell which is performing actions onto this virtual machine. But what we want is we want to perform actions in the postgress SQL instance that we have installed. For that we'll have to use this super user and we'll be using psql to do that. So we'll do this. We'll type it here and then we are in that UI. Now we will create a login role. Understand that what we will do here is we will create a database and then we will supply a owner for that database. The database name would be sonar cube and the owner for database would be sonar user. So create role this this is use a strong password for me both the user and the password will be sonar. So I will copy this from here and then I will paste it here. So this will create the role for me. This will create the database sonar cube and the owner will be sonar. For this one I will paste it here. And then next is we'll grant all privileges to sonar user on this sonar cube database. I'll paste this here. And it's saying create database sonar cube owner sonar syntax error near create. Oh, I think I copied both the lines. Is it? I copied the comment. Sonar cube does not exist. I think this command I didn't Oh, I didn't copy the semicolon in sonar as well. I didn't copy. Oh, just wait. This is part of the syntax. Semicolon. Oh, yeah. Create role. Oh, this command also. Oh, this did not give an error. Why? Anyway, the role is now created. So, you have to copy the semicolon as well. Semicolon. I'll paste it here. And database is created. Now, I will grant access and then we can quit it using this. I'll quit it from here. And then I can run the verification. And so if I run this, I should see the role. We saw the role is here uh sonar. And then if I run this, this should list the sonar cube database. So sonar cube database. Yeah, it is here. And you see access privileges is with sonar. So this is fine. And then this should not return anything for us right now. I'll paste it. I'll just quit it and then I'll paste it here. I'll press Ctrl A to come at the very front and then here I will write Sonar. Sonar is my password. I'll press enter and did not find any relation. This is fine because there is nothing connected to this database yet. Nothing connected as in sonar cube instance is not talking with this sonar cube database that we have just created. So I'll clear my screen. I'll go at the top. Now here are few kernel tweaks that you have to do. So I'll just copy them and paste them. You have to do them as is. Do not worry about them. And here also I will do some tweaks that are mentioned here. So you just have to follow the GitHub notes and you should be at a good place. Now in this step what we are doing is we are creating a dedicated user for sonar cube and that user we are calling sonar. So I will copy this. I will paste this here. Now whatever actions that we will perform so we'll be downloading a sonar cube binary. We'll be installing sonar cube. Then what we'll do is we'll give all the rights to that directory to this sonar user so that we run sonar cube service using the sonar user because that's a best practice. So if I'm running sonar cube service I would want a different user for that not be using Ubuntu user or the root user for that. Now comes the important part that is download and install. So I'll just quickly open this link to show you something. So if I zoom in, there are different editions of Sonar Cube that are available at your disposal at learning stage. Community build edition is the one that you should be using. It covers all the important things that you will be dealing with as part of DevSec Ops. And if in enterprise environments you would typically see enterprise edition or data center edition being used. And you can go to this page and check what all functionalities are available. What are the differences between all of these versions. Here we are using the latest release of community build version. So I will go here and then I will cd into the temporary directory because that is where I will be downloading the binary for this. So I will just copy this command and this will download this specific version for it. Now do not use it 2 3 months down the line. Check the video upload date and if there is a new release you should be using that. Now I am downloading it as sonarcube.szip. As you can see, hyphen o is sonarcube.zip. And once this is downloaded, what we will do is we'll download unzip software as well. Unzip package as well to unzip it. I'll come here. Let it complete. I will paste it. I'll go back to the notes again. And here there are simple commands. So what what we are doing first we are unzipping sonar cube.zip. Then we are moving sonar cube to opt and like we have discussed in maven lecture when you are installing certain binaries third party binaries you should be installing them in the optional directory opt directory and we are calling this sonar cube current while we are copying it and that's also fine and then like I told you what we are doing is for this directory we are changing the ownership of both user and group to sonar user. So I will copy all these three commands. I will go here. I'll paste them. I'll press enter. So if I do ls-l on optar, I'll have to add sudo here. Sonar cube current. Then you see everything has changed to sonar sonar. That is what we wanted. Now eighth point is configure sonar cube to use post gray SQL. Now see what we want is we want sonar cube to be using the database that we have just created. So we'll have to point our sonar cube application to the correct database. Understand that we have installed both of these things onto a single VM. Hence, sonar cube application can refer to the sonar cube database with just local host. If this were a different instance, then you would have to type the host name or whatever means you have defined to communicate with that instance. It could be IP address as well, but in production it is recommended you always use DNS names for communication. Now, I will copy this. I will what I'm doing is I am editing this file opt sonar cubeq current configuration sonar.properties. Now whenever you want to change the behavior of sonar cube then this is the file that you will be editing and I'm editing this file as sonar user. You see hyphen u I'm using sudo so that from Ubuntu user I can invoke diim using sonar user. So I'll copy this. So I'll go here and here you see when I said H2, H2 is there. It is not recommended for production. You can see this line here. It is recommended for tests but not for production. Then you have different options here. We have configured a different database server for us. So what we will do is remove this hash. Here I will be providing the username and password that should be used. So our username was sonar and the password was also sonar. Again this is for accessing the database not the Linux instance. So if I go here what we are doing here is we are accessing our database using the sonar user. So you see we created a sonar user and a password was also sonar like we created. So we are supplying this here not the Linux user that we created. So let's scroll down and here we have supplied this. Now if you were to use an external database you have three options. Okay. So you can use Microsoft SQL server or your SQL Azure or you can grow Postgra which we are using right now. You can also use Oracle. And if I talk about here you can also use Amazon RDS with Postgray SQL as well. So since we are using this we'll have to perform the modifications in the SQL section. So I am already in insert mode here. What I will do is I will first uncomment this and you see this is the property JDBC postgraq localhost is fine because you know my instance is the database instance is in the same VM. Now what I will do is at the very last I will just provide the port number and the port number from my database is 54 32 I think. Hold on. Yeah 5432 sonar cube. 5 432 and then sonar cube. That is what we wanted. Now what I will do is escape shift zz to save this. I will go at my GitHub documentation. So what we have done thus far is we have downloaded the binary. In that binary we have moved it into the opt directory and then we have done some changes in the sonar.properties file. But understand right now sonar cube service is not running at all because we have not created the sonar cube service. So what we will now do is we will create a service for sonar cube and the service that we will be creating will reside in this path. So we are calling it sonar cube.service and it is not just this. If your machine is running SSH you would see that there is also a SSH.service created the these are called unit files and we'll be creating this now. So let me copy this. I'll paste it here. Okay. and I'll go into insert mode and I will paste this block in this. Now what we are saying here is we are creating a service called sonar cube.service. If I run pseudo systemctl stop sonar cube service then you should invoke this. If I am running start then you must invoke these scripts and these scripts as you know we have kept the binary in this path. Hence we are running it from there itself. So I'll copy this and then I will paste it here. Escape shift zz. So we have created a unit file. Now as soon as I do this I can perform a system ctl damon reload and my Linux system will detect it. So if I now run systemctl status sonar cube and press enter then it will tell me that it is disabled but it is detecting that sonar cube service and I do not have to write dot service here because that is automatically appended. Now I will copy this. I'll paste this here. I'll enable the service and then let's copy both of these to start the service and then check the status of it. I'll press enter and now the service is running. I'll press Q. It will exit. Now I will come here. See I have defined what all things we are doing. We you can read it from here. Now if your sonar cube is not starting properly then you can use these things to troubleshoot. But for now we are done. So let's go here. I will go to instances. I will copy this. I will write http colon slash slash I'll add that IP address here and here I will write 9000 because that is on which sonar cube listens on and taa here is sonar cube for you sonar cube is starting now till the time it starts I want to show you the output for that verification command now which previously did not give us anything so we ran And this during verification and this did not result in anything. So if I go to my CLI now I paste it here. I press enter. I have to provide the password not the placeholder for the password. So let me write sonar here. I'll press enter. And you see it is now listing the tables for me. So it works now. So I'll quit this. I will clear my screen and let's go to our browser and then let's go to sonar cube. So admin admin is what is the default password and login. So write admin admin I'll login into this and change password screen. That's fine. Old password is admin. New password is something very difficult to guess. I'll enter my password and then I'll confirm it and I'll press update. Welcome. I'll do later. Got it. And now this is the Sonar Cube UI for you. Let's do a quick walk through of the UI. If I go to quality profiles, you see quality profile are collection of rules to apply during an analysis. For each language there is a default profile and that prof def default profile is called sonar way. All projects not explicitly assigned to some other profile will be analyzed with the default. Ideally all projects will use the same profile for a language. Now quality profiles are collection of rules and there are different quality profiles created for different programming languages and even for different components. So if you see Azure resource manager also has a quality profile. Cloud formation AWS also has a quality profile. Same with docker flex go. Now let's search for Java here. And if I go here I you see there are 537 rules. Now quality profiles are collection of rules. Now this quality profile has 537 rules. So if I go to this profile I can see what are those rules and what is the categorization of those rules. So if you see security related, reliability related, maintainability related and I told you when I talk about maintainability and reliability, we are dealing with code quality in general. So if I click on this active rules, it will take me to this rules tab. Now it is listing all the rules for me. And you see it has also defined severity for these rules. So if I go to high it will tell me all the rules that are created for high priority high severity. Now I want you to understand one thing that you as DevOps engineer if you are not from a programming background you might not understand a lot of these things that are going on the screen and you don't need to understand them deeply. Firstly, you will use a quality profile for a programming language that you are using. And it is often that you could be creating a custom quality profile. And custom quality profile, let's say if Sonar Way for Azure Resource Manager has 31 rules, maybe the one you create could only have 25 rules. It depends on what your project demands. And all these rules you will be creating based on discussions with developers not DevOps alone will be responsible for creating quality profiles. Here is quality gate. Now quality gate as I told you you can have multiple permutation and combinations within a quality gate. For example I have a quality gate which should fail. I am saying the quality gate should fail. I'm not saying the pipeline should fail. Now upon failure of quality gate, your pipeline is failing. That is something that you have to configure. So here I'm saying my quality gate should fail if my coverage is greater than or equal to 80%. So anything lower than 80% should be failing. And then not just this, you can create custom quality gates and we will see that as we progress with this lecture. Now this is the basic of the UI of sonar cube. Now that we have this understanding, let's go to the sonar cube architecture and then we will start with our demo. So let's go to my diagrams and then let's talk about sonar cube architecture. Server stores results and runs rules. Scanners analyze code in CI and push reports to the server. So there are two components. There is a server and then there is a scanner like a server and a client. So sonar cube server is something that we just installed. So we installed the sonar cube application. We also installed a different database and that database is running our sonar cube database. And then this is the part we have not touched yet. Server stores the result. So whatever you defined here the database for this will be storing whatever the results of the scans are whatever rules are being created all of those things are stored here projects measures settings users so if you're creating any users those users are stored there your projects your default settings all those things are stored in the sonar Q server and now that we have had a proper bifurcation So within the sonar cube server we have a sonar cube application and a different sonar cube database. So you can read here what all things are being stored in the database. So when we are discussing about sonar cube server understand that I'm talking about both the sonar cube application and the sonar cube database that thing is clear. So central service storing analysis results metrics and issues provides web UI for browsing projects triaging issues. So if I go here you see there is a UI and in this UI you can create multiple projects. You can create projects locally or you can set up new projects. And then it is saying runs compute engine evaluation rules, metrics, quality gates. And this we have briefly screen in the UI and we'll be seeing this in detail when we move to the demo. Next is stores data in DB projects, measures, settings and users. So all of these things are stored in the DB itself. exposes HTTP API for scanners CI and integrations. Now understand sonar cube scanner is sitting somewhere else and your CI server is sitting somewhere else. How do you enable integration between these two for that you have something called sonar cube scanner. Now sonar cube scanner what it will do is it will run in your CI server and then whatever reports it is receiving it will send those reports to your sonar cube server. So next let's discuss sonar cube scanner. It can be also be thought of as the client or the agent. Client that analyzes code and produces an analysis report. So this is the one that is actually scanning the code. Now when I say scanning the code, it is performing SAS and code quality. Understand that code coverage is not performed by this scanner. This scanner just receives the report and then delivers it to the sonar cube server. When it comes to code coverage, next is runs in CI agents, build servers or developer machines. That is fine. Reads config. collects sources, tests and coverage reports. We have already discussed this stateless and scalable. So this is an important point. Maybe you have Jenkins in your environment and also have GitHub actions. You can configure a same sonar cube server but can have multiple sonar cube scanners. This point is talking about that common variants maven gradal generic sonar scanner. Now that we understand this, let's configure first a Jenkins instance and then let's start with our demo. So I will go to my browser. I will go to instances. I will go to Jenkins here. I will click on connect and I will copy this. I will go to my terminal. I will go to this second tab of this terminal. I will paste this. Press enter. go to my let's first press yes here then I'll go to my GitHub notes here and then I will scroll down scroll down scroll down further down and we have briefly discussed quality profiles quality gates sonar cube server sonar cube scanner now let's do the Jenkins lab so we already have the appropriate security group associated with our Jenkins server. Let's scroll down. Let's do the naming now. We'll change the host name to Jenkins because we like to adhere to the best practices. I'll go here. Then I will change the time zone. I'll press enter. I'll scroll down. Now here you see I'm installing JDK. Install JDK includes JRE the runtime plus Java C and dev tools needed by Maven which is why we are installing JDK here. I will press I'll paste it here. Press enter. Go here. Now these steps are taken directly from the official documentation of Jenkins. So there is no need to explain these points. We are just installing Jenkins. I'll copy these and I will come here. Let it complete. I'll paste it here. Press enter. Now this will install Jenkins. Once Jenkins is installed, I will run this system Ctl associated command so that we enable Jenkins. We start it and then we'll check the status of it. I'll come here. Let it complete. It has completed. I'll paste it here. And then let me go back to the documentation again. So now the installation is complete. I will also run this command so that we know the password for Jenkins. I'll just paste that command here. And you do not have to remember this. When we log into the console, you will see this line there as well. I'll go to my browser. I will come here. Instances. I will copy the IP address of my Jenkins instance. I'll come here. http colon slash slash. I'll add this and 8080 is the port on which Jenkins listens by default. I'm in the sign in page. Now it is showing. You can find the password from here. So we have already run that. So I'll copy the password and I will paste it here. I will click on install suggested plugins here. Install suggested plugins. I encourage you to do the same. And this will do the installation. till that time let's do one thing we can install Maven in our Jenkins instance so what I will do is I'll copy this and it's simple and in our Maven lecture we installed this using binary in production you would see that often binaries are used to install versions so that their life cycle can be managed outside of the package managers like a here I'll paste it here press enter this will install Maven and it will also give me the version it has installed. It will install 3.8.9 and let's check the Maven version. MVN 38. Yeah, 387. Anyway, now let's scroll down. Now, see, I want you to know why we are installing Maven, why we are installing Docker. The architecture of Jenkins that we are using, our Jenkins controller and the Jenkins executor are both the same. So our controller is the one where we are defining the jobs and controller is the one which is also acting as an executor because it is also running our jobs. In this scenario, you would want your Jenkins to have Maven and Docker installed. You want to install this because you want your Jenkins server to run Maven and Docker specific commands. I want you to understand that Jenkins at a very high level is just an automation server, right? But that automation server requires tools. If you are asking it to do something, if you are asking Jenkins to do Maven specific jobs, then it must have Maven installed. If you are asking it to run Helm specific commands, then your Jenkins should have Helm installed. If you are asking it to run cubectl commands, then Jenkins must have cubectl installed. But having said that, I also want to mention one more thing. In our architecture both the controller and executor is the same. In production implementations you would have Jenkins controller and that Jenkins controller will be bifurcating the jobs will be dividing the jobs onto different agents. For example, Docker specific jobs will be running onto Docker agents. Agents that have Docker installed. Similarly, Maven specific jobs or Maven specific tasks will be assigned to agents that are Maven specific that have Maven installed and so on. And as we move on to advanced demos, as I upload advanced demos in my channel, you would see that we would be leveraging all those things. And not just for DevOps, but also for dev sec ops. when I'll be uploading advanced demos you can always refer to those because after this lecture you we you would have gotten a solid understanding of dev seccops flow in general now we have Maven installed let's install docker again all the steps that I'm using are documented in the official documentation of docker itself I'm just adhering to that first step is if you are working with a VM that is being used for other purposes I would suggest you to remove this so that you have a fresh installation. I just freshly created this VM. So I'll just move to second step here. I will paste that here and then I will come here. I will add docker repository to apt sources and then finally I will run apt update and I will install the things that are required for docker. I'll paste it here. It is installing. While it installs, let's see what we want to do next. Now, what I want to do is what I'm doing is I want my Jenkins to be running docker commands. Now, for Jenkins to run docker commands, it must be part of docker group only then it can run those commands. And while I'm on this screen, I'm also making Ubuntu, which is my current user via which I have logged in into my Jenkins server also part of that docker group. And then I'm restarting the Jenkins service. So I will copy this first. Let me see whether that has completed because I don't want to restart Jenkins in middle it. It is username. Let's say let's create a new user here. Cloud with vos. Yeah, it's already created here. And I'll give it a strong password. I will confirm my strong password. Full name is Vun Jooshi. email is abc at the ratexyz.com. Save and continue. And here is the Jenkins URL. So I'll save and finish this and then I'll click on start using Jenkins. And there in my CLI I was supposed to run that command, right? I'll go here and then let's run all these three commands. I'm not sure. I'll come here. I'll paste those commands here. I'll press enter. Okay, this has run. Now let's run docker version. Docker versions should run from my Ubuntu user as well. And it is working. So now we have Jenkins server ready. And that Jenkins has Maven and Docker installed. And again I could have also used plugins instead of directly installing these tools onto my Jenkins CLI, but that is a discussion that we did in our Jenkins CI/CD series. So for now let's clear our screen and now let's start with the demo. Now before I start with the demo I want to give you a quick glimpse of what we are going to do. So this demo is sonar cube with docker maven and Jenkins. End to end we'll be injecting bad code. We will be running sonar scan. We'll be enforcing quality gates. And then we'll be building a container image and deploying a container. So the first step that we will do is we'll create a private repository. We will upload our code in that private repository. Then we will let Jenkins do rest of it. Jenkins will first check out the code from the private repository. Then we will have Maven integrated with Jenkins. Maven will be compiling the software and it will be there will be Jakokco plug-in. We'll be modifying our pom.xml here. We'll be adding a Jakco plug-in. That plug-in will be collecting the test reports and we'll be delivering those reports to our Sonar Q. Then the Sonar Q will be performing the scans here. And here those scans imply SAS and code quality scans. Here sonar gate decision. Sonar will tell whether to allow this pipeline or to fail this pipeline. It will only allow the pipeline if the quality gates are green. It will deny the pipeline to move forward. If quality gates are failing and once the quality gates succeed, we will be creating a container image and we will be finally running a container from that container image. So that is the complete flow and in production the flow that you would see would be similar to this. In addition to this you would be seeing dash, SCA, sbomb and so on. So let's go to our GitHub nodes and see what we want to do. So the first step is we want to create a private GitHub repository and then we also want to you know create a token. Now why we are creating a token? We are creating a token because this is the token that our Jenkins will be using to interact with our GitHub repository. So I will copy this name. I will go to my GitHub repository here. Let me scroll at the top here and then I can go to the homepage. Here I can go to repositories and then I can click on new repository and here I can give a name to this repository. Let's call this cloud with vos private repo and here I want this to be private and I will click on create repository. That's it. A repository is created for me. Now I want to create a personal access token because that is how my Jenkins will access my private repository. So here I will go to settings and then in settings I want to go to developer settings and in developer settings I want to go to personal access tokens. Here I'll go to tokens classic and then I will click on generate new token. I want to generate a classic token here. I can call this Jenkins GitHub integration. I want the names to define exactly what I'm doing. Please pardon the long name. Now I will have repo selected and then I will click on generate token. I'll be deleting this token after this lecture after uploading this lecture. There is no point remembering this. So what I will do is I'll copy this. You will be only shown this once. So copy it and paste it somewhere safe. So I'll go to my Visual Studio code and here I'll go to this file and I will paste my GitHub token here. Then I will go to my browser. So we have generated the token. We have created the private repository. Now what I will do is I'll go here to my steps again and I'll scroll down. Now see now is the step where we are creating a Maven project. So this is the project that where we will be running all our security scans. Before I run this step, I will be using my Jenkins VM to run these steps. But if your laptop has Maven installed and git installed, you can run it from your own laptop as well. I am using my Jenkins server so that the larger audience can follow along with me. I'll be cding into the temp directory and then we have already seen this. We are using Maven archetype quick start with version 1.5 here. So we have discussed this bit by bit in our Maven lecture. So I'll not spend any time discussing this. I'll copy this. I'll go to my Jenkins VM. I'm on Jenkins VM. I'll paste all of these here. I'll press enter. I want you to clearly know what we are doing. We are replicating an actual production implementation. We are treating our laptop, our Jenkins server in this scenario as a developer laptop. So developer, what would developer do? If I press ls, developer will have the code like this and then the developer will be pushing this code onto a private repository. Those are the exact steps that we will be doing. But before we do those steps, I want you to know the archetype that we are using here, the quick start archetype that we are using. This does not have the Jakokco plug-in defined. And the code that is there just says hello world. But I want to show you how vulnerabilities, how code smells will be detected and how Sonar Q will show them. Hence what we will do is we'll modify a few things so that we can see how sonar cube shows these things to us. So firstly we will be adding a jakokco plug-in and you know the plug-in information we put it in the pom.xml. So I'll edit my pom.xml. I'll go into insert mode. I will scroll down where plugins are defined. And I see that you see plugins is a plural here. Here is the first plug-in. This is the plug-in element. And this is the starting tag. This is the closing tag for plugins. This is the starting tag. And at the very bottom, you would see there is a closing tag. This is the closing tag for plugins. Now, this is the closing tag for this plug-in. So I'll go into insert mode here and then I will add my plug-in at the very last. I'll press enter. And now I will go to my browser from where I will copy the plug-in that I wish to add. Now this plug-in you see is for Jakokco Maven plug-in. This will have Jakokco. Now Jakokco once we have Jakokco it can share the code coverage reports with your sonar cube. Understand that your surefire and failsafe plugins will be performing unit and integration tests but it is Jakokco plug-in which will be creating the coverage reports. Now I will copy this and then I will go here and I will paste this here. This has disturbed the formatting a little and we'll fix that later. So I'll save this. Now if I run ls you have src and pom.xml. Let me also quickly install apt install tree so that I can show you the structure. I should have added a pseudo as well. pseudo apt install tree. So if I run tree now you can see there is pom.xml XML and src has main which has your main code and then test has the tests defined. So what I will do is I will add this as part of our code. So what I will be doing is I'll be modifying this code. So right now this code just says hello world and for our practice that will not suffice. So I'll go here. I will press D 10D that will delete 10 lines. So if you press DD it removes a single line. If you press D10D it will remove 10 lines and 20 will remove 20 and so on. You get the idea. I'll copy this and then I'll paste it here. So here what we are doing is we are adding code smell. We are adding a security vulnerability. You remember what we called this? We called this security hotspot right and then we are also defining a bug and so on. So let's close this and we have polluted our code now. So we are good to perform the testing. Now what is the next step? Let's go there. I'll scroll down. Now let's perform the get commit. So I'll clear my screen first. I'll run ls. You see our code is ready to be pushed. I'll write get init. Get init will initialize this directory. I'll press enter. Initialized an empty directory which is okay. Get add. I want to add everything that you see. And then I will run get commit and then hyphen m message could be initial commit with form and code. Right? I have to spell it right. And that's why copy pasting is good. I'll press enter. Now let me just quickly also do this. User email is fine. Let's add the name. I will add Vun Jooshi here. And now what I can do is let's get branch V. Now oh we have to run get commit. Hold on. Get commit. And then if I now run g branch-env, you see this is the master branch. And in GitHub we have something called main. And I like the name main better. So let's do one thing. So here is the repository that we created. Okay. So this one if I go here you would see that this one has main. So let's do one thing. I will just quickly rename this. I'll write get branch - m main. So we have this main name here and then what we can do is I can go to my GitHub nodes. I will quickly go here and yeah we have to add this repository. Now you would have mostly seen that this is usually called origin and that is the name that is quite popular when I talk about remote. So I usually name my remotes in a way that I can recognize them. So which is why I have not written get remote add origin and then written that URL. I have written get remote add private repo because I want to call this private repo. So once you have done this now I want to push my code to this private repository. understand that I cannot push to a private repository until and unless I provide some authentication information and that is the authentication information I have to provide next. So if I go to Visual Studio Code, if I go to my browser, I have to copy this. I will paste this onto Visual Studio Code. I will copy this personal access token and I will insert this token here. Okay. Then I will copy this. What I'm saying is get remote set URL private repo this one so that I can freely push to this private repository. I'll paste it here. I'll press enter. If I run get remote v. Now you can see that that repository is having this URL that we put just now. Once you have done this, run this command with caution. Okay, you should not be showing your personal access tokens. Get push private repo and then I want to push this to the main branch. So I'll press enter and this has done the job. So if I go here to my browser and to the repository that we just created. If I hit refresh here then you see our files pom.xml and srcr here. Maven is associated with maven wrapper. You don't have to know much about it but understand that this file should not go in. Ignore anyway. So src and pom.xml are now here. Now let's see what we want to do next. Create Jenkins freestyle job using execute shell. I am using a Jenkins freestyle job in this demo for simplicity. Once I have advanced demos in my channel, they will be using Jenkins pipeline. And if you are interested in knowing Jenkins pipeline or the pipeline syntax or Jenkins multibranch pipelines then I already have detailed demos in my channel which will show you that. But for now let's stick to Jenkins freestyle job. And anyone who already knows Jenkins would know how to convert these freestyle jobs into a Jenkins pipeline. and maybe when we do advanced demos later in this channel, we will be covering dev sec ops using Jenkins file. So for now, let's create a freestyle job named my app sonar job. So I'll go to my Jenkins screen. Here is my dashboard and my Jenkins is ready. The first thing I want to do is change this to dark mode because this is blinding cloud with var Josh my password is this tab keep me signed in and here what I can do is I can it was in settings and here appearance and I want this appearance to be dark it's done oh cancel save and then I can go to Jenkins here and let's create a job and I want to call this job my app sonar job. It's a freestyle job. Okay. Now here I will now before I forget let me do one more thing. Okay. I'll go to this pom.xml. It is not formatted properly. Right? You have this last plug-in is everywhere. And what I will do is I'm deliberately doing this so that you can also see. I'll go to XML formatter. And here what we can do is familiar with this one. Yeah, this one. I'll paste it here. I'll click on format beautify. And this has fixed our plug-in. Okay. Previously it was you see all over the place. Now it has fixed it. So I will quickly copy this. I will go here. I will paste it here. Oh, I'll go to edit mode. And then I'll select this all and I'll paste this. And I'll click on commit changes. I'm committing the changes from the UI and refactor pom.xml for improved structure. You see how copilot how fast it was. Anyway, so I'll click on commit changes and we have the correct structure of pom.xml now. So let's go back to our Jenkins job here. Source code management get. Now it is asking us to provide the repository URL. How do we provide that? Let's close this one first. Let's go to private repo. Let's go here. Let's quickly copy this. Yeah, I'll copy this. I'll paste this here. Now again, you know that we require credentials whenever we want Jenkins to access our private repository. And credentials is the place where you configure it. Now it is saying fail to connect. Why failing? Because this is a private repository. I'll click on add here. Jenkins. I will global unrestricted username with password. The scope will be global. Global implies any of the jobs can also use it. Otherwise, a different one is system with system only Jenkins and nodes can access it. Username will be cloud with varos for me. You have to enter your username and password. I will go to Visual Studio Code. I have my personal access token here. I will paste it here. ID I can call it GitHub. GitHub token seems all right to me. And then I will click on add. And as soon as I select this, this red should go because uh Jenkins will verify that indeed the person has provided correct credentials for this private repository. And here I don't have a master anymore. So I'll just write main here. I'll scroll down. What will be the trigger of the pipeline? For my pipeline, I'll directly click on build now. So the trigger will be manual here. Now environment, I also have to supply some details about sonar cube, right? And along with details as an IP address, I should also have some sort of authentication for sonar cube, right? And right now in this step, we are defining that authentication. So I'll click on use secret text or file. I will click on add here. I'll click on secret text. But Vun, we have not generated anything for sonar cube yet. How do you intend to provide this here? So we'll be doing that. But first I want to explain what are bindings. Now bindings are used to inject secrets securely into the build environment. So you never hardcode tokens or paste them into commands. As I told you in the next step, we'll be adding certain build steps. And there will be execute shell. In execute shell, I don't want to enter these credentials, which is why I'm adding these credentials as bindings. And here for GitHub, we added it within the git section, the source code management itself. So these credentials will not be displayed in plain text in console outputs and that is what we want. That is why we are using bindings here. Now we must have a project created in sonar cube and that project will have everything associated with our application. Correct? And our application if I show this to you is called my app. And that is if I go here. Yeah, this is called my app. My hyphen app and this is important because GAV parameters are important when we talk about Maven and Sonar Cube integration and you will see this shortly. Why I go here I can set up a diff a CI here but for now let's create a local project. Now display name I'm calling it my app. And if I hit on thisformational message, the project key is unique identifier for your project. It may contain up to 400 characters. These these these are allowed with at least with this non-digit. I will click my app. And now I'll write my app and then we'll press next. Set up new code for project. Now what is this? I want you to understand that let's say you have 1,000 lines of code. You have run sonar cube analysis for those thousand lines. The next time when you run the analysis, do you want to run the analysis for those thousand lines again or would you want to run the analysis for only things that you have changed? I hope you have answered I only want to run it for the things that I have changed. Understand what I told you. Your primary purpose is to ensure your pipelines run in as less time as possible covering all what is needed and to keeping that in mind you want your security scans to complete as soon as possible. If they are doing the entire scans again and again isn't that futile. So what this step is asking you is what do you define as new code and the options that you have are previous version and this is the one that we are using. So any code that has changed since the previous version is considered the new code. So let's say a scan was run for your thousand lines and it found two vulnerabilities in and now in the new code what you did is you fixed those vulnerabilities. So it will only run on the part that has changed. It will not run it from the very beginning. So that's the crux here. And then you have multiple options here. You can supply number of days. Any code that has changed in the last x days is considered new code. So you have various ways you can define this. For our demo, we will choose previous version. And then we will click on create code. And if you see here follow the instances default default is also the previous version. So you can click on create project now. Now the project is created but we do not yet have any credentials credentials that we will use to access sonar cube from our Jenkins instance. So for that we'll have to do two more things. First is let's create a user. I will go here security and I will click on users. Let's create a new user and then with that user we will associate a token and that token will be used by Jenkins. So I will click on create user and the login name for this user I want genkins and then I will also write sonar so that I know this user is genkins sonar and then I will also add my app. Why I'm adding my app? Because I know that I created this user specifically for this app or for this project. Now you will not be using user created for Vun or user created for Prakash or user created for Kanea in here. You will be using a different user that is specifically created for integration between Jenkins and Sonar Cube. So that is what I have done here. Now the password that you provide here is not needed for us because we will not be using this password to access Sonarq. We'll be using token. But since it is asking it, let's provide that password as well. And here the name will be Jenkins Sonar and ABC XYZ can be the email address. So I'll create this user and then if I come here, I can create a token. Now token I will call Jenkins sonar and then you can set an expiry as well. So I'll click on generate and now I will copy this token. And this is also shown only once. So it is better if you save it somewhere. So I'll paste it here. And then I will close this. Now what I want to do is we have a project created. We have a user created. We also have a token associated with that user. But what I also want to do is I want to give that user system administrator privileges. Now that user is a sonar administrator. Now I'll click on done. And third thing that I want to do is I want to define a quality gate. I'll click on create quality gate. I'll call this my app quality gate. I'll click on create. And you see whatever was there in the default quality gate those things are already here. And I also want you to see one more thing projects. Every project not specifically associated to a quality gate will be associated to this one by default. So there is this quality gate that is available here by default. So we'll go here now. See if your quality gate fails you will be reaching out to your fellow developers and tell them that these are the problems you will have to fix it. It is not you who will be fixing those problems as DevOps or dev sec ops. your point of concern is ensuring the scans and all these things are running properly and in as less time as possible. So what I will now do is I will delete all these rules because our code is not designed for these complex rules for now. So I'll delete all these rules and then I will add a new condition. I will say run the condition on overall code not just the new code. This is important overall code and then quality because I have a tiny code and we'll be running this multiple times. Okay. So I want it to run on the overall code quality gate fails when coverage and see you have so many options unit test errors unit test failures. I will let you explore these options. But here I want to choose coverage and I'm saying if coverage is less than 80 then you fail this quality gate. I will click on add condition. Now it is asking me which are the projects you want to associate with my app quality gate. For me this are these are the projects that are not yet associated. So I want this to be associated. So I will be clicking here. Now if I go to all, if I go to with I go here, I go here. If I go to with, now you see my app is here. So now we have all the things in place. Now let's go to Jenkins and configure other things. So I will come to my Jenkins screen and variable I want to use is called sonar token and we'll be using this variable in our next step and I'll show you how specific credentials. Now it is asking for credentials. So we have not added those credentials in Jenkins yet. Let's click on add Jenkins and this is fine. And here I want to choose secret text. Now you would be thinking but Vun in GitHub you chose username and password in here you are just adding secret text. Understand that GitHub expects both username and password although these tokens are unique but when it comes to sonar cube it is just expecting that token and that token is unique. So I will type that secret here. So let me go to Visual Studio Code. I will copy this. I will paste this here. So whatever ID I give to the token in the CLI or in the Jenkins console, I will be using that ID to call these credentials. So if I click on this question mark, it will give you a gist about it. An internal unique ID by which these credentials are identified from jobs and other configurations. So let us give it an identification called sonar cube- token. This is a good one. So if I scroll down I can click on add here. Now it has selected that token for us. If I scroll down I will click on build steps. Add build steps here. And then I will choose execute shell. I will also expand this. Now let's go back to our GitHub notes. I'll scroll down. I'll scroll further down. We are in the demo, right? Yeah. Now this is the part that I will be pasting onto there. So let's go through this. First we are listing whatever is there in our workspace. And what will be there in our workspace? Our first step was get. It will be performing a get checkout first. So whatever is cloned will be shown to us when we run this first step. Then we are defining what is the sonar IP. Now sonar IP this will be the IP address of your sonar cube instance. So you will we'll take it that from the AWS console. Now the third is Maven build plus test plus coverage plus sonar cube scan. Understand what I told you in the architecture part. There are two things to sonar cube. There is a server and then there is a scanner. Now for the scanner part, we are using a Maven plug-in that is performing the scanning for us. That is playing the role of the scanner here. But for certain other languages, you will have to install a Jenkins plug-in called Sonar Cube plugin. And this is important. So I'll just quickly show that to you as well. If I open this in new tab, if I go to plugins here, I Oh, see it's saying Java 17 is end of life March 2026. So, we'll have to I'll start using Java 21 from now onwards. I'll go to plugins here. I'll go to available plugins and then here I can check for Sonar Cube. So you will be installing this sonar cube scanner plug-in for certain advanced use cases. For now we are just using Maven plug-in to perform the functionality of scanner. So what we are saying is we are first running MVN clean which will just delete the target folder. It will perform the cleanup and we have discussed this plenty of times. If I talk about clean, clean has three phases. We are running this phase. It will remove all files generated by the previous build. That is what this will do. Then we are saying verify. Now again understand this is extremely important. We are running verify. And if you run verify then all the previous phases are run. So verify will also run the package integration test and all of these. So if you have run MVN verify then you already have the artifact. Keep this important point in mind. So first we ran the clean phase then we ran the verify phase and after that we are invoking a maven plug-in named sonar and within that plug-in we are calling the role sonar. I hope this is understood. Then we are saying sonar project key is my app. That is the project key we defined back in the sonar cube UI. Remember they must be same. Then we are providing sonar cube host URL. This is the URL on which sonar cube is listening. So we have variableized it and the variables value is being picked up from here. Next is sonar cube token. So from where are you picking the token? So we have created a binding which is why we can call it like this sonar token. Why we can call it like this? Because I have defined that variable like this sonar token. Try to create that mental picture in your head right now. And then what we are saying is package. Now this is the important piece. You do not have to run any of these. Why you don't have to run? Because we already have the artifact at this stage. Then why do we want to run this? Hence, we will not be running Maven package or MVN jar jar. You could have also thought that we can run that but that is not needed because MVN verify has already created the artifact for you. And then in step five we are creating a docker file. Understand that this would have resulted in a target folder and that target folder would have the jar file. And what we are doing here is we are just copying that jar file and naming it app.jar. We are using an image that has Java runtime environment JRE because we just want to run an application that is based on Java. We are not building a Java application. Hence, we do not need the Java compiler. And then finally entry point is this. We are running the application Java - jar app.jar is the artifact that I want to run. So this is my docker file. Then using this docker file I am building my container image. I'm creating my container image. And then in seventh step what I am doing is I am removing my Java app. Now why I have added this step? I am removing forcefully removing this container. Now if you run this multiple times then this will give you an error stating the container with this name already exists. So whenever I'm kicking in my pipeline, I have added this step so that your pipeline doesn't fail for this reason that this container already exists. Now I want to let you know one more thing. If you are building image like this, the build context will also have your source code and your pom.xml. And you do not want that in production implementations. you want your build context should only have files that are needed for docker build. I just wanted to mention this so that you have clear idea. What I will now do is I will copy this entire block. I'll go to my Jenkins UI. I will paste this here. I will go to AWS screen. I will copy my sonar cube IP address. I'll copy this. I'll come here. I'll go to the variable section. And here I will define the value of my variable. Another thing that I want to do is I don't want to run this MVN package unnecessarily because I already have the artifact with me. And I will also comment this one out. This looks fine to me. And yeah, we have added the token. My app is here. Credentials we have provided. I think we are good to apply this. And let me quickly check in the GitHub notes if there is something that we need to do after this. Yeah, this is good. So let's go here. I will click on save and let's click on build. Now this will trigger the pipeline. Now let's see what happens. Let's click here. Let's go to console output so that we can see what is going on. Okay. Okay. The pipeline has failed. And the reason for failure is quality gate status failed. View details on this. Now before I show you the UI, I want to show you something else here. I think I didn't reach here and I directly moved on to next steps. What we are saying here is quality gate weight is equal to two. We are saying you wait for the quality gate. If the quality gate is failing, you fail the pipeline. That is what we have done. The quality gate, we were waiting for the quality gate to either succeed or fail. It failed and we have failed the pipeline. That is what you see here. Now let's copy this and then I will paste it here and then yeah let's go to my app. So this will show me the details about my app project and it says failed new code is no because we were we selected overall code and it is showing all the things that we discussed security hotspot one. So let's start with all of these. So issues security hotspot code measures activity. Let's do a walk through of all of these. If I go to issues, it will tell me about all the issues that are there in my code. Now again I'm saying not all of these things would be understood by you but it is okay as long as you you know understand them from a very high level. So issues is segregating things based on these are for pom.xml. Okay. And these things are for your main code itself. App dot on Java. And then you have test.java has these things. Now again let's go to security hotspots. If I go to security hotspots, we can see that there was one password and it has said password detected in this. And then we can go on code. It will show you the entire code. Now I want you to know why this pipeline failed. The coverage is 0%. Now what does coverage mean? Coverage imply test coverage, right? And I told you that the testing requires developer to define a testing framework and then define test cases that how do you want to test this, how do you want to test that and then the plugins that Maven has can perform that testing but the developer must define the framework and the tests to be performed. In our scenario, we didn't have any of those. We just had the Jakokco plug-in. So what Jakokco plug-in received was the coverage is 0%. And that is what we see on our screen. If you see source code, the coverage is 0%. I expand this 0%. So what I am trying to convey to you is your developers must define test cases. And why this failed? because we have a quality gate that wanted more than 80% or equal to 80%, but we are giving it 0%. Hence our quality gate failed. Now what we want to do is now we want to rerun the pipeline and we want to sorry this was the quality gate but uh it's saying the same thing if coverage is less than 80% you fail it. Now what we want to do is we want to rerun our pipeline but this time we want to have it run successfully. Now in actual production you would be reaching out to your developers and telling them that fix these problems only then the pipeline will succeed. But in here we are the problem creator and we are the problem fixers. So what we will do is we will just delete this condition altogether so that it does not check for this and then I will come to my Jenkins UI and then I will rerun this pipeline build now and this time let's see how this works and then I can go to console output and this time it should ideally succeed. So it would be running all the steps like we have defined in our execute shell section. And you see it has run everything. And this error is because there was no container with name my Java app because previous run did not reach this stage at all. It failed in that section itself in the quality gate itself. Here then we are creating the container. Now after creating the container we are also deleting the container once it has done what it is supposed to do. I hope you have an end to end understanding. Let me quickly see if I want to cover anything else. So I have covered everything that I wanted to cover. So that's a wrap for this lecture. In this lecture we took dev seccops from concepts to production. You saw why dev secops exists. what each security tool category means and how SAS dash code quality checks SCA and SBOM fit into real CI pipeline. We installed Sonar Cube, explored its architecture, set up Jenkins with Maven and Docker, and finally ran a full Sonar Cube plus Jenkins dev secc Ops workflow end to end. If this session helped you understand dev sec ops the way a DevOps engineer should do like the video, drop your questions in the comment and share it with anyone who wants to level up their cloud and DevOps skills. I will see you in the next one. Thank you very much. Hello everyone, I am Varun Jooshi and I welcome you to cloud with VJosh where we build realworld DevOps and cloudnative systems through hands-on production focused demos. Today we are building a full production grade dev sec ops pipeline the kind that will help you in interviews and in real world project work. We will combine Jenkins, Sonar Cube, Trivy, Amazon ECR, Amazon EKS, Arbback, image scanning and build a rollouts. We will cover installation and configuration of Jenkins controller on EC2. We'll be setting up a secure asset based Jenkins agent. Install sonar cube with postres SQL and configure quality gates. build the CI flow, git, trivi file system, maven sonar, image scan, ECR push and so on. We will be provisioning a multi-AZ Amazon EKS cluster. Configure AM configure AWS O config map arbback and deploy with rollout checks. Run the entire flow from code push to a secured production grade deployment. All commands, manifests, IM policies and the Jenkins file are available in the GitHub notes so you can follow along easily. So let's get started. Like in life, this lecture also has some prerequisites. So let's quickly visit them and after that we'll get started. I'll go to my browser and here I am in my YouTube channel. So firstly you should have good understanding of Maven and Sonar cube as we will be using these tools extensively in our demo. There are certain Jenkins concepts and other Kubernetes concepts that you must know as we progress with this lecture but all of those things are already covered in my channel. I will link appropriate videos where required so that you can learn without interruption. With that being said, let's go to the diagrams and see what are we going to deploy in this session. So demo end toend production dev sec ops pipeline. See here the orchestrator that will be orchestrating our entire CI/CD will be Jenkins. We will have a Jenkins controller and the tasks that are related to our projects will be performed by a Jenkins agent so that there is proper role separation and the controller just handles the logic the control plane and there is an agent that is actually running the job for you. Now let's see what all stages or what all steps will be there in our pipeline and have a sky by view of all the things. First is check out private git repository. So like in production implementations I'm sure your application is also hosted onto a private repository. Now that repository could be on GitHub, GitLab or any other offering but in this lecture we will be leveraging GitHub as our private repository. Now if you have a private repository then if you want to access that repository you will need credentials to do that and that is exactly what we are going to do in the very first stage. Now to give you a background of the application that we are deploying, we are deploying a Java application. A very simple Java application that just says welcome to cloud with VJOS. Hence [snorts] in the repository what we will start with is pom.xml along with the source code and as we progress there will be more things that will be added to that repository. more things like the Docker file, the Jenkins file and so on. But we will start with the source code and pom.xml. And that is exactly what your developers will be doing. Your developers will be pushing the code along with pom.xml into a private repository and from there you DevOps folks will start your work. Now I will be mentioning DevOps because as you know the line between DevOps and DevSec Ops is now blurred. So everything including security is slowly and steadily moving in the DevOps side of things. In the second step we will be performing a TV scan and this TV scan is SCA. And if you remember, we learned in our Sonar Cube lecture what exactly is SCA? What will SCA do? SCA will scan for vulnerabilities in your thirdparty libraries. For example, we know that in Java, we define all the dependencies or the third-party libraries in our pom.xml. So, Trivy will be scanning this pom.xml XML to see whether there are any vulnerabilities in the dependencies that we have defined or not and TV is not just SCA it will also check our OS packages. It will also check whether there are any secrets that are openly available the well-known patterns. For example, maybe you have AWS secrets in your source code and you should never be doing that. Trivy will be able to detect that. So the first step is scanning SCA and if this fails our pipeline will fail and that is what we want in production. We want that if something is not right with my code. If my code or my dependencies they have any vulnerabilities I want my pipeline to fail. Then next we have build plus test. In the build stage, we'll be leveraging Maven to build our code and then we will be performing scans using a plug-in called Sonar. And as you see in the next stage, we have Sonar cube analysis which will be performing SAS that is static application security testing. And in case if any of these things fail, fail as in if your code has vulnerabilities and your quality gates define that I cannot pass this code if there are any vulnerabilities or if your code coverage is less than let's say 80%, then I will not allow the pipeline to move forward. I will fail this pipeline again. If you have not watched the Maven and Sonar cube lecture, these things will be a foreign language for you. So I request you to first go through that so that all things in this demo make sense to you. And in the next stage as we know we'll be doing ECR login plus we'll be building the image. So if you want to build the image then you must have tools that are required to build the image such as if you are using docker you should have docker installed to build your container images then ECR login. So if you want to at some stage push your container image to an image registry then of course you will have to login into that image registry. And in our demo we are using Amazon ECR to host our container images. Hence in this stage what we'll be doing is we'll first be performing ECR login. Then we'll be building the image and in subsequent stage next to next stage we'll be pushing that container image to AWS ECR. At this stage I want you to understand that we will also be performing try image vulnerability scanning. Wun we have already performed SCA here. We have already performed SAS here. SAS is which is checking your code for vulnerabilities. SCA was checking your dependencies for vulnerabilities. SAS is checking your code for vulnerabilities. Understanding the difference is the key here. And then here the Trivy image scan is performing the scan on your image. But Wun, we have already done these things. Why do I need to scan my image? I want you to clearly know that your docker file uses a base image. In this step, we are scanning your base image for any vulnerabilities. And again, in this step as well, if there are high or critical vulnerabilities, if there are any findings like this, then we are failing the pipeline. I want you to clearly know that there are three stages where we essentially are failing the pipeline. If our desired thresholds are not met, this is the key point here. For example, maybe for application one, 70% code coverage is all right. But for application two, at least 90% code coverage is important. So for you DevOps folks, it becomes imperative that you configure these quality gates, these failures, these successfuls based on your app requirement and then as we discussed here we'll be pushing to AWS ECR and then finally we will be deploying it to Amazon EKS and I believe this is the step where everything will come together your AWS knowledge, your authentication knowledge your authorization knowledge because we will be leveraging principle of least privilege. So our Jenkins which will be deploying resources onto Amazon EKS must authenticate and must only be able to do things that we allow it to do nothing more nothing less. So with that critical understanding let's get started. So in this demo the first step would be to configure our infrastructure. So we'll be configuring three things and straight away we'll be doing that. First we'll be creating a Jenkins controller. Second, we'll be creating a Jenkins agent. Third, we'll be establishing the communication between the Jenkins controller and Jenkins agent. And that is where SSH comes into picture. And then at the very last, we'll be configuring sonar cube with an external database which is something that you would see in production implementations. So with that said, what I will do is I'll go to my GitHub repository. I'll go to my browser first. Here I have this repository Jenkins basics to production. I have added project one here. All the steps inch by inch, word by word are mentioned in my repository. So you can follow along with me and if it helps do do start the repository it helps me a lot. Now [snorts] first step is install Jenkins controller. So let's go there. And you see I am using C7 iflex.large instance. I'll be using this instance for all the three components. My controller my agent and sonar cube. This provides two vCPUs and 4 GB of RAM which I feel is sufficient for these demos. Now if you want to lower the instance type then you can maybe use T3 small but I have used C7i flex.l large throughout this lecture and this falls under the AWS free credit. So if you have those credits, if you don't have those credits, then I would encourage you to create a new AWS account with all the details and then AWS will give you I think 120 free credits to begin with and they will also give you 50 more if you you know clarify certain criterias for them. Anyway, I'll let you figure that out. For now, let's go to the console and let's start creating instances. I'll click on launch instance here. This one I want everyone that is following this lecture to be very specific with nomenclature because nomomenclature will help you a lot when you are dealing with a production grade issue. So Jenkins controller is the name that I'll give to this machine. This is the name tag not the host name of the machine. The host name we'll be changing once the machine is configured for us. I'll be choosing Ubuntu. Instance type here I will change this to C7i flex large which is free tier eligible it will give me two vCPUs and 4 GIB of memory GBtes. So I'll click here key pair I have already created a key pair and key pair is called cloud with var sjen Mumbai. I want you to know that these key pairs are regional in nature. So if you are dealing with an AWS account and you deploy resources to multiple regions then I encourage you to always have the region name in your key bear naming. Another point I want to highlight I am calling this account cloud with varoo sj which is why I have it here so that if I have multiple key pairs in my machine I know that which key pair to be used for which account. This gives you a clarity. Hence, I highly highly encourage you to use naming that helps you understand when you look at this 6 months down the line because I assure you, you won't remember. Now, if you do not have a key pair, just click on create key pair here. The algorithm that you should be choosing is ED25519. You could choose RS as well but this one is a latest and greatest one which you should be using anyway. So I already have this key pair created and I have selected that. I'll scroll down. I will be using the default settings here but here I will be choosing an existing security group and the security group I already have three security groups created. I will be choosing the security group that I have created for Jenkins controller just to give you a quick glimpse of it. I'll open this in new tab. I will go to security groups and here I will select the Jenkins controller. Now the inbound rules I have is port 22 is allowed from anywhere and this is something that I am using and you can be restrictive with it. You can only allow your source IP. But I have configured these for simplicity. In actual production implementations, you would see that only what is needed is allowed. And if you see the latest trend, this trend of setting up jump hosts or sshing into machine is slowly moving away when you are on AWS specifically because you would be using systems manager which provides you other means to login into your machine rather than using SSH. So you would be typically using those things here, not the traditional jump hosts or bastion hosts that you would have used before. Second, I am allowing port 8080. Now 80080 is the port on which Jenkins listens. So I am allowing that and again I'm allowing that for the entire world which you might not be doing in production but I'm doing this for simplicity. Then we have done this. I also want to give you a walk through of all other security groups because we are already in this screen. And then we have Jenkins agent and Jenkins agent I am only allowing port 22 here only as such it is the Jenkins agent that is listening on port 22 from everyone since we will be connecting to our Jenkins agent from Jenkins controller over port 22 that port 22 is already allowed in our Jenkins agent so that Jenkins controller can connect to it. Now previously JNLP was used Java network JNLP Java network hold on I've forgotten the name JNLP Java network launch protocol yes Java network launch protocol was used but now we are using normal SSH connections and that was used because you know if your agent was sitting behind the firewall and so on but now it is preferred to use SSH based agent and we'll see this briefly as we progress. Then we have the sonar cube SG. Sonar cube SG again 22 is used so that I can SSH into Sonar cube and then I have allowed 9,000 so that I can access the UI of Sonar Cube. So this is for SSH and this is for UI. Again when Jenkins interacts with sonar cube it interacts on port 9,000 itself which is why you do not have to allow anything else. Again in production implementations you only allow what is needed. Do not allow anything else. Principle of least privilege everywhere you go. Now launch instance here I will come I'll change this to 20GB. Now when we'll be configuring agents, we'll have that 30GB and I'll explain that to you later. But for now, let's keep this 20 GB and then I will click on launch instance. I'll go to instances and I see this is pending. And while this is pending, let's also create an instance for Sonar Q. We'll just creating this that instance. We'll be configuring it after we have set up the controller and the agent. So let's do that later because I see this one has already started. So I'll click on connect. I'll copy this and then I will go to my terminal and in my terminal I will cd into SSH directory. I'll press ls and with ls you see I have so many keys here private keys here. But I want you to know that this is the one that we will be leveraging. And I know this because I have done the naming properly. And of course at the AWS screen, I chose this. And before I paste this, if I do ls-la, then you would also see that I have given appropriate permissions. I just have 600 for the this key pair. So you would also prefer 600 for your private keys. I'll paste that here. And oh, I have to copy that again. Let me go there. I'll copy this and then I will paste it here. And this is asking me do you trust this? Now this is called trust on first use. We'll briefly discuss this later as well when controller is making connection to the agent. So I'll press yes here. And this is added to my known host file. Now if I connect to this machine any other time it will not ask me to you know type yes or no because the fingerprint is added in known hosts. I trust the destination I am accessing because it is indeed the destination I want to access. So I will go to my GitHub notes now and here let's start configuring. So the permissions part I've also mentioned here. The first thing is we'll be setting the host name because we don't want these generic host names. We want particular host names that tells us what that thing is doing. So I will copy this. I'll paste it here. Exec bash will just refresh so that we see the changes right away. And then I want to change the time zone. understand that this command is changing the time zone of the Linux operating system of this machine. But when we install Java the JVM part, we still have to change the time zone for the JVM part so that when you work with the UI, you see the correct timestamps in your logs to in your UI too. So I will again go back here. Now we'll be installing Java 21. This is JDK. Now understand that there are two options that you have. One is JRE and another is JDK. JRE is preferred when you want to just run Java applications. JDK is preferred when you want to also build the Java application. So JDK is used predominantly by us DevOps and developers. So that we can also do compilation and all other things that JDK comes with. But why are we installing JDK in the controller? Vun, we are not building anything in the controller. We will be building things in our agent. So agent must have JDK. That part we understand. But why do I need to install JDK in my controller as well? The reason for that is Jenkins core and plugins depend on JDK tools. JDK ensures that you have maximum compatibility, stability and plug-in supports because we will be leveraging different plugins and there could be a plug-in which also requires JDK. Hence, in the controller as well, I will recommend you to install JDK. So I'll copy this and then I will go to my terminal and I will paste it there and this will install JDK. Then is the part where we add Jenkins repository. So these steps will add the Jenkins repository and then once the repository is added we can install Jenkins. But before we do that, we are also running pseudo apt update so that our indexes have the information about the latest version. So I will copy this thing and then I will come here. Let it finish and once it finishes I'll paste that onto here. I will paste this here. I'll press enter. And all these steps that you see here are taken from the official documentation. And you can see the reference link here too. Now is the part that I was telling you. Now we'll be setting the JVM the time zone in the JVM as well. So that is what we'll be doing. Now you could use this. It will directly do the changes and we'll let you know. So let's take this one or you can manually just add this part in your you know Jenkins service. I will copy this. This is essentially modifying the you know unit file that is created for Jenkins. So I'll go here. I will paste it here and then it has done its job. And before I yeah let's do these things. So first we are doing a demon reload. Why a dammon reload? Because we have done some changes in the unit file. So it is always good to you know do a demon reload. Then we are restarting Jenkins. And finally we are checking the status of Jenkins. Now I don't know why this these steps are repeated. Uh let's just copy this and then I will also run one more command which is like enable Jenkins so that even if we reboot our system Jenkins service automatically start. So it is active and running. I will hit Q here and I will paste that command and it will enable Jenkins and then I want to check the status of Jenkins again. It says that Jenkins is up and running. So let's go to our browser. I will go here. I'll go to instances. This instance is already selected. I will copy this thing and I will paste it here. And then I will also add 8080. And I will explicitly mention that this is HTTP not HTTP. I'll press enter. And voila, we have the Jenkins screen in front of us. It is asking that you can check the initial password here. So we have already ssed into our Jenkins server. So we'll go here. I will write p sudo cat. I will paste that path here. And here is [snorts] my password. So I'll copy this thing and then I will paste it here. I will hit continue. I'll press never here. And then I will be installing the suggested plugins. Now why I'm choosing this? because it will by default install everything that we need initially. Now I want you to know that in my Jenkins series I have explicitly covered what all these things are and why we need them. But for now just a quick overview we won't be using gradal and or you know LDAP these things we are not using. We would be of course using the dark theme and then git of course we would be using. So understand at this stage itself that the git plug-in is already installed and is again a build tool for Java. Gradal again an advanced build tool for Java especially if you are using Android applications. Pipeline graph view we need and I'll show this to you while we will see how our pipeline is behaving and then there are a few more. So we'll let this finish until that time let's see what we want to do next. Now this can finish in the background. Till this point we have already done what we wanted to do. Now let's start configuring our Jenkins agent. Now again in Jenkins agent I will be assigning 30GB of storage because when I assigned 15 GB of storage I was constantly getting disk issues. This is because all our all your tools that you will be installing in agent requires some storage. And as we progress, you will see why. But at this stage itself, I want you to know that Jenkins is just an orchestrator for you. So for example, if you have to run any commands that are specific to Maven, if you have to run any commands that are specific to Sonar Cube or to Trivy or to AWS or to docker, then you must have those tools installed because Jenkins is just an orchestrator. It will help you move from point A to point B. But to reach there, you must provide Jenkins with all the tooling that it needs. Now since it is our Jenkins agent which will be running all these jobs for us, we must ensure that we provide that agent with all the tools that are required. Hence all these tools may download you know privy may download CVEes to their local database first and then if I talk about Maven if you have watched the Maven lecture you know there is a local repository created and that will also take some storage which is why I would suggest you to assign 25 to 30 GB to your agent because agent will be doing the actual leg work hence agent must be provided with sufficient resources for compute and memory C7 if flex large should suffice. So I'll come here I will select this Jenkins controller action image and templates launch more like this and this time I will call this Jenkins agent rest I am satisfied with most of the things I'll change the security group first I will choose select existing I will remove this controller one I will choose the agent security group Jenkins agent SG and Then here I will choose 30GB and then I will press launch instance. Now I want you to know one more thing very clearly. There is a difference between security group name and the name. This name is the name tag. This is the name of the security group itself. Now if I go to the tags, let's select this agent SG. And if I go to tags, I don't see any tags here because I have not defined the name tag. That is why I don't see anything or I do not have any other tags as well. But this is the security group name itself. This is not a tag. So this is a nuanced difference. Most of the folks do not understand. There is a difference between a tag and the actual security group name. And this you know this changes if I move to my instances. So if I go here the name that you provide while creating the instance is actually the name tag. So if I move to tags you see the name tag is added and the value for that tag is Jenkins controller. So understand this nuanced difference. I'll go to my agent VM now and here I will click on connect. Then I will copy this and then I will go to my terminal and what we have is it has named this one Jenkins controller which is what we wanted. I will press CtrlT so that I get a new tab. I will zoom in a little here. I will cd into SSH because that is where my private key is. I will paste that command. This will work because this key is in my working directory in my current directory. Now if you have this somewhere else then you may have to provide that path not may you will have to provide that path. I'll press enter again. T O FU trust on first use. I will say yes and then I will clear my screen. Again we'll follow the steps from our documentation. That documentation is golden. Not just for this demo but as you are working in production grade projects. You can always come and refer this for creating or dismantling any infrastructure. So here let's move to our controller step. This is SSHbased Jenkins agent on EC2. We are here. Let's run this command. Here we are setting up the host name. Host name is Jenkins agent which is explanatory. Then we'll set the time zone. And then we'll scroll down again. We'll install Java 21. And here as well we need JDK. And we know why we need JDK because it is the agent who will be building the apps. If you have Maven, Maven will require Java underneath and Maven to perform the compilation for you, to perform the packaging for you, to perform the verification for you. It will require Java 21, not 21. It will require Java development kit that is JDK. Now I want you to clearly know that you will not use random users to perform tasks. You would want that all your Jenkins tasks are performed by a user that you explicitly create for Jenkins. So I will not be running my Jenkins tasks using this Ubuntu user. I will create a separate user Jenkins so that that user is the one that is running commands for me. So I will copy this. I will paste this here. And you have detailed comments in my you know GitHub repository so that you know what we are doing here. M says I want the home directory for this user. S says the shell for this user will be bash that is the born again shell. Now our Jenkins agent till this stage is kind of ready because Jenkins agent just needs Java installed. That's it. But we have not told the controller that this is the Jenkins agent. Now to do that thing we first have to you know have some sort of connection between the controller and the agent. So first I want you to understand that connection. So I'll take you to my diagrams and then I will take you here. Now again I have discussed the mutual authentication that happens in SSH in a greater detail if I talk about my Kubernetes TLS section. So if you want deeper understanding then you can always watch that. But here I will explain that to you very briefly. So here is our Jenkins controller that is running on an EC2 instance and here is the Jenkins agent which is also running onto an EC2 instance. So we have configured both of these. Now we want to SSH from our Jenkins controller to our Jenkins agent. To do that, first we will be generating a key pair using SSH key gen utility and we'll be generating this key pair in the Jenkins controller itself. Now once the key pair is generated, what we will do is we know that my key.pub which is the public key of the key pair that we generated. So this is the key pair we generated and we generated this key pair in the SSH directory itself. Now you would be thinking why is this var lib Jenkins? I want you to know that if I talk about Jenkins, the default Jenkins home is vib Jenkins. But the user that we manually created in our agent, the home for that user will be /home/jenkins itself. That is what we expect. If I create a user var, then the default home would be /home/vosh. Similarly, if I talk about Jenkins, what it has defined in its configuration is the home for me will be vib Jenkins. As simple as that. Now, since its home is this, our SSH directory will exist here and then here is where we'll generate our key pair. Now, if this directory does not exist anywhere, we will create that. But for understanding we are saying that we will be creating these key pairs in this directory. And once this key pair is created we know that this public keys information this public keys data must be available with the Jenkins agent in the authorized_keys file. So what we will do is we'll be creating this key pair. Then we'll be copying this key onto our Jenkins agent. As simple as that. Once we have done that, Jenkins controller can SSH into Jenkins agent by using this private key. and Jenkins agent. The SSH HD demon that is running in the Jenkins agent can identify that indeed the private key presented by the Jenkins controller is associated with the public key that is already there in my authorized keys file. As simple as that. So we'll be doing this now. Few bullet pointers. Jenkins controller acts as SSH client. We know that because this is the one that will be initiating the communication. Second initiates communication and the one who initiates communication is called the client and towards the entity for which the connection is initiated is called the server. So this is the client, this is the server and then lastly runs build via SSH agent. So whenever we areuling a job and running that job, Jenkins controller will be asking this Jenkins agent to run that job. So Jenkins agent acts as SSH server, receives public key, executes pipeline steps. We know that. I hope this understanding is clear. Now let's go to the GitHub repository and while I do these things, you will understand them in a better way. Now generate SSH key on the controller. Now I want you to clearly focus on one thing. What I'm doing is I will be generating these keys and I will be accessing this as the user Jenkins. Now what is the significance of this? Now the Jenkins user created in our controller will be the one who will be generating these keys. I don't want to use that Ubuntu user. I want to do things like we do in production implementation. So I'll copy this one. I will go to my terminal. I will go to my controller. And here I will clear my screen for better visibility. I'll paste it here. And you see the key part. We have you know logged in into this one because we have typed pseudo su-en jenkins. We have logged in as Jenkins user. If I press ls, you see these are all the details about my Jenkins home. So these are all are the things that are available in Jenkins home. Now if you have watched my previous lectures on Jenkins, you will understand what all these things are. But for now I will just write ls-la. You see SSH is not yet created here. So let's do that thing. So I will do mkdir. SSH and then I will cd into SSH. I will do ls. I don't see anything here. Now what I will do is now I will be running this command because this will make sense once you have SSH directory. So I will copy this. I wouldn't have to you know enter in here because I am using absolute paths here not relative paths. So I will press enter and this has started the process of creating this key. Now I want you to understand this command as well. This is just a comment that we are adding and we are saying the algorithm that I want you to use is ed2519- f is this is where I want my key to be located. So I will press enter. I will don't I will not assign a passphrase. I will press enter again. And if I do ls-la, you see that I have a public key here. And this public key needs to be transferred to our Jenkins agent. Now again, I will just be catting this file and copying the content and pasting it there. But you can also use SSH copy ID and so on. There are plethora of options to copy a file from one Jenkins server or from one Linux host to another Linux host. Since this is not not a Linux course, I won't go into telling you SCP commands and SSH copy ID. For simplicity, we'll just be copying the contents and doing our job. So, we'll copy it in a little while. But first let's see what we want to do in our Jenkins agent. Copy the public key to agent VM. So here we are saying this just copy the file and on the agent SSS session already open switch to Jenkins user. Understand that we just created a Jenkins user in our agent as well. So what we want to do is we want to leverage this Jenkins user to perform anything Jenkins. Now I want you to know that when controller accesses our agent VM, it will be using this Jenkins user. So if I want to SSH into a destination, I must provide a username that exists in that destination. So the destination for my Jenkins controller is this Jenkins agent. And I am saying when you access your destination you must use the user Jenkins which is why we have created this user Jenkins so that everything Jenkins is done via the Jenkins user. So I'll clear this for better real estate and then I will just create a file here. So what I'm doing is I'm first logging in using the Jenkins user. So sudo su-en jenkins and once I am here with the Jenkins user in the Jenkins agent VM then I will run this one. I want to create a directory SSH and then I want to create a file that is called authorized key. So I'll press enter and voila I am in the file. Now I will come to my controller. I will cat the Jenkins agent key dotpub. Here I'll press enter and this is my public key. I will copy this public key from here and then I will paste this public key here. I will press escape shift zz to save this file. Now let's see what we want to do next. Here is we are setting up the permissions. Like I told you 60 is good for you know these files these key files so that only the user has the permissions not others and groups and then here I'm doing it same for the directory SSH is a directory authorized_keys is a file I'll copy this and then I will just paste it here and I'm on the agent VM that is where I want to run this I'll press enter and this has done its job. Now let's go here. Now we have to test this connection from the controller. Test the connection. So what I'm doing is pseudo su as Jenkins user. I want to SSH into my Jenkins instance and I want to run the command host name. So let's see whether this works or not. So when we run this command, we should see Jenkins agent, right? I'll copy this one. I will go to my terminal. I will go to my controller. I will paste this here. And here understand that our key is located in Jenkins home in the controller. And in the controller, the Jenkins home is where lib Jenkins. So I'll go here and here is the placeholder for agents public IP. I'll go to my console. I'll go to my browser and here I want the public IP of my agent which is this. I will come here. I will paste that here. I will press enter and I want you to pay clear attention here. This is showing the fingerprint and saying do you trust this as in it is asking you to verify whether this fingerprint is for the server or not. Now I am not going to do that verification for now. That is why I am just pressing yes. This says trust this on first use and then continue to trust this until this identity changes. So if you let's say are not using an elastic IP and if you just stop this Jenkins agent and then start it tomorrow or start it after a couple of seconds then this public IP will change and when this IP changes you will again have to do this because the identity that you trusted here has changed. So understand these nuances of SSH it is of paramount importance. I'll press enter. I'm trusting this and it has shown me the host name. So SSH works and we are good. Now let's go to the notes and see what we want to do next. You have sshed from controller to your agent. And that works. But how does the controller know that where we ssed is actually an agent? We don't know that the controller doesn't know that. So we will have to tell the controller that the agent where the jobs will run is this. And that is what we will do now. So we will go to the Jenkins UI. Finally, we will create a user cloud with VJOS. Let's call it that. And password. Let's give it a secure password. I will give the same password here. name is Varun Jooshi and the email is cloudwithvosthegmail.com and if you have any feedback if you want to share anything personal then feel free to communicate with me on this email address cloudwithvos at the rategmail.com I will click on save and continue now this is the Jenkins URL again when you are dealing with production implementations you would have a DNS name for your Jenkins URL and that DNS name will obviously point to an IP address and that IP address even if it changes although it wouldn't but even if it changes for your specific use case or for your specific implementation then the DNS name will always remain the same. Hence it is recommended what you provide in Jenkins URL should be persistent because if you are running certain post actions post actions as in once your pipeline runs you do this you could be sharing these things these URLs with your teammates or with your let's say team leads who when click on this URL will directly be taken to the logs page or to the Jenkins URL which is why it is important that you provide a functional URL that remains persistent. Now, because if this URL changes, you will have to update this URL in the UI. It is doable, but it is recommended you choose a persistent name here. So, always access your things using DNS names, not IP addresses. I'll click on save and finish. Start using Jenkins. And firstly before I go blind I will be changing this appearance to dark mode so that we can work safely. Yes I have changed it to dark mode. Now if I go here I just click on settings. I can click on set up the agent from here as well or I can click on nodes and configure my agent from there. So I will click here and here I will click on new node. What is the name of the new node? Let's call it Jenkins agent. You can give it any name. This is a permanent agent which is fine because this is the one that it will be there forever in at least our scenario forever as in till we do this pipeline. And I'll press create here description you can add it number of executor. What this means is how many jobs can this you know agent run in parallel. Now since I have vCPUs two vCPUs I can choose two here so that we can have parallelism here. But if you do not want jobs to run in parallel you can have one. If your agent has let's say 20 CPUs then you can even have 20. It doesn't have to be onetoone with vcpus because this decision is subjective and will depend on what sort of deployment you have. So for now I will just choose one exeutor here because we for sure will only be running one pipeline at once and number of executors one should suffice and I also want to go to the Jenkins our repository so that I can see the steps here as well. So name Jenkins agent type permanent agent. I've written everything here so that you can work in peace. Here Jenkins remote root directory. Now here you would specify the directory where you your workspace will be created. So workspace as in when you are running a job when your agent runs the job it will create a workspace and workspace is like a scratch directory. So for that we have created the home directory of Jenkins user. We would want to create that. Now again extremely important permissions are of paramount importance. We have created a user Jenkins right in our agent VM and we are providing the home directory of the Jenkins user itself. So whenever our controller accesses our Jenkins agent using the username Jenkins which is already there in our Jenkins agent, it will by default have access to its home directory. So it is important that you take care of permissions. It's not that you can provide any path here. Provide the path for which the Jenkins user has full access. So I'll write this here. Then labels. See you can call it anything but I like to be descriptive. Hence I will provide this name Docker Maven TV. Now this will have other tools as well like cubectl or maybe eksctl or definitely AWS CLI but for now we are providing it this label. I'll come here. I will give that label here. Usage use this node as much as possible. This is fine. Launch method is launch agent by connecting it to the controller. And here is the part where I'll change it to launch agents via SSH. And then it is asking me to provide the details. Again, it is asking me to provide the details of the agent. Here I could provide the public IP address of my agent. But that is not how you would do things in production. In production, you would supply the private DNS name for your agent so that your controller doesn't have to walk miles to reach your controller on a public IP. And when you are using a public IP, the traffic from AWS first goes to the internet, then to your instance. And we don't want that. This is an internal traffic. We want this to stay internal. Hence, we will provide the private IP address of the Jenkins agent here. I want you to clearly know that you would be using private DNS names in production. So, you could be using this name. But for this demo, I will be using this private IPv4 IP of my agent for my controller to make connection to it. So, I'll come here and then I will provide this IP here. Now it is asking for credentials. Now credentials as in how do I connect to this host and remember we are connecting by supplying our private key. So we'll have to provide the contents of our private key to this UI so that when controller is connecting to the agent it can do so seamlessly. Right folks. So here I will click on add Jenkins. This is global credentials. This is fine. And here [snorts] is the part where I will choose SSH username with private key. It just if you understand the concepts these things will come automatically to you. We have created public and private keys. Hence it is obvious that we will be choosing SSH username with private key here. Here it is asking us for the ID and the ID that we can give here is Jenkins agent which works fine for us. Username we know what is the username. Username is Jenkins that we just created. private key on passphrase. We have not given any passphrase that is fine but enter private key directly. And here we can click on add and here we have to add our private key. So let's go back to our terminal and copy our private key. So we are already in the Jenkins controller. We are already logged in as Jenkins and then we are already in SSH. So if I press ls you see our private key is this one. So what I can do is I can write cat Jenkins key press enter and this is our private key. Now your private keys must be private. Do not do screen sharing or do not share them with anyone. These are meant to be private. So I will copy this. I will come to my Jenkins UI. I will paste this here and then I will click on add here. Now this is added and here I can choose those credentials. This part is done host key verification strategy. Now I will be choosing the first one known host file verification strategy. And what is this strategy? You remember I have been telling you whenever I'm trying to access something for the very first time, it is asking me to press yes. If I accept the fingerprint, if I trust that indeed the server that is I'm communicating to me has this fingerprint and we have been adhering to trust on first use. Again I would tell you that in our Kubernetes TLS sessions I have demystified this in greater detail. If you want to look at it go and check that out. But for now what we have to do is if I choose known host file verification strategy which is what you would be choosing in production scenarios and then keep this agent online as much as possible. I'll click on save. Okay, now let's see what happens if I go to my Jenkins agent and I go to my logs. It is trying to launch the agent. First is you can see these logs here. Let me zoom in a little. It is trying to launch our agent which is all right. But if I go to my logs here, it says key exchange was not finished. Connection is closed. Trying in 15 seconds. There are nine more retries. So it is trying to access that but there is no one who can say yes which is why it is again and again failing. Understand we did press yes once but that yes was only provided for this public IP but the identity changes if I am authenticating to my agent using the private IP address of my agent. Hence I must first press yes with the private IP and that is what we are going to do in this stage. Everything is connected guys. Now I'll go here. I will again copy this private IP address of my agent. I will provide that IP here. And I want to show this to you in parallel. So if you go here, the Jenkins controller is still trying to connect to our agent. Okay, here. Now I'll press enter. Now this is again saying the same thing. Do you trust? Because this fingerprint is based on the identity of the destination. The identity changed because our Jenkins controller is using a private IP which is why it is asking us to provide these credentials. I will say yes to say yes to the fingerprint. I'll say yes. Press enter. It is added. If I go back here, it should now connect because in the known host files in my controller, I have an entry for Jenkins agent and it says launch failed. Let's wait for some more time and see how it works. So, let's go here again and let's click on launch agent again and let's see if this works this time or not. Let me also see if I've missed any steps. Okay, this is fine. This is also fine. Yeah. Yes. So, we used this strategy and I mean we scanned it with this. You could also use SSH key scan to update the fingerprints. Let's see if it worked now. Log says launch failed. SSH connection closed. Let me go to configure home Jenkins. Use this node as much as possible. Launch node is credentials is Jenkins and known host file is file verification strategy. This is fine. And yeah, this is correct. log launch failed me launch again but if it works from the CLI it should work from there as well if I do ls- l if [clears throat] it is working from here then it should work from there as well yeah ls-l is also working lf a is also working so if I go again let me see If I have configured the username correctly, it's username is here. Credentials. Where have I configured the username? Well, let me just reverify these credentials, guys. I will go to credentials. I'll go to system here. Global credentials. Jenkins agent update username Jenkins is fine and then key is also fine a replace let me let's just see if it is working now and this This is strange. Let me try to home Jenkins. This is fine. Agent IP 3464. This is also fine. And here I was trying to update the credentials. Let me let me you know try to enter that again. I will come to my terminal. I will ls cat jenkins agent key. I'm not sure why it is saying the format is not supported. SSH authentication successful connected online. I really have no clue what happened. I just entered that private key again and it started working and previously the error was also quite off. It was saying that algorithm was not supported and we used the supported algorithm anyway. So now that our agent is successfully connected, let's see what are the next steps. So here install Jenkins controller. We are done with this. Done with this. We are done with this. Yes, we are done with this as well. Yeah, we are done with this too. Configure agent UI. Done with this. Now we want to install sonar cube. So I'll go to instances again. I will click on the controller one action image and templates launch mode like this. And here I will supply sonar Q. And then I will come down. This is fine. Ubuntu is fine. This is fine. Existing security group. Yes. But this time I will choose the sonar cube security group. 20GB is fine for this. And then I will click on launch instance. I'll go to instances and then I will choose sonar cube and then I will wait for connect to appear. And till that time let's go to our documentation. Same thing C7 I flex large 20GI then the security groups we have already seen and we will be starting from these steps. So I'll go to my instances, click on connect, copy this. I'll come to my terminal and here I will press CtrlT. So the first tab is for controller, the second is for agent and the third one is for sonar cube. So in the flow in the sequence like we configured, I'll cd into SSH. I will zoom in a little here. I will paste that command here. Press enter. I will say yes for the fingerprint. And now you know why this exists. I'll press yes. And I'll clear my screen for some real estate. And then I will go to my browser. I will go to instances. I'll go to my documentation. I will start with setting up the host name. I'll paste it here. Then I will change the time zone. I will confirm the changes are implemented. Asia, Kolkata. I'm in India and then I will copy this and this is the key part here and you press enter first. We are installing JRE here not JDK. Why is that? This is because Sonar Cube requires Java runtime to work properly and we are not building any application here which is why we are good with just JRE. I'm using version 21 throughout of Java be it JDK or JRE and then I will scroll down and here is a typo you would see Java 17 because Java 17 was the one I used before anyway. So let's scroll down install post gray and create DB for sonar. Now this is a one-time activity. What we are saying is the sonar cube instance that we are running we want the database to be hosted onto postgres SQL. Now ideally what you would see in production is there is one virtual machine that is for sonar cube and then there is another virtual machine that is a DB machine and DB VM will hold your databases. Now we are not going to this level of bifurcation. What we are doing is we have a virtual machine created but within that sonar Q virtual machine we are creating a database for sonar cube. So in production you would be using a different database and then you would tell sonar cube how to reach that database. In this specific scenario which we are using, I will just say local host. But if you are hosting your database separately, then you provide the identification information of the database instance that is hosting the sonar cube database. And here we are installing postresql with common extensions. We will enable postresql and then we will start postrql. So I'll copy all these commands. I will go to my terminal. I will paste those commands in the Sonar QV VM. Press enter and this will start installing and running Postgress SQL. Now I will go to Psql. Psql is the CLI for Postgress SQL itself. So I will copy this and then I will paste it here. Now you will see a Postgress CLI. Now I will be creating my database along with a password. I will be creating a user sonar with password sonar. And why I'm doing this? So that when my application tries to access the this database, it can provide the authentication information which I am creating right now. So I'm creating sonar user and that sonar user will have sonar password. These are DB users. So I'll copy this. Remember to copy the semicolon as well. So I'll paste it here. It will tell me create role. And then I will create a database. And I'm calling that database Sonar Cube. And who will be the owner of that database? Sonar user will be the owner for that database. So I'll paste this here. Hold on. I didn't copy it properly. So I'll copy this and then I will paste it here. And this will say create database. Now I will go to this section which will grant all privileges on database sonar cube to sonar user. Again the password that I'm also using for this is sonar. So username is also sonar. Password is also sonar. And quick verification. And we can run this verification. So first let's do one thing. We will quit from the postress CLI. I'll enter this. And this is telling me yes sonar is there. And in the second step we'll verify that the sonar cube db indeed exists. And yes it exists because I can see it here. So I will quit this one. And then this will not result in anything because right now we do not have anything in our database. So instead of strong password here placeholder let me write sonar. And this will tell me that did not find any relations which is all right at this stage. Now what we will do is we'll be tuning in certain sonar Q parameters. Now this all things are there in the documentation. I don't want to bore you with what I'm doing but understand that you will be tweaking certain kernel level parameters for sonar cube to run properly. And then as I always do create a user for sonar so that anything that sonar is doing sonar cube is doing that sonar user is being used. So I will copy this and then I will paste it here. Again in the comments you can read thoroughly what we are doing creating a dedicated user for sonar with its home directory at oparq. Now there are various download options for sonar cube. I am using a community build. You have different editions in production based on what your requirements are. You can choose the version that you need. So for now I will cd into temp. I will download the sonar cube zip. I'll call it sonar cube zip. And I'll be downloading version 25.11.0. And I think this is the patch release or something. And then we'll be installing unzip first because we are downloading a zip package. And then we will move it to this directory. And then we'll be changing the ownership for this directory. So I will copy this and then I will go to my terminal. I'll paste all these commands here and then I will scroll further down and then we are saying p sudoy-enu with user sonar we want to edit the sonar properties and it is in the sonar properties that we provide the username and password that we created a while back for our postgray instance understand that here we'll be telling our sonar cube application to reach out to localhost port 5432. But if you host your database separately, you will add the identification, the DNS name or the IP address which is not recommended for your database instance. I will copy this thing from here and then understand that we are editing it via the sonar user. So I will press here and then I will press enter and here is the file. I'll press I to go in the insert mode and if you see user credentials are to be provided here I will uncomment this first and then in the place of password I will write sonar and username I will also write sonar. And here is the critical piece. Now I wanted this to be production-like which is why I am not using the default embedded H2 database that is you see default here which could have been used for development work or for you know lab demonstration but I wanted this to be as close to production as possible which is why I am using postress SQL. You also have option to use Oracle or Microsoft SQL. And all these three options that you have including postress SQL are all relational databases. Again, you could use a self-managed database here or you could be using a managed service by cloud provider. For example, you could have also used Amazon RDS for Postgress SQL here. Here first since we are using Postgress SQL I will uncomment this and then I will have to provide the path here. So till local host it is fine. Then I will add the port number which is 5431 5431 slash I'll go to my documentation and then I just have sonar cube forward slash sonar cube. Now I will hit escape shift ZZ to save this file. Now that this file is saved, I have to create a unit file. Now what is a unit file? Unit file defines a service. So we are creating a unit file named sonar cube. Now this is just a small configuration file that tells OS how to start, stop and manage a service. So if you see here we are telling it how to start, how to stop and how to manage other things about the service. So we are saying if it fails you restart it. Then it also tells us what it depends on. So this is a Linux topic. So I will leave it here. Here we are creating a unit file. So I will come here. I will paste it here. Then I will copy this content. I will go into insert mode. I'll paste it here. Escape, shift, zz to save this. And then I will scroll down. Then damon reload is fine. It will read all the files in the unit file location, which is this one. You know this location. And there are other locations as well, but that is outside of this scope. Then we'll enable sonar cube. We'll start cube. And we'll finally check the status of sonar cube. Now if you go to the GitHub documentation, I have written all the steps that are to be performed and what is the significance of those steps. Of course, I cannot cover everything in the video because if I do that, that will become a course in itself. So that is why I like to keep my documentation detailed so that most folks can get all of their answers within the GitHub repository itself. But if you need more information then of course at the very last of my documentation you would find references which are typically official references which you can read to gain more understanding but for now our sonar cube service is running and we all are happy. So let's go to our browser and then I will sign in again. Why did it sign me out? Anyway I will sign in again. I am in my instances. I'll go to sonar cube. I will copy the public IP address of sonar cube. I will write http and then forward slash slash. I'll enter the IP. Sonar cube listens on port 9,000 by default. I'll press enter and it is not working. Congratulations. Is the IP correct? Yes, the IP is correct. Uh why it is not loading? Have I associated the right security group with it? Yes, I have. Port 9,000 is allowed. Is it adding HTTPS by default there? What's the problem? Let me check the status of the Sonar Cube service. It's running, man. Oh, inactive. Let's try to restart that again. Sonar cube is active. I want to check the status again. Code this is fine. Sonar cube current this sonar.sh this is fine. Let me go to my GitHub documentation. Let me see if this is loading anything here where there could be some error from my side only. Hold on. Let me try to run this. And I want to run this one. I ran this previously. Does it have it in its history? It may, but let's do it like this. And here I will write sonar. Oh, it doesn't see anything here. H what I've done is I've also added troubleshooting steps. So let's go to the browser and then here if I scroll down further down further down further down. Yeah. So let's check the logs and because all these things are stopping in sequence. If I run free age used free is there. Let me run that kernel parameter tweaks again. Um I think those did not run properly. Do piston ctl restart n cube. If I stopped again, let me check other logs. I'll go here. So now let me check the web logs. connection to local host. Check the host name and TCIP connections. Hold on. I think there is some problem with the sonar cube configuration sonar.properties. So let me quickly verify that this file. Let me just see if we have entered everything correctly. It's fine. Sonar sonar and this is postress SQL. And if I come here, we had to write 5432, not 5431. This was the problem, guys. I'll save this and more troubleshooting. Right. sudo system ctl restart sonar cube and this time it should work and let me write status. So that's why reading logs is important. So it gave us exactly what we needed. It said this and then we reached this conclusion. If I check status s a t us I have to spell it right. Status is now running. If I go to browser and then I hit refresh. Perfect. It is working. Now the username and password the default username and password for sonar cube is admin. Admin. So let us allow it some time. Home. Yeah. admin admin so we'll log in here and then never old password is admin new password I'll set a secure password here press enter and this I will do never later so now our sonar cube instance is ready now we have all the three components that we need ready so Let's start with the demo. If I go to my diagram, I will take you to this screen. So first step is check out from private git repository. Now for that we first must have a repository. So I will go to this screen. I will go to my browser. I will go to this screen. Then let me go to the top here. And then from here cloud with VJosh. And then I can close this one. This is not needed. I can close the YouTube link as well. And here I will go to repositories. Now let's click on new. This repository I will call cloud with vjos private repo. This will be private. Here I will scroll down and click on create repository. And now we have a repository created which is private. But I want you to clearly know that when you create a private repository, you need credentials to access it. So now we will be creating credentials that we will use to access this repository. So I'll go to settings. I'll scroll down go to developer settings. And here I will go to personal access tokens. And then I will go to tokens classic. Here I will choose generate new token. generate new token classic and I will call this token Jenkins GitHub so that I know what this token is used for. I will choose repo here and then I will scroll down and I will click on generate token. Again do not show these tokens to your folks or colleagues. It is supposed to be private. I will delete these credentials before uploading this video. So I'll copy this and then I will go to visual studio code and here I will just create a new file in the root itself and not here I would rather create this file in project files new files and I will call this creds and in this creds file I will just paste it you don't have to worry about rest of the details that are here we'll dissect them but for now just to this. Copy this here. Let me explain the code to you. So I will go to Java Maven. This is where I'm holding my code. So I have the src directory and src has main and test. As we know main will have my actual application code which is in the file named app. Java. And I have added some vulnerabilities so that I can demo this to you at a very high level. This code will just be displaying cloud with varos simple dev seccops demo. And then there are test frameworks that I have defined. I have defined the JUnit test framework and I have also defined a couple of test cases so that we can also see how code coverage behaves and then I have my pom.xml. I have a simple pom.xml. I won't be explaining this pom.xml to you because we have already covered this deeply in our Maven lecture. So this is our code. Now I want this to be production-l like which is why we will be committing the source code onto our GitHub repository side by side. But one point I want you to understand that I will be using this token for my Jenkins to interact with this and I am acting as a developer and I am also using this GitHub token. But in actual production you will have two different tokens. One token will be used by Jenkins and another token would be used by developers. So with that understanding let's start our work. So I will go to the terminal first because I want the code to be in my GitHub repository. So we will start by creating a new tab. And in this new tab what I will do is I will cd into courses and here jenkins and then this is common and java dot maven. So java.m maven is the directory that holds my src and pom.xml. So if I press ls you see pom.xml and src. So if I run tree you see I have app.java Java in my main directory and I have app test on Java in my test directory which is the standard structure that Maven would create for you and I have the pom.xml in the root itself. So first things first I will run get init. So get init will initialize this as a g repository and then I will write get add dot so that all the files that are currently untragged will be tracked by git and then I will write get commit- m and then I will call this commit initial commit with code and pom.xml. So always have meaningful messages. I will press enter. And then if I write get branch-v then you would see my current branch is called master. But if I talk about GitHub they would have named my branch main. I like to keep things consistent which is why I will be renaming this from master to main. So I will write get branch- m and I will write just main here. So if I run that command again, you would see my branch is now renamed to main. If I write get status here, you see nothing to commit. We have a working tree clean. So because we have already committed this initially. Now what I want is I want to add a private repository. So for that what I will do is I will write get remote add private repo and then the URL of that repo. So I will have to spell this correctly. I'm calling this private repo. You would have seen a lot of folks use origin here and which is fine but I like to keep the name meaningful which is why I have used private repo. Now I will go to my browser. I will go here. Here where I've created my private repo. I will copy the address of my private repo from here. And then I will just simply paste my repo URL here. I will press enter. Now once I have done this, I have not provided any credentials yet. Okay. If I try to push it, it will ask me for the username. So for that what I now want to do is I want to provide some credentials. So that is what we are going to do in this step. So what I will do is I will copy this and then I will come to my visual studio code. I will paste the command here and then I will copy this token and the placeholder I will paste this token here and then I will run this command in my terminal. Now once I do this now I can perform my pushes. I will write get push private repo main. I'll press enter. And then if I go to my browser now and if I hit on code again or you can hit refresh you see we have src and pom.xml and this is what you will see in your repository. Now as we progress we will update this. Now that we have done this let's create our first job. I'll go to I'm already in my browser and here I will go to dashboard new item and I want to call this job cloud with varosh dev sec ops demo and this will be a pipeline job. I'll click okay. Now at this stage itself I want you to know one thing very clearly that I am using the main branch but in production main branches are often protected. See I cannot cover everything that is used in production in a single project. So what I have done is in this project I have focused on security and both DevOps and I've tried to maintain that balance but I already have a lecture in my channel that tells you how to work with multi-branch pipeline jobs. So you can always watch that lecture if you want to see how the branching strategy in production works. And again like I told you before as well if you want full understanding then you should also have watched the SDLC life cycle the branching strategies and if you go to my Jenkins playlist you will find first two lectures they are not relevant to Jenkins only they are relevant to CI/CD in general. So there we have discussed how branching strategy works in production, where you should keep your code, what are feature branches, what are release branches and so on. So look at that. But for now we are creating a pipeline job and we will be working with the main branch itself. Now I will scroll down and here I will choose pipeline script from SCM. Why pipeline script from SCM? because what we will be doing in this demo is we will be doing this production style. So our Jenkins file will exist in our repository itself and then in SCM I will choose git and now we have all the things floated. I'll just move this to this space and this I will move here. And now it is asking for repository URL. Repository URL is here. I will copy this. I will paste this here. And credentials, I will choose Jenkins. But Jenkins is not the credentials for this. Jenkins were the credentials for our Jenkins agent, not for GitHub. Now for GitHub, we have used the credentials in our CLI. But now Jenkins will also need access to our repository if it has to check out. So if you look at the first stage of our pipeline, it is to check out from private repository. If Jenkins must perform that check out, Jenkins must be provided by the credentials. You have to engrave this in your mind. Beat whatever CI/CD tooling you are using, your CI/CD tooling is just acting as an orchestrator, you will still have to integrate different tools in your pipeline so that whatever you are trying to do, you can do those things. So I will go to my browser again and this time I will click on add Jenkins kind of will be just secret text. Now when I talk about GitHub kind will be username with password. So when I talk about GitHub, GitHub expects the username along with the token. Which is why we are using username with password. Now why I'm mentioning this distinction is because if I talk about sonar cube there we will just use secret text because sonar cube is not expecting the username. it is just expecting the token and based on that token it will figure out with which user that token is associated but with GitHub you provide both username with password so I'll click here I will keep the scope global so that my pipeline can also access these credentials then I'll scroll down username would be cloud with varosh that is my GitHub username you will have to choose yours and in the password section section I will have to paste the GitHub token. So I will copy this from here and I will paste this token here. ID would be GitHub pat that's a cool name GitHub personal access token. I will click on add. Now as soon as I choose those credentials this red mark should go. If the red mark still says that implies your token has anomalies. So fix it and provide the right token. And here is the branch specifier. My branch is main that is why I will write main here. Again if you want to know about multibranch pipelines then you should refer to the lecture that is already there in my Jenkins CI/CD course. I will click on save here and then let's click on build now. Firstly, I want you to notice that it is showing the current time. And why it is doing that? Because we changed the time for both the operating system and also for JVM. So if I click here, I can go to the console output and it will tell me why it failed. Now it is saying unable to find Jenkins file from kit and this failure was obvious. Now whenever we are running a pipeline job we supplied that the Jenkins file you will find in the root and that file was not there. So if I go to my repository there is no Jenkins file here which is why this job failed. So if I go to configure section and I scroll down, it was looking for a Jenkins file. Now if you have not named it Jenkins file, you can provide that custom name and custom path here and it will look for that file. But here we are keeping the things at default and that is what it is recommended you keep the name Jenkins file itself because your repository is private anyway. So you have Jenkins file but we have not supplied the Jenkins file. So let's start the coolest part that is writing Jenkins file. So I will go to my visual studio code and always use an IDE which understands Groovy JSON to write these files so that you get color coding and I will show you why this is so important in a little while. So I'll right click on Java Maven. I'll click on new file here and I will call this new file Jenkins file and I'll press enter and let's start writing our Jenkins file. Now the first things first I will write pipeline. Now pipeline is from where everything starts. So whenever you are dealing with Jenkins file, you start with pipeline and I start a curly brace. And as soon as I add one curly brace, my ID is intelligent enough to know that he would also need a closing curly brace, which is why it added that. I will press enter. Now let's write the first thing that we want to do. We want to tell our pipeline that the agent that you should be using to run this pipeline or to run this job, what is the name of that agent? I will not be supplying the name of that agent. I will be supplying the label associated with this agent. Understand that for my entire pipeline I'm just defining a single label which implies the agent that has this label will be running everything in my pipeline all the stages of my pipeline. You can have different agents with different labels and then these labels or these agents can be called at different stages of your pipeline. For example, you may have an agent that only has cubectl. In that scenario, you would be using that agent to run cubectl specific commands. Maybe there is an agent that has Maven, sonar, cube and so on installed. So to run those kind of jobs, you assign that label, assign that agent. But in our example, we will be using a single agent which will be running our entire pipeline which is why I'm defining this at the pipeline level itself. You also have the functionality to define the agent section or the label section within a stage as well. So with that understanding I will write docker maven and privy. understand that this name must match the name that you defined here. So if I open this one, I go to this agent, then you would see this one I called docker maven tree which is why docker maven trivia. Understanding this piece is critical my dear friends. And then let's do one thing. I will press enter. And now I want you to see the important piece. I will write stages here. stages is a plural which is why I can have multiple stages. So I open a curly brace. Press enter. Now inside pipeline I have agent and stages. Agent and stages are at the same level. But now we want to add multiple stages. Hence we must define different stages within the stages block. For example, I will start with my first stage. And the first stage, what I'm calling my first stage is privy file system scan. Understand that within stages, we have the stage block. But within the stage block, we will have to do something, right? We'll have to perform certain steps within the stage block. And what those steps are? we define within the stage block. So in this stage I am performing certain steps and in this stage I will only be performing one step which is sh is calling the shell. I will write privy fs exit code one severity high critical and a dot. What does this mean varun? Firstly, we are telling our pipeline job that the first thing that you need to do is you have to assign this job to an agent that has label docker maven trivia. And once you have found that agent, you run this stage onto that agent. And that agent will be running this in its shell. Understand? We are defining in its shell. And what is the command that it should be running in its shell? It is trivy file system exit code one severity high critical. Now what we are saying with this line is if there are any vulnerabilities that have high and critical associated with it then I want you to fail this pipeline. fail this pipeline because any exit code but zero implies failure. So we are saying you fail the entire pipeline if there are any high or critical vulnerabilities. Now again important thing is to understand how this syntax is working which is why Visual Studio Code is so powerful or or any IDE that supports this color coding. See steps has green curly brace right. If I click on green curly brace it tells me which one is the closing curly brace. So that is the color coding that you get. And you also see it is showing a box outside this. And this box signifies that this opening curly brace is associated with this closing curly brace. So if I click on this pink curly brace, it shows me it highlights the opening curly brace. Similarly, if I check this closing curly brace, it tells me its association of the opening curly brace that it is associated with. So you get two things. First is color coding and then you get this identification because as you progress you would see that there could be multiple white curly braces. Then this box helps you identify which one are the pair of opening and closing. So this is important to us. This one you see pink is here as well and pink is here as well. So you know this opening curly brace is associated with this closing curly brace. So keep that thing in mind. Now let's get rid of the syntax. Can we run this command? Let's try actual production workflow here. Jenkins file is in the root of our repository. So if I go to my terminal and I run ls, it will show me that right now you are not tracking this file. Uh why it is oh if I write get status I'm sorry if I write get status it will tell you that Jenkins file is not being tracked right now. So let's do one thing. get add dot and then let's add get commit- m added tree stage. Let's just write this for now. I'll press enter and then I will write get push private repo main. I'll press enter. Oh, sorry I have to spell it right. Private repo main. And this will push it. Now if I go to my browser and I go to my private repository, I hit refresh. I see Jenkins file now exists and it was pushed you know now I will now go here. I'll go here and I will now click on build now. Now now let's see what happens. I will go to stages. And this is a very good UI to see what is happening. So if I go to this, it tells me that my job has failed again. My pipeline has failed. If I click here, SCM checkout was automatically added because now it found the Jenkins file there. Previously, Jenkins file was not there. Hence, we didn't see this. Since the Jenkins file was there, it said your checkout works seamlessly because you provided the correct credentials. But the first stage in your pipeline so to speak, which is Trivy FS scan, did not succeed. And why didn't it succeed? It says preview not found. And this brings me to that important point that I mentioned at the beginning. Your Jenkins is just an orchestrator. If your agent who is performing this stage of the build does not have Trivy installed, then your pipeline would fail. So now let's install Trivy in our Jenkins agent because agent is the one that is doing the leg work that is running our jobs. So I will go here and then in this stage privy fs scan I will go here and then I will scroll down and this is how you install Trivy. Now you should be logged into your agent VM firstly. So let's install trib and I am installing this in the default path itself in your I'll show this to you. I'll just copy this right now all the commands and this is the version of tree that we are installing. If I go to my CLI I will paste this in my agent Jenkins agent VM. First I will exit this because I want to run pseudo specific commands and my Ubuntu user if I write id Ubuntu is part of the pseudo group which is why it can run sudo specific command. So I'll paste all those commands and I'll press enter. Now this will install trivia. Now you would be thinking wun but this will gen user will have access to it. it will have access to it and why it will have access to it because the location where TV is installed all the users have access to that location. So if I run which trivy you would see that it is installed in usr bin. So if I run ls-l on this location then you would see that everyone has permissions to execute this binary. You see uh owner has full and then execute permissions are with groups and others as well. So our Jenkins user can also run this. Now that we have installed Trivy, let's go to our browser and run this again. So I will rerun this. And this time our Trivy file system scan should succeed. And let's see what it has for us. It says that you know you see all the logs here for this stage and this says it did not find any vulnerabilities. But you would be thinking Vun how is that possible? You deliberately added vulnerabilities in your code right? If I go here if I show src to you and then main and then app java you have problems in your code but did not flag it. Why didn't it flag these? I want you to clearly know that privy we are using for SCA. We are in this stage and we are using privy for SCA. It will only look for vulnerabilities in your dependencies not the actual code. For your actual code you have sashed. Understanding this distinction is important. That is why TV did not detect anything. Now I don't want to keep you hanging. What I want to do is I want to deliberately add a problem so that TV can detect it. So I will right click here. I will click on new file and I'll call this file secrets.ext. Okay. And then what I will do is I will add something that is in format of AWS secret access key. It is not a genuine key but it works for our demo. And in pom.xml I also want to add a dependency. I want you to clearly know that when I talk about trivi it can perform SCA plus more to detect CVE linked vulnerabilities plus misconfigurations and known secret patterns that SAS cannot find. So for example, if I talk about this, this is a known pattern for secrets. But if I go to my pom.xml, if I go to my Jenkins code here, if I go here, then I have hardcoded something. But this is not a known pattern, which is why TV won't detect it. And critical point TV is mainly for the vulnerabilities that are there in your third-party libraries. And in pom.xml, where do we define third-party libraries on which our application depends? We define them in the dependencies section, which is what we are going to do. So I'll copy I'll go to my browser and I have noted all these points here. So I'll go here. I'll scroll down and here is the vulnerability that I want to add. Hold on. Yeah, simulator problem. So I will copy this and then let's go to our pom.xml and here. So this is dependencies is a plural. This is the first dependency. This is the opening tag. This is the closing tag because it has this forward slash. I'll come here. I will paste it here. And then let me just, you know, align it properly so that it looks neat. And then this as well. I'll select this block. I'll press command and closing curly brace. This is fine. This is under it. Yeah, this indentation looks good to me. I'll save this. And now let's commit this. Understand? We have to commit. A lot of folks run it just like that. We have to commit the changes that we have done. So get add and then commit addit review stage with vulnerabilities. Enter. And then push private repo main. And now I will come to my Jenkins screen again. This time I want this to check out the code again. So this rerun should not be used. I will come here and then I will click on build now. And then let me go to stages. Let me go here. And this time the TV file system scan failed. And let's see why it failed. It says your pom.xml has three vulnerabilities and your secrets.ext has one secret that is there. You fix that dear DevOps engineer and then I will let you pass because I have been configured to fail the pipeline if there are any high or critical level vulnerabilities and I see your code has three which is why I am failing. And then it also defines what has the problem and what you need to fix. And to fix that we simply will delete our secrets.ext. I'll delete this. And what I can do is I can come to my code. I can come to my pom.xml. And this particular dependency I can just comment using command and forward slash in Mac. I'll save this. I will again commit this commit with vulnerabilities. I will just write fixed here and then I will push this again. And if I run this again, I'll come here. I will run build now. If I go to stages now, you would see this has now succeeded. So if you come here, this says everything is fine. Now that we have done this, let's see what we want to do next. Next is your build and test. So this is the part where we will be building our application and we will be testing our application. So what I will do is I will just copy paste the command lit because it is a lengthy command and then I will be explaining you step by step what we are going to do. So let me come to Visual Studio Code and I will open my Jenkins file here. Stages we have added the first stage. We identify where is this stage ending. I will click on this. It tells me that this is the closing curly brace for this. I'll come here, press enter so that I can add another stage here and then I will just copy that stage for you. So that let I have to explain a few more things. So let's do one thing. I will ex I will write that stage first. stage and I am calling this stage let's say build and sonar because we are doing sonar scanning here and then understand that we want to access our sonar cube installation from our Jenkins. So to do that we must first provide credentials to do the same. So now let's add those credentials so that we can do the same. So let's go to our chrome browser and then here I will go to sonar cube and here I will create a local project and this local project I will call cloud with varosh dev secops demo and the project key will also be the same. The branch will be main. I'll click on next and follows the instance default which is current default previous version. So what we are saying is new code is only the one that has changed from the previous version. Understand as DevOps engineers our primary moto is to reduce the time that the pipeline takes to run while performing everything that has to be performed. So if you have already scanned 80% of the code, I don't want you to rescan that 80% of the code. I only want you to scan the new code. That is what we are defining here. So I'll create project. And this has created a project for us. Now the project is created. But what we also want to do is we want to create a quality gate. Now by default the project that we have created will get associated with the default quality gate that we have. But I also want to show you how to create a quality gate. So we will be creating a quality gate as well. So if I click on create, you would see that this UI appears and it is asking us to name our quality gate. So I will name it cloud with varosh dev sec ops demo and I will add a QP here so that I know this is a quality gate QG rather so that I know I click on create and you see it has copied all the rules all the conditions that were there in the sonar way built-in quality gate. Now if you want deeper information I would highly encourage you to watch the sonar cube lecture but for now we will add one more condition here and that condition will be for the overall code because we want to fail the pipeline if the overall code does not adhere to what we have defined. So let's say I want to fail the pipeline if the overall code coverage is less than 80%, I will add this condition. Now this quality gate is created but right now it does not have any project associated with it. I told you that a project when created gets associated with the default quality gate profile. But right now we want to associate our project with the quality gate that we created. So with without I will click on this checkbox and then if I come here again I will see my project is associated with this quality gate. So this work is done. We have created a project. We have associated a quality gate with that project. Now we want to create a token. Now one way is you create the token for administrator user itself but we don't want to do that we will create a new user and I will call it Jenkins sonar and password I will give it a secure password and we are not going to use this password anyway but we have to keep a secure password and name let's call this Jenkins sonar itself and then email is ABC at the xyz.com and then we can create this. Now we have to create a token for this user and that is what is important. But before I do that I will give this access to sonar administrators. I'll press enter and then here I will create a new token. I will call this Jenkins sonar and then expires in 30 days let's say and then I'll click on generate. You only see that once like GitHub token. So I'll copy this. I'll go to Visual Studio Code Creds and I will paste it here. Now I will click on close. We have the token. Now we have to add this credential into our pipeline. How do I do that? See there is a way via which you can generate what you have to add in this step. So what I will now do is I will go to my Jenkins dashboard and here let's go to Jenkins and then I'll go to my job and I'll hit configure here and then if I scroll down I see pipeline syntax here. Okay, this can be used to generate certain scripts. I'll click on pipeline syntax and I will use a sample step called with credentials. I will choose with credentials bind credentials to variables. So this creates a binding. Now why this is important? Because any credentials that you use like this will not be exposed in the console or in the you know if you check the logs of your Jenkins. This is good because you want your credentials to be redacted which is why we always use binding. So I'll click add here. And this time with GitHub we used username and password. But like I told you, Sonar Cube does not expect you to specify a username which is why I will choose secret text here. Now what is the variable that you want to use which you will use to call this secret? Understand? I have stored the tokens but I need a way via which I can call this token and that way is variable. So you define a variable and I will define a very descriptive one sonar token so that I can use this variable. Now what are the credentials that you want to use for this? I will click on add here. I'll go to Jenkins and this time I will choose secret text. Here it is asking what is your secret text. I will go to my visual studio code. I will go to creds. I will copy this one. I will paste it here. And the ID is let's call this sonar cube token. And then we can click on add. And then I click on generate pipeline. So it will generate the exact syntax that is needed for us. So I will just copy this or I can use this mark here as well. I'll go to Visual Studio Code. I'll go to my Jenkins file. I will come here within this stage. And within this stage I will have to you know open a curly brace. I will open that curly brace and then I will have to also add steps. What are the steps I want to use for this stage and within the steps block I will paste what I have copied. I'll hold on. I'll go here. Let me just copy this the oldfashioned way. I'll come here and this is this pink is for entire stages. This is for the pipeline and this curly brace within steps that is green is for our step. So I will add this here. I'll go to view and then I will also word this. So with credentials string credentials ID is sonar cube token. Variable that we want to use is sonar cube token. And then here is where you can add the next commands that you want to run. And this is where I want to use copy paste. So I will copy the block that I want to use here. And then I will just paste it here. So here I am running a shell command. I'm saying mvn clean verify. And if you have not been through Maven lesson, this will not make sense to you. But for now, what I can tell you is I'll go to this here. Maven clean will automatically run the pre-clean for you and the clean as well. So it runs the phase that you are running along with the previous all phases. In the next phase, I am saying MVN verify. So first it will clean and then it will run MVN verify. MVN verify is this phase which will run all the phases that are before MVN verify. So it will also package which is why you will get a jar file dot jar and it will also perform unit tests. Now how it can perform unit test? So if I go to my visual studio code I have my pom.xml XML here I have defined JUnit as a dependency which is why Maven knows that JUnit tests are there and secondly there is also a surefire plug-in which is being used and if you have watched the sonar cube lecture all of this will make sense to you so if I come here we are essentially doing this we are performing doing JUnit tests and why we can perform this because we have defined a testing framework which is JUnit and then I showed you the code as well where we have defined test cases and in our Maven we have shorefire plug-in which is performing these tests for us and then further we have Jakokco Jakokco is Java code coverage plug-in Jakoko records code coverage for sonar cube and it delivers that to our Sonar Cube server and that is how Sonar Cube knows that the code coverage is this. Understand that Sonar Cube can do SAS but it cannot do code coverage for code coverage reports. It depends on JCO. So let's move back and again watch the Sonar Cube lecture if this is not making sense. And here we have the shorefire plug-in which will be running the tests and Jakokco plug-in is here which is you know delivering the reports to our sonar cube and based on this sonar cube will be passing or failing our pipeline. Again in the quality gate that we have defined we have said that if the coverage is less than 80% then you mark this as failed but there are other parameters as well that you could have defined. So if I look the default profile if I look at this quality gate then you see there are multiple conditions that you can add based on which you can fail your pipeline. Now let's go to our visual studio code and see rest of our Jenkins file. Then first I'm running clean then verify then I'm running sonar sonar. So sonar sonar implies I am invoking the sonar plug-in and in that plug-in I'm invoking the sonar goal. So then we are specifying the project key that you want to use is this one. And this is the project key that we created in the UI while we were defining a local project. Now this is an important piece here. I'm saying sonar host URL is this sonar IP. But we have not defined this variable anywhere. How do I define variables in a Jenkins file? For that, let's come at the very top of the pipeline. And here alongside agent, I will create a line environment environment. And here I will use a opening curly brace. And then within this environment block, I will add sonar IP. And the IP that I want to use for sonar cube is I want to use the internal IP of my sonar cube virtual machine which is this one. I'll copy this. I will paste this here. Always use private IP addresses. However, you could have also used public IP address. It would work just fine. But I wanted you to see how production implementations work. Now sonar IP value we have defined sonar token it will take the credentials from here that also we have defined and quality gate you have to wait for quality gate that is true that is selfexplanatory. So we have done all these things. Let's run this pipeline. And I want you to think in your head, will this pipeline fail or will this pipeline pass? And here the step would be build and sonar. Okay. And then let's push this. And then let's come here. I will go here. Here. And I will build it. Now I'll close this. Close this. Let's It has failed. So I go here. Let me go to stages rather. So our this stage succeeded and then build and sonar failed and it says MVN clean this this this this Maven not found. Remember what I told you your agent must have whatever it is trying to do here. We asked our agent to run MVN specific commands but we do not have Maven installed in our Jenkins agent. So either you install Maven in your agent or add Maven as a tool. Now we are going to add Maven as a tool in our Jenkins so that our agents can run Maven specific command. So I'll go to my Jenkins. I'll go to settings. I will go to tools here and then if I scroll down and then here I will add Maven and I am calling this Maven 3. Now understand you could be building different projects that may require different versions of Maven which is why this exists. What I can do is I can call this Maven 3911 and know that this name is associated with this Maven version and other installation that I add of Maven that I can call Maven 3.9.1 if I have certain installations that depend on this Maven version. Understand when you are doing this Jenkins will be installing the required Maven on the fly. So your agent VM must have internet connectivity. If you do not have then you can also add a zip. That functionality you have. So I'm calling this Maven 3 and the version I'm using is 3.9.11. I will save this and then I have defined a tool but I have not called that tool in my pipeline yet. So let me def do that. I will come here and here let's write it here below the agent. What I will do is I will add a section called tools. And this is where we define our tools. And the tools that I want to define right now is just Maven. But which Maven my friend? I want to define Maven 3. And Maven 3 is the name that we gave to our installation. You see here Maven 3 was the name which is why I'm calling this Maven 3. Try to connect the dots. Now that we have done this, I will go to my terminal. I will do get add then get commit and then I will push this. So if I go back to my browser here I can run this job again. So I'll go here this one and then I will click on build now and I'll go to stages and let's see what is happening. So TV stage succeeded build and sonar. Let's see if it will succeed or it will fail. So it is running maven specific commands. We know that because you see this has started progressing. And now let's see whether it will fail or it will succeed. And I want you to clearly know that in our pipeline we will have three places that will decide whether the pipeline will fail or not. that is TV file system scan, quality gate scan and TV image scan. So let's go to our browser again and this has failed again but this time the reason is different. Maven specific commands did run successfully but if I scroll down my logs will tell me a different story. So let's see what my logs are saying. It is saying script return exit code one. It is not giving me the complete logs. If I scroll above. Okay, if I scroll further up, let me just zoom out a little so that I can see properly. Has it redact redacted the logs? Hold on. Maybe it has purged the logs. Let me come at the very bottom. Oh yeah, now I see the full logs. It says build failure failed to execute goal this this this this on this project status failed. What is this? And it is asking you to check here. It says the quality gate has failed. And why has quality gate failed? Let's see that. I'll go here. I'll go to projects. What this is automatically created for us. And I want you to check a nuanced thing. They have named it this we named it cloud with vjosh - dev sec ops demo but from where did this name come into picture so if I go to my visual studio code and I go to pom.xml then the name that I have defined is this which is why it is using that name. Now if you have not watched maven lecture you are at loss here. So you see here and if I go here then you see why it has failed. It says the coverage is just 3.2%. The required coverage is this much. And then there are other problems with the code as well. If I go to issues, it will mark the other problems. Now at this stage, this is the point where you reach out to your developers that we are facing, we are getting these issues. Please fix this. Please make the coverage. All right? Only then the pipeline will succeed. But since we are doing this in our lab environment, I think we can pass this using the means that you should never be using in production. So what I will do is I'll go to my quality gate. I will go here and then I will edit this rule and I will mark the coverage just 2%. So anything that is less than 2% you then fail. But our code coverage is 3.2% so it will succeed. But you should never do this in production. The minimum code coverage that I have seen in production is 65 70%, not below that. So I'll update this condition and once this condition is updated I will come back to my this job and then what we can do is I can restart from a stage and that stage is build do sonar. Let's see how it works. Now I'll go to stages and then let's see what happens in this stage. Now this time the build is success because the quality gate allowed this to pass. Now we have a good understanding of how this works. So let's see what we want to do next. So I'll go to my diagrams and in my diagram we have done both of these things. Now we have to perform ECR login and image build. So let's first perform ECR login and then see what we have to do. So I'll come to my Jenkins pipeline. But before we do anything pipeline, I think it makes sense to have a repository first. So let's go to AWS. I'll go to my browser and then here I will look for ECR. Yeah, I want to use Amazon ECR. Here I am in Mumbai region. I want to create a repository and what I want to name this repository is cloud with varosh dev seccop ops- demo. And I'll just zoom in a little so that you can see properly. Image tags setting mutable or immutable. In production you would always use immutable. Now this defines whether redundant tags can be pushed or not. So always use immutable so that if 2.6 version let's say exists then no one else can repush 2.6 because that creates chaos. You don't want that. Now it is asking are there any tag exclusions and I will have tag exclusions. I will have a latest tag here. Now understand that when you are downloading let's say an image and you do not supply a tag you docker typically adds latest as you know the tag but for that to work an image with latest tag must exist in your repository if that does not exist then latest won't work that is one thing second what I'm saying is if someone has pushed a latest image and then if someone else pushes the latest image with a tag latest then you should allow that because we'll have to allow that so that anyone who wants to use or work with the latest version of the application they can just pull the latest tag. However, some level of controls must be there in your organization so that whenever you are pushing a version that is the latest indeed should have a latest tag as well. And that is what we will be doing. We'll be pushing image with both the tags. A version tag which we'll see what version tag we'll be using and then a latest tag. So I've added latest here. I'll click on add filter. Now if you are using KMS you can use that you can have your customer managed keys your own keys or AWS manage but for this one I'll be using AES 256 here I will just click on create now as soon as you click on create it will tell you what all are the commands that you can use to push this. The URI is also available at your disposal. So if I click on this I can view push commands from here and this is what we will be using. So let's go to our Jenkins file and let's add another stage. So this stage started with assan curly brace and then I will add a new stage here. This stage is let's call this ECR login. So we are going to login into ECR and here in this stage these are the steps and I'll add steps here and then I'll add another curly brace and then I will mention the step here. Now see what I can do. I can just quickly copy this and I will paste this here. SH I want to run this then this is fine. But see your pipeline will not look good if you have these lengthy URIs here. Okay. So let's do one thing. Let's variableize this part. And we already know how to do that. So I'll copy this and then I will come at the top and in the environment section I will add another variable here. Let's call this ECR registry. And the URI is this. This is the registry. So I have added this here. Now what I want to do is this is the variable name. So I will copy this and then instead of this I will be using that. See if you look at this command this is AWS specific command. It is using AWS. Hence we must have a binary that understands AWS. What is AWS? It is essentially AWS CLI. To run this command, our Jenkins agent must have AWS CLI installed. That's first. Second, we are also using Docker login. So, Docker must also be installed in our agent if we want this command to run successfully. So, let's do that. So, I will go to my browser and here I will go to my GitHub notes. This one I will come to the very top first and then I will go to this stage. This stage is ECR login. Install AWS CLI on Jenkins agent. I'll go here. This is not working. The click is not working. I'll have to fix that. But anyway, here are the steps to install AWS CLI. And you have to do this in your Jenkins agent. So, I will copy all of these. And again this binary we are installing I think this will be installed in usr bin for which all the users have access. So that will be available to our Jenkins user by default. So I'll enter these commands and this will install AWS CLI. And here we if I run which AWS it's installed here and all the users will have access to this. And we can also verify this using this command. So if I run this as Jenkins user then I can check the AWS version. So AWS CLI is indeed installed. Now let's docker engine installation. So all these steps are taken from the official documentation. Here in the first step we are removing if there are any installations of Docker already in your machine. This is not needed for our use case because we have set up a new VM. Then we are updating the index of all the packages. Here are the things that are required by Docker. We are adding all the keys. Then we are adding the repository. And finally we are installing these things from that repository. So let's let's run all of these commands. I'll go to my terminal and then I will paste them here. Unable to locate is fine because the first command won't run successfully as we do not have Docker already installed. So that's expected and once we are done with this then what we will be doing is this is an important piece we will be adding our Jenkins user to the docker group so that our Jenkins user can run docker specific commands and then again we are also adding the Ubuntu user if you want wish to skip this you can ideally only Jenkins should be allowed but I added this so that you can quickly test docker right from your Ubuntu user itself. But in production you will only use this not this one. For this one I can use both of these. So I'll come here. I will paste these and I have done this and then let's see the docker version. So first we are checking the docker version as Ubuntu user and then this is that output and then we are checking the docker version as Jenkins user. So both of these work. This is good. Now I want you to understand one more thing. Will this pipeline run? Will this stage be successful? If not, can you tell me why? So let's do one thing. Let's first commit and then we'll come to we'll see the logs and see how it works. Commit. And this one is your ECR login. And then I will write here push. And then let's go to our browser and I will come here here and I will build it now. Now you can go to stages and see how it is working. So all of these succeeded. We know they had to succeed. And here let's see what the log says. AWS ECR get login this docker login this unable to locate credentials. You can configure credentials by running AWS login. So you are trying to access Amazon ECR service from your Jenkins agent without supplying any AWS credentials. How will you be able to access Amazon ECR if you have not provided the credentials to access the same? Now if your Jenkins agent was deployed outside of AWS then you could be using AWS secret key or there are other means as well but we are in AWS itself. Both our controller and agent are in AWS. Our agent wants to access Amazon ECR service. How do I grant access to my agent? It is simple. I just attach appropriate AM role and my agent will be assuming that role while it tries to access Amazon ECR. So let's associate an instance profile with our Jenkins agent VM. But before doing that we will have to create an AM role. So I'll close this. [clears throat] Here I will choose roam ro. I'll come here and here I will say I'll zoom in a little. Then I will say create role for AWS service. And yes it will be EC2. EC2 is fine here. I will click next. And what is the policy that you want to associate with this role? Now I will use an existing policy. So here are the policies for public registries and for private as well. So if I go here you see public and you see private. So we are using the private registry right now. That is what you would see in your you know your applications. So we will come here and then I will choose EC2 container registry power user. I will select this policy and then I will click on next and here I want to give the role name. So I will call this Jenkins agent role. Giving this name and then we will be using this name later as well. So name it in such a way that you remember it and always follow nomenclature that is understandable. So we are using this name and then I will click on create role. Now this will give our Jenkins agent access to Amazon ECR. So let's come back to the Jenkins job and then let's rerun this from a specific stage and that stage would be ECR login and let's see if this works this time or not. And this time it also fails. Let's see why did it fail. Who will attach the role to the instance? So let's attach that role to the instance. We have just created the role. Let's attach that. And I didn't do it deliberately. Okay. I I genuinely forgot. Security modify IM role. And here I will choose the IM role that I just created. This is called the instance profile in this language. I'll select this one and update IM ro. And now if I run the pipeline, this should succeed in my opinion. Let's use a rerun this time and let it run. This GUI is so intuitive to me. I, you know, like seeing this everything green, green, green. It's so satisfying when you have a running pipeline. It has 10, 15 stages and all of those are green. It's so satisfactory, I tell you. And then you see the login has succeeded. So we have performed the ECR login but we have not built our image yet. So let's start building our container image. So I will go to my Visual Studio Code. Firstly to build any container image we must have a docker file and docker file you can find the docker file in the project files itself in the repository. So we will be upgrading this Java Maven with different things. We'll now add docker file. So I want to copy this for now and then I will paste it in Java M. I'm pasting it in the root itself. So if I see the docker file, it's a simple docker file. We are using Eclipse Turin 21 that is Java 21. Working directory is / app. And then we are copying whatever is generated as app do.jar inside /app directory. Now see I told you whatever leg work is being done is done by the Jenkins agent itself. And if you remember while configuring agent we also defined what would be the Jenkins home in the agent. Where will the workspace be saved? where what would be the scratch space that the agent would would be using and if you remember we supplied forward slhomeward slashjenkins there so I am in the Jenkins agent right now so if I pseudo-en u jenkins I log in as sudu jenkins bash have to supply the command that I want to run anyway so I'll go to cd home jenkins and that's the home of our Jenkins user and if I press ls is you see workspace here and you also see tools here. Now this tools will have Maven. So if I run tree here do I have tree? [clears throat] Anyway, forget it. I'll cd into tools. And then if I do ls, you see Maven installation is here. I told you your agent will require internet access if you're using that tools section and you're not providing the installer. Anyway, so I'll come back and if I go to CD workspace, you would see that whatever was there in our repository, you see here and this is the name that we gave to our pipeline job. So if I go here and do ls then you see Jenkins file is here pom.xml is here src there is also target and this was created because we also ran mvn verify and that's why this was created. So if I cd into target, if I do ls, then you would see a file named like this was created for us. And that is exactly what we are doing with this command. So what we are saying is copy from target and you go to this file and copy that as app.tchar. So you see this is the file that we are copying as try to you know think why we are doing something and then we are exposing our application on port 8080. This is just for documentation. Your application should also be listening on port 8080. Our application is which is why I have added that. Now another thing is entry point. This is the command that I want to run when my application is running. I want to run this app.jar jar this file and that is what will show you cloud with varoosh welcome to cloud with varosh and so on whatever we are doing in the application so we have the docker file in the root now if we commit jenkins would know there the docker file that I need to refer when I'm building something but that build step we have not yet added so let's start with that step I will come here steps stage can closing bracket that I'll come here. I will add another stage and this stage let's call this one image build image build image I have to spell this right so that it looks neat and then in the stage here I'll add this curly braces and then I will have steps I will again have curly braces now I will copy the command that I want to run just give me a moment moment so that I can copy it. I will paste it here. Perfect. Again, I'm invoking a shell. Then I'm writing export docker build kit zero. Now why I am doing this? So this will essentially disable docker build kit. So builds you know run in classic and predictable mode only. That's the reason for this and I will tell you why I'm doing this in a little while. Then our normal usual docker build command. I'm saying docker build- platform Linux AMD 64. Now this is telling docker that the image that I am building the application that will result from this supports AMD 64 architecture and which [clears throat] is the reason the EKS nodes that we will provision as part of this lecture. The Amazon EKS cluster we provision the worker nodes will also have AMD 64 architecture. Now you know why this matters. If you have developed your application for ARM and then you are trying to run that application onto a worker node that has AMD 64 then it won't work. And for further knowledge, AMD is the one that introduced 64-bit architecture. Then Intel no didn't want to call it AMD 64. So Intel called it x86_64. But x86_64 from Intel or AMD 64 they imply the same thing. Why this matters is because the application that we are building it supports AMD 64 architecture and the base image that I am using also supports AMD 64 architecture. Hence the image that I want to create is for the platforms that have AMD 64 architecture. That is what we are defining here. Now why this becomes important is when you are dealing with enterprisegrade applications you want to be precise. You want to tell everything that is needed so that you do not get extra things free. So that's why I'm defining this. And when I was not defining this, my Amazon ECR had a few more blanks pushed to it. Which is why I added this Docker build kit is equal to zero. Nothing fancy. We have already used Docker build so many times in this course. U in Jenkins course or in my Kubernetes course. If you're new here, Docker build is just building the container image. If you do not understand this, you are in the wrong lecture because this is a CI/CD pipeline lecture which deploys onto Kubernetes. And to do that, creating container image is the first step. Anyway, I'm then defining tags. I am pushing two tags. I'm saying the first tag is image repo colon build number but varun you have not defined image repo yet let's define that now I will go here and then I will say my image repo this would be I'm adding double quotes here okay because I will be using a variable within a variable and then I will call this this and I'll tell you what I'm doing I'm saying my image repo is ECR registry this forward/cloud with var dev seccopsy demo and this is exactly what you saw here on the console so if I come here exactly this I'm defining this URI and then I will just define the tag and what is the tag that you are defining Vun I'm saying dollar build number and then latest is I'm sure you understand but what about build number now there are certain environment variables that are exposed by Jenkins and we are using one of those environment variables. Now if you want to access those environment variables what you can always do is you can first copy this name. I'll copy it from here. I will paste it here and then I will write env.html and I press enter. And these are all the environment variables that you can use that are available for your pipeline jobs. And here what I'm using is I'm using a build number and this is the build number that I'm talking about. So if I go to my pipeline, everything has a build number associated with all the runs they have a build number. Now I am tagging my application with the build number so that when I see my image I exactly know which build resulted in this build number. So what I will now do is this is understood. Now you will also have your applications versioning as well like which version of application you are using. I have not shown that here but you must keep that in mind. So what you could be seeing is here you could be using you know like something like this app version and then a build number. So you are tagging your image with application version as well and then the build number from which that image resulted. So that gives you full control when you see the image itself. Anyway, so we will just use this for now and we have supplied that. Now that we have done both of these things, we can see whether these steps works for us or not. So I will go to my terminal again and here I will go here. I will first add this and then I will commit this. I will say container image build. Press enter. And then I will push this. Once this is pushed, I will come here. I will run build now. And this time I will go to stages. And you see build number 12 has started. and then permission denied while trying to connect to docker API. Now understand we installed docker after connecting to the agent. Correct? So we have to refresh that so that our controller adds agent with the refreshed permission. So what I will do now is I will go to my Jenkins screen. From here I will go to agent. I will disconnect this. Yes. And then I will again launch agent. I'll see the logs. It says connection successful. Now I will run this job again. I'll come here and I will click on build now. And let's see the stages. And if I go here, this is running all the stages that we have defined up till now. And at the very last, we see the build image stage. So let's see how it works now. And we are in this stage. And this time it has started building the things for us. No more that error. So just disconnect your agent and reconnect it if you also see those problems. Now it has completed. So it has completed building the image. So if I go to my terminal, I am already logged into my agent and if let's say I run docker ps here, docker images here, I'm sorry. Then you see the images. This is the base image that we are using. We don't care about this one right now. You see there are two images that are created for us. One with the latest tag and one with tag 13. And why is this 13? This is 13 because this is build number 13. And we added the build number in the command that we were running in our Jenkins file. So we said that you must use the build number. Now that you have this understanding, let's move to the next step. What you would be thinking, Vun, why haven't you pushed yet? My dear friends, we'll have to perform an image scan to ensure that this image, which is our base image. When I talk about the Docker file used by our application, is vulnerability free. And that is what privy image vulnerability scan will do for you. It will scan your base image and its OS packages to see whether there are any vulnerabilities associated with it or not. So let's just quickly do that step. So I'll go to my visual studio code and same this time I will check this is the cyan curly brace and then I'll come here I will add another stage and this stage I will call privy image scan and then we have opening closing curly braces. I'll press enter and here we'll have steps. I'll again have an opening closing curly brace and inside steps I will have the command and the command is extremely simple. I'll paste it here. Now I want you to see the difference. In the previous command we said that tree file system scan and I want you to run this on everything that is in the current directory. And I want you to clearly know what is the current directory. Current directory is the workspace where it has cloned everything. This is the current working directory. So it is saying scan everything here. But this time we are saying TV image. FS has changed to TV image because we are performing an image scan this time and if you find any high or critical vulnerabilities then you fail the pipeline. So this is a quality gate that we are applying that any high or critical vulnerabilities you fail the pipeline and vulnerabilities in the base image. And here we are supplying the image on which the scan must be performed. Simple. And then I will come to my terminal and I will go here. And then I will quickly add commit with I will write here image scan. And these messages are important guys when you are you know looking back at your history. And then I'll press enter. I will come to my browser. I will come here again build now and then I will go to stages come here and then let's see what our build image stage results in. Build image is already here from the last time. We want to see the next one that is TV image scan. TV image scan. It's so good, right? It labels everything so properly. So TV image scan has appeared here. If I click here then it is performing the scanning in our container image. And you see our command has expanded. Whatever we had variableized it now has 14 because this is builder number 14. So whatever variable is being defined that is resulting. It is not scanning anything stale. It is scanning what we asked it to scan. Now this scan is successful. Understand the image that we are using is free of vulnerabilities which is why it has not flagged anything. So with this said we are good. And if I expand this further yeah output was you know redacted by this terminal. Now you see the full output and here is the detail for that. no vulnerabilities and it is not just performing image scan, it is also performing something more because it also scanned app app.jar as well. In this step, we wrote trivi image. Now to know more about trivi you will have to read about trivi. It is not that this is a trivial class. Understand that when you are integrating a new tool, you must first understand what that tool is using. We know as a principle that Trivy is used for SCA and is used for image scanning primarily. Other things you read the documentation and explore further and once you understand one tool then other tools become so easy to understand. So for example if you know Jenkins, CI/CD then be it GitHub actions or GitLab they seem like a cakewalk. Now that we have done this, let's see what we want to do next. Next is we want to push to AWS ECR and they call it Amazon ECR not AWS ECR. So we'll push to Amazon ECR. Let's see what are the steps for it. And again these steps would be simple. Simple as in whatever you do when you are using manual methods. It is just Jenkins is automating things for us. So I will directly copy the entire block for this because I don't want to waste time in doing simple things with you. Here this and this I'll come here. I will add this. Now I have added that stage as well. Now this is push to ECR. Steps is docker push this the image tag and then the second image tag. We want to push both of them. So I'll go to my terminal and here I will write get add this get commit. I have to have a good commit message. Anyway, ignore this one. And here I will write get push private repo main. And then I will go to my browser and here again I would run the same thing build now and then I will go to stages. Let this complete and once this is complete we should see that our images our tags will be here. Understand that we call this a repository right like Ubuntu is a repository and then that repository has multiple tags and this repository cloud with VJO dev secops demo has two images as in two tags one with 15 and another is latest. That is how it works. Now the push has already happened. now is the last and the most interesting stage that is deploying onto an Amazon EKS cluster. So if I go to Jenkins now you would see this has pushed to ECR successfully and then you can also see all the logs here. Now is the interesting stage that is deploy to Amazon EKS and this is also where we are failing. In case the deployment is not successful, we will be rolling back. So let's start working on this step. Now before we start working on this, I quickly want to create a cluster and I will just run the commands to create a cluster and then I will walk you through what I'm doing. Okay, I'll just cd I'll come one step back and from here I will cd into project files and I'll do ls and I will run eksctl create cluster and the file that I want to use to create cluster is eks-configy. Now what I'm saying is create a cluster using this configuration file. Now to run this command your thin client as in your laptop or whatever you are using to you know run this lab should have eksl installed. You will find all these details in the github repository. So do not worry about them but you should have that eksl installed AWS CLI installed and we I will attach the steps on how to do all those things in the GitHub notes. You will press enter and cannot find EC2 key. Hold on, hold on. Let me run AWS configure list profiles. Yeah, this is the profile that I am using. Okay, hold on. Let me make this profile default. Okay, export AWS default. I think uh I mean I closed the session from where I was working in the practice sessions which is why I have to you know define the default profile again and there are ways via which I can make this profile as you know perpetual default but I don't want to go there right now. So default profile is CWVJ - SJ AWS default profile. Now we'll press enter. And now if I try to run that command that should succeed because yeah it has now succeeded. So that's small roadblock. Now what we can do is now let me explain you what we are going to do because this creation takes some time. I'll go to my diagrams and this is what we are going to deploy. We are going to create an EKS cluster and you know in EKS cluster. There is a control plane and then there is a data plane. The control plane part is managed by AWS. They will have redundant API servers and your HCD nodes and they have three AS where they will deploy your database at CD and then your API server along with other control plane components is also redundant. So here for this part you do not have to care because it is a managed service. Here is where I am using EKS managed worker nodes wherein we will be creating two worker nodes exactly like this in two different availability zones. So if we are creating two worker nodes and that two in different availability zones, we want to ensure that the application that I am deploying is deployed in such a way that the pods associated with that application leverages both these availability zones. Otherwise there is no point for me to have two a2 does not have any pods pertaining to my application. If my application warrants high availability of two A's then I must ensure I have means via which I can ensure that if I spin 10 pods five will be in a 1 and five will be in a 2. That is your responsibility as a DevOps administrator. So for that to happen we will have things in place. So this is the cluster that we are creating. Now let me walk you through the configuration file that I have used to create this cluster. Under project files we used EKS config.yml. Extremely simple. We are creating a cluster. We are calling that cluster cloud with various devs sec ops EKS. We are creating that in the Mumbai region. The version we are specifying is 1.32. AWS is offering 1.33 as well now. So you can use that. And then I am adding certain tags to the resources that will be created for this cluster. So these are those tags owner tag environment project purpose and then I'm specifying I want to use two availability zones I am with oidc is true and we discussed this in if you want to you know look at greater detail for this there is a there is an ingress demo in my uh channel and a stateful set demo in my channel very detailed production like and there I discuss all these things in greater detail you Check that out. Then I'm creating a managed node group. What I'm saying is I'm calling this managed node group cloud with vosh nng public and public I'm calling this public because the private networking is false here. So my nodes worker nodes will be accessible over the internet which you may not need. I am doing this because the application that I will be deploying will be exposed using node port service. But War Vun who uses note port in production and I agree with you 100%. But I wanted this demo to be within 3 4 hours. I did not want it to stretch so long which is why I have not created any ingress or I have not deployed AWS's load balancer controller. If you want to see that scenario, there is a detailed 2.5 hours video in my channel that walk you step by step on how to do that and how to expose your applications using that. You are very welcome to integrate that application with this CI/CD pipeline. But for now, we will be exposing the application that we are deploying with note portut. Then I'm saying allow SSH. We won't need SSH but I'm just saying allow SSH and then public key name that I'm using is the same one that I use for instances. We won't be logging in into our instances. So this won't be used. Then I'm defining few add-on policies here. I'm saying that true true these things should be allowed. Labels our nodes will have these Kubernetes labels and then these will be the tags associated with our nodes. That is what I have defined. Now let's see where is our installation. So the installation is still going on till that point. Let's do a few more things that we want to do. So I'll come to Visual Studio Code and then I'll come to Jenkins file and then let's see the Kubernetes manifests that we will be dealing with. There is deploy svc.yamel in project files that you can use. deploy as in deployment plus the service manifest exists here. So if I go here, it is a generic deployment that you would have used thousand of times. I'm using two replicas and then this is the important part. This is the part that will ensure if I have 10 replicas, five is in one a, five is in another a because here the topology key that I'm defining is zone. So if I have let's say two zones, it will try to you know deploy one pod in one zone and second pod in another zone. When unsatisfiable I'm saying do not schedule. So this is a strict rule. You can be lenient with this. So if you hover over this when unsatisfiable I think this will tell you. I mean schedule anyway is another option I think that you can have here. label selector I'm saying this is applicable for all the pods that have app is equal to cloud with varos dev secc ops demo and that is the label that we are adding to the pods that will be part of this deployment. So very simple max skew is one that is you know uh default you cannot have this zero. The max ske one says the imbalance of one is applicable can be there but not more than that. So skew is the imbalance that you can have here is the container section and you see these lines because we have not defined resources section as in limits and requests which is why you are seeing this container name is this image. Now this is the important piece. I am saying you have to use this image. Now I'm saying latest here but do not worry. We will have something in place which will have a specific tag here and we'll see how that works. For now just understand this is the entire URI of your repository. So if I go here to my browser, you see entire this. If I go to image repositories here, the entire this is here. And then we are saying the tag we are supplying the tag. Port says container listens on port 8080 which is on what my application listens on. Then I am defining a node port service. It's a simple node port service that listens on port 31,000. So we should be able to access this application on any of the nodes public IP on port 31,000 once the deployment is successful. So we have understood this. Now what I want to do is I want to add a stage in my Jenkins file which will ensure that this file you know firstly I'll move this to my this because it will be required for to run cubectl commands and it will be required by the next stage where we'll be editing this file to change this latest to something significant as in the build number. Let's do that. I'll come to my Jenkins file. I have this stage here in can. And then I will add another stage here. And this stage I will just call this stage proper naming because in this stage we will be updating the deployment with a proper name. So I'll call this update deployment. Okay. And then here I will have opening curly brace, closing curly brace. Then here I will have steps and within steps I will only have one step and that step is this one. Now here I am using set. So set is a substitute utility which will let you substitute something with something. So here what I'm saying is substitute my image you know with this one and do that globally. So globally will not matter because we only have one place where we have to perform the changes. I just added G for completeness. So this what will this do is it will go to image and it will find this and then it will replace this with this variable and this variable both of these variables have already been defined in our Jenkins pipeline. So image repo is this and then the tag is build number. So that is what this stage will do. Now let's execute this and I'll show you how this will work. Oh this cluster creation is still ongoing. I wanted to push. So let me do one thing. I will have another terminal opened. I will quickly cd into courses courses and then here I will go to Jenkins and then common and from common I want to go to Java Maven right Java Maven is where I want to go here. Let's just quickly revise what we have done. It should have deployment and service manifest which it has. It should have Jenkins updated file which is which it has. So let's run this now. Let's commit this and then push it. So I'll go to my terminal here. I will write get status. It should show that unttracked files. Yeah, modified is Jenkins and this is unttracked. So I will write get add dot and then get commit- m updated deployment image tag. Yeah. And then I'll press enter. And then I will write get push private repo main. And here I'll check the spelling and then I'll press enter. So now let's go to our Jenkins UI and I will quickly run this and I'll go to stages and by the time this is running let's go to our terminal and see what is the status of our cluster. So the cluster is still being created. Let's again go back to our browser and build 16 has failed has failed before even starting. Why is this console output update deployment? Oh, hold on. This should be in single quotes. That is what happens when you do things in a hurry. Now the color coding has returned. Right? There are two parentheses after this. So this should now work. Let me go here and then get add get commit get push. Now let's come back to Jenkins and here I will build now and then I will go to stages. Okay, this looks good to me now. So now what I want to show you is how it has modified. So let's go to our terminal. And here I want to go to agent. Yeah. And if I do ls, you see deploy svc exists. Now previously it did not because it is just this stage that we added this. Now I'll go to this one and it has updated the deployment. So this has ran successfully. But how do we verify that? So if I come here, if I cat into this deploy.yamel, you see here this has changed. This was latest in our source code. But the checkout that Jenkins has performed the file here in our temporary workspace has 17. I hope this is making sense and you are within yourself saying, "Ah, this is how it all works." And now let's go to our terminal. We are already there. Let's see if cluster has been created or not. So cluster is still not created. Let's do one thing. I want to add that cluster step as well. So here is the cyan brace. I will add another stage. As long as you follow these curly braces and the color coding, you will never face problems with your you know Jenkins files and their syntax. And anyway, if you face any problems, you can always give it to you know AI tools to you know format your files. It is all doable and then I can have here deploy to Kubernetes. Correct? So this is fine. Now I want you to know one more thing. We will be deploying these onto our Kubernetes cluster. Right? So our Jenkins agent will be using cubectl client to run cubectl apply commands. Correct? But our Jenkins agent does not have cubectl installed. So let's do that installation now. So I'll go to my browser and I will close this and then here is yes stage four is done. We are on the last stage right now and that stage is deploy to AW. We have already discussed this and then we have done this as well and then it is deploy to Kubernetes. So first I want to check the installation steps. Yeah, install cubectdl on Jenkins agent. So I'll copy this. I will go to my terminal. I will go to my agent and then I will no no [clears throat] woron. I will exit. I have to run this as Ubuntu user because Jenkins is not part of the pseudo group. And then I will run this. This will tell me whether the second one will tell me whether Jenkins can access and Jenkins can indeed access Jenkins user can indeed access the cubectl client. Once we have done that, let's scroll up. I want the cluster to be created. Okay, the cluster has created. Congratulations. So, let's go to the CLI. And here I want to show you a few things before we move forward. Elastic Kubernetes service clusters. And if I click here, if I go to tags, you see the tags that we supplied are automatically added here, which is what we wanted. So if I go here, if I now run cubectl get nodes, then I should see two nodes because in my EKS config file, I asked it to create two nodes. Minimum nodes two and desired capacity is also two of 20 GB each. So you see two nodes are there for you and they are running version the cubelet in my nodes is running version 1.32.9. So this is understandable. Now what I want to do is I have created an EKS cluster. I have installed cubectl utility in my Jenkins agent. But but but I want to run this command. So let's go to our Visual Studio Code and I want to explain this to you first here. So we have this and then I will add steps here and the steps that I want you to perform dear is these. So let me paste these steps. Okay, just give me a moment. If I come here, these are the steps I want to perform. So these are hefty steps. Firstly, I am running multiple commands in this shell, not a single command. Previously I was running single commands. Hence I was providing here I provided shell two times. But here I am running a chunk which is why I have added all these under a single. So you have sh here then I have three single quotes. I have added them. When you are running multiple command and you want to invoke the shell only once, you can use this. And this one is the preferred way to do it. And then I'm saying AWS EKS update cube config. Understand my Jenkins agent will be running the cubectl commands. Here I was running the cubectl commands as vun. Jooshi user. If I write AWS STS get caller identity then it is varun.jooshi that was running the commands and vun.jooshi has administrative level privileges which is why he could see what all are the nodes that are running. Okay, using cubectl commands wun could see what the cluster has. If I run cubectl get pods, I can see this because Wun is by default Wun. Jooshi is by default have administrative access to the cluster. He's part of master's group and we'll see what is that later. But for now understand that user Vun. Jooshi is able to do that. But our Jenkins agent has one identity and that identity is the role that we associated with Jenkins. Right? In Jenkins agent, we associated a role with our Jenkins agent. So if I go here, if I go to Jenkins agent, if I go to actions, security, modify IM roles, then we added Jenkins agent role to our Jenkins agent, which is why Jenkins agent EC2 instance was able to access Amazon ECR. Now we want Jenkins agent role to access our cluster. Now if you are familiar with Kubernetes concepts, you know there is a cube config file that is the source of authentication that your cubectl client uses to interact with your cluster. And now what we are doing is in this step what we are telling our Jenkins agent is we are creating its cube config file. So we are saying update the cube config file and you update that cube config file for a cluster that is in AP south 1 that is in Mumbai region. The name of that cluster is cloud with var dev secops EKS because that is what we named our cluster. So keep that in mind. And then I am saying the cube config file will be stored here. So for this to run this command what I want is I want AWS CLI to be installed and then I want to update these details. In the second step I'm saying cube cuttle create namespace this and then I'm saying apply this manifest file. Now to do these things my Jenkins agent role must have access to my Kubernetes cluster. so that it can perform namespace creation, it can perform deployment creation and service creation. But we have not allowed our Jenkins role to do those things yet. Hence, we first must do that. So, let's start with it. What I have done is I have added AWS cube config policy. Now to update this information your Jenkins agent role must have access to your cluster. It has to perform describe cluster action. For that we'll have to create a policy and attach this policy. So I'll copy this. I will go to my browser and then in here I will go to AM roles. Roles are here. Jenkins agent role and here what I will do is I will add permissions and this time let's create an inline policy. Now inline policy can only be associated with one entity. That's what I'm doing here. I will choose EC2 here and then I will say I want to paste a JSON and then I will paste that JSON here. Understand that to run this command to run this command your Jenkins agent must have access to this cluster. You are running EKS specific command. Your Jenkins agent does not have access to Amazon EKS yet. It just has access to Amazon ECR. You can only take actions on services for which you have been granted access. Now in this step I'm granting that access to this Jenkins agent role so that it can run this command make a note that this still cannot be performed and I'll show you why and this time I'll write create policy policy name is required temp EKS node access okay so that I know that this is a temporary policy I'll create this and this is now added do this. Now let's do one thing. I will come here and then I will try to run this. Okay, I'll come here first and then let's do add and then let's commit and write here deploy to EKS and then let's write get push private repo main. And once we have done this, we can come to our browser and go to Jenkins screen. And here we can run build now. And once you do that, you will see it has started running. So let's go to stages and let's see how this pans out for us. If firstly the deployment will fail. I'll am telling you right away. But let's see the logs to understand why it has failed. It has failed. And if I come here, it's saying added new context. And this is the important part. You must be logged into the server. You are unauthorized. It is using the correct cube config file. It is not saying that it failed in this command. This command worked successfully. But when it tried to run this, it received an error that you are unauthorized. And if you have watched my Kubernetes authorization and authentication lectures, this will make so much sense to you. And we took the example of Jenkins itself in those lectures, especially in the service account lecture. And now let's do one thing. Let's come back here and fix the permission problems. Now before I do that, I want you to know one thing. When I talk about AWS, it is the AWS O config map that handles the authentication part. I'm choosing my words very carefully. AWS O is the config map that handles the authentication part. So you must first authenticate to the Kubernetes cluster and then if you have authorizations then you can perform certain actions here. We are just updating the cube config file Kubernetes cluster. We have not yet authenticated. We have not yet authorized to perform any actions in there. So we have to do two things. First we have to fix the authentication and then we have to work on the authorization part. First we will work on the authentication and AWS o is the config map that takes care of the authentication. So if I write cubectl edit cm - n cube system and then aws o is the name of that config map. You see here we say map roles. Right now this section that is added here this is allowing your nodes to join this cluster because this exists your nodes can join the cluster. But Warun how come you are able to access your cluster if you run cubectl get pods you have not added yourself anywhere and you must be logged in into the server. Hold on. I think just give me a moment. I used this one to. So if I run cubectl get pods, I am able to run this command. And here it was not running because here my identity is not that. If I run AWS STS get caller identity. This failed because my identity is not varun. It is varun. Jooshi. But it is not for the account that we are working in. So we are working in the account which has at the ending 648. Okay. But this CLI window which I am in the terminal this is working on an AWS account that has 470 at the last. Although user is same but it's a different account. But if I talk about this, if I run AWS STS get caller identity here, then this is using the 648 account and I used this user to create my cluster, which is why this user has by default access to anything in this cluster. But this piece is not shown in the AWS O config map just for your information. It is invisible. It's like a golden key that the master has. Now we want to create keys for other users. And that is what we are going to do. We are going to add entry so that our Jenkins agent role can authenticate to this cluster and let's do that. So I will run that command again. cubectl edit cm and then I will go into insert mode and then I will come here and I will go back here. I'll go back to visual studio code now because I have to copy the part that I have to add here where I have added that it is AWS oedit. So I will copy this. I'll explain this to you in a while. It's very important you know and then I will go to my terminal and here I will just paste this. I have to indent this properly because you all know how critical YAML is about indentations. So this has to be just underneath this username can come here group come here and we are indented properly. So what I'm saying is the role ARN is Jenkins agent role and you know how you fetch your answer. You go here. You go here and ARN is this. And I have just added this ARN here. And I'm saying Jenkins agent role. I'm saying username is Jenkins agent role and groups is system authenticated. If I would have added masters then that would have given you know all privileges. But I'm saying this is an authenticated user for me. Now once I have done this, this is the authentication piece. I have cleared the authentication piece. Now I have to walk in through the authorization piece. And for authorization, I have an arbback for you. And here is cluster ro and cluster ro bindings. Again go to my CKA playlist and search for authorization. Learn about these only then it will make sense to you. Here I'm creating a cluster role. That cluster role is called Jenkins deployer role. And that Jenkins deployer role will have access to deployments plus replica set. It will be able to perform all these actions. Then it will have access to pods all these actions access to services all these actions. Access to name spaces all these actions. And why I'm giving access to namespaces because we know that in our Jenkins file we are also creating a namespace here. So and then finally we are creating a cluster role binding. Now cluster role binding binds user service accounts or groups to cluster roles. Now here this would be name spacewide and if you want more information about this go and watch my authorization lecture. So here we are saying kind is user name of the user is Jenkins agent role must match the username in AWS O. So if I go to my CLI again and I run a describe on this config map then you would see that the username is Jenkins agent role. The Jenkins agent role is here and then the role reference which is the role that you want to associate with this user. That role reference is Jenkins deployer role. And where is Jenkins deployer role? It is here. So this user will have all these accesses. So what I will do is I will apply this cluster role. So I'll go to the terminal and then here I will press ls and then I will run cubectl apply - f I have to apply what I have to apply cluster ro bindings.yamel YAML and once I have done this that cluster role and cluster cluster role binding would have been created for me. Now I will [snorts] come to my Jenkins pipeline again to see what do I have to do next. This will also work. This will also work. Now we have edited the AWS O config map. So I think we have done whatever we wanted to do. Now let me quickly just commit this. Okay, I will run get add get commit- m deploy to EKS. No. Oh, here we we have just done the changes at cluster level. We have not modified anything in our Jenkins file. So, this should work. And just let me quickly see whether this file is already here. Docker file is already there. We don't need any of these. So, let's apply this. I will go to our browser and then here I will go here and then let's run this thing build now and then I will go to stages and this should show me what is happening. deploy to Kubernetes deployment successfully rolled out. So if I come here, I go to this terminal here, if I run cubectl get pods, I don't see anything. But if I write the name space name which was cloud with v jo dev sec ops then you would see I have two pods running and I want to show that these pods are running on different nodes because we have applied that setting no topology spread constant. So if I write hyphen o wide in here then you would see that this is deployed onto this node and this is deployed onto this node. So if I go to my browser I go to instances I hit refresh then you would see that two more instances should appear here for my cluster and these are the two the first one and the last one. We are good here and both of these are deployed into different availability zones. So if I check here 1 A and 1 B rest of our infra resides in availability zone 1 A. So we are good here. Now let's check the accessibility of our application. So I will copy this public IP address. I'll go here. I will write http col// I'll add that and then it is 31,000. I'll press enter. It is not working. Can someone tell me why it is not working? It is not working because we have not allowed port 31,000 in our security group. So let's see what is the security group that is associated with these instances. So if I go to uh security and then I see these are the two security groups. Now I can edit either of these but I will prefer this one. I'll go here edit inbound rules. I will add an inbound rule. I will keep it custom and here I will add 31,000 and then here from anywhere I can save this rule and this should now work. Yeah, cloud with varos simple dev sec op demo. So we have deployed an end toend pipeline. Now just to improve certain things what we can do is we can have certain post actions in our pipeline. So that is exactly what we will do now. So I will come here. I also want to show you the logs for this one. So I'll go here. Here. And then you see rolled out was successful. And this worked because in our pipeline here we said if we gave 60 seconds in case this was unsuccessful then we would roll it back. [clears throat] Now we have done this. This is this stage. What I want to do is outside of stage I want to add certain post actions. Again you can have post actions within stages but you can have them for the entire pipeline. Now this action I want to have it for the entire pipeline. So stages were starting here but pipeline was starting here. So I want to add this within the pipeline block. So this closing curly brace was for this stage. This closing curly brace is for the stages section. You know you see this highlighted here. And then after this I want to add our post actions and this is the post action. So if it is success pipeline is successful we will print this and failure we will print this. Always we will print this no matter what. We'll say finished. We'll save this. We will go to iterm. We will go to this screen. We will add this. Then we will commit this and we'll add a meaningful message post actions. And then we will just simply push it using this command. Now if I run this pipeline, we will also see post actions and that is what we want to see now. So you can click on stages to see oh I have a mistake. Let me go to the console output workflow. Hold on. I have a curly brace error. Oh this there is no curly brace that is closing this pipeline. Right. This is this has turned red which is why. So, oh, then I'll add this here. Okay, try speaking getting recorded at the same time. It's not easy as it seems. And then I have this. This should work now. So, I'll go to my terminal. And then I will add and then I will commit. And then I will push. And then I will go back crying. And then I will click build now. And this should now work. I'm hopeful. Okay, it has started at least. So, something would work, right? I'll go here and this should work. And by the time this completes, I want to walk you through some more things that you would be dealing in production. Stage nine, post actions. Yeah, post actions. Now, see why would you use post actions? Now, I have given a very simple example. You could be using post actions to send emails. You can you know regardless of what happened inside the stage you can send deployment notifications push artifacts tag builds as stable there are so many things create Jira ticket log failure metrics in case of failures and so on. So you could be using all these options and maybe as I create another project or another demo I will be using some of these but I want you to keep these things in mind. If it's a success you would would want to send an email that the deployment succeeded. You can access the application here and so on. Then what we have been doing up till now is we have been clicking on build now for our pipeline to run. But you can always create web hook and when you create web hook whenever you push onto your repository a pipeline will trigger automatically. I have jotted down all the steps to do that. It's extremely simple. I would highly highly encourage you to do that. And then lastly I want to talk about a few things. This pipeline is production ready but there are major chances of improvement. You can improve this. First is deploying Kubernetes inress. So I have detailed lecture for that. You can refer that multibranch pipelines. You will never ever be pushing directly onto main. All these main branch developer development branch, production branch, whatever g strategy you are using. It could be trunk based or it could be git flow based. But your main branches, your development branches, your staging branches, all these will be protected. You will only be allowed to push onto your feature branches and then a PR will be raised. I have covered this in depth in my multibranch pipeline lecture. So do watch this and try to implement the pipeline that we just implemented using this. Before I move to the next one, let's see what is Jenkins doing. So the deployment is successful and as suggested post actions are here. It says build 21 finished, build 21 succeeded. That is what we wanted to see. So let's continue what we were discussing. So here I have not introduced Argo CD because I don't want to cover any topic that I have not covered in this channel. So I will soon be covering Argo CD and once I do that I will be creating projects that would be leveraging Argo CD. We have used private IP addresses somewhere but we should be using DNS names. Use image digests. Now we have provided tags but in production implementations what you would see is you use image digests instead of tags and you see here our latest tag is being replaced as we move up with the pipeline. So we started creating our images from build number 15 and we completed this demo in build number 21. So if you go here, this is our build 21, which is why you see 21 is the latest one. And here is the digest for this, which is what I was saying. You would be typically using digests in production implementations, not these tags because these are indeed immutable. You you use digests in production. Then other improvements that can be done signed images plus policy enforcement. There are things like Kyverno that can be integrated centralized secrets manager. So right now we have used credential bindings. Bindings is one step in securing your credentials but you can also use a product that is meant for secrets like Hashi Corp vault or AWS's secrets manager. Then observability integration. So we have not integrated any cloudatch data dog or anything. We are not doing any monitoring of sort. So you could be improving this pipeline by this policy as a code. We have not used you know any security related policies or any Helm or Terraform for deployment. You could be using those things. Argo rollouts I've already covered automated cleanups and cost optimization. So we have not done these things as well. You could be doing these and there could be plethora of other improvements that you already are thinking. So we can integrate all of these things but I assure you a demo with this much depth will clear a lot of your doubts. Now I will go to my diagrams and then I will wrap up this lecture. So we have created this robust pipeline and with this on screen I wanted to end this lecture. So that wraps up dev secc Ops mega project where we built a complete production style CI/CD pipeline using Jenkins TV sonar cube Amazon ECR and multi-AZ Amazon EKS cluster. You saw how real teams use security gates SAS image scanning immutable artifacts am with arbback rollouts checks and automatic rollbacks to run safe deployments at scale. If this session helped you, drop a quick thanks or hi in the comments and subscribe for more advanced EKS GitHops Dev Sec Ops content that is coming soon. I will see you in the next session. Thank you very much. Hi, I am Vun Jooshi and welcome to the final lecture of our Jenkins basics to production course. Today we cover one of the most important Jenkins features, shared libraries. Instead of repeating the same build, test, deploy steps in every Jenkins files, shared libraries let you centralize common pipeline logic and reuse it across all your projects, which is super cool in my opinion. We will understand why these exist, how the directory structure works, how to register a private library in Jenkins, and then wire two private apps to the same shared steps. We will finish by changing a couple of lines in the library and watching how both applications update instantly. a perfect way to close this series. So let's get started. Why Jenkins shared library? Now remove the name Jenkins shared library from your memory for some time and let's understand what we have been doing thus far. Now let's say you are dealing with 20 applications and these 20 applications each of these will have a repository and then all of these repositories will also hold a Jenkins file and there could be multiple steps that are repeated in all of these Jenkins file. But Vun why would I repeat my steps? I want you to know that when you are dealing with let's say a project and that project is supporting let's say 20 applications you won't be creating different image registries for all these 20 apps. You will essentially have a common image registry and in that image registry you will have all the container images be it for development workloads, staging workloads or production workloads for all those 20 applications and not just image registry. Think of it like that. the Sonar Cube server, you will have a common Sonar Cube server across all these 20 apps. Privy. Now when you are performing a scan, let's say you are flagging high and critical level vulnerabilities in your container images and for that the command that you run is common. Hence that command is repeated in all the 20 Jenkins file. Let's say for example now you are flagging your high and critical level vulnerabilities in your images using a specific tree command that we saw in our mega project which is the previous video. And now your manager comes to you and tells you, "Okay, Abishek, for now we were only flagging high and critical level vulnerabilities, but now I also want you to include medium level vulnerabilities. If Trivy finds any medium level vulnerabilities, you fail the pipeline." Now in that case if your command is repeated 20 times in those 20 Jenkins file then you would have to make modifications at 20 different places and that is brutal. Now someone is thinking why can't I automate? Now developing an automation for just 20 changes might feel overwhelming. So let's say you decided to do all those changes manually. What if there are errors in copy paste while you are doing this manually? This increases the risk. Hence, what if you centralized that command at a central place and then in all of those 20 Jenkins file, you were calling that central place. Wouldn't that be awesome? And if you have to make any changes, you just make the change in that central place. And since all of those Jenkins file for your 20 apps is already referring to that shared location to that central location, your work is done. You just make the change at one place and you are done. And I just gave you example of image registry, sonar cube server, tree commands. But imagine docker push command, docker build commands. All of these are common in most of the pipelines. You do not want to repeat things again and again when you can have them centralized at a single place. And if you are from a programming background, I want you to immediately contrast this with functions for things that you have to do again and again. You don't write code for that same thing again and again. You just create a function and then you call that function whenever you want to do that specific thing. And Jenkins shared library helps you do the same thing. It allows you to extract all the commonalities and dump those commonalities into a central shared place from which you can call those things. As simple as that. I hope this has given you a highlevel view of why we need something at a central place. Since I already have a slide for it, let's read what we are saying here. Too many pipelines repeat identical CI/CD steps everywhere. Changing a standard step requires editing every project. So you have to edit 20 Jenkins file in our example. And here I [snorts] was just saying 20 apps. But let's say each application has four microservices. Then 4 into 20 you are dealing with 80 Jenkins files and imagine editing those files. It's cumbersome. You don't want to do that. You want a way via which you can make the changes at just one place. And all those 80 microservices, all those 80 Jenkins file can just refer that central location and it will find out whatever is needed and how all of these things are wired. We will see that diagrammatically. But at this point of time, I just want you to understand why something like that was needed. Because we DevOps folks do not just handle 20 30 microservices. You will be you will be part of projects where you are dealing with hundreds thousands of microservices and in those scenarios you do not want to deal with single Jenkins file. You will have a central location which will be holding all the commonalities. Inconsistencies appear when teams copy paste. Like we discussed, updating tool URLs or credentials become slow and risky. Now imagine you have sonar cube at a specific IP address. And for this example, let's say you have configured your Jenkins file to reach out to an IP address which you should never be doing. You should be using DNS names always. But let's say that IP address changes. then you will have to make changes in 20 different places or 80 different places. You don't want that. And tool URLs can change. So keep these things in mind whenever you are architecting a CI/CD pipeline or whenever you are architecting a solution. All these things scalable. Is the solution I am proposing scalable? The client today wants 20 microservices. But shall I ask a question to client? How about 6 months down the line? Do you intend to deploy more microservices? Do you intend to rearchitect the application that are traditional VMs into microervices at a later stage? So all these plannings, all these questions should come to your mind even when the client says I just have 40 microservices or 20 microservices. Always ensure the solution that you are proposing can be scaled. And this is not just applicable for Jenkins shared library here. It is applicable for cloud environments, for traditional virtual machines, for on premises, for CI/CD, for Kubernetes or any IT solution you are dealing with or even your personal business. Is that scalable? How do I scale that? And if I want to scale, what are the other things that I must ensure must be in line when scaling becomes necessary. Last one is central teams struggle to enforce organizationwide pipeline standards. Now if you have a central place, you can always enforce the usage of shared libraries. So that once you have defined that this is the sonar cube server that everyone must be using then they just call that shared library and they can use that sonar cube server. Now this is important for your security teams because security teams would want that anyone that is running any pipelines their pipelines must be scanned for SAS for code quality code coverage and so on. For that you must enforce these things and all these results must be dumped onto a single server or single sonar cube server for example and then shared library is something that will help you achieve that. Now all these points cover why do we need Jenkins shared library. Now let's see what is a Jenkins shared library. A Jenkins shared library is a central like we said version controlled repository. I want you to know right now itself that the shared library that you are creating will be updated as your application progresses. Maybe you added a sonar cube step. So you will be adding that sonar cube step in your shared library. Maybe now you want to scan medium level vulnerabilities as well. So you will be editing your shared library. Now since it is version controlled, you as an administrator have a choice whether to use the latest version of the shared library or a version that was pushed on let's say 21st of July. So it gives you that level of freedom. And then while configuring Jenkins shared library, we will see what all other options are available. You can even supply a commit hash. So I want my pipeline to run with the Jenkins shared library status as it was on this commit hash. So this gives you a lot of flexibility. Maybe for application one who are using the same shared library a specific version or a specific tag does not perform medium level scans and that is exactly what is needed by app one. But app 2 requires even medium level vulnerabilities to be scanned. So that is possible because these shared libraries are version controlled and Jenkins gives you the freedom to choose the version of the shared library that you want to deal with. So let's read this again. Is a central version controlled repository for reusable and standardized pipeline logic. A central repo to store reusable pipeline logic. Standardizes CI/CD steps across many projects. Version control library pipelines can be imported by Jenkins files. Now this is interesting. How does my pipeline job knows which library, which shared library to use? because I can have multiple shared libraries but I also want app one to use that shared library but app 2 to use that shared library. How do I do that? You define that in the Jenkins file itself. You define that this Jenkins file should be using this shared library. That Jenkins file should be using shared library too and so on. Next is single source of truths for build, test, deploy, scan and image ops. Now there could be multiple stages in your CI/CD pipelines. The steps or stages are not limited to what you see here. Maybe you are doing something else as well. If there are commonalities across multiple applications or multiple microservices, you can always take the common thing out into a shared library and that's the reason it is called shared library because it is shared between multiple Jenkins files and those Jenkins files could be pertaining to your standalone applications or it could be for your three- tier architecture or it could be for your microservices. Now we have the understanding of why and what of Jenkins shared library. Now let's see how Jenkins connects your apps through a shared library. Now let's understand what is happening in this diagram. We'll be dissecting this step by step. Firstly, we have two applications and these two applications have certain commonalities and we now want to use Jenkins shared library here. Let's see what all are the moving parts that are there and how to wire these moving parts together. So we have app one private repository. As you know your application code would be residing in private repos. So the example that I'm giving here is close to production. So app one private repo is here. App 2 private repo is here. And then we also have a repository for the shared library. As I told you shared library is version controlled. So if it is version controlled, how it is version controlled? Because it has its own repository. In this example, we are saying we have three repositories. And in this architecture, all three repositories are created in GitHub. All three repos live separately in GitHub. But Jenkins stitches them together through the shared library. Now at the very top you see Jenkins controller, checks out these repos and loads the shared library. Why I'm saying loads the shared library? because it is the Jenkins file in which you define which shared library to use. Now I will quickly give you a glimpse of what is in app one private repo. It has the app code plus it has the docker file but plus it has a Jenkins file. Now docker file may be or may not be there. If you are dealing with non-containerized applications and you are using your CI/CD to deploy those then docker file of course will not be there. But I am taking an example which we will see in the demo. Hence I also have the docker file. Now let's see what all things you will change in Jenkins file when you are dealing with shared library. So first is import the shared library and for reference I have marked the step here itself. Now understand if my Jenkins file should be using and when I say Jenkins file understand that your application or your microservices will have Jenkins file for them. So I am talking about that Jenkins file that would essentially be placed with your application code in the repository where your code is committed or pushed. So you have Jenkins file here. Now in the Jenkins file at the very top I mentioned that hey Jenkins file this is the shared library I wish to use. So here I'm saying use my first shared library at the rate main is you have to use the main branch and we will see why this matters once we move to the demo section. So I have two demos for you. This first demo is a simple one so that you we can stitch the story together and then second demo is a little advanced one which you would see in production. It's like production. Then second is call the shared library function. So first is import the shared library and how we are importing this shared library by defining this step at the very top of our Jenkins file. Then call the shared library function. I will come to this in a little while. Now when you are creating your shared library here is the shared library. Since I told you that our shared library is also private, it is obvious that when you are configuring your shared library in your Jenkins, you will be supplying the repository URL along with the credentials that Jenkins must be using to access your shared library private repo. So that is what you will be doing here. Also, you will be selecting the branch or tag and I have missed one thing or the commit hash. You can supply these things and we'll see what these things are later. For now, understand that the Jenkins file has at the very top the library it wishes to use. Now let's see what is happening here. Shared library has a defined structure. So for example here I have shared library private. This has three directories src, v and resources. Now, right off the bat, v is the most critical one for us devops folks. Now, v is the directory that contains simple top level groovy scripts that act like functions. Now, this is a mouthful, I know, but we will be dissecting it step by step. In this lecture, we will be only discussing the v one because this is the one which is the most important one. SRC and resources are for advanced use cases. For example, you would use src that will hold your groovy and java classes for complex object-oriented logic and resources. Anything other than Groovy or Groovy files you will find in resources section. So for example, if you are using YAML, JSON, templates or scripts, all of those will reside in resources. Now I will not be covering SRC and resources because this lecture is meant to give you a view of shared library and the things that are most commonly used. If I would have covered SRC and resources, this would become a programming class and it will be too complex. So I do not want to do that. But I assure you once you have understanding of what I'm teaching here then you can go forward and conquer any of these you know shared libraries and you will understand what is happening. So with that said let's see what is there in V. Anything placed inside V is treated as a global variable and becomes directly callable from your Jenkins file. Now what do I mean? For example, if you see this snip here, what we are doing is this is my Jenkins file and I have written build with Maven here. Now why I have written build with Maven here? Because inside the V directory I have created a file that is named build with Maven.groovy. I'm not adding groovy here because extensions you are not supposed to add but you call this thing using the file name without the extension. So if you want to call this function that you see here that is doing maven clean install then you would essentially call that by using the file name. This is a critical piece to understand. You do not have to specify anything that is inside. What you do is you just call the file name without the extension. And what will that do? It will go to that file and invoke the function. And what is the function? The main function in anything. Groovy inside. V is the call function. And within the call function, we are running a shell command that says mvn clean install. Now I want you to imagine with me right now. Let's say you have 20 applications. All those 20 applications are running MVN clean install. Your manager walks to you and tells you I don't want to run MVN clean install now. I just want to run MVN clean package. Now if you have been through Maven, you will understand what I'm saying. But if you do not have understanding of that, go and watch that lecture. I have that in this channel or just understand we are changing certain command. So here our manager says change this install to package. I don't want you to run the install just run package. So you will just be changing it here and your Jenkins file is already calling that function from here already calling that file from here. So once you change it here all those 20 Jenkins file that are using this shared library will be running MVN clean package instead of install. I hope this makes sense. Now if you have understood up till here that is all there is to Jenkins shared library. Having said that let's see what we want to discuss next. Each file must use the Groovy extension. That is understood we are using it. The file name becomes the function name as I told you. So here I'm calling it build with Maven because this file is named build with Maven. We do not include the extension when we are calling it from the Jenkins file. Recommended naming style is camel case. So that's why you see the first letter is lower case and then each word after that starts with uppercase letter that is camel case for you. Jenkins looks for a call function inside each file. Like I told you the main function that is called is call. So you would see that call is always there. This is the main function that gets called whenever you are calling a file. And then that main function can have multiple sub functions. But the main function that gets called is the call function. So we have this understanding. Now let's do first a simple demo and then we will move to a complex demo. So let's go to our browser first and then I am creating a Jenkins server along with you a Jenkins controller. Now if you already know the steps involved in Jenkins installation you are good to go. You can skip this section if you already have a Jenkins up and running. If you don't you can follow along with me. So I'll write Jenkins controller because that is what I am creating. I want to use Ubuntu. Ubuntu 24.04 LTS is fine by me. And then here I am choosing this instance C7i flex large because this will make things faster and I want that 2 vCPUs 4 GIB. these instances which have free tier eligible. I'm using these because I can use these with free AWS credits. I'll choose this one. Then here the key pair that I wish to use is cloud with VJOS SJ Mumbai. And then I will scroll further down. I already have a security group created and the security group that I wish to use is Jenkins controller SG. And if you have followed the previous mega demo then you know Jenkins controller SG only allows two things. It allows port 22 from everywhere which you will not be doing in production and it allows 8080 that is the port on which Jenkins listen and that also from everywhere. So for now only two ports are opened for the outside world. I'll scroll down. I'll change this to 20 just to be on the safe side. Although we wouldn't be using this much storage. I'll scroll further down and we are good here. I'll click on launch instance. By the time it launches this instance, I'll go to my GitHub repository. I'll go to Jenkins basics to production. That is the repository for this lecture. And then I will go to shared library. Now whatever we'll be doing in any of these demos or whatever theory I have discussed is thoroughly covered in this repository. So I would encourage you to go through these and if you find this helpful I would encourage you to start the repository as well. So here I'll go to lab install Jenkins controller. So these things we have already done. I will scroll down and then what I want to do is I want to SSH into the machine and then I want to give this machine a logical host name so that we know what we are dealing with. So I'll come here. I'll go to instances. I will click on this. I'll click on connect. Then I will copy the command that can be used to initiate the SSH connection. I'll go to my terminal. I am in my home directory. I'll cd into SSH. I already have the key that I wish to use here. It is cloud with varosh sjmumbai.pm and I already have set the correct permissions and you can follow the documentation that I have shared in my GitHub notes if you want to set the permissions as well. So I'll press enter and I will click on yes this is trust on first use. I will clear my screen so that I have more real estate and then I will copy this command to set the host name. Now the host name is set to Jenkins controller. After that I will also set the time zone so that we can study the logs properly. Now this will set the time zone for this virtual machine for this operating system. But JVM also requires the time to be set correctly. And JVM will be there once we install Java 21. And we are installing JDK. JDK is Java development kit. I keep on mentioning this because I want everyone to understand that there is a difference between JRE and JDK. You install JRE when you want to run Java applications. But when you want to build the Java applications, you also want compiler to be there. and JDK is the one that comes with compiler and other essential tools that are required for building a Java application or troubleshooting a Java application. I'll copy this and then I will paste this here. So this will install Java for me. Then I will scroll further down. Now we will begin installing Jenkins. Now installing Java is a prerec for Jenkins which is why we installed Java. Now we will be first adding the repositories for Jenkins and then we'll be installing Jenkins. So I'll copy all of these. I'll go to my terminal. I'll let this complete first and once it is I'll paste the commands. Okay, I'll paste the command. Now you can see that we have all the things. Java compiler version is 21.0.9 and open JDK version is 21.0.9 which is fine. I'll click on enter and then I will move to my repository again. Here is the part where I am setting the JVM time zone. So I will be using this non-interactive command to do this. You can use either of these. Both of these are doing the same thing. This will just do whatever I want in just one click. I'll go here. I'll paste it here. I'll press enter. And then I'll come here. Damon reload will reload the unit file. This will enable Jenkins so that even after a reboot Jenkins starts automatically. Then we are checking the status in the final command. So I'll paste it here. I'll press enter. So I see the Jenkins service is running. I'll quit this. I'll go to my browser. I will come here. I will go to instances. I will tell him to remind me later. And then I will copy this public IP address. http. It's not HTTPS. Remember folks, I'll paste it here. It is 8080. I'll press enter. And here it is saying you can copy the password from this location. I will go here. P sudo cat. I'll paste that here. I'll copy the password. And then I will paste the password here. I will click on continue. Never. And then here install suggested plugins. That is what I want you to choose. Now I want you to know that [snorts] once this will take a minute or so we'll go back to our repository. So we have checked the accessibility we are able to access Jenkins. Now we also must install Docker engine onto our Jenkins controller. But Warun why now understand that Jenkins is just an orchestrator. You would want the tools that are required for your pipeline to be available in Jenkins. So if you have watched my previous lecture, if we are doing TV scans, we want TV to be installed into Jenkins. If we are logging into AWS ECR or running AWS specific commands via AWS CLI, then we would want AWS CLI to be installed onto our Jenkins controller or to our Jenkins agent. If Jenkins agent is the one that is actually running the jobs and as we have seen in this series thus far in production environments, you will have the controller that will just be used for creating jobs and so on and the actual leg work of running the jobs will be performed by your agent and we saw that in our mega demo. But in this lecture, our controller is acting as both controller and it it is also doing the leg work. Leg work as in it is the one that is running the jobs for us. Since our jobs that we'll be creating in this lecture, we'll be using docker commands because we'll be building a container image and then we'll be deploying a container using that image. For that, we need Docker Engine installed, which is why these are the steps that we'll be using to install Docker Engine onto our Jenkins controller. So, I'll copy all these commands. I will go to the terminal here and I'll clear my screen. I'll paste all of these commands here and I'll press enter. So, this will install everything. I have omitted the first one because this is a fresh VM. I'm pretty sure it does not have Docker engine already installed. Once this is done, in the next step, what we'll be doing is we'll be adding our Jenkins user in the Docker group because all the Jenkins related jobs will be running with the user Jenkins. So, we want that user Jenkins to be able to create Docker containers for us, which is why we are making Jenkins user part of the Docker group. when in the next step we are making Ubuntu user also part of the docker group because the user that I am using to perform tasks is Ubuntu and I would want this user to also able to run docker specific commands because I'll be using this user for verification. So I'll quickly copy these I'll paste them here and before I can run before I run the restart command let's see that if this is okay. So here I will create a user which will be named cloud with varosh. I will give it a secure password. Here again I'll confirm the password. Full name is Vun Jooshi. Email address is abcthexyz.com. I'll save and continue here. And here I will leave this as is. Save and finish. Start using Jenkins. Now finally I will run this command that I that will restart Jenkins. I'll go to my CLI. I will paste that here and this will restart. And then finally what I'll do is I will verify that the user Ubuntu can run docker - version and then I will verify that user Jenkins can also run dockery version. I'll come here. I will paste these commands here and I can see both of these can run this command. So docker installation is done and now Jenkins and Ubuntu user can run docker specific command. So we are good here. Now let's move to the demo section. I'll remain in my browser. So what I will do is I will go at the very top and then I will open this thing and then I will go to repositories and now we want to do a simple demo. So what I will do now I will create a public repository first and then we'll move to the private repository. I'll click on new and I will call this shared library demo. I'll scroll down. This is already public which is fine. I will click on create repository. Now when you are dealing with this you won't see an option to create a directory. Remember what I told you. If you see here you will see three folders src v and resources. We will not be discussing src or resources. So we'll just be talking about v. We'll go here. We have to create a directory named v. So I'll click on create a new file. Here I will write V but I will also add a forward slash which will make V a directory. Then here what I want to name this file. Remember what I told you whatever name here you give you can call that in your Jenkins file without that extension. So and we have to use camel case because that is what is recommended. So I will come here and I will just call this simple echo because in this demo we'll just be echoing something and then I will also mention dot groovy. This is fine what I want to enter in this file. So I will quickly copy the contents and I'll paste it here. Now let me explain this to you. I already told you that we will be calling a function named call. So call is the main function which will get called whenever you use simple echo in your Jenkins file. And then what we are doing we have this uh parenthesis here. We open and close a parenthesis. Then we have a curly brace. And within the curly brace we are saying echo Jenkins shared library project with cloud with valor. And then we are closing the curly brace. That is all what we are doing here. I will click on commit changes. Copilot will be you know give me a commit message. Add simple echo function to echo a message. I'll click on commit changes. So we have one file created here. Now if I go to the diagram we have this part sorted. Now we want to create a repo. Here private repo is shown but for now we'll be creating a public repo. And then we have to create a shared library in Jenkins. So let's go to our Jenkins UI. And here first let me change this to dark. And then I will zoom in a little. And here I will go here. I will hold on cloud with where Josh was my user. Then I'll enter my secure password. keep me signed in. Sign in. Okay. Why this has changed the appearance again? I'll move it to dark again. System and in system I will search for global and then I move to global trusted pipeline libraries. I'll click on add. It is asking me to name the shared library and I will choose a cliched name. My first shared library. Yeah, spells right. Default version. Now remember what I told you. Your shared libraries are version controlled. So you have the flexibility of choosing the version that you want to choose. So if I click on this question mark, you can either have a branch name, tag name or a commit hash. But here in our example we will be using main. So what we are saying is whatever is there in the main branch you just pick that up that is the version of shared library we wish to use and there are other things as well that you can use as you can see etc here according to the SCM. So I am choosing main here. But I want you to clearly know that why were we calling our library with at the rate main? Because we wanted our library to use main. And now you'll understand this as I progress further. I promise you. Then here is load implicitly. I do not want to load this shared library implicitly. I only want to load this when someone is calling this shared library. So what I'm saying is when someone writes in their Jenkins file that this is the shared library I wish to use only then that Jenkins file can use this shared library. Next is allow default version to be overridden. So this is the important piece. So for example if I have defined main here then I don't have to type at the rate main here. I can even omit that because the default version is already main. But I'm saying allow default version to be overridden. But if I want to let's say mention a commit hash for application two but I want the main for application one I can do that. Remember I told you maybe for application one I want to scan medium level vulnerabilities as well which was part of a specific commit for that you can use a commit hash here and here you can continue to use main because main has what you wanted. So here I am allowing default version to be overridden. Next is include at the rate library changes in job recent changes. What does this mean varun? So remember when we were discussing different jobs there was a feature when you pushed something in your repository that will trigger your pipelines automatically. Right? And this point says you whenever there is a change in your shared library and any of the pipelines any of the jobs that are using that shared library if they are configured to run automatically then they will also run whenever there is a change in the shared library. So that is what it is saying include at the rate library changes in the job recent changes. But understand this will only work if you have configured your pipeline to get triggered whenever let's say there is some activity in your repository. So it will only work then next one is cache fetched versions on controller for quick retrieval. Now understand in our example we just have a couple of Jenkins files. We'll be dealing with app one and app two as we progress to demo two. In demo one we'll just have one application and that to test application. But remember what I told you you as DevOps engineers will be aiming to reduce the runtime of your pipeline to minimum while covering all the compliance or all the requirements for your application. We said that before. So here if you are dealing with 20 30 40 applications you don't want all of those or you don't want your controller to fetch the shared library again. You want it to cache it so that your builds or whatever you are doing with your pipelines can be finished in a breeze. So that is what this is saying cache fetged versions. Retrieval method modern SCM is fine. source code management is get project repository. So this is the one that is stitching everything. So you in your job will be defining that this is the shared library you wish to use and within the shared library configuration you are defining the repository that is linked with this shared library. So understand create that mental picture in your head folks and then I will enter the repository URL. So this is what we created just now. I will go here and then I will click here. I will copy this and then I will paste it here simply. Credentials none because this is a public repository. So I will click on save here. This is saved. Now I'll click on new item. I want to create a job and this job I will call shared library job as expected. This will be a pipeline job. I'll click okay. But here I will be choosing pipeline script not pipeline script from SCM because in the next demo we'll be doing this. So for now because we are understanding how shared library work we are just choosing pipeline script here. Now what is the pipeline script that you want to run. So I will quickly copy that and then I will paste it here. Now see how simple this is. I am saying this pipeline job you should be using my first shared library at the rate main. And this is part of the syntax. You have a space here then you have an underscore here and then the pipeline job like you have the difference is here now how we are calling what we created. So we created this here in the v directory we have simple echo.groovy. So what we are saying is whenever someone writes simple echo you invoke the main function. So whenever I am calling this here I'm saying in and in the steps we are saying simple echo. So that will trigger this and what will happen? What will happen is it will type Jenkins shared library project with cloud with varos. Now why this is so powerful right now you would be saying wun why can't I just write you know echo here why do I have to go to so much trouble by creating that shared library and so on. This is just one Jenkins job. Imagine you had 100 Jenkins job which were displaying this for you and your TL walks to you and tells you that I want CWVJ to be expanded. It should say cloud with VJOS complete. You won't be making changes into 100 of your jobs. You will just make the change here and it will be reflected in all your pipelines when you run your pipeline. So here I am calling that function. I will click on apply save and when I click on build now this will do what I have asked it to do. So let's check the console output from here. So as expected you will see both here. So see it is referencing shared library demo as well because this is a public repository. We didn't supply any credentials but we supplied this in the shared library we created within Jenkins and then you can see the job ran and it said Jenkins shared library project with cloud with varos as simple as this I hope this makes complete sense to you now that we have this understanding let's move to demo two where we'll be dealing with a production like scenario. So let me give you a brief of demo 2. Demo two will be exactly like this. I would say we will be creating three private repository. One for app one, another for app 2 and the last one for shared library. So let's start doing this. So I'll go to my GitHub. I will go here and cloud with vos. I will go to repositories. Here I'll click on new and here I will call it app one private which is here conveniently. I will click on private and then I will click on create a repository. Once this is done I will again go here. I will click on repository. new repository. I will be creating a repository for app 2 as well and app 2 private and this will also be private and then I will click on create a repository and then I will also create a repository for shared library. So I'll go to repositories again. This is private. This is private. App one private app 2 private. I will create a repository for shared library private as well. So this I will change to private and then I will click on create repository. Now this part is fine. So we have three private repositories. Now when you have a private repository you need credentials to log into that private repository. So let's do that. So what I will do is I will click here. I will go to settings and then I will scroll down developer settings. Here I will go [snorts] to personal access tokens tokens classic. So we will be using a personal access token classic to access our private repositories. Understand Jenkins will only be able to check out or to see whatever is there in your repositories only when you provide credentials for the same. So in this step we will be generating the that token and then in the next step we will be configuring those credentials within our Jenkins. So I'll click here classic and then let's call this Jenkins GitHub and expiration could be 7 days. I want repo level access. I will scroll down. I will click on generate token. So you will only see this once. So copy this and do not worry. I will be removing these credentials before I upload this video. So I'll paste this here for now and then I will go to my Jenkins console here. I will go to Jenkins. I will go to settings and here I will go to credentials system global credentials and here I will click on add credentials. Now I want to add credentials which has username with password. I want to I want those to be global because I want my job to be accessing those credentials. Username is cloud with varosh. I'll enter that here. And then password that I wish to use is I will copy that token. Ctrl C and then I will paste it here. Now we'll be using this token for two things. first is for Jenkins accessing these three repositories and then we'll also use these this token for our thin client that is my laptop to push code onto our private repository. Now often these would be different not often always these would be different. Your Jenkins will have a separate pad personal access token and your thin client your laptop or your you know bastion host jump host or whatever means you are using to access your repositories will have different personal access token. So ID I will call this Jenkins ID I will give it GitHub pat. Now this is important because this is how you call the credentials. So GitHub pat is here. I will click on create. So this will create the credentials for us. Now these credentials are created. What we now want to do is I want to show you what we are building. So let's go to our Visual Studio code. So I already have a project files directory which has app one and app 2 in it. App one has the logic for app 1. So here is the code for app 1. App one listens on port 5000. App one will just say I am app 1. Welcome to cloud with VJOS. App one your friendly demo micros service built with flask shipped by Jenkins running in docker then we have a requirements.ext now with Python you will see that whatever packages that you want to you know install are there defined separately in requirements.ext and we want flask as flask is the framework which we'll be using for our application. Then here is the docker file. So docker file is simple. We are saying we want to use python 3.11 slim workdir is forward/ app. We are copying requirement.ext and then we are installing the packages that we need referring to requirements.ext so that our image size is small. We are saying do not cache anything. Then we are copying app 1.py pi into forward slash app. Finally, we are running our application. We are running our application with a username app user because you should not be running your applications as user root. If you want to understand this further, go to my Kubernetes playlist and search for security or pod security. You will find what all measures you can take to ensure your pods do not run as root. Then the user that I wish to use is app user. Expose is just for documentation here. So that my DevOps admins know that this application listens on port 5,000. And finally I'm running that application using Python app 1.py. A simple thing that we are doing. Then is the Jenkins file. Now we have already done so many demos. We have written these files from the very scratch. So I did not want to waste anyone's time in that. Hence I have already written a very small Jenkins file. It just has two stages. It has a build stage and a deploy stage. We have defined three variables. Repo app one flask tag is we are tagging this with the build number. This is available by Jenkins. So we are using the existing variables that are available for our pipeline jobs. Then port I am defining as 5,000 because 5,000 is the port on which my application listens and the host port for this will also be 5,000. Then there are stages. Build stage we are docker build- t repo is app one flask and tag is this one. Extremely simple, right? And then we have stage. We have a deploy stage. Steps is we are doing two steps. First I am saying remove any container with the name app one flask because we could be running this job multiple times. So for the very first time the job will succeed but next time if I don't have this step the job will fail saying that there is a container with the same name already there. So we don't want that to happen which is why I am first running this command. But Warun if this command fails for the very first time then pipeline will also fail because when you run this job for the very first time there will be no container with this name. So that's why I am writing doublepipe true which says that if this fails then run this command which will throw the exit code zero. So it will proceed. So this command will only run if this one fails. That is what doublepipe will do for you. Then in the next one we are saying docker run run run in the background hyphen d and then or in detached mode name of the container will be dollar repo that is app one flask will be the name of the container hyphen port. The port forwarding is whenever someone hits port 5,000 on the host they should be directed to port 5,000 on the container. And then the image that should be used while creating this container is this one. And this is the image we created in the build step. Very simple. Now in application 2, everything is same. Instead of app one, you have app 2. So if I go here, so app 2.py has everything app 2. So app 2, app 2 and then docker file as well app 2 because we are copying app 2.py. Jenkins file as well. Here you see app to flask and this application is listening on port 5050. Now we have done two main things. We have created our personal access token. We have done a walk through of both the applications that we are about to deploy. Now what we want to do is we want to push the code that is here onto our private repositories. Now what I want to do right now is first I want to show you how this looks without shared library. We will just do a smoke test. We will run the jobs and see everything is working as expected. So let's go to the command line. I will go to my terminal and this is the controller. I don't want to deal with here. Now I'm working with my laptop. So I'll go to this terminal. I'm already in project files. If I run ls, you see I already have app one and app 2. So I'll cd into app one. So right now if I do get status, I see this is showing the results of my you know another repository another uh you know directory. But for this directory in F1, this is not get initialized yet. So I'll clear my screen. I will run get init first. Now this will initialize this. Now if I run get status now, you would see that it is saying all these files are currently unttracked. So if I want to track these, I will write get add dot. Now this will start tracking all the files. Dot represents all these files. I will write get commit- m I will write initial comet with code and Jenkins file we'll ignore if there are any spelling errors I'll press enter and this part is understood but understand up till now if I go to my repository in the browser I go here here rather and then if I go to here. I want to go to home. Then uh I should have gone via show more. And then if I go to app one private, what I see here is they call this main branch. But if I go here get branch v, then I'll come to know that this is calling it master. So what we want to do is we want to change the name of our branch. So what I will do is I'll zoom in as well a little so that you can see properly. I will write get and branch and what I want to do is I want to name my branch main. So if I now run get branch v you will see it is now changed to main. Now that this is done what I will do is I will run a command. Let me copy that command. What I'm doing is I am adding a remote and this remote I am naming it private repo. You would have often seen that people name it origin. So either is fine. I prefer private repo here. So I have written private repo. I have added a remote and this one you have to replace with your username. Just give me a moment. I will write here cloud with varosh. Cloud with varosh. I will just quickly see my username there. I don't think these are case sensitive but I don't want to have any problem. So this is written in you know the case that it prefers. So I will write press enter remote private already exists. So I'll have to remove that private first. get remote remove private repo and then I will run this again. So this has now added. Now if I what I want to do is I want to provide credentials because I will not be able to push until I provide credentials. So what I will do is I'll copy this and then let me come to Visual Studio Code. So I have somewhere where I can you know uh I'll let me create a new file. I'll just create it directly here. I will call this creds and then I will paste it here and then I will go to my browser. I will go to this tab. I will copy this token. I will paste this token here. And then I will copy this entire thing and then I'll come to my terminal. I'll paste it here. And then I will run simple get push private repo. I would have done this beforehand but I was thinking that maybe there are some students who would like to see the entire workflow which is why I'm doing this again. If you have already seen this a million times in this series, please pardon me. Then I will write main here because what I'm doing is I am pushing the main branch to this remote. I'll press enter. Now this will do the push. If I go to my browser now and I go to app one, if I hit refresh, I would see that whatever files were there are available in my app one private. Now I want to do this thing for app 2 private as well. So what I will do is I'll quickly copy paste this time. Okay, I'll copy and then I'll come to Visual Studio Code. I will come here. I'll paste these commands here. I will copy this username and I'll paste it here. Okay. And then I will copy this entire command and I will paste this here. I'll have to change this to app to private. And I'll have to also change this to app to private. And I think rest everything looks okay. I will copy this. And then I will paste it here. Let me in the last command. I just want to do a force. I'll copy this. I'll paste it here. I'll do a force push. And this should work. I will go to my browser. I will refresh it. More learning for you. This is brute force, okay? Do not do this in production. Do not force push it until and unless you know what you're doing. I know what I'm doing right now, which is why it is fine to run these flags. Use these flags with caution. RM- RF orce. These can cause destruction, folks. I'm telling you people. Anyway, so let's let's move ahead. So we have done this. This is good. Now we have the code in our repository. What we want to do is we want to create the jobs that will be using these repositories. Right? So I will go to my Jenkins console. I will go here. I will create a new item. I will call this simple app one job. I'll call this a pipeline. And then I will scroll down and this time I will choose pipeline script from SCM because I have my Jenkins file committed in my private repository. Understand these things my friends and then I'll choose get here and then repository URL. As soon as I will paste that URL it will give me a red flag that my dear friend I want credentials. This is a private repo and as expected and here I will say use these credentials and be happy and it is happy. Now I'll write main here I will because main is the branch where everything is placed and then I will click on save. Let's click on build now. Now this should succeed. Why this should succeed? Because right now we are saying run this job normally. No shared library nothing here. Now this should run. I'll click on build now. Until the time this runs let's create another job. Let's call this app 2- job. And this will also be a pipeline job. Okay. And here I scroll down. I choose pipeline script from SCM. I go to app to private. I copy the URL. I go here. I choose get as SCM. I paste that here. It won't be happy for some time. Let's make it happy by providing the credentials. This I want to be main. I will scroll down. I will click on save. I will build this now. I will go to Jenkins and app one has run successfully. And this is deploying in our Jenkins controller itself. So if I go to my item, I go to this controller, I clear my screen for more real estate. I run docker ps. Permission denied. Why would you deny me permission, my friend? Let me just quickly I'll go to my repository here. Install Jenkins controller. We verified this, right? sudo hyphen new docker version Jenkins can run it but Ubuntu cannot why is that sudo docker ps we were able to run it when I last checked why is this idbuntu is part of the docker group what was that command new gp let Let me try to run docker ps. That's strange. Let me add p sudo. Anyway, we'll troubleshoot that later. But app one flask is created. And if I go to my browser, why is app 2 flask not created yet. I will click on refresh. This job has failed. So let's see why this has failed. I'll click here. Console output. If I scroll down, scroll down. Scroll down. Invalid IP address 5050. Oh, I think my Docker. My Jenkins file has a problem. So, let me quickly rectify this with you. More troubleshooting. Better Jenkins file. I'm saying hyphen p port but port port 2 * 5050. That's unacceptable. Let's correct this. App one has this correct. This one I have corrected right now. these things happen and then I'll go to iterm remember we have to commit this we have to push this so I will go to get add dot if I run get status first you will see that there have been changes made to Jenkins file I'll write get add dot get commit- m fixed port variable because we want our messages to be explanatory. I'll press enter. Get push private repo main. I'll press enter and then I will go to my browser. I will go to app 2 job build now. And if this succeeds, I will be running app one job again because I want to see symmetry. Build one, build two. It has succeeded now. So let me quickly run app one job again. So that VC symmetry. So if I go to my item and go to my controller, if I run sudo docker ps, you see I have both of these containers running. App one flask, app 2 flask. And if I go to my browser, if I copy the public IP address of my instance and I write http I forward slash forward slash I paste the IP address and it is listening on port 5000. This won't work. And someone is saying wun you have not entered the port number in the security group. How would it work? So I have to open two ports. 5,000 and 50/50. So, let's do that. 50/50. Interesting, right? I'll go here. Go to the security group. Edit inbound rules. Add rules. 5,000. I'll open it for everyone. Do not do this in production. 5050. And then here for everyone. You can write descriptions as well. And this should now work here. http this is not working 5,000 5,000 ports this yeah took some time I'll copy this I'll paste this here and then let's also check 50/50 and this should also work so this is showing app 2 that is what we expected this is showing app one which is what we expected. So things are working as expected. Now let's do one thing. Now let's create our shared library. So let's now create our shared library. So I'll go to my dashboard here. I will go to settings. I will go to system. We have been here before. Remember previously we were here when we were creating a shared library that was pointing to our public shared library that we created in our previous demo. But this time our shared library repo is private. So we have to supply certain level of credentials there don't we? I'll keep the name as is. I will keep all these settings as is. What I will do this time is I will just be adding our private repo here. So if I open this in a new tab, what is this new thing coming here? Open link in split view. Oh, this is interesting. So I can have one tab here, one tab here. We'll use it in some course or in this lecture if need be. I will go to repositories here and shared library private. I will copy the name from here. We don't have anything in this repository right now and we will soon have something. Don't worry about it. I'll go here. I will paste this here and then credentials. We have the same credentials that we'll be using and save this. That's all we had to do. We edited our existing shared library. And now our existing shared library that is my first shared library is pointing to this shared library private repo. What we want is we want to create certain files in this repository which will help us externalize the commonality. So let's do this step by step. So I'll go to Visual Studio Code. Let me close this. Let close this. And let me close this. So that we can see step by step what we are doing here. Okay. I will come here. I will first create a new folder here. I will call this shared library. I will go to shared library and I will create a new folder and I will call this v. I told you that we won't be creating src or resources but we will be creating v.s. Now what I'm doing is I'm creating a structure here and then we'll push it like we did for app one and app 2. So we have v created. Now I am creating a new file here. Now watch this very carefully. I will call this build image and then I will give a name dot groovy. Simple, right? Extremely simple. Nothing major we have done. I will open Jenkins file for one of our apps app one and what I will do is I'll do this split right so that we can see these things side by side we have our Jenkins file here and this I will also view and I will word wrap this now I have this here I what I want to do is I want to take these steps out because I will tell you later I why I want these out but for now I don't want these steps to be here. I want a certain function which will call my you know library here and my function will run this. So for now what I will do is watch very carefully. I will just cut it and I'll paste it here. Since this is build image.groovy I am only concerned about build right now. I don't care about anything else like we saw before. Here I will have the same function that we will always have and then I will have a opening curly brace. I'll come here and then I will come down and I will have a closing curly brace. We have done this. Now in this Jenkins file I will just have one thing. What I will tell this is I will write build image here and then I will just close this. What I'm saying is in this step my dear friend you just call this function and this function will know what to do. And what is that we are doing? We are doing this command. We are building an image here but we have externalized the common thing. Both of these Jenkins file had this common step which we have now externalized. We have centralized that step. That is what we have done. Now what I want to do is I want to do something similar for my deploy step. Now what I will now do is remember we are creating different files for different stages for this stage and these steps I will create a different file and that file will be called and once that file is called the function in that file that will be under call will be invoked. So we have done this for build image this stage. Now I want to do it for deploy. So I'll right click here again I'll write a new file and this file I will call deploy app dot groovy simple right and then I will take this here so that you can see side by side and I will do something similar I will copy this entire thing I will paste it here of course I'll have to remove this step from here and I will just copy these steps rather cut these steps and paste these steps here. I will go here view and I will word wrap this so that you can see more. It's already word wrapped. It's hung or what view. Okay. Okay. Anyway, so this let me close this. Now we have this here, right? This is exactly what we want to do. But here what I want to do is I want to call the function. And how do I call this function? I just write deploy app and that will call this function. And this will be run. So I will write here deploy app. That's it. This will go here and run this. Now this is exactly what I will do in the Jenkins file of app 2. But I will just have certain changes. So I'll go here to Jenkins file for app 2. Here everything else is fine. Here I will just write the name of that file that is build image. And then here I will write deploy. This will call this. I will save these things. I will close this. I will close this. I will close this. Let me just quickly review. This looks good. We are building the image here. Here we are deploying a container using that image. This looks okay to me. And this Jenkins file also looks okay to me. We are calling build image. There is correct spelling here as well. Deploy app. If I go here to this Jenkins file, this is build image and this is deploy app. The spelling is correct in both of these. I will save these. I will go to my terminal now. I will go to this tab. I will we are in app 2 right now. So get add dot get because we have made changes in the Jenkins file. So we have to commit uh both app one and app 2. The Jenkins file has changed. So I will write get commit Jenkins file changed to have shared library and I will have to also write hyphen m here and then press enter get push private repo main. This is done. I will come one step back. I will cd into app one and this time I will write get add dot and then get commit jenkins file to shared library. This is fine and then I will just push this to main and we also have to do it for our shared library. So I'll come one step back and then I will go to shared library directory. We run ls here and I run get init first because I don't think this was initialized. Yes, this was not initialized. I will run get add dot I will run get commit- m then I will write here first commit in shared library and uh we'll have to supply the credentials as well here. So if I run get branch- v, this is the master branch. So I will run get branch- m main. And then let's go there to our visual studio code. I have creds here. Then we want to run these things. So let me quickly copy that. I will go to my browser and this is the this is the directory and here I want to just copy this name from here. I will paste this here and I will paste this here. I hope there's no space right. It's correct. And then I will just copy these three things. And then I will come here. I will paste it here. and I'll press enter. So this is done. I will go to my repository and then I will just refresh this to see I can see all those things here. I can see v here first commit and shared library and then I see both my groovy files here. So I will now go to Jenkins and then let's rerun these jobs. So we have done the shared library part. We have defined the private repository. We have pushed to our private repositories. We have the fresh code everywhere. Now finally let's run this. I'll click on this. I'll click on this. Let's go to one of these jobs and see everything is working. So this is this has failed. Beginner's luck is not with us today. So I will go to console output and see why this has failed. Error error error. Build image found among. This is interesting. Okay, this is for app one. Let's see if app 2 is showing the same thing. We copy pasteed. So that's expected. I will go here. Console output no walk Jenkins change Jenkins file change to have shared library. That's fine. That's our commit message. End of pipeline stage deploy skip due to earlier failure. So this failed somewhere here. itself. Okay, let me see the code again. Wow. Just wow. Can anyone tell me what is wrong? We don't have that library block at the top. How would this work without that? So, let me quickly add that folks. I'll come here. I will add that here. I will add that in Jenkins file of app one as well. These things happen. Okay. And I did not plan this. This I actually forgot. So I'll go to my terminal. I will come one step back. I will cd into app one. I will get add dot get commit- m fixed. Let's write that. and get push private repo main. This is fine. Now let's first run app one. Okay, then we'll come to app two. Let's see some success this time. App one job. I'll run this. And this is running. I can go to the console output from here itself. And I think this time it succeeded. Okay, it's a success folks. Some success. I'll go to my terminal and let me first see I did it in both the files right I added this here as well right let me just go one step back I will go to cd app 2 and here I will run get add dot get commit- m fixed in production you will write you'll expand this message not just fixed I will write get push private repo main. So I'm pushing main to this private repo. This is done. Everything looks good. I'll go to Chrome now. I will go to Jenkins. I will now run app 2. So this was build number four for app one and build number three for app two. I will quickly refresh this. Now both have completed successfully. I will go to my terminal. Now I'll go to this controller and let me run sudo docker ps and I see both of these containers now running app one flask and app 2 flask both are running and I also want to show you the logs for one of these jobs. So I'll come here and then I can go to stages and this will tell me what happened in each of these stages. So our containers are running just fine. And if I go to build I can see what happened in the build stage. Both the shared library and our private repos along with the shared library repo were used to build our application. So if you come here and I go to console output you can see all the details here. So shared library was used and then I would encourage you to check all these logs to understand what was unfolding underneath. How was Jenkins orchestrating everything. So I would encourage you to do that. But for now you would be thinking Vun you have done these things pat on your back. It is good. But how this is useful for me? Now I want you to imagine your team lead comes to you and tells you Abhishek yesterday someone yesterday we patched our docker host and upon the reboot of that host our containers didn't come up. First is this. I want you to fix this immediately. Second is there are no labels in your container images. I want you to label the container image with the maintainers email address. You Abishek are already using shared library. You know and you nod to your TL I will get this done as soon as possible. You raise the change request and then the request is tracked there. So what you will do to fix this? Now if you were not using shared library, what would you have done? You would have come to each Jenkins file and you would have changed the command to add certain flags. Now what those flags are, we'll see later. But if you had 20 applications or 200 microservices, you would have made changes in all of these. But you are smart. you are using Jenkins shared library. So what you would do is you would come here first. Let's replicate that problem. So if I go to my iterm right now both of my containers are running. So if I run sudo systemctl restart docker and I press enter. Now this will restart docker for me. We all know that. But after docker has restarted, let's see what is the status of our container. So if I do that, you see both my containers are in stopped state. So if I run docker ps now and I have to add p sudo here and I have to add hyphen a flag to see the stopped containers. You see that both of these containers have exited. So the docker service was restarted or when the host will be restarted, we would see that our containers will stop and we don't want that. We want our containers to be running 24 + 7 because these containers are running a web application which is accessed let's say 24 + 7. So we would want these containers to automatically restart start when the docker host is rebooted. So what I will do is I will come to my visual studio code. I will go to my shared library code. I won't be touching my Jenkins file. Okay. I'll go to this deploy. And here I will add a flag. Now the flag that I will add is I will call this restart and then I will say unless stop. Now if I have manually stopped this container then you don't restart it. But if there is a docker you know service restart or the host is rebooted you automatically restart this container. So I have added this step. Now this was requirement one. Requirement two was I want a maintainer label. So what I will do is I will come to this build image and here I will add another flag. I will add label and here I will write maintainer is equal to cloud with vjosh at the rategmail.com and by the way this is a valid email address. If you want to interact with me if you have certain feedback feel free to reach me on this email address. Now we have added both of these points. We'll have to first commit these and once we have committed we can rerun our pipeline jobs to see whether our changes have taken effect or not. So I'll come to my terminal and here I will go to this tab. I will go one step back. I will cd into shared library. Here I will run get status and this will show me that you have made changes to two of your files. Now let's run get add dot get commit- m. I will just write automated a few things and then I'll press enter and finally I will run get push private main. I'll press enter again. I will go to my browser and I have a habit of always refreshing my repo when I have pushed something new. I don't have a clue why because if that h terminal has shown success it is there right but I do this refresh all the time and then once this is done I will come to my Jenkins screen I will click here and I will click on build now and once I go here this is running and I want to do the same thing for app 2 job as well. So I wanted to do certain changes. I did those changes in my central shared library repo. I did not modify my Jenkins files that were placed in app one and app 2. And just to let you know all these files I will be committing onto the GitHub repositories and I will also include the old Jenkins files so that you can follow along. So what I will now do is I'll go to my terminal here. I will yeah I'll go to the terminal I'll go to this controller and now I will run docker ps and I see both of my containers are now running. So if I first run docker images, this will show me all the images that are there in this docker host. And I see for app 2, this is build five. For app one, build five is the latest one. And if I go to my browser, what you will see is if I refresh this, build five is the latest one. And both of these builds have succeeded. So if I run docker inspect, I will write this one. Let's check it for app 2. I'll run this and I'll press enter and I'll have to add pseudo. I'll do this. And if I scroll up, you will see there is maintainer cloud with varjosh at the rategmail.com. So first requirement is done. Second requirement was our containers should be automatically started when there is a host reboot or the docker service is rebooted. So let's do that as well. I will run the command p sudo systemct ctl restart docker and then we'll be checking the status of our container. So let it do its magic and then let's run docker ps and you see our containers have been up for 5 seconds because that is when the docker service came up. So our containers both of these are up and running. Now this is something very simple that I have shown you but I want you to understand that right now I have not moved certain parts of my pipeline into my shared library. For example, if I let's say move all these things also there then changing the repo or changing the tag port all of these things becomes so simple. So what I want to now do is I want to quickly take you to my GitHub repository and I want to show you what all are the possibilities when you are using shared library. So I will move at the very top and then I will scroll down and here I will choose why centralizing config matters. And here you will see a lot of things. I'll suggest you give it a read. So this really starts to shine in real CI setups where multiple apps rely on common tools like SAS scanners, dashed tools, image scanners, code quality platforms. So all of these things are common in most of the applications. So what you can do is you can move these things out. Maven commands, you are running the same Maven command for most of your apps. you can move that to a shared library. So I hope all of these things make sense to you. What I will also do is all these files that we have used you will find in the repository. I will also move the old Jenkins file that we were using initially to the repository of this lecture. With that said, it's a wrap for this lecture. This was our final lecture in the Jenkins basics to production course. You saw how shared libraries remove duplication, simplify maintenance, and let you update many pipelines by changing one file. Both apps picked up a new build and deploy logic automatically, proving why real teams rely on this approach. If you have any questions, feel free to ask them in the comment section and I will reply. If this helped, do consider liking, sharing, and subscribing. It will mean a lot to me. Thank you very much. If you have made it this far, well done. Completing a long hands-on CI/CD master class takes focus and discipline, and that effort matters. By now you should have a clear understanding of how CI/CD works in production. Not just Jenkins pipelines, but how code flows from commit to build, testing, security, and deployment in real teams. If you practiced along with the demos, you should also feel more confident reasoning about CI/CD systems, identifying gaps, and understanding why pipelines are designed the way they are. I also want to say this clearly. Your feedback matters to me. If this course helped you in production or interviews, I would genuinely love to hear that. And if something felt unclear or incomplete, tell me that too. I read the comments and use that feedback to improve future content. All the notes, YAML, and Jenkins files used in this course are available in the GitHub repository linked below. Treat it as your long-term reference when working on real pipelines. If this course added value, the simplest way to support the channel is by liking the video, subscribing to the channel, and leaving a comment. It really helps this content reach more learners. And if you would like to support the channel further, consider joining as a channel member. I don't lock content behind PayWall's membership is simply a way to support the free in-depth learning I try to put out consistently. Finally, keep building, experiment, break things, fix them, and keep asking why systems are designed the way they are. That curiosity is what will make you strong DevOps engineer in the long run. I will see you in the next video. Thank you very much.

Generated algorithmically for Search Engine Indexing.

Summarize Another Video