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

基于FROM scratch构建镜像:用户身份与权限排查问题求助

问题描述

目标是基于FROM scratch构建Docker镜像,需要:

  • 通过whoami查看容器执行用户
  • 通过ls -l检查文件权限

但遇到以下问题:

  • scratch镜像本身没有whoami、ls这类基础命令,尝试安装busybox失败
  • 虽然scratch镜像支持USER指令,但无法指定有效用户

已尝试的操作:

  1. 在构建阶段创建非root用户playerone,通过COPY --from=0 /etc/passwd /etc/passwd复制到scratch镜像层,再执行USER playerone
  2. 下载busybox二进制文件,设置ENTRYPOINT ["/busybox"]

执行后出现权限错误:

docker: Error response from daemon: failed to create shim: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "/busybox": permission denied: unknown

相关文件内容

Dockerfile

# syntax=docker/dockerfile:1

## Build
# Alpine is chosen for its small footprint
# compared to Ubuntu
FROM golang:1.19-alpine

WORKDIR /app

# Download necessary Go modules
COPY go.mod ./
# COPY go.sum ./
# RUN go mod download

COPY *.go ./

RUN go build -o /main

RUN adduser \
    -h "/dev/null" \
    -g "" \
    -s "/sbin/nologin" \
    -D \
    -H \
    -u 10001 \
    playerone

## Deploy
FROM scratch

WORKDIR /

COPY --from=0 /main /main

COPY --from=0 /etc/passwd /etc/passwd

USER playerone

ENTRYPOINT [ "/main" ]

main.go

package main

import "log"

func main() {
    log.Println("Hello World!")
}

go.mod

module github.com/kidfrom/learn-golang/docker-scratch

go 1.19

解决方案

1. 解决scratch镜像无基础命令的问题

scratch是完全空的镜像,没有任何系统二进制文件,直接用whoami、ls肯定不行,有两种可行方案:

方案一:在Go程序中直接输出所需信息

修改main.go,用Go标准库获取用户和文件权限信息,不需要依赖系统命令:

package main

import (
    "log"
    "os"
    "os/user"
)

func main() {
    // 获取当前用户信息
    u, err := user.Current()
    if err != nil {
        log.Fatalf("无法获取当前用户: %v", err)
    }
    log.Printf("当前用户: %s (UID: %s)", u.Username, u.Uid)

    // 检查/main文件权限
    fileInfo, err := os.Stat("/main")
    if err != nil {
        log.Fatalf("无法获取文件信息: %v", err)
    }
    log.Printf("/main 文件权限: %s", fileInfo.Mode().String())

    log.Println("Hello World!")
}

重新构建镜像后运行,就能直接看到用户和权限信息,完全不需要额外工具。

方案二:复制静态编译版busybox到镜像

scratch没有动态链接库,必须用静态编译的busybox。在构建阶段添加获取并处理busybox的步骤:

## Build
FROM golang:1.19-alpine

# 安装curl并下载静态编译的busybox,添加执行权限
RUN apk add --no-cache curl && \
    curl -L https://busybox.net/downloads/binaries/1.35.0-x86_64-linux-musl/busybox -o /busybox && \
    chmod +x /busybox

# 其余构建步骤不变...

## Deploy
FROM scratch

COPY --from=0 /main /main
COPY --from=0 /busybox /busybox
COPY --from=0 /etc/passwd /etc/passwd

USER playerone

# 通过busybox执行命令后再运行主程序
ENTRYPOINT ["/busybox", "sh", "-c", "whoami && ls -l /main && /main"]

你之前遇到的权限错误,就是因为复制的busybox没有添加可执行权限,加上chmod +x就能解决。

2. 确保USER指令在scratch中生效

你的现有Dockerfile复制/etc/passwd的方式是对的,但要注意两个细节:

  • 确认构建阶段创建的playerone用户确实在复制的/etc/passwd里
  • 给/main添加普通用户可执行的权限,在构建阶段的go build后加chmod命令:
    RUN go build -o /main && \
        chmod 755 /main
    
    或者更严格的权限设置:
    RUN go build -o /main && \
        chown playerone:playerone /main && \
        chmod 700 /main
    

3. 验证镜像运行

修改后重新构建:

docker build -t scratch-go .

运行容器:

docker run --rm scratch-go

如果是修改Go程序的方案,会输出用户信息、文件权限和Hello World;如果是用busybox的方案,会先输出用户名、文件列表,再输出Hello World。

内容的提问来源于stack exchange,提问作者Jason Rich Darmawan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 15:30:43