英文:
using shared dockerfile for multiple dockerfiles
问题
我所拥有的是多个相似且简单的dockerfile
。
但是我想要的是只有一个基础的dockerfile
,然后我的dockerfile
将它们的变量传递给基础的dockerfile
。
在我的情况下,dockerfile
之间唯一的区别就是它们的EXPOSE
指令,所以我认为最好保留一个基础的dockerfile
,然后其他的dockerfile
只需将变量注入到基础的dockerfile
中,就像一个模板引擎一样。
一个示例的dockerfile
:
FROM golang:1.17 AS builder
WORKDIR /app
COPY . .
RUN go mod download
RUN go build -o /bin/app ./cmd/root.go
FROM alpine:latest
WORKDIR /bin/
COPY --from=builder /bin/app .
EXPOSE 8080
LABEL org.opencontainers.image.source="https://github.com/mohammadne/bookman-auth"
ENTRYPOINT ["/bin/app"]
CMD ["server", "--env=dev"]
英文:
What I have, are multi similar and simple dockerfile
s
But what I want is to have a single base dockerfile
and my dockerfile
s
pass their variables into it.
In my case the only difference between dockerfile
s are
simply their EXPOSE
, so I think it's better to keep a base dockerfile
and other dockerfile
s only inject that variables into base dockerfile
like a template engine
A sample dockerfile
:
FROM golang:1.17 AS builder
WORKDIR /app
COPY . .
RUN go mod download
RUN go build -o /bin/app ./cmd/root.go
FROM alpine:latest
WORKDIR /bin/
COPY --from=builder /bin/app .
EXPOSE 8080
LABEL org.opencontainers.image.source="https://github.com/mohammadne/bookman-auth"
ENTRYPOINT ["/bin/app"]
CMD ["server", "--env=dev"]
答案1
得分: 5
IMPORT
指令将永远不会被实现
很久以前,有人提出了在Docker
中使用IMPORT
指令的建议。
不幸的是,这些问题已经关闭,但PR仍然是开放的:
- docker - 使用共享的Dockerfile用于多个Dockerfile - Stack Overflow
- 提案:Dockerfile添加INCLUDE · Issue #735 · moby/moby
- 为docker构建文件实现一个INCLUDE动词/指令 · Issue #974 · moby/moby
- 添加INCLUDE功能 · Issue #40165 · moby/moby
- docker build:关于include命令的初始工作 · Pull Request #2108 · moby/moby
- Dockerfile模板化以自动化镜像创建
- 像专家一样使用Dockerfile模板化!| 作者:Ahmed ElGamil | Dockbit
解决方案
但是对于你的情况,你只需要使用一点点sed
命令。
例如:
# 情况1:原地模板化
EXPOSED_PORT=8081 sed -i "s/EXPOSE 8080/EXPOSE $EXPOSED_PORT/" Dockerfile
# 情况2:从模板生成Dockerfile
sed "s/EXPOSE 8080/EXPOSE $EXPOSED_PORT/" Dockerfile.template > Dockerfile
解释:
EXPOSED_PORT=8081
声明了一个本地的bash
变量sed
是一个用于文本操作的工具sed -i "s/EXPOSE 8080/EXPOSE $EXPOSED_PORT/" Dockerfile
将Dockerfile
中的EXPOSE 8080
替换为EXPOSE 8081
sed "s/EXPOSE 8080/EXPOSE $EXPOSED_PORT/" Dockerfile.template > Dockerfile
从Dockerfile.template
生成新的Dockerfile
文件
英文:
IMPORT
directive will never be implemented
A long time ago there was proposed IMPORT
directive for Docker
Unfortunately, issues are closed while PR's are still open:
- docker - using shared dockerfile for multiple dockerfiles - Stack Overflow
- Proposal: Dockerfile add INCLUDE · Issue #735 · moby/moby
- implement an INCLUDE verb/instruction for docker build files · Issue #974 · moby/moby
- Add INCLUDE feature · Issue #40165 · moby/moby
- docker build: initial work on the include command by flavio · Pull Request #2108 · moby/moby
- Dockerfile templating to automate image creation
- Templating your Dockerfile like a boss! | by Ahmed ElGamil | Dockbit
Solution for your case
But for your case, all you need - is just a bit of sed
E.g.:
# Case1: inplace templating
EXPOSED_PORT=8081 sed -i "s/EXPOSE 8080/EXPOSE $EXPOSED_PORT/" Dockerfile
# Case2: generating Dockerfile from template
sed "s/EXPOSE 8080/EXPOSE $EXPOSED_PORT/" Dockerfile.template > Dockerfile
Explanation:
EXPOSED_PORT=8081
declares localbash
variablesed
is a tool for text manipulationsed -i "s/EXPOSE 8080/EXPOSE $EXPOSED_PORT/" Dockerfile
replacesEXPOSE 8080
toEXPOSE 8081
sed "s/EXPOSE 8080/EXPOSE $EXPOSED_PORT/" Dockerfile.template > Dockerfile
generates the newDockerfile
fromDockerfile.template
答案2
得分: 4
你可以将暴露的端口作为镜像的构建参数。如果你创建一个像这样的Dockerfile:
FROM alpine:latest
ARG EXPOSED_PORT
EXPOSE ${EXPOSED_PORT}
在构建镜像时,你可以通过传递端口号来指定要暴露的端口,例如:
docker build -t myimage --build-arg EXPOSED_PORT=8000 .
值得注意的是,EXPOSE语句主要是用于文档说明。即使没有EXPOSE语句,你的镜像也可以正常工作。
英文:
You can have the exposed port as a build argument for the image. If you make a dockerfile like this
FROM alpine:latest
ARG EXPOSED_PORT
EXPOSE ${EXPOSED_PORT}
You can specify which port is exposed when you build it by passing the port number like this
docker build -t myimage --build-arg EXPOSED_PORT=8000 .
It's worth noting that the EXPOSE statement mainly is documentation. Your image will work the same without the EXPOSE statement.
答案3
得分: 2
你有一个非常好的想法。我有两个想法:
- 按照你描述的方式创建基础的dockerfile,然后像这样构建它:
docker image build tag base
。然后你可以有两行的Dockerfile,看起来像是FROM base \n EXPOSE 8080
。 - 或者你可以只有一个Dockerfile,然后在运行容器的方式上进行更改。有一个
expose
开关,你可以在Dockerfile中指定的几乎任何东西都可以在run
命令中被覆盖。
英文:
You have a very good idea. I have two thoughts:
- Create the base dockerfile as you described and then build it like this:
docker image build tag base
. Then you can have two liner Dockerfiles that look likeFROM base \n EXPOSE 8080
- Alternatively you can have a single Dockerfile and just change the way you run the containers. There is an
expose
switch. Just about anything you specify in the Dockerfile can be overriden in therun
command.
答案4
得分: 2
根据yasen的说法,不可能有导入指令。
最后我所做的是如下所示:链接到GitHub存储库
- 创建一个带有
EXPOSE ${{ EXPOSED_PORT }}
的模板文本文件:
FROM golang:1.17 AS builder
WORKDIR /app
COPY . .
RUN go mod download && make ent-generate
RUN go build -o /bin/app ./cmd/root.go
FROM alpine:latest
WORKDIR /bin/
COPY --from=builder /bin/app .
EXPOSE ${{ EXPOSED_PORT }}
LABEL org.opencontainers.image.source="https://github.com/mohammadne/bookman-library"
ENTRYPOINT ["/bin/app"]
CMD ["server", "--env=dev"]
- 然后创建一个Python脚本
#!/usr/bin/python
from shutil import copyfile
import os
class Config:
def __init__(self, service, port):
self.service = service
self.port = port
configs = [
Config("auth", "8080"),
Config("user", "8081"),
Config("library", "8082"),
]
pathToDir = "../build"
template = f"{pathToDir}/template.txt"
for config in configs:
outputDir = f"{pathToDir}/{config.service}"
os.mkdir(outputDir)
fileName = copyfile(template, f"{outputDir}/Dockerfile")
with open(fileName, "rt") as file:
replacedText = file.read().replace('${{ EXPOSED_PORT }}', config.port)
with open(fileName, "wt") as file:
file.write(replacedText)
然后在Python脚本中,你可以替换你的模式!!!
英文:
as yasen said, it's impossible to have import directive.
finally what I have did is as follow: link to github repository
- create a template text file with
EXPOSE ${{ EXPOSED_PORT }}
:
FROM golang:1.17 AS builder
WORKDIR /app
COPY . .
RUN go mod download && make ent-generate
RUN go build -o /bin/app ./cmd/root.go
FROM alpine:latest
WORKDIR /bin/
COPY --from=builder /bin/app .
EXPOSE ${{ EXPOSED_PORT }}
LABEL org.opencontainers.image.source="https://github.com/mohammadne/bookman-library"
ENTRYPOINT ["/bin/app"]
CMD ["server", "--env=dev"]
- and then create a python script
#!/usr/bin/python
from shutil import copyfile
import os
class Config:
def __init__(self, service, port):
self.service = service
self.port = port
configs = [
Config("auth", "8080"),
Config("user", "8081"),
Config("library", "8082"),
]
pathToDir = "../build"
template = f"{pathToDir}/template.txt"
for config in configs:
outputDir = f"{pathToDir}/{config.service}"
os.mkdir(outputDir)
fileName = copyfile(template, f"{outputDir}/Dockerfile")
with open(fileName, "rt") as file:
replacedText = file.read().replace('${{ EXPOSED_PORT }}', config.port)
with open(fileName, "wt") as file:
file.write(replacedText)
then in the python script you can replace your patterns !!!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论