Skip to content

AKS Hybrid Small topology 1.3 AHR Manual

Yuriy Lesyuk edited this page Oct 23, 2020 · 4 revisions

AKS Hybrid Small Topology 1.3 | AHR Manual

What to expect:

  • detailed instructions,
  • no steps skipped or redirected,
  • no gui for actionable tasks for better scriptability/automation (but all right for checks and validations),
  • interim validation steps.
  • tidying up afterwards (deleting all created resources).

Duration: 60m

__Prerequisites:++

  • Azure project and a resource group;
  • GCP project

Both clouds have shells. You can do installation using both, or each. On Azure Shell you can setup gcloud. Similarly, on Gloud you can install az.

Both shells are a free resource and disintegrate after an idle timeout, having only ~ [home] directory persisted. As a result, the only way to setup gcloud at Azure or az at GCP is to install it into a home directory.

Both shells have tmux preinstalled. It's useless for a long-running operations with such a short shell VM time-to-live.

Azure shell: 20 min timeout

GCP shell: 60 min timeout

Saying that, GCP Cloud Shell has an hour of idle time, which makes it practical for majority of situations without having you setting up a bastion host.

The timeout also means you better start to work with environment variables configuration files as a way to persist your session state. That is what we are going to do.

Configure Google Cloud and UI

Install az n a gcp cloud shell

?. Open a GCP Cloud Shell in your browser

https://ssh.cloud.google.com/

?. Execute az installation script from https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-linux

Accept defaults (for install directory; executable directory; allow to modify bashrc profile and do modifications)

curl -L https://aka.ms/InstallAzureCli | bash

NOTE: az completion will be configured, still make a note for az completion file location, ~/lib/azure-cli/az.completion.

?. Either re-open shell or start another bash instance to activate .bashrc configs.

bash

?. Log into your Azure account, using a link and a code to authenticate.

az login

?. Test your connection

az account show

You will see az account show output json if logged in successfully.

Define Installation Hybrid Home

Let's keep all nice and tidy. We are going to organize all dependencies and configuration files in a single hybrid install directory. ?. Configure hybrid install environment location

export HYBRID_HOME=~/apigee-hybrid-install

?. Create $HYBRID_HOME directory, if it does not exist.

mkdir -p $HYBRID_HOME

Install ahr with examples and templates

?. If not, be in the Hybrid Install Home directory

cd $HYBRID_HOME

?. Clone ahr git repository

git clone https://github.com/yuriylesyuk/ahr.git

?. Define AHR_HOME variable and add bin directory to the PATH

export AHR_HOME=$HYBRID_HOME/ahr
export PATH=$AHR_HOME/bin:$PATH

Define GCP project, Azure project, and Hybrid Configuration Variables

?. Define the hybrid configuration file name

export HYBRID_ENV=$HYBRID_HOME/hybrid-13.env

?. Use provided example configuration for a small footprint hybrid runtime cluster.

cp $AHR_HOME/examples/hybrid-sz-s-1.3.sh $HYBRID_ENV

?. Inspect the $HYBRID_ENV configuration file.

vi $HYBRID_ENV

Observe:

  • sourced ahr-lib.sh file that contains useful functions like token() and is required to correctly generate names of the asm and apigectl distributives;

  • we control versions of cert-manager, asm, Kubernetes and Apigee hybrid here;

  • example contains GCP project variables; we are going to add Azure variables as well;

  • cluster parameters are defined, including a cluster template and a name for a cluster config file, used to create a cluster at GKE. We are going to use az utility to create an AKS cluster;

  • the last section defines default values describing hybrid properties, as well as HYBRID_CONFIG variable that configures a hybrid configuration file;

  • the RUNTIME_IP variable is commented out, as it is treated differently depending on your circumstances.

?. Add environment variables that describe following Azure project properties, right after GCP Project variable group:

#
# Azure Project
#
export RESOURCE_GROUP=yuriyl

export AZ_REGION=westeurope
export AZ_VNET=$RESOURCE_GROUP-vnet-$AZ_REGION
export AZ_VNET_SUBNET=$RESOURCE_GROUP-vnet-$AZ_REGION-subnet

?. Define network layout.

For a region AZ_REGION we are creating our AKS cluster in, we need a virtual network VNET. We will define a subnet in it for the cluster nodes. As we are going to use Azure CNI, we also need to allocate another subnet that will host services, as well as docker bridge addresses pool and a DNS service IP.

