我有以下Dockerfile
ARG DEV_USER=dev
# Other stuff ...
USER $DEV_USER
# Other stuff ...
WORKDIR /home/$DEV_USER/Projects
当我启动一个容器并执行
ls /home/dev
时,Projects
文件夹归root
拥有。 WORKDIR是否忽略USER被较早调用的事实? 最佳答案
我没有找到详细的文档,但是对此我很感兴趣,所以我只是看看docker source code,我想我们可以从源代码中获得线索:
moby / builder / dockerfile / dispatcher.go(第299行):
// Set the working directory for future RUN/CMD/etc statements.
//
func dispatchWorkdir(d dispatchRequest, c *instructions.WorkdirCommand) error {
......
if err := d.builder.docker.ContainerCreateWorkdir(containerID); err != nil {
return err
}
return d.builder.commitContainer(d.state, containerID, runConfigWithCommentCmd)
}
在上面,我们可以看到它将调用
ContainerCreateWorkdir
,接下来是代码:moby / daemon / workdir.go:
func (daemon *Daemon) ContainerCreateWorkdir(cID string) error {
......
return container.SetupWorkingDirectory(daemon.idMapping.RootPair())
}
在上方,我们可以看到它叫做
SetupWorkingDirectory
,接下来是代码:moby / container / container.go(第259行):
func (container *Container) SetupWorkingDirectory(rootIdentity idtools.Identity) error {
......
if err := idtools.MkdirAllAndChownNew(pth, 0755, rootIdentity); err != nil {
pthInfo, err2 := os.Stat(pth)
if err2 == nil && pthInfo != nil && !pthInfo.IsDir() {
return errors.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir)
}
return err
}
return nil
}
在上方,我们可以看到它叫做
MkdirAllAndChownNew(pth, 0755, rootIdentity)
,接下来是代码:moby / pkg / idtools / idtools.go(第54行):
// MkdirAllAndChownNew creates a directory (include any along the path) and then modifies
// ownership ONLY of newly created directories to the requested uid/gid. If the
// directories along the path exist, no change of ownership will be performed
func MkdirAllAndChownNew(path string, mode os.FileMode, owner Identity) error {
return mkdirAs(path, mode, owner, true, false)
}
上面将在中间构建容器中设置文件夹,并使用
rootIdentity
更改文件夹的所有权。最后,这里的
rootIdentity
是什么?它以
daemon.idMapping.RootPair()
的形式传递到这里,接下来是声明:moby / pkg / idtools / idtools.go(第151行):
// RootPair returns a uid and gid pair for the root user. The error is ignored
// because a root user always exists, and the defaults are correct when the uid
// and gid maps are empty.
func (i *IdentityMapping) RootPair() Identity {
uid, gid, _ := GetRootUIDGID(i.uids, i.gids)
return Identity{UID: uid, GID: gid}
}
参见函数desc:
您可以继续查看
GetRootUIDGID
是什么,但是我认为现在从desc函数开始就足够了。最终它将使用将WORKDIR
的所有权更改为root
。而且,还要看看
USER
是做什么的?__moby/builder/dockerfile/dispatcher.go (Line 543):__
// USER foo
//
// Set the user to 'foo' for future commands and when running the
// ENTRYPOINT/CMD at container run time.
//
func dispatchUser(d dispatchRequest, c *instructions.UserCommand) error {
d.state.runConfig.User = c.User
return d.builder.commit(d.state, fmt.Sprintf("USER %v", c.User))
}
上面,仅将用户设置为运行config并直接提交进一步的命令,但与
WORKDIR
设置无关。而且,如果您想更改所有权,我想您将必须自己使用
chown
或RUN
中的ENTRYPOINT/CMD
来完成。