{"id":74163,"date":"2018-11-27T12:21:14","date_gmt":"2018-11-27T20:21:14","guid":{"rendered":""},"modified":"2025-06-30T00:20:16","modified_gmt":"2025-06-30T07:20:16","slug":"tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm","status":"publish","type":"post","link":"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/","title":{"rendered":"Tutorial: Using Azure DevOps to setup a CI\/CD pipeline and deploy to Kubernetes"},"content":{"rendered":"\n<h4 class=\"wp-block-heading\" id=\"note-for-its-1-year-anniversary-i-refreshed-this-blog-article-in-november-2019-to-leverage-new-features-with-helm-3-and-azure-pipelines-mainly-yaml-for-both-build-ci-and-release-cd-as-well-as-to-incorporate-great-feedback-we-ve-been-receiving-from-our-readers-thank-you\"><em>Note: for its 1-year anniversary, I refreshed this blog article in November 2019 to leverage new features with Helm 3 and Azure Pipelines (mainly YAML for both Build\/CI and Release\/CD), as well as to incorporate great feedback we\u2019ve been receiving from our readers. Thank you!&nbsp;<\/em><\/h4>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"introduction\">Introduction<\/h3>\n\n\n\n<p>In this blog article, we will show you how to set up a CI\/CD pipeline to deploy your apps on a Kubernetes cluster with Azure DevOps by leveraging a Linux agent, Docker, and Helm. The combination of these technologies will illustrate how you can easily set up a CI\/CD pipeline, leverage Configuration-as-Code, and Infrastructure-as-Code, and accelerate your DevOps journey with containers.<\/p>\n\n\n\n<p>Here are the technologies we will walkthrough below:<\/p>\n\n\n\n<p><strong>Azure DevOps<\/strong>&nbsp;helps to implement your CI\/CD pipelines for any platform, any languages.<\/p>\n\n\n\n<p><strong>Docker<\/strong>&nbsp;adds more consistency and quality for your apps, their deployment, and management. Docker allows also to be programming languages agnostic, all your apps packaged as Docker images could be in different languages: .NET Core, Java, Node.js, Go, Python, etc.<\/p>\n\n\n\n<p><strong>Helm,<\/strong>&nbsp;as the package manager for Kubernetes, simplifies and automates more your apps deployments in Kubernetes. We will use the new Helm 3 throughout this tutorial.<\/p>\n\n\n\n<p><strong>Kubernetes<\/strong>&nbsp;is a container orchestrator that makes the collaboration between developers and IT pros easy and will for sure help you in the orchestration, management, and monitoring of all your apps containerized, in a consistent way.<\/p>\n\n\n\n<p><strong>Azure Kubernetes Service (AKS)<\/strong>&nbsp;is a fully managed Kubernetes container orchestration service, simplifying the process around creating, scaling, and upgrading your Kubernetes cluster. You are not paying for the master nodes since that\u2019s part of the managed offer.<\/p>\n\n\n\n<p><strong>Azure Container Registry (ACR)<\/strong>&nbsp;is a dedicated enterprise container registry with advanced features like Helm chart repository, geo-replication of your registry across the globe, container build capabilities, security scanning for your images, etc.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"prerequisites-setup\">Prerequisites &amp; Setup<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Azure DevOps account:\u00a0<\/strong>we will use an Azure DevOps project for a Git repo and build\/release pipelines. Create your free account and a new project\u00a0<a href=\"https:\/\/azure.microsoft.com\/services\/devops\/\">here<\/a>.<\/li>\n\n\n\n<li><strong>Azure Subscription:<\/strong>\u00a0needed to provision the Azure services for this demonstration. If you don\u2019t have one, you can get a free trial one\u00a0<a href=\"https:\/\/azure.microsoft.com\/free\/\">here<\/a>.\u00a0Make sure the\u00a0<a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/project\/navigation\/preview-features\">Multi-stage pipelines in the Preview experience is turned on<\/a>.<\/li>\n\n\n\n<li><strong>Bash Shell:\u00a0<\/strong>we will leverage\u00a0<a href=\"https:\/\/docs.microsoft.com\/azure\/cloud-shell\/overview\">Azure Cloud Shell<\/a>. Once your Azure Subscription is set up you can enable and use your associated Azure Cloud Shell session. In this article, Bash, which you can access\u00a0<a href=\"https:\/\/shell.azure.com\/bash\">here<\/a>.\u00a0<em>Notes: you could use any local bash terminal. Make sure you have\u00a0<a href=\"https:\/\/docs.microsoft.com\/cli\/azure\/install-azure-cli\">installed the Azure CLI<\/a>\u00a0version .0.73 or later and you have\u00a0<a href=\"https:\/\/helm.sh\/docs\/intro\/quickstart\/#install-helm\">installed the Helm<\/a>\u00a0version 3.0.0 or later.<\/em><\/li>\n\n\n\n<li><strong>Container registry:\u00a0<\/strong>we will use Azure Container Registry (ACR) to store both your Docker images and your Helm charts. For that you can run the commands below from Azure Cloud Shell:<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n# Create a resource group $rg on a specific location $location (for example eastus) which will contain the Azure services we need \n$ az group create -l $location -n $rg\n# Create an ACR registry $acr\n$ az acr create -n $acr -g $rg -l $location --sku Basic\n<\/pre><\/div>\n\n\n<p><strong>Kubernetes cluster:\u00a0<\/strong>We will leverage Azure Kubernetes Service (AKS). For that, you can run the commands below from Azure Cloud Shell:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nSetup of the AKS cluster\n$ latestK8sVersion=$(az aks get-versions -l $location --query 'orchestrators[-1].orchestratorVersion' -o tsv)\n$ az aks create -l $location -n $name -g $rg --generate-ssh-keys -k $latestK8sVersion\n# Once created (the creation could take ~10 min), get the credentials to interact with your AKS cluster\n$ az aks get-credentials -n $name -g $rg\n# Setup the phippyandfriends namespace, you will deploy later some apps into it\n$ kubectl create namespace phippyandfriends\n$ kubectl create clusterrolebinding default-view --clusterrole=view --serviceaccount=phippyandfriends:default\n<\/pre><\/div>\n\n\n<p><strong>Azure Roles and Permissions:\u00a0<\/strong>we need to assign 3 specific service principals with specific Azure Roles that need to interact with our ACR and our AKS<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n# 1. Assign acrpull role on our ACR to the AKS-generated service principal, the AKS cluster will then be able to pull images from our ACR\n$ ACR_ID=$(az acr show -n $acr -g $rg --query id -o tsv)\n$ az aks update -g $rg -n $aks --attach-acr $ACR_ID\n# 2. Create a specific Service Principal for our Azure DevOps pipelines to be able to push and pull images and charts of our ACR\n$ registryPassword=$(az ad sp create-for-rbac -n $acr-push --scopes $ACR_ID --role acrpush --query password -o tsv)\n# Important note: you will need this registryPassword value later in this blog article in the Create a Build pipeline and Create a Release pipeline sections\n$ echo $registryPassword\n# 3. Create a specific Service Principal for our Azure DevOps pipelines to be able to deploy our application in our AKS\n$ AKS_ID=$(az aks show -n $aks -g $rg --query id -o tsv)\n$ aksSpPassword=$(az ad sp create-for-rbac -n $aks-deploy --scopes $AKS_ID --role \"Azure Kubernetes Service Cluster User Role\" --query password -o tsv)\n# Important note: you will need this aksSpPassword value later in this blog article in the Create a Release pipeline section\n$ echo $aksSpPassword\n<\/pre><\/div>\n\n\n<p>You now have an ACR registry and AKS cluster ready to be used throughout this blog article.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"the-devops-workflow-with-containers\">The DevOps workflow with containers<\/h3>\n\n\n\n<p>This is the DevOps workflow with containers illustrated in this blog article:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/DevOps-workflow-with-containers_image-1.png\" alt=\"DevOps workflow with containers\" \/><\/figure>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Devs and Ops commit code change (apps, infrastructure-as-code, etc.) to Azure repos<\/li>\n\n\n\n<li>Azure build pipeline will build and push both the app as a Docker image and the Helm chart in an Azure Container Registry (ACR)<\/li>\n\n\n\n<li>Azure release pipeline will deploy the specific Helm chart to an Azure Kubernetes Service (AKS) cluster<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"source-control\">Source control<\/h3>\n\n\n\n<p>We will use the existing&nbsp;<a href=\"https:\/\/github.com\/Azure\/phippyandfriends\">Azure\/phippyandfriends<\/a>&nbsp;GitHub repo. This repo has a few services, each of them represents an individual character of the Children\u2019s Guide to Kubernetes and their new friend NodeBrady. Each service is written in a different language, showing how an AKS cluster can run anything you can bring it.&nbsp;<code>Parrot<\/code>&nbsp;is in .NET Core,&nbsp;<code>CaptainKube<\/code>&nbsp;is in Go,&nbsp;<code>Phippy<\/code>&nbsp;in PHP and&nbsp;<code>NodeBrady<\/code>&nbsp;in Node.js.<\/p>\n\n\n\n<p>First, you will need to import this repo&nbsp;<a href=\"https:\/\/github.com\/Azure\/phippyandfriends\">https:\/\/github.com\/Azure\/phippyandfriends<\/a>&nbsp;into your own Azure repos (from the Azure DevOps project you just created earlier):<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/AzureDevOps_2-1024x626.png\" alt=\"source control - screenshot 1\" class=\"wp-image-74177\" \/><\/figure>\n\n\n\n<p>Once imported, you will be able to browse the source code of the four different apps:\u00a0<code>CaptainKube, NodeBrady, Parrot<\/code>\u00a0and\u00a0<code>Phippy<\/code>:<\/p>\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/SourceControl.webp\" alt=\"source control - screenshot 2\" class=\"wp-image-75466 webp-format\" srcset=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/SourceControl.webp 954w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/SourceControl-300x212.webp 300w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/SourceControl-768x542.webp 768w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/SourceControl-330x233.webp 330w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/SourceControl-800x564.webp 800w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/SourceControl-400x282.webp 400w\" data-orig-src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/SourceControl.png\" data-orig-srcset=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/SourceControl.png 954w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/SourceControl-300x212.png 300w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/SourceControl-768x542.png 768w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/SourceControl-330x233.png 330w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/SourceControl-800x564.png 800w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/SourceControl-400x282.png 400w\"><\/figure>\n\n\n\n<p>Each app has its own folder and the same structure within it:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Files of the app itself<\/strong>, depending on the programming languages:\u00a0<code>Parrot<\/code>\u00a0is in .NET Core,\u00a0<code>CaptainKube<\/code>\u00a0is in Go,\u00a0<code>Phippy<\/code>\u00a0in PHP and\u00a0<code>NodeBrady<\/code>\u00a0in Node.js.<\/li>\n\n\n\n<li><strong>Dockerfile<\/strong>\u00a0<strong>file<\/strong>\u00a0is a script leveraged by Docker, composed of various commands (instructions) and arguments listed successively to automatically perform actions on a base image in order to create a new Docker image by packaging the app.<\/li>\n\n\n\n<li><strong>charts\/* folder<\/strong>\u00a0contains the files defining Helm Chart of the app. Helm Charts helps you define, install, and upgrade your app in Kubernetes.<\/li>\n<\/ul>\n\n\n\n<p>With the next sections, we will also leverage the&nbsp;<code>ci-pipeline.yml<\/code>&nbsp;and&nbsp;<code>cd-pipeline.yml<\/code>&nbsp;files, which play an important role as Configuration-as-Code for the Azure Pipeline definitions.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"create-a-build-continuous-integration-ci-pipeline\">Create a Build \/ Continuous Integration (CI) pipeline<\/h3>\n\n\n\n<p>We will now create an Azure build pipeline for the Parrot app&nbsp;<code>(parrot-ci)<\/code>&nbsp;to be able to both build\/push its Docker image and package\/push its Helm chart. For that, we will need to create a build pipeline definition using the&nbsp;<a href=\"https:\/\/github.com\/Azure\/phippyandfriends\/blob\/master\/parrot\/ci-pipeline.yml\">parrot\/ci-pipeline.yml<\/a>&nbsp;file. From the menu<strong>&nbsp;Pipelines &gt; Pipelines<\/strong>, follow the steps illustrated below:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/ci_image-4.gif\" alt=\"CI pipeline gif\" \/><\/figure>\n\n\n\n<p>Here is how you could retrieve the values of the associated&nbsp;<strong>Variables<\/strong>&nbsp;by running the following commands:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>registryLogin: az ad sp show --id http:\/\/$acr-push\u00a0--query appId -o tsv<\/code><\/li>\n\n\n\n<li><code>registryName: echo $acr<\/code><\/li>\n\n\n\n<li><code>registryPassword:<\/code>You got this value in the\u00a0<strong>Prerequisites &amp; Setup<\/strong>\u00a0section by setting up the associated service principal.<\/li>\n<\/ul>\n\n\n\n<p>You could now&nbsp;<strong>Run Pipeline<\/strong>&nbsp;which will push both the Docker image and the Helm chart in your ACR. You could look at both the&nbsp;<a href=\"https:\/\/github.com\/Azure\/phippyandfriends\/blob\/master\/parrot\/ci-pipeline.yml\">parrot\/ci-pipeline.yml<\/a>&nbsp;and the&nbsp;<a href=\"https:\/\/github.com\/Azure\/phippyandfriends\/blob\/master\/common\/ci-steps-template.yml\">common\/ci-steps-template.yml<\/a>&nbsp;files to see the details for those steps.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Run-pipeline_image-5-1024x512.webp\" alt=\"Run pipeline screenshot\" \/><\/figure>\n\n\n\n<p>Important note: you need to rename this Build definition by&nbsp;<code>parrot-ci<\/code>. This name is important as it will be reused as an input for the next CD\/Release phase.<\/p>\n\n\n\n<p>From there you can run some Azure CLI commands to check what you pushed in ACR:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n# List Docker images from your ACR\n$ az acr repository list -n $acr\n# List Helm charts from your ACR\n$ az acr helm list -n $acr\n# Show details of a specific Helm chart from your ACR\n$ az acr helm show chart-name -n $acr\n<\/pre><\/div>\n\n\n<p>Now both the Docker image and the Helm chart could be used for any Kubernetes cluster from anywhere: locally, etc. You will see in the next section how to use them with a release pipeline.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"create-a-release-continuous-delivery-cd-pipeline\">Create a Release \/ Continuous Delivery (CD) pipeline<\/h3>\n\n\n\n<p>We will now create an Azure release pipeline for the Parrot app&nbsp;<code>(parrot-cd)<\/code>&nbsp;to be able to deploy it via its associated Helm chart. For that, we will need to create a release pipeline definition using the&nbsp;<a href=\"https:\/\/github.com\/Azure\/phippyandfriends\/blob\/master\/parrot\/cd-pipeline.yml\">parrot\/cd-pipeline.yml<\/a>&nbsp;file.&nbsp;From the menu<strong>&nbsp;Pipelines &gt; Pipelines<\/strong>, follow the steps illustrated below:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/cd_image-6.gif\" alt=\"CD pipeline gif\" \/><\/figure>\n\n\n\n<p>Here is how you could retrieve the values of the associated&nbsp;<strong>Variables&nbsp;<\/strong>by running the following commands:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>rg: echo\u00a0<code>$rg<\/code><\/li>\n\n\n\n<li>aks: echo\u00a0<code>$aks<\/code><\/li>\n\n\n\n<li>aksSpId:\u00a0<code>az ad sp show --id http:\/\/$aks-deploy --query appId -o tsv<\/code><\/li>\n\n\n\n<li>aksSpSecret: You got this value in the\u00a0<strong>Prerequisites &amp; Setup<\/strong>\u00a0section by setting up the associated service principal<\/li>\n\n\n\n<li>aksSpTenantId:\u00a0<code>az account show --query tenantId -o tsv<\/code><\/li>\n\n\n\n<li>registryLogin:\u00a0<code>az ad sp show --id\u00a0<a href=\"http:\/\/$acr-push\/\">http:\/\/$acr-push<\/a>\u00a0--query appId -o tsv<\/code><\/li>\n\n\n\n<li>registryName:\u00a0<code>echo $acr<\/code><\/li>\n\n\n\n<li>registryPassword: You got this value in the\u00a0<strong>Prerequisites &amp; Setup<\/strong>\u00a0section by setting up the associated service principal<\/li>\n<\/ul>\n\n\n\n<p>You could now\u00a0<strong>Run pipeline<\/strong>\u00a0which will deploy the Parrot\u2019s Helm chart into our AKS cluster. You could look at both the\u00a0<a href=\"https:\/\/github.com\/Azure\/phippyandfriends\/blob\/master\/parrot\/cd-pipeline.yml\">parrot\/cd-pipeline.yml<\/a>\u00a0and the\u00a0<a href=\"https:\/\/github.com\/Azure\/phippyandfriends\/blob\/master\/common\/cd-steps-template.yml\">common\/cd-steps-template.yml<\/a>\u00a0files to see the details for those steps.<\/p>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7-1024x832.webp\" alt=\"screenshot of job run\" class=\"wp-image-78762 webp-format\" srcset=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7-1024x832.png 1024w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7-300x244.png 300w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7-768x624.png 768w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7-308x250.png 308w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7-330x268.png 330w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7-800x650.png 800w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7-400x325.png 400w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7-650x528.webp 650w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7-450x366.png 450w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7.webp 1159w\" data-orig-src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7-1024x832.png\" data-orig-srcset=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7-1024x832.png 1024w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7-300x244.png 300w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7-768x624.png 768w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7-308x250.png 308w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7-330x268.png 330w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7-800x650.png 800w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7-400x325.png 400w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7-650x528.png 650w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7-450x366.png 450w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/Running-jobs_image-7.png 1159w\"><\/figure>\n\n\n\n<p>Once deployed successfully, you can now run this command from your Azure Cloud Shell to get the&nbsp;<code>EXTERNAL-IP<\/code>&nbsp;value of the&nbsp;<code>service\/parrot-parrot<\/code>:<\/p>\n\n\n\n<p><code>$ kubectl get all -n phippyandfriends<\/code><\/p>\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/AzureDevOps_11.webp\" alt=\"Screenshot of Azure Cloud Shell\" class=\"wp-image-74173 webp-format\" srcset=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/09\/jenkins-portal-08.webp 994w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/09\/jenkins-portal-08-300x244.webp 300w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/09\/jenkins-portal-08-768x624.webp 768w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/09\/jenkins-portal-08-308x250.webp 308w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/09\/jenkins-portal-08-330x268.webp 330w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/09\/jenkins-portal-08-800x650.webp 800w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/09\/jenkins-portal-08-400x325.webp 400w\" data-orig-src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/09\/jenkins-portal-08.png\" data-orig-srcset=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/09\/jenkins-portal-08.png 994w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/09\/jenkins-portal-08-300x244.png 300w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/09\/jenkins-portal-08-768x624.png 768w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/09\/jenkins-portal-08-308x250.png 308w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/09\/jenkins-portal-08-330x268.png 330w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/09\/jenkins-portal-08-800x650.png 800w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/09\/jenkins-portal-08-400x325.png 400w\"><\/figure>\n\n\n\n<p>Then, open a web browser to navigate to this URL:<\/p>\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/AzureDevOps_12-1024x293.webp\" alt=\"Browser connection status\" class=\"wp-image-74746 webp-format\" srcset=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/AzureDevOps_12-1024x293.webp 1024w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/AzureDevOps_12-300x86.webp 300w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/AzureDevOps_12-768x219.webp 768w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/AzureDevOps_12-1536x439.webp 1536w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/AzureDevOps_12-330x94.webp 330w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/AzureDevOps_12-800x229.webp 800w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/AzureDevOps_12-400x114.webp 400w, https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/AzureDevOps_12.webp 1816w\" data-orig-src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/AzureDevOps_12-1024x293.webp\"><\/figure>\n\n\n\n<p><em>Congratulations! You have deployed the Parrot app on your Kubernetes cluster via a Helm Chart. With the next section, you will see how to deploy the other apps\/friends.<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"where-are-phippy-and-the-other-friends\">Where are Phippy and the other friends?<\/h3>\n\n\n\n<p>You are right, we just have the Parrot app so far! You could now repeat with both Parrot\u2019s Build and Release pipelines definitions you created and adapt them for CaptainKube, Phippy, and NodeBrady.<\/p>\n\n\n\n<p>You should now have four build definitions and four release definitions that you can now run to eventually see the Parrot app showing its friends:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2018\/11\/AzureDevOps_13-1024x842.png\" alt=\"Browser screenshot\" class=\"wp-image-74175\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"further-considerations\">Further considerations<\/h3>\n\n\n\n<p>You may want to complete this tutorial with other features and concepts, here are a few examples:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/pipelines\/process\/approvals\">Approvals and Checks<\/a>\u00a0to pause your CI\/CD pipeline with Manual Approvals.<\/li>\n\n\n\n<li><a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/pipelines\/library\/variable-groups\">Variable groups<\/a>\u00a0and Azure KeyVault to reuse, store, and better protect your secrets.<\/li>\n\n\n\n<li><a href=\"https:\/\/docs.microsoft.com\/cli\/azure\/ext\/azure-devops\/devops\">Azure DevOps CLI<\/a>\u00a0to automate all your Azure DevOps actions.<\/li>\n\n\n\n<li>Clone the development stage to add more environments\/stages like production, etc.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"conclusion\">Conclusion<\/h3>\n\n\n\n<p>Congratulations! You have deployed four different apps in a Kubernetes cluster by leveraging Azure DevOps, Azure Container Registry, Azure Kubernetes Service, Docker, and Helm! You have also used Azure Cloud Shell to run some Azure, Helm, and Kubernetes commands.<\/p>\n\n\n\n<p>As illustrated throughout this blog post, all together the technologies used will help you create a generic, strong and robust DevOps pipeline to deploy your apps from any language to any platform. There are three central pieces simplifying the collaboration between the developers and the IT Pros \u2013 it\u2019s about Configuration-as-Code and Infrastructure-as-Code:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Dockerfile<\/strong>\u00a0as the description of the packaging of your app<\/li>\n\n\n\n<li><strong>Helm chart<\/strong>\u00a0as the description of the deployment of your app on Kubernetes<\/li>\n\n\n\n<li><strong>YAML Build and Release pipelines<\/strong>\u00a0as the description of the CI\/CD pipeline process in Azure DevOps<\/li>\n<\/ul>\n\n\n\n<p>Hope you enjoyed this blog article and hopefully you will be able to leverage this for your own apps and needs. Questions or feedback? Let us know in the comments below. Cheers!<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"resources\">Resources:<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>GitHub repository used to illustrate this blog article:\u00a0<a href=\"https:\/\/github.com\/Azure\/phippyandfriends\">Azure\/phippyandfriends<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/aka.ms\/learnkubernetes\">Kubernetes Learning Path \u2013 50 days from zero to hero with Kubernetes<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/cloudblogs.microsoft.com\/opensource\/2018\/12\/11\/phippy-and-friends-new-book-cloud-native-computing-foundation\/\">Phippy and friends join the Cloud Native Computing Foundation<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/cloudblogs.microsoft.com\/opensource\/2019\/11\/13\/helm-3-available-simpler-more-secure\/\">Helm 3: Simpler and more secure<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Note: for its 1-year anniversary, I refreshed this blog article in November 2019 to leverage new features with Helm 3 and Azure Pipelines (mainly YAML for both Build\/CI and Release\/CD), as well as to incorporate great feedback we\u2019ve been receiving from our readers.<\/p>\n","protected":false},"author":5562,"featured_media":95476,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"msxcm_post_with_no_image":false,"ep_exclude_from_search":false,"_classifai_error":"","_classifai_text_to_speech_error":"","footnotes":""},"post_tag":[2272],"content-type":[340],"topic":[2241,2242,2244],"programming-languages":[],"coauthors":[394],"class_list":["post-74163","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","tag-microsoft","content-type-tutorials-and-demos","topic-cloud","topic-containers","topic-devops","review-flag-1593580428-734","review-flag-1593580415-931","review-flag-1593580771-946","review-flag-1-1593580432-963","review-flag-2-1593580437-411","review-flag-3-1593580442-169","review-flag-anywh-1593580318-567","review-flag-free-1593619513-693","review-flag-lever-1593580265-989","review-flag-new-1593580248-669"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.2 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Tutorial: Using Azure DevOps to setup a CI\/CD pipeline and deploy to Kubernetes<\/title>\n<meta name=\"description\" content=\"Learn how to setup a CI\/CD pipeline to deploy your apps on a Kubernetes cluster with Azure DevOps by leveraging a Linux agent, Docker and Helm.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Tutorial: Using Azure DevOps to setup a CI\/CD pipeline and deploy to Kubernetes\" \/>\n<meta property=\"og:description\" content=\"Learn how to setup a CI\/CD pipeline to deploy your apps on a Kubernetes cluster with Azure DevOps by leveraging a Linux agent, Docker and Helm.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/\" \/>\n<meta property=\"og:site_name\" content=\"Microsoft Open Source Blog\" \/>\n<meta property=\"article:published_time\" content=\"2018-11-27T20:21:14+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-30T07:20:16+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2024\/06\/Hybrid-meeting-800x533-1.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1170\" \/>\n\t<meta property=\"og:image:height\" content=\"640\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Mathieu Benoit\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@OpenAtMicrosoft\" \/>\n<meta name=\"twitter:site\" content=\"@OpenAtMicrosoft\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Mathieu Benoit\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 min read\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/\"},\"author\":[{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/author\/mathieu-benoit\/\",\"@type\":\"Person\",\"@name\":\"Mathieu Benoit\"}],\"headline\":\"Tutorial: Using Azure DevOps to setup a CI\/CD pipeline and deploy to Kubernetes\",\"datePublished\":\"2018-11-27T20:21:14+00:00\",\"dateModified\":\"2025-06-30T07:20:16+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/\"},\"wordCount\":1658,\"commentCount\":72,\"publisher\":{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2024\/06\/Hybrid-meeting-800x533-1.webp\",\"keywords\":[\"Microsoft\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/\",\"url\":\"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/\",\"name\":\"Tutorial: Using Azure DevOps to setup a CI\/CD pipeline and deploy to Kubernetes\",\"isPartOf\":{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2024\/06\/Hybrid-meeting-800x533-1.webp\",\"datePublished\":\"2018-11-27T20:21:14+00:00\",\"dateModified\":\"2025-06-30T07:20:16+00:00\",\"description\":\"Learn how to setup a CI\/CD pipeline to deploy your apps on a Kubernetes cluster with Azure DevOps by leveraging a Linux agent, Docker and Helm.\",\"breadcrumb\":{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/#primaryimage\",\"url\":\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2024\/06\/Hybrid-meeting-800x533-1.webp\",\"contentUrl\":\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2024\/06\/Hybrid-meeting-800x533-1.webp\",\"width\":1170,\"height\":640},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/opensource.microsoft.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Tutorial: Using Azure DevOps to setup a CI\/CD pipeline and deploy to Kubernetes\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/#website\",\"url\":\"https:\/\/opensource.microsoft.com\/blog\/\",\"name\":\"Microsoft Open Source Blog\",\"description\":\"Open dialogue about openness at Microsoft \u2013 open source, standards, interoperability\",\"publisher\":{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/opensource.microsoft.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/#organization\",\"name\":\"Microsoft Open Source Blog\",\"url\":\"https:\/\/opensource.microsoft.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2019\/08\/Microsoft-Logo.png\",\"contentUrl\":\"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2019\/08\/Microsoft-Logo.png\",\"width\":259,\"height\":194,\"caption\":\"Microsoft Open Source Blog\"},\"image\":{\"@id\":\"https:\/\/opensource.microsoft.com\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/OpenAtMicrosoft\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Tutorial: Using Azure DevOps to setup a CI\/CD pipeline and deploy to Kubernetes","description":"Learn how to setup a CI\/CD pipeline to deploy your apps on a Kubernetes cluster with Azure DevOps by leveraging a Linux agent, Docker and Helm.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/","og_locale":"en_US","og_type":"article","og_title":"Tutorial: Using Azure DevOps to setup a CI\/CD pipeline and deploy to Kubernetes","og_description":"Learn how to setup a CI\/CD pipeline to deploy your apps on a Kubernetes cluster with Azure DevOps by leveraging a Linux agent, Docker and Helm.","og_url":"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/","og_site_name":"Microsoft Open Source Blog","article_published_time":"2018-11-27T20:21:14+00:00","article_modified_time":"2025-06-30T07:20:16+00:00","og_image":[{"width":1170,"height":640,"url":"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2024\/06\/Hybrid-meeting-800x533-1.png","type":"image\/png"}],"author":"Mathieu Benoit","twitter_card":"summary_large_image","twitter_creator":"@OpenAtMicrosoft","twitter_site":"@OpenAtMicrosoft","twitter_misc":{"Written by":"Mathieu Benoit","Est. reading time":"8 min read"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/#article","isPartOf":{"@id":"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/"},"author":[{"@id":"https:\/\/opensource.microsoft.com\/blog\/author\/mathieu-benoit\/","@type":"Person","@name":"Mathieu Benoit"}],"headline":"Tutorial: Using Azure DevOps to setup a CI\/CD pipeline and deploy to Kubernetes","datePublished":"2018-11-27T20:21:14+00:00","dateModified":"2025-06-30T07:20:16+00:00","mainEntityOfPage":{"@id":"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/"},"wordCount":1658,"commentCount":72,"publisher":{"@id":"https:\/\/opensource.microsoft.com\/blog\/#organization"},"image":{"@id":"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/#primaryimage"},"thumbnailUrl":"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2024\/06\/Hybrid-meeting-800x533-1.webp","keywords":["Microsoft"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/","url":"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/","name":"Tutorial: Using Azure DevOps to setup a CI\/CD pipeline and deploy to Kubernetes","isPartOf":{"@id":"https:\/\/opensource.microsoft.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/#primaryimage"},"image":{"@id":"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/#primaryimage"},"thumbnailUrl":"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2024\/06\/Hybrid-meeting-800x533-1.webp","datePublished":"2018-11-27T20:21:14+00:00","dateModified":"2025-06-30T07:20:16+00:00","description":"Learn how to setup a CI\/CD pipeline to deploy your apps on a Kubernetes cluster with Azure DevOps by leveraging a Linux agent, Docker and Helm.","breadcrumb":{"@id":"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/#primaryimage","url":"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2024\/06\/Hybrid-meeting-800x533-1.webp","contentUrl":"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2024\/06\/Hybrid-meeting-800x533-1.webp","width":1170,"height":640},{"@type":"BreadcrumbList","@id":"https:\/\/opensource.microsoft.com\/blog\/2018\/11\/27\/tutorial-azure-devops-setup-cicd-pipeline-kubernetes-docker-helm\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/opensource.microsoft.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Tutorial: Using Azure DevOps to setup a CI\/CD pipeline and deploy to Kubernetes"}]},{"@type":"WebSite","@id":"https:\/\/opensource.microsoft.com\/blog\/#website","url":"https:\/\/opensource.microsoft.com\/blog\/","name":"Microsoft Open Source Blog","description":"Open dialogue about openness at Microsoft \u2013 open source, standards, interoperability","publisher":{"@id":"https:\/\/opensource.microsoft.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/opensource.microsoft.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/opensource.microsoft.com\/blog\/#organization","name":"Microsoft Open Source Blog","url":"https:\/\/opensource.microsoft.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/opensource.microsoft.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2019\/08\/Microsoft-Logo.png","contentUrl":"https:\/\/opensource.microsoft.com\/blog\/wp-content\/uploads\/2019\/08\/Microsoft-Logo.png","width":259,"height":194,"caption":"Microsoft Open Source Blog"},"image":{"@id":"https:\/\/opensource.microsoft.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/OpenAtMicrosoft"]}]}},"msxcm_display_generated_audio":false,"msxcm_animated_featured_image":null,"distributor_meta":false,"distributor_terms":false,"distributor_media":false,"distributor_original_site_name":"Microsoft Open Source Blog","distributor_original_site_url":"https:\/\/opensource.microsoft.com\/blog","push-errors":false,"_links":{"self":[{"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/posts\/74163","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/users\/5562"}],"replies":[{"embeddable":true,"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/comments?post=74163"}],"version-history":[{"count":3,"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/posts\/74163\/revisions"}],"predecessor-version":[{"id":97845,"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/posts\/74163\/revisions\/97845"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/media\/95476"}],"wp:attachment":[{"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/media?parent=74163"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/post_tag?post=74163"},{"taxonomy":"content-type","embeddable":true,"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/content-type?post=74163"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/topic?post=74163"},{"taxonomy":"programming-languages","embeddable":true,"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/programming-languages?post=74163"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/opensource.microsoft.com\/blog\/wp-json\/wp\/v2\/coauthors?post=74163"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}