Hi, Habr! At first glance, the title of this article may seem strange to you: Java and Visual Studio - what do they have in common? Why Visual Studio in general when there are a lot of other cool Java development tools: Eclipse, NetBeans, IntelliJ IDEA and others (we’re not going to make a holivar). In fact, Visual Studio now is not just a development environment, but a whole product family, where Visual Studio IDE is just one of the tools. Under the cut, we'll talk about Microsoft Visual Studio Team Services (VSTS).
Microsoft Visual Studio Team Services is a DevOps cloud platform that allows you to flexibly build DevOps processes for continuous integration, assembly and deployment (CI / CD). Of course, this is not complete without support for version control, built-in bag tracking, Agile planning tools and many other opportunities for developers of different “religions” and “suits”. And, of course, for Java developers, there is also useful functionality for DevOps automating its solutions. How they can effectively use the possibilities of VSTS, and will be discussed in our today's article.
During its 20 years of existence, the Java platform has built around itself a rich ecosystem from various tools for building, deploying, testing applications that Java developers use in their daily practice, and many of which, in fact, have already become the industry standard (Maven, Gradle, Ant , JUnit, JMeter and many others). And, of course, each developer or team has its own preferences for choosing tools: someone is used to building a project using Maven, and someone uses Gradle. The main idea of ​​VSTS is to provide developers with opportunities that will allow building CI / CD processes as flexibly as possible using familiar and familiar OSS tools for building, deploying, testing. VSTS is a cloud platform (unlike the
Microsoft Team Foundation Server , which is deployed on-premise), however, thanks to such a mechanism as
build agents , which we will discuss below, you can build, for example, on-premise (in your data center), and, of course, on your virtual machines in the clouds (Azure, AWS, Google and other platforms).
')
The most illustrative features of VSTS can be illustrated by a simple example of a Java application with a full build and deploy cycle. Immediately I will make a reservation that I will not describe the full and detailed step-by-step tutorial, the
purpose of this article is to convey the idea of ​​using the VSTS platform for Java DevOps processes .
For our experiments, you will need a Microsoft Visual Studio Team Services account.
You can get it for free using your Microsoft Account or by creating a new one.
So, let's begin our fascinating journey. By registering, we need to create a project.

Specify the name of the project, Git as a version control system and create a new project.

After creating the project, VSTS automatically creates a new Git repository and offers to clone it to your work machine using the Git CLI or to clone it and open it in a Java IDE, for example,
IntelliJ IDEA , also supported by
Eclipse . For these two IDEs there are plug-ins for integration with VSTS.