Those address previces in CIDR notation are:

For VNet create command:

--address-prefixes $AZ_VNET_CIDR network cidr XXX

--subnet-prefix $AZ_VNET_SUBNET_CIDR subnet for cluster nodes

For AKS create command: --service-cidr=$AKS_SERVICE_CIDR is a CIDR notation IP range from which to assign service cluster IPs --docker-bridge-address is a specific IP address and netmask for the Docker bridge, using standard CIDR notation --dns-service-ip is an IP address assigned to the Kubernetes DNS service

Of course, with /14 (262,144 addresses)and /16 (65,536 addresses) subnet masks we are very generous, not to say wasteful, but why not if we can and what's more important, those values are soft-coded in the variables and you can change them as it suits you.

CIDR: 10.0.0.0/14 CIDR IP Range: 10.0.0.0 - 10.3.255.255

CIDR: 10.0.0.0/16 CIDR IP Range: 10.0.0.0 - 10.0.255.255
CIDR: 10.1.0.0/16 CIDR IP Range: 10.1.0.0 - 10.1.255.255

?. Add network definition variables to the HYBRID_ENV file

# network layout
export AZ_VNET_CIDR=10.0.0.0/14
export AZ_VNET_SUBNET_CIDR=10.0.0.0/16

export AKS_SERVICE_CIDR=10.1.0.0/16
export AKS_DNS_SERVICE_IP=10.1.0.10
export AKS_DOCKER_CIDR=172.17.0.1/16

We'll fix the RUNTIME_IP address after we provision a static IP address. We are going to use default values for all other variables.

Define Project environment variable and Set default Project Config

?. Define PROJECT variable

NOTE: For qwiklabs account, you can use

export PROJECT=$(gcloud projects list|grep qwiklabs-gcp|awk '{print $1}')
export PROJECT=<gcp-project-id>

?. Set it up as a a gcloud config default

gcloud config set project $PROJECT

Set up session environment

?. Now that we set up required variables that the env file depends (PROJECT, AHR_HOME), we can source the HYBRID_ENV

source $HYBRID_ENV

GCP: Enable APIs

?. We need a number of google apis enabled for correct operations of gke hube, apigee organization, asm, etc.

Let's enable them

ahr-verify-ctl api-enable

Azure: Kubernetes Cluster creation

We are going to create Azure objects using CLI commands. We will be using Azure portal to verify objects creation state.

NOTE: If you didn't yet, create a resource group.

az group create --name $RESOURCE_GROUP --location $AZ_REGION

?. Create Azure network and a subnet

REF: az network * https://docs.microsoft.com/en-us/cli/azure/network/vnet?view=azure-cli-latest

az network vnet create \
 --name $AZ_VNET \
 --resource-group $RESOURCE_GROUP \
 --location $AZ_REGION \
 --address-prefixes $AZ_VNET_CIDR \
 --subnet-name $AZ_VNET_SUBNET \
 --subnet-prefix $AZ_VNET_SUBNET_CIDR

az vnet

?. Get subnet resource Id we need to supply as a parameter to create AKS cluster

export AZ_VNET_SUBNET_ID=$(
    az network vnet subnet show \
    --resource-group $RESOURCE_GROUP \
    --vnet-name $AZ_VNET \
    --name $AZ_VNET_SUBNET \
    --query id \
    --output tsv )

?. TODO: Portal snapshot

?. Verify the value. It is rather involved. That is why we don't want to write it manually.

echo $AZ_VNET_SUBNET_ID

/subscriptions/07e07c10-acbd-417b-b4b0-3aca8ce79b38/resourceGroups/yuriyl/providers/Microsoft.Network/virtualNetworks/yuriyl-vnet-eastus/subnets/yuriyl-vnet-eastus-subnet

?. Create an AKS cluster

az aks create \
  --resource-group $RESOURCE_GROUP \
  --name $CLUSTER \
  --location $AZ_REGION \
  --kubernetes-version 1.17.11 \
  --nodepool-name hybridpool \
  --node-vm-size Standard_DS3_v2 \
  --node-count 4 \
  --network-plugin azure \
  --vnet-subnet-id $AZ_VNET_SUBNET_ID \
  --service-cidr $AKS_SERVICE_CIDR \
  --dns-service-ip $AKS_DNS_SERVICE_IP \
  --docker-bridge-address $AKS_DOCKER_CIDR \
  --generate-ssh-keys \
  --output table

