All skills
microsoft avatar

/azure-app-onboard

@cda1f27 official

End-to-end orchestrator: from a business idea, app idea, or existing app to running Azure deployment with cost estimates and pre-deploy approval. Analyzes your app, auto-detects the right Azure services, scaffolds infrastructure code, and deploys — tailored to your app, not a template. Handles moving existing apps to Azure without rewriting or with minimal changes. WHEN: bring your app to Azure, plan my app, cost to run, is my code ready to deploy, deploy my app to the cloud, deploy all my services, what Azure services do I need, plan my Azure deployment, deploy my new app to Azure, one-click deploy, I have an app and want it on Azure, migrate my app to Azure, help me get started, build an app, no code yet, starter project. DO NOT USE FOR: use azd for deployment(use azure-deploy), optimizing existing costs (use cost-optimization), code readiness checks only (use azure-app-onboard-prereq).

Use this Skill: https://skilld.dev/gh/microsoft/github-copilot-for-azure/azure-app-onboard

This session only. Nothing lands on disk.

preparereferencesdeploy-strategy.md

≈1.7k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Deploy Strategy

Determine how application code will be deployed to Azure based on prereq scan results. The prepare phase writes deployStrategy to prepare-plan.json; scaffold encodes it in Bicep; deploy executes it.

Deployment Patterns

Three patterns — select based on prereq-output.json.components[].buildRequirements:

⛔ Dockerfile ≠ Container Apps. A Dockerfile that only serves static files (nginx, httpd, COPY . /usr/share/nginx/html) is NOT a backend app. Route static-only Dockerfiles as static sites per service-mapping.md § Static Dockerfile sites, not Pattern C.

Pattern When deployStrategy needed?
A: Oryx auto-build No native modules, no Dockerfile Yes — startup command + app settings go in Bicep at scaffold time
B: Startup-install Native modules detected (hasNativeModules: true) Yes — startup command + fallback install + app settings in Bicep
C: Container-only Has Dockerfile that runs a server process (Express, Flask, uvicorn, etc.) No — route to Container Apps (Dockerfile IS the deploy strategy)

Additional routing:

Condition Action
Jib build plugin (Java + com.google.cloud.tools.jib) Container-only via Jib push to ACR — no Dockerfile needed

Pattern A: Oryx Auto-Build (Default)

Languages: Node.js, Python, .NET, Go, Java, PHP, Ruby

Oryx detects the stack from project manifests, installs dependencies, and builds automatically during zip deploy.

Still write deployStrategy to prepare-plan.json — even though Oryx auto-detects, the startup command and app settings MUST be in Bicep at scaffold time (not generated at deploy time). This eliminates imperative CLI commands during deploy.

"deployStrategy": {
  "codeDeployPattern": "oryx-auto",
  "requiredAppSettings": {
    "SCM_DO_BUILD_DURING_DEPLOYMENT": "true",
    "ENABLE_ORYX_BUILD": "true",
    "ORYX_DISABLE_COMPRESSION": "true"
  },
  "reason": "Standard Oryx build — no native modules, no Dockerfile. Compression disabled to avoid startup extraction delays. No custom appCommandLine — Oryx launcher handles decompression + start."
}

Read prereq-output.json.entryPoint for the app's start file — do NOT re-read manifests. Build the startup command from package.json start script (Node.js) or framework convention (Python gunicorn, .NET/Go/Java Oryx-native).

⛔ Do NOT set a custom appCommandLine for Pattern A. Let Oryx use package.json start script or framework defaults natively. A custom appCommandLine (cd /home/site/wwwroot && node {entryPoint}) replaces the Oryx launcher entirely — the launcher handles node_modules.tar.gz decompression, and bypassing it causes MODULE_NOT_FOUND crashes. Only set appCommandLine when initCommands[] has required: true entries (migrations).

⛔ TypeScript projects: Verify typescript + @types/* are in dependencies (not devDependencies) — Oryx production mode skips devDeps, causing tsc build failures.

⛔ When initCommands[] has required: true entries: Set startupCommand to prepend migrations: "cd /home/site/wwwroot && {initCommand} && {framework-default-start}". Migrations are idempotent — safe on every cold start. Otherwise, omit startupCommand entirely (let Oryx handle it).

Scaffold encodes startupCommand → Bicep appCommandLine, and requiredAppSettings → Bicep siteConfig.appSettings. Deploy only does: wait → zip → health check.


Pattern B: Startup-Install (Native Modules)

When native modules are detected, Oryx may fail to compile them. The startup-install pattern provides a two-layer safety net.

Two-Layer Strategy

  1. Primary — Oryx zip build: SCM_DO_BUILD_DURING_DEPLOYMENT=true + ENABLE_ORYX_BUILD=true tells Oryx to run dependency installation during the Kudu-side zip deploy. The Kudu build environment on App Service Linux has gcc, make, and build tools available, so native compilation CAN succeed here.

  2. Fallback — startup-install command: appCommandLine runs dependency installation on first container boot IF the dependency directory doesn't exist. The existence guard ensures it only runs when needed — subsequent restarts skip it because /home is persistent storage.

Both layers are set in Bicep at scaffold time. The startup command is insurance — not the primary mechanism.

Why two layers? az webapp deploy --type zip uses the OneDeploy API, which may not trigger Oryx even with SCM_DO_BUILD_DURING_DEPLOYMENT=true. The startup command catches this case. If Oryx DID build successfully, the guard skips the redundant install.

Deploy Strategy Schema

Write to prepare-plan.json.deployStrategy:

"deployStrategy": {
  "codeDeployPattern": "startup-install",
  "startupCommand": "cd /home/site/wwwroot && if [ ! -d node_modules ]; then npm install --production; fi && node index.js",
  "requiredAppSettings": {
    "WEBSITES_CONTAINER_START_TIME_LIMIT": "1800",
    "SCM_DO_BUILD_DURING_DEPLOYMENT": "true",
    "ENABLE_ORYX_BUILD": "true",
    "ORYX_DISABLE_COMPRESSION": "true"
  },
  "reason": "Native module (better-sqlite3 via node-gyp) requires server-side npm install."
}

Replace startupCommand and reason with language-specific values from the entry point table below.

Entry Point & Startup Commands

Same as Pattern A, but Node.js adds a dependency guard: if [ ! -d node_modules ]; then npm install --production; fi before the start command.

⛔ Inline commands only. Never generate a .sh startup script file — CRLF causes bash exit code 2. ⛔ Python: do NOT use venv in startup commands.

SKU Implications

When f1Viable: false (any of: native modules, TypeScript build, large deps, WSGI/ASGI server), F1 is not viable — use B1 (~$13/mo) minimum. Surface at approval gate: "⚠️ {f1BlockReason}. B1 minimum required."

Container Timeout

WEBSITES_CONTAINER_START_TIME_LIMIT controls how long Azure waits for the container to start responding.

Value Use case
230 (default) Standard apps, no native compilation
1800 (max) Startup-install — native compilation takes 2-5 min. Python with scipy/scikit-learn can take longer

Always set to 1800 when codeDeployPattern == "startup-install".


Pattern C: Container-Only

When the component has a Dockerfile with backend logic, route to Container Apps. The Dockerfile IS the deploy strategy — no deployStrategy needed in prepare-plan.json.

The deploy phase handles: ACR build → image push → Bicep redeploy with real image. See code-deployment-container-apps.md.

For Java apps using Jib (build.gradle + com.google.cloud.tools.jib), the build produces a container image without a Dockerfile — push to ACR via jib task.

Source: SKILL.md on GitHub

No alerts22d3 checks · Risk SAFE
  • Gen Agent Trust Hub22d

    This skill includes some security considerations such as the processing of untrusted project files to generate deployment scripts and the dynamic generation of infrastructure code. While these warrant review, they are used within the skill's intended functionality to automate Azure onboarding. See detailed analysis for context.

  • Socket22d

    No alerts

  • Snyk22d

    Risk: LOW · No issues

Signed by skilld at cda1f27. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated last week
metadata
{
  "author": "Microsoft",
  "version": "0.0.0-placeholder"
}

README badge

README badge for microsoft/github-copilot-for-azure/azure-app-onboard