Как настроить приложение Python Dash для чтения из .env.development и .env.production при развертывании в Azure на основе развернутой среды?

Я создал веб-приложение Python Dash, которое имеет следующие файлы .env, .env.development и .env.production. И этот файл в настоящее время развертывается в Службе приложений Azure через файл CICD build&deploy.yml через Azure DevOps. Но я хочу реализовать так, чтобы при развертывании веб-приложения в среде DEV оно использовало файл .env.development, а при PROD env — файл .env.production. Кроме того, есть ли способ запустить локально, чтобы приложение получало значения из файлов .env.development и .env?

Программист React здесь, в React, это способ кодирования с точки зрения обработки среды. Есть какие-нибудь советы по разработке веб-приложений на Python с точки зрения обработки среды? И как решить проблему, о которой я говорил выше? Любая помощь или предложения будут очень полезны, спасибо!

Мой файл .env выглядит так:

REACT_VERSION=18.2.0

КАК я использую компоненты Dash Mantine (пакет из Dash), им необходимо создать файл .env со следующим значением.

.env.разработка:

ENVIRONMENT = "dev"

.env.производство:

ENVIRONMENT = "prod"

А это файл, который извлекает значения dev или prod (env.py):

from dotenv import load_dotenv
import os

load_dotenv()
environment = os.getenv('ENVIRONMENT')
print("ENV: ", environment)

В настоящее время, когда я запускаю это локально, он печатает: ENV: None

А это мой файл build&deploy.yml:

trigger: 
  branches:
    include:
      - main

pr:
  autoCancel: false
  branches:
     include:
      - develop
 
pool:
  vmImage: 'vm-pool-image'
 
variables:
  pythonVersion: '3.12' 
 
stages:
- stage: ArchiveArtifact
  jobs:
  - job:
    steps:
    - task: UsePythonVersion@0
      inputs:
        versionSpec: '$(pythonVersion)'
        addToPath: true

    - script: |
        sed 's/\${GITHUB_TOKEN}/'"$(GitHubToken)"'/' requirements.txt > temp_requirements.txt
        mv temp_requirements.txt requirements.txt
      displayName: 'Replace GitHub token in requirements.txt'
 
    - task: ArchiveFiles@2
      inputs:
        rootFolderOrFile: '$(Build.SourcesDirectory)'
        includeRootFolder: false
        archiveType: 'zip'
        archiveFile: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
        replaceExistingArchive: true
 
    - task: PublishBuildArtifacts@1
      inputs:
        PathtoPublish: '$(Build.ArtifactStagingDirectory)'
        ArtifactName: 'drop'
        publishLocation: 'Container'
 
- stage: DeployDev
  displayName: 'Deploy to Dev'
  dependsOn: ArchiveArtifact
  jobs:
  - deployment: DevDeploy
    pool: 'dev-agent-pool'
    environment: 'dev'
    strategy:
     runOnce:
       deploy:
        steps:
        - task: AzureWebApp@1
          inputs:
            azureSubscription: 'subscription'
            appType: 'webAppLinux'
            appName: 'web-app-dev-name'
            package: '$(Pipeline.Workspace)/drop/$(Build.BuildId).zip'
            deploymentMethod: 'auto'
            
- stage: DeployProd
  displayName: 'Deploy to Prod'
  dependsOn: DeployDev
  condition: and(succeeded(), or(eq(variables['Build.SourceBranch'], 'refs/heads/main') , eq(variables['Build.SourceBranch'], 'refs/heads/release/*')))
  jobs:
  - deployment: ProdDeploy
    pool: 'agent-pool'
    environment: 'prod'
    strategy:
     runOnce:
       deploy:
        steps:
        - task: AzureWebApp@1
          inputs:
            azureSubscription: 'prod_subscription'
            appType: 'webAppLinux'
            appName: 'web-app-prod-name'
            package: '$(Pipeline.Workspace)/drop/$(Build.BuildId).zip'
            deploymentMethod: 'auto'

Рассмотрите ли вы вместо этого использование переменных среды Службы приложений?

Alvin Zhao - MSFT 10.07.2024 12:03

Привет @JasonSusanto! Есть ли у вас возможность проверить ответы ниже, используя переменные среды в настройках приложения? Надеюсь, информация поможет решить ваш вопрос в этом посте. Спасибо и желаю вам хороших выходных.

Alvin Zhao - MSFT 12.07.2024 10:06

Привет @JasonSusanto! Могу ли я узнать, может ли какой-либо из приведенных ниже ответов использовать переменные среды в настройках приложения, чтобы помочь решить ваш запрос в этом посте. Спасибо.

Alvin Zhao - MSFT 15.07.2024 08:26
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
3
109
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Поскольку вы развертываете одни и те же артефакты в разных веб-приложениях, вы можете напрямую использовать os.getenv, чтобы получить значение переменных среды из настроек каждого приложения, а не из каждого .env файла в вашем репозитории.

Вот мой пример фрагмента кода для вашей справки.

@app.route("/env/")
def env():
    env = os.getenv('env', 'default_env')
    build = os.getenv('build', 'default_build')
    return render_template(
        "env.html",
        env=env,
        build=build
    )

окр.html

<!DOCTYPE html>
<html lang = "en">
<head>
    <meta charset = "UTF-8">
    <meta name = "viewport" content = "width=device-width, initial-scale=1.0">
    <title>Flask App</title>
</head>
<body>
    <h1>Welcome to the Flask App</h1>
    <p>Environment: {{ env }}</br>Build: {{ build }}</p>

</body>
</html>

Конвейер YAML для развертывания

- stage: CD
  jobs:
  - deployment: Deploy
    environment: E-Dev
    strategy:
      runOnce:
        deploy:
          steps:
          - task: AzureRmWebAppDeployment@4
            inputs:
              ConnectionType: 'AzureRM'
              azureSubscription: 'ARMSvcCnnSub0'
              appType: 'webAppLinux'
              WebAppName: '$(WebAppDev)'
              packageForLinux: '$(Pipeline.Workspace)/**/*.zip'
              AppSettings: >
                -env "dev"
                -build "$(Build.BuildId)"
                -PWD "$(SecretVar)"

Еще одним преимуществом является то, что мы можем передавать значения секретных переменных во время развертывания конвейера, не раскрывая такие значения в нашем коде.

По умолчанию load_dotenv() прочитает файл .env в вашем проекте.

есть ли способ запустить локально, и приложение получит значения из файлов .env.development и .env?

Да. Вы можете использовать следующий код Python:

load_dotenv('actual env file path')

env.py

from dotenv import load_dotenv
import os

load_dotenv()
load_dotenv('.env.development')

environment = os.getenv('ENVIRONMENT')
REACT_VERSION = os.getenv('REACT_VERSION')

print("ENV: ", environment)
print("REACT_VERSION: ", REACT_VERSION)

Результат:

Я хочу реализовать так, чтобы при развертывании веб-приложения в среде DEV оно использовало файл .env.development, а при PROD env использовало файл .env.production.

Чтобы удовлетворить ваши требования, вы можете установить настройки приложения в переменных среды веб-приложения (как рассказал Элвин в ответе), чтобы скрипт Python мог решить, какой файл .env загружать.

Вот пример:

env.py

from dotenv import load_dotenv
import os

load_dotenv()
APP_ENVIRONMENT = os.getenv("ENV") 
if APP_ENVIRONMENT == 'dev':
 load_dotenv('.env.development')
if APP_ENVIRONMENT == 'prod':
 load_dotenv('.env.production')
environment = os.getenv('ENVIRONMENT')
REACT_VERSION = os.getenv('REACT_VERSION')

print("ENV: ", environment)
print("REACT_VERSION: ", REACT_VERSION)

Вы можете вручную установить настройки приложения переменной ENV в разделе «Веб-приложение» -> «Переменные среды» -> «Настройки приложения».

Или вы можете установить его в задаче Pipeline Azure Web APP.

Например:

- task: AzureWebApp@1
  inputs:
    azureSubscription: 'subscription'
    appType: 'webAppLinux'
    appName: 'web-app-dev-name'
    package: '$(Pipeline.Workspace)/drop/$(Build.BuildId).zip'
    deploymentMethod: 'auto'
    appSettings: '-ENV dev'

Образец YAML:

stages:
- stage: ArchiveArtifact
  jobs:
  - job:
    steps:
    - task: UsePythonVersion@0
      inputs:
        versionSpec: '$(pythonVersion)'
        addToPath: true

    - script: |
        sed 's/\${GITHUB_TOKEN}/'"$(GitHubToken)"'/' requirements.txt > temp_requirements.txt
        mv temp_requirements.txt requirements.txt
      displayName: 'Replace GitHub token in requirements.txt'
 
    - task: ArchiveFiles@2
      inputs:
        rootFolderOrFile: '$(Build.SourcesDirectory)'
        includeRootFolder: false
        archiveType: 'zip'
        archiveFile: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
        replaceExistingArchive: true
 
    - task: PublishBuildArtifacts@1
      inputs:
        PathtoPublish: '$(Build.ArtifactStagingDirectory)'
        ArtifactName: 'drop'
        publishLocation: 'Container'
 
- stage: DeployDev
  displayName: 'Deploy to Dev'
  dependsOn: ArchiveArtifact
  jobs:
  - deployment: DevDeploy
    pool: 'dev-agent-pool'
    environment: 'dev'
    strategy:
     runOnce:
       deploy:
        steps:
        - task: AzureWebApp@1
          inputs:
            azureSubscription: 'subscription'
            appType: 'webAppLinux'
            appName: 'web-app-dev-name'
            package: '$(Pipeline.Workspace)/drop/$(Build.BuildId).zip'
            deploymentMethod: 'auto'
            appSettings: '-ENV dev'
            
- stage: DeployProd
  displayName: 'Deploy to Prod'
  dependsOn: DeployDev
  condition: and(succeeded(), or(eq(variables['Build.SourceBranch'], 'refs/heads/main') , eq(variables['Build.SourceBranch'], 'refs/heads/release/*')))
  jobs:
  - deployment: ProdDeploy
    pool: 'agent-pool'
    environment: 'prod'
    strategy:
     runOnce:
       deploy:
        steps:
        - task: AzureWebApp@1
          inputs:
            azureSubscription: 'prod_subscription'
            appType: 'webAppLinux'
            appName: 'web-app-prod-name'
            package: '$(Pipeline.Workspace)/drop/$(Build.BuildId).zip'
            deploymentMethod: 'auto'
            appSettings: '-ENV Prod'

Если в настройках приложения We APP для параметра ENV установлено значение dev, сценарий env.py будет читать файл .env.development. Или он прочитает файл .env.production.

Другие вопросы по теме