{"id":2266,"date":"2025-07-21T16:17:37","date_gmt":"2025-07-21T16:17:37","guid":{"rendered":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2025\/07\/21\/azure-developer-cli-from-dev-to-prod-with-one-click\/"},"modified":"2025-07-21T16:17:37","modified_gmt":"2025-07-21T16:17:37","slug":"azure-developer-cli-from-dev-to-prod-with-one-click","status":"publish","type":"post","link":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2025\/07\/21\/azure-developer-cli-from-dev-to-prod-with-one-click\/","title":{"rendered":"Azure Developer CLI: From Dev to Prod with One Click"},"content":{"rendered":"<p>This post walks through how to implement a <strong>\u201cbuild once, deploy everywhere\u201d<\/strong> pattern using <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/developer\/azure-developer-cli\/overview\" target=\"_blank\">Azure Developer CLI (azd)<\/a> that provisions environment-specific infrastructure and promotes applications from dev to prod with the same build artifacts. You\u2019ll learn how to use conditional Bicep deployment, environment variable injection, package preservation across environments, and automated CI\/CD promotion from development to production.<\/p>\n<h2>Environment-Specific Infrastructure<\/h2>\n<p>When deploying applications across environments, different requirements emerge:<\/p>\n<p>Component<br \/>\nDevelopment<br \/>\nProduction<\/p>\n<p><strong>Networking<\/strong><br \/>\nPublic access<br \/>\nVNet integration + Private endpoints<\/p>\n<p><strong>Storage<\/strong><br \/>\nPublic with restrictions<br \/>\nPrivate endpoints only<\/p>\n<p><strong>App Service Plan<\/strong><br \/>\nB2 Basic<br \/>\nS1 Standard<\/p>\n<p><strong>Security<\/strong><br \/>\nManaged identity<br \/>\nEnhanced network isolation<\/p>\n<p>Rather than maintaining separate infrastructure templates or complex configuration files for each environment, we can use a single set of Bicep files that adapt based on an environment variable. This approach eliminates infrastructure drift while keeping deployments simple and consistent.<\/p>\n<h2>Set up resources based on an environment variable<\/h2>\n<p>To conditionally provision resources based on environment type, azd leverages an environment variable AZURE_ENV_TYPE to make decisions at deployment time.<\/p>\n<p>Behind the scenes, azd passes AZURE_ENV_TYPE to Bicep as the envType parameter:<\/p>\n<p>@description(&#8216;Environment type &#8211; determines networking configuration (dev\/test\/prod)&#8217;)<br \/>\n@allowed([&#8216;dev&#8217;, &#8216;test&#8217;, &#8216;prod&#8217;])<br \/>\nparam envType string = &#8216;dev&#8217;<\/p>\n<p>This parameter then drives conditional resource deployment in Bicep:<\/p>\n<p><strong>For Network Deployment:<\/strong><\/p>\n<p>\/\/ Deploy network infrastructure only for production environments<br \/>\nmodule network &#8216;.\/network.bicep&#8217; = if (envType == &#8216;prod&#8217;) {<br \/>\n  name: &#8216;networkDeployment&#8217;<br \/>\n  params: {<br \/>\n    location: location<br \/>\n    tags: tags<br \/>\n    abbrs: abbrs<br \/>\n    resourceToken: resourceToken<br \/>\n  }<br \/>\n}<\/p>\n<p><strong>Similarly for Storage Configuration:<\/strong><\/p>\n<p>module storageAccount &#8216;br\/public:avm\/res\/storage\/storage-account:0.17.2&#8217; = {<br \/>\n  name: &#8216;storageAccount&#8217;<br \/>\n  params: {<br \/>\n    name: storageAccountName<br \/>\n    allowSharedKeyAccess: false<br \/>\n    publicNetworkAccess: envType == &#8216;prod&#8217; ? &#8216;Disabled&#8217; : &#8216;Enabled&#8217;<br \/>\n    networkAcls: envType == &#8216;prod&#8217; ? {<br \/>\n      defaultAction: &#8216;Deny&#8217;<br \/>\n      virtualNetworkRules: []<br \/>\n      bypass: &#8216;AzureServices&#8217;<br \/>\n    } : {<br \/>\n      defaultAction: &#8216;Allow&#8217;<br \/>\n      virtualNetworkRules: []<br \/>\n      bypass: &#8216;AzureServices&#8217;<br \/>\n    }<br \/>\n    \/\/ &#8230; other configuration<br \/>\n  }<br \/>\n}<\/p>\n<p><strong>Finally for App Service Plan Sizing:<\/strong><\/p>\n<p>sku: {<br \/>\n  name: envType == &#8216;prod&#8217; ? &#8216;S1&#8217; : &#8216;B2&#8217;<br \/>\n  tier: envType == &#8216;prod&#8217; ? &#8216;Standard&#8217; : &#8216;Basic&#8217;<br \/>\n}<\/p>\n<h2>Enhance default CI\/CD workflow<\/h2>\n<p>azd includes a powerful command to bootstrap CI\/CD pipeline:<\/p>\n<p>azd pipeline config<\/p>\n<p>This generates a basic workflow. However, for dev-to-prod promotion, enhance it with these steps:<\/p>\n<p><strong>1. Package Once:<\/strong><\/p>\n<p>&#8211; name: Package Application<br \/>\n  run: |<br \/>\n    mkdir -p .\/dist<br \/>\n    azd package app &#8211;output-path .\/dist\/app-package.zip<br \/>\n    # Create a backup copy for production deployment<br \/>\n    cp .\/dist\/app-package.zip .\/app-package-backup.zip<br \/>\n    echo &#8220;\u2705 Application packaged and backup created&#8221;<\/p>\n<p><strong>2. Deploy to Dev:<\/strong><\/p>\n<p>&#8211; name: Deploy to Development<br \/>\n  run: azd deploy app &#8211;from-package .\/dist\/app-package.zip &#8211;no-prompt<\/p>\n<p><strong>3. Validation Gate:<\/strong><\/p>\n<p>&#8211; name: Validate Application<br \/>\n  run: |<br \/>\n    echo &#8220;\ud83d\udd0d Validating application in development environment&#8230;&#8221;<br \/>\n    # Add your validation logic here:<br \/>\n    # &#8211; Health checks and integration tests<br \/>\n    # &#8211; Security and compliance scanning<br \/>\n    # &#8211; Performance validation<br \/>\n    sleep 3  # Simulate validation time<br \/>\n    echo &#8220;\u2705 Application validation passed&#8221;<\/p>\n<p><strong>4. Set environment variables:<\/strong><\/p>\n<p>&#8211; name: Promote to Production<br \/>\n  run: |<br \/>\n    # Create production environment name by replacing -dev with -prod, or adding -prod if no -dev suffix<br \/>\n    PROD_ENV_NAME=&#8221;${AZURE_ENV_NAME%-dev}-prod&#8221;<br \/>\n    echo &#8220;Production environment name: $PROD_ENV_NAME&#8221;<\/p>\n<p>    # Set environment variables for this step<br \/>\n    export AZURE_ENV_NAME=&#8221;$PROD_ENV_NAME&#8221;<br \/>\n    export AZURE_ENV_TYPE=&#8221;prod&#8221;<\/p>\n<p><strong>5. Deploy to Prod:<\/strong><\/p>\n<p># Use the same package created earlier &#8211; true &#8220;build once, deploy everywhere&#8221;<br \/>\nPACKAGE_PATH=&#8221;.\/app-package-backup.zip&#8221;<\/p>\n<p>if [ -f &#8220;$PACKAGE_PATH&#8221; ]; then<br \/>\n  echo &#8220;\ud83d\ude80 Deploying to production using existing package: $PACKAGE_PATH&#8221;<br \/>\n  azd deploy app &#8211;from-package &#8220;$PACKAGE_PATH&#8221; &#8211;no-prompt<br \/>\n  echo &#8220;\u2705 Production deployment completed successfully&#8221;<\/p>\n<p><strong>6. Clean Up:<\/strong><\/p>\n<p>  # Clean up the backup package after successful deployment<br \/>\n  rm -f &#8220;$PACKAGE_PATH&#8221;<br \/>\n  echo &#8220;\ud83e\uddf9 Cleaned up package backup&#8221;<br \/>\nelse<br \/>\n  echo &#8220;\u274c Package backup not found &#8211; falling back to regular deployment&#8221;<br \/>\n  azd deploy &#8211;no-prompt<br \/>\nfi<\/p>\n<h2>Try It Out<\/h2>\n<p>You can try this approach using the complete implementation <a href=\"https:\/\/github.com\/puicchan\/azd-dev-prod-appservice-storage\">here<\/a>.<\/p>\n<p><strong>Watch the walkthrough:<\/strong> See this entire process in action in the video below that shows the complete setup and deployment flow.<\/p>\n\n<h3>Step-by-Step Setup<\/h3>\n<p>Follow these steps to set up both development and production environments, then configure the CI\/CD pipeline:<\/p>\n<p><strong>1. Initialize project from the template<\/strong><\/p>\n<p>azd init -t https:\/\/github.com\/puicchan\/azd-dev-prod-appservice-storage<\/p>\n<p>This downloads the complete implementation with all Bicep files and <strong>enhanced<\/strong> GitHub Actions workflow.<\/p>\n<p><strong>2. Set Up Development Environment<\/strong><\/p>\n<p>azd up<\/p>\n<p>When prompted for the environment name, use myproj-dev (or your preferred naming pattern with -dev suffix).<\/p>\n<p><strong>Note<\/strong>: The default envType is dev, so you don\u2019t need to set the AZURE_ENV_TYPE environment variable for development. The infrastructure will automatically provision with public access and cost-optimized resources.<\/p>\n<p><strong>3. Set Up Production Environment<\/strong><\/p>\n<p>Create and configure the production environment:<\/p>\n<p># Create new production environment<br \/>\nazd env new myproj-prod<\/p>\n<p># Set environment type to production<br \/>\nazd env set AZURE_ENV_TYPE prod<\/p>\n<p># Deploy production environment<br \/>\nazd up<\/p>\n<p>This provisions production infrastructure with VNet integration, private endpoints, and enhanced security. Note that running azd up deploys the app to the production infrastructure as well. This is for demonstration purpose plus we are still in development stage. In a real-world scenario, you\u2019d probably never deploy your app directly if it is already in production.<\/p>\n<p><strong>4. Switch Back to Development Environment<\/strong><\/p>\n<p>azd env select myproj-dev<\/p>\n<p>You\u2019re now ready to develop and test in the development environment.<\/p>\n<p><strong>5. Make Code Changes<\/strong><\/p>\n<p>Edit your application code (e.g., modify app\/templates\/index.html or app.py) to test the promotion workflow.<\/p>\n<p><strong>6. Configure CI\/CD Pipeline<\/strong><\/p>\n<p>azd pipeline config<\/p>\n<p>The GitHub Actions workflow is enhanced with dev-to-prod promotion logic. Specifically, the pipeline will:<\/p>\n<p>Deploy and validate in development (`myproj-dev`)<br \/>\nAutomatically promote to production (`myproj-prod`) using the same package<br \/>\nHandle environment naming conversion automatically<\/p>\n<p>Once configured, every push to the main branch will trigger the automated dev-to-prod promotion pipeline!<\/p>\n<h2>Conclusion<\/h2>\n<p>In summary, this pattern combines conditional Bicep deployment, package preservation, and smart environment naming to create reliable dev-to-prod promotions with the same build artifacts.<\/p>\n<p>Questions about implementation or want to share your own approach? Join the discussion <a href=\"https:\/\/github.com\/Azure\/azure-dev\/discussions\/5447\">here<\/a>.<\/p>\n<p>The post <a href=\"https:\/\/devblogs.microsoft.com\/devops\/azure-developer-cli-from-dev-to-prod-with-one-click\/\">Azure Developer CLI: From Dev to Prod with One Click<\/a> appeared first on <a href=\"https:\/\/devblogs.microsoft.com\/devops\">Azure DevOps Blog<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>This post walks through how to implement a \u201cbuild once, deploy everywhere\u201d pattern using Azure Developer CLI (azd) that provisions [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":94,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[3],"tags":[],"class_list":["post-2266","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure"],"_links":{"self":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/2266","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/comments?post=2266"}],"version-history":[{"count":0,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/2266\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media\/94"}],"wp:attachment":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media?parent=2266"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/categories?post=2266"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/tags?post=2266"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}