Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

The ${localEnv:UID} is not expanded in devcontainer.json so Dockerfile can't use a custom UID/GID during build time #6834

Closed
astaruch opened this issue Jun 16, 2022 · 4 comments
Assignees
Labels
containers Issue in vscode-remote containers info-needed Issue requires more information from poster

Comments

@astaruch
Copy link

astaruch commented Jun 16, 2022

I have a following shortened Dockerfile:

FROM ubuntu:bionic-20210723

ARG USERNAME=dev
ARG PUID=1001
ARG PGID=1001

RUN set -x && groupadd --gid $PGID ${USERNAME} && \
    useradd --no-log-init --gid $PGID --create-home --shell /bin/bash --uid $PUID ${USERNAME} && \
    echo "${USERNAME}:${USERNAME}" | chpasswd

USER ${USERNAME}

WORKDIR /home/${USERNAME}

COPY --chown=${USERNAME}:${USERNAME} file.txt /opt/dir/

Then I am building it locally with the current user UID/GID:

docker build --build-arg=PUID="$(id --user)" --build-arg=PGID="$(id --group)" --tag "test-image:latest" --file Dockerfile .

And then /opt/dir has expected file permissions and dev has expeceted ID/GID:

fk300661@vec-002v:/tmp/docker$ docker run -it --rm test-image bash
dev@33f24f68da68:~$ ls -l /
.dockerenv  boot/       etc/        lib/        media/      opt/        root/       sbin/       sys/        usr/
bin/        dev/        home/       lib64/      mnt/        proc/       run/        srv/        tmp/        var/
dev@33f24f68da68:~$ ls -l /opt/dir/
total 0
-rw-r--r-- 1 dev dev 0 Jun 16 16:06 file.txt
dev@33f24f68da68:~$ id dev
uid=819704580(dev) gid=1656600513(dev) groups=1656600513(dev)

So far so good.

When I want to use the VS Code and utilize the Remote Containers, I go into the troubles. If I don't pass PID/GID, I can't operate on these files. Here is my devcontainer.json:

// 	 For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.234.0/containers/docker-existing-dockerfile
{
	"name": "Existing Dockerfile",

	// Sets the run context to one level up instead of the .devcontainer folder.
	"context": "..",

	// Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename.
	"dockerFile": "../Dockerfile",

	// Set *default* container specific settings.json values on container create.
	"settings": {}

}

I am there not able to create files in the directory where I want:

dev@c31a51b20738:/opt/dir$ cd /opt/dir/
dev@c31a51b20738:/opt/dir$ id
uid=819704580(dev) gid=1656600513(dev) groups=1656600513(dev)
dev@c31a51b20738:/opt/dir$ ls -l
total 0
-rw-r--r-- 1 1001 1001 0 Jun 16 16:06 file.txt
dev@c31a51b20738:/opt/dir$ touch new_file.txt
touch: cannot touch 'new_file.txt': Permission denied

It is because remapping of the UID/GID happened:

3975 ms] Start: Run: docker build -f /tmp/vsch/updateUID.Dockerfile-0.238.2 -t vsc-docker-106e1b2a28651184b5b20203111b59f3-uid --build-arg BASE_IMAGE=vsc-docker-106e1b2a28651184b5b20203111b59f3 --build-arg REMOTE_USER=dev --build-arg NEW_UID=819704580 --build-arg NEW_GID=1656600513 --build-arg IMAGE_USER=dev /tmp/vsch
Sending build context to Docker daemon   5.12kB
Step 1/10 : ARG BASE_IMAGE
Step 2/10 : FROM $BASE_IMAGE
 ---> 6581b43e7b70
Step 3/10 : USER root
 ---> Running in 41c1af5a994e
Removing intermediate container 41c1af5a994e
 ---> ea7662ca72e3
Step 4/10 : ARG REMOTE_USER
 ---> Running in 5bafb4f2005e
Removing intermediate container 5bafb4f2005e
 ---> b2922b7f28ec
Step 5/10 : ARG NEW_UID
 ---> Running in 8fb748040e60
Removing intermediate container 8fb748040e60
 ---> 7d40f48e6a3f
Step 6/10 : ARG NEW_GID
 ---> Running in 8ed1eaed61a0
Removing intermediate container 8ed1eaed61a0
 ---> 62257c11e00b
Step 7/10 : SHELL ["/bin/sh", "-c"]
 ---> Running in 06ef976f7b06
Removing intermediate container 06ef976f7b06
 ---> 05992923057a
Step 8/10 : RUN 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;
 ---> Running in 9dfd9ab67983
Updating UID:GID from 1001:1001 to 819704580:1656600513.
Removing intermediate container 9dfd9ab67983
 ---> 815ca284e384
Step 9/10 : ARG IMAGE_USER
 ---> Running in ce1bc8f89610
Removing intermediate container ce1bc8f89610
 ---> 6ea133941eb5
Step 10/10 : USER $IMAGE_USER
 ---> Running in 287a997e590b
Removing intermediate container 287a997e590b
 ---> 28aa4430f135

If I disable the remapping via updateRemoteUserUID: false, I can't write into the workspace inside the Docker container (apart from the previously created /opt/dir).

What would solve this problem is using a build arguments (build.args) in the devcontainer.json. There exists a bash variable UID:

$ echo $UID
819704580

$ man bash

       UID    Expands to the user ID of the current user, initialized at shell startup.  This variable is readonly.

So I was hoping for a following to work:

// 	 For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.234.0/containers/docker-existing-dockerfile
{
	"name": "Existing Dockerfile",

	// Sets the run context to one level up instead of the .devcontainer folder.
	"context": "..",

	// Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename.
	"dockerFile": "../Dockerfile",

	// Set *default* container specific settings.json values on container create.
	"settings": {},

	"build": {
		"args": {
			"PUID": "${localEnv:UID}"
		}
	}

}

But sadly, it is an empty variable and thus building the Docker for Remote Container fails:

 > [2/4] RUN set -x && groupadd --gid 1001 dev &&     useradd --no-log-init --gid 1001 --create-home --shell /bin/bash --uid  dev &&     echo "dev:dev" | chpasswd:
#0 0.240 + groupadd --gid 1001 dev
#0 0.264 + useradd --no-log-init --gid 1001 --create-home --shell /bin/bash --uid dev
#0 0.271 useradd: invalid user ID 'dev'
------
error: failed to solve: executor failed running [/bin/sh -c set -x && groupadd --gid $PGID ${USERNAME} &&     useradd --no-log-init --gid $PGID --create-home --shell /bin/bash --uid $PUID ${USERNAME} &&     echo "${USERNAME}:${USERNAME}" | chpasswd]: exit code: 3

My problem would be solved be either a new VS Code variable, that will hold a current user UID/GID, so I can just use build.args with "PUID": "${VS_CODE_NEW_VARIABLE_FOR_UID}".

Or what am I doing wrong, that localEnv:UID is not working in the VS Code?

When I try to use localEnv:USER, then it gets the right environment value (but of course it fails on the build, since it is the name of user, and not UID), so how can I access the UID?

I have tried modyfing my ~/.bashrc with something like export VS_CODE_WORKAROUND_UID=$(id --user). Then sourcing it and reloading the VS Code and I can see that it is in the environment:

export | grep VS_CODE
declare -x VS_CODE_WORKAROUND_UID="819704580"

But ${localEnv:VS_CODE_WORKAROUND_UID} is still empty.

Thanks

  • VSCode Version: 1.66.2
  • Local OS Version: Windows 10
  • Remote OS Version: Ubuntu 18.04
  • Remote Extension/Connection Type: SSH + Containers

Does this issue occur when you try this locally?: Yes/No
Does this issue occur when you try this locally and all extensions are disabled?: Yes/No

@astaruch
Copy link
Author

astaruch commented Jun 16, 2022

One workaround is following:

  1. Install sudo inside Docker
  2. Add a ${USERNAME} into the sudoers
  3. Add password-less sudo commands for a ${USERNAME}
  4. Change file permissions after container startup via postAttachCommand and change it to the desired user (but since it is without shell, I can't use $USER and need to hardcode a user).

So it can be following the setup:

FROM ubuntu:bionic-20210723

ARG USERNAME=dev
ARG PUID=1001
ARG PGID=1001

RUN apt-get update && \
    apt-get install --yes sudo  && \
    rm -rf /var/lib/apt/lists/

RUN set -x && groupadd --gid $PGID ${USERNAME} && \
    useradd --no-log-init --gid $PGID --create-home --shell /bin/bash --uid $PUID ${USERNAME}  --groups sudo && \
    echo "${USERNAME}:${USERNAME}" | chpasswd && \
    echo "${USERNAME} ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/${USERNAME}

USER ${USERNAME}

WORKDIR /home/${USERNAME}

COPY --chown=${USERNAME}:${USERNAME} file.txt /opt/dir/

devcontainer.json:

//       For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.234.0/containers/docker-existing-dockerfile
{
        "name": "Existing Dockerfile",

        // Sets the run context to one level up instead of the .devcontainer folder.
        "context": "..",

        // Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename.
        "dockerFile": "../Dockerfile",

        // Set *default* container specific settings.json values on container create.
        "settings": {},

        "postAttachCommand": "sudo chown -R dev:dev /opt/dir/"

}

Seems like a hacky solution, but works:

dev@50d7a92a7123:/workspaces/docker$ cd /opt/dir/
dev@50d7a92a7123:/opt/dir$ id
uid=819704580(dev) gid=1656600513(dev) groups=1656600513(dev),27(sudo)
dev@50d7a92a7123:/opt/dir$ touch new_file.txt
dev@50d7a92a7123:/opt/dir$ ls -l
total 0
-rw-r--r-- 1 dev dev 0 Jun 16 16:06 file.txt
-rw-r--r-- 1 dev dev 0 Jun 16 16:52 new_file.txt
dev@50d7a92a7123:/opt/dir$ 

@github-actions github-actions bot added the containers Issue in vscode-remote containers label Jun 16, 2022
@chrmarti
Copy link
Contributor

UID is not exported by bash. Try exporting it in .bashrc or .bash_profile and make sure you restart VS Code completely (close all its windows) to let it read the environment variables again.

@chrmarti chrmarti self-assigned this Jun 17, 2022
@chrmarti chrmarti added the info-needed Issue requires more information from poster label Jun 17, 2022
@github-actions
Copy link

This issue has been closed automatically because it needs more information and has not had recent activity. See also our issue reporting guidelines.

Happy Coding!

@ehenry7
Copy link

ehenry7 commented Jul 25, 2022

i found out that if i add "export UID" to my ~/.bash_profile it solves this issue

@github-actions github-actions bot locked and limited conversation to collaborators Aug 8, 2022
# for free to subscribe to this conversation on GitHub. Already have an account? #.
Labels
containers Issue in vscode-remote containers info-needed Issue requires more information from poster
Projects
None yet
Development

No branches or pull requests

3 participants