Skip to content

Instantly share code, notes, and snippets.

@so0k

so0k/Azure.md Secret

Last active July 20, 2017 02:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save so0k/cc51cfccebd0e1d669ce7900c3c6a8f8 to your computer and use it in GitHub Desktop.
Save so0k/cc51cfccebd0e1d669ce7900c3c6a8f8 to your computer and use it in GitHub Desktop.
Kubernetes / Draft and dotnet Core 1.1

DevOps on Azure

Overview

Instead of using App Services, I recommend ACS (Kubernetes).

For monitoring:

(New Relic does not support dotnet core for the forseeable future)

Azure services:

  1. Sign up for Azure

  2. Install Azure CLI (OSX Instructions - manual)

    https://docs.microsoft.com/en-us/cli/azure/install-azure-cli

    pip install azure-cli
    

    Add az.completion.sh to ~/.bash_profile:

    grep az.completion ~/.bash_profile
    > source /usr/local/bin/az.completion.sh
    
  3.  Enable your device to use your cloud account:

    az login
    To sign in, use a web browser to open the page https://aka.ms/devicelogin and enter the code ****** to authenticate...
    # once window is closed:
    [
      {
        "cloudName": "AzureCloud",
        "id": "****",
        "isDefault": true,
        "state": "Enabled",
        "tenantId": "****",
        "user": {
          "name": "me@outlook.com",
          "type": "user"
        }
      }
    ]
    

    See also az command reference

  4. Set default region and other options

    az configure
    az account list-locations | jq '.[].name'
    az configure --defaults location=southeastasia
    

    See also: list of resource group locations

  5. Get Kubernetes client kubectl:

    az acs kubernetes install-cli
    
  6. Create Kubernetes cluster (list of resource group locations)

     az group create --name acs
     az acs create -g acs -n kubernetes-service --dns-prefix=sample \
            --orchestrator-type kubernetes \
            --ssh-key-value ~/.ssh/id_test.pub \
            --agent-count 1 \
            --agent-vm-size Standard_DS1_v2
    

    Depending on location and DNS prefix, returned masterprofile will be sample.southeastasia.cloudapp.azure.com

    Defaults:

    • --dns-prefix: The concatenation of the domain name and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If not set and cluster name contains underscore, error InvalidDomainNameLabel is raised.
    • --agent-vm-size: set to Standard_DS1_v2 on Free Trial (default= Standard_D2_v2) - see types
    • --master-count: 1
    • --agent-count: set to 1 While on Free Trial (default = 3)
    • --ssh-key-value: default is ~/.ssh/id_rsa.pub, another option is to use --generate-ssh-keys to automatically generate a new key.

    az acs Docs (with k8s as the orchestrator)

  7. Get kubectl credentials (this will add cluster definition if ~/.kube/config already exists):

    az acs kubernetes get-credentials --ssh-key-file ~/.ssh/id_rsa --resource-group=acs --name=kubernetes-service
    

    Troubleshoot with: az acs list -o table

    in case your private key is not id_rsa, you need to pass in the --ssh-key-file parameter.

    Get FQDN of master

    az acs show --name kubernetes-service --resource-group acs --query "masterProfile.fqdn" -o tsv
    
  8. launch the dashboard:

    Using az tool

    az acs kubernetes browse --resource-group acs --name kubernetes-service
    

    Using just kubectl:

    kubectl proxy -p 8002
    open http://localhost:8002/ui
    
  9. Download, Extract and Init Helm (OSX)

    mkdir -p ~/bin/{helm,draft}
    curl -Lo ~/helm.tar.gz https://kubernetes-helm.storage.googleapis.com/helm-v2.5.0-darwin-amd64.tar.gz
    tar -zxvf ~/helm.tar.gz
    mv ~/darwin-amd64/helm ~/bin/helm/helm-v2.5.0
    rm -rf ~/darwin-amd64/
    ln -s ~/bin/helm/helm-v2.5.0 /usr/local/bin/helm
    helm init
    
  10. Download and Extract Draft (OSX)

    mkdir -p ~/bin/{helm,draft}
    curl -Lo ~/draft.tar.gz https://azuredraft.blob.core.windows.net/draft/draft-canary-darwin-amd64.tar.gz
    tar -zxvf ~/draft.tar.gz
    mv ~/darwin-amd64/draft ~/bin/draft/draft-canary
    rm -rf ~/darwin-amd64/
    ln -s ~/bin/draft/draft-canary /usr/local/bin/draft
    
    # don't run draft init yet, set up registry first!
    
  11. Create Azure Container Registry

    az acr check-name --name sample
    az acr create --resource-group acs --name sample --sku Basic --admin-enabled true
    az acr list --resource-group acs --query "[].{acrName:name,acrLoginServer:loginServer}" -o table
    az acr credential show --name <acrName> --query passwords[0].value -o tsv
    
  12. Use Docker with ACR

    docker login sample.azurecr.io --username sample
    docker pull nginx:1.10-alpine
    docker tag nginx:1.10-alpine sample.azurecr.io/nginx:1.10-alpine
    docker push sample.azurecr.io/nginx:1.10-alpine
    az acr repository list --name sample -o table
    az acr repository show-tags --name sample --repository alpine -o table
    
  13. Init Draft

    draft init
    - sample.azurecr.io
    - sample
    - password
    - sample.southeastasia.cloudapp.azure.com
    

    Note, you can retrieve docker credentials from existing docker config with following snippets:

    read DOCKER_USERNAME DOCKER_PASSWORD <<<$( \
      jq -r '.auths["sample.azurecr.io"].auth' ~/.docker/config.json \
      | base64 -D | tr ":" " ")
    

    if your config is using osxkeychain, then you verify you have which docker-credential-osxkeychain.

    In this case, use this command:

    read DOCKER_USERNAME DOCKER_PASSWORD <<<$( \
      docker-credential-osxkeychain get <<<"sample.azurecr.io" \
      | jq -r '"\(.Username) \(.Secret)"')
    
  14. Init an Ingress controller (nginx or traefik)

    helm install stable/nginx-ingress
    

    wait for the LoadBalancer to provision and confirm default 404 backend works

    kubectl get svc
    

    Note IP and use below...

    curl -H "Host: sample.southeastasia.cloudapp.azure.com" 52.187.59.77
    
  15. Optional - Install vscode and Configure Docker / Kubernetes and Helm extensions use CMD+, to edit settings and point to sample.azurecr.io