Output:

SSH key files '/home/student_00_638a7fc61408/.ssh/id_rsa' and '/home/student_00_638a7fc61408/.ssh/id_rsa.pub' have been generated under ~/.ssh to allow SSH access to the VM. If using machines without permanent storage like Azure Cloud Shell without an attached file share, back up your keys to a safe location
DnsPrefix                 EnableRbac    Fqdn                                                    KubernetesVersion    Location    MaxAgentPools    Name            NodeResourceGroup                ProvisioningState    ResourceGroup
------------------------  ------------  ------------------------------------------------------  -------------------  ----------  ---------------  --------------  -------------------------------  -------------------  ---------------
hybrid-clu-yuriyl-07e07c  True          hybrid-clu-yuriyl-07e07c-d17b2653.hcp.eastus.azmk8s.io  1.17.11              eastus      10               hybrid-cluster  MC_yuriyl_hybrid-cluster_eastus  Succeeded            yuriyl

?. You can now open Azure portal and see created cluster there.

az cluster

?. Get cluster credentials

az aks get-credentials --resource-group $RESOURCE_GROUP --name $CLUSTER

Merged "hybrid-cluster" as current context in /home/student_00_638a7fc61408/.kube/config

NOTE: Make a note of the kube config file location if you want to copy/move those credentials to another server.

?. Verify kubectl communication with the cluster by getting list of deployed pods

kubectl get pods -A

NAMESPACE     NAME                                         READY   STATUS    RESTARTS   AGE
kube-system   azure-cni-networkmonitor-2kcjs               1/1     Running   0          2m47s
kube-system   azure-cni-networkmonitor-k8pjf               1/1     Running   0          2m48s
...

GCP: Attach the cluster on Anthos

We are using Anthos attached cluster to control the cluster from GCP. For this we need to:

  • register the cluster in the Anthos;
  • create a kubernetes service account;
  • login into the cluster via GCP Console

GKE Hub: Cluster membership registration

NOTE: roles required for gkehub membership management:

--role=roles/gkehub.admin --role=roles/iam.serviceAccountAdmin --role=roles/iam.serviceAccountKeyAdmin --role=roles/resourcemanager.projectIamAdmin

?. Create a new service account for cluster registration

gcloud iam service-accounts create anthos-hub --project=$PROJECT

?. Grant GKE Hub connect role to the service account

gcloud projects add-iam-policy-binding $PROJECT \
--member="serviceAccount:anthos-hub@$PROJECT.iam.gserviceaccount.com" \
 --role="roles/gkehub.connect"

?. Create key and download its JSON file

gcloud iam service-accounts keys create $HYBRID_HOME/anthos-hub-$PROJECT.json \
--iam-account=anthos-hub@$PROJECT.iam.gserviceaccount.com --project=$PROJECT

?. Register the AKS cluster in the GKE Hub

gcloud container hub memberships register $CLUSTER \
--context=$CLUSTER \
--kubeconfig=~/.kube/config \
--service-account-key-file=$HYBRID_HOME/anthos-hub-$PROJECT.json

Waiting for membership to be created...done.
Created a new membership [projects/qwiklabs-gcp-00-27dddd013336/locations/global/memberships/hybrid-cluster] for the cluster [hybrid-cluster]
Generating the Connect Agent manifest...
Deploying the Connect Agent on cluster [hybrid-cluster] in namespace [gke-connect]...
Deployed the Connect Agent on cluster [hybrid-cluster] in namespace [gke-connect].

In the output, observe that besides cluster membership registration, the GKE Connect Agent was deployed into the target cluster.

At this point of time we can see our cluster in GCP Console.

?. In GCP Console, Open Kubernetes Engine / Cluster page

gke cluster

NOTE: If something went wrong and you need to remove the cluster membership

gcloud container hub memberships list

NAME                   EXTERNAL_ID
apigee-hybrid-cluster  5bbb2607-4266-40cd-bf86-22fdecb21137

gcloud container hub memberships unregister $CLUSTER_NAME \
--context=$CLUSTER_NAME \
--kubeconfig=~/kubeconfig-azure.yaml 

Kubectl: Register the cluster

?. Create kubernetes service account

kubectl create serviceaccount anthos-user

kubectl create clusterrolebinding aksadminbinding --clusterrole view --serviceaccount default:anthos-user

kubectl create clusterrolebinding aksadminnodereader --clusterrole node-reader --serviceaccount default:anthos-user

kubectl create clusterrolebinding aksclusteradminbinding --clusterrole cluster-admin --serviceaccount default:anthos-user

GCP Console: Log into Cluster

?. Get the token for the service account

CLUSTER_SECRET=$(kubectl get serviceaccount anthos-user -o jsonpath='{$.secrets[0].name}')

kubectl get secret ${CLUSTER_SECRET} -o jsonpath='{$.data.token}' | base64 --decode

?. In GCP Console, Open Kubernetes Engine / Cluster page, press Login button

gke log to cluster

?. Chose Token method, paste the token and click LOGIN

NOTE: Whichever select-and-copy technique you are using, make sure the token is a single line of characters with no end-of-line characters.

The cluster is attached now:

gke logged cluster

kubectl: Install Cert-manager

NOTE: use either Azure Cloud Shell or GCP Cloud Shell's kubectl and cluster config file

?., download and install cert-manager

kubectl apply --validate=false -f $CERT_MANAGER_MANIFEST

gke cert manager

Azure: Create Public IP for ASM Ingress Load Balancer

See for details: https://docs.microsoft.com/en-us/azure/aks/static-ip

?. Create public IP

az network public-ip create --resource-group $RESOURCE_GROUP --name $CLUSTER-public-ip --location $AZ_REGION --sku Standard --allocation-method static --query publicIp.ipAddress -o tsv

The provisioned IPv4 address will be shown. Make a note of if.

?. Assign delegated permissions to the resource group for our Service Principal.

export SP_PRINCIPAL_ID=$(az aks show --name $CLUSTER --resource-group $RESOURCE_GROUP --query servicePrincipalProfile.clientId -o tsv)

export SUBSCRIPTION_ID=$(az account show --query id -o tsv)


az role assignment create --assignee $SP_PRINCIPAL_ID --role "Network Contributor" --scope /subscriptions/$SUBSCRIPTION_ID/resourcegroups/$RESOURCE_GROUP

?. Edit $HYBRID_ENV to configure RUNTIME_IP (at the end of the file):

NOTE: Use following az and sed commands to do it programmatically

export RUNTIME_IP=$(az network public-ip show --resource-group $RESOURCE_GROUP --name $CLUSTER-public-ip --query ipAddress --output tsv)

sed -i -E "s/^(export RUNTIME_IP=).*/\1$RUNTIME_IP/g" $HYBRID_ENV

vi $HYBRID_ENV

export RUNTIME_IP=<insert-the-output-of-previous-command>

Install Anthos Service Mesh (ASM)

?. Set up a profile variable for on-prem ASM configuration,

vi $HYBRID_ENV

export ASM_PROFILE=asm-multicloud

?. re-source $HYBRID_ENV to actualise changed values in the current session

source $HYBRID_ENV

?. Prepare session variables to create an IstioOperator manifest file.

NOTE: Those are 'derived' variables present in the template file and replaced by ahr-cluster-ctl template command. Therefore, we don't need them in the $HYBRID_ENV

export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT} --format="value(projectNumber)")
export ref=\$ref
export ASM_RELEASE=$(echo "$ASM_VERSION"|awk '{sub(/\.[0-9]+-asm\.[0-9]+/,"");print}')

?. As it happens with IstioOperator, there always are some annotations and/or parameters you need to fine-tune on a Kubernetes platform-by-platform basis.

For AKS, we need to set up an annotation for resource group so that static IP address is correctly identified.

Clone provided IstioOperator template for on-prem/multi-cloud installation.

cp $AHR_HOME/templates/istio-operator-$ASM_RELEASE-$ASM_PROFILE.yaml $HYBRID_HOME/istio-operator-aks-template.yaml

?. Edit $HYBRID_HOME/istio-operator-aks-template.yaml to add necessary service annotation

We need to create a service.beta.kubernetes.io/azure-load-balancer-resource-group: $RESOURCE_GROUP in the spec.components.ingressGateways[name=istio-ingressgateway].k8s.serviceAnnotations property.

NOTE: We are using a variable name here, because we are going to process this template and resolve the variable in the next step.

vi $HYBRID_HOME/istio-operator-aks-template.yaml

  service.beta.kubernetes.io/azure-load-balancer-resource-group: $RESOURCE_GROUP

The result should look like this:

istio operator az annnotation

WARNING: If you are using Azure DNS for your service, you need to apply a DNS label to the service.

?. Process the template to obtain $ASM_CONFIG file.

$AHR_HOME/templates/istio-operator-$ASM_RELEASE-$ASM_PROFILE.yaml > $ASM_CONFIG

Process provided template file suitable for on-prem ASM installation

ahr-cluster-ctl template $HYBRID_HOME/istio-operator-aks-template.yaml > $ASM_CONFIG

?. Inspect $ASM_CONFIG file

vi $ASM_CONFIG

Observe:

?. Get ASM installation files

ahr-cluster-ctl asm-get $ASM_VERSION

?. Define ASM_HOME and add ASM bin directory to the path by copying and pasting provided export statements from the previous command output.

export ASM_HOME=$HYBRID_HOME/istio-$ASM_VERSION
export PATH=$ASM_HOME/bin:$PATH

?. Install ASM into our cluster

istioctl install -f $ASM_CONFIG

! global.mtls.enabled is deprecated; use the PeerAuthentication resource instead
✔ Istio core installed                
✔ Istiod installed                                                           
✔ Ingress gateways installed                                                                                                                                                                                     
✔ Addons installed                                                                                                                               
✔ Installation complete 

?. At the Services & Ingress page of Kubernetes Engine section, observe configured Ingress IP address.

?. Drill down into istio-ingressgateway Service configuration and observe the annotation created:

gke ingress annotation

Apigee Hybrid Organization Configuration

? Create hybrid organization, environment, and environment group.

ahr-runtime-ctl org-create $ORG --ax-region $AX_REGION

ahr-runtime-ctl env-create $ENV

ahr-runtime-ctl env-group-create $ENV_GROUP $RUNTIME_HOST_ALIAS

ahr-runtime-ctl env-group-assign $ORG $ENV_GROUP $ENV

?. SAs and their Keys

ahr-sa-ctl create-sa all

ahr-sa-ctl create-key all

?. Set up synchronizer Service Account identifier (email)

ahr-runtime-ctl setsync $SYNCHRONIZER_SA_ID

?. Configure self-signed certificate for Ingress Gateway

ahr-verify-ctl cert-create-ssc $RUNTIME_SSL_CERT $RUNTIME_SSL_KEY $RUNTIME_HOST_ALIAS

Apigee Hybrid Runtime Install

?. Get apigeectl and hybrid distribution

ahr-runtime-ctl get

?. Configure APIGEE_HOME variable

export APIGEECTL_HOME=$HYBRID_HOME/$(tar tf $HYBRID_HOME/$HYBRID_TARBALL | grep VERSION.txt | cut -d "/" -f 1)

?. Add apigeectl directory to your PATH

export PATH=$APIGEECTL_HOME:$PATH

?. Generate Runtime Configuration yaml file

ahr-runtime-ctl template $AHR_HOME/templates/overrides-small-13-template.yaml > $RUNTIME_CONFIG

?. Inspect generated runtime configuration file

vi $RUNTIME_CONFIG

?. Observe:

  • TODO:

?. Deploy apigee hybrid init components

ahr-runtime-ctl apigeectl init -f $RUNTIME_CONFIG

?. Wait until all containers are ready

ahr-runtime-ctl apigeectl wait-for-ready -f $RUNTIME_CONFIG

?. Deploy hybrid components

ahr-runtime-ctl apigeectl apply -f $RUNTIME_CONFIG

?. Wait until they are ready

ahr-runtime-ctl apigeectl wait-for-ready -f $RUNTIME_CONFIG

Deploy ping Proxy and Execute Test Request to it

?. Deploy provided ping proxy

$AHR_HOME/proxies/deploy.sh

?. Execute a test request

curl --cacert $RUNTIME_SSL_CERT https://$RUNTIME_HOST_ALIAS/ping -v --resolve "$RUNTIME_HOST_ALIAS:443:$RUNTIME_IP" --http1.1

Azure: Delete resources

?. Delete cluster

az aks delete \
--name $CLUSTER \
 --resource-group $RESOURCE_GROUP \
  --yes

?. Delete public ip

az network public-ip delete \
--name $CLUSTER-public-ip \
 --resource-group $RESOURCE_GROUP

?. Delete network

az network vnet delete \
 --name $AZ_VNET \
 --resource-group $RESOURCE_GROUP 
Clone this wiki locally