docker - 多个 Dockerfile 在项目中重用共享库

标签 docker dockerfile

我有以下代码结构,我正在尝试构建我的 Dockerfile 以最大化缓存等。

serverfoo/
    Dockerfile
    main.go

serverbar/
    Dockerfile
    main.go

proto/
    Dockerfile
    sharedproto.proto // Generates a sharedproto.pb.go file to be imported.

两个serverfooserverbar导入编译好的sharedproto.pb.go我在工作站上手动重新生成的文件。这工作正常,但现在我正在尝试将我的两台服务器容器化。

我的服务器文件夹的 Dockerfiles 不能(默认)复制 proto/内容。理想情况下,我将 protobuf 预编译为 sharedproto.pb.go然后将该文件的缓存版本导入两个服务器 Dockerfile。目标是缓存已编译的 protobuf,直到底层 proto 被修改。

我是 Docker 新手,需要一些此类事情的最佳实践。我想避免根 Dockerfile在我的项目目录中,它只有代码来编译无数不同的服务器。

我愿意在某种程度上重组我的项目。

最佳答案

NOTE: I suppose your target is to have on the specific server container both the compiled go file ( from specific main.go file ) and the compiled protocol buffer file ( from shared sharedproto.proto file ).



假设您的文件在您的工作站上按如下方式组织:
serverfoo/
   Dockerfile
   main.go

serverbar/
   Dockerfile
   main.go

proto/
   Dockerfile
   sharedproto.proto

您可以使用多阶段构建来构建特定的服务器 Dockerfile,如下所示(例如 serverbar Dockerfile ):
#####
# The serverbar Dockerfile
#####

#----
# Compile proto stage
#----
FROM moul/protoc-gen-gotemplate AS protostage
WORKDIR /workspace
# Copy .proto file
COPY proto/sharedproto.proto .
# Compile .pb.go
RUN protoc -I=. --go_out=. sharedproto.proto

#----
# Build stage
#----
FROM golang:1.12.4-alpine3.9 as buildstage
WORKDIR /workspace
COPY serverbar/main.go .
RUN GOOS=linux GOARCH=amd64 go build -o serverbar main.go

#----
# Final stage
#----
FROM alpine:3.7
WORKDIR /home
COPY --from=buildstage workspace/serverbar .
COPY --from=protostage workspace/sharedproto.pb.go .
CMD ["./serverbar"]

使用这种方法,您基本上有以下 3 个阶段:
  • 原型(prototype)阶段 : 在这个阶段创建的容器上,你需要将共享的protocol buffer源文件编译成 sharedproto.pb.go 然后将包括在第三个最后阶段。所以在这里你需要在容器上安装 协议(protocol) 编译器和相关的 Go 插件。但是,与 Docker 一样,您会找到一个已包含所需工具的 docker 镜像。为此,我们可以从 开始。 moul/protoc-gen-gotemplate docker 形象。
    具体来说,遵循 Dockerfile 指令会生成 工作区/sharedproto.pb.go :
      RUN protoc -I=. --go_out=. sharedproto.proto
    
  • 构建阶段 : 这里需要将服务器源文件编译成可执行文件。这也将包括在第三个最后阶段。为了避免安装 Golang,我们可以从 开始。 golang:1.12.4-alpine3.9 docker 镜像已经包含了所有需要的工具。
    具体来说,遵循 Dockerfile 指令会生成 工作区/服务器栏 可执行:
      RUN GOOS=linux GOARCH=amd64 go build -o serverbar main.go
    
  • 最后阶段 :这是服务器容器,我们将上传到我们的 Docker 注册表以进行测试或生产,我们将使用以下命令复制在前两个阶段编译的文件:
      COPY --from=buildstage workspace/serverbar .
      COPY --from=protostage workspace/sharedproto.pb.go .
    


  • 此解决方案的优点之一是,对于每个服务器构建,您可以缓存已编译的 protobuf,直到修改底层 proto。

    示例:
    第一次 build 服务器栏 container 我们可以注意到 .proto 编译是在一个 ID 为 的新容器上执行的。 92ae211bd27d :
    > docker build -f serverbar/Dockerfile .
    Sending build context to Docker daemon  10.24kB
    Step 1/13 : FROM moul/protoc-gen-gotemplate AS protostage
     ---> 635345fde953
    Step 2/13 : WORKDIR /workspace
     ---> Using cache
     ---> de8890a5e775
    Step 3/13 : COPY proto/sharedproto.proto .
     ---> 1253fa0576aa
    Step 4/13 : RUN protoc -I=. --go_out=. sharedproto.proto
     ---> Running in 8426f5810b98 
    Removing intermediate container 8426f5810b98
     ---> 92ae211bd27d <=========================================
    Step 5/13 : FROM golang:1.12.4-alpine3.9 as buildstage
     ---> b97a72b8e97d
    Step 6/13 : WORKDIR /workspace
    
    ....
    

    然后在不修改 sharedproto.proto 的情况下再次构建,我们可以注意到 ID 为 的容器92ae211bd27d 从缓存中重复使用。
    > docker build -f serverbar/Dockerfile .
    Sending build context to Docker daemon  10.24kB
    Step 1/13 : FROM moul/protoc-gen-gotemplate AS protostage
     ---> 635345fde953
    Step 2/13 : WORKDIR /workspace
     ---> Using cache
     ---> de8890a5e775
    Step 3/13 : COPY proto/sharedproto.proto .
     ---> Using cache
     ---> 1253fa0576aa
    Step 4/13 : RUN protoc -I=. --go_out=. sharedproto.proto
     ---> Using cache <=========================================
     ---> 92ae211bd27d
    Step 5/13 : FROM golang:1.12.4-alpine3.9 as buildstage
     ---> b97a72b8e97d
    
    ....
    

    关于docker - 多个 Dockerfile 在项目中重用共享库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59819333/

    相关文章:

    docker - 为什么我的cron(tinycron)有时执行两次命令?

    docker - 我在 docker hub 上用于导入 ACR 的图像源 URL 是什么

    python - Docker - "127.0.0.1"不是有效端口 - Django

    python - Docker:没有这样的选项:--use-wheel

    Dockerfile apt-get install - 503 服务不可用

    linux - 在 docker-compose 命令中使用内联注释

    python - 如何在AWS ECS上的Flask/MongoDB中设置环境变量?

    docker - 使用 Ansible 部署 docker 时如何设置运行参数?

    postgresql - Codenvy添加postgresql到项目报错

    spring - Docker Compose + Spring Boot + Postgres 连接