diff --git a/.devcontainer/README.md b/.devcontainer/README.md index 6299e6f..79f221d 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -35,13 +35,13 @@ Changes you can make are notably: - Changes to the Docker image in [Dockerfile](Dockerfile) - Changes to VSCode **settings** and **extensions** in [devcontainer.json](devcontainer.json). -- Change the entrypoint script by adding a bind mount in [devcontainer.json](devcontainer.json) of a shell script to `/root/.welcome.sh` to replace the [current welcome script](https://github.com/qdm12/basedevcontainer/blob/master/shell/.welcome.sh). For example: +- Change the entrypoint script by adding a bind mount in [devcontainer.json](devcontainer.json) of a shell script to `/home/user/.welcome.sh` to replace the [current welcome script](https://github.com/qdm12/basedevcontainer/blob/master/shell/.welcome.sh). For example: ```json // Welcome script { "source": "/yourpath/.welcome.sh", - "target": "/root/.welcome.sh", + "target": "/home/user/.welcome.sh", "type": "bind" }, ``` diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 1ef7de2..19c99a1 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -21,13 +21,13 @@ // Zsh commands history persistence { "source": "${localEnv:HOME}/.zsh_history", - "target": "/root/.zsh_history", + "target": "/home/user/.zsh_history", "type": "bind" }, // Git configuration file { "source": "${localEnv:HOME}/.gitconfig", - "target": "/root/.gitconfig", + "target": "/home/user/.gitconfig", "type": "bind" }, // SSH directory for Linux, OSX and WSL diff --git a/README.md b/README.md index 22946b0..a0234e6 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ Base Alpine development container for Visual Studio Code, used as base image by - Contains the packages: - `libstdc++`: needed by the VS code server - `zsh`: main shell instead of `/bin/sh` + - `sudo`: run commands as root if needed - `git`: interact with Git repositories - `openssh-client`: use SSH keys - `nano`: edit files from the terminal @@ -59,6 +60,7 @@ Base Alpine development container for Visual Studio Code, used as base image by - Docker uses buildkit by default, with the latest Docker client binary. - Extensible with docker-compose.yml - Supports SSH keys with Linux, OSX and Windows +- Runs without root as `user` (uid 1000 and gid 1000) user but you can run Docker without sudo and can use sudo if needed ## Requirements @@ -130,18 +132,20 @@ You can build and extend the Docker development image to suit your needs. RUN echo "alias ls='ls -al'" >> ~/.zshrc ``` - - Add some Alpine packages: + - Add some Alpine packages, you will need to switch to `root`: ```Dockerfile FROM qmcgaw/basedevcontainer + USER root RUN apk add bind-tools + USER user ``` 1. Modify `.devcontainer/docker-compose.yml` and add `build: .` in the vscode service. 1. Open the command palette in Visual Studio Code (CTRL+SHIFT+P) 1. Select `Dev-Containers: Rebuild Container` -- You can bind mount a file at `/root/.welcome.sh` to modify the welcome message. +- You can bind mount a file at `/home/user/.welcome.sh` to modify the welcome message (use `/root/.welcome.sh` for `root`) ## TODO diff --git a/alpine.Dockerfile b/alpine.Dockerfile index 4636e4b..800c999 100644 --- a/alpine.Dockerfile +++ b/alpine.Dockerfile @@ -31,6 +31,8 @@ LABEL \ org.opencontainers.image.title="Base Dev container" \ org.opencontainers.image.description="Base Alpine development container for Visual Studio Code Dev Containers development" ENV BASE_VERSION="${VERSION}-${CREATED}-${COMMIT}" +ARG USER_UID=1000 +ARG USER_GID=1000 # CA certificates RUN apk add -q --update --progress --no-cache ca-certificates @@ -39,16 +41,26 @@ RUN apk add -q --update --progress --no-cache ca-certificates RUN apk add -q --update --progress --no-cache tzdata ENV TZ= +# Setup non root user with sudo access +RUN apk add -q --update --progress --no-cache sudo +WORKDIR /home/user +RUN adduser user -s /bin/sh -D -u $USER_UID $USER_GID && \ + mkdir -p /etc/sudoers.d && \ + echo user ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/user && \ + chmod 0440 /etc/sudoers.d/user + # Setup Git and SSH RUN apk add -q --update --progress --no-cache git mandoc git-doc openssh-client -COPY .ssh.sh /root/ -RUN chmod +x /root/.ssh.sh -# Retro-compatibility symlink -RUN ln -s /root/.ssh.sh /root/.windows.sh +COPY --chown=0:0 .ssh.sh /root/ +RUN chmod +x /root/.ssh.sh && \ + cp /root/.ssh.sh /home/user/.ssh.sh && \ + chown ${USER_UID}:${USER_GID} /home/user/.ssh.sh && \ + # Retro-compatibility symlinks + ln -s /root/.ssh.sh /root/.windows.sh && \ + ln -s /home/user/.ssh.sh /home/user/.windows.sh -WORKDIR /root -# Setup shell for root and ${USERNAME} +# Setup shell for root and user ENTRYPOINT [ "/bin/zsh" ] RUN apk add -q --update --progress --no-cache zsh nano zsh-vcs ENV EDITOR=nano \ @@ -56,40 +68,65 @@ ENV EDITOR=nano \ # MacOS compatibility TERM=xterm RUN apk add -q --update --progress --no-cache shadow && \ + usermod --shell /bin/zsh user && \ usermod --shell /bin/zsh root && \ apk del shadow -COPY shell/.zshrc shell/.welcome.sh /root/ -RUN git clone --single-branch --depth 1 https://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh - -COPY shell/.p10k.zsh /root/ -RUN apk add -q --update --progress --no-cache zsh-theme-powerlevel10k gitstatus && \ - ln -s /usr/share/zsh/plugins/powerlevel10k ~/.oh-my-zsh/custom/themes/powerlevel10k +COPY --chown=${USER_UID}:${USER_GID} shell/.zshrc shell/.welcome.sh /home/user/ +RUN cp /home/user/.zshrc /root/.zshrc && \ + cp /home/user/.welcome.sh /root/.welcome.sh && \ + chown 0:0 /root/.zshrc /root/.welcome.sh && \ + sed -i "s/HOMEPATH/home\/user/" /home/user/.zshrc && \ + sed -i "s/HOMEPATH/root/" /root/.zshrc +RUN git clone --single-branch --depth 1 https://github.com/robbyrussell/oh-my-zsh.git /home/user/.oh-my-zsh && \ + chown ${USER_UID}:${USER_GID} -R /home/user/.oh-my-zsh && \ + cp -r /home/user/.oh-my-zsh /root/.oh-my-zsh && \ + chown 0:0 -R /root/.oh-my-zsh + +COPY shell/.p10k.zsh /home/user/ +RUN ln -s /home/user/.p10k.zsh /root/.p10k.zsh && \ + apk add -q --update --progress --no-cache zsh-theme-powerlevel10k gitstatus && \ + ln -s /usr/share/zsh/plugins/powerlevel10k /root/.oh-my-zsh/custom/themes/powerlevel10k && \ + ln -s /usr/share/zsh/plugins/powerlevel10k /home/user/.oh-my-zsh/custom/themes/powerlevel10k # Docker CLI -COPY --from=docker /bin /usr/local/bin/docker +COPY --from=docker --chown=${USER_UID}:${USER_GID} /bin /usr/local/bin/docker ENV DOCKER_BUILDKIT=1 +# All possible docker host groups +RUN G102=`getent group 102 | cut -d":" -f 1` && \ + G976=`getent group 976 | cut -d":" -f 1` && \ + G1000=`getent group 1000 | cut -d":" -f 1` && \ + if [ -z $G102 ]; then G102=docker102; addgroup --gid 102 $G102; fi && \ + if [ -z $G976 ]; then G976=docker976; addgroup --gid 976 $G976; fi && \ + if [ -z $G1000 ]; then G1000=docker1000; addgroup --gid 1000 $G1000; fi && \ + addgroup user $G102 && \ + addgroup user $G976 && \ + addgroup user $G1000 # Docker compose -COPY --from=compose /bin /usr/libexec/docker/cli-plugins/docker-compose +COPY --from=compose --chown=${USER_UID}:${USER_GID} /bin /usr/libexec/docker/cli-plugins/docker-compose ENV COMPOSE_DOCKER_CLI_BUILD=1 -RUN echo "alias docker-compose='docker compose'" >> /root/.zshrc +RUN echo "alias docker-compose='docker compose'" >> /home/user/.zshrc && \ + echo "alias docker-compose='docker compose'" >> /root/.zshrc # Buildx plugin -COPY --from=buildx /bin /usr/libexec/docker/cli-plugins/docker-buildx +COPY --from=buildx --chown=${USER_UID}:${USER_GID} /bin /usr/libexec/docker/cli-plugins/docker-buildx # Logo ls -COPY --from=logo-ls /bin /usr/local/bin/logo-ls -RUN echo "alias ls='logo-ls'" >> /root/.zshrc +COPY --from=logo-ls --chown=${USER_UID}:${USER_GID} /bin /usr/local/bin/logo-ls +RUN echo "alias ls='logo-ls'" >> /home/user/.zshrc && \ + echo "alias ls='logo-ls'" >> /root/.zshrc # Bit -COPY --from=bit /bin /usr/local/bin/bit +COPY --from=bit --chown=${USER_UID}:${USER_GID} /bin /usr/local/bin/bit ARG TARGETPLATFORM RUN if [ "${TARGETPLATFORM}" != "linux/s390x" ]; then echo "y" | bit complete; fi -COPY --from=gh /bin /usr/local/bin/gh +COPY --from=gh --chown=${USER_UID}:${USER_GID} /bin /usr/local/bin/gh -COPY --from=devtainr /devtainr /usr/local/bin/devtainr +COPY --from=devtainr --chown=${USER_UID}:${USER_GID} /devtainr /usr/local/bin/devtainr # VSCode specific (speed up setup) RUN apk add -q --update --progress --no-cache libstdc++ + +USER user diff --git a/debian.Dockerfile b/debian.Dockerfile index 59e1e3a..025d541 100644 --- a/debian.Dockerfile +++ b/debian.Dockerfile @@ -31,6 +31,8 @@ LABEL \ org.opencontainers.image.title="Base Dev container Debian" \ org.opencontainers.image.description="Base Debian development container for Visual Studio Code Dev Containers development" ENV BASE_VERSION="${VERSION}-${CREATED}-${COMMIT}" +ARG USER_UID=1000 +ARG USER_GID=1000 # CA certificates RUN apt-get update -y && \ @@ -43,6 +45,18 @@ RUN apt-get update -y && \ rm -r /var/cache/* /var/lib/apt/lists/* ENV TZ= +# Setup non root user with sudo access +RUN apt-get update -y && \ + apt-get install -y --no-install-recommends sudo && \ + rm -r /var/cache/* /var/lib/apt/lists/* +WORKDIR /home/user +RUN addgroup --gid $USER_GID user && \ + useradd user --shell /bin/sh --create-home --uid $USER_UID --gid $USER_GID && \ + mkdir -p /etc/sudoers.d && \ + echo user ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/user && \ + chmod 0440 /etc/sudoers.d/user && \ + rm /var/log/faillog /var/log/lastlog + # Setup Git and SSH # Workaround for older Debian in order to be able to sign commits RUN echo "deb https://deb.debian.org/debian bookworm main" >> /etc/apt/sources.list && \ @@ -52,12 +66,15 @@ RUN echo "deb https://deb.debian.org/debian bookworm main" >> /etc/apt/sources.l RUN apt-get update -y && \ apt-get install -y --no-install-recommends man openssh-client less && \ rm -r /var/cache/* /var/lib/apt/lists/* -COPY .ssh.sh /root/ -RUN chmod +x /root/.ssh.sh -# Retro-compatibility symlink -RUN ln -s /root/.ssh.sh /root/.windows.sh - -# Setup shell +COPY --chown=0:0 .ssh.sh /root/ +RUN chmod +x /root/.ssh.sh && \ + cp /root/.ssh.sh /home/user/.ssh.sh && \ + chown ${USER_UID}:${USER_GID} /home/user/.ssh.sh && \ + # Retro-compatibility symlinks + ln -s /root/.ssh.sh /root/.windows.sh && \ + ln -s /home/user/.ssh.sh /home/user/.windows.sh + +# Setup shell for root and user ENTRYPOINT [ "/bin/zsh" ] RUN apt-get update -y && \ apt-get install -y --no-install-recommends zsh nano locales wget && \ @@ -72,37 +89,63 @@ RUN echo "LC_ALL=en_US.UTF-8" >> /etc/environment && \ echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen && \ echo "LANG=en_US.UTF-8" > /etc/locale.conf && \ locale-gen en_US.UTF-8 -RUN usermod --shell /bin/zsh root - -COPY shell/.zshrc shell/.welcome.sh /root/ -RUN git clone --single-branch --depth 1 https://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh +RUN usermod --shell /bin/zsh user && \ + usermod --shell /bin/zsh root + +COPY --chown=${USER_UID}:${USER_GID} shell/.zshrc shell/.welcome.sh /home/user/ +RUN cp /home/user/.zshrc /root/.zshrc && \ + cp /home/user/.welcome.sh /root/.welcome.sh && \ + chown 0:0 /root/.zshrc /root/.welcome.sh && \ + sed -i "s/HOMEPATH/home\/user/" /home/user/.zshrc && \ + sed -i "s/HOMEPATH/root/" /root/.zshrc +RUN git clone --single-branch --depth 1 https://github.com/robbyrussell/oh-my-zsh.git /home/user/.oh-my-zsh && \ + chown ${USER_UID}:${USER_GID} -R /home/user/.oh-my-zsh && \ + cp -r /home/user/.oh-my-zsh /root/.oh-my-zsh && \ + chown 0:0 -R /root/.oh-my-zsh ARG POWERLEVEL10K_VERSION=v1.16.1 -COPY shell/.p10k.zsh /root/ -RUN git clone --branch ${POWERLEVEL10K_VERSION} --single-branch --depth 1 https://github.com/romkatv/powerlevel10k.git ~/.oh-my-zsh/custom/themes/powerlevel10k && \ - rm -rf ~/.oh-my-zsh/custom/themes/powerlevel10k/.git +COPY shell/.p10k.zsh /home/user/ +RUN ln -s /home/user/.p10k.zsh /root/.p10k.zsh && \ + git clone --branch ${POWERLEVEL10K_VERSION} --single-branch --depth 1 https://github.com/romkatv/powerlevel10k.git /home/user/.oh-my-zsh/custom/themes/powerlevel10k && \ + rm -rf /home/user/.oh-my-zsh/custom/themes/powerlevel10k/.git && \ + chown -R ${USER_UID}:${USER_GID} /home/user/.oh-my-zsh/custom/themes/powerlevel10k && \ + ln -s /home/user/.oh-my-zsh/custom/themes/powerlevel10k /root/.oh-my-zsh/custom/themes/powerlevel10k # Docker CLI COPY --from=docker /bin /usr/local/bin/docker ENV DOCKER_BUILDKIT=1 +# All possible docker host groups +RUN G102=`getent group 102 | cut -d":" -f 1` && \ + G976=`getent group 976 | cut -d":" -f 1` && \ + G1000=`getent group 1000 | cut -d":" -f 1` && \ + if [ -z $G102 ]; then G102=docker102; addgroup --gid 102 $G102; fi && \ + if [ -z $G976 ]; then G976=docker976; addgroup --gid 976 $G976; fi && \ + if [ -z $G1000 ]; then G1000=docker1000; addgroup --gid 1000 $G1000; fi && \ + usermod -a -G $G102 user && \ + usermod -a -G $G976 user && \ + usermod -a -G $G1000 user # Docker compose -COPY --from=compose /bin /usr/libexec/docker/cli-plugins/docker-compose +COPY --from=compose --chown=${USER_UID}:${USER_GID} /bin /usr/libexec/docker/cli-plugins/docker-compose ENV COMPOSE_DOCKER_CLI_BUILD=1 -RUN echo "alias docker-compose='docker compose'" >> /root/.zshrc +RUN echo "alias docker-compose='docker compose'" >> /home/user/.zshrc && \ + echo "alias docker-compose='docker compose'" >> /root/.zshrc # Buildx plugin -COPY --from=buildx /bin /usr/libexec/docker/cli-plugins/docker-buildx +COPY --from=buildx --chown=${USER_UID}:${USER_GID} /bin /usr/libexec/docker/cli-plugins/docker-buildx # Logo ls -COPY --from=logo-ls /bin /usr/local/bin/logo-ls -RUN echo "alias ls='logo-ls'" >> /root/.zshrc +COPY --from=logo-ls --chown=${USER_UID}:${USER_GID} /bin /usr/local/bin/logo-ls +RUN echo "alias ls='logo-ls'" >> /home/user/.zshrc && \ + echo "alias ls='logo-ls'" >> /root/.zshrc # Bit -COPY --from=bit /bin /usr/local/bin/bit +COPY --from=bit --chown=${USER_UID}:${USER_GID} /bin /usr/local/bin/bit ARG TARGETPLATFORM RUN if [ "${TARGETPLATFORM}" != "linux/s390x" ]; then echo "y" | bit complete; fi -COPY --from=gh /bin /usr/local/bin/gh +COPY --from=gh --chown=${USER_UID}:${USER_GID} /bin /usr/local/bin/gh + +COPY --from=devtainr --chown=${USER_UID}:${USER_GID} /devtainr /usr/local/bin/devtainr -COPY --from=devtainr /devtainr /usr/local/bin/devtainr +USER user diff --git a/shell/.zshrc b/shell/.zshrc index 2bb1636..c523390 100644 --- a/shell/.zshrc +++ b/shell/.zshrc @@ -1,4 +1,4 @@ -ZSH=/root/.oh-my-zsh +ZSH=/HOMEPATH/.oh-my-zsh ZSH_CUSTOM=$ZSH/custom POWERLEVEL9K_DISABLE_CONFIGURATION_WIZARD=true ZSH_THEME="powerlevel10k/powerlevel10k" @@ -21,8 +21,20 @@ test -S /var/run/docker.sock [ "$?" = 0 ] && DOCKERSOCK_OK=yes [ -z $DOCKERSOCK_OK ] && >&2 echo "[WARNING] Docker socket not found, docker will not be available" +# Fixing permission on Docker socket +if [ ! -z $DOCKERSOCK_OK ]; then + DOCKERSOCK_USER=`stat -c "%u" /var/run/docker.sock` + DOCKERSOCK_GROUP=`stat -c "%g" /var/run/docker.sock` + if [ "$DOCKERSOCK_GROUP" != "1000" ] && [ "$DOCKERSOCK_GROUP" != "102" ] && [ "$DOCKERSOCK_GROUP" != "976" ]; then + echo "Docker socket not owned by group IDs 1000, 102 or 976, changing its group to `id -g`" + sudo chown $DOCKERSOCK_USER:`id -g` /var/run/docker.sock + sudo chmod 770 /var/run/docker.sock + fi +fi + echo echo "Base version: $BASE_VERSION" +echo "Running as `whoami`" where code &> /dev/null && echo "VS code server `code -v | head -n 1`" if [ ! -z $DOCKERSOCK_OK ]; then echo "Docker server `docker version --format {{.Server.Version}}` | client `docker version --format {{.Client.Version}}`"