Skip to content

Publish image for 05-assistive-chatbot #76

Publish image for 05-assistive-chatbot

Publish image for 05-assistive-chatbot #76

Workflow file for this run

name: "Build and push Docker image"
run-name: "Publish image for ${{inputs.dockerfile_folder}}"
on:
workflow_dispatch:
inputs:
dockerfile_folder:
description: 'Folder containing Dockerfile to build'
required: true
type: choice
options:
- '05-assistive-chatbot'
- '02-household-queries'
subdomain:
description: 'Subdomain of navalabs.co'
type: choice
required: true
default: 'chat'
options:
- 'chat'
- 'chatbot'
- 'chatbdt'
- 'chat-bdt'
- 'bdtbot'
- 'bdt-bot'
- 'bdt-chat'
- 'bdt-chatbot'
- 'chatbot-prototype'
- 'chat.zone'
service_name:
description: 'Name of target service. Leave blank if unsure'
type: choice
default: ''
options:
- ''
- 'container-service-3'
- 'container-service-2'
- 'chatbot-chainlit-svc'
- 'secure-chatbot-svc'
build_image:
description: "Build and push image"
required: true
type: boolean
default: 'true'
deploy_image:
description: "Deploy image"
required: true
type: boolean
default: 'true'
# image_tag:
# description: 'Tag/Version of the image to push'
# required: true
# type: string
# default: '0.06'
create_new_svc:
description: "Create new Lightsail service"
required: true
type: boolean
default: 'false'
delete_images:
description: 'Delete previous images associated with service'
required: true
type: boolean
default: 'false'
env:
AWS_REGION: us-east-1
IMAGE_NAME: localimage
jobs:
publish-image:
runs-on: ubuntu-latest
steps:
- name: Check inputs
id: check_inputs
run: |
service_name="${{ inputs.subdomain }}-svc"
# if [ "${service_name}" = "" ]; then
# case "${{ inputs.dockerfile_folder }}" in
# '02-household-queries') service_name='secure-chatbot-svc';;
# '05-assistive-chatbot') service_name='chatbot-chainlit-svc';;
# *) exit 1;;
# esac
# fi
echo "service_name=$service_name" >> $GITHUB_OUTPUT
if [ ${{ inputs.create_new_svc }} == 'false' ]; then
echo "Since not creating new service, checking if service '$service_name' exists"
aws lightsail get-container-services --service-name "$service_name"
fi
# image_tag="${{ inputs.image_tag }}"
# if [ "${image_tag}" = "" ]; then
# case "${service_name}" in
# # The image_tag is specific to the `*-svc` service
# 'secure-chatbot-svc') image_tag='0.01';;
# 'chatbot-chainlit-svc') image_tag='chatbot-chainlit';;
# container-service-*) image_tag='not-used';;
# *) echo "Unknown service_name: '${service_name}'"; exit 3;;
# esac
# fi
# echo "image_tag=$image_tag" >> $GITHUB_OUTPUT
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ env.AWS_REGION }}
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
mask-aws-account-id: true
# TODO: secure credentials: https://github.com/aws-actions/amazon-ecr-login?tab=readme-ov-file#ecr-private
# https://github.com/docker/login-action?tab=readme-ov-file#aws-elastic-container-registry-ecr
# https://medium.com/@lukhee/automating-aws-lightsail-deployments-with-github-actions-53c73c9a1c1f
- name: "Upgrade AWS CLI version and setup lightsailctl"
run: |
# aws --version
# curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
# unzip awscliv2.zip
# sudo ./aws/install --bin-dir /usr/local/bin --install-dir /usr/local/aws-cli --update
# which aws
aws --version
sudo curl "https://s3.us-west-2.amazonaws.com/lightsailctl/latest/linux-amd64/lightsailctl" -o "/usr/local/bin/lightsailctl"
sudo chmod +x /usr/local/bin/lightsailctl
aws lightsail push-container-image help
- name: "Create new Lightsail container service"
if: inputs.create_new_svc
env:
FULL_DOMAIN: ${{ inputs.subdomain }}.navalabs.co
SERVICE_NAME: ${{ steps.check_inputs.outputs.service_name }}
run: |
# check if service already exists
if aws lightsail get-container-services --service-name "$SERVICE_NAME"; then
echo "Already exists!"
else
# `micro` power is needed for it's memory capacity; 60%+ memory is needed for the vector DB
aws lightsail create-container-service --service-name $SERVICE_NAME --power micro --scale 1 --public-domain-names navalabs-cert=$FULL_DOMAIN
# TODO: wait for service to be "READY" before updating container service
while true; do
sleep 15
SVC_STATE=$(aws lightsail get-container-services --service-name "$SERVICE_NAME" | jq -r '.containerServices[0].state')
echo "service state: $SVC_STATE"
if [ "$SVC_STATE" == "READY" ]; then
break
fi
done
SVC_URL=$(aws lightsail get-container-services --service-name "$SERVICE_NAME" | jq -r '.containerServices[0].url')
# Remove 'https://' prefix
TARGET_DOMAIN=${SVC_URL#https://}
# Remove '/' suffix
TARGET_DOMAIN=${TARGET_DOMAIN%/}
# If domain entry exists, delete it
OLD_TARGET=$(aws lightsail get-domain --domain-name navalabs.co | jq -r ".domain.domainEntries[] | select( .name == \"$FULL_DOMAIN\" ) | .target")
if [ "$OLD_TARGET" ] ; then
echo "Deleting existing '$FULL_DOMAIN' entry with target '$OLD_TARGET'"
aws lightsail delete-domain-entry --domain-name navalabs.co --domain-entry "type=A,isAlias=true,name=$FULL_DOMAIN,target=$OLD_TARGET"
fi
# Create DNS assignment by adding a domain entry
aws lightsail create-domain-entry --domain-name navalabs.co --domain-entry "type=A,isAlias=true,name=$FULL_DOMAIN,target=$TARGET_DOMAIN"
fi
- name: "Delete previous container images"
if: inputs.delete_images
env:
SERVICE_NAME: ${{ steps.check_inputs.outputs.service_name }}
run: |
AWS_IMAGES=$(aws lightsail get-container-images --region "$AWS_REGION" --service-name "$SERVICE_NAME" --output text)
IMAGE_NAMES=$(echo $AWS_IMAGES | grep -Eo ':"$SERVICE_NAME"\.${{ inputs.image-name }}\.[0-9]+')
echo $IMAGE_NAMES
FIRST=0
while read LINE; do
if [ "$FIRST" -ne 0 ]; then
aws lightsail delete-container-image --region "$AWS_REGION" --service-name "$SERVICE_NAME" --image $LINE;
fi
FIRST=1;
done <<< $IMAGE_NAMES
- name: "Login to Amazon ECR"
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
with:
mask-password: true
- name: "Checkout source code"
if: inputs.build_image
uses: actions/checkout@v4
- name: "Build image"
if: inputs.build_image
run: |
cd ${{ inputs.dockerfile_folder }}
# TODO: make this more easily editable and secure
# The DOT_ENV_FILE_CONTENTS contains LITERAL_API_KEY, OPENAI_API_KEY, RETRIEVE_K, LLM_MODEL_NAME, SUMMARIZER_LLM_MODEL_NAME
echo "${{secrets.DOT_ENV_FILE_CONTENTS}}" > .env
echo "BUILD_DATE=$(date +%Y-%m-%d-%T)" >> .env
echo "GIT_SHA=${{ github.sha }}" >> .env
docker build -t "$IMAGE_NAME" --build-arg GURU_CARDS_URL="https://docs.google.com/uc?export=download&id=${{ secrets.GURU_CARDS_URL_ID }}" .
- name: "Publish image to Lightsail"
if: inputs.build_image
id: pub_image_to_ls
env:
ECR_PATH: ${{ steps.login-ecr.outputs.registry }}/${{ secrets.ECR_REPO }}
SERVICE_NAME: ${{ steps.check_inputs.outputs.service_name }}
# IMAGE_TAG: ${{ steps.check_inputs.outputs.image_tag }}
# LABEL must match regex ^(?:[a-z0-9]{1,2}|[a-z0-9][a-z0-9-]+[a-z0-9])$
LABEL: git-push
IMAGE_SHA_TAG: ${{ github.sha }}
run: |
echo "# Publishing image for $SERVICE_NAME"
aws lightsail push-container-image --region $AWS_REGION --service-name "$SERVICE_NAME" --label "$LABEL" --image "$IMAGE_NAME"
LS_DOCKER_IMAGE=$(aws lightsail get-container-images --service-name "$SERVICE_NAME" | jq -r .containerImages[0].image)
echo "Image name: '$LS_DOCKER_IMAGE'"
echo "LS_DOCKER_IMAGE=$LS_DOCKER_IMAGE" >> $GITHUB_ENV
- name: Deploy container on AWS Lightsail
if: inputs.deploy_image
env:
SERVICE_NAME: ${{ steps.check_inputs.outputs.service_name }}
run: |
TEMPLATE='{
"serviceName": "$SERVICE_NAME",
"containers": {
"chatbot": {
"image": "$LS_DOCKER_IMAGE",
"command": [],
"environment": {
"ENV": "PROD",
"BUILD_DATE": "$BUILD_DATE"
},
"ports": {
"8000": "HTTP"
}
}
},
"publicEndpoint": {
"containerName": "chatbot",
"containerPort": 8000,
"healthCheck": {
"healthyThreshold": 2,
"unhealthyThreshold": 4,
"timeoutSeconds": 20,
"intervalSeconds": 60,
"path": "/healthcheck",
"successCodes": "200-499"
}
}
}'
echo "$TEMPLATE" | BUILD_DATE=$(date +%Y-%m-%d-%T%z) envsubst > config.json
cat config.json
aws lightsail create-container-service-deployment --cli-input-json file://config.json
# aws lightsail create-container-service-deployment --region ${{ inputs.aws-region }} --cli-input-json '${{ inputs.aws-lightsail-service-config }}' > /dev/null
# aws lightsail update-container-service --service-name "$SERVICE_NAME" --no-is-disabled
# TODO: Wait for deployment to complete
# TODO: warm up vector DB on startup
# - name: "Update AWS Service"
# if: inputs.deploy_image
# env:
# CLUSTER_NAME: genai-experiments
# run: |
# aws ecs update-service --force-new-deployment --cluster "$CLUSTER_NAME" --service "${{ steps.check_inputs.outputs.service_name }}"