Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iac #15

Merged
merged 3 commits into from
Jul 1, 2024
Merged

iac #15

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ Alice Retrieval-Augmented Generation (RAG) is a proof of concept application des

This project showcases my ability to implement advanced AI techniques, containerization, CI/CD, documentation, and web-based interaction using Streamlit, all while adhering to best practices in software development and deployment.

Alice RAG stands out by utilizing the LlamaIndex framework to create a vector database from Alice’s Adventures in Wonderland, enabling precise and contextually relevant responses to user queries. The code then employs Gemini models to generate answers based on the retrieved context. The solution is containerized using Docker, ensuring seamless deployment and scalability, and is designed to be cloud-ready, with optional Infrastructure as Code (IaC) scripts for Azure deployment. The project demonstrates a full-stack AI application reflecting my comprehensive skill set in AI engineering, DevOps, and cloud infrastructure management. Through this project, I aim to illustrate my capability to deliver robust, efficient, and user-friendly AI solutions in a professional setting.
![screnshot-alicerage](img/alicerag.png)
1 change: 1 addition & 0 deletions alice-rag-llm
Submodule alice-rag-llm added at 607457
67 changes: 67 additions & 0 deletions bicep/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
The `bicep/` folder contains the Infrastructure as Code (IaC) scripts needed to deploy the Alice RAG as an App Service in Azure. Below is an explanation of the initial requirements and the steps to set up the application.

While these steps would typically be integrated into the CI/CD pipeline, to avoid Gemini API and Azure costs, the `launch.sh` script must be executed manually.

