About Me

My photo
I am an MCSE in Data Management and Analytics, specializing in MS SQL Server, and an MCP in Azure. With over 19+ years of experience in the IT industry, I bring expertise in data management, Azure Cloud, Data Center Migration, Infrastructure Architecture planning, as well as Virtualization and automation. I have a deep passion for driving innovation through infrastructure automation, particularly using Terraform for efficient provisioning. If you're looking for guidance on automating your infrastructure or have questions about Azure, SQL Server, or cloud migration, feel free to reach out. I often write to capture my own experiences and insights for future reference, but I hope that sharing these experiences through my blog will help others on their journey as well. Thank you for reading!

Configure Azure CNI networking in Azure Kubernetes Service (AKS) & Create an ingress controller with a static public IP address in Azure Kubernetes Service (AKS)

By default, AKS clusters use kubenet, and a virtual network and subnet are created for you. With kubenet, nodes get an IP address from a virtual network subnet. Network address translation (NAT) is then configured on the nodes, and pods receive an IP address "hidden" behind the node IP. This approach reduces the number of IP addresses that you need to reserve in your network space for pods to use.

With Azure Container Networking Interface (CNI), every pod gets an IP address from the subnet and can be accessed directly. These IP addresses must be unique across your network space, and must be planned in advance. Each node has a configuration parameter for the maximum number of pods that it supports. The equivalent number of IP addresses per node are then reserved up front for that node. This approach requires more planning, and often leads to IP address exhaustion or the need to rebuild clusters in a larger subnet as your application demands grow.

This article shows you how to use Azure CNI networking to create and use a virtual network subnet for an AKS cluster. For more information on network options and considerations, see Network concepts for Kubernetes and AKS.


An ingress controller is a piece of software that provides reverse proxy, configurable traffic routing, and TLS termination for Kubernetes services. 

Kubernetes ingress resources are used to configure the ingress rules and routes for individual Kubernetes services. 

Using an ingress controller and ingress rules, a single IP address can be used to route traffic to multiple services in a Kubernetes cluster.

This article shows you how to deploy the NGINX ingress controller in an Azure Kubernetes Service (AKS) cluster. The ingress controller is configured with a static public IP address. The cert-manager project is used to automatically generate and configure Let's Encrypt certificates. Finally, two applications are run in the AKS cluster, each of which is accessible over a single IP address.


Prerequisite :-

  • The cluster identity used by the AKS cluster must have at least Network Contributor permissions on the subnet within your virtual network. If you wish to define a custom role instead of using the built-in Network Contributor role, the following permissions are required:
    • Microsoft.Network/virtualNetworks/subnets/join/action
    • Microsoft.Network/virtualNetworks/subnets/read


# Update the extension to make sure you have the latest version installed
az extension update --name aks-preview
az feature register --namespace "Microsoft.ContainerService" --name "PodSubnetPreview"
az feature list -o table --query "[?contains(name, 'Microsoft.ContainerService/PodSubnetPreview')].{Name:name,State:properties.state}"
az provider register --namespace Microsoft.ContainerService
~~~~~~~~~~~~~~~~~~~~ once in a life time within Azure Subscription ~~~~~~~~~~~~~~~~
resourceGroup="myResourceGroup"
vnet="myVirtualNetwork"
location="eastus"
clusterName="myAKSCluster"
subscription="XXXXX-dc97-49d2-XXXX-1XXXXXXX"
vnet="myVirtualNetwork"
# Create the resource group
az group create --name $resourceGroup --location $location
# Create our two subnet network
az network vnet create -g $resourceGroup --location $location --name $vnet --address-prefixes 10.0.0.0/8 -o none

az network vnet subnet create -g $resourceGroup --vnet-name $vnet --name nodesubnet --address-prefixes 10.240.0.0/16 -o none

az network vnet subnet create -g $resourceGroup --vnet-name $vnet --name podsubnet --address-prefixes 10.241.0.0/16 -o none
#Create a AKS Cluster
az aks create -n $clusterName -g $resourceGroup -l $location \
 --max-pods 250 \
 --node-count 2 \
 --network-plugin azure \
 --generate-ssh-keys    \
 --vnet-subnet-id /subscriptions/$subscription/resourceGroups/$resourceGroup/providers/Microsoft.Network/virtualNetworks/$vnet/subnets/nodesubnet \
 --pod-subnet-id /subscriptions/$subscription/resourceGroups/$resourceGroup/providers/Microsoft.Network/virtualNetworks/$vnet/subnets/podsubnet

#Configure ACR integration for existing AKS clusters
MYACR=wpaContainerRegistry
resourceGroup="myResourceGroup"
# Run the following line to create an Azure Container Registry if you do not already have one
az acr create -n $MYACR -g $resourceGroup --sku standard
#Attach  ACR integration for existing AKS clusters
az aks update -n myAKSCluster -g myResourceGroup --attach-acr wpaContainerRegistry

