Steps to follow:

ARTIFACTORY: How to build a docker build using Azure DevOps and push it to Artifactory

AuthorFullName__c
Swarnendu Kayal
articleNumber
000005291
ft:sourceType
Salesforce
FirstPublishedDate
2022-05-26T15:26:23Z
lastModifiedDate
2024-03-10T07:44:24Z
VersionNumber
4
 
  1. Create a Dockerfile and upload it to a GitHub repository. The example Docker file looks like below -

ARG BASEIMAGE

FROM $BASEIMAGE

#FROM nginx

RUN echo $BASEIMAGE

RUN rm /etc/nginx/conf.d/*

RUN echo "files are deleted"

ADD helloworld.conf /etc/nginx/conf.d/

ADD index.html /usr/share/nginx/html/

ADD arti-error.txt /usr/share/nginx/html/

It’s a simple docker file, which is just taking the base image as an argument, which will be pulled as part of the Azure DevOps task. Then removes the existing files and then adds the files “helloworld.conf”, “index.html” and “arti-error.txt” files to the specific directories under the new image. These files also need to be pushed to the same GitHub repository where the Dockerfile is uploaded.

(Note: The files mentioned above can be any files. Our intention is to put some files to the nginx image that we have pulled and create a new image which we will push to the Artifactory)
 
2. Create an organization in the Azure DevOps as below - 

User-added image
User-added image

3. After the organization is created, install the Artifactory-Azure DevOps plugin - You need to install the plugin by going to the market place as shown the below screenshot - 

User-added image

User-added image

4. Now create a new project by clicking on the “New Project” button as shown in the screenshot here - 

User-added image

And create the project by giving the details - 

User-added image


5. Now it is time to create the pipeline. Please check the below screenshot - 

User-added image

It will ask you to select where your Dockerfile is and all, basically the source code. Select GitHub as that is your source code provider and then select the repository name. Once you complete the authentication, it will create a basic template.

6. We need to create the Artifactory connections and the docker registry as below. These will be used to authenticate Azure DevOps with Artifactory and also the docker registry which will be used in the tasks. It is created as below -

User-added image
User-added image

Art service connection - 

User-added image

User-added image

Note: Please configure the URL of your instance as “https://<Artifactory URL>/artifactory”.

Docker connection - 

User-added image

User-added image

7. Now it is time to create the pipeline. We are going to define some variables as shown below which we will use in the tasks that we are going to create - 

parameters:
- name: prodName
  displayName: Product to Build
  type: string
  default: 'nginx'
- name: registry
  displayName: Registry Hostname
  type: string
  default: test.jfrog.io'
- name: targetRepo
  displayName: Target Repo to push to
  type: string
  default: 'k-docker'

variables:
  prodName: ${{ parameters.prodName }}
  registry: ${{ parameters.registry }}
  targetRepo: ${{ parameters.targetRepo }}
  buildContext: 'test-$(prodName)'
  imageNameTb: '$(registry)/$(targetRepo)/test-$(prodName)'
  imageNameBase: '$(registry)/$(targetRepo)/$(prodName)'


8. We have to have four tasks - 

A. Artifactory tool installer - Create it as below - 
User-added image

You can install the specific version of the JFrog CLI once you select the “Install Custom Version” checkbox. By default, the latest version will be picked up. However, Make sure you have the repository “cli'' created in the Artifactory as below - 

User-added image

B. Then add the task for pulling the docker base image. This task comes from the Artifactory-Azure DevOps plugin - 

User-added image


Here we can define the specific image name like “Nginx”. However, we have defined the variable for the image as “imageNameBase” above. So we are using it here. Basically, we would like to pull the image as “arturl/k-docker/nginx” and from the variables defined above the “imageNameBase” will create the image as mentioned above.

C. Define the task for the docker build. This is a default task that comes bundled with the Azure DevOps. The Artifactory - Azure DevOps plugin does not have the docker build option. So we are building it with the default docker task - 

User-added image

As you can see, the “Build context” is kept blank. So when the related code will be generated, there will be an attribute as “buildContext” which will be blank. We can remove the attribute from the generated code.

This task will pick the Dockerfile from the GitHub page and then build the new docker image

D. Now the docker image is built. You will be able to see a log in the task in the Azure DevOps task log as below - 

Successfully built acb00a56ee2e
Successfully tagged test.jfrog.io/k-docker/test-nginx:20220517.2

We will now push this newly created image to the Artifactory repository using the task as shown below - 

User-added image
This will push the image to the docker repository and create a build-info.json file with all the build related information and the dependencies that are required as part of the docker build and all the environment variables.

E. Now we need to push the “build-info.json” file that is created, to the Artifactory, which will register this as a build in the Artifactory. The task is as follows -

User-added image


F. After this we have to scan the build using the JFrog Xray. The task will be defined as below - 


User-added image

Please make sure to have the below checklist before triggering the build with Xray scan step - 
 
1. create a watch and policy before we run the pipeline. Otherwise the Xray scan using the Azure DevOps task will not succeed. Please follow the below links for creating the watch and policy -
Create the policy and the rules using this link – https://www.jfrog.com/confluence/display/JFROG/Creating+Xray+Policies+and+Rules

 

Create the watch and add the repository, build, policies and rules using this link – https://www.jfrog.com/confluence/display/JFROG/Configuring+Xray+Watches

2. Make sure to enable the below option in the rules of the policy when it is created - 

User-added image

3. Need to include the build in the Indexed Resources in the JFrog platform. However, when the build is first created with the Xray scan task, it will skip the Xray scan step as the build is not included in the Indexed Resources. That’s why it is recommended to include the builds using the Include or Exclude pattern. For this example, the Include pattern is “*/**”. This means the platform will add all the builds that are pushed to the Artifactory, to the Indexed Resources - 

User-added image


For more details on the Indexe Resources, It is also recommended to go through this KB article - https://jfrog.com/knowledge-base/xray-how-to-index-and-scan-all-builds-in-xray-in-the-unified-platform/
 
After saving the above tasks, the “azure-pipelines.yaml” file will be saved to the same repository where the Dockerfile and the other files are pushed in the GitHub and the build wil be triggered in the background. The generated code along with the defined variables is as below - 
 
trigger:
- master
pool:
 vmImage: ubuntu-latest
parameters:
- name: prodName
 displayName: Product to Build
 type: string
 default: 'nginx'
- name: registry
 displayName: Registry Hostname
 type: string
 default: test.jfrog.io'
- name: targetRepo
 displayName: Target Repo to push to
 type: string
 default: 'k-docker'
 
variables:
 prodName: ${{ parameters.prodName }}
 registry: ${{ parameters.registry }}
 targetRepo: ${{ parameters.targetRepo }}
 buildContext: 'test-$(prodName)'
 imageNameTb: '$(registry)/$(targetRepo)/test-$(prodName)'
 imageNameBase: '$(registry)/$(targetRepo)/$(prodName)'
 
steps:
   - task: ArtifactoryToolsInstaller@1
     displayName: 'Install Build deps'
     inputs:
       artifactoryService: 'kayal-art'
       cliInstallationRepo: 'cli' 
 
   - task: ArtifactoryDocker@1
     displayName: 'Pull Image'
     inputs:
       command: 'pull'
       artifactoryService: 'kayal-art'
       sourceRepo: 'k-docker'
       imageName: '$(imageNameBase)'
 
   - task: Docker@2
     displayName: 'Build Image'
     inputs:
       containerRegistry: 'ArtDocker'
       repository: '$(targetRepo)/$(buildContext)'
       command: 'build'
       Dockerfile: '$(Build.SourcesDirectory)/Dockerfile'
       arguments: '--build-arg BASEIMAGE=$(imageNameBase)'
       tags: |
         $(Build.BuildNumber)
  
   - task: ArtifactoryDocker@1
     displayName: 'Push Image'
     inputs:
       command: 'push'
       artifactoryService: 'kayal-art'
       targetRepo: 'k-docker'
       imageName: '$(imageNameTb):$(Build.BuildNumber)'
       collectBuildInfo: true
       buildName: '$(Build.DefinitionName)'
       buildNumber: '$(Build.BuildNumber)'
       includeEnvVars: true
 
   - task: ArtifactoryPublishBuildInfo@1
     displayName: 'Publish Build Info'
     inputs:
       artifactoryService: 'kayal-art'
       buildName: '$(Build.DefinitionName)'
       buildNumber: '$(Build.BuildNumber)'
  
   - task: ArtifactoryXrayScan@1
     displayName: 'Xray Scan'
     inputs:
       artifactoryService: 'kayal-art'
       buildName: '$(Build.DefinitionName)'
       buildNumber: '$(Build.BuildNumber)'
       allowFailBuild: true
 
The “displayNames” are added manually as they are not generated by the task. This will show the Display names of the Tasks. If not defined, it will show the name of the Tasks as the Display names - 

User-added image


Please note that the Azure DevOps plugin runs the JFrog CLI in the background. So basically, the steps that we are doing here, except the docker build steps, we are following the steps as mentioned in this blog - https://jfrog.com/blog/manage-your-docker-builds-with-jfrog-cli-in-5-easy-steps/