我使用远程容器作为我的开发环境。所以本质上在我的项目中我有一个 Dockerfile、docker-compose.yml 和我的 devcontainer.json,vscode 使用它们来构建、启动和启动到安装了我的代码的容器中。到目前为止效果很好。
问题是,在 Linux 主机上,如果执行 docker ps,我会看到我的单个容器,但如果查看 docker 镜像,会创建两个容器,最后一个是启动的容器。
我的 docker-compose 看起来像这样:
app:
container_name: my_app
build:
context: ..
dockerfile: .devcontainer/Dockerfile
volumes:
- ../..:/workspaces:cached
我的 .devcontainer.json 看起来像这样:
"name": "my_app_service",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
"customizations": {
"vscode": {
"extensions": ["ms-python.python"]
},
"settings": {
"terminal.integrated.shell.*": "/bin/bash"
}
}
docker ps 显示单个容器正在运行:
container name: my_app
image: vsc-my_proj-64ad9a6809f39eaa523af6a319f22b90b2d1358fe3a8aebc93ac1dfaebf5f22a-uid
docker images 显示了创建的两个镜像,其名称为:
REPOSITORY: my_app_devcontainer-app
REPOSITORY: vsc-my_proj-64ad9a6809f39eaa523af6a319f22b90b2d1358fe3a8aebc93ac1dfaebf5f22a-uid
(请注意,上面的“my_proj”部分图像名称来 self 的 vscode 项目文件夹名称。) 我可以删除第一张图片。但我想了解为什么会发生这种情况?看起来不应该——它几乎就像构建发生了两次。 另外,有没有办法使用 docker-compose 指定图像名称,或者在 vscode 中使用 devcontainer.json (我知道如何从 docker-build 命令行参数执行此操作)。
感谢您帮助解决这个问题
最佳答案
我也想知道同样的事情,所以我做了以下事情:
步骤
- 我打印了图像历史记录,只打印了显示实际 docker 文件语句的列。请参阅https://docs.docker.com/config/formatting/和 https://docs.docker.com/engine/reference/commandline/history/
docker image history PUTIMAGE_HASH_HERE_FOR_IMAGE_NOT_ENDING_IN_UID --no-trunc --format "table {{.CreatedBy}}" > image_wo_uid.txt
docker image history PUTIMAGE_HASH_HERE_FOR_IMAGE_WITH_UID_AT_END --no-trunc --format "table {{.CreatedBy}}" > image_uid.txt
然后比较两者:
diff image_wo_uid.txt image_uid.txt
这会给你类似的东西(注意:按时间顺序倒序):
1a2,9
> USER vscode
> ARG IMAGE_USER
> RUN |3 REMOTE_USER=vscode NEW_UID=1000 NEW_GID=1000 /bin/sh -c eval $(sed -n "s/${REMOTE_USER}:[^:]*:\([^:]*\):\([^:]*\):[^:]*:\([^:]*\).*/OLD_UID=\1;OLD_GID=\2;HOME_FOLDER=\3/p" /etc/passwd); eval $(sed -n "s/\([^:]*\):[^:]*:${NEW_UID}:.*/EXISTING_USER=\1/p" /etc/passwd); eval $(sed -n "s/\([^:]*\):[^:]*:${NEW_GID}:.*/EXISTING_GROUP=\1/p" /etc/group); if [ -z "$OLD_UID" ]; then echo "Remote user not found in /etc/passwd ($REMOTE_USER)."; elif [ "$OLD_UID" = "$NEW_UID" -a "$OLD_GID" = "$NEW_GID" ]; then echo "UIDs and GIDs are the same ($NEW_UID:$NEW_GID)."; elif [ "$OLD_UID" != "$NEW_UID" -a -n "$EXISTING_USER" ]; then echo "User with UID exists ($EXISTING_USER=$NEW_UID)."; elif [ "$OLD_GID" != "$NEW_GID" -a -n "$EXISTING_GROUP" ]; then echo "Group with GID exists ($EXISTING_GROUP=$NEW_GID)."; else echo "Updating UID:GID from $OLD_UID:$OLD_GID to $NEW_UID:$NEW_GID."; sed -i -e "s/\(${REMOTE_USER}:[^:]*:\)[^:]*:[^:]*/\1${NEW_UID}:${NEW_GID}/" /etc/passwd; if [ "$OLD_GID" != "$NEW_GID" ]; then sed -i -e "s/\([^:]*:[^:]*:\)${OLD_GID}:/\1${NEW_GID}:/" /etc/group; fi; chown -R $NEW_UID:$NEW_GID $HOME_FOLDER; fi; # buildkit
> SHELL [/bin/sh -c]
> ARG NEW_GID
> ARG NEW_UID
> ARG REMOTE_USER
> USER root
结论
- 以 uid 结尾的镜像正在采取额外措施来保证 uid 和 guid 均为 1000(请参阅长 RUN 语句)。如果 1000 处已存在另一个用户/组,它有一堆错误处理来输出错误。
- 我猜测 devcontainer 程序员这样做是因为他们无法确定正在使用什么基本镜像,因此 USER vscode 的 uid/guid 可能不是 1000/1000。
注释
- 详细信息可能因 Linux 发行版而异(我认为),但基本上,如果您保证您的用户 ID/组 ID 为 1000 或以上,那么您就处于“非系统用户”(=常规用户)uid 空间。讨论示例:https://ubuntuforums.org/showthread.php?t=1740376
- 有些人建议改为 10000,而不是 1000,这样可以降低在 1000 范围内遇到现有用户的可能性,这种情况很有可能发生,因为第一个非系统用户将会 如果不采取其他步骤,则为 1000。讨论示例:https://news.ycombinator.com/item?id=25621610
- 我不确定为什么额外的代码不首先确定 1000 以上的第一个可用 uids/guid 并使用它们而不是 1000,以防万一 1000 已被占用。
关于docker - vscode devcontainers - 为什么构建两个图像?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75915194/