Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Java on Azure: First Cloud Native Steps: Automated Build, Test, and Deploy

0.00/5 (No votes)
20 Apr 2021 1  
In this article, we show you how to set up an automated CI/CD pipeline using Azure DevOps Pipelines integrated with GitHub.

One of the most difficult tasks in any project is creating and maintaining a build and deployment process. If you have multiple workgroups using multiple projects, there is a risk of missed steps in the deployment process. This is also a risk of differences in build processes that create incompatible deliverables that cannot be deployed. This can bring down an entire enterprise. Azure DevOps provides a way of managing your build and deployment processes for multiple workgroups using multiple projects that reduces these risks.

To demonstrate how you can use Azure DevOps to reduce these risks, We show you how to create three projects in one organization. In the previous article, we introduced you to the concept of cloud native applications and why you should use them. In this article, we demonstrate how to create and add one project to an organization. You will create and add the other two projects. Each project will have a unique build and deployment pipeline. The pipeline runs every time code is pushed to an integrated GitHub repository. This means you can spend more time developing code — instead of fiddling with getting it running — because the build and deployment of updated code is unique and automated. And since this is in the cloud, you and your team have access to it from anywhere. Everyone has the right version of code, and there is no fear of losing the latest version because a machine crashed.

This article does not provide the exact steps that each developer needs to migrate from their current environment to Azure because every development team has a customized build and deployment pipeline. But the process we present here bridges an Eclipse/GitHub environment with Azure. This provides a path for moving your environment completely to Azure in the future if you choose. This way, you can migrate in steps that make sense, without having to do a "rip and replace" to gain the benefits of working in the cloud.

We assume you are using an Eclipse/Java/GitHub stack for development, and we show you the steps to extend that stack to deploy Azure Functions. Along the way, we provide links to documentation to help you get started if your environment doesn’t match our assumptions or, if you want to explore further.

Prerequisites

This article assumes you have:

Process Overview

Because we’re working in three environments: GitHub, Azure, and Eclipse, you must sign into GitHub and Azure, with Eclipse running.

Here are the major steps:

  1. Add a repository to GitHub.
  2. Create a function app with Azure Functions.
  3. Create an Azure DevOps organization.
  4. Build a pipeline:
    1. Add a project.
    2. Create a service connection.
    3. Add a pipeline.
  5. Add eGit to your Eclipse application.
  6. Create an Azure Function:
    1. Add a local repository.
    2. Commit the code.
    3. Pull before push to sync the local and remote repositories.
    4. Push the code into GitHub.
  7. Verify the build and update.

You normally create the DevOps organization once. Since this article only adds one project to the organization, it makes sense to add it immediately after you create the organization. You will add two more projects on your own to complete the implementation.

Add a Repository to GitHub

On the GitHub login page, click New.

Set the project name to "AzureFunctionHelloWorld." Select Add a README File and select Add .gitgnore. Then specify "Java" as the format and click Create Repository.

Create an Azure Function App

Each Azure function app is a serverless application that provides access to many independent functions. In this implementation, each function app provides only one function. We must create a function app to provide a runtime environment in which we can deploy our Azure Functions. Microsoft provides complete documentation for this. We only go through the portion that creates the function app.

On the Azure portal home page, search for "Function App." In the Function App Overview, click Create.

Select your subscription. Since we’re going to run applications on Linux, create a new Resource Group for them. On the Resource Group list, click Create New and enter a name. Click OK when done.

Set the name of the function app to "AzureFunctionHelloWorld." Click Next: Hosting.

Click the Hosting tab and select Linux. Click Review + create to accept the remaining defaults.

Click Create to create your function app.

When the deployment is complete, you’ll see this page:

Create an Azure DevOps Organization

Azure DevOps is a full-service platform that supports end-to-end collaborative software development and delivery. Microsoft’s article on Azure DevOps provides a great overview of the services that Azure DevOps provides. We’ll focus on setting up a pipeline using an external GitHub repository, which is a part of the Azure DevOps toolset. There are other options, such as the Azure Repos feature (see DevOps Repos), which provides version control resources. If you already use other Azure services, this keeps everything in one place.

