docker - Docker从文件中编写构建时间参数
问题描述
我知道可用的变量替换,我可以.env
在项目的根目录中使用 a 并且可以这样做,但在这种情况下,我正在调整现有项目,.env
预计现有文件位置并且我想防止必须在多个文件上有 var 条目!
有关更多信息,请参阅文档,所有代码都可以docker-support
在 repo 的分支上作为 WIP 获得,但我将在下面简洁地描述项目和问题:
项目结构
|- root
| |- .env # mongo and mongo-express vars (not on git!)
| |- docker-compose.yaml # build and ups a staging env
| |- docker-compose.prod.yaml # future wip
| |- api # the saas-api service
| |- Dockerfile # if 'docked' directly should build production
| |- .env # api relative vars (not on git!)
| |- app # the saas-app service
| |- Dockerfile # if 'docked' directly should build production
| |- .env # api relative vars (not on git!)
或者在这里查看整个内容,顺便说一下,它目前工作得很好,但是saas-app
在构建一个我迄今为止可以识别的用于登台/制作的图像时存在一个问题。
问题
在构建时 Next.js 使用 webpack 构建页面的静态版本来完成process.env
替换,因此它需要在 docker build 阶段包含实际最终运行的变量,因此 next.js 不需要在运行时再次重建,并且这样我就可以在流量需要时安全地生成多个实例!
我知道,如果在运行时没有发送相同的变量,它将不得不再次重建,这违背了本练习的重点,但这正是我在这里试图阻止的,如果发送了错误的值,它就在我们身上不是项目!
而且我还需要考虑 Next.js BUILD ID 管理,但这是另一个时间/问题。
尝试
我一直在测试在其Dockerfile上包含应用程序预期的每个变量的 ARG 和 ENV 声明,例如:
ARG GA_TRACKING_ID=
ENV GA_TRACKING_ID ${GA_TRACKING_ID}
这可以按预期工作,但是它迫使我在docker-compose.yml文件中手动声明它们,这并不理想:
saas-app:
build:
context: app
args:
GA_TRACKING_ID: UA-xXxXXXX-X
我不能在这里使用变量替换,因为我的根.env
不包含这个 var,它是 on ./app/.env
,而且我还测试了将值留空但它没有从env_file
orenviroment
定义中提取它,我相信这是预期的。
我已经使用存储库中的现有版本粘贴了完整输出:docker-compose config
理想情况下,我想:
saas-app:
build:
args:
LOG_LEVEL: notice
NODE_ENV: development
PORT: '3000'
context: /home/pedro/src/opensource/saas-boilerplate/app
command: yarn start
container_name: saas-app
depends_on:
- saas-api
environment:
...
成为:
saas-app:
build:
args:
LOG_LEVEL: notice
NODE_ENV: development
PORT: '3000'
BUCKET_FOR_POSTS: xxxxxx
BUCKET_FOR_TEAM_AVATARS: xxxxxx
GA_TRACKING_ID: ''
LAMBDA_API_ENDPOINT: xxxxxxapi
NODE_ENV: development
STRIPEPUBLISHABLEKEY: pk_test_xxxxxxxxxxxxxxx
URL_API: http://api.saas.localhost:8000
URL_APP: http://app.saas.localhost:3000
context: /home/pedro/src/opensource/saas-boilerplate/app
command: yarn start
container_name: saas-app
depends_on:
- saas-api
environment:
...
问题
如果可能的话,我将如何实现这一目标,但是:
- 无需将现有
.env
文件合并到单个根目录中,也无需在多个文件上复制 var。 - 无需手动声明撰写文件上的值,或者不必在命令上推断它们,例如
docker-compose build --build-arg GA_TRACKING_ID=UA-xXxXXXX-X
? - 无需在构建阶段
COPY
处理每个.env
文件,因为它感觉不正确和/或不安全? - 也许
args_file
对撰写团队的撰写build
选项功能请求在我看来是有效的,你也会这么说吗? .env
或者也许在撰写文件上有一个根选项,您可以在其中为变量替换设置多个文件?- 或者也许我没有看到另一个解决方案?有任何想法吗?
- 我不介意将每个
.env
文件作为config或secret发送,这是比拆分 compose 文件更清洁的解决方案,是否有人在生产中运行这样的示例?
解决方案
我已经设法实现了一种不影响任何现有开发工作流程的折衷方案,也不允许在没有环境变量的情况下构建应用程序(对于生产构建而言,这一要求更为重要)。
我基本上决定重用 docker 的内部能力来读取.env
文件并在 compose 文件上使用变量替换,这是一个例子:
# compose
COMPOSE_TAG_NAME=stage
# common to api and app (build and run)
LOG_LEVEL=notice
NODE_ENV=development
URL_APP=http://app.saas.localhost:3000
URL_API=http://api.saas.localhost:8000
API_PORT=8000
APP_PORT=3000
# api (run)
MONGO_URL=mongodb://saas:secret@saas-mongo:27017/saas
SESSION_NAME=saas.localhost.sid
SESSION_SECRET=3NvS3Cr3t!
COOKIE_DOMAIN=.saas.localhost
GOOGLE_CLIENTID=
GOOGLE_CLIENTSECRET=
AMAZON_ACCESSKEYID=
AMAZON_SECRETACCESSKEY=
EMAIL_SUPPORT_FROM_ADDRESS=
MAILCHIMP_API_KEY=
MAILCHIMP_REGION=
MAILCHIMP_SAAS_ALL_LIST_ID=
STRIPE_TEST_SECRETKEY=
STRIPE_LIVE_SECRETKEY=
STRIPE_TEST_PUBLISHABLEKEY=
STRIPE_LIVE_PUBLISHABLEKEY=
STRIPE_TEST_PLANID=
STRIPE_LIVE_PLANID=
STRIPE_LIVE_ENDPOINTSECRET=
# app (build and run)
STRIPEPUBLISHABLEKEY=
BUCKET_FOR_POSTS=
BUCKET_FOR_TEAM_AVATARS=
LAMBDA_API_ENDPOINT=
GA_TRACKING_ID=
查看更新的 docker-compose.yml我还使用了扩展字段来确保在构建和运行时只发送正确和有效的变量。
它打破了问题的规则 1.,但我觉得这是一个足够好的折衷方案,因为它不再依赖于其他.env
文件,无论如何这在大多数情况下都可能是开发密钥!
不幸的是,如果 vars 将来发生变化,我们将需要维护 compose 文件,并且必须将相同的.env
文件用于生产构建,但由于这可能会在某些 CI/CD 上在外部完成,所以不用担心。
我正在发布此问题,但并未完全解决问题,如果其他人可以提出更好的想法,我将不胜感激。
推荐阅读
- python - 确定 TD 标签内的类
- templates - 如何在样式范围内添加类?
- java - 性能与稍微干净的代码:在循环之前和循环期间检查属性
- react-native - 在导航器中的何处放置重置堆栈功能?
- node.js - 如何使用 node.js 和 MongoDB Atlas 删除数据库?
- php - 我的登录没有重定向到我在 PHP 中的索引
- typescript - 将 Typescript 的类型交集与可区分的联合使用时出现意外的类型错误
- mouseevent - 当我将鼠标悬停在 Wix 元素上时,它会打开和关闭吗?
- php - 无法为每个重新声明函数错误
- mdriven - 缺少 DisplayWecpofUI()