基于FROM scratch构建镜像:用户身份与权限排查问题求助
问题描述
目标是基于FROM scratch构建Docker镜像,需要:
- 通过
whoami查看容器执行用户 - 通过
ls -l检查文件权限
但遇到以下问题:
scratch镜像本身没有whoami、ls这类基础命令,尝试安装busybox失败- 虽然
scratch镜像支持USER指令,但无法指定有效用户
已尝试的操作:
- 在构建阶段创建非root用户
playerone,通过COPY --from=0 /etc/passwd /etc/passwd复制到scratch镜像层,再执行USER playerone - 下载
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 /mainRUN 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
相关产品推荐
相关产品推荐

