Skip to content

Deploy Nosana

Deploy Nosana #1

Workflow file for this run

name: Deploy Nosana
on:
workflow_dispatch:
inputs:
image_tag:
description: Docker image tag to deploy
required: true
default: latest
deployment_name:
description: Prefix for the Nosana deployment name
required: true
default: miku
market_filter:
description: GPU/market filter
required: true
default: '3090'
market_type:
description: Nosana market type
required: true
default: PREMIUM
permissions:
contents: read
concurrency:
group: deploy-nosana-${{ github.ref }}
cancel-in-progress: true
jobs:
deploy-nosana:
runs-on: ubuntu-latest
env:
DOCKER_IMAGE: ${{ secrets.DOCKER_USERNAME }}/miku
NOSANA_API_KEY: ${{ secrets.NOSANA_API_KEY }}
LLM_API_KEY: ${{ secrets.GEMINI_API_KEY }}
NOSANA_API_BASE: https://dashboard.k8s.prd.nos.ci/api
NOSANA_MARKET_FILTER: ${{ inputs.market_filter }}
NOSANA_MARKET_TYPE: ${{ inputs.market_type }}
steps:
- uses: actions/checkout@v4
- name: Validate deployment secrets
run: |
test -n "${{ env.NOSANA_API_KEY }}" || {
echo "NOSANA_API_KEY secret is required";
exit 1;
}
test -n "${{ env.LLM_API_KEY }}" || {
echo "GEMINI_API_KEY secret is required for the current deploy workflow";
exit 1;
}
- name: Resolve market address
id: resolve-market
run: |
normalized_market_filter=$(printf '%s' "${{ env.NOSANA_MARKET_FILTER }}" | tr '[:upper:]' '[:lower:]')
normalized_market_type=$(printf '%s' "${{ env.NOSANA_MARKET_TYPE }}" | tr '[:upper:]' '[:lower:]')
response_file=$(mktemp)
status_code=$(curl -sS -o "$response_file" -w '%{http_code}' \
-H "Authorization: Bearer ${{ env.NOSANA_API_KEY }}" \
"${{ env.NOSANA_API_BASE }}/markets/")
case "$status_code" in
2*) ;;
*)
echo "Failed to fetch Nosana markets (HTTP $status_code)"
cat "$response_file"
exit 1
;;
esac
market_address=$(jq -r --arg filter "$normalized_market_filter" --arg marketType "$normalized_market_type" '
map(select(
((.type // "") | ascii_downcase) == $marketType
and
(
((.name // "") | ascii_downcase | contains($filter))
or
((.gpu // "") | ascii_downcase | contains($filter))
)
))
| .[0].address // empty
' "$response_file")
test -n "$market_address" || {
echo "Unable to resolve Nosana ${{ env.NOSANA_MARKET_TYPE }} market address for filter: ${{ env.NOSANA_MARKET_FILTER }}"
cat "$response_file"
exit 1
}
echo "market_address=$market_address" >> "$GITHUB_OUTPUT"
- name: Prepare deployment payload
id: payload
run: |
tmp_job_definition=$(mktemp)
jq \
--arg image "${{ env.DOCKER_IMAGE }}:${{ inputs.image_tag }}" \
--arg apiKey "${{ env.LLM_API_KEY }}" \
--arg baseUrl "https://generativelanguage.googleapis.com/v1beta/openai" \
--arg smallModel "gemini-2.5-flash" \
--arg largeModel "gemini-2.5-flash" \
--arg embeddingModel "gemini-embedding-001" \
--arg embeddingDimensions "1536" \
'
.ops[0].args.image = $image
| .ops[0].args.env.OPENAI_API_KEY = $apiKey
| .ops[0].args.env.OPENAI_BASE_URL = $baseUrl
| .ops[0].args.env.OPENAI_SMALL_MODEL = $smallModel
| .ops[0].args.env.OPENAI_LARGE_MODEL = $largeModel
| .ops[0].args.env.OPENAI_EMBEDDING_MODEL = $embeddingModel
| .ops[0].args.env.OPENAI_EMBEDDING_DIMENSIONS = $embeddingDimensions
' ./nos_job_def/nosana_eliza_job_definition.json > "$tmp_job_definition"
payload_file=$(mktemp)
deployment_name="${{ inputs.deployment_name }}-${GITHUB_RUN_NUMBER}"
jq -n \
--arg name "$deployment_name" \
--arg market "${{ steps.resolve-market.outputs.market_address }}" \
--argjson timeout 300 \
--argjson replicas 1 \
--arg strategy "SIMPLE" \
--slurpfile job "$tmp_job_definition" \
'{
name: $name,
market: $market,
timeout: $timeout,
replicas: $replicas,
strategy: $strategy,
job_definition: $job[0]
}' > "$payload_file"
echo "payload_file=$payload_file" >> "$GITHUB_OUTPUT"
- name: Create deployment
id: create-deployment
run: |
response_file=$(mktemp)
status_code=$(curl -sS -o "$response_file" -w '%{http_code}' \
-X POST \
-H "Authorization: Bearer ${{ env.NOSANA_API_KEY }}" \
-H "Content-Type: application/json" \
--data @"${{ steps.payload.outputs.payload_file }}" \
"${{ env.NOSANA_API_BASE }}/deployments/create")
case "$status_code" in
2*) ;;
*)
echo "Failed to create deployment (HTTP $status_code)"
cat "$response_file"
exit 1
;;
esac
deployment_id=$(jq -r '.id // .deployment.id // empty' "$response_file")
test -n "$deployment_id" || {
echo "Deployment id missing from response"
cat "$response_file"
exit 1
}
echo "deployment_id=$deployment_id" >> "$GITHUB_OUTPUT"
- name: Start deployment
run: |
response_file=$(mktemp)
status_code=$(curl -sS -o "$response_file" -w '%{http_code}' \
-X POST \
-H "Authorization: Bearer ${{ env.NOSANA_API_KEY }}" \
"${{ env.NOSANA_API_BASE }}/deployments/${{ steps.create-deployment.outputs.deployment_id }}/start")
case "$status_code" in
2*) ;;
*)
echo "Failed to start deployment (HTTP $status_code)"
cat "$response_file"
exit 1
;;
esac
deployment_status=$(jq -r '.status // .deployment.status // empty' "$response_file")
case "$deployment_status" in
STARTING|RUNNING)
cat "$response_file"
;;
*)
echo "Unexpected deployment status: ${deployment_status:-<empty>}"
cat "$response_file"
exit 1
;;
esac