devcontainer build fixups for macOS clients (#874)

# Pull Request

## Title

Fixups to the devcontainer build for macOS clients.

---

## Description

- Use a more portalable random number generator
- Address some differences in docker.sock privileges.
- Address differences in `stat` arguments.
- Switch to wget mode for conda installation to workaround lack of arm64
apt repo.
- When pulling base images to prime cache, use the appropriate
architecture (for Windows we only support amd64 for now).
- Remove `:latest` from `cache-from` args for `podman` compliance.
- Address some differences in `sed` syntax.

- Fixes #873 

---

## Type of Change

- 🛠️ Bug fix

---

## Testing

- local MacBook testing
- CI testing for Linux

---

## Additional Notes

Doesn't currently do builds for arm64 platform in the pipeline.
Can work towards addressing that in the future.
This commit is contained in:
Brian Kroth 2024-10-21 10:17:37 -05:00 коммит произвёл GitHub
Родитель d2738e70e5
Коммит 72e10d1833
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
11 изменённых файлов: 62 добавлений и 27 удалений

Просмотреть файл

@ -64,12 +64,9 @@ COPY --from=deps-prep --chown=vscode:conda /tmp/conda-tmp/mlos_deps.yml /tmp/con
# Combine the installation of miniconda and the mlos dependencies into a single step in order to save space.
# This allows the mlos env to reference the base env's packages without duplication across layers.
RUN echo "Setup miniconda" \
&& curl -Ss https://repo.anaconda.com/pkgs/misc/gpgkeys/anaconda.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/conda.gpg > /dev/null \
&& gpg --keyring /etc/apt/trusted.gpg.d/conda.gpg --no-default-keyring --fingerprint 34161F5BF5EB1D4BFBBB8F0A8AEB4F8B29D82806 \
&& echo "deb [arch=amd64 signed-by=/etc/apt/trusted.gpg.d/conda.gpg] https://repo.anaconda.com/pkgs/misc/debrepo/conda stable main" | sudo tee /etc/apt/sources.list.d/conda.list \
&& sudo apt-get update \
&& sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends conda \
&& sudo apt-get clean && sudo rm -rf /var/lib/apt/lists/* \
&& curl -Ss --url https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-$(uname -m).sh -o /tmp/miniconda3.sh \
&& sudo sh /tmp/miniconda3.sh -b -u -p /opt/conda \
&& rm -rf /tmp/miniconda3.sh \
&& echo "# Adjust the conda installation to be user/group writable." \
&& sudo /opt/conda/bin/conda init --system \
&& sudo chgrp -R conda /opt/conda \

Просмотреть файл

@ -35,7 +35,7 @@ if ("$env:NO_CACHE" -eq 'true') {
else {
$cacheFrom = 'mloscore.azurecr.io/devcontainer-cli:latest'
$devcontainer_cli_build_args += " --cache-from $cacheFrom"
docker pull $cacheFrom
docker pull --platform linux/amd64 $cacheFrom
}
$cmd = "docker.exe build -t devcontainer-cli:latest -t cspell:latest " +

Просмотреть файл

@ -10,20 +10,26 @@ set -eu
scriptdir=$(dirname "$(readlink -f "$0")")
cd "$scriptdir/"
source ../common.sh
# Build the helper container that has the devcontainer CLI for building the devcontainer.
if [ ! -w /var/run/docker.sock ]; then
echo "ERROR: $USER does not have write access to /var/run/docker.sock. Please add $USER to the docker group." >&2
exit 1
fi
DOCKER_GID=$(stat -c'%g' /var/run/docker.sock)
DOCKER_GID=$(stat $STAT_FORMAT_GID_ARGS /var/run/docker.sock)
# Make this work inside a devcontainer as well.
if [ -w /var/run/docker-host.sock ]; then
DOCKER_GID=$(stat -c'%g' /var/run/docker-host.sock)
DOCKER_GID=$(stat $STAT_FORMAT_GID_ARGS /var/run/docker-host.sock)
fi
export DOCKER_BUILDKIT=${DOCKER_BUILDKIT:-1}
# TODO: Add multiplatform build support?
#devcontainer_cli_build_args='--platform linux/amd64,linux/arm64'
devcontainer_cli_build_args=''
if docker buildx version 2>/dev/null; then
devcontainer_cli_build_args+=' --progress=plain'
else
@ -33,10 +39,10 @@ fi
if [ "${NO_CACHE:-}" == 'true' ]; then
devcontainer_cli_build_args+=' --no-cache --pull'
else
cacheFrom='mloscore.azurecr.io/devcontainer-cli:latest'
cacheFrom='mloscore.azurecr.io/devcontainer-cli'
tmpdir=$(mktemp -d)
devcontainer_cli_build_args+=" --cache-from $cacheFrom"
docker --config="$tmpdir" pull "$cacheFrom" || true
docker --config="$tmpdir" pull --platform linux/$(uname -m) "$cacheFrom" || true
rmdir "$tmpdir"
fi

Просмотреть файл

@ -42,13 +42,13 @@ if ($null -eq $env:DOCKER_BUILDKIT) {
$devcontainer_build_args = ''
if ("$env:NO_CACHE" -eq 'true') {
$base_image = (Get-Content "$rootdir/.devcontainer/Dockerfile" | Select-String '^FROM' | Select-Object -ExpandProperty Line | ForEach-Object { $_ -replace '^FROM\s+','' } | ForEach-Object { $_ -replace ' AS\s+.*','' } | Select-Object -First 1)
docker pull $base_image
docker pull --platform linux/amd64 $base_image
$devcontainer_build_args = '--no-cache'
}
else {
$cacheFrom = 'mloscore.azurecr.io/mlos-devcontainer:latest'
$devcontainer_build_args = "--cache-from $cacheFrom"
docker pull "$cacheFrom"
docker pull --platform linux/amd64 "$cacheFrom"
}
# Make this work inside a devcontainer as well.

Просмотреть файл

@ -12,16 +12,21 @@ repo_root=$(readlink -f "$scriptdir/../..")
repo_name=$(basename "$repo_root")
cd "$scriptdir/"
source ../common.sh
DEVCONTAINER_IMAGE="devcontainer-cli:latest"
MLOS_AUTOTUNING_IMAGE="mlos-devcontainer:latest"
# Build the helper container that has the devcontainer CLI for building the devcontainer.
NO_CACHE=${NO_CACHE:-} ./build-devcontainer-cli.sh
DOCKER_GID=$(stat -c'%g' /var/run/docker.sock)
DOCKER_GID=$(stat $STAT_FORMAT_GID_ARGS /var/run/docker.sock)
# Make this work inside a devcontainer as well.
if [ -w /var/run/docker-host.sock ]; then
DOCKER_GID=$(stat -c'%g' /var/run/docker-host.sock)
DOCKER_GID=$(stat $STAT_FORMAT_GID_ARGS /var/run/docker-host.sock)
fi
if [[ $OSTYPE =~ darwin* ]]; then
DOCKER_GID=0
fi
# Build the devcontainer image.
@ -30,7 +35,7 @@ rootdir="$repo_root"
# Run the initialize command on the host first.
# Note: command should already pull the cached image if possible.
pwd
devcontainer_json=$(cat "$rootdir/.devcontainer/devcontainer.json" | sed -e 's|^\s*//.*||' -e 's|/\*|\n&|g;s|*/|&\n|g' | sed -e '/\/\*/,/*\//d')
devcontainer_json=$(cat "$rootdir/.devcontainer/devcontainer.json" | sed -e 's|^[ \t]*//.*||' -e 's|/\*|\n&|g;s|*/|&\n|g' | sed -e '/\/\*/,/*\//d')
initializeCommand=$(echo "$devcontainer_json" | docker run -i --rm $DEVCONTAINER_IMAGE jq -e -r '.initializeCommand[]')
if [ -z "$initializeCommand" ]; then
echo "No initializeCommand found in devcontainer.json" >&2
@ -39,16 +44,18 @@ else
eval "pushd "$rootdir/"; $initializeCommand; popd"
fi
# TODO: Add multi-platform build support?
#devcontainer_build_args='--platform linux/amd64,linux/arm64'
devcontainer_build_args=''
if [ "${NO_CACHE:-}" == 'true' ]; then
base_image=$(grep '^FROM ' "$rootdir/.devcontainer/Dockerfile" | sed -e 's/^FROM //' -e 's/ AS .*//' | head -n1)
docker pull "$base_image" || true
docker pull --platform linux/$(uname -m) "$base_image" || true
devcontainer_build_args='--no-cache'
else
cache_from='mloscore.azurecr.io/mlos-devcontainer:latest'
devcontainer_build_args="--cache-from $cache_from --cache-from mlos-devcontainer:latest"
cache_from='mloscore.azurecr.io/mlos-devcontainer'
devcontainer_build_args="--cache-from $cache_from --cache-from mlos-devcontainer"
tmpdir=$(mktemp -d)
docker --config="$tmpdir" pull "$cache_from" || true
docker --config="$tmpdir" pull --platform linux/$(uname -m) "$cache_from" || true
rmdir "$tmpdir"
fi

18
.devcontainer/common.sh Normal file
Просмотреть файл

@ -0,0 +1,18 @@
##
## Copyright (c) Microsoft Corporation.
## Licensed under the MIT License.
##
case $OSTYPE in
linux*)
STAT_FORMAT_GID_ARGS="-c%g"
STAT_FORMAT_INODE_ARGS="-c%i"
;;
darwin*)
STAT_FORMAT_GID_ARGS="-f%g"
STAT_FORMAT_INODE_ARGS="-f%i"
;;
*)
echo "ERROR: Unhandled OSTYPE: $OSTYPE"
exit 1
;;
esac

Просмотреть файл

@ -20,7 +20,8 @@ if [ ! -f .env ]; then
fi
# Also prep the random NGINX_PORT for the docker-compose command.
if ! [ -e .devcontainer/.env ] || ! egrep -q "^NGINX_PORT=[0-9]+$" .devcontainer/.env; then
NGINX_PORT=$(($(shuf -i 0-30000 -n 1) + 80))
RANDOM=$$
NGINX_PORT=$((($RANDOM % 30000) + 1 + 80))
echo "NGINX_PORT=$NGINX_PORT" > .devcontainer/.env
fi
@ -55,6 +56,6 @@ if [ "${NO_CACHE:-}" != 'true' ]; then
## Make sure we use an empty config to avoid auth issues for devs with the
## registry, which should allow anonymous pulls
#tmpdir=$(mktemp -d)
#docker --config="$tmpdir" pull -q "$cacheFrom" >/dev/null || true
#docker --config="$tmpdir" pull --platform linux/$(uname -m) -q "$cacheFrom" >/dev/null || true
#rmdir "$tmpdir"
fi

Просмотреть файл

@ -49,5 +49,5 @@ if ($env:NO_CACHE -ne 'true') {
$cacheFrom = 'mloscore.azurecr.io/mlos-devcontainer'
# Skip pulling for now (see TODO note above)
Write-Host "Consider pulling image $cacheFrom for build caching."
#docker pull $cacheFrom
#docker pull --platform linux/amd64 $cacheFrom
}

Просмотреть файл

@ -17,15 +17,20 @@ repo_root=$(readlink -f "$scriptdir/../..")
repo_name=$(basename "$repo_root")
cd "$repo_root"
container_name="$repo_name.$(stat -c%i "$repo_root/")"
source .devcontainer/common.sh
container_name="$repo_name.$(stat $STAT_FORMAT_INODE_ARGS "$repo_root/")"
# Be sure to use the host workspace folder if available.
workspace_root=${LOCAL_WORKSPACE_FOLDER:-$repo_root}
if [ -e /var/run/docker-host.sock ]; then
docker_gid=$(stat -c%g /var/run/docker-host.sock)
docker_gid=$(stat $STAT_FORMAT_GID_ARGS /var/run/docker-host.sock)
else
docker_gid=$(stat -c%g /var/run/docker.sock)
docker_gid=$(stat $STAT_FORMAT_GID_ARGS /var/run/docker.sock)
fi
if [[ $OSTYPE =~ darwin* ]]; then
docker_gid=0
fi
set -x

1
.vscode/extensions.json поставляемый
Просмотреть файл

@ -19,6 +19,7 @@
"ms-python.pylint",
"ms-python.python",
"ms-python.vscode-pylance",
"ms-vscode-remote.remote-containers",
"ms-vsliveshare.vsliveshare",
"njpwerner.autodocstring",
"redhat.vscode-yaml",

Просмотреть файл

@ -23,7 +23,7 @@ MKDIR_BUILD := $(shell test -d build || mkdir build)
#CONDA_INFO_LEVEL ?= -q
# Run make in parallel by default.
MAKEFLAGS += -j$(shell nproc)
MAKEFLAGS += -j$(shell nproc 2>/dev/null || sysctl -n hw.ncpu)
#MAKEFLAGS += -Oline
.PHONY: all