Import the images used by the Helm chart into your ACR

REGISTRY_NAME= wpaContainerRegistry
SOURCE_REGISTRY=k8s.gcr.io
CONTROLLER_IMAGE=ingress-nginx/controller
CONTROLLER_TAG=v1.0.4
PATCH_IMAGE=ingress-nginx/kube-webhook-certgen
PATCH_TAG=v1.1.1
DEFAULTBACKEND_IMAGE=defaultbackend-amd64
DEFAULTBACKEND_TAG=1.5
CERT_MANAGER_REGISTRY=quay.io
CERT_MANAGER_TAG=v1.5.4
CERT_MANAGER_IMAGE_CONTROLLER=jetstack/cert-manager-controller
CERT_MANAGER_IMAGE_WEBHOOK=jetstack/cert-manager-webhook
CERT_MANAGER_IMAGE_CAINJECTOR=jetstack/cert-manager-cainjector

az acr import --name $REGISTRY_NAME --source $SOURCE_REGISTRY/$CONTROLLER_IMAGE:$CONTROLLER_TAG --image
 $CONTROLLER_IMAGE:$CONTROLLER_TAG
az acr import --name $REGISTRY_NAME --source $SOURCE_REGISTRY/$PATCH_IMAGE:$PATCH_TAG --image $PATCH_IMAGE:$PATCH_TAG
az acr import --name $REGISTRY_NAME --source $SOURCE_REGISTRY/$DEFAULTBACKEND_IMAGE:$DEFAULTBACKEND_TAG --image $DEFAULTBACKEND_IMAGE:$DEFAULTBACKEND_TAG
az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_CONTROLLER:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_CONTROLLER:$CERT_MANAGER_TAG
az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_WEBHOOK:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_WEBHOOK:$CERT_MANAGER_TAG
az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_CAINJECTOR:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_CAINJECTOR:$CERT_MANAGER_TAG

Next, create a public IP address with the static allocation method using the az network public-ip create command. The following example creates a public IP address named myAKSPublicIP in the AKS cluster resource group obtained in the previous step:
#Create a public IP Address
az network public-ip create --resource-group MC_myResourceGroup_myAKSCluster_eastus --name myAKSPublicIP --sku Standard --allocation-method static --query publicIp.ipAddress -o tsv


#Create an ingress controller with a static public IP address in Azure Kubernetes Service (AKS)
ACR_URL="wpacontainerregistry.azurecr.io"
STATIC_IP="104.211.52.25"
DNS_LABEL="mywayorhighway"
# Use Helm to deploy an NGINX ingress controller
helm install nginx-ingress ingress-nginx/ingress-nginx \
--version 4.0.13 \
--namespace ingress-basic --create-namespace \
--set controller.replicaCount=2 \
--set controller.nodeSelector."kubernetes\.io/os"=linux \
--set controller.image.registry=$ACR_URL \
--set controller.image.image=$CONTROLLER_IMAGE \
--set controller.image.tag=$CONTROLLER_TAG \
--set controller.image.digest="" \
--set controller.admissionWebhooks.patch.nodeSelector."kubernetes\.io/os"=linux \
--set controller.admissionWebhooks.patch.image.registry=$ACR_URL \
--set controller.admissionWebhooks.patch.image.image=$PATCH_IMAGE \
--set controller.admissionWebhooks.patch.image.tag=$PATCH_TAG \
--set controller.admissionWebhooks.patch.image.digest="" \
--set defaultBackend.nodeSelector."kubernetes\.io/os"=linux \
--set defaultBackend.image.registry=$ACR_URL \
--set defaultBackend.image.image=$DEFAULTBACKEND_IMAGE \
--set defaultBackend.image.tag=$DEFAULTBACKEND_TAG \
--set defaultBackend.image.digest="" \
--set controller.service.loadBalancerIP=$STATIC_IP \
--set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"=$DNS_LABEL

~~~~~~~~~~~~~~~~~aks-helloworld-one.yaml~~~~~~~~~~~~~

apiVersion: apps/v1
kind: Deployment
metadata:
  name: aks-helloworld-one
spec:
  replicas: 1
  selector:
    matchLabels:
      app: aks-helloworld-one
  template:
    metadata:
      labels:
        app: aks-helloworld-one
    spec:
      containers:
      - name: aks-helloworld-one
        image: mcr.microsoft.com/azuredocs/aks-helloworld:v1
        ports:
        - containerPort: 80
        env:
        - name: TITLE
          value: "Welcome to Azure Kubernetes Service (AKS)"
---
apiVersion: v1
kind: Service
metadata:
  name: aks-helloworld-one
spec:
  type: ClusterIP
  ports:
  - port: 80
  selector:
    app: aks-helloworld-one
~~~~~~~~~~~~~~~~~~~~~~~ End of the file aks-helloworld-one~~~~~~~~~~~~~~~~

