|
| 1 | +# Baremetal Production Deploy |
| 2 | +# |
| 3 | +# Builds the agent + control-plane binaries, bakes a VM image on the production |
| 4 | +# host via Packer, and launches the new agent VM. |
| 5 | +# |
| 6 | +# Trigger: automatic on push to main (after PR has been validated on staging). |
| 7 | +# Dispatch inputs let you override GPU PCI address, memory, and CPU count — |
| 8 | +# but sensible defaults come from infra/ansible/inventory/production.yml. |
| 9 | +# |
| 10 | +# App deployment (private-llm etc.) is handled by the private-llm repo, |
| 11 | +# not here. This workflow owns infra only. |
| 12 | + |
1 | 13 | name: Baremetal Production Deploy |
2 | 14 |
|
3 | 15 | on: |
| 16 | + push: |
| 17 | + branches: [main] |
| 18 | + paths: |
| 19 | + - "agent/**" |
| 20 | + - "control-plane/**" |
| 21 | + - "images/**" |
| 22 | + - "infra/**" |
| 23 | + - ".github/workflows/baremetal-*" |
4 | 24 | workflow_dispatch: |
5 | 25 | inputs: |
6 | 26 | vfio_device: |
7 | | - description: "PCI address for GPU passthrough" |
| 27 | + description: "PCI address for GPU passthrough (e.g. 0d:00.0)" |
8 | 28 | default: "0d:00.0" |
9 | 29 | agent_memory: |
10 | | - description: "Agent VM memory" |
11 | | - default: "128G" |
| 30 | + description: "Agent VM memory (overrides inventory default)" |
| 31 | + default: "" |
12 | 32 | agent_cpus: |
13 | | - description: "Agent VM CPUs" |
14 | | - default: "32" |
| 33 | + description: "Agent VM CPUs (overrides inventory default)" |
| 34 | + default: "" |
15 | 35 |
|
16 | 36 | concurrency: |
17 | 37 | group: dd-baremetal-production |
18 | | - cancel-in-progress: false |
| 38 | + cancel-in-progress: false # Never cancel an in-progress production deploy |
19 | 39 |
|
20 | 40 | permissions: |
21 | | - id-token: write |
22 | 41 | contents: read |
23 | 42 |
|
24 | 43 | jobs: |
25 | 44 | deploy: |
26 | 45 | runs-on: ubuntu-latest |
27 | 46 | environment: production |
28 | 47 | steps: |
| 48 | + # ── Build binaries ────────────────────────────────────────────────── |
29 | 49 | - uses: actions/checkout@v4 |
| 50 | + |
30 | 51 | - uses: dtolnay/rust-toolchain@stable |
31 | 52 | - uses: Swatinem/rust-cache@v2 |
| 53 | + |
| 54 | + # Build both dd-agent and dd-cp in release mode |
32 | 55 | - run: cargo build --workspace --release |
| 56 | + |
33 | 57 | - run: pip install ansible |
34 | 58 |
|
| 59 | + # ── SSH setup ─────────────────────────────────────────────────────── |
| 60 | + # Write the deploy key to the path the inventory expects (/tmp/deploy-key) |
35 | 61 | - name: Set up SSH |
36 | 62 | run: | |
37 | | - mkdir -p ~/.ssh |
38 | | - echo "${{ secrets.BAREMETAL_SSH_KEY }}" > ~/.ssh/deploy_key |
39 | | - chmod 600 ~/.ssh/deploy_key |
40 | | - ssh-keyscan -H "${{ vars.BAREMETAL_PRODUCTION_HOST }}" >> ~/.ssh/known_hosts 2>/dev/null |
| 63 | + echo "${{ secrets.BAREMETAL_SSH_KEY }}" > /tmp/deploy-key |
| 64 | + chmod 600 /tmp/deploy-key |
| 65 | + ssh-keyscan -H 162.222.34.121 >> ~/.ssh/known_hosts 2>/dev/null || true |
41 | 66 |
|
| 67 | + # ── Deploy agent VM ───────────────────────────────────────────────── |
| 68 | + # Runs the baremetal-agent-deploy playbook against the production inventory. |
| 69 | + # Build-time vars and GPU passthrough are passed with -e. |
| 70 | + # Workflow dispatch inputs override inventory defaults when provided. |
42 | 71 | - name: Deploy agent to production host |
43 | 72 | env: |
44 | 73 | ANSIBLE_HOST_KEY_CHECKING: "false" |
45 | 74 | run: | |
46 | 75 | sha12="$(echo "${{ github.sha }}" | cut -c1-12)" |
| 76 | + EXTRA_VARS=( |
| 77 | + -e "agent_binary_local=${GITHUB_WORKSPACE}/target/release/dd-agent" |
| 78 | + -e "cp_binary_local=${GITHUB_WORKSPACE}/target/release/dd-cp" |
| 79 | + -e "packer_template_dir=${GITHUB_WORKSPACE}/images/packer" |
| 80 | + -e "image_name=dd-baremetal-${sha12}" |
| 81 | + -e "vfio_device=${{ inputs.vfio_device || '0d:00.0' }}" |
| 82 | + ) |
| 83 | + # Only override inventory defaults when the dispatch input is non-empty |
| 84 | + if [ -n "${{ inputs.agent_memory }}" ]; then |
| 85 | + EXTRA_VARS+=(-e "agent_memory=${{ inputs.agent_memory }}") |
| 86 | + fi |
| 87 | + if [ -n "${{ inputs.agent_cpus }}" ]; then |
| 88 | + EXTRA_VARS+=(-e "agent_cpus=${{ inputs.agent_cpus }}") |
| 89 | + fi |
| 90 | + EXTRA_VARS+=( |
| 91 | + -e "dd_intel_api_key=${{ secrets.INTEL_API_KEY }}" |
| 92 | + -e "dd_cp_admin_password=${{ secrets.DD_CP_ADMIN_PASSWORD }}" |
| 93 | + -e "dd_cp_cf_api_token=${{ secrets.DD_CP_CF_API_TOKEN }}" |
| 94 | + -e "dd_cp_cf_account_id=${{ secrets.DD_CP_CF_ACCOUNT_ID }}" |
| 95 | + -e "dd_cp_cf_zone_id=${{ secrets.DD_CP_CF_ZONE_ID }}" |
| 96 | + ) |
47 | 97 | ansible-playbook infra/ansible/playbooks/baremetal-agent-deploy.yml \ |
48 | | - -i "${{ vars.BAREMETAL_PRODUCTION_HOST }}," \ |
49 | | - -u "${{ vars.BAREMETAL_PRODUCTION_USER }}" \ |
50 | | - --private-key ~/.ssh/deploy_key \ |
51 | | - -e "agent_binary_local=${GITHUB_WORKSPACE}/target/release/dd-agent" \ |
52 | | - -e "cp_binary_local=${GITHUB_WORKSPACE}/target/release/dd-cp" \ |
53 | | - -e "packer_template_dir=${GITHUB_WORKSPACE}/images/packer" \ |
54 | | - -e "image_name=dd-baremetal-${sha12}" \ |
55 | | - -e "dd_env=production" \ |
56 | | - -e "cp_url=https://app.${{ vars.DD_CF_DOMAIN || 'devopsdefender.com' }}" \ |
57 | | - -e "dd_skip_attestation=true" \ |
58 | | - -e "agent_node_size=llm" \ |
59 | | - -e "agent_memory=${{ inputs.agent_memory }}" \ |
60 | | - -e "agent_cpus=${{ inputs.agent_cpus }}" \ |
61 | | - -e "vfio_device=${{ inputs.vfio_device }}" |
62 | | -
|
63 | | - - name: Deploy private-llm (H100 GPU mode) |
64 | | - env: |
65 | | - GH_TOKEN: ${{ github.token }} |
66 | | - run: | |
67 | | - CP_URL="https://app.${{ vars.DD_CF_DOMAIN || 'devopsdefender.com' }}" |
68 | | - OIDC_TOKEN=$(curl -s -H "Authorization: bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \ |
69 | | - "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=devopsdefender" | jq -r '.value') |
70 | | - gh api repos/devopsdefender/private-llm/contents/docker-compose.h100.yml \ |
71 | | - -H "Accept: application/vnd.github.raw" > /tmp/compose.yml |
72 | | - COMPOSE_B64=$(base64 -w0 /tmp/compose.yml) |
73 | | - curl -sf -X POST "${CP_URL}/api/v1/deploy" \ |
74 | | - -H "Authorization: Bearer ${OIDC_TOKEN}" \ |
75 | | - -H "Content-Type: application/json" \ |
76 | | - -d "{\"app_name\":\"private-llm\",\"app_version\":\"${{ github.sha }}\",\"compose\":\"${COMPOSE_B64}\",\"node_size\":\"llm\"}" |
| 98 | + -i infra/ansible/inventory/production.yml \ |
| 99 | + "${EXTRA_VARS[@]}" |
77 | 100 |
|
78 | | - - name: Cleanup |
| 101 | + # ── Cleanup ───────────────────────────────────────────────────────── |
| 102 | + - name: Cleanup SSH key |
79 | 103 | if: always() |
80 | | - run: rm -f ~/.ssh/deploy_key |
| 104 | + run: rm -f /tmp/deploy-key |
0 commit comments