Coder Social home page Coder Social logo

aks-voteapp-demo's Introduction

AKS VoteApp Deployment Instructions

The following instructions are used to demonstrate how to provision an AKS cluster on Azure and deploy a cloud native application into it.

๐Ÿค˜

The cloud native application is architected using microservices and is presented to the user as a web application. The application frontend provides the end-user with the ability to vote on one of 6 programming languages: C#, Python, JavaScript, Go, Java, and/or NodeJS. Voting results in AJAX calls being made from the browser to an API which in turn then saves the results into a MongoDB database.

AKSDeployment

Updates/Changelog

Thu 15 Feb 2024

  • Removed --docker-bridge-address option on az aks create as this has been deprecated
  • Corrected name of nginx svc from aks-nginx-ingress-nginx-ingress to aks-nginx-ingress-controller
  • Increased Kubernetes version to 1.27.7 to align with current Azure default
  • Updated network policy selectors to use correct podSelector labels for nginx
  • Added commands to delete the service principle

Mon 16 Jan 2023 11:57:20 NZDT

  • Updated instructions and retested end-to-end
  • Added instruction to create resource group
  • Added --location parameter to commands that use it
  • Removed deprecated --skip-assignment parameter
  • Upgraded cluster version to 1.25.2
  • Updated DNS testing to use the container image cloudacademydevops/networkutils:v2
  • Updated the Ingress resources to networking.k8s.io/v1
  • Updated networkpolicy curl commands to include --max-time 5 to control connection timeout

Tue 3 Nov 2020 20:51:59 NZDT

  • Updated instructions and retested end-to-end
  • Upgraded cluster version to 1.18.8
  • Mongo deployment now pinned down to use 4.2 to ensure replication setup initiates
  • Helm nginx-ingress deployment updated
  • Minor fixes to various kubectl commands

Client Tools

Tested with the following client tool versions

  • az 2.44.1
  • kubectl 1.27.7
  • helm 3.10.3

VoteApp

Along the way, you'll get to see how to work with the following AKS cluster resources:

  • Namespace
  • Secret
  • Deployment
  • Service
  • StatefulSet
  • PersistentVolume
  • PersistentVolumeClaim
  • IngressController (Nginx)
  • Ingress
  • NetworkPolicy

STEP 1:

Create a new AKS cluster

STEP 1.1:

Authenticate the Azure CLI. In the terminal execute the following command:

az login

STEP 1.2:

Define the variables used during the setup and installation:

{
CLUSTER_NAME=akstest
RESOURCE_GROUP=aks
LOCATION=westus
VNET_NAME=cloudacademy-aks-vnet
K8S_VERSION=1.27.7
}

STEP 1.3:

Create new resource group.

az group create --location $LOCATION --resource-group $RESOURCE_GROUP

STEP 1.4:

Create a new service principal. The AKS cluster will later be created with this.

SP=$(az ad sp create-for-rbac --name spdemocluster)

APPID=$(echo $SP | jq -r .appId)
PASSWD=$(echo $SP | jq -r .password)

echo APPID: $APPID
echo PASSWD: $PASSWD

STEP 1.5:

Create a new vnet and subnet for the AKS cluster

az network vnet create \
    --name $VNET_NAME \
    --resource-group $RESOURCE_GROUP \
    --location $LOCATION \
    --address-prefixes 10.0.0.0/8 \
    --subnet-name aks-subnet \
    --subnet-prefix 10.240.0.0/16

STEP 1.6:

Assign the contributor role to the service principal scoped on the vnet previously created

VNETID=$(az network vnet show \
  --name $VNET_NAME \
  --resource-group $RESOURCE_GROUP \
  --query id \
  -o tsv)

echo VNETID: $VNETID

az role assignment create \
  --assignee $APPID \
  --scope $VNETID \
  --role Contributor

STEP 1.7:

Create the AKS cluster and place it in the vnet subnet previously created

Standard_B2ms 1.15.10

SUBNETID=$(az network vnet subnet show \
  --name aks-subnet \
  --resource-group $RESOURCE_GROUP \
  --vnet-name $VNET_NAME \
  --query id \
  -o tsv)

echo SUBNETID: $SUBNETID

az aks create \
  --name $CLUSTER_NAME \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION \
  --node-count 2 \
  --node-vm-size Standard_D4s_v3 \
  --vm-set-type VirtualMachineScaleSets \
  --kubernetes-version $K8S_VERSION \
  --network-plugin azure \
  --service-cidr 10.0.0.0/16 \
  --dns-service-ip 10.0.0.10 \
  --vnet-subnet-id $SUBNETID \
  --generate-ssh-keys \
  --network-policy azure \
  --service-principal $APPID \
  --client-secret $PASSWD 

This takes between 5-10 minutes to complete so sit back and relax, its major chill time ๐Ÿ‘

Congrats!! You've just baked yourself a fresh AKS Kubernetes cluster!!

STEP 2:

Test the kubectl client cluster authencation

az aks get-credentials -g $RESOURCE_GROUP --name $CLUSTER_NAME --admin
kubectl get nodes
kubectl config view
kubectl config get-contexts
kubectl config current-context

STEP 3:

Install the Nginx Ingress Controller. This will allow us to direct inbound exteranl HTTP calls to the Frontend and API services that will be deployed into the AKS cluster.

STEP 3.1:

Create the nginx-ingress namespace - holds the Nginx Ingress Controller components.

cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
  name: nginx-ingress
  labels:
    name: nginx-ingress
EOF

STEP 3.2:

Use Helm to install the Nginx Ingress Controller.

Notes:

  1. The helm client needs to be installed locally
  2. This has beem successfully tested with helm version v3.10.3
  3. The helm client authenticates to the AKS cluster using the same ~/.kube/config credentials established earlier
  4. This has beem successfully tested with the helm chart nginx-stable/nginx-ingress version 0.16.0 and app version 3.0.0
helm version
helm repo add nginx-stable https://helm.nginx.com/stable
helm repo update
helm search repo nginx-ingress
helm install aks-nginx-ingress nginx-stable/nginx-ingress --namespace nginx-ingress

STEP 3.3:

Query the Nginx Ingress Controller and determine the public ip address that has been assigned to it.

Wait until the Nginx Ingress Controller has been allocated a public IP address

kubectl get svc aks-nginx-ingress-controller -n nginx-ingress --watch

Use Ctrl-C key sequence to exit the watch

Notes:

  1. The public IP address will be used to create both the API and Frontend service FQDNs used later on
  2. The API FQDN will be used to within the API's Ingress resource for host based path routing
  3. The Frontend FQDN will be used to within the Frontend's Ingress resource for host based path routing
  4. The https://nip.io/ dynamic DNS service is being used to provide wildcard DNS
kubectl get svc aks-nginx-ingress-controller -n nginx-ingress -o json

INGRESS_PUBLIC_IP=$(kubectl get svc aks-nginx-ingress-controller -n nginx-ingress -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')

echo INGRESS_PUBLIC_IP: $INGRESS_PUBLIC_IP

API_PUBLIC_FQDN=api.$INGRESS_PUBLIC_IP.nip.io
FRONTEND_PUBLIC_FQDN=frontend.$INGRESS_PUBLIC_IP.nip.io

echo API_PUBLIC_FQDN: $API_PUBLIC_FQDN
echo FRONTEND_PUBLIC_FQDN: $FRONTEND_PUBLIC_FQDN

STEP 4:

Create the cloudacademy namespace - holds the main sample cloud native application components

cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
  name: cloudacademy
  labels:
    name: cloudacademy
EOF

Configure the cloudacademy namespace to be the default

kubectl config set-context --current --namespace cloudacademy

STEP 5:

Deploy MongoDB 3 x ReplicaSet

AKSDeployment

STEP 5.1:

Display the available AKS storage classes. We use the default storage class in the following MongoDb deployment.

kubectl get storageclass

STEP 5.2:

Create a new Mongo StatefulSet name mongo

Note: security (--auth flag) hasn't been enabled on the MongoDb database - done to make the demonstration quicker.

cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mongo
  namespace: cloudacademy
spec:
  serviceName: mongo
  replicas: 3
  selector:
    matchLabels:
      role: db
  template:
    metadata:
      labels:
        role: db
        env: demo
        replicaset: rs0.main
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: replicaset
                  operator: In
                  values:
                  - rs0.main
              topologyKey: kubernetes.io/hostname
      terminationGracePeriodSeconds: 10
      containers:
        - name: mongo
          image: mongo:4.2
          command:
            - "numactl"
            - "--interleave=all"
            - "mongod"
            - "--wiredTigerCacheSizeGB"
            - "0.1"
            - "--bind_ip"
            - "0.0.0.0"
            - "--replSet"
            - "rs0"
          ports:
            - containerPort: 27017
          volumeMounts:
            - name: mongodb-persistent-storage-claim
              mountPath: /data/db
  volumeClaimTemplates:
    - metadata:
        name: mongodb-persistent-storage-claim
      spec:
        accessModes:
          - ReadWriteOnce
        storageClassName: default
        resources:
          requests:
            storage: 0.5Gi
EOF

STEP 5.3:

Examine the Mongo Pods launch ordered sequence

kubectl get pods --watch
kubectl get pods
kubectl get pods --show-labels
kubectl get pods -l role=db

Use Ctrl-C key sequence to exit the watch

Display the MongoDB Pods, Persistent Volumes and Persistent Volume Claims

kubectl get pod,pv,pvc

STEP 5.4:

Create a new Headless Service for Mongo named mongo

cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: mongo
  namespace: cloudacademy
  labels:
    role: db
    env: demo
spec:
  ports:
  - port: 27017
    targetPort: 27017
  clusterIP: None
  selector:
    role: db
EOF

STEP 5.5:

Examine the Mongo Headless Service

kubectl get svc

Examine the DNS records for the Mongo Headless Service

kubectl run -i --tty --restart=Never --rm utils --image cloudacademydevops/networkutils:v2 -- host mongo

Examine the individual DNS records for the Mongo Headless Service

kubectl run -i --tty --restart=Never --rm utils --image cloudacademydevops/networkutils:v2 -- bash -c 'for i in {0..2}; do host mongo-$i.mongo; done'

STEP 5.6:

Confirm that the mongo shell can resolve each of the 3 mongo headless service assigned dns names:

for i in {0..2}; do kubectl exec -it mongo-0 -- mongo mongo-$i.mongo --eval "print('mongo-$i.mongo succeeded')" && echo; done

On the mongo-0 pod, initialise the mongo database replica set:

cat << EOF | kubectl exec -it mongo-0 -- mongo
rs.initiate();
sleep(2000);
rs.add("mongo-1.mongo:27017");
sleep(2000);
rs.add("mongo-2.mongo:27017");
sleep(2000);
cfg = rs.conf();
cfg.members[0].host = "mongo-0.mongo:27017";
rs.reconfig(cfg, {force: true});
sleep(5000);
EOF

Confirm the mongo database replication status:

kubectl exec -it mongo-0 -- mongo --eval "rs.status()" | grep "PRIMARY\|SECONDARY"

STEP 5.7:

Load the initial voting app data into the Mongo database

cat << EOF | kubectl exec -it mongo-0 -- mongo
use langdb;
db.languages.insert({"name" : "csharp", "codedetail" : { "usecase" : "system, web, server-side", "rank" : 5, "compiled" : false, "homepage" : "https://dotnet.microsoft.com/learn/csharp", "download" : "https://dotnet.microsoft.com/download/", "votes" : 0}});
db.languages.insert({"name" : "python", "codedetail" : { "usecase" : "system, web, server-side", "rank" : 3, "script" : false, "homepage" : "https://www.python.org/", "download" : "https://www.python.org/downloads/", "votes" : 0}});
db.languages.insert({"name" : "javascript", "codedetail" : { "usecase" : "web, client-side", "rank" : 7, "script" : false, "homepage" : "https://en.wikipedia.org/wiki/JavaScript", "download" : "n/a", "votes" : 0}});
db.languages.insert({"name" : "go", "codedetail" : { "usecase" : "system, web, server-side", "rank" : 12, "compiled" : true, "homepage" : "https://golang.org", "download" : "https://golang.org/dl/", "votes" : 0}});
db.languages.insert({"name" : "java", "codedetail" : { "usecase" : "system, web, server-side", "rank" : 1, "compiled" : true, "homepage" : "https://www.java.com/en/", "download" : "https://www.java.com/en/download/", "votes" : 0}});
db.languages.insert({"name" : "nodejs", "codedetail" : { "usecase" : "system, web, server-side", "rank" : 20, "script" : false, "homepage" : "https://nodejs.org/en/", "download" : "https://nodejs.org/en/download/", "votes" : 0}});
EOF

STEP 5.8:

Confirm data has been loaded correctly

kubectl exec -it mongo-0 -- mongo langdb --eval "db.languages.find().pretty()"

STEP 6:

AKSDeployment - API

Deploy the API consisting of a Deployment, Service, and Ingress:

STEP 6.1:

Create a secret to store the mongodb connection credentials

Note: this is for demonstration purposes only - security (auth) hasn't been enabled on the MongoDb database.

The username and password values need to be base64 encode first like so

echo -n 'admin' | base64
echo -n 'password' | base64
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: mongodb-secret
  namespace: cloudacademy
data:
  username: YWRtaW4=
  password: cGFzc3dvcmQ=
EOF

API: create deployment resource

cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: cloudacademy
  labels:
    role: api
    env: demo
spec:
  replicas: 4
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 25%
  selector:
    matchLabels:
      role: api
  template:
    metadata:
      labels:
        role: api
    spec:
      containers:
      - name: api
        image: cloudacademydevops/api:v2
        imagePullPolicy: Always
        env:
          - name: MONGO_CONN_STR
            value: mongodb://mongo-0.mongo,mongo-1.mongo,mongo-2.mongo:27017/langdb?replicaSet=rs0
          - name: MONGO_USERNAME
            valueFrom:
              secretKeyRef:
                name: mongodb-secret
                key: username
          - name: MONGO_PASSWORD
            valueFrom:
              secretKeyRef:
                name: mongodb-secret
                key: password
        ports:
        - containerPort: 8080
        livenessProbe:
          httpGet:
            path: /ok
            port: 8080
          initialDelaySeconds: 2
          periodSeconds: 5
        readinessProbe:
          httpGet:
             path: /ok
             port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
          successThreshold: 1
EOF

STEP 6.2:

API: create service resource

cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: api
  namespace: cloudacademy
  labels:
    role: api
    env: demo
spec:
  ports:
   - protocol: TCP
     port: 8080
  selector:
    role: api
EOF

STEP 6.3:

API: create ingress resource

cat << EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api
  namespace: cloudacademy
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
    - host: $API_PUBLIC_FQDN
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api
                port:
                  number: 8080
EOF

STEP 6.4:

  • Examine the rollout of the API deployment
  • Examine the pods to confirm that they are up and running
  • Examine the API pod log to see that it has successfully connected to the MongoDB replicaset
  • Examine the API service details
kubectl rollout status deployment api
kubectl get pods
kubectl get pods -l role=api
kubectl logs <API_POD_NAME_HERE>
kubectl get svc

STEP 6.5:

Test the API route url - test the /ok, /languages, and /languages/{name} endpoints

curl -s $API_PUBLIC_FQDN/ok

Note: The following commands leverage the jq utility to format the json data responses

curl -s $API_PUBLIC_FQDN/languages | jq .
curl -s $API_PUBLIC_FQDN/languages/go | jq .
curl -s $API_PUBLIC_FQDN/languages/java | jq .
curl -s $API_PUBLIC_FQDN/languages/nodejs | jq .

STEP 7:

AKSDeployment

Create a new frontend Deployment

Notes:

  1. The value stored in the $API_PUBLIC_FQDN variable is injected into the frontend container's REACT_APP_APIHOSTPORT environment var - this tells the frontend where to send browser initiated API AJAX calls

STEP 7.1:

Frontend: create deployment resource

cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
  namespace: cloudacademy
  labels:
    role: frontend
    env: demo
spec:
  replicas: 4
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 25%
  selector:
    matchLabels:
      role: frontend
  template:
    metadata:
      labels:
        role: frontend
    spec:
      containers:
      - name: frontend
        image: cloudacademydevops/frontend:v10
        imagePullPolicy: Always
        env:
          - name: REACT_APP_APIHOSTPORT
            value: $API_PUBLIC_FQDN
        ports:
        - containerPort: 8080
        livenessProbe:
          httpGet:
            path: /ok
            port: 8080
          initialDelaySeconds: 2
          periodSeconds: 5
        readinessProbe:
          httpGet:
             path: /ok
             port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
          successThreshold: 1
EOF

STEP 7.2:

Frontend: create service resource

cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: frontend
  namespace: cloudacademy
  labels:
    role: frontend
    env: demo
spec:
  ports:
   - protocol: TCP
     port: 8080
  selector:
    role: frontend
EOF

STEP 7.3:

Frontend: create ingress resource

cat << EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: frontend
  namespace: cloudacademy
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
    - host: $FRONTEND_PUBLIC_FQDN
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: frontend
                port:
                  number: 8080
EOF

STEP 7.4:

Examine the rollout of the Frontend Deployment

kubectl rollout status deployment frontend
kubectl get pods
kubectl get pods -l role=frontend

STEP 7.5:

Use the curl command to test the application via the frontend route url

curl -s -I $FRONTEND_PUBLIC_FQDN
curl -s -i $FRONTEND_PUBLIC_FQDN

Generate the frontend URL

echo http://$FRONTEND_PUBLIC_FQDN

Now test the full end-to-end application using the Chrome browser...

Note: Use the Developer Tools within the Chrome browser to record, filter, and observe the AJAX traffic (XHR) which is generated when any of the +1 vote buttons are clicked.

VoteApp

STEP 8

Query the MongoDb database directly to observe the updated vote data.

kubectl exec -it mongo-0 -- mongo langdb --eval "db.languages.find().pretty()"

STEP 9

Setup and install Network Policies to control pod-to-pod traffic

STEP 9.1

Default deny all network policy for pod-to-pod traffic within the cloudacademy namespace

cat << EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: cloudacademy
spec:
  podSelector: {}
  policyTypes:
  - Ingress
EOF

Test to confirm that the frontend traffic path is now blocked

curl -vv -i --max-time 5 $FRONTEND_PUBLIC_FQDN

STEP 9.2

Allow mongo-to-mongo pod traffic, required for MongoDb data replication

cat << EOF | kubectl apply -f -
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: allow-from-mongo-to-mongo
  namespace: cloudacademy
spec:
  podSelector:
    matchLabels:
      role: db
  ingress:
  - from:
      - podSelector:
          matchLabels:
            role: db
EOF

STEP 9.3

Allow api-to-mongo pod traffic, required to allow the API to read/write data into the MongoDb database

cat << EOF | kubectl apply -f -
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: allow-from-api-to-mongo
  namespace: cloudacademy
spec:
  podSelector:
    matchLabels:
      role: db
  ingress:
  - from:
      - podSelector:
          matchLabels:
            role: api
EOF

STEP 9.4

Allow ingress-to-api pod traffic, required to allow API ajax calls from the browser

cat << EOF | kubectl apply -f -
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: allow-from-ingress-to-api
  namespace: cloudacademy
spec:
  podSelector:
    matchLabels:
      role: api
  ingress:
  - from:
      - podSelector:
          matchLabels:
            app.kubernetes.io/instance: aks-nginx-ingress
        namespaceSelector:
          matchLabels:
            name: nginx-ingress
EOF

STEP 9.5

Allow ingress-to-frontend pod traffic, required to allow the frontend (html, js, css) to be requested by the browser

cat << EOF | kubectl apply -f -
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: allow-from-ingress-to-frontend
  namespace: cloudacademy
spec:
  podSelector:
    matchLabels:
      role: frontend
  ingress:
  - from:
      - podSelector:
          matchLabels:
            app.kubernetes.io/instance: aks-nginx-ingress
        namespaceSelector:
          matchLabels:
            name: nginx-ingress
EOF

STEP 9.6

Allow ingress-to-kube-dns from pod traffic in cloudacademy namespace, required to allow pod dns traffic to resolve

cat << EOF | kubectl apply -f -
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: allow-from-cloudacademy-ns-to-kube-dns
  namespace: kube-system
spec:
  podSelector:
    matchLabels:
      k8s-app: kube-dns
  ingress:
  - from:
      - namespaceSelector:
          matchLabels:
            name: cloudacademy
EOF

Step 10

Test to confirm that the frontend traffic path is now repaired and working

curl -vv -i --max-time 5 $FRONTEND_PUBLIC_FQDN

Test the application again within the browser and generate some voting traffic

Query the MongoDb database directly to observe the updated vote data

kubectl exec -it mongo-0 -- mongo langdb --eval "db.languages.find().pretty()"

STEP 11

When you've finished with the AKS cluster and no longer need it tear it down to avoid ongoing charges!!

az aks delete --name $CLUSTER_NAME -g $RESOURCE_GROUP

Step 12

Find the ID of the spdemocluster service principle we created earlier, and delete it:

sp_id=$(az ad sp list --display-name spdemocluster --query "[0].id" -o tsv)
echo sp_id=$sp_id
az ad sp delete --id $sp_id
app_id=$(az ad app list --display-name spdemocluster --query "[0].id" -o tsv)
echo app_id=$app_id
az ad app delete --id $app_id

Good luck with your AKS adventures!!

๐Ÿš€

http://cloudacademy.com

aks-voteapp-demo's People

Contributors

jeremycook123 avatar pjlewisuk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

aks-voteapp-demo's Issues

Issue on step 5.6

Hi there!

I've been following the course Introduction to AKS and I was stuck on step 5.6 specifically on the part of adding mongo-1.mongo:27017:

cat << EOF | kubectl exec -it mongo-0 mongo
rs.initiate();
sleep(2000);
rs.add("mongo-1.mongo:27017");
sleep(2000);
rs.add("mongo-2.mongo:27017");
sleep(2000);
cfg = rs.conf();
cfg.members[0].host = "mongo-0.mongo:27017";
rs.reconfig(cfg, {force: true});
sleep(5000);
EOF

While executing the code above, I tried to create another terminal session and run:

cat << EOF | kubectl exec -it mongo-0 mongo
rs.status();
EOF

and the response I got was:

{
        "set" : "rs0",
        "date" : ISODate("2020-08-17T08:06:59.484Z"),
        "myState" : 1,
        "term" : NumberLong(1),
        "syncSourceHost" : "",
        "syncSourceId" : -1,
        "heartbeatIntervalMillis" : NumberLong(2000),
        "majorityVoteCount" : 2,
        "writeMajorityCount" : 2,
        "votingMembersCount" : 2,
        "writableVotingMembersCount" : 2,
        "optimes" : {
                "lastCommittedOpTime" : {
                        "ts" : Timestamp(1597650208, 1),
                        "t" : NumberLong(1)
                },
                "lastCommittedWallTime" : ISODate("2020-08-17T07:43:28.560Z"),
                "readConcernMajorityOpTime" : {
                        "ts" : Timestamp(1597650208, 1),
                        "t" : NumberLong(1)
                },
                "readConcernMajorityWallTime" : ISODate("2020-08-17T07:43:28.560Z"),
                "appliedOpTime" : {
                        "ts" : Timestamp(1597651616, 1),
                        "t" : NumberLong(1)
                },
                "durableOpTime" : {
                        "ts" : Timestamp(1597651616, 1),
                        "t" : NumberLong(1)
                },
                "lastAppliedWallTime" : ISODate("2020-08-17T08:06:56.654Z"),
                "lastDurableWallTime" : ISODate("2020-08-17T08:06:56.654Z")
        },
        "lastStableRecoveryTimestamp" : Timestamp(1597650208, 1),
        "electionCandidateMetrics" : {
                "lastElectionReason" : "electionTimeout",
                "lastElectionDate" : ISODate("2020-08-17T07:43:26.545Z"),
                "electionTerm" : NumberLong(1),
                "lastCommittedOpTimeAtElection" : {
                        "ts" : Timestamp(0, 0),
                        "t" : NumberLong(-1)
                },
                "lastSeenOpTimeAtElection" : {
                        "ts" : Timestamp(1597650206, 1),
                        "t" : NumberLong(-1)
                },
                "numVotesNeeded" : 1,
                "priorityAtElection" : 1,
                "electionTimeoutMillis" : NumberLong(10000),
                "newTermStartDate" : ISODate("2020-08-17T07:43:26.584Z"),
                "wMajorityWriteAvailabilityDate" : ISODate("2020-08-17T07:43:26.646Z")
        },
        "members" : [
                {
                        "_id" : 0,
                        "name" : "mongo-0:27017",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 1775,
                        "optime" : {
                                "ts" : Timestamp(1597651616, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2020-08-17T08:06:56Z"),
                        "syncSourceHost" : "",
                        "syncSourceId" : -1,
                        "infoMessage" : "",
                        "electionTime" : Timestamp(1597650206, 2),
                        "electionDate" : ISODate("2020-08-17T07:43:26Z"),
                        "configVersion" : 2,
                        "configTerm" : 1,
                        "self" : true,
                        "lastHeartbeatMessage" : ""
                },
                {
                        "_id" : 1,
                        "name" : "mongo-1.mongo:27017",
                        "health" : 1,
                        "state" : 0,
                        "stateStr" : "STARTUP",
                        "uptime" : 1410,
                        "optime" : {
                                "ts" : Timestamp(0, 0),
                                "t" : NumberLong(-1)
                        },
                        "optimeDurable" : {
                                "ts" : Timestamp(0, 0),
                                "t" : NumberLong(-1)
                        },
                        "optimeDate" : ISODate("1970-01-01T00:00:00Z"),
                        "optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"),
                        "lastHeartbeat" : ISODate("2020-08-17T08:06:58.626Z"),
                        "lastHeartbeatRecv" : ISODate("1970-01-01T00:00:00Z"),
                        "pingMs" : NumberLong(0),
                        "lastHeartbeatMessage" : "",
                        "syncSourceHost" : "",
                        "syncSourceId" : -1,
                        "infoMessage" : "",
                        "configVersion" : -2,
                        "configTerm" : -1
                }
        ],
        "ok" : 1,
        "$clusterTime" : {
                "clusterTime" : Timestamp(1597651616, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(1597651616, 1)
}

I hope you can update the steps so that I can proceed with it. I fairly new with Kubernetes and I would really like more about it. This course was a good one especially with this specific demo. Kudos to the team and hoping to learn more about cloud with you guys!

Regards,
Julius

Issue with Step 5 AKS Create fails with PropertyChangeNotAllowed

Hi @jeremycook123

This step was fine:

SUBNETID=$(az network vnet subnet show \
  --name aks-subnet \
  --resource-group $RESOURCE_GROUP \
  --vnet-name $VNET_NAME \
  --query id \
  -o tsv) 
echo SUBNETID: $SUBNETID

SUBNETID: /subscriptions/4d916bc0-XXXX-XXXX-XXXX-XXXXXXXXX/resourceGroups/RTL-Arthur/providers/Microsoft.Network/virtualNetworks/arthur-paf-aks-vnet/subnets/aks-subnet

But next step of cluster creation fails:

az aks create \
  --name $CLUSTER_NAME \
  --resource-group $RESOURCE_GROUP \
  --node-count 2 \
  --node-vm-size Standard_D2as_v4 \
  --vm-set-type VirtualMachineScaleSets \
  --kubernetes-version 1.22.15 \
  --network-plugin kubenet \
  --service-cidr 10.0.0.0/16 \
  --dns-service-ip 10.0.0.10 \
  --docker-bridge-address 172.17.0.1/16 \
  --vnet-subnet-id $SUBNETID \
  --generate-ssh-keys \
  --network-policy azure \
  --enable-addons http_application_routing \
  --location uksouth \
  --enable-cluster-autoscaler \
  --min-count 1 \
  --max-count 5 \
  --service-principal $APPID \
  --client-secret $PASSWD \
  --attach-acr arthuracr

AAD role propagation done[############################################] 100.0000%(PropertyChangeNotAllowed) Changing property 'servicePrincipalProfile.clientId' is not allowed.
Code: PropertyChangeNotAllowed
Message: Changing property 'servicePrincipalProfile.clientId' is not allowed.
Target: servicePrincipalProfile.clientId

Tried to delete .azure folder but still the same. Any thoughts?

Not sure if related

Azure/azure-cli#5219

docker run -v ${HOME}:/root -it azuresdk/azure-cli-python:dev helps?

python 3.9.9
kompose 1.26.0
kubectl 1.24.0
azure-cli 2.37.0
jq 1.6
Mac OSX 12.5

Issue with STEP 7.5

Hi,

I'm having issue displaying the frontend portal. To be more specific if I run:
curl -s -i $FRONTEND_PUBLIC_FQDN
this is the result:

HTTP/1.1 404 Not Found
Server: nginx/1.19.1
Date: Thu, 20 Aug 2020 11:34:52 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 21
Connection: keep-alive

default backend - 404

I tried to navigate logs but didn't found any obvious issue. All pods are running:

NAME                       READY   STATUS    RESTARTS   AGE
api-f44858555-4w9cs        1/1     Running   0          59m
api-f44858555-khcw2        1/1     Running   0          59m
api-f44858555-lx6br        1/1     Running   0          59m
api-f44858555-spj79        1/1     Running   0          59m
frontend-d5dbcf48d-2fccn   1/1     Running   0          57m
frontend-d5dbcf48d-jh2vl   1/1     Running   0          57m
frontend-d5dbcf48d-ncktp   1/1     Running   0          57m
frontend-d5dbcf48d-p47hl   1/1     Running   0          57m
mongo-0                    1/1     Running   0          81m
mongo-1                    1/1     Running   0          81m
mongo-2                    1/1     Running   0          80m

Thanks a lot

Daniele

PS: Note I have some issues with nip.io since it's blocked by my company policy. I'm currently using Azure Cloud Shell and a private PC to access it but I wonder if there are alternative solutions.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.