{"id":23459506,"url":"https://github.com/devkimchi/aspir8-from-scratch","last_synced_at":"2025-10-30T22:31:00.470Z","repository":{"id":215529176,"uuid":"739163558","full_name":"devkimchi/aspir8-from-scratch","owner":"devkimchi","description":"Let's deploy Aspire-flavoured apps to a Kubernetes cluster, through Aspir8! Are you new to Kubernetes? Don't worry. Let's start from scratch.","archived":false,"fork":false,"pushed_at":"2024-09-22T06:13:34.000Z","size":185,"stargazers_count":20,"open_issues_count":1,"forks_count":4,"subscribers_count":5,"default_branch":"main","last_synced_at":"2024-12-24T06:14:41.039Z","etag":null,"topics":["aspir8","aspirate","aspire","kubernetes"],"latest_commit_sha":null,"homepage":"","language":"CSS","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devkimchi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2024-01-04T23:19:40.000Z","updated_at":"2024-11-29T20:51:30.000Z","dependencies_parsed_at":"2024-01-24T17:36:07.808Z","dependency_job_id":null,"html_url":"https://github.com/devkimchi/aspir8-from-scratch","commit_stats":null,"previous_names":["devkimchi/aspir8-from-scratch"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devkimchi%2Faspir8-from-scratch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devkimchi%2Faspir8-from-scratch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devkimchi%2Faspir8-from-scratch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devkimchi%2Faspir8-from-scratch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devkimchi","download_url":"https://codeload.github.com/devkimchi/aspir8-from-scratch/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239070003,"owners_count":19576477,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aspir8","aspirate","aspire","kubernetes"],"created_at":"2024-12-24T06:14:40.838Z","updated_at":"2025-10-30T22:30:59.832Z","avatar_url":"https://github.com/devkimchi.png","language":"CSS","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Aspir8 from Scratch\r\n\r\nLet's deploy [Aspire](https://learn.microsoft.com/dotnet/aspire/get-started/aspire-overview)-flavoured apps to a [Kubernetes](https://kubernetes.io/) cluster, through [Aspir8](https://github.com/prom3theu5/aspirational-manifests)! Are you new to Kubernetes? Don't worry. Let's start from scratch.\r\n\r\n\u003c!-- \u003e This document is based on MacOS Sonoma with M2 Silicon Chip. If you are using a different OS or different chipset, it might be behaving differently. --\u003e\r\n\r\n## Table of Contents\r\n\r\n- [Aspir8 from Scratch](#aspir8-from-scratch)\r\n  - [Table of Contents](#table-of-contents)\r\n  - [Prerequisites](#prerequisites)\r\n  - [Local Kubernetes Cluster Setup through Docker Desktop](#local-kubernetes-cluster-setup-through-docker-desktop)\r\n  - [Kubernetes Dashboard Setup](#kubernetes-dashboard-setup)\r\n    - [Use Kubernetes Dashboard v2.x](#use-kubernetes-dashboard-v2x)\r\n    - [Use Helm Charts](#use-helm-charts)\r\n  - [Aspire-flavoured App Build](#aspire-flavoured-app-build)\r\n  - [Aspire-flavoured App Deployment to Kubernetes Cluster through Aspir8](#aspire-flavoured-app-deployment-to-kubernetes-cluster-through-aspir8)\r\n    - [Use local container registry](#use-local-container-registry)\r\n    - [Use Azure Kubernetes Services (AKS)](#use-azure-kubernetes-services-aks)\r\n    - [Use Amazon Elastic Kubernetes Service (EKS)](#use-amazon-elastic-kubernetes-service-eks)\r\n    - [Use Google Kubernetes Engine (GKE)](#use-google-kubernetes-engine-gke)\r\n    - [Use NHN Kubernetes Services (NKS)](#use-nhn-kubernetes-services-nks)\r\n\r\n## Prerequisites\r\n\r\n- for Aspire\r\n  - [.NET 8 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) 8.0.200 or higher with the [Aspire workload](https://learn.microsoft.com/dotnet/aspire/fundamentals/setup-tooling?tabs=dotnet-cli)\r\n  - [Visual Studio Code](https://code.visualstudio.com/) with the [C# Dev Kit](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit) extension\r\n- for local Kubernetes cluster\r\n  - [Docker Desktop](https://www.docker.com/products/docker-desktop/)\r\n- for Azure\r\n  - [Azure subscription](https://azure.microsoft.com/free)\r\n  - [Azure CLI](https://learn.microsoft.com/cli/azure/what-is-azure-cli)\r\n- for AWS\r\n  - [AWS subscription](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html?nc2=h_ct\u0026src=header_signup)\r\n  - [AWS CLI](https://aws.amazon.com/cli/)\r\n- for GKE\r\n  - TBD\r\n- for NHN Cloud\r\n  - [NHN Cloud subscription](https://id.nhncloud.com/join)\r\n\r\n## Local Kubernetes Cluster Setup through Docker Desktop\r\n\r\n1. [Install Docker Desktop on you local machine](https://docs.docker.com/desktop/install/mac-install/).\r\n1. [Enable Kubernetes in Docker Desktop](https://docs.docker.com/desktop/kubernetes/).\r\n1. [Deploy sample app to a Kubernetes cluster](https://docs.docker.com/get-started/kube-deploy/).\r\n\r\n## Kubernetes Dashboard Setup\r\n\r\n### Use Kubernetes Dashboard v2.x\r\n\r\n\u003c!-- If you want to directly setup the Kubernetes Dashboard on your local machine, follow the steps below. Otherwise, skip this section and go to the next section, [MicroK8s Setup](#microk8s-setup). --\u003e\r\n\r\n\u003e **Note:** This is only applicable for Kubernetes Dashboard v2.x.\r\n\r\n**References**\r\n\r\n- [Deploy and Access the Kubernetes Dashboard](https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/)\r\n- [Creating sample user](https://github.com/kubernetes/dashboard/blob/master/docs/user/access-control/creating-sample-user.md)\r\n\r\n1. Get dashboard version.\r\n\r\n    ```bash\r\n    # Bash\r\n    dashboard_version=$(curl 'https://api.github.com/repos/kubernetes/dashboard/releases' | \\\r\n        jq -r '[.[] | select(.name | contains(\"-\") | not)] | .[0].name')\r\n\r\n    # PowerShell\r\n    $dashboard_version = $($(Invoke-RestMethod https://api.github.com/repos/kubernetes/dashboard/releases) | `\r\n        Where-Object { $_.name -notlike \"*-*\" } | Select-Object -First 1).name\r\n    ```\r\n\r\n1. Install dashboard.\r\n\r\n    ```bash\r\n    # Bash\r\n    kubectl apply -f \\\r\n      https://raw.githubusercontent.com/kubernetes/dashboard/$dashboard_version/aio/deploy/recommended.yaml\r\n\r\n    # PowerShell\r\n    kubectl apply -f `\r\n      https://raw.githubusercontent.com/kubernetes/dashboard/$dashboard_version/aio/deploy/recommended.yaml\r\n    ```\r\n\r\n\u003c!-- 1. Install metrics server.\r\n\r\n    ```bash\r\n    kubectl apply -f \\\r\n      https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml\r\n    ``` --\u003e\r\n\r\n1. Create admin user.\r\n\r\n    ```bash\r\n    kubectl apply -f ./admin-user.yaml\r\n    ```\r\n\r\n1. Get the access token. Take note the access token to access the dashboard.\r\n\r\n    ```bash\r\n    # Bash\r\n    kubectl get secret admin-user \\\r\n        -n kubernetes-dashboard \\\r\n        -o jsonpath={\".data.token\"} | base64 -d\r\n\r\n    # PowerShell\r\n    kubectl get secret admin-user `\r\n        -n kubernetes-dashboard `\r\n        -o jsonpath='{ .data.token }' | `\r\n        % { [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($_)) }\r\n    ```\r\n\r\n1. Run the proxy server.\r\n\r\n    ```bash\r\n    kubectl proxy\r\n    ```\r\n\r\n1. Access the dashboard using the following URL:\r\n\r\n    ```text\r\n    http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/\r\n    ```\r\n\r\n1. Enter the access token to access the dashboard.\r\n\r\n### Use Helm Charts\r\n\r\n\u003e **Note:** From Kubernetes Dashboard v3.x, use [Helm Charts](https://artifacthub.io/packages/helm/k8s-dashboard/kubernetes-dashboard) approach.\r\n\r\n1. Install [Helm](https://helm.sh/docs/intro/install/).\r\n\r\n1. Run the following commands to install the Kubernetes Dashboard.\r\n\r\n    ```bash\r\n    # Add kubernetes-dashboard repository\r\n    helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/\r\n\r\n    # Deploy a Helm Release named \"kubernetes-dashboard\" using the kubernetes-dashboard chart\r\n    helm upgrade --install kubernetes-dashboard kubernetes-dashboard/kubernetes-dashboard --create-namespace --namespace kubernetes-dashboard\r\n    ```\r\n\r\n1. Create admin user.\r\n\r\n    ```bash\r\n    kubectl apply -f ./admin-user.yaml\r\n    ```\r\n\r\n1. Get the access token. Take note the access token to access the dashboard.\r\n\r\n    ```bash\r\n    # Bash\r\n    kubectl get secret admin-user \\\r\n        -n kubernetes-dashboard \\\r\n        -o jsonpath={\".data.token\"} | base64 -d\r\n\r\n    # PowerShell\r\n    kubectl get secret admin-user `\r\n        -n kubernetes-dashboard `\r\n        -o jsonpath='{ .data.token }' | `\r\n        % { [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($_)) }\r\n    ```\r\n\r\n1. Run the proxy server.\r\n\r\n    ```bash\r\n    kubectl -n kubernetes-dashboard port-forward svc/kubernetes-dashboard-kong-proxy 8443:443\r\n    ```\r\n\r\n1. Access the dashboard using the following URL:\r\n\r\n    ```text\r\n    https://localhost:8443\r\n    ```\r\n\r\n1. Enter the access token to access the dashboard.\r\n\r\n\u003c!-- ## MicroK8s Setup\r\n\r\nTBD --\u003e\r\n\r\n## Aspire-flavoured App Build\r\n\r\n1. Install .NET Aspire workload.\r\n\r\n    ```bash\r\n    # Bash\r\n    sudo dotnet workload update \u0026\u0026 sudo dotnet workload install aspire\r\n\r\n    # PowerShell\r\n    dotnet workload update \u0026\u0026 dotnet workload install aspire\r\n    ```\r\n\r\n1. Create a new Aspire starter app.\r\n\r\n    ```bash\r\n    dotnet new aspire-starter -n Aspir8\r\n    ```\r\n\r\n1. Build the app.\r\n\r\n    ```bash\r\n    dotnet restore \u0026\u0026 dotnet build\r\n    ```\r\n\r\n1. Run the app locally.\r\n\r\n    ```bash\r\n    dotnet run --project Aspir8.AppHost\r\n    ```\r\n\r\n1. Open the app in a browser, and go to the weather page to see whether the API is working or not. The port number might be different from the example below.\r\n\r\n    ```text\r\n    http://localhost:17008\r\n    ```\r\n\r\n## Aspire-flavoured App Deployment to Kubernetes Cluster through Aspir8\r\n\r\n### Use local container registry\r\n\r\n1. Install [Distribution (formerly known as Registry)](https://github.com/distribution/distribution) as a local Docker Hub (Container Registry).\r\n\r\n    ```bash\r\n    docker run -d -p 6000:5000 --name registry registry:latest\r\n    ```\r\n\r\n   \u003e **Note:** The port number of `6000` is just an arbitrary number. You can choose your own one.\r\n\r\n1. Install [Aspir8](https://github.com/prom3theu5/aspirational-manifests).\r\n\r\n    ```bash\r\n    dotnet tool install -g aspirate\r\n    ```\r\n\r\n1. Initialise Aspir8.\r\n\r\n    ```bash\r\n    cd Aspir8.AppHost\r\n    aspirate init -cr localhost:6000 -ct latest --disable-secrets true --non-interactive\r\n    ```\r\n\r\n1. Build and publish the app to the local container registry.\r\n\r\n    ```bash\r\n    aspirate generate --image-pull-policy Always --include-dashboard true --disable-secrets true --non-interactive\r\n    ```\r\n\r\n1. Deploy the app to the Kubernetes cluster.\r\n\r\n    ```bash\r\n    aspirate apply -k docker-desktop --non-interactive\r\n    ```\r\n\r\n1. Check the services in the Kubernetes cluster.\r\n\r\n    ```bash\r\n    kubectl get services\r\n    ```\r\n\r\n1. Install a load balancer for `webfrontend` to the local Kubernetes cluster.\r\n\r\n    ```bash\r\n    kubectl apply -f ../load-balancer.yaml\r\n    ```\r\n\r\n1. Install a load balancer for `aspire-dashboard` to the local Kubernetes cluster.\r\n\r\n    ```bash\r\n    kubectl apply -f ../aspire-dashboard.yaml\r\n    ```\r\n\r\n1. Open the app in a browser, and go to the dashboard page to see the logs\r\n\r\n    ```text\r\n    http://localhost:18888\r\n    ```\r\n\r\n1. Open the app in a browser, and go to the weather page to see whether the API is working or not.\r\n\r\n    ```text\r\n    http://localhost/weather\r\n    ```\r\n\r\n### Use Azure Kubernetes Services (AKS)\r\n\r\n\u003e **Note:** It uses [Azure CLI](https://learn.microsoft.com/cli/azure/what-is-azure-cli), which is the imperative approach. The declarative approach using Bicep is TBD.\r\n\r\n1. Set environment variables. Make sure that you use the closest or preferred location for provisioning resources (eg. `koreacentral`).\r\n\r\n    ```bash\r\n    # Bash\r\n    export AZURE_ENV_NAME=\"aspir8$RANDOM\"\r\n    export AZ_RESOURCE_GROUP=rg-$AZURE_ENV_NAME\r\n    export AZ_NODE_RESOURCE_GROUP=rg-$AZURE_ENV_NAME-mc\r\n    export AZ_LOCATION=koreacentral\r\n    export ACR_NAME=acr$AZURE_ENV_NAME\r\n    export AKS_CLUSTER_NAME=aks-$AZURE_ENV_NAME\r\n\r\n    # PowerShell\r\n    $AZURE_ENV_NAME = \"aspir8$(Get-Random -Minimum 1000 -Maximum 9999)\"\r\n    $AZ_RESOURCE_GROUP = \"rg-$AZURE_ENV_NAME\"\r\n    $AZ_NODE_RESOURCE_GROUP = \"rg-$AZURE_ENV_NAME-mc\"\r\n    $AZ_LOCATION = \"koreacentral\"\r\n    $ACR_NAME = \"acr$AZURE_ENV_NAME\"\r\n    $AKS_CLUSTER_NAME = \"aks-$AZURE_ENV_NAME\"\r\n    ```\r\n\r\n1. Create a resource group.\r\n\r\n    ```bash\r\n    az group create -n $AZ_RESOURCE_GROUP -l $AZ_LOCATION\r\n    ```\r\n\r\n1. Create an [Azure Container Registry (ACR)](https://learn.microsoft.com/azure/container-registry/container-registry-intro).\r\n\r\n    ```bash\r\n    # Bash\r\n    az acr create \\\r\n        -g $AZ_RESOURCE_GROUP \\\r\n        -n $ACR_NAME \\\r\n        -l $AZ_LOCATION \\\r\n        --sku Basic \\\r\n        --admin-enabled true\r\n\r\n    # PowerShell\r\n    az acr create `\r\n        -g $AZ_RESOURCE_GROUP `\r\n        -n $ACR_NAME `\r\n        -l $AZ_LOCATION `\r\n        --sku Basic `\r\n        --admin-enabled true\r\n    ```\r\n\r\n1. Get ACR credentials.\r\n\r\n    ```bash\r\n    # Bash\r\n    export ACR_LOGIN_SERVER=$(az acr show \\\r\n        -g $AZ_RESOURCE_GROUP \\\r\n        -n $ACR_NAME \\\r\n        --query \"loginServer\" -o tsv)\r\n    export ACR_USERNAME=$(az acr credential show \\\r\n        -g $AZ_RESOURCE_GROUP \\\r\n        -n $ACR_NAME \\\r\n        --query \"username\" -o tsv)\r\n    export ACR_PASSWORD=$(az acr credential show \\\r\n        -g $AZ_RESOURCE_GROUP \\\r\n        -n $ACR_NAME \\\r\n        --query \"passwords[0].value\" -o tsv)\r\n\r\n    # PowerShell\r\n    $ACR_LOGIN_SERVER = $(az acr show `\r\n        -g $AZ_RESOURCE_GROUP `\r\n        -n $ACR_NAME `\r\n        --query \"loginServer\" -o tsv)\r\n    $ACR_USERNAME = $(az acr credential show `\r\n        -g $AZ_RESOURCE_GROUP `\r\n        -n $ACR_NAME `\r\n        --query \"username\" -o tsv)\r\n    $ACR_PASSWORD = $(az acr credential show `\r\n        -g $AZ_RESOURCE_GROUP `\r\n        -n $ACR_NAME `\r\n        --query \"passwords[0].value\" -o tsv)\r\n    ```\r\n\r\n1. Create an [AKS](https://learn.microsoft.com/azure/aks/intro-kubernetes) cluster.\r\n\r\n   \u003e **Note:** Depending on the location you create the cluster, the VM size might vary.\r\n\r\n    ```bash\r\n    # Bash\r\n    az aks create \\\r\n        -g $AZ_RESOURCE_GROUP \\\r\n        -n $AKS_CLUSTER_NAME \\\r\n        -l $AZ_LOCATION \\\r\n        --node-resource-group $AZ_NODE_RESOURCE_GROUP \\\r\n        --node-vm-size Standard_B2s \\\r\n        --network-plugin azure \\\r\n        --generate-ssh-keys \\\r\n        --attach-acr $ACR_NAME\r\n\r\n    # PowerShell\r\n    az aks create `\r\n        -g $AZ_RESOURCE_GROUP `\r\n        -n $AKS_CLUSTER_NAME `\r\n        -l $AZ_LOCATION `\r\n        --node-resource-group $AZ_NODE_RESOURCE_GROUP `\r\n        --node-vm-size Standard_B2s `\r\n        --network-plugin azure `\r\n        --generate-ssh-keys `\r\n        --attach-acr $ACR_NAME\r\n    ```\r\n\r\n1. Connect to the AKS cluster.\r\n\r\n    ```bash\r\n    # Bash\r\n    az aks get-credentials \\\r\n        -g $AZ_RESOURCE_GROUP \\\r\n        -n $AKS_CLUSTER_NAME \\\r\n\r\n    # PowerShell\r\n    az aks get-credentials `\r\n        -g $AZ_RESOURCE_GROUP `\r\n        -n $AKS_CLUSTER_NAME `\r\n    ```\r\n\r\n1. Connect to ACR.\r\n\r\n   \u003e **Note:** This is the demo purpose only. You should manually enter username and password from your input.\r\n\r\n    ```bash\r\n    docker login $ACR_LOGIN_SERVER -u $ACR_USERNAME -p $ACR_PASSWORD\r\n    ```\r\n\r\n1. Install [Aspir8](https://github.com/prom3theu5/aspirational-manifests).\r\n\r\n    ```bash\r\n    dotnet tool install -g aspirate\r\n    ```\r\n\r\n1. Initialise Aspir8.\r\n\r\n    ```bash\r\n    cd Aspir8.AppHost\r\n    aspirate init -cr $ACR_LOGIN_SERVER -ct latest --non-interactive\r\n    ```\r\n\r\n   \u003e **Note:** If you are asked to enter or skip the repository prefix, enter `n` to skip it.\r\n\r\n1. Build and publish the app to ACR.\r\n\r\n    ```bash\r\n    aspirate generate --image-pull-policy IfNotPresent --non-interactive\r\n    ```\r\n\r\n1. Deploy the app to the AKS cluster.\r\n\r\n    ```bash\r\n    aspirate apply -k $AKS_CLUSTER_NAME --non-interactive\r\n    ```\r\n\r\n1. Install a load balancer to the AKS cluster.\r\n\r\n    ```bash\r\n    kubectl apply -f ../load-balancer.yaml\r\n    ```\r\n\r\n1. Confirm the `webfrontend-lb` service type is `LoadBalancer`, and note the external IP address of the `webfrontend-lb` service.\r\n\r\n    ```bash\r\n    kubectl get services\r\n    ```\r\n\r\n1. Open the app in a browser, and go to the weather page to see whether the API is working or not.\r\n\r\n    ```text\r\n    http://\u003cEXTERNAL_IP_ADDRESS\u003e\r\n    ```\r\n\r\n1. Once you are done, delete the entire resources from Azure.\r\n\r\n    ```bash\r\n    az group delete -n $AZ_RESOURCE_GROUP -f Microsoft.Compute/virtualMachineScaleSets -y --no-wait\r\n    ```\r\n\r\n### Use Amazon Elastic Kubernetes Service (EKS)\r\n\r\n\u003e **Note:**\r\n\u003e \r\n\u003e - It uses both [AWS Console](https://console.aws.amazon.com/) and [AWS CLI](https://aws.amazon.com/cli/) to provision resources to AWS.\r\n\u003e - It uses the Root account for this demo purpose only. You should use the IAM user with the least privilege.\r\n\r\n1. Set environment variables. Make sure that you use the closest or preferred location for provisioning resources (eg. `ap-northeast-2`).\r\n\r\n    ```bash\r\n    # Bash\r\n    export AWS_ENV_NAME=\"aspir8$RANDOM\"\r\n    export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query \"Account\" --output text)\r\n    export AWS_LOCATION=ap-northeast-2 # Seoul\r\n    export ECR_LOGIN_SERVER=$AWS_ACCOUNT_ID.dkr.ecr.AWS_LOCATION.amazonaws.com\r\n    export EKS_STACK_NAME=aspir8-stack\r\n    export EKS_CLUSTER_NAME=eks-$AWS_ENV_NAME\r\n    export EKS_NODE_GROUP_NAME=aspir8-nodegroup\r\n\r\n    # PowerShell\r\n    $AWS_ENV_NAME = \"aspir8$(Get-Random -Minimum 1000 -Maximum 9999)\"\r\n    $AWS_ACCOUNT_ID = $(aws sts get-caller-identity --query \"Account\" --output text)\r\n    $AWS_LOCATION = \"ap-northeast-2\" # Seoul\r\n    $ECR_LOGIN_SERVER = \"$($AWS_ACCOUNT_ID).dkr.ecr.$($AWS_LOCATION).amazonaws.com\"\r\n    $EKS_STACK_NAME = \"aspir8-stack\"\r\n    $EKS_CLUSTER_NAME = \"eks-$AWS_ENV_NAME\"\r\n    $EKS_NODE_GROUP_NAME = \"aspir8-nodegroup\"\r\n    ```\r\n\r\n1. Create a VPC stack for EKS.\r\n\r\n    ```bash\r\n    # Bash\r\n    aws cloudformation create-stack \\\r\n        --region $AWS_LOCATION \\\r\n        --stack-name $EKS_STACK_NAME \\\r\n        --template-url https://s3.us-west-2.amazonaws.com/amazon-eks/cloudformation/2020-10-29/amazon-eks-vpc-private-subnets.yaml\r\n    \r\n    # PowerShell\r\n    aws cloudformation create-stack `\r\n        --region $AWS_LOCATION `\r\n        --stack-name $EKS_STACK_NAME `\r\n        --template-url https://s3.us-west-2.amazonaws.com/amazon-eks/cloudformation/2020-10-29/amazon-eks-vpc-private-subnets.yaml\r\n    ```\r\n\r\n1. Create an EKS cluster role and attach it to the policy.\r\n\r\n    ```bash\r\n    # Bash\r\n    aws iam create-role \\\r\n        --role-name Aspir8AmazonEKSClusterRole \\\r\n        --assume-role-policy-document file://\"eks-cluster-role-trust-policy.json\"\r\n    aws iam attach-role-policy \\\r\n        --policy-arn arn:aws:iam::aws:policy/AmazonEKSClusterPolicy \\\r\n        --role-name Aspir8AmazonEKSClusterRole\r\n    \r\n    # PowerShell\r\n    aws iam create-role `\r\n        --role-name Aspir8AmazonEKSClusterRole `\r\n        --assume-role-policy-document file://\"eks-cluster-role-trust-policy.json\"\r\n    aws iam attach-role-policy `\r\n        --policy-arn arn:aws:iam::aws:policy/AmazonEKSClusterPolicy `\r\n        --role-name Aspir8AmazonEKSClusterRole\r\n    ```\r\n\r\n1. Create an EKS cluster node role and attach it to the policies.\r\n\r\n    ```bash\r\n    # Bash\r\n    aws iam create-role \\\r\n        --role-name Aspir8AmazonEKSNodeRole \\\r\n        --assume-role-policy-document file://\"eks-node-role-trust-policy.json\"\r\n    aws iam attach-role-policy \\\r\n        --policy-arn arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy \\\r\n        --role-name Aspir8AmazonEKSNodeRole\r\n    aws iam attach-role-policy \\\r\n        --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly \\\r\n        --role-name Aspir8AmazonEKSNodeRole\r\n    aws iam attach-role-policy \\\r\n        --policy-arn arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy \\\r\n        --role-name Aspir8AmazonEKSNodeRole\r\n    \r\n    # PowerShell\r\n    aws iam create-role `\r\n        --role-name Aspir8AmazonEKSNodeRole `\r\n        --assume-role-policy-document file://\"eks-node-role-trust-policy.json\"\r\n    aws iam attach-role-policy `\r\n        --policy-arn arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy `\r\n        --role-name Aspir8AmazonEKSNodeRole\r\n    aws iam attach-role-policy `\r\n        --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly `\r\n        --role-name Aspir8AmazonEKSNodeRole\r\n    aws iam attach-role-policy `\r\n        --policy-arn arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy `\r\n        --role-name Aspir8AmazonEKSNodeRole\r\n    ```\r\n\r\n1. Create an EKS cluster by following this [document](https://docs.aws.amazon.com/eks/latest/userguide/getting-started-console.html#eks-create-cluster).\r\n\r\n1. Create an EKS cluster nodes by following this [document](https://docs.aws.amazon.com/eks/latest/userguide/getting-started-console.html#eks-launch-workers).\r\n\r\n1. Connect to the EKS cluster.\r\n\r\n    ```bash\r\n    aws eks update-kubeconfig --name $EKS_CLUSTER_NAME --region $AWS_LOCATION\r\n    ```\r\n\r\n1. Connect to ECR.\r\n\r\n    ```bash\r\n    aws ecr get-login-password --region $AWS_LOCATION | docker login --username AWS --password-stdin $ECR_LOGIN_SERVER\r\n    ```\r\n\r\n1. Create repositories in ECR.\r\n\r\n    ```bash\r\n    aws ecr create-repository --repository-name apiservice --region $AWS_LOCATION\r\n    aws ecr create-repository --repository-name webfrontend --region $AWS_LOCATION\r\n    ```\r\n\r\n1. Install [Aspir8](https://github.com/prom3theu5/aspirational-manifests).\r\n\r\n    ```bash\r\n    dotnet tool install -g aspirate\r\n    ```\r\n\r\n1. Initialise Aspir8.\r\n\r\n    ```bash\r\n    cd Aspir8.AppHost\r\n    aspirate init -cr $ECR_LOGIN_SERVER -ct latest --non-interactive\r\n    ```\r\n\r\n   \u003e **Note:** If you are asked to enter or skip the repository prefix, enter `n` to skip it.\r\n\r\n1. Build and publish the app to ECR.\r\n\r\n    ```bash\r\n    aspirate generate --image-pull-policy IfNotPresent --non-interactive\r\n    ```\r\n\r\n1. Deploy the app to the EKS cluster.\r\n\r\n    ```bash\r\n    aspirate apply -k $EKS_CLUSTER_NAME --non-interactive\r\n    ```\r\n\r\n1. Install a load balancer to the EKS cluster.\r\n\r\n    ```bash\r\n    kubectl apply -f ../load-balancer.yaml\r\n    ```\r\n\r\n1. Confirm the `webfrontend-lb` service type is `LoadBalancer`, and note the URL under the external IP address column of the `webfrontend-lb` service.\r\n\r\n    ```bash\r\n    kubectl get services\r\n    ```\r\n\r\n1. Open the app in a browser, and go to the weather page to see whether the API is working or not.\r\n\r\n    ```text\r\n    http://\u003cxxxx.ap-northeast-2.elb.amazonaws.com\u003e\r\n    ```\r\n\r\n1. Once you are done, delete the entire resources from AWS.\r\n\r\n    ```bash\r\n    # Delete EKS node group\r\n    aws eks delete-nodegroup --nodegroup-name $EKS_NODE_GROUP_NAME --cluster-name $EKS_CLUSTER_NAME\r\n\r\n    # Delete EKS cluster\r\n    aws eks delete-cluster --name $EKS_CLUSTER_NAME\r\n\r\n    # Delete ECR repositories\r\n    aws ecr delete-repository --repository-name apiservice --force --region $AWS_LOCATION\r\n    aws ecr delete-repository --repository-name webfrontend --force --region $AWS_LOCATION\r\n\r\n    # Delete CloudFormation stack\r\n    aws cloudformation delete-stack --stack-name $EKS_STACK_NAME\r\n    ```\r\n\r\n   \u003e **Note:**\r\n   \u003e \r\n   \u003e - Deleting the EKS node group takes 5-10 mins.\r\n   \u003e - Only after the EKS node group is deleted, the EKS cluster can be deleted.\r\n   \u003e - While deleting the CloudFormation stack, you might be failing the deletion process. It's highly likely because of Elastic Load Balancer. Go to [EC2 Dashboard](https://ap-northeast-2.console.aws.amazon.com/ec2/home), and delete the existing load balancer instance first.\r\n\r\n### Use Google Kubernetes Engine (GKE)\r\n\r\nTBD\r\n\r\n### Use NHN Kubernetes Services (NKS)\r\n\r\n\u003e **Note:**\r\n\u003e \r\n\u003e - It uses [NHN Cloud Console](https://console.nhncloud.com/) to manage NHN Kubernetes Service (NKS).\r\n\u003e - It uses [NHN Container Registry (NCR)](https://www.nhncloud.com/kr/service/container/nhn-container-registry-ncr) as the container registry.\r\n\r\n1. Add the following Docker Hub repository details to `Aspir8.ApiService/Aspir8.ApiService.csproj`.\r\n\r\n    ```xml\r\n    \u003cPropertyGroup\u003e\r\n      \u003cContainerRepository\u003e{{DOCKER_USERNAME}}/apiservice\u003c/ContainerRepository\u003e\r\n    \u003c/PropertyGroup\u003e\r\n    ```\r\n\r\n1. Add the following Docker Hub repository details to `Aspir8.Web/Aspir8.Web.csproj`.\r\n\r\n    ```xml\r\n    \u003cPropertyGroup\u003e\r\n      \u003cContainerRepository\u003e{{DOCKER_USERNAME}}/webfrontend\u003c/ContainerRepository\u003e\r\n    \u003c/PropertyGroup\u003e\r\n    ```\r\n\r\n1. Set environment variables.\r\n\r\n    ```bash\r\n    export NHN_ENV_NAME=\"aspir8$RANDOM\"\r\n    export NKS_CLUSTER_NAME=nks-$NHN_ENV_NAME\r\n    ```\r\n\r\n1. Create an NKS cluster from the console.\r\n1. Get the `kubeconfig` of the NKS cluster from the console.\r\n1. Connect to the NKS cluster using the `kubeconfig`.\r\n\r\n    ```bash\r\n    export KUBECONFIG=~/.kube/config:~/path/to/downloaded/kubeconfig\r\n    kubectl config view --merge --flatten \u003e ~/.kube/merged_kubeconfig\r\n    mv ~/.kube/config ~/.kube/config.bak\r\n    mv ~/.kube/merged_kubeconfig ~/.kube/config\r\n    ```\r\n\r\n1. Change the context to the NKS cluster.\r\n\r\n    ```bash\r\n    kubectl config use-context default\r\n    ```\r\n\r\n1. Connect to Docker Hub.\r\n\r\n   \u003e **Note:** This is the demo purpose only. You should manually enter username and password from your input.\r\n\r\n    ```bash\r\n    docker login registry.hub.docker.com -u \u003cDOCKER_USERNAME\u003e -p \u003cDOCKER_PASSWORD\u003e\r\n    ```\r\n\r\n1. Initialise Aspir8.\r\n\r\n    ```bash\r\n    cd Aspir8.AppHost\r\n    aspirate init -cr registry.hub.docker.com -ct latest --non-interactive\r\n    ```\r\n\r\n1. Build and publish the app to Docker Hub.\r\n\r\n    ```bash\r\n    aspirate generate --image-pull-policy IfNotPresent --non-interactive\r\n    ```\r\n\r\n1. Deploy the app to the NKS cluster.\r\n\r\n    ```bash\r\n    aspirate apply -k toast-$NKS_CLUSTER_NAME --non-interactive\r\n    ```\r\n\r\n1. Install a load balancer to the NKS cluster.\r\n\r\n    ```bash\r\n    kubectl apply -f ./load-balancer.yaml\r\n    ```\r\n\r\n1. Confirm the `webfrontend` service type is `LoadBalancer`, and note the external IP address of the `webfrontend` service.\r\n\r\n    ```bash\r\n    kubectl get services\r\n    ```\r\n\r\n1. Open the app in a browser, and go to the weather page to see whether the API is working or not.\r\n\r\n    ```text\r\n    http://\u003cEXTERNAL_IP_ADDRESS\u003e\r\n    ```\r\n\r\n1. Once you are done, delete the entire resources from the console and container images from Docker Hub.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevkimchi%2Faspir8-from-scratch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevkimchi%2Faspir8-from-scratch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevkimchi%2Faspir8-from-scratch/lists"}