To set up an Azure DevOps account, follow the instructions on the DevOps Get Started webpage.

To continue using your existing GitHub repository, visit the Azure DevOps page. Click Start Free with GitHub.

GitHub asks for your credentials.

Provide your credentials. Click Sign in.

GitHub asks you to provide authorization.

Provide your authorization. After providing authorization, you’ll see the DevOps main page.

Add a Project

Now that you have an organization, you can add a project to it. This process is documented in DevOps Create a Project.

Click New Project in the top right corner of the page.

Fill out the fields in the next page as shown below. Keep this project private.

When the project is created, you see the following page.

Create a Service Connection

The pipeline needs a service connection to create the build and deployment environment. Service connections are configured for each project.

On the project home page, click Project Settings in the bottom left corner.

Scroll through the Project Settings panel until you see Service connections.

For a new project, you will see either of the pages shown in the screen captures below.

Click New service connection. Select Azure Resource Manager. Click Next in the bottom right corner.

Select Service principal (automatic). Click Next in the bottom right corner.

Select the Subscription Scope level. Select your active Subscription and Resource group. Make sure the resource group you select is the one you selected when you created the Azure Function as your build will fail if these don’t match.

Set the Service connection name to "AzureServiceConnector." Select Grant access permission to all pipelines. Click Save in the bottom right corner.

Add a Pipeline

Now you can add your pipeline.

Return to the project home page. You will see either of the Overview pages shown below. Select the Pipelines option from the project tool panel.

Click Create Pipeline. If this is your first project, the button is at the bottom.

If you have other projects or pipelines, the button is in the top right corner.

To connect the pipelinet to your code in GitHub, click GitHub.

At this point, you will encounter one of several workflows. The pages and their layouts vary depending on:

  • Whether this is a new organization
  • Whether this organization authenticates using GitHub or Azure
  • Whether Azure’s Pipeline application was previously installed in GitHub
  • The number of existing projects within the organization
  • The number of pipelines in each project

There are two workflows that you may encounter. One is called the New Organization Workflow. The other is called the "Existing Organization" Workflow.

The "New Organization" Workflow

If you have a new organization that authenticates using GitHub, or if your organization doesn’t have any projects or pipelines, your workflow is as follows.

Confirm access to GitHub.

To Authorize pipelines to access all repositories, click All repositories.

Log into your Microsoft account.

If you don’t see your existing project in the Select a project list, click the Switch directory link and change to the directory in which your project was created.

Click Continue when you have selected the project.

From the list of available repositories, select the "AzureFunctionHelloWorld" repository created earlier.

The next page is from GitHub, prompting you to install Azure Pipelines in the repository.

Click Approve & Install in the bottom left corner. You may be asked to log into Azure.

When the installation is complete, you’ll see the configuration panel.

Click Show more.

Note that this workflow continues after the "Existing Organization" workflow section below.

The "Existing Organization" Workflow

If you have an existing organization that has projects or pipelines, you may need to authorize Azure Pipelines to connect to GitHub.

Azure Pipelines connects to GitHub and provides a list of repositories.

The next page is from GitHub, prompting you to install Azure Pipelines in the repository.

Click Approve & Install in the bottom left corner. You may be asked to log into Azure.

When the installation is complete, you’ll see the configuration panel.

Click Show more.

Continuing Both Workflows

Both the previous workflows meet at this point.

Once you have created the pipeline, scroll down the list and click Maven.

This creates a YAML file that implements the build step of the process.

While this is a good start, your pipeline also needs to deploy the function. Replace all of the starter code with the code shown below. Click Save.

At the top of your YAML file, set some variables that you’ll need when you deploy:

  • The name of the service connection that you created above
  • The name of your web app (this is the same one you used above when you created the web app using the Azure CLI)
  • The name of your function app (this is what you provided as a staging Directory in pom.xml)
  • The name of the directory in which the POM file resides
variables:
  serviceConnectionToAzure: 'AzureJavaConnector'
  appName: 'AzureFunctionHelloWorld'
  functionAppName: 'AzureFunctionHelloWorld'
  POM_XML_Directory: 'AzureFunctionHelloWorld'

trigger:
- main

pool:
  vmImage: ubuntu-latest

steps:
- task: Maven@3
  inputs:
    mavenPomFile: '$(POM_XML_Directory)/pom.xml'
    mavenOptions: '-Xmx3072m'
    javaHomeOption: 'JDKVersion'
    jdkVersionOption: '1.11'
    jdkArchitectureOption: 'x64'
    publishJUnitResults: true
    testResultsFiles: '**/surefire-reports/TEST-*.xml'
    goals: 'package'

- task: CopyFiles@2
  displayName: Copy Files
  inputs:
    SourceFolder: $(system.defaultworkingdirectory)/$(POM_XML_Directory)/target/azure-functions/$(functionAppName)/
    Contents: '**'
    TargetFolder: $(build.artifactstagingdirectory)   

- task: PublishBuildArtifacts@1
  displayName: Publish Artifact
  inputs:
    PathtoPublish: $(build.artifactstagingdirectory)    

- task: AzureFunctionApp@1
  displayName: Azure Function App deploy
  inputs:
    azureSubscription: $(serviceConnectionToAzure)
    appType: 'functionAppLinux'
    appName: $(appName)
    package: $(build.artifactstagingdirectory)
    runtimeStack: 'JAVA|11'

Provide a Commit message. Click Save in the bottom right corner.

This action will save the updated YAML file and commit it to the GitHub repository. This commit will trigger your pipeline, and you should see a job queued. It doesn’t matter what the outcome of this job is because we haven’t committed any code to the repository yet, but it is important that we created the job.

This completes the Azure configuration.

Add eGit to your Eclipse Application

Now that we have a functioning pipeline, we must set up Eclipse so that we can add the code for our Azure function.

If you have eGit installed and configured, skip this step. If not, start by installing eGit. Then, to configure eGit, you need to add a few properties.

Select Windows > Preferences from the menu to open the Preferences dialog. Type "eGit" in the filter. Select Configuration from the list. Select the User Settings tab in the Configuration pane.

If the options shown below don’t appear, add them, and then set these values:

  • Email is your GitHub user ID
  • Name is the name associated with your committed changes

Create an Azure Function

Use this process every time you create a new function. For more information, see: Create your first function with Java and Eclipse.

There are several important prerequisites:

The Maven archetype provides a minimal but fully functional Azure Function. The article, Create your first function with Java and Eclipse, explains how to run it locally, but we’ll skip that step in this tutorial because we know the code can be built and it produces a working result.

In Eclipse, select File > New > Project from the menu. In the New Project dialog box, select Create a Maven project > Maven Project.

Accept the defaults. Click Next at the bottom of the New Maven Project dialog box.

Enter "com.microsoft.azure" to filter the list. Select azure-functions-archetype.

Set the Group Id and Artifact Id fields at the top, as well as the "groupId," "artefactId," and "appName" properties shown in the following screen capture. Scroll down to "javaVersion" and set the value to 11.

You now have the source code for a fully functional Azure function. Let’s create a local repository for it and then save it on GitHub.

Add a Local Repository

To open the Git Repositories view, select Window > Show View > Other from the menu. Select Git Repositories.

Right-click the project to display the context menu. Select Team > Share Project to display the Share Project dialog box.

In the Share Project dialog box, click Create to the right of the Repository field to display the Create a Git Repository dialog box. Set the name as shown in the following screen capture. Click Finish.

Ensure the fields in the Share Project dialog box have the values shown in the following screen capture. Your paths will be different, but make sure that all fields reference the "AzureFunctionHelloWorld" directory. Click Finish.

