Containers, Kubernetes and DevOps for an Old as Dirt Developer (Or DevOps Nirvana with Kubernetes), Part 5/6

Table Of Content

Part 1: Intro to containers, Kubernetes and DevOps

Part 2: Getting started (setting up my dev environment)

Part 3: My first app –  .net core, vscode, WSL, containerize and deploy to local k8s AND debug it while running in k8s??? GTFOH

Part 4: Deploy to k8s in the cloud (Azure Kubernetes Service – AKS) and debug from VSCode

Part 5: Set up CI/CD pipeline for Kubernetes using DevOps best practices

Part 6: Debugging generic Kubernetes Clusters with Draft (coming soon)

DevOps pipelines for k8s

So we’ve finally come to creating DevOps pipelines for Kubernetes apps using DevOps best practices. Remember, our “app” is so much more than just our source code. And so much more than just the container image with our app running in it. Our app consists of a specific version of our container image as well as the Kubernetes configuration for that specific version.

In the previous installments, I walked through how to set up a dev environment, how to create an app, and how to containerize it using Draft or Azure Dev Spaces. And part of what Draft and what Azure Dev Spaces did was create an initial set of Helm charts that makes sense for the technology picked. Using Helm, I can create a Helm package which consists of an application image and the configurations for that image. And also using Helm, I can deploy that package (both image and configuration) into a Kubernetes cluster.

Bam! Everything I need. So now, my pipeline should look something like this.

Build pipeline:

  1. Compile/package up app
  2. Create image
  3. Push image to a Docker registry
  4. Create a Helm package (helm charts + the image that I just created)
  5. Store my Helm package somewhere

Release pipeline:

  1. Deploy the Helm package into a Kubernetes cluster.

Using Azure DevOps Project

Since I’m going to host my app in Azure using Azure Kubernetes Service, it makes sense for me to use VSTS as my DevOps tool. All right, question time. Who here likes building out pipelines? Honestly, I’m not a huge fan of building out pipelines. I know they are super important and I will do it because it’s absolutely needed. But my first love is slinging code. I sure wish there was a way to automatically build out my pipeline.

Guess what? There totally is.  We have made it rediculously simple to go from nothing at all to a full end to end DevOps project. And what’s this DevOps project I speak of? It is your whole DevOps solution in a box.  And this box contains 5 things. You get a team project in VSTS. You get sample code in the language that you pick in the git repo in your VSTS project. You get a build and release pipeline that makes sense for the technologies that you picked and you get infrastructure deployed out in Azure. And when it’s all done, it will send the sample app through the build and release pipeline all the way out to the infrastructure in Azure. And you get all of this with just a couple of clicks. Click here for a detailed description of  Azure DevOps Projects.

Let’s see how we create a DevOps project for an app that will run in a Kubernetes cluster hosted in AKS.

Creating an Azure DevOps project for a .net core app running in AKS

  1. Browse to your portal and click on Create resource

    image

  2. Click on DevOps Project
    image
  3. Click on .NET and the Next
    image
  4. Click on ASP.NET Core and the Next
    image
  5. Click on Kubernetes Service and the Next
    image
  6. We now get to a screen where we can either create a brand new VSTS account or use an existing one.
    image
  7. I’m going to use my demo account named MSVSTSDemo-A, I’m going to name my project name AbelBlogDevOpsProjk8s, leave the azure infrastructure as default and click Done
    image
    The default infrastructure is a kubernetes cluster with 3 nodes with size Standard_D2_v2. If I wanted to configure this, I would just click  on Change and configure my cluster size
    image
  8. After clicking Done, all I need to do now is… nothing.  Except wait. Just let Azure do its thing.  It’s going to build me out my end to end DevOps project. A new team project in VSTS, sample .net core code in the repo, a build and release pipeline that makes sense for the technologies picked that will build and deploy my sample app into an AKS cluster it provisions for us in Azure.  This takes quite a while so seriously, kick back and relax for a bit until it’s finished. When it’s finally done, you get a portal blade that looks like this
    image

Yeah, literally. A couple of clicks and you get a full end to end DevOps project. All the links in this portal blade are deep links into the provisioned infrastructure. Along the left hand side, you see the CI/CD pipeline with links to the repo, build and release. Along the right hand side, you see all the resources provisioned in azure. The AKS cluster, application insight monitoring your app, and you even get a link to the external endpoint of your sample app that is already built and deployed.

Clicking on the link under Code
image

will take us directly to the repo in VSTS

image

Notice this is just a git repo holding our .net core sample app with Helm charts and Docker file. Navigating to the build definition, you can see we created a build definition that makes sense for a .net core container app using helm charts.

image
We first build the container image of our sample app. Then we push that image to the Container Registry (which we provisioned for you). Next we install Helm onto the build agent and then create the helm package (this consists of the helm charts and a reference to the container image) and we publish that package back to VSTS as a build artifact.

