英文:
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 dockerfiles
But what I want is to have a single base dockerfile and my dockerfiles
pass their variables into it.
In my case the only difference between dockerfiles are
simply their EXPOSE, so I think it's better to keep a base dockerfile and other dockerfiles 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 8081sed "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=8081declares localbashvariablesedis a tool for text manipulationsed -i "s/EXPOSE 8080/EXPOSE $EXPOSED_PORT/" DockerfilereplacesEXPOSE 8080toEXPOSE 8081sed "s/EXPOSE 8080/EXPOSE $EXPOSED_PORT/" Dockerfile.template > Dockerfilegenerates the newDockerfilefromDockerfile.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
exposeswitch. Just about anything you specify in the Dockerfile can be overriden in theruncommand.
答案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 !!!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论