After you have created the local repository, you’ll see it displayed in the Repositories view as shown below.

Add Routine Operations

You’ll perform the commit, pull, and push operations in the following sections every time you complete a unit test successfully.

Commit New Code

Before you commit changes, select Window > Show View > Other from the menu to open the Git Staging dialog box.

In the Git Staging view, click the "double plus" icon to move your changes from Unstaged Changes to Staged Changes. Add a Commit Message. Click Commit.

Pull Before Push

Git can’t push your changes to the remote repository if your local repository is out of sync with that remote repository. We know we pushed the Pipeline YAML file into the remote repository, which means the local repository is out of sync with the remote repository. To fix this, we need to pull the remote repository before we can push our changes.

Right-click the project to show the context menu. Select Team > Pull.

In the Pull dialog box, enter the URL of your GitHub repository in the URI field. This will automatically complete the Host and Repository path fields. Make sure you selected the "https" Protocol and fill out the Authentication fields. Click Next.

Add the link to the remote repository.

If everything is working as expected, when you type "m" in the Reference field, Eclipse contacts GitHub and finds all branches starting with the letter "m." It also displays the warning message saying the remote repository is out of sync with the local repository. Click on the "main" branch to select it.

The Reference field updates after you select the branch.

Select Configure upstream for push and pull, This saves the step of entering all this data again for the Push operation. Click Finish to perform the Pull operation.

The result of your Pull operation is shown below.

Click Close to complete the Pull operation.

Push New Code to GitHub

Right-click the project to show the context menu. Select Team > Push Branch "master."

In the Push Branch master dialog box, click Preview.

Click Push to confirm that you want to push the committed code to the GitHub repository and to complete the operation.

Click Close in the Confirmation dialog box to confirm that the operation is complete.

Confirm Push and Function Update

Confirm that the Push operation succeeded by checking GitHub.

This should trigger the pipeline to start a new job.

When the job completes, click it to review the result.

You see the installed function in the function app.

Verify Build and Update

Last, but far from least, you can run the Azure function in your browser using the base URL as shown in the app overview.

The rest of the URL is "api/HttpExample" because this is the function name provided in the Maven template.

To test the function, open your browser and retrieve this URL:
https://azurefunctionhelloworld.azurewebsites.net//api/HttpExample?name=ExamplePollingCorp

The Azure Function Run Method

The sample code provided by Microsoft is in Create your first function with Java and Eclipse, but there are three items we’d like to point out. These will be useful in the next article.

The first item is the name of the function set in the @FunctionName decorator. The default name is "HttpExample." As shown above, this name, and the name of the Azure function app that contains it, both appear in the URL to call the HttpExample function.

https:// <Function App Name> .azurewebsites.net//api/ <@Name Decorator> ?

The second item is that the HTTP request methods are enabled by the methods property. The sample supports both the GET and POST methods. You can add or remove methods as needed.

Java
@FunctionName("HttpExample")
public HttpResponseMessage run(
        @HttpTrigger(
            name = "req",
            methods = {HttpMethod.GET, HttpMethod.POST},
            authLevel = AuthorizationLevel.ANONYMOUS)
            HttpRequestMessage<Optional<String>> request,
        final ExecutionContext context) {

Finally, authLevel is set to "ANONYMOUS." We do this because we enabled authentication using the Azure Active Directory, which screens out most attacks. We want to allow the function to use the provided identity to determine which actions to authorize for the user.

Next Steps

You now have a complete, fully integrated, cloud native CI/CD process for creating Azure functions, as well as a working serverless function. We’ll use these in the next article to build a complete application. Because of the work done here, we’ll be able to focus on building the application instead of discussing what we must do to test and deploy it.

If you want to learn more about the CI/CD tools available on the Azure platform, these articles give you a good overview:

Now that you have the process in place, look at the last article in this series to build a fully functional microservice.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here