Reference:

  1. Do need CI/CD - https://www.visualstudio.com/en-us/docs/overview
  2. ACS CI/CD but using Kubernetes as an orchestrator
  3. Get Started with Kubernetes

.NET Core overview

Homepage: dot.net

Creating an application from scratch using the dotnet cli tools

Playing with sample Web API App

Generate sample API app2

mkdir app2 && cd app2
dotnet new webapi

For sample app full logging set EnvironmentName to Development:

export ASPNETCORE_ENVIRONMENT="Development"

Reference: Working with multiple environments

To install NuGet packages (dependencies) of sample api app, run dotnet restore

dotnet restore
  Restoring packages for /app2/app2.csproj...
  Generating MSBuild file /app2/obj/app2.csproj.nuget.g.props.
  Generating MSBuild file /app2/obj/app2.csproj.nuget.g.targets.
  Writing lock file to disk. Path: /app2/obj/project.assets.json
  Restore completed in 3.43 sec for /app2/app2.csproj.

  NuGet Config files used:
      /root/.nuget/NuGet/NuGet.Config

  Feeds used:
      https://api.nuget.org/v3/index.json

Preview app with (Google for microsoft watcher tool to increase "dev inner loop")

dotnet run

To add logs to the controller: Use Logging extensions:

using Microsoft.Extensions.Logging;

Use DI on a constructor to get a reference to the logger:

        private readonly ILogger _logger;

        public ValuesController(ILogger<ValuesController> logger)
        {
            _logger = logger;
        }

Use the logger:

        // POST api/values
        [HttpPost]
        public void Post([FromBody]string value)
        {
            _logger.LogInformation($"Value received {value}");
            _values.Add(value);
        }

To compile App, run dotnet publish

dotnet publish -c Release -o bin .
Microsoft (R) Build Engine version 15.1.548.43366
Copyright (C) Microsoft Corporation. All rights reserved.

  app2 -> /app2/bin/Release/netcoreapp1.1/app2.dll

Note: dotnet build vs dotnet publish

the product of dotnet build isn't ready to be transferred to another machine to run. This is in contrast to the behavior of the .NET Framework in which building an executable project (an application) produces output that's runnable on any machine where the .NET Framework is installed. To have a similar experience with .NET Core, you use the dotnet publish command

Notice that by default dotnet publish will create a distribution meant to be deployed to an environment with the netcoreapp framework pre-installed (such as the -runtime docker images). running multiple of these images on the same host will benefit from sharing the framework image layers.