We will return to integration with IDE in our article a little later, but for now just clone the code from GitHub. Click Import, specify the URL of our GitHub repository (
https://github.com/easkerov/SampleJava.git ) and complete the import. In our case, the public repository and authorization is not needed, but, of course, you can use private repositories, specifying the necessary credentials for access.

After the import is complete,
Files explorer will be opened for our repository, where you can add and make changes to the application artifacts, switch between branches or create new ones. Of course, within a single project, there may be several repositories, and you can configure separate CI / CD processes for them.
And we proceed to the next stage - the assembly of our application. To do this, we need to create a
build definition in our project.

There are 2 important concepts in VSTS related to configuring CI / CD processes. This
is the build definition (Build Definition) and
the release definition (Release Definition) . Both definitions make it very flexible to build DevOps processes through the concept of tasks. Tasks can be of different types: for example, building a project in Maven, executing a Bash script, building a Docker container, copying files, deploying an application to a Tomcat container - these are all examples of tasks from which you can build your CI / CD processes. When creating a build process definition, you can use an already prepared template with a given set of tasks for a specific task (for example, building a project in Maven / Gradle) or create an empty assembly definition and determine the set of tasks yourself in this process. In our case, we will select an empty template and define the tasks in it ourselves.

The order of assembling and publishing our application will be the following: the first step is to install all front-end dependencies using the Bower package manager, then build our application in Maven, as a result we get a
war artifact that we place in the Docker container with Tomcat and publish it in Docker Registry (in our case it will be a private registry based on the
Azure Container Registry ).

Having created an empty template, we must define the necessary tasks in it. Each step of our CI process is a separate task. For example, the Bower assembly is a separate task that we need to add to our CI pipeline and configure. However, not all tasks are available out of the box in VSTS. For example, Bower does not have a default task in VSTS. But, fortunately, there is the
Visual Studio Marketplace , where Microsoft and third-party developers publish VSTS extensions for integration with various tools. Installing these extensions in VSTS is extremely simple, just find the module you need and install it in your environment by clicking Install and specifying your VSTS account.

Before you define specific tasks for assembling our application, you need to specify where our application will be built. We can collect it using the mechanism of the build and release agents (Build / Release agents) that is in VSTS. Agents can be of two types:
hosted and private .
Hosted agents are the easiest to use, since these environments (VMs) are built by the VSTS platform itself, with all the resulting advantages of cloud computing (maintenance, upgrade, etc.). And there is a choice of OS for the environment - it can be Windows / Linux (the latter is still in the preview). But what if we have a complicated case, and for the environment in which we build a Java application, we need a specific complex configuration of the components of the assembly (for example, you need to define the Maven private repository in
settings.xml ). In this case, you can deploy the environment yourself (on Linux / Windows / MacOS), install the
Private Build Agent and initiate an application build in it from the VSTS console. And your own environment (VM) can be deployed in the clouds (Azure, Google, AWS) or in its own data center.
For our example, a hosted agent on a Linux machine is sufficient. You must set this explicitly in the process settings (Process).

Next, we build the CI process, and determine the tasks that will be performed in it.

In our CI process there will be 6 tasks. Let's take a closer look at what it will consist of.
Before the build begins, the cloning of files from the Git project repository to the current environment (virtual machine) occurs automatically, then VSTS performs the sequence of tasks that we specified in the build definition.
Bower.Install. The first task, Bower.Install, allows us to install all front-end dependencies using the Bower package manager. To do this, you just need to correctly configure the task settings. As can be seen from the screenshot above, the configuration is simple and does not require special comments (unless you need to explicitly specify
--allow-root ).
Maven.Build. In the second step, we build the application using the Maven task, and
pom.xml artifact from the Git repository of our application. In addition to the task name and Maven goals, you can configure the JUnit test publishing parameters, specify JDK settings (version, architecture, memory settings, etc.), as well as connect tools for static code analysis (SonarQube, Checkstyle, PMD, FindBugs) and coverage code (JaCoCo, Cobertura, etc.).

Docker.ImageBuild. In the third step, we build the Docker image using the ready-made Dockerfile from the Git repository of our project. For this step, the Docker task is used (which will be used in the next step). As the Action parameter, we select
Build an image and Dockerfile. Additionally, you can also specify options for assembling an image.
Docker.ImagePush. In the fourth step, we publish the image we collected in the previous step of the Docker into the private Docker registry, in our case, the
Azure Container Registry (ACR) is used as the registry, but you can also use other private / public Docker registry (Docker Hub). Please note that here we use the same Docker task as in the previous step, but the Action parameter in this case is set as
Push an Image . As the name of the image that we collect and publish, we specify the expression
devopsdemoregistry.azurecr.io/javademo:v$(Bild.buildId) , where $ (Build.BuildId) is a variable with the current build ID.

We are going to deploy the application to the
Azure Container Service cloud container
service and use well-known
Kubernetes as the container management system. For publication, a YAML manifest was prepared in advance with a description of the deployment and service of Kubernetes objects.
Shell script In the YAML artifact, you need to correctly identify the Docker image that we are going to use in the deployment. In the case of each new build, mark each assembled Docker image with our application using the Build ID in the image tag, respectively, and when deploying, in the CD process we need to launch the deployment process using the image of the Build Id we need. To do this, in the YAML manifest, the desired image is determined by substituting the parameter value, and this happens in step 5 using the
Shell Script task and Linux
sed command.
Publish Artifact. Finally, we come to the final, 6th step of our CI process. Since the application runs in a container, the Docker image of which we published in the ACR at the 4th step, we will not publish any other artifacts of the application. The only artifact we need for the CD process is the modified YAML manifest for deployment to Kubernetes. We will publish it at this step. The published YAML artifact will be used later in the release definition to deploy the application through the Kubernetes task.

Our CI process is almost configured, only a few additional settings remain, and we can check the build process. To start the CI process after each change in the selected source code branch (for example, master), you need to enable the
Continuous Integration option in the Build Definition properties. In addition, at the same time you can enable the option of assembly on a schedule (Scheduled).

Our build definition is ready and now is the time to test it. Click Save & queue, then VSTS will ask us to confirm the build settings, and enjoy the process.
After placing the assembly in the queue, the process will be assigned a Build ID, which VSTS will inform us about.

Clicking on the link with the Build ID, you will see the process of assembling and executing those tasks that we identified earlier. After the build is complete, you can view test statistics, code coverage (if you customized), logs, and finally download the artifacts that were published as a result of the build.


We publish our Docker image after each build in the Azure Container Registry and open the
Azure Portal console, for our registry, we can really make sure that our image is published.

After completing the CI process, we are ready to move on and configure the CD process for our Java application. To do this, we need to create a new
Release Definition in our project.

For the application, we will use an empty definition and add the necessary tasks to it.

In the next step, VSTS offers to specify the project and the definition of the assembly on the basis of which our deployment will take place. Additionally, we enable the
Continuous deployment option, which means that the deployment will begin immediately after the successful completion of the assembly (CI process) for our application.

For the process CD, some settings need to be made: give a meaningful name to the definition and CD environment and select the
Release Agent to be used for the deployment. In our case, we continue to use
Hosted Linux Preview . Pay attention to the concept of
environment (environment) in the context of
Release Definition . Environments are logical entities that define where we will deploy the application. In our simple example, this is just a Dev environment, but for industrial solutions, Test, Q & A, Stage, Prod environments, etc. can be added here. Accordingly, each environment can have its own set of tasks, with different deployment algorithms in different physical or virtual environments. In addition, there is a special
approval mechanism
(approvals) , which allows you not to start a deployment in the next environment until a user or group of users with the appropriate rights approves (or refuses) to continue the CD process. For example, deploy applications to Prod after Stage only after approval of one or more users.

Now we are ready to add one single task for the CD process, the
Kubernetes task . However, by default this extension is not in the VSTS directory, but again it rescues the
Visual Studio Marketplace , which I mentioned above,
where you can find it and install it for your VSTS account.

In fact, in the Kubernetes task, the
kubectl CLI is used and using the
apply command, our YAML manifest is applied and the application is deployed to Kubernetes (recall that we are going to publish the application to the
Azure Container Service cloud container
service ).
The CD process is ready and it's time to start the deployment.

After launching the deployment, we will see our process in the list, after that it can be opened and you can follow the progress of the implementation and the result.

As you can see from the execution results, the CD process completed successfully and the deployment and service objects were created in Kubernetes successfully.

Deployment results can be checked by checking the status of pods, deployments and services through the CLI kubectl. And of course, just by clicking on the link in your favorite browser: http: // <EXTERNAL-IP>: 8080

And what else is useful for Java developers in VSTS?
VSTS supports integration with various IDEs, allowing developers to work with the platform, essentially without leaving the limits of their development environment. That is, view the list of tasks assigned to you, conduct a code review, create Pull Requests and much more, not to mention the usual work with the GIT repository.
Plug-in integration is currently supported for the popular Java IDE: IntelliJ IDEA, Android Studio, Eclipse.
Let's check with a simple example how this works for IDE IntelliJ IDEA. To do this, you need to install a plug-in for VSTS. Where to download it, and how to install it is
described here .

Suppose we were assigned a new task from the backlog in VSTS and previously created a new branch of Git branch with the name
homepage (these operations can be done in the VSTS console). The first step is to clone the desired Git repository on a working machine. The easiest way to do this is using the Clone option and selecting IntelliJ IDEA. A special script will automatically start the IDE and checkout process.


For example, edit the
index.jsp file, add a new element to the list with the Deployment header, and make commit and push.

In the Commit window, in addition to the basic settings, you can specify the immediate task with which this commit is associated. Next, do commit and push.

The next step is to create a pull request directly in IntelliJ IDEA and specify the master branch as the target branch. We also specify our last commit as changes and create a pull request.

After creating a pull request, it can be opened and viewed in the VSTS console in a browser.

To complete the pull request, it must be approved (approve). Approval is granted to users or a group of users with special rights in VSTS. After the approve process is complete, the pull request can be completed.

If necessary, you can remove the homepage branch, which we used to develop a specific functionality of the application and make squash merge.

The merge of changes to the master branch automatically initiates the CI / CD process of building, testing and deploying our application to the Azure Container Service. By going to the
Build & Release section, you can monitor the build and deployment process.

After completing the CI / CD processes, open your favorite browser and enjoy the changes in the application.

Frequently asked Questions
- I have a CI process built in Jenkins, why do I need VSTS? Jenkins and VSTS are well integrated and complementary. For example, you can continue to use Jenkins Server for CI assemblies (on-premise or in the clouds), and for CD processes use VSTS. Moreover, you can have a complex CI process, where the Jenkins assembly is only part of the assembly definition in VSTS. Jenkins integration with VSTS is performed using a special Team Foundation Server Plugin module.
- What about load testing? Can I use JMeter in VSTS? Yes, Apache JMeter is already available out of the box in VSTS. How to use it can be found in the documentation .
- Can I write my own extension for VSTS? Yes, you can, a special developer SDK is available. Detailed information can be found here: Write your first extension for Visual Studio Team Services .
- Where can I find additional materials and examples about Java development in VSTS? For Java developers, there is a separate portal with information, examples, tutorials, on the topic of using VSTS in Java development: http://java.visualstudio.com/ . And of course official VSTS documentation is available.
Conclusion
This article has reviewed only a simple example of using VSTS in Java DevOps and some aspects have not been considered in detail, for example, integration with code coverage tools (JaCoCo, Cobertura) and static code analysis (SonarQube, PMD, CheckStyle, etc.). , VSTS – , ,
«Any Developer, Any Language, Any Platform» !