- 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 -
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 -
4. Now create a new project by clicking on the “New Project” button as shown in the screenshot here -
And create the project by giving the details -
5. Now it is time to create the pipeline. Please check the below screenshot -
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 -
Art service connection -
Note: Please configure the URL of your instance as “https://<Artifactory URL>/artifactory”.
Docker connection -
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 -
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 -
B. Then add the task for pulling the docker base image. This task comes from the Artifactory-Azure DevOps plugin -
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 -
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 -
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 -
F. After this we have to scan the build using the JFrog Xray. The task will be defined as below -
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 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 -
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 -
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/
2. Make sure to enable the below option in the rules of the policy when it is created -
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 -
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
- 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 -
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/
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/