1. Obtain an Azure account. New accounts receive a $200 credit and access to the free tier. For more details, visit [Azure](https://azure.microsoft.com/en-us/free).

2. Install the Azure CLI using [brew](https://brew.sh/) on macOS:

```shell
brew install az
```
or using your favorite Linux package manager.

3. Log in to Azure CLI: Open your terminal and log in to your Azure account using the Azure CLI.

```shell
az login
```
this will open a web browser where you can enter your Azure credentials.

4. Create a Resource Group where the resources will be deployed. Here the location is set to eastern USA.

```shell
# create resource group
az group create --location eastus --name demo-app
```

5. Create the container registry by executing the Bicep template from `bicep/infra/`.

```shell
# create container registry
az deployment group create \
--resource-group demo-app \
--template-file ./acr/main.bicep \
--parameters containerRegistryName=aliceragllm
```

6. Login to Azure Container Registry (ACR), to be able to push the Docker image.

```shell
az acr login -n aliceragllm
```

7. Build the image (or pull the latest from DockerHub) and push it to ACR.

```shell
# retrieve, tag, push the image
docker pull --platform linux/amd64 pmiron/alice-rag-llm:latest
docker tag pmiron/alice-rag-llm:latest aliceragllm.azurecr.io/alice-rag-llm:latest
docker push aliceragllm.azurecr.io/alice-rag-llm:latest
```

8. Finally, deploy the application by executing the Bicep template from `bicep/app/`. This will create the App Service, App Service Plan, and assign the role. *Note*: by default, the app is publicly accessible (`publicNetworkAccess: 'Enabled'`). To avoid extra costs, stop the App Service from the console when not in use.

```shell
# deploy app
az deployment group create \
--resource-group demo-app \
--template-file ./app/main.bicep \
--parameters \
appServiceName=alicerag \
containerRegistryName=aliceragllm \
dockerImageNameTag=alice-rag-llm:latest \
geminiAPI=$GEMINI_API_KEY
```

![screnshot-alicerag-azure](../img/alicerag-azure.png)
54 changes: 54 additions & 0 deletions bicep/app/appservice.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
param location string
param appServiceName string
param dockerImage string
param geminiAPI string
param streamlitPort string

resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = {
name: toLower('asp-${appServiceName}')
location: location
kind: 'linux'
sku: {
name: 'B1'
}
properties: {
reserved: true
}
}

resource appService 'Microsoft.Web/sites@2022-03-01' = {
name: appServiceName
location: location
kind: 'app,linux,container'
identity: {
type: 'SystemAssigned'
}
properties: {
serverFarmId: appServicePlan.id
// in practice it would use internal VPC
publicNetworkAccess: 'Enabled'
siteConfig: {
linuxFxVersion: 'DOCKER|${dockerImage}'
acrUseManagedIdentityCreds: true
appSettings: [
{
name: 'DOCKER_ENABLE_CI'
value: 'true'
}
// port forwarding
{
name: 'WEBSITES_PORT'
value: streamlitPort
}
// set Gemini environment key
{
name: 'GEMINI_API_TOKEN'
value: geminiAPI
}
]
}
}
}

output principalId string = appService.identity.principalId
output appServiceResourceName string = appService.name
27 changes: 27 additions & 0 deletions bicep/app/main.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
param location string = resourceGroup().location
param appServiceName string
param containerRegistryName string
param dockerImageNameTag string
param geminiAPI string
param streamlitPort string = "8501"

var dockerImage = '${containerRegistryName}.azurecr.io/${dockerImageNameTag}'

module appService 'appservice.bicep' = {
name: '${appServiceName}-app'
params: {
appServiceName: appServiceName
location: location
dockerImage: dockerImage
geminiAPI: geminiAPI
streamlitPort: streamlitPort
}
}

module roleAssignment 'roleassignment.bicep' = {
name: '${appServiceName}-roleassignment'
params: {
appServicePrincipalId: appService.outputs.principalId
containerRegistryName: containerRegistryName
}
}
19 changes: 19 additions & 0 deletions bicep/app/roleassignment.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
param containerRegistryName string
param appServicePrincipalId string

resource containerRegistry 'Microsoft.ContainerRegistry/registries@2021-09-01' existing = {
name: containerRegistryName
}

// acrPullDefinitionId is AcrPull: https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#acrpull
var acrPullDefinitionId = '7f951dda-4ed3-4680-a7ca-43fe172d538d'

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(containerRegistry.name, appServicePrincipalId, 'AcrPullSystemAssigned')
scope: containerRegistry
properties: {
principalId: appServicePrincipalId
principalType: 'ServicePrincipal'
roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', acrPullDefinitionId)
}
}
13 changes: 13 additions & 0 deletions bicep/infra/main.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
param containerRegistryName string
param location string = resourceGroup().location

resource containerRegistry 'Microsoft.ContainerRegistry/registries@2022-12-01' = {
name: containerRegistryName
location: location
sku: {
name: 'Basic'
}
properties: {
adminUserEnabled: true
}
}
38 changes: 38 additions & 0 deletions bicep/launch.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/bin/zsh
RESOURCE_GROUP="demo-app"
REGISTRY_NAME="aliceragllm"
DOCKERHUB="pmiron"
IMAGE="alice-rag-llm:latest"
APPSERVICE_NAME="alicerag"
LOCATION="eastus"

# login
az login

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

# create container registry
az deployment group create \
--resource-group $RESOURCE_GROUP \
--template-file ./infra/main.bicep \
--parameters containerRegistryName=$REGISTRY_NAME

# login to acr
az acr login -n $REGISTRY_NAME

# retrieve, tag, push the image
# in practice we would probably push after creating the image
docker pull --platform linux/amd64 $DOCKERHUB/$IMAGE
docker tag $DOCKERHUB/$IMAGE $REGISTRY_NAME.azurecr.io/$IMAGE
docker push $REGISTRY_NAME.azurecr.io/$IMAGE

# deploy app
az deployment group create \
--resource-group $RESOURCE_GROUP \
--template-file ./app/main.bicep \
--parameters \
appServiceName=$APPSERVICE_NAME \
containerRegistryName=$REGISTRY_NAME \
dockerImageNameTag=$IMAGE \
geminiAPI=$GEMINI_API_KEY
4 changes: 2 additions & 2 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Follow these steps to run the container locally and interact with the Alice RAG
- Ensure you have a valid Gemini API token. This token is required to interact with the Gemini model and can be obtained on the Gemini API `website <https://ai.google.dev/pricing>`_ (free tier available).
- Use the following command to run the Docker container, which will expose the application on port 8501, set the `GEMINI_API_TOKEN` environment variable, and run the application on the local machine. Note that in a real-world scenario, this token would be stored securely in a secret management system, but since the image is freely available on DockerHub for this POC, it is passed as an environment variable.

>>> docker run -p 8501:8501 -e GEMINI_API_TOKEN="TOKEN_STRING" alice-rag-llm
>>> docker run -p 8501:8501 -e GEMINI_API_TOKEN="SECRET_TOKEN" alice-rag-llm

The application will be accessible locally at `http://0.0.0.0:8501 <http://0.0.0.0:8501>`_.

Expand All @@ -35,6 +35,6 @@ Running from DockerHub

The container is also available on DockerHub at `pmiron/alice-rag-llm <https://hub.docker.com/repository/docker/pmiron/alice-rag-llm/general>`_. Similarly, you can pull the image from the repository and run it directly on your local machine.

>>> docker run -p 8501:8501 -e GEMINI_API_TOKEN="TOKEN_STRING" pmiron/alice-rag-llm:latest
>>> docker run -p 8501:8501 -e GEMINI_API_TOKEN="SECRET_TOKEN" pmiron/alice-rag-llm:latest

Note: For optimal performance, the application is available for both `linux/amd64` and `linux/arm64` architectures.
Binary file added img/alicerag-azure.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/alicerag.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading