You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Groovy的de.gesellix docker-client构建Docker镜像?

如何使用Groovy的de.gesellix docker-client构建Docker镜像?

我来帮你排查这个问题~你遇到的{"message":"unexpected EOF"}错误,核心原因是直接传递Dockerfile的输入流不符合Docker远程API的要求——Docker构建镜像时需要的是包含Dockerfile的上下文tar归档流,而不是单独的Dockerfile文本流。咱们一步步调整代码来解决:

1. 理解问题根源

Docker的Build API接收的是整个构建上下文的压缩包(通常是tar格式),这个上下文里包含Dockerfile以及构建过程中需要的所有文件(比如拷贝到镜像里的本地文件)。你之前直接传了Dockerfile的文本流,客户端解析时自然会因为格式不对报“意外EOF”。

2. 修正代码的两种方式

方式一:用临时目录作为构建上下文(最简单)

我们可以把Dockerfile写入临时目录,让客户端自动处理上下文的打包:

#!/usr/bin/env groovy
@Grapes(
    [
        @Grab(group='de.gesellix', module='docker-client', version='2025-01-19T00-00-00'),
        @Grab(group='commons-io', module='commons-io', version='2.18.0'),
    ]
)
import de.gesellix.docker.remote.api.BuildInfo
import de.gesellix.docker.remote.api.BuildImageRequest
import de.gesellix.docker.remote.api.core.StreamCallback
import de.gesellix.docker.client.DockerClientImpl
import java.nio.charset.StandardCharsets

void buildTestContainer() {

    def dockerBuildStr = """FROM ubuntu:25.04
RUN env DEBIAN_FRONTEND=noninteractive apt update && apt install -y curl python3-pyqt6 libmpv-dev python3-pycodestyle xvfb
RUN curl -LsSf https://astral.sh/uv/install.sh | env XDG_BIN_HOME=/bin sh
""".stripIndent()

    // 创建临时目录并写入Dockerfile
    def tempDir = File.createTempDir()
    def dockerFile = new File(tempDir, "Dockerfile")
    dockerFile.text = dockerBuildStr

    def dockerClient = new DockerClientImpl()
    println(dockerClient.images())
    println(dockerClient.ping().content)

    // 构建请求配置,可添加标签等参数
    def buildRequest = new BuildImageRequest()
    buildRequest.setTags(["my-test-image:latest"])

    // 使用临时目录作为上下文执行构建
    dockerClient.build(new StreamCallback<BuildInfo>() {
        @Override
        void onNext(BuildInfo buildInfo) {
            println(buildInfo)
        }
    },
        java.time.Duration.ofDays(1),
        buildRequest,
        tempDir
    )

    // 清理临时目录(可选)
    tempDir.deleteDir()
}

buildTestContainer()

方式二:手动打包Dockerfile为tar流(适合无文件系统场景)

如果不能创建临时目录,我们可以手动把Dockerfile打包成tar流传给客户端:

#!/usr/bin/env groovy
@Grapes(
    [
        @Grab(group='de.gesellix', module='docker-client', version='2025-01-19T00-00-00'),
        @Grab(group='commons-io', module='commons-io', version='2.18.0'),
        @Grab(group='org.apache.commons', module='commons-compress', version='1.26.1'),
    ]
)
import de.gesellix.docker.remote.api.BuildInfo
import de.gesellix.docker.remote.api.BuildImageRequest
import de.gesellix.docker.remote.api.core.StreamCallback
import de.gesellix.docker.client.DockerClientImpl
import org.apache.commons.compress.archivers.tar.TarArchiveEntry
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream
import java.nio.charset.StandardCharsets

void buildTestContainer() {

    def dockerBuildStr = """FROM ubuntu:25.04
RUN env DEBIAN_FRONTEND=noninteractive apt update && apt install -y curl python3-pyqt6 libmpv-dev python3-pycodestyle xvfb
RUN curl -LsSf https://astral.sh/uv/install.sh | env XDG_BIN_HOME=/bin sh
""".stripIndent()

    // 手动将Dockerfile打包为tar流
    def baos = new ByteArrayOutputStream()
    def tarOut = new TarArchiveOutputStream(baos)
    tarOut.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX)

    def entry = new TarArchiveEntry("Dockerfile")
    entry.setSize(dockerBuildStr.getBytes(StandardCharsets.UTF_8).length)
    tarOut.putArchiveEntry(entry)
    tarOut.write(dockerBuildStr.getBytes(StandardCharsets.UTF_8))
    tarOut.closeArchiveEntry()
    tarOut.close()

    def contextStream = new ByteArrayInputStream(baos.toByteArray())

    def dockerClient = new DockerClientImpl()
    println(dockerClient.images())
    println(dockerClient.ping().content)

    def buildRequest = new BuildImageRequest()
    buildRequest.setTags(["my-test-image:latest"])

    dockerClient.build(new StreamCallback<BuildInfo>() {
        @Override
        void onNext(BuildInfo buildInfo) {
            println(buildInfo)
        }
    },
        java.time.Duration.ofDays(1),
        buildRequest,
        contextStream
    )
}

buildTestContainer()

3. 额外注意点

  • 确保Dockerfile的语法正确:你的Dockerfile里的命令已经用stripIndent()处理了缩进,没问题,但要注意&&连接命令的格式(你已经写对了)。
  • 可以在BuildImageRequest里添加更多参数,比如setBuildArgs()传递构建参数,setPull(true)强制拉取基础镜像等。

备注:内容来源于stack exchange,提问作者djsumdog

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 09:53:07