Browsing to the release pipeline, you’ll see we create a release pipeline that again, makes sense for the technology picked. We use Helm to deploy the Helm package into the AKS cluster that we provisioned.
image

And finally, clicking on the external endpoint

image

takes us directly to the sample app.
image

built and deployed using our piplines all the way out into k8s in AKS provisioned by the AzureDevOps project. Pretty cool huh! End to end DevOps pipeline for k8s in AKS, all in a box.

Replacing the sample app with your real app

Azure DevOps projects are cool but the million dollar question of course is, how do i replace that sample app with my real app?  Simple enough. Remember the repo holding the sample code is just a git repo. Simply clone the repo onto your hard drive, delete all the files (except don’t delete what’s in the .git directory), copy your real code there, commit, push and voila! Your app will now flow through the build and release pipeline all the way out into the AKS cluster.

So that’s what I did. I copied the app we created in the previous blog post into my cloned repo, commit and pushed back to vsts. The build kicked off and…

image

Failure! WHAAAAAT?????

Looking at the error, it looks like my Helm package task couldn’t find the Chart.yaml file. And looking at our build definition, here is where I define where the Helm charts are

image

Which clearly doesn’t exist in my real code. Easy enough to fix, let’s click on the elipses and pick where my Helm charts are in the repo

image

image

Now lets save the build and queue it up again….

image

Bam! Success. My app was built, an image was created, pushed to my Azure Container Registry and a helm package was created. Which kicked off my release….

image

Failure!!! WHAAAAAT!!!!!! Looking at my release log…

image

Ugghh.. of course. My helm package isn’t called sampleapp anymore. My real app is called adsapp, Ok, easy enough. Jumping into my release definition

image

Lets change $(System.DefaultWorkingDirectory)/**/sampleapp-*.tgz to $(System.DefaultWorkingDirectory)/**/adsapp-*.tgz,

image

save it, kick off a new release….

image

Bam! Success!!!! And now jumping back into the Azure portal showing the DevOps project blade and click the external endpoint of our app
image

And….

image

WHAT!!!!!! What went wrong???? This was supposed to just work? Ok… time to debug. Let’s look at the release log and let’s look at the upgrade helm task.

image

Oh yeah, of course. My helm charts describe a container with only internal IP’s (I know practically nothing about ops, kubernetes etc so forgive me if my terminology is wrong). No external facing address. Ok  I’ll tweek values.yaml file….

# Default values for adsapp.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
fullnameOverride: adsapp
replicaCount: 1
image:
  repository: abelblogdevopsprojk8s29992.azurecr.io/abelblogdevopsprojk8s2
  tag: latest
imagePullSecrets: []
  # Optionally specify an array of imagePullSecrets.
  # Secrets must be manually created in the namespace.
  # ref: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod
  #
  # This uses credentials from secret "myRegistryKeySecretName".
  # - name: myRegistryKeySecretName
service:
  port: 80
ingress:
  enabled: false
  annotations:
    kubernetes.io/ingress.class: addon-http-application-routing
    # kubernetes.io/ingress.class: nginx
    # kubernetes.io/tls-acme: "true"
  path: /
  hosts:
    - dev-sampleapp.8c95c150-c05e-43d8-bcc2-7703ac33f743.eastus.aksapp.io
  tls: []
    # - secretName: chart-example-tls
    #   hosts:
    #     - chart-example.local
secrets: {}
  # Optionally specify a set of secret objects whose values
  # will be injected as environment variables by default.
  # You should add this section to a file like secrets.yaml
  # that is explicitly NOT committed to source code control
  # and then include it as part of your helm install step.
  # ref: https://kubernetes.io/docs/concepts/configuration/secret/
  #
  # This creates a secret "mysecret" and injects "mypassword"
  # as the environment variable mysecret_mypassword=password.
  # mysecret:
  #   mypassword: password
resources: {}
  # We usually recommend not to specify default resources and to leave this as a conscious
  # choice for the user. This also increases chances charts run on environments with little
  # resources, such as Minikube. If you do want to specify resources, uncomment the following
  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
  # limits:
  #  cpu: 100m
  #  memory: 128Mi
  # requests:
  #  cpu: 100m
  #  memory: 128Mi
nodeSelector: {}
tolerations: []
affinity: {}
values.yaml

Check them in… wait for it to build… release… and….

image
Bam!!! Success. End to end DevOps for AKS with just a couple of clicks + some super minor tweeking of my build and release definitions and my helm chart!

Conclusion

When you talk about DevOps best practices and AKS, it makes sense to have a pipeline that will let us pull our source code from a repo,  build an image and the Kubernetes configuration from the source and then push that into a Kubernetes cluster. Helm let’s us do just that. And scaffolding a helm pipeline into AKS is super easy to do with Azure DevOps projects.

Next> Debugging generic Kubernetes Clusters with Draft (coming soon)

 

Leave a Reply

Your email address will not be published. Required fields are marked *