Deploy Nosana #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |