Skip to content

Commit

Permalink
feat: helm chart (#240)
Browse files Browse the repository at this point in the history
Signed-off-by: Sertac Ozercan <sozercan@gmail.com>
  • Loading branch information
sozercan authored May 26, 2024
1 parent fac6b9e commit 2bb0f9e
Show file tree
Hide file tree
Showing 21 changed files with 853 additions and 108 deletions.
83 changes: 83 additions & 0 deletions .github/workflows/release-pr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: release-pr
on:
push:
tags:
- 'v[0-9]+.[0-9]+.0' # run this workflow when a new minor version is published
workflow_dispatch:
inputs:
release_version:
description: 'Which version are we creating a release pull request for?'
required: true

permissions:
contents: write
pull-requests: write

jobs:
create-release-pull-request:
runs-on: ubuntu-22.04
steps:
- name: Harden Runner
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
with:
egress-policy: audit

- name: Set release version and target branch for vNext
if: github.event_name == 'push'
run: |
TAG="$(echo "${{ github.ref }}" | tr -d 'refs/tags/v')"
MAJOR_VERSION="$(echo "${TAG}" | cut -d '.' -f1)"
echo "MAJOR_VERSION=${MAJOR_VERSION}" >> ${GITHUB_ENV}
MINOR_VERSION="$(echo "${TAG}" | cut -d '.' -f2)"
echo "MINOR_VERSION=${MINOR_VERSION}" >> ${GITHUB_ENV}
# increment the minor version by 1 for vNext
echo "NEWVERSION=v${MAJOR_VERSION}.$((MINOR_VERSION+1)).0-beta.0" >> ${GITHUB_ENV}
# pre-release is always being merged to the master branch
echo "TARGET_BRANCH=master" >> ${GITHUB_ENV}
echo "TAG=${TAG}" >> ${GITHUB_ENV}
- name: Set release version and target branch from input
if: github.event_name == 'workflow_dispatch'
run: |
NEWVERSION="${{ github.event.inputs.release_version }}"
echo "${NEWVERSION}" | grep -E '^v[0-9]+\.[0-9]+\.[0-9](-(beta|rc)\.[0-9]+)?$' || (echo "release_version should be in the format vX.Y.Z, vX.Y.Z-beta.A, or vX.Y.Z-rc.B" && exit 1)
echo "NEWVERSION=${NEWVERSION}" >> ${GITHUB_ENV}
echo "TAG=${NEWVERSION}" >> ${GITHUB_ENV}
MAJOR_VERSION="$(echo "${NEWVERSION}" | cut -d '.' -f1 | tr -d 'v')"
MINOR_VERSION="$(echo "${NEWVERSION}" | cut -d '.' -f2)"
# non-beta releases should always be merged to release branches
echo "TARGET_BRANCH=release-${MAJOR_VERSION}.${MINOR_VERSION}" >> ${GITHUB_ENV}
# beta releases should always be merged to master
if [[ "${NEWVERSION}" =~ "beta" ]]; then
echo "TARGET_BRANCH=master" >> ${GITHUB_ENV}
fi
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633
with:
fetch-depth: 0

- name: Create release branch if needed
run: |
git checkout "${TARGET_BRANCH}" && exit 0
# Create and push release branch if it doesn't exist
git checkout -b "${TARGET_BRANCH}"
git push --set-upstream origin "${TARGET_BRANCH}"
- run: make release-manifest

- name: Create release pull request
uses: peter-evans/create-pull-request@70a41aba780001da0a30141984ae2a0c95d8704e # v6.0.2
with:
commit-message: "chore: Prepare ${{ env.NEWVERSION }} release"
title: "chore: Prepare ${{ env.NEWVERSION }} release"
branch: "release-${{ env.NEWVERSION }}"
base: "${{ env.TARGET_BRANCH }}"
signoff: true
labels: |
release-pr
${{ github.event.inputs.release_version }}
8 changes: 8 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,11 @@ jobs:
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
prerelease: false

- name: Publish Helm chart
uses: stefanprodan/helm-gh-pages@0ad2bb377311d61ac04ad9eb6f252fb68e207260 # v1.7.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
charts_dir: charts
target_dir: charts
linting: off
1 change: 0 additions & 1 deletion .github/workflows/test-docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ jobs:
deb.debian.org:80
nightly.link:443
developer.download.nvidia.com:443
pci-ids.ucw.cz:443
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6

Expand Down
129 changes: 129 additions & 0 deletions .github/workflows/test-helm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
name: helm-test

on:
push:
branches:
- main
paths-ignore:
- '**.md'
- 'website/**'
pull_request:
branches:
- main
paths-ignore:
- '**.md'
- 'website/**'

permissions: read-all

jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 240
steps:
- uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1
with:
tool-cache: true
android: true
dotnet: true
haskell: true
large-packages: true
docker-images: true
swap-storage: true

- name: Harden Runner
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: block
allowed-endpoints: >
auth.docker.io:443
*.huggingface.co:443
cdn.dl.k8s.io:443
dl.k8s.io:443
download.docker.com:443
gcr.io:443
github.com:443
huggingface.co:443
*.githubusercontent.com:443
production.cloudflare.docker.com:443
proxy.golang.org:443
registry-1.docker.io:443
storage.googleapis.com:443
deb.debian.org:80
developer.download.nvidia.com:443
get.helm.sh:443
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5

# need containerd image store for testing local images
- uses: crazy-max/ghaction-setup-docker@5bddaa4323ffd60efb2b5045b75b9637c12d4e50 # v3.2.0
with:
daemon-config: |
{
"debug": true,
"features": {
"containerd-snapshotter": true
}
}
- uses: crazy-max/ghaction-github-runtime@b3a9207c0e1ef41f4cf215303c976869d0c2c1c4 # v3.0.0

- name: build aikit
run: |
docker buildx build . -t aikit:test \
--load --provenance=false --progress plain \
--cache-from=type=gha,scope=aikit \
--cache-to=type=gha,scope=aikit,mode=max
- name: build test model
run: |
docker buildx build . -t testmodel:test \
-f test/aikitfile-llama.yaml \
--load --provenance=false --progress plain \
--cache-from=type=gha,scope=testmodel \
--cache-to=type=gha,scope=testmodel,mode=max
- name: list images
run: docker images

- name: install e2e dependencies
run: make test-e2e-dependencies

- name: create kind cluster
run: kind create cluster --wait 5m

- name: load test model image into kind cluster
run: kind load docker-image testmodel:test

- name: deploy test model
run: |
helm install charts/aikit --wait --debug --name-template aikit \
--set image.repository=testmodel \
--set image.tag=test \
--set image.pullPolicy=Never \
--set ui.enabled=false
kubectl port-forward service/aikit 8080:8080 &
- name: run test
run: |
result=$(curl --fail --retry 10 --retry-all-errors http://127.0.0.1:8080/v1/chat/completions -H "Content-Type: application/json" -d '{
"model": "llama-3-8b-instruct",
"messages": [{"role": "user", "content": "explain kubernetes in a sentence"}]
}')
echo $result
choices=$(echo "$result" | jq '.choices')
if [ -z "$choices" ]; then
exit 1
fi
- name: save logs
if: always()
run: |
echo "KIND_LOGS_PATH=$(kind export logs)" >> $GITHUB_ENV
- name: publish logs
if: always()
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: kind-logs
path: $KIND_LOGS_PATH
4 changes: 2 additions & 2 deletions .github/workflows/test-kubernetes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
storage.googleapis.com:443
deb.debian.org:80
developer.download.nvidia.com:443
pci-ids.ucw.cz:443
get.helm.sh:443
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6

Expand Down Expand Up @@ -124,4 +124,4 @@ jobs:
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: kind-logs
path: ${KIND_LOGS_PATH}
path: $KIND_LOGS_PATH
12 changes: 10 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
VERSION := v0.8.0

REGISTRY ?= ghcr.io/sozercan
KIND_VERSION ?= 0.22.0
KUBERNETES_VERSION ?= 1.29.3
KIND_VERSION ?= 0.23.0
KUBERNETES_VERSION ?= 1.30.1
HELM_VERSION ?= 3.15.1
TAG ?= test
OUTPUT_TYPE ?= type=docker
TEST_IMAGE_NAME ?= testmodel
Expand Down Expand Up @@ -42,4 +45,9 @@ test-e2e-dependencies:

# used for kubernetes test
curl -sSL https://dl.k8s.io/release/v${KUBERNETES_VERSION}/bin/linux/amd64/kubectl -o ${GITHUB_WORKSPACE}/bin/kubectl && chmod +x ${GITHUB_WORKSPACE}/bin/kubectl
curl https://get.helm.sh/helm-v${HELM_VERSION}-linux-amd64.tar.gz | tar xz && mv linux-amd64/helm ${GITHUB_WORKSPACE}/bin/helm && chmod +x ${GITHUB_WORKSPACE}/bin/helm
curl -sSL https://github.com/kubernetes-sigs/kind/releases/download/v${KIND_VERSION}/kind-linux-amd64 -o ${GITHUB_WORKSPACE}/bin/kind && chmod +x ${GITHUB_WORKSPACE}/bin/kind

.PHONY: release-manifest
release-manifest:
@sed -i "s/version: $$(echo ${VERSION} | cut -c2-)/version: $$(echo ${NEWVERSION} | cut -c2-)/" ./charts/aikit/Chart.yaml
24 changes: 24 additions & 0 deletions charts/aikit/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: v2
name: aikit
description: Kubernetes Helm chart to deploy AIKit LLM images

# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application

# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.8.0

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: 0.8.0
41 changes: 41 additions & 0 deletions charts/aikit/templates/NOTES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
Get the application URL by running these commands:

{{- if .Values.ui.enabled }}

{{- if .Values.ui.ingress.enabled }}
{{- range $host := .Values.ui.ingress.hosts }}
{{- range .paths }}
http{{ if $.Values.ui.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
{{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.ui.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ (printf "%s-webui" (include "aikit.fullname" .)) }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.ui.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "aikit.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ (printf "%s-webui" (include "aikit.fullname" .)) }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo http://$SERVICE_IP:{{ .Values.ui.service.port }}
{{- else if contains "ClusterIP" .Values.ui.service.type }}
echo "Visit http://127.0.0.1:8080 to access aikit WebUI."
kubectl --namespace {{ .Release.Namespace }} port-forward service/{{ (printf "%s-webui" (include "aikit.fullname" .)) }} 8080:{{ .Values.ui.service.port }}
{{- end }}

{{- else }}

{{- if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ (include "aikit.fullname" .) }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "aikit.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ (include "aikit.fullname" .) }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
echo "Visit http://127.0.0.1:8080 to access aikit API."
kubectl --namespace {{ .Release.Namespace }} port-forward service/{{ (include "aikit.fullname" .) }} 8080:{{ .Values.service.port }}
{{- end }}

{{- end }}
Loading

0 comments on commit 2bb0f9e

Please sign in to comment.