Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Devcontainer improvements #10

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 65 additions & 11 deletions images/devcontainer/default.nix
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# A fat and modifiable Nix image
{ dockerTools
{ stdenv
, dockerTools
, bashInteractive
, cacert
, closureInfo
, coreutils
, curl
, direnv
, gcc-unwrapped
, gitReallyMinimal
, glibc
, gnugrep
Expand All @@ -21,15 +21,44 @@
, openssh
, procps
, shadow
, sudo
, xz
, patchelf
, mkUserEnvironment
, writeScriptBin
}:
let
channel = builtins.getEnv("NIXPKGS_CHANNEL");

/**
This entrypoint patches node binary copied by vscode. This always succeeds
as vscode is always slower to run node, as our entrypoint to patch it.

This solution is prefered to LD_LIBRARY_PATH, as setting LD_LIBRARY_PATH
globally messes environment, as libraries found this way will always have
priority. Only other other alternative i can think of to patch node is to
have a LD_PRELOAD set with that returns the right libraries, but that
solution even if it is more clean can present more runtime issues.
**/
entrypoint = writeScriptBin "entrypoint.sh" ''
#!${bashInteractive}/bin/bash -e

until ${patchelf}/bin/patchelf \
--set-rpath "${stdenv.cc.cc.lib}/lib" \
--set-interpreter "${glibc}/lib64/ld-linux-x86-64.so.2" \
$HOME/.vscode-server/bin/*/node 2>/dev/null; do true; done

echo "vscode server binaries successfully patched"

"$@"
'';

# generate a user profile for the image
profile = mkUserEnvironment {
derivations = [
# container entrypoint
entrypoint

# core utils
coreutils
procps
Expand All @@ -53,9 +82,9 @@ let

# for user management
shadow
sudo

# for the vscode extension
gcc-unwrapped
iproute
];
};
Expand All @@ -71,14 +100,19 @@ let
export USER=nobody
${nix}/bin/nix-store --load-db < ${closureInfo { rootPaths = [ profile ]; }}/registration

# set the user profile
# set default profile
${profile}/bin/nix-env --profile nix/var/nix/profiles/default --set ${profile}

# minimal
mkdir -p bin usr/bin
ln -s /nix/var/nix/profiles/default/bin/sh bin/sh
ln -s /nix/var/nix/profiles/default/bin/env usr/bin/env

# install sudo
mkdir -p usr/bin usr/lib/sudo
cp ${sudo}/bin/sudo usr/bin/sudo
cp -r ${sudo}/libexec/sudo/* usr/lib/sudo

# might as well...
ln -s /nix/var/nix/profiles/default/bin/bash bin/bash

Expand All @@ -94,23 +128,19 @@ let
# make sure /tmp exists
mkdir -m 0777 tmp

# allow ubuntu ELF binaries to run. VSCode copies it's own.
mkdir -p lib64
ln -s ${glibc}/lib64/ld-linux-x86-64.so.2 lib64/ld-linux-x86-64.so.2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you sure you don't want to keep this? Other extensions might also download random binaries.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add later if there would be some issues, would not make this default as it solves only part of problem. If some third party binary is not statically linked, it's a good chance it will require also some other libraries. Regarding installing of vscode plugins can probably be automatized using home-manager module and binaries can be patched there.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please don't remove this otherwise it will break actions/checkout@v3 when we use devcontainer as github action iamge


# VSCode assumes that /sbin/ip exists
mkdir sbin
ln -s /nix/var/nix/profiles/default/bin/ip sbin/ip
'';

config = {
Cmd = [ "/nix/var/nix/profiles/default/bin/bash" ];
Entrypoint = [ "/nix/var/nix/profiles/default/bin/entrypoint.sh" ];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I was hacking on it, vscode was running the container with its own entry point. Is that not the case anymore?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean it works for me if using docker-compose, but have to still test with plain devcontainer.

Cmd = [ "sleep" "infinity" ];
Env = [
"ENV=/nix/var/nix/profiles/default/etc/profile.d/nix.sh"
"GIT_SSL_CAINFO=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"
"LD_LIBRARY_PATH=/nix/var/nix/profiles/default/lib"
"PAGER=less"
"PATH=/nix/var/nix/profiles/default/bin"
"PATH=/usr/bin:/nix/var/nix/profiles/default/bin"
"SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"
(
if channel != "" then
Expand All @@ -119,6 +149,30 @@ let
"NIX_PATH=nixpkgs=${../nix/fake_nixpkgs}"
)
];

# commands to run before build of every Dockerfile using this image
OnBuild = [
# fix permissions of sudo and set suid bit
"RUN chmod -R u+s,u+rx,g+x,o+x /usr/bin/sudo && chown -R root:root /usr/lib/sudo"

# expose USERNAME, USER_UID, USER_GID as build arguments
"ARG USERNAME=vscode"
"ARG USER_UID=1000"
"ARG USER_GID=$USER_UID"

# add user and group, add user to wheel group
"RUN groupadd -f -g $USER_GID $USERNAME && useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -G wheel -m $USERNAME"

# fix permissions of nix store
"RUN chown -R $USER_UID:$USER_GID /nix"

# change user, change workdir and create user profile
"USER $USERNAME"
"WORKDIR /home/$USERNAME"
"RUN nix-env --profile /nix/var/nix/profiles/per-user/$USERNAME/profile -iA"
"ENV USER=$USERNAME"
"ENV PATH=/usr/bin:/nix/var/nix/profiles/per-user/$USERNAME/profile/bin:/nix/var/nix/profiles/default/bin"
];
Labels = {
# https://github.com/microscaling/microscaling/blob/55a2d7b91ce7513e07f8b1fd91bbed8df59aed5a/Dockerfile#L22-L33
"org.label-schema.vcs-ref" = "master";
Expand Down
15 changes: 14 additions & 1 deletion images/devcontainer/root/etc/bashrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
# interactive session
if [[ $- == *i* ]]; then

PS1='\[\033[0;32;40m\][nix]$\[\033[0m\] '
# Provide a nice prompt if the terminal supports it.
if [ "$TERM" != "dumb" -o -n "$INSIDE_EMACS" ]; then
PROMPT_COLOR="1;31m"
let $UID && PROMPT_COLOR="1;32m"
if [ -n "$INSIDE_EMACS" -o "$TERM" == "eterm" -o "$TERM" == "eterm-color" ]; then
# Emacs term mode doesn't support xterm title escape sequence (\e]0;)
PS1="\n\[\033[$PROMPT_COLOR\][\u@\h:\w]\\$\[\033[0m\] "
else
PS1="\n\[\033[$PROMPT_COLOR\][\[\e]0;\u@\h: \w\a\]\u@\h:\w]\\$\[\033[0m\] "
fi
if test "$TERM" = "xterm"; then
PS1="\[\033]2;\h:\u:\w\007\]$PS1"
fi
fi

fi
1 change: 1 addition & 0 deletions images/devcontainer/root/etc/nix/nix.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sandbox = relaxed
2 changes: 2 additions & 0 deletions images/devcontainer/root/etc/sudo.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Plugin sudoers_policy /usr/lib/sudo/sudoers.so
Plugin sudoers_io /usr/lib/sudo/sudoers.so
2 changes: 2 additions & 0 deletions images/devcontainer/root/etc/sudoers
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
root ALL=(ALL:ALL) SETENV: ALL
%wheel ALL=(ALL:ALL) NOPASSWD:ALL