Deploy to a Linux Virtual Machine

Azure DevOps Services

Learn how to set up a continuous improvement/continuous development (CI/CD) pipeline for multi-virtual machine deployments. Use the instructions in this article for any app that publishes a web deployment package.

Note

If you want to deploy your application to a Linux virtual machine using the classic editor, see Deploy web apps to Linux virtual machines (VMs).

Get your sample code

If you already have an app in GitHub that you want to deploy, you can create a pipeline for that code.

If you are a new user, fork this repo in GitHub:

https://github.com/spring-projects/spring-petclinic

Note

Petclinic is a Spring Boot application built using Maven.

Prerequisites for the Linux VM

Use Ubuntu 16.04 for following the next section in this article, and more steps for Java or JavaScript.

Create an environment with virtual machines

You can add virtual machines as resources within environments and target for multi-VM deployments. The deployment history view provides traceability from the VM to the commit.

  1. Sign into your Azure DevOps organization and navigate to your project.

  2. Go to the Pipelines page and select Environments > Create Environment.

  3. Specify a Name (required) for the environment and a Description.

  4. Choose Virtual Machines as a Resource to be added to the environment, and then select Next.

  5. Choose the Windows or Linux for the Operating System and copy the PowerShell registration script.

  6. Run the PowerShell registration script on each of the target VMs registered with the environment.

    Note

    • The Personal Access Token (PAT) of the signed in user gets pre-inserted in the script and expires after three hours.
    • If your VM already has any agent running on it, provide a unique name to register with the environment.
  7. Once VM is registered, it will start appearing as an environment resource under Resources.

    VMcreation screenshot.

  8. To add more VMs, copy the script again. Select Add resource and choose Virtual Machines. This script is the same for all the VMs you want to add to the same environment.

    Each machine interacts with Azure Pipelines to coordinate deployment of your app.

    VMresource view

  9. You can add or remove tags for the VM. Select on the dots at the end of each VM resource in Resources.

    Tags limit deployment to specific VMs when the environment's used in a deployment job. Each tag is limited to 256 characters. There's no limit to the number of tags you can create.

    VMtags


Define your CI build pipeline

You need a CI build pipeline that publishes your web app. You also need a deployment script that can be run locally on the Ubuntu server. Set up a CI build pipeline based on the runtime you want to use.

  1. Sign in to your Azure DevOps organization and go to your project.

  2. In your project, go to the Pipelines page, and then choose the action to create a new pipeline.

  3. Select GitHub as the location of your source code.

    You may be redirected to GitHub to sign in. If so, enter your GitHub credentials.

  4. When the list of repositories appears, select the sample app repository that you want.

  5. Azure Pipelines analyzes your repository and recommends a suitable pipeline template.

Select the starter template and copy this YAML snippet to build your Java project and run tests with Apache Maven:

- job: Build
    displayName: Build Maven Project
    steps:
    - task: Maven@3
      displayName: 'Maven Package'
      inputs:
        mavenPomFile: 'pom.xml'
    - task: CopyFiles@2
      displayName: 'Copy Files to artifact staging directory'
      inputs:
        SourceFolder: '$(System.DefaultWorkingDirectory)'
        Contents: '**/target/*.?(war|jar)'
        TargetFolder: $(Build.ArtifactStagingDirectory)
    - upload: $(Build.ArtifactStagingDirectory)
      artifact: drop

For more information, do the steps mentioned in Build your Java app with Maven for creating a build.

Define CD steps to deploy to the Linux VM

  1. Edit your pipeline and include a deployment job by referencing the environment and the VM resources you created earlier:

    jobs:  
    - deployment: VMDeploy
      displayName: web
      environment:
        name:  <environment name>
        resourceType: VirtualMachine
        tags: web1
      strategy:
    
  2. Select specific sets of VMs from the environment to receive the deployment by specifying the tags that you've defined for each VM in the environment.

    For more information, see the complete YAML schema for deployment job.

  3. Specify either runOnce or rolling as a deployment strategy.

    runOnce is the simplest deployment strategy. All the life-cycle hooks, namely preDeploy deploy, routeTraffic, and postRouteTraffic, get executed once. Then, either on: success or on: failure gets executed.

    See the following example of a YAML snippet for runOnce :

    jobs:
    - deployment: VMDeploy
      displayName: web
      pool:
        vmImage: 'ubuntu-latest'
      environment:
        name: <environment name>
        resourceType: VirtualMachine
      strategy:
        runOnce:
          deploy:
            steps:
            - script: echo my first deployment
    
  4. See the following example of a YAML snippet for the rolling strategy. You can update up to five targets gets in each iteration. maxParallel determines the number of targets that can be deployed to, in parallel. The selection accounts for absolute number or percentage of targets that must remain available at any time, excluding the targets being deployed to. It's also used to determine the success and failure conditions during deployment.

    jobs: 
    - deployment: VMDeploy
      displayName: web
      environment:
        name: <environment name>
        resourceType: VirtualMachine
      strategy:
          rolling:
            maxParallel: 2  #for percentages, mention as x%
            preDeploy:
              steps:
              - download: current
                artifact: drop
              - script: echo initialize, cleanup, backup, install certs
            deploy:
              steps:
              - task: Bash@3
                inputs:
                  targetType: 'inline'
                  script: |
                    # Modify deployment script based on the app type
                    echo "Starting deployment script run"
                    sudo java -jar '$(Pipeline.Workspace)/drop/**/target/*.jar'
            routeTraffic:
              steps:
              - script: echo routing traffic
            postRouteTraffic:
              steps:
              - script: echo health check post-route traffic
            on:
              failure:
                steps:
                - script: echo Restore from backup! This is on failure
              success:
                steps:
                - script: echo Notify! This is on success
    

    With each run of this job, deployment history gets recorded against the <environment name> environment that you've created and registered the VMs.

Pipeline traceability views in environment

The Deployments view provides complete traceability of commits and work items, and a cross-pipeline deployment history per environment.

VMDeployments_view

VMjobs_view

Next steps