There are also -runtime-deps docker images which do not include the framework! these are meant to be used for applications published using dotnet publish -r|--runtime <RUNTIME_IDENTIFIER> (self contained deployments). This does not make seem to make much sense for Docker (the images won't share framework layer as it is tied to the application layer), but docker already ensures fixed framework versions through version pinning in image tags.

To run the app listening on all interfaces:

ASPNETCORE_URLS=http://*:5000 dotnet bin/app2.dll
# or
dotnet bin/app2.dll --urls "http://*:5000"

Basic MVC App with xunit tests

Creating a Solution is not mandatory, but may be usefull if we want to split the app into separate modules using projects.

(This is also easier to manage using Visual Studio).

dotnet new sln

Generate mvc and xunit projects within the Solution:

dotnet new mvc -n BasicApp
dotnet new xunit -n BasicApp.Tests

Save references to the projects in the solution

dotnet sln add BasicApp/BasicApp.csproj
dotnet sln add BasicApp.Tests/BasicApp.Tests.csproj

You may now run commands across all projects from the parent solution, download all dependencies:

dotnet restore

Testing with FluentAssertions

Move to the Test project. Add references to the main project and the FluentAssertions package.

cd BasicApp.Tests
dotnet add reference ../BasicApp/BasicApp.csproj
dotnet add package FluentAssertions
dotnet add package Microsoft.AspNetCore.Mvc

Download AspNetCore.Mvc and FluentAssertions Dependencies

dotnet restore

Create the Controllers/HomeControllerFacts for all unit tests related to the HomeController.

mkdir Controllers
touch Controllers/HomeControllerFacts.cs

See FluentAssertions Wiki

Sometimes you might like to first assert that an object is of a certain type using BeOfType and then continue with additional assertions on the result of casting that object to the specified type. You can do that by chaining those assertions onto the Which property like this:

        [Fact]
        public void About_ReturnsAViewResult_WithAMessage()
        {
            // Instantiate
            var controller = new HomeController();

            // Call
            var aboutResult = controller.About();

            //Verify Message Exists
            aboutResult.Should().BeOfType<ViewResult>()
                .Which.ViewData.Should().ContainKey("Message");
        }

Other references

Some basic info on Draft

Important Azure services:

  • App Services
  • Azure Service fabric (used for Azure SQL Db, DocumentDB, Intune and Skype for Business)
  • Azure Container Service - enables to run popular platforms

Note also: what Microsoft is doing with Azure and Azure Stack is really exciting. With Azure Stack, you can get the power of the public cloud, and still maintain control within your own data center. Having one API and approach with Azure Resource Manager, for both on-premises with Azure Stack and the public cloud with Azure, is really exciting. Not everything can, or should, move to the public cloud. Being able to have a cohesive story and approach for on-premises and cloud, is something I don’t think anyone else can fully realize.

The base for enabling Kubernetes deployments on Azure:

https://github.com/Azure/acs-engine

creates ARM templates for different orchestrator types, Swarm, Mesos and Kubernetes) continuously develops and improves the templates, and are overall super supportive. Using acs-engine it’s possible to select which version of Kubernetes you want to deploy (currently supported versions are 1.5.3, 1.5.7 and 1.6.2), and also tweak some other features (like multiple agent pools) which is not possible using the az command line.

Azure ~ What is a Service Principal and why do we need it? (it's like an IAM "user", instead of running under root)

  • focus on minimal privileg principle "service accounts"
  • supports certs to automate authentication for unattended tasks

az ad sp create-for-rbac is your friend, with that command it’s easy to create a service principal which works for the ACS Kubernetes (with the “Collaborator” role, e.g. For a resource group).

https://github.com/Azure/draft

When moving to Kubernetes...

  • Started out with copying Makefile snippets Notice all Deis repos have same Makefiles..

Developers are spoiled... RoR: Build a blog in 15 minutes

From Mind to "MVP" / "working product" > goes really fast in the rails world

With k8s - Devs now have to learn, all the resource types of Kubernetes, Dockerfiles, ... - back to starting from scratch... a lot harder than rake scaffold

the "mean time to dopamine experience"

Note worthy plugins

  • Helm plugin to vscode
  • K8s plugin to vscode
  • Azure plugin to vscode (Azure Container Registry...)
  • Azure Container Service (kubernetes cluster)

Install vscode

CMD+P > inst ext:

CMD+, > add Docker Hub username for Kubernetes extension...

Reference presentations:

Note also:

The Continuous Delivery Tools for Visual Studio extension makes it simple to automate and stay up to date on your DevOps pipeline for ASP.NET and other projects targeting Azure.

@so0k
Copy link
Author

so0k commented Jul 5, 2017

to use draft with minikube set up dnsmasq on OSX:

Was having an issue setting up dnsmasq while also allowing OpenVPN to push DNS server for internal domain when on VPN

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment