Я создал веб-приложение 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'
Привет @JasonSusanto! Есть ли у вас возможность проверить ответы ниже, используя переменные среды в настройках приложения? Надеюсь, информация поможет решить ваш вопрос в этом посте. Спасибо и желаю вам хороших выходных.
Привет @JasonSusanto! Могу ли я узнать, может ли какой-либо из приведенных ниже ответов использовать переменные среды в настройках приложения, чтобы помочь решить ваш запрос в этом посте. Спасибо.
Поскольку вы развертываете одни и те же артефакты в разных веб-приложениях, вы можете напрямую использовать 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
.
Рассмотрите ли вы вместо этого использование переменных среды Службы приложений?