$> kubectl apply -f aks-helloworld-one -n ingress-basic
~~~~~~~~~~~~~~~~~~~~~~~~~~begin  of the file aks-helloworld-two.yaml~~~~~~~~~~~
apiVersion: apps/v1
kind: Deployment
metadata:
  name: aks-helloworld-two
spec:
  replicas: 1
  selector:
    matchLabels:
      app: aks-helloworld-two
  template:
    metadata:
      labels:
        app: aks-helloworld-two
    spec:
      containers:
      - name: aks-helloworld-two
        image: mcr.microsoft.com/azuredocs/aks-helloworld:v1
        ports:
        - containerPort: 80
        env:
        - name: TITLE
          value: "AKS Ingress Demo"
---
apiVersion: v1
kind: Service
metadata:
  name: aks-helloworld-two
spec:
  type: ClusterIP
  ports:
  - port: 80
  selector:
    app: aks-helloworld-two
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ End of the file aks-helloworld-two~~~~~~~~~~~~~~~~
$> kubectl apply -f aks-helloworld-two -n ingress-basic

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Start of the file aks-helloworld-three.yaml~~~~~~~~~~~~~~~~

apiVersion: apps/v1
kind: Deployment
metadata:
  name: aks-helloworld-three
spec:
  replicas: 1
  selector:
    matchLabels:
      app: aks-helloworld-three
  template:
    metadata:
      labels:
        app: aks-helloworld-three
    spec:
      containers:
      - name: aks-helloworld-three
        image: mcr.microsoft.com/dotnet/core/samples:aspnetapp
        ports:
        - containerPort: 80
        env:
        - name: TITLE
          value: "AKS Ingress Demo for aspnet"
---
apiVersion: v1
kind: Service
metadata:
  name: aks-helloworld-three
spec:
  type: ClusterIP
  ports:
  - port: 80
  selector:
    app: aks-helloworld-three
~~~~~~~~~~~~~~~~~~~~end of the file aks-helloworld-three.yaml~~~~~~~~~~

$> kubectl apply -f aks-helloworld-three -n ingress-basic

~~~~~~~~~~~~~~~~~Start of the hello-world-ingress.yaml~~~~~~~~~~~~~~~~

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-world-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-staging
    nginx.ingress.kubernetes.io/rewrite-target: /$1
    nginx.ingress.kubernetes.io/use-regex: "true"
spec:
  tls:
  - hosts:
    - mywayorhighway.eastus.cloudapp.azure.com
    secretName: tls-secret
  rules:
  - host: mywayorhighway.eastus.cloudapp.azure.com
    http:
      paths:
      - path: /hello-world-one(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: aks-helloworld-one
            port:
              number: 80
      - path: /hello-world-two(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: aks-helloworld-two
            port:
              number: 80
      - path: /hello-world-three(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: aks-helloworld-three
            port:
              number: 80              
      - path: /(.*)
        pathType: Prefix
        backend:
          service:
            name: aks-helloworld-one
            port:
              number: 80

~~~~~~ End of the hello-world-ingress~~~~~~~~~~~~~~

 kubectl apply -f hello-world-ingress -n ingress-basic


Verify certificate object

Next, a certificate resource must be created. The certificate resource defines the desired X.509 certificate. For more information, see cert-manager certificates.

Cert-manager has likely automatically created a certificate object for you using ingress-shim, which is automatically deployed with cert-manager since v0.2.2. For more information, see the ingress-shim documentation.

To verify that the certificate was created successfully, use the 

kubectl describe certificate tls-secret --namespace ingress-basic command.

output:-


Owner References:

    API Version:           networking.k8s.io/v1

    Block Owner Deletion:  true

    Controller:            true

    Kind:                  Ingress

    Name:                  hello-world-ingress

    UID:                   834c59a2-571a-4486-94fd-01b9a52ef132

  Resource Version:        129384

  UID:                     d363a50a-b23f-41f3-ab25-07b96de68598

Spec:

  Dns Names:

    mywayorhighway.eastus.cloudapp.azure.com

  Issuer Ref:

    Group:      cert-manager.io

    Kind:       ClusterIssuer

    Name:       letsencrypt-staging

  Secret Name:  tls-secret

  Usages:

    digital signature

    key encipherment

Status:

  Conditions:

    Last Transition Time:  2022-02-06T16:34:52Z

    Message:               Certificate is up to date and has not expired

    Observed Generation:   1

    Reason:                Ready

    Status:                True

    Type:                  Ready

  Not After:               2022-05-07T15:34:50Z

  Not Before:              2022-02-06T15:34:51Z

  Renewal Time:            2022-04-07T15:34:50Z

  Revision:                1

Events:

  Type    Reason     Age   From          Message

  ----    ------     ----  ----          -------

  Normal  Issuing    69m   cert-manager  Issuing certificate as Secret does not exist

  Normal  Generated  69m   cert-manager  Stored new private key in temporary Secret resource "tls-secret-hqgnt"

  Normal  Requested  69m   cert-manager  Created new CertificateRequest resource "tls-secret-whkqg"

  Normal  Issuing    69m   cert-manager  The certificate has been successfully issued

udr@Azure:~$


URL accessible :-

https://mywayorhighway.eastus.cloudapp.azure.com/hello-world-three

https://mywayorhighway.eastus.cloudapp.azure.com/hello-world-two

https://mywayorhighway.eastus.cloudapp.azure.com/hello-world-one

https://mywayorhighway.eastus.cloudapp.azure.com





Create shared access signature (SAS) named SAS1 for Storage as exhibit below.

 You have an Azure subscription named Subscription1.

In Subscription1, you create an Azure file share named MyFileShare.

You create a shared access signature (SAS) named SAS1 as shown in the following exhibit.

Write a AZ CLI Code and print the SAS1 value 


Scripts
========
$MyResourceGroup="RG102"
$location="North Europe"
$storageaccountname= "storage16854"

#A virtual network named Paris-VNet that will contain two sub#nets named Subnet1 and Subnet2

# Create a resource group.
az group create --location $location --name $myResourceGroup

az storage account create -n $storageaccountname  -g $MyResourceGroup  --kind StorageV2 --https-only --access-tier Hot --sku Standard_LRS 


az storage share create --account-name $storageaccountname --name myfileshare02

$pkey = az storage account keys list -g $myResourceGroup  -n $storageaccountname   --query [0].value -o tsv


$sastoken = az storage account generate-sas --start '2018-09-01' --expiry '2018-09-14' --permissions rwl --resource-types sco --services f --https-only --account-name storage16852   --account-key $pkey --ip 193.77.134.10-193.77.134.50

$sastoken


AZ CLI Create a Storage account based on below Exhibit

 

Introduction:

In cloud environments, securing access to resources such as storage accounts is a priority for organizations. One of the most effective ways to enhance security is by implementing Azure Private Endpoints. This feature ensures that traffic between your virtual network and Azure services travels securely over the Microsoft backbone network, avoiding exposure to the public internet.

In this blog post, we will dive into how to create a secure Azure Storage Account using Private Endpoints, walking through the commands provided and breaking down each step. By the end of this guide, you’ll not only understand the purpose of each command but also have a clear idea of how to deploy these resources securely using Azure CLI.


Table of Contents:

  1. Key Concepts in Azure Networking and Storage Security
    • Resource Groups and Storage Accounts
    • Virtual Networks (VNets) and Subnets
    • Private Endpoints and Private Link
  2. Step-by-Step Guide to Securing Azure Storage with Private Endpoints
    • Creating a Resource Group
    • Setting Up a Storage Account
    • Configuring a Virtual Network (VNet)
    • Implementing Private Endpoints
  3. Memory Techniques for Key Concepts
    • Mnemonics for Resource Creation
    • Story-based Learning for Private Endpoints
  4. Use Case: Enhancing Data Security in a Corporate Environment
  5. Conclusion

1. Key Concepts in Azure Networking and Storage Security

Before we dive into the practical steps, it’s important to understand the key components involved in securing an Azure Storage Account using Private Endpoints:

Resource Groups:

A resource group is a logical container that holds related Azure resources. It allows you to manage and organize resources in a structured way.

  • Command: az group create --location <region> --name <resource-group-name>

Storage Accounts:

An Azure Storage Account provides scalable and highly secure storage in the cloud. It’s where your data (like blobs, files, queues, and tables) is stored.

  • Command: az storage account create --name <storage-name> --resource-group <resource-group> --sku Standard_LRS

Virtual Networks (VNets) and Subnets:

VNets are your private network in Azure. Within VNets, subnets allow you to segment your network into smaller ranges of IP addresses, enhancing isolation and control.

  • Command: az network vnet create --resource-group <resource-group> --name <vnet-name> --address-prefix <vnet-address-range> --subnet-name <subnet-name> --subnet-prefix <subnet-address-range>

Private Endpoints:

Private Endpoints allow you to connect your virtual network to Azure services (e.g., Storage, SQL) via a private IP. Traffic between your resources and the Azure service stays on the Azure backbone network, improving security.

  • Command: az network private-endpoint create --name <private-endpoint-name> --resource-group <resource-group> --vnet-name <vnet-name> --subnet <subnet-name> --private-connection-resource-id <resource-id> --group-id <resource-type>

2. Step-by-Step Guide to Securing Azure Storage with Private Endpoints

Let’s break down each of the steps from the provided script to understand what’s happening.

Step 1: Create a Resource Group

Every Azure resource must belong to a resource group. Creating a resource group helps in managing related resources.

bash

az group create --location NorthEurope --name RG101

This command creates a new resource group named RG101 in the North Europe region.

Step 2: Create a Storage Account

Here, you’re creating a Storage Account that will store your data in the cloud.

bash

az storage account create -n storage16852 -g RG101 --kind StorageV2 --https-only --access-tier Hot --sku Standard_LRS
  • storage16852: The name of your storage account.
  • Standard_LRS: Locally-redundant storage for the storage account.
  • --https-only: Ensures secure communication with HTTPS.
  • --access-tier Hot: Optimizes for frequent access.

Step 3: Set Up a Virtual Network (VNet) and Subnet

You need to create a virtual network and a subnet to define the range of IP addresses that can communicate with your storage account.

bash

az network vnet create -g RG101 -n storagevnet --address-prefix 10.3.0.0/16 --subnet-name 'subnet3' --subnet-prefix 10.3.1.0/24
  • VNet Address Prefix (10.3.0.0/16): The range of IP addresses for your entire virtual network.
  • Subnet Address Prefix (10.3.1.0/24): A smaller segment within the VNet.

Step 4: Disable Private Endpoint Network Policies

To allow private endpoint creation within the subnet, you need to disable subnet-level network policies.

bash

az network vnet subnet update --name subnet3 --resource-group RG101 --vnet-name storagevnet --disable-private-endpoint-network-policies true

This allows the VNet’s subnet to accept private endpoints.

Step 5: Create a Private Endpoint for the Storage Account

Now, you create a private endpoint that links the storage account to the VNet via a private IP address.

bash

$storage_id=$(az storage account show -g RG101 -n storage16852 --query "id" -o tsv) az network private-endpoint create --name myPrivateEndpoint --resource-group RG101 --vnet-name storagevnet --subnet subnet3 --private-connection-resource-id $storage_id --group-id blob --connection-name myConnection

Here:

  • $storage_id: Captures the storage account’s resource ID.
  • private-connection-resource-id: The resource ID of the storage account.
  • --group-id blob: Specifies the type of service the endpoint connects to (Blob storage).

3. Memory Techniques for Key Concepts

Mnemonics for Resource Creation:

Use the mnemonic “RSVP” to remember the order of creation:

  • R for Resource Group: Create your logical container first.
  • S for Storage Account: Set up your secure storage.
  • V for Virtual Network: Define your network and subnet.
  • P for Private Endpoint: Create your secure connection to the storage.

Story-based Learning:

Imagine you're setting up a private storage vault in a secure building. First, you need to decide where (the Resource Group), then you need to buy a secure vault (the Storage Account). Next, you build walls and gates around the building (the VNet and Subnet), ensuring only authorized people (your Private Endpoint) can enter through the private access doors.


4. Use Case: Enhancing Data Security in a Corporate Environment

Scenario:

Your company needs to store sensitive financial documents in the cloud. It’s crucial that no public internet access is allowed to the storage account. Instead, the company wants to secure the storage by ensuring all traffic to it flows through its private network.

Solution:

By using Azure Private Endpoints, you can ensure that all communication between your storage account and your virtual machines stays within the Azure backbone network. This enhances data security and ensures that sensitive documents are not exposed to public networks.

Command Example:

bash

az network private-endpoint create \ --name FinancialDataEndpoint \ --resource-group CorporateDataGroup \ --vnet-name CorporateVNet \ --subnet FinanceSubnet \ --private-connection-resource-id $(az storage account show -g CorporateDataGroup -n FinanceStorage --query "id" -o tsv) \ --group-id blob \ --connection-name FinanceStorageConnection

5. Conclusion

Securing a storage account using Private Endpoints in Azure ensures that sensitive data remains accessible only within your virtual network, significantly enhancing security. Using Azure CLI, you can automate and simplify the process of creating resource groups, storage accounts, VNets, and private endpoints.

By following this step-by-step guide, you can set up a secure environment to protect your data and avoid exposing it to public networks. With practical commands, Azure Portal instructions, and mnemonics, you now have the knowledge to confidently implement secure Azure Storage solutions in your projects.


AZ CLI - Create multiple VNETS,SUBNETS,Network Peering and DNS Zone.

You plan to create the following networking resources in a resource group named HumongousRG.

Default Azure system routes that will be the only routes used to route traffic

A virtual network named Paris-VNet that will contain two subnets named Subnet1 and Subnet2

A virtual network named ClientResources-VNet that will contain one subnet named ClientSubnet

A virtual network named AllOffices-VNet that will contain two subnets named Submit3 and Subnet4


You plan to enable peering between Paris-VNet and AllOffices-VNet. You will enable the Use remote gateways setting for the Paris-VNet peerings. 

You plan to create a private DNS zone named humongousinsurance.local and set the registration network to the ClientResources-VNet virtual network.

$MyResourceGroup="HumongousRG"

$location="eastus"

#A virtual network named Paris-VNet that will contain two sub#nets named Subnet1 and Subnet2

# Create a resource group.

az group create --location $location --name $myResourceGroup

az network vnet create -g $MyResourceGroup -n Paris-VNet --address-prefix 10.0.0.0/16 --subnet-name Subnet1 --subnet-prefix 10.0.1.0/24

az network vnet subnet create -g $MyResourceGroup --vnet-name Paris-VNet -n MySubnet --address-prefixes 10.0.2.0/24 

#A virtual network named ClientResources-VNet that will contain one subnet named ClientSubnet

az network vnet create -g $MyResourceGroup -n ClientResources-VNet --address-prefix 10.1.0.0/16 --subnet-name ClientSubnet --subnet-prefix 10.1.1.0/24

#A virtual network named AllOffices-VNet that will contain two subnets named Subnet3 and Subnet4

az network vnet create -g $MyResourceGroup -n AllOffices-VNet --address-prefix 10.2.0.0/16 --subnet-name 'subnet3' --subnet-prefix 10.2.1.0/24

az network vnet subnet create -g $MyResourceGroup --vnet-name 'AllOffices-VNet' -n Subnet4 --address-prefixes 10.2.2.0/24 

az network vnet peering create -g $MyResourceGroup -n Paris-VNetToAllOffices-VNet --vnet-name Paris-VNet --remote-vnet AllOffices-VNet  --allow-vnet-access --allow-forwarded-traffic

az network vnet peering create -g $MyResourceGroup -n AllOffices-VNetToParis-VNet --vnet-name AllOffices-VNet --remote-vnet Paris-VNet  --allow-vnet-access --allow-forwarded-traffic

You plan to create a private DNS zone named humongousinsurance.local and set the registration network to the ClientResources-VNet virtual network

===========================================================================


az network private-dns zone create -g $MyResourceGroup -n humongousinsurance.local

az network private-dns link vnet create --resource-group $MyResourceGroup --zone-name  "humongousinsurance.local" --name MyDNSLink --virtual-network ClientResources-VNet --registration-enabled true

Manage storage account keys with Key Vault and the Azure CLI

$myResourceGroup="rg-fhpl-use-qa"

$location="eastus"

$storagename = "stousefhplqa"

$container = "mybackupcontainer"

$ADE_KV_NAME = "keyvault-common-fhpl-qa"

$nameofsecret = "secnamefhplqa"

$upnname = "XXXXX.onmicrosoft.com" # put your valid upn name here

$subsid = "9239f519-XXXX-4e92-XXXX-c84d53XX3714"

# Create a resource group.

az group create --location $location --name $myResourceGroup

# Create a Storage Account

az storage account create --name $storagename --resource-group $myResourceGroup --location $location --sku Standard_LRS --kind=StorageV2

# Create a storage container

az storage container create --account-name $storagename --name $container

az keyvault create --name $ADE_KV_NAME --resource-group $myResourceGroup --location $location --sku premium 

echo "- Key vault: $ADE_KV_NAME"

#

az role assignment create --role "Storage Account Key Operator Service Role" --assignee 'https://vault.azure.net' --scope "/subscriptions/$subsid/resourceGroups/$myResourceGroup/providers/Microsoft.Storage/storageAccounts/$storagename"

az keyvault set-policy --name $ADE_KV_NAME  --upn $upnname  --storage-permissions get list delete set update regeneratekey getsas listsas deletesas setsas recover backup restore purge

# Give your user principal access to all storage account permissions, on your Key Vault instance

az keyvault storage add --vault-name $ADE_KV_NAME -n $storagename  --active-key-name key1 --auto-regenerate-key --regeneration-period P1D --resource-id "/subscriptions/$subsid/resourceGroups/$myResourceGroup/providers/Microsoft.Storage/storageAccounts/$storagename" 

$pkey = az storage account keys list -g $myResourceGroup  -n $storagename   --query [0].value -o tsv

$sastoken = az storage account generate-sas --expiry '2022-12-31' --permissions cdlruwap  --resource-types sco --services bfqt --https-only --account-name $storagename   --account-key (az storage account keys list -g $myResourceGroup  -n $storagename   --query [0].value -o tsv)

$sastoken

az keyvault storage sas-definition create --vault-name $ADE_KV_NAME  --account-name $storagename -n $nameofsecret --validity-period P1D --sas-type account --template-uri $sastoken

az keyvault storage sas-definition show --id "https://$ADE_KV_NAME.vault.azure.net/storage/$storagename/sas/$nameofsecret" 

az keyvault secret show --id "https://$ADE_KV_NAME.vault.azure.net/secrets/$storagename-$nameofsecret" 


Create an Azure private DNS zone using the Azure CLI

A DNS zone is used to host the DNS records for a particular domain. To start hosting your domain in Azure DNS, you need to create a DNS zone for that domain name.

 Each DNS record for your domain is then created inside this DNS zone. 

To publish a private DNS zone to your virtual network, you specify the list of virtual networks that are allowed to resolve records within the zone. 

These are called linked virtual networks. When autoregistration is enabled, Azure DNS also updates the zone records whenever a virtual machine is created, changes its' IP address, or is deleted.


 creates a virtual network named rakAzureVNet.

 =============================================


az network vnet create \

  --name rakAzureVNet \

  --resource-group RG1 \

  --location centralus \

  --address-prefix 10.2.0.0/16 \

  --subnet-name backendSubnet \

  --subnet-prefixes 10.2.0.0/24


Then it creates a DNS zone named fhplcloudops.com in the RG1 resource group

===========================================================================


az network private-dns zone create -g RG1 \

 -n fhplcloudops.com


links the DNS zone to the rakAzureVNet virtual network, and enables automatic registration.

============================================================================================


az network private-dns link vnet create -g RG1 -n MyDNSLink \

   -z fhplcloudops.com -v rakAzureVNet -e true

   

List DNS private zones

========================

az network private-dns zone list \

-g RG1

  

az network private-dns zone list


Create the test virtual machines

=================================

az vm create \

 -n myVM01 \

 --admin-username AzureAdmin \

 -g RG1 \

 -l centralus \

 --subnet backendSubnet \

 --vnet-name rakAzureVNet \

 --nsg NSG01 \

 --nsg-rule RDP \

 --image win2016datacenter


az vm create \

 -n myVM02 \

 --admin-username AzureAdmin \

 -g RG1 \

 -l centralus \

 --subnet backendSubnet \

 --vnet-name rakAzureVNet \

 --nsg NSG01 \

 --nsg-rule RDP \

 --image win2016datacenter

 

Create an additional DNS record

====================================

To create a DNS record, use the az network private-dns record-set [record type] add-record command. 

For help with adding A records for example, see az network private-dns record-set A add-record --help.


The following example creates a record with the relative name db in the DNS Zone fhplcloudops.com, in resource group RG1. 

The fully qualified name of the record set is db.fhplcloudops.com. The record type is "A", with IP address "10.2.0.4".

Here 10.2.0.4 is nothing but a IP adddress of VM - myVM01

 

 az network private-dns record-set a add-record \

  -g RG1 \

  -z fhplcloudops.com \

  -n db \

  -a 10.2.0.4

  

  View DNS records

  =====================

  az network private-dns record-set list \

  -g RG1 \

  -z fhplcloudops.com

  

  Test the private zone

  ======================

  You can use the ping command to test name resolution. So, configure the firewall on both virtual machines to allow inbound ICMP packets.


Connect to myVM01, and open a Windows PowerShell window with administrator privileges.


Run the following command:

New-NetFirewallRule –DisplayName "Allow ICMPv4-In" –Protocol ICMPv4


From the myVM02 Windows PowerShell command prompt, ping myVM01 using the automatically registered host name:

==========================================================================================================


ping myVM01.fhplcloudops.com

Now ping the db name you created previously:


PowerShell


Copy

ping db.fhplcloudops.com

Setting up Docker engine on Ubuntu server on Azure VM

First go to Azure portal and create ubuntu 18.4 version VM.

Open the Azure VM and note the IP address and connect to the server using putty


Installing Docker on Linux

 

 Prerequisite

    1.   64 bit version of Ubuntu

    2.  Network Connected

    3.  Uninstall Docker

    4.  Make modifications to the Linux package installer (apt) to add docker repository

    5.  Update Package

    6.  Install Docker

     7. Verify

Ist step Uninstall Docker

   sudo apt-get remove docker docker-engine docker-ce docker.io

2nd step Update Packages and Allow Apt to Use a Repository over HTTPS

    sudo apt-get update

and

  sudo apt-get install \

  apt-transport-https \

 ca-certificates \

curl \

software-properties-common

3rd Step Add the Docker official GPG key to Apt

   curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add

4th Step Verify That you now have the Docker GPG Key

   sudo apt-key fingerprint 0EBFCD88

output:-

admina@ubuntuserver01:~$ sudo apt-key fingerprint 0EBFCD88

pub   rsa4096 2017-02-22 [SCEA]

      9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88

uid           [ unknown] Docker Release (CE deb) <docker@docker.com>

sub   rsa4096 2017-02-22 [S]

Here  we get the official response from Docker. We can see the UID of the Docker release. Everything looks good.

5th Add the Docker Repository to Apt

sudo add-apt-repository \

  "deb [arch=amd64] https://download.docker.com/linux/ubuntu \

 $(lsb_release -cs) \

 stable"

And with that repository added, we're going to do an apt-get update again to download the latest package index now that we have the Docker repository added to our list of repositories. run again, apt-get update.

6th Re-Update the Apt Package Index

   sudo apt-get  update

7th To install a specific version of Docker Engine, list the available versions in the repo, then select and install:

   apt-cache madison docker-ce

set desired version below and execute below command (sudo apt-get install docker-ce=18.03.1~ce~3-0~ubuntu

)

If you didn't want to specify a specific version and just get the latest stable version, you could just do an apt-get install docker-ce. I have added on the equals here to specify the specific version of Docker CE for Ubuntu that we'd like to run.

 8th Install a Specific Version of Docker

   sudo apt-get install docker-ce=18.03.1~ce~3-0~ubuntu

 Verify that Docker Engine is installed correctly by running the hello-world image but before verification Add Groups and Users

 9th Add Groups and Users

     sudo groupadd docker

    sudo usermod -aG docker $USER

   *Log out and log back in for this to take effect

 10th  Verify Docker Is Installed

    docker version

    docker run hello-world

output

admina@ubuntuserver01:~$ docker version

Client:

 Version:      18.03.1-ce

 API version:  1.37

 Go version:   go1.9.5

 Git commit:   9ee9f40

 Built:        Wed Jun 20 21:43:51 2018

 OS/Arch:      linux/amd64

 Experimental: false

 Orchestrator: swarm


Server:

 Engine:

  Version:      18.03.1-ce

  API version:  1.37 (minimum version 1.12)

  Go version:   go1.9.5

  Git commit:   9ee9f40

  Built:        Wed Jun 20 21:42:00 2018

  OS/Arch:      linux/amd64

  Experimental: false

admina@ubuntuserver01:~$ docker run hello-world


if you do not want to do all these 

https://github.com/Azure/azure-quickstart-templates/tree/master/docker-simple-on-ubuntu



Docker Architecture

The Docker Engine is designed as a client server application and it's really made up of three different things.

 It starts off with dockerd or the Docker daemon which is installed when you install Docker and that's the server, that's the Docker server itself. 

 Along with the installation of the Docker Engine, you receive a RESTful API which is important because that defines the interface that all other programs

 use to talk to the daemon and there's so many different pieces that make up the typical Docker ecosystem, 

 both tools from Docker as well as third-party tools. 

 And then finally, you have the Docker client.

 So, this is the actual Docker command that you run as a client to talk to the Docker server, to pull down images, build images and instantiate containers.





 No matter what version of Docker you're using whether it's the Community Edition or the Enterprise Edition 

 the Docker Engine is the required foundation that makes it all possible.

 Now let's review the typical Docker architecture. 



 The Docker daemon is installed on the Docker host.

 That Docker host could be your desktop or laptop computer, 

 it could be a server in the data center or it could be a virtual machine running up in the cloud.

 From there, the Docker host is used to execute or instantiate your containers and images. 

 It's administered through the Docker client which could be on the same host as the Docker daemon or it could be remote.

 That's the beauty of the Docker client server architecture. 

 Using the Docker client you can pull down images from a registry and then execute those images as containers running on the Docker host.


Docker NameSpace

The Docker engine utilizes something called 'Namespaces' to isolate what's happening in the running containers
 from the operating system that those containers are running on. With Namespaces the kernal resources such as the process ID, 
 user IDs, network storage, and inner process communications or IPC, 
 can all be virtualized and shared between the host operating system and the containers running on top.
 Namespaces weren't created by Docker. 
 Linux Namespaces are a core feature of the Linux kernal and have been around since 2002. Since that time there's been a lot of enhancement around 
 Namespaces and Docker has capitalized on those enhancements in the Docker engine. 
 Docker utilizes process, mount, IPC, network, and user Namespaces 
 to isolate what's happening on the Docker host from what's happening in the Docker containers. 
 Thankfully, Microsoft has even added the equivalent of Namespace isolation in Windows so that Docker for Windows could provide the same functionality.
 Namespaces are similar in concept to what a hypervisor does to provide the virtual resources like virtual CPU,
 virtual memory and virtual storage to a virtual machine.
 Namespaces keep containers isolated until Docker administrators.
 for example, allow containers to communicate over the Docker virtual networks on the same host. 
 With the Namespace isolation in Docker operating systems and applications running in containers feel like they have their own process trees,
 file systems, network connections, and more.
 
 It's even possible in Docker to map a user account in a container to a user account in the host operating system.
 Here's a simple example of how Namespace isolation works. 
 For example, here I am in an Ubuntu Docker host, and if I do a ps -ef you can see there are roughly a hundred different processes running on this host. 
 If I do the ip addr command or ip address it'll list out the ip addresses. 
 You can there's roughly some 70 different network interfaces on this host.
 docker run -it alpine /bin/sh
 However if I do a  docker run -it alpine /bin/sh
 
 we pull down an alpine Linux image, we're running that as a container, 
 and now if I perform the same commands here, for example ps -ef, 
 we have exactly two processes. 
 So what's happening in this operating system in the container is isolated off the process isolation.
 Using Namespaces is isolating us off from what's happening in the Docker host and vice versa. 
 Another example here is if I run the ip addr command, you can see we have exactly two interfaces, 
 with two different ip addresses on those interfaces.
 Again, another example of how Namespaces work to isolate off network resources from the Docker host. 
 So that's how Namespaces work in Docker.