Skip to content

Commit e9dc58a

Browse files
kkrishTalianhaopre-commit-ci[bot]poussa
authored
Azure automated deployment for OPEA applications - Infosys (#629)
* CI: dump all containers' log for chart test (#627) Signed-off-by: Lianhao Lu <lianhao.lu@intel.com> Signed-off-by: kkrishTa <Kamalakara_T@infosys.com> * AKS Deployment for OPEA applications Signed-off-by: kkrishTa <Kamalakara_T@infosys.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Signed-off-by: kkrishTa <Kamalakara_T@infosys.com> * Reverted changes by pre commit hook. Updated readme as per suggestions Signed-off-by: kkrishTa <Kamalakara_T@infosys.com> * Adding code spell ignore for Azure Kubernetes Service Signed-off-by: kkrishTa <Kamalakara_T@infosys.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Signed-off-by: kkrishTa <Kamalakara_T@infosys.com> * Adding code spell ignore for AKS and reverting pre commit changes Signed-off-by: kkrishTa <Kamalakara_T@infosys.com> * Updating cluster name to opea as a generic name Signed-off-by: kkrishTa <Kamalakara_T@infosys.com> * helm chart: Add service account support (#624) * helm: Add service account support in common services 1. Add service account creation support, disabled by default. 2. Add support of sharing the same service account by setting global.sharedSAName, disabled by default. Signed-off-by: Lianhao Lu <lianhao.lu@intel.com> * helm: Add service account support in e2e charts 1. Add service account creation support, enabled by default. 2. Add support of sharing the same service account by setting global.sharedSAName, enabled by default. Signed-off-by: Lianhao Lu <lianhao.lu@intel.com> --------- Signed-off-by: Lianhao Lu <lianhao.lu@intel.com> Signed-off-by: kkrishTa <Kamalakara_T@infosys.com> * README: add links to terraform docs (#633) * README: add links to terraform docs Signed-off-by: Sakari Poussa <sakari.poussa@intel.com> * README: fix broken links Signed-off-by: Sakari Poussa <sakari.poussa@intel.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Signed-off-by: Sakari Poussa <sakari.poussa@intel.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Signed-off-by: kkrishTa <Kamalakara_T@infosys.com> * Adding link to the Azure terraform readme to opea documentation Signed-off-by: kkrishTa <Kamalakara_T@infosys.com> * Corrected md file link Signed-off-by: kkrishTa <Kamalakara_T@infosys.com> * Updated relative links Signed-off-by: kkrishTa <Kamalakara_T@infosys.com> --------- Signed-off-by: Lianhao Lu <lianhao.lu@intel.com> Signed-off-by: kkrishTa <Kamalakara_T@infosys.com> Signed-off-by: Sakari Poussa <sakari.poussa@intel.com> Co-authored-by: Lianhao Lu <lianhao.lu@intel.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Sakari Poussa <sakari.poussa@intel.com>
1 parent 7a26d06 commit e9dc58a

9 files changed

Lines changed: 345 additions & 3 deletions

File tree

.github/code_spell_ignore.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
aks
2+
AKS

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,21 +47,22 @@ The following steps are optional. They're only required if you want to run the w
4747

4848
### Use GenAI Microservices Connector (GMC) to deploy and adjust GenAIExamples
4949

50-
Follow [GMC README](https://github.com/opea-project/GenAIInfra/blob/main/microservices-connector/README.md)
50+
Follow [GMC README](microservices-connector/README.md)
5151
to install GMC into your kubernetes cluster. [GenAIExamples](https://github.com/opea-project/GenAIExamples) contains several sample GenAI example use case pipelines such as ChatQnA, DocSum, etc.
5252
Once you have deployed GMC in your Kubernetes cluster, you can deploy any of the example pipelines by following its Readme file (e.g. [Docsum](https://github.com/opea-project/GenAIExamples/blob/main/DocSum/kubernetes/intel/README_gmc.md)).
5353

5454
### Use helm charts to deploy
5555

5656
To deploy GenAIExamples to Kubernetes using helm charts, you need [Helm](https://helm.sh/docs/intro/install/) installed on your machine.
5757

58-
For a detailed version, see [Deploy GenAIExample/GenAIComps using helm charts](https://github.com/opea-project/GenAIInfra/tree/main/helm-charts/README.md)
58+
For a detailed version, see [Deploy GenAIExample/GenAIComps using helm charts](helm-charts/README.md)
5959

6060
### Use terraform to deploy on cloud service providers
6161

6262
You can use [Terraform](https://www.terraform.io/) to create infrastructure to run OPEA applications on various cloud service provider (CSP) environments.
6363

64-
- [AWS/EKS: Create managed Kubernetes cluster on AWS for OPEA](https://github.com/opea-project/GenAIInfra/blob/main/cloud-service-provider/aws/eks/terraform/README.MD)
64+
- [AWS/EKS: Create managed Kubernetes cluster on AWS for OPEA](cloud-service-provider/aws/eks/terraform/README.MD)
65+
- [Azure/AKS: Create managed Kubernetes cluster on Azure for OPEA](cloud-service-provider/azure/aks/terraform/README.md)
6566

6667
## Additional Content
6768

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# OPEA applications Azure AKS deployment guide
2+
3+
This guide shows how to deploy OPEA applications on Azure Kubernetes Service (AKS) using Terraform.
4+
5+
## Prerequisites
6+
7+
- Access to Azure AKS
8+
- [Terraform](https://developer.hashicorp.com/terraform/tutorials/azure-get-started/install-cli), [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/) and [Helm](https://helm.sh/docs/helm/helm_install/) installed on your local machine.
9+
- Keep the Azure subscription handy and enter the subscription id when prompted during the terraform execution.
10+
11+
## Setup
12+
13+
The setup uses Terraform to create AKS cluster with the following properties:
14+
15+
- 1-node AKS cluster with 50 GB disk and `Standard_D32d_v5` SPOT (or standard based on the application variables) instance (16 vCPU and 32 GB memory)
16+
- Cluster autoscaling up to 10 nodes
17+
- Storage Class (SC) `azurefile-csi` and Persistent Volume Claim (PVC) `model-volume` for storing the model data
18+
19+
Initialize the Terraform environment.
20+
21+
```bash
22+
terraform init
23+
```
24+
25+
## AKS cluster
26+
27+
By default, 1-node cluster is created which is suitable for running the OPEA application. See `variables.tf` and `opea-<application-name>.tfvars` if you want to tune the cluster properties, e.g., number of nodes, instance types or disk size.
28+
29+
## Persistent Volume Claim
30+
31+
OPEA needs a volume where to store the model. For that we need to create Kubernetes Persistent Volume Claim (PVC). OPEA requires `ReadWriteMany` option since multiple pods needs access to the storage and they can be on different nodes. On AKS, only Azure File Service supports `ReadWriteMany`. Thus, each OPEA application below uses the file `aks-azfs-csi-pvc.yaml` to create PVC in its namespace.
32+
33+
## OPEA Applications
34+
35+
### ChatQnA
36+
37+
Use the commands below to create AKS cluster.
38+
User has to input their Azure subscription id while running the following commands when prompted.
39+
40+
```bash
41+
terraform plan --var-file opea-chatqna.tfvars -out opea-chatqna.plan
42+
terraform apply "opea-chatqna.plan"
43+
```
44+
45+
Once the cluster is ready, the kubeconfig file to access the new cluster is updated automatically. By default, the file is `~/.kube/config`.
46+
47+
Now you should have access to the cluster via the `kubectl` command.
48+
49+
Deploy ChatQnA Application with Helm
50+
51+
```bash
52+
helm install -n chatqna --create-namespace chatqna oci://ghcr.io/opea-project/charts/chatqna --set service.type=LoadBalancer --set global.modelUsePVC=model-volume --set global.HUGGINGFACEHUB_API_TOKEN=${HFTOKEN}
53+
```
54+
55+
Create the PVC as mentioned [above](#-persistent-volume-claim)
56+
57+
```bash
58+
kubectl apply -f aks-azfs-csi-pvc.yaml -n chatqna
59+
```
60+
61+
After a while, the OPEA application should be running. You can check the status via `kubectl`.
62+
63+
```bash
64+
kubectl get pod -n chatqna
65+
```
66+
67+
Ensure that all pods are running.
68+
You can now start using the OPEA application.
69+
70+
```bash
71+
OPEA_SERVICE=$(kubectl get svc -n chatqna chatqna -ojsonpath='{.status.loadBalancer.ingress[0].hostname}')
72+
curl http://${OPEA_SERVICE}:8888/v1/chatqna \
73+
-H "Content-Type: application/json" \
74+
-d '{"messages": "What is the revenue of Nike in 2023?"}'
75+
```
76+
77+
Cleanup
78+
79+
Delete the cluster via the following command. User has to input their Azure subscription id while running the following commands when prompted.
80+
81+
```bash
82+
helm uninstall -n chatqna chatqna
83+
terraform destroy -var-file opea-chatqna.tfvars
84+
```
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Copyright (C) 2024 Intel Corporation
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
apiVersion: v1
5+
kind: PersistentVolumeClaim
6+
metadata:
7+
name: model-volume
8+
spec:
9+
accessModes:
10+
- ReadWriteMany
11+
storageClassName: azurefile-csi
12+
resources:
13+
requests:
14+
storage: 100Gi
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
provider "kubernetes" {
2+
config_path = "~/.kube/config"
3+
}
4+
5+
# Resource Group
6+
resource "azurerm_resource_group" "main" {
7+
name = "${var.cluster_name}-rg"
8+
location = var.location
9+
}
10+
11+
# Virtual Network
12+
module "vnet" {
13+
source = "Azure/vnet/azurerm"
14+
resource_group_name = azurerm_resource_group.main.name
15+
vnet_name = "${var.cluster_name}-vnet"
16+
vnet_location = azurerm_resource_group.main.location
17+
18+
tags = {
19+
environment = "dev"
20+
}
21+
depends_on = [azurerm_resource_group.main]
22+
}
23+
24+
# AKS Cluster
25+
resource "azurerm_kubernetes_cluster" "main" {
26+
name = var.cluster_name
27+
location = azurerm_resource_group.main.location
28+
resource_group_name = azurerm_resource_group.main.name
29+
dns_prefix = var.cluster_name
30+
kubernetes_version = var.cluster_version
31+
private_cluster_public_fqdn_enabled = true
32+
33+
default_node_pool {
34+
name = "default"
35+
auto_scaling_enabled = true
36+
node_count = var.node_count
37+
vm_size = var.instance_types[0]
38+
min_count = var.min_count
39+
max_count = var.max_count
40+
vnet_subnet_id = module.vnet.vnet_subnets[0]
41+
os_disk_size_gb = var.os_disk_size_gb
42+
}
43+
44+
identity {
45+
type = "SystemAssigned"
46+
}
47+
48+
network_profile {
49+
network_plugin = "azure"
50+
load_balancer_sku = "standard"
51+
service_cidr = "10.0.4.0/24"
52+
dns_service_ip = "10.0.4.10"
53+
}
54+
55+
}
56+
57+
# Azure Files Storage Account
58+
resource "azurerm_storage_account" "main" {
59+
name = replace(lower("${var.cluster_name}st"), "-", "")
60+
resource_group_name = azurerm_resource_group.main.name
61+
location = azurerm_resource_group.main.location
62+
account_tier = "Premium"
63+
account_replication_type = "LRS"
64+
account_kind = "FileStorage"
65+
}
66+
67+
# Azure Files Share
68+
resource "azurerm_storage_share" "main" {
69+
name = "aksshare"
70+
storage_account_id = azurerm_storage_account.main.id
71+
quota = 100
72+
}
73+
74+
# Key Vault
75+
resource "azurerm_key_vault" "main" {
76+
name = "${var.cluster_name}-kv"
77+
location = azurerm_resource_group.main.location
78+
resource_group_name = azurerm_resource_group.main.name
79+
tenant_id = data.azurerm_client_config.current.tenant_id
80+
sku_name = "standard"
81+
soft_delete_retention_days = 7
82+
purge_protection_enabled = false
83+
84+
access_policy {
85+
tenant_id = data.azurerm_client_config.current.tenant_id
86+
object_id = data.azurerm_client_config.current.object_id
87+
88+
key_permissions = [
89+
"Create",
90+
"Delete",
91+
"Get",
92+
"List",
93+
]
94+
95+
secret_permissions = [
96+
"Set",
97+
"Get",
98+
"Delete",
99+
"List",
100+
]
101+
}
102+
}
103+
104+
# Update kubeconfig
105+
resource "null_resource" "kubectl" {
106+
provisioner "local-exec" {
107+
command = "az aks get-credentials --resource-group ${azurerm_resource_group.main.name} --name ${azurerm_kubernetes_cluster.main.name} --overwrite-existing"
108+
}
109+
depends_on = [azurerm_kubernetes_cluster.main]
110+
}
111+
112+
# Data source for Azure subscription information
113+
data "azurerm_client_config" "current" {}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
cluster_name = "opea"
2+
instance_types = ["Standard_D32d_v5"]
3+
node_pool_type = "Spot" # cheaper
4+
os_disk_size_gb = 50
5+
location = "eastus"
6+
kubernetes_version = "1.30"
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
output "cluster_endpoint" {
2+
description = "Endpoint for AKS control plane"
3+
#sensitive = false
4+
sensitive = true
5+
value = azurerm_kubernetes_cluster.main.kube_config.0.host
6+
}
7+
8+
output "oidc_issuer_url" {
9+
description = "The URL for the OpenID Connect issuer"
10+
value = azurerm_kubernetes_cluster.main.oidc_issuer_url
11+
}
12+
13+
output "location" {
14+
description = "Azure region"
15+
value = var.location
16+
}
17+
18+
output "cluster_name" {
19+
description = "Kubernetes Cluster Name"
20+
value = azurerm_kubernetes_cluster.main.name
21+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
terraform {
2+
required_providers {
3+
azurerm = {
4+
source = "hashicorp/azurerm"
5+
version = "~> 4.0"
6+
}
7+
kubernetes = {
8+
source = "hashicorp/kubernetes"
9+
version = "2.33.0"
10+
}
11+
}
12+
}
13+
14+
# Azure provider configuration
15+
provider "azurerm" {
16+
features {}
17+
subscription_id = var.subscription_id
18+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
variable "location" {
2+
description = "Azure region"
3+
type = string
4+
default = "eastus"
5+
}
6+
7+
variable "cluster_name" {
8+
description = "AKS cluster name"
9+
type = string
10+
default = "opea aks cluster"
11+
}
12+
13+
variable "kubernetes_version" {
14+
description = "AKS cluster version"
15+
type = string
16+
default = "1.30"
17+
}
18+
19+
variable "use_custom_node_config" {
20+
description = "Enable custom node configuration"
21+
type = bool
22+
default = true
23+
}
24+
25+
variable "subscription_id" {
26+
description = "This is the Azure subscription id of the user"
27+
type = string
28+
}
29+
30+
variable "os_disk_size_gb" {
31+
description = "OS disk size in GB for nodes"
32+
type = number
33+
default = 50
34+
}
35+
36+
variable "node_pool_type" {
37+
description = "VM spot or on-demand instance types"
38+
type = string
39+
default = "Regular" # Regular for on-demand, Spot for spot instances
40+
}
41+
42+
variable "min_count" {
43+
description = "Minimum number of nodes"
44+
type = number
45+
default = 1
46+
}
47+
48+
variable "max_count" {
49+
description = "Maximum number of nodes"
50+
type = number
51+
default = 10
52+
}
53+
54+
variable "node_count" {
55+
description = "Desired number of nodes"
56+
type = number
57+
default = 1
58+
}
59+
60+
variable "resource_group_name" {
61+
description = "Name of the resource group"
62+
type = string
63+
default = null
64+
}
65+
66+
variable "vnet_subnet_id" {
67+
description = "ID of the subnet where the cluster will be deployed"
68+
type = string
69+
default = null
70+
}
71+
72+
73+
variable "cluster_version" {
74+
description = "Kubernetes version for the cluster"
75+
type = string
76+
default = "1.30"
77+
}
78+
79+
variable "instance_types" {
80+
description = "Azure VM instance type"
81+
type = list(string)
82+
default = ["Standard_D32d_v5"]
83+
}

0 commit comments

Comments
 (0)