From 29adff29310c96afd428d5877dbd2c32e43778e2 Mon Sep 17 00:00:00 2001 From: Kushal Azim Ekram Date: Mon, 16 May 2022 23:20:06 +0000 Subject: [PATCH 01/10] Added k3d folder --- .../.devcontainer/Dockerfile | 33 ++ .../.devcontainer/devcontainer.json | 31 ++ .../.devcontainer/library-scripts/README.md | 5 + .../library-scripts/common-debian.sh | 454 ++++++++++++++++++ .../docker-in-docker-debian.sh | 346 +++++++++++++ .../library-scripts/kubectl-helm-debian.sh | 249 ++++++++++ containers/kubernetes-helm-k3d/.npmignore | 6 + containers/kubernetes-helm-k3d/README.md | 61 +++ .../test-project/test-utils.sh | 149 ++++++ .../kubernetes-helm-k3d/test-project/test.sh | 21 + 10 files changed, 1355 insertions(+) create mode 100644 containers/kubernetes-helm-k3d/.devcontainer/Dockerfile create mode 100644 containers/kubernetes-helm-k3d/.devcontainer/devcontainer.json create mode 100644 containers/kubernetes-helm-k3d/.devcontainer/library-scripts/README.md create mode 100755 containers/kubernetes-helm-k3d/.devcontainer/library-scripts/common-debian.sh create mode 100755 containers/kubernetes-helm-k3d/.devcontainer/library-scripts/docker-in-docker-debian.sh create mode 100755 containers/kubernetes-helm-k3d/.devcontainer/library-scripts/kubectl-helm-debian.sh create mode 100644 containers/kubernetes-helm-k3d/.npmignore create mode 100644 containers/kubernetes-helm-k3d/README.md create mode 100644 containers/kubernetes-helm-k3d/test-project/test-utils.sh create mode 100755 containers/kubernetes-helm-k3d/test-project/test.sh diff --git a/containers/kubernetes-helm-k3d/.devcontainer/Dockerfile b/containers/kubernetes-helm-k3d/.devcontainer/Dockerfile new file mode 100644 index 0000000000..8f576679c3 --- /dev/null +++ b/containers/kubernetes-helm-k3d/.devcontainer/Dockerfile @@ -0,0 +1,33 @@ +# Note: You can use any Debian/Ubuntu based image you want. +FROM mcr.microsoft.com/vscode/devcontainers/base:0-bullseye + +# Enable new "BUILDKIT" mode for Docker CLI +ENV DOCKER_BUILDKIT=1 + +# Options +ARG INSTALL_ZSH="true" +ARG UPGRADE_PACKAGES="false" +ARG USE_MOBY="true" +ARG USERNAME=vscode +ARG USER_UID=1000 +ARG USER_GID=$USER_UID +# Install needed packages and setup non-root user. Use a separate RUN statement to add your own dependencies. +COPY library-scripts/*.sh /tmp/library-scripts/ +RUN apt-get update && /bin/bash /tmp/library-scripts/common-debian.sh "${INSTALL_ZSH}" "${USERNAME}" "${USER_UID}" "${USER_GID}" "${UPGRADE_PACKAGES}" "true" "true" \ + && /bin/bash /tmp/library-scripts/docker-in-docker-debian.sh "true" "${USERNAME}" "${USE_MOBY}" \ + && /bin/bash /tmp/library-scripts/kubectl-helm-debian.sh "latest" "latest" "latest" \ + && mkdir -p /home/${USERNAME}/.minikube \ + && chown ${USERNAME} /home/${USERNAME}/.minikube \ + && apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/* /tmp/library-scripts/ + +VOLUME [ "/var/lib/docker" ] + +# Setting the ENTRYPOINT to docker-init.sh will start up the Docker Engine +# inside the container "overrideCommand": false is set in devcontainer.json. +# The script will also execute CMD if you need to alter startup behaviors. +ENTRYPOINT [ "/usr/local/share/docker-init.sh" ] +CMD [ "sleep", "infinity" ] + +# [Optional] Uncomment this section to install additional OS packages. +# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ +# && apt-get -y install --no-install-recommends diff --git a/containers/kubernetes-helm-k3d/.devcontainer/devcontainer.json b/containers/kubernetes-helm-k3d/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..4a22c4f8bd --- /dev/null +++ b/containers/kubernetes-helm-k3d/.devcontainer/devcontainer.json @@ -0,0 +1,31 @@ +{ + "name": "Kubernetes - Minikube-in-Docker", + "dockerFile": "Dockerfile", + "runArgs": ["--privileged"], + "mounts": [ + "source=minikube-var-lib-docker,target=/var/lib/docker,type=volume", + "source=minikube-config,target=/home/vscode/.minikube,type=volume", + ], + "overrideCommand": false, + + // Set *default* container specific settings.json values on container create. + "settings": {}, + + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-azuretools.vscode-docker", + "ms-kubernetes-tools.vscode-kubernetes-tools" + ], + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "kubectl version", + + // Use 'postStartCommand' to run commands after the container is created like starting minikube. + // "postStartCommand": "nohup bash -c 'minikube start &' > minikube.log 2>&1", + + // Minikube does not like running as root, so use a non-root user. + "remoteUser": "vscode" +} diff --git a/containers/kubernetes-helm-k3d/.devcontainer/library-scripts/README.md b/containers/kubernetes-helm-k3d/.devcontainer/library-scripts/README.md new file mode 100644 index 0000000000..d1ca1955fc --- /dev/null +++ b/containers/kubernetes-helm-k3d/.devcontainer/library-scripts/README.md @@ -0,0 +1,5 @@ +# Warning: Folder contents may be replaced + +The contents of this folder will be automatically replaced with a file of the same name in the repository's [script-library folder](https://github.com/microsoft/vscode-dev-containers/tree/main/script-library) whenever the repository is packaged. + +To retain your edits, move the file to a different location. You may also delete the files if they are not needed. diff --git a/containers/kubernetes-helm-k3d/.devcontainer/library-scripts/common-debian.sh b/containers/kubernetes-helm-k3d/.devcontainer/library-scripts/common-debian.sh new file mode 100755 index 0000000000..af4facc8f6 --- /dev/null +++ b/containers/kubernetes-helm-k3d/.devcontainer/library-scripts/common-debian.sh @@ -0,0 +1,454 @@ +#!/usr/bin/env bash +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- +# +# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/common.md +# Maintainer: The VS Code and Codespaces Teams +# +# Syntax: ./common-debian.sh [install zsh flag] [username] [user UID] [user GID] [upgrade packages flag] [install Oh My Zsh! flag] [Add non-free packages] + +set -e + +INSTALL_ZSH=${1:-"true"} +USERNAME=${2:-"automatic"} +USER_UID=${3:-"automatic"} +USER_GID=${4:-"automatic"} +UPGRADE_PACKAGES=${5:-"true"} +INSTALL_OH_MYS=${6:-"true"} +ADD_NON_FREE_PACKAGES=${7:-"false"} +SCRIPT_DIR="$(cd $(dirname "${BASH_SOURCE[0]}") && pwd)" +MARKER_FILE="/usr/local/etc/vscode-dev-containers/common" + +if [ "$(id -u)" -ne 0 ]; then + echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.' + exit 1 +fi + +# Ensure that login shells get the correct path if the user updated the PATH using ENV. +rm -f /etc/profile.d/00-restore-env.sh +echo "export PATH=${PATH//$(sh -lc 'echo $PATH')/\$PATH}" > /etc/profile.d/00-restore-env.sh +chmod +x /etc/profile.d/00-restore-env.sh + +# If in automatic mode, determine if a user already exists, if not use vscode +if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then + USERNAME="" + POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)") + for CURRENT_USER in ${POSSIBLE_USERS[@]}; do + if id -u ${CURRENT_USER} > /dev/null 2>&1; then + USERNAME=${CURRENT_USER} + break + fi + done + if [ "${USERNAME}" = "" ]; then + USERNAME=vscode + fi +elif [ "${USERNAME}" = "none" ]; then + USERNAME=root + USER_UID=0 + USER_GID=0 +fi + +# Load markers to see which steps have already run +if [ -f "${MARKER_FILE}" ]; then + echo "Marker file found:" + cat "${MARKER_FILE}" + source "${MARKER_FILE}" +fi + +# Ensure apt is in non-interactive to avoid prompts +export DEBIAN_FRONTEND=noninteractive + +# Function to call apt-get if needed +apt_get_update_if_needed() +{ + if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then + echo "Running apt-get update..." + apt-get update + else + echo "Skipping apt-get update." + fi +} + +# Run install apt-utils to avoid debconf warning then verify presence of other common developer tools and dependencies +if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then + + package_list="apt-utils \ + openssh-client \ + gnupg2 \ + dirmngr \ + iproute2 \ + procps \ + lsof \ + htop \ + net-tools \ + psmisc \ + curl \ + wget \ + rsync \ + ca-certificates \ + unzip \ + zip \ + nano \ + vim-tiny \ + less \ + jq \ + lsb-release \ + apt-transport-https \ + dialog \ + libc6 \ + libgcc1 \ + libkrb5-3 \ + libgssapi-krb5-2 \ + libicu[0-9][0-9] \ + liblttng-ust0 \ + libstdc++6 \ + zlib1g \ + locales \ + sudo \ + ncdu \ + man-db \ + strace \ + manpages \ + manpages-dev \ + init-system-helpers" + + # Needed for adding manpages-posix and manpages-posix-dev which are non-free packages in Debian + if [ "${ADD_NON_FREE_PACKAGES}" = "true" ]; then + # Bring in variables from /etc/os-release like VERSION_CODENAME + . /etc/os-release + sed -i -E "s/deb http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME} main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME} main contrib non-free/" /etc/apt/sources.list + sed -i -E "s/deb-src http:\/\/(deb|httredir)\.debian\.org\/debian ${VERSION_CODENAME} main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME} main contrib non-free/" /etc/apt/sources.list + sed -i -E "s/deb http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME}-updates main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME}-updates main contrib non-free/" /etc/apt/sources.list + sed -i -E "s/deb-src http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME}-updates main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME}-updates main contrib non-free/" /etc/apt/sources.list + sed -i "s/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main contrib non-free/" /etc/apt/sources.list + sed -i "s/deb-src http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main contrib non-free/" /etc/apt/sources.list + sed -i "s/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main contrib non-free/" /etc/apt/sources.list + sed -i "s/deb-src http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main contrib non-free/" /etc/apt/sources.list + # Handle bullseye location for security https://www.debian.org/releases/bullseye/amd64/release-notes/ch-information.en.html + sed -i "s/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main contrib non-free/" /etc/apt/sources.list + sed -i "s/deb-src http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main contrib non-free/" /etc/apt/sources.list + echo "Running apt-get update..." + apt-get update + package_list="${package_list} manpages-posix manpages-posix-dev" + else + apt_get_update_if_needed + fi + + # Install libssl1.1 if available + if [[ ! -z $(apt-cache --names-only search ^libssl1.1$) ]]; then + package_list="${package_list} libssl1.1" + fi + + # Install appropriate version of libssl1.0.x if available + libssl_package=$(dpkg-query -f '${db:Status-Abbrev}\t${binary:Package}\n' -W 'libssl1\.0\.?' 2>&1 || echo '') + if [ "$(echo "$LIlibssl_packageBSSL" | grep -o 'libssl1\.0\.[0-9]:' | uniq | sort | wc -l)" -eq 0 ]; then + if [[ ! -z $(apt-cache --names-only search ^libssl1.0.2$) ]]; then + # Debian 9 + package_list="${package_list} libssl1.0.2" + elif [[ ! -z $(apt-cache --names-only search ^libssl1.0.0$) ]]; then + # Ubuntu 18.04, 16.04, earlier + package_list="${package_list} libssl1.0.0" + fi + fi + + echo "Packages to verify are installed: ${package_list}" + apt-get -y install --no-install-recommends ${package_list} 2> >( grep -v 'debconf: delaying package configuration, since apt-utils is not installed' >&2 ) + + # Install git if not already installed (may be more recent than distro version) + if ! type git > /dev/null 2>&1; then + apt-get -y install --no-install-recommends git + fi + + PACKAGES_ALREADY_INSTALLED="true" +fi + +# Get to latest versions of all packages +if [ "${UPGRADE_PACKAGES}" = "true" ]; then + apt_get_update_if_needed + apt-get -y upgrade --no-install-recommends + apt-get autoremove -y +fi + +# Ensure at least the en_US.UTF-8 UTF-8 locale is available. +# Common need for both applications and things like the agnoster ZSH theme. +if [ "${LOCALE_ALREADY_SET}" != "true" ] && ! grep -o -E '^\s*en_US.UTF-8\s+UTF-8' /etc/locale.gen > /dev/null; then + echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen + locale-gen + LOCALE_ALREADY_SET="true" +fi + +# Create or update a non-root user to match UID/GID. +group_name="${USERNAME}" +if id -u ${USERNAME} > /dev/null 2>&1; then + # User exists, update if needed + if [ "${USER_GID}" != "automatic" ] && [ "$USER_GID" != "$(id -g $USERNAME)" ]; then + group_name="$(id -gn $USERNAME)" + groupmod --gid $USER_GID ${group_name} + usermod --gid $USER_GID $USERNAME + fi + if [ "${USER_UID}" != "automatic" ] && [ "$USER_UID" != "$(id -u $USERNAME)" ]; then + usermod --uid $USER_UID $USERNAME + fi +else + # Create user + if [ "${USER_GID}" = "automatic" ]; then + groupadd $USERNAME + else + groupadd --gid $USER_GID $USERNAME + fi + if [ "${USER_UID}" = "automatic" ]; then + useradd -s /bin/bash --gid $USERNAME -m $USERNAME + else + useradd -s /bin/bash --uid $USER_UID --gid $USERNAME -m $USERNAME + fi +fi + +# Add add sudo support for non-root user +if [ "${USERNAME}" != "root" ] && [ "${EXISTING_NON_ROOT_USER}" != "${USERNAME}" ]; then + echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME + chmod 0440 /etc/sudoers.d/$USERNAME + EXISTING_NON_ROOT_USER="${USERNAME}" +fi + +# ** Shell customization section ** +if [ "${USERNAME}" = "root" ]; then + user_rc_path="/root" +else + user_rc_path="/home/${USERNAME}" +fi + +# Restore user .bashrc defaults from skeleton file if it doesn't exist or is empty +if [ ! -f "${user_rc_path}/.bashrc" ] || [ ! -s "${user_rc_path}/.bashrc" ] ; then + cp /etc/skel/.bashrc "${user_rc_path}/.bashrc" +fi + +# Restore user .profile defaults from skeleton file if it doesn't exist or is empty +if [ ! -f "${user_rc_path}/.profile" ] || [ ! -s "${user_rc_path}/.profile" ] ; then + cp /etc/skel/.profile "${user_rc_path}/.profile" +fi + +# .bashrc/.zshrc snippet +rc_snippet="$(cat << 'EOF' + +if [ -z "${USER}" ]; then export USER=$(whoami); fi +if [[ "${PATH}" != *"$HOME/.local/bin"* ]]; then export PATH="${PATH}:$HOME/.local/bin"; fi + +# Display optional first run image specific notice if configured and terminal is interactive +if [ -t 1 ] && [[ "${TERM_PROGRAM}" = "vscode" || "${TERM_PROGRAM}" = "codespaces" ]] && [ ! -f "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed" ]; then + if [ -f "/usr/local/etc/vscode-dev-containers/first-run-notice.txt" ]; then + cat "/usr/local/etc/vscode-dev-containers/first-run-notice.txt" + elif [ -f "/workspaces/.codespaces/shared/first-run-notice.txt" ]; then + cat "/workspaces/.codespaces/shared/first-run-notice.txt" + fi + mkdir -p "$HOME/.config/vscode-dev-containers" + # Mark first run notice as displayed after 10s to avoid problems with fast terminal refreshes hiding it + ((sleep 10s; touch "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed") &) +fi + +# Set the default git editor if not already set +if [ -z "$(git config --get core.editor)" ] && [ -z "${GIT_EDITOR}" ]; then + if [ "${TERM_PROGRAM}" = "vscode" ]; then + if [[ -n $(command -v code-insiders) && -z $(command -v code) ]]; then + export GIT_EDITOR="code-insiders --wait" + else + export GIT_EDITOR="code --wait" + fi + fi +fi + +EOF +)" + +# code shim, it fallbacks to code-insiders if code is not available +cat << 'EOF' > /usr/local/bin/code +#!/bin/sh + +get_in_path_except_current() { + which -a "$1" | grep -A1 "$0" | grep -v "$0" +} + +code="$(get_in_path_except_current code)" + +if [ -n "$code" ]; then + exec "$code" "$@" +elif [ "$(command -v code-insiders)" ]; then + exec code-insiders "$@" +else + echo "code or code-insiders is not installed" >&2 + exit 127 +fi +EOF +chmod +x /usr/local/bin/code + +# systemctl shim - tells people to use 'service' if systemd is not running +cat << 'EOF' > /usr/local/bin/systemctl +#!/bin/sh +set -e +if [ -d "/run/systemd/system" ]; then + exec /bin/systemctl/systemctl "$@" +else + echo '\n"systemd" is not running in this container due to its overhead.\nUse the "service" command to start services instead. e.g.: \n\nservice --status-all' +fi +EOF +chmod +x /usr/local/bin/systemctl + +# Codespaces bash and OMZ themes - partly inspired by https://github.com/ohmyzsh/ohmyzsh/blob/master/themes/robbyrussell.zsh-theme +codespaces_bash="$(cat \ +<<'EOF' + +# Codespaces bash prompt theme +__bash_prompt() { + local userpart='`export XIT=$? \ + && [ ! -z "${GITHUB_USER}" ] && echo -n "\[\033[0;32m\]@${GITHUB_USER} " || echo -n "\[\033[0;32m\]\u " \ + && [ "$XIT" -ne "0" ] && echo -n "\[\033[1;31m\]➜" || echo -n "\[\033[0m\]➜"`' + local gitbranch='`\ + if [ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ]; then \ + export BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || git rev-parse --short HEAD 2>/dev/null); \ + if [ "${BRANCH}" != "" ]; then \ + echo -n "\[\033[0;36m\](\[\033[1;31m\]${BRANCH}" \ + && if git ls-files --error-unmatch -m --directory --no-empty-directory -o --exclude-standard ":/*" > /dev/null 2>&1; then \ + echo -n " \[\033[1;33m\]✗"; \ + fi \ + && echo -n "\[\033[0;36m\]) "; \ + fi; \ + fi`' + local lightblue='\[\033[1;34m\]' + local removecolor='\[\033[0m\]' + PS1="${userpart} ${lightblue}\w ${gitbranch}${removecolor}\$ " + unset -f __bash_prompt +} +__bash_prompt + +EOF +)" + +codespaces_zsh="$(cat \ +<<'EOF' +# Codespaces zsh prompt theme +__zsh_prompt() { + local prompt_username + if [ ! -z "${GITHUB_USER}" ]; then + prompt_username="@${GITHUB_USER}" + else + prompt_username="%n" + fi + PROMPT="%{$fg[green]%}${prompt_username} %(?:%{$reset_color%}➜ :%{$fg_bold[red]%}➜ )" # User/exit code arrow + PROMPT+='%{$fg_bold[blue]%}%(5~|%-1~/…/%3~|%4~)%{$reset_color%} ' # cwd + PROMPT+='$([ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ] && git_prompt_info)' # Git status + PROMPT+='%{$fg[white]%}$ %{$reset_color%}' + unset -f __zsh_prompt +} +ZSH_THEME_GIT_PROMPT_PREFIX="%{$fg_bold[cyan]%}(%{$fg_bold[red]%}" +ZSH_THEME_GIT_PROMPT_SUFFIX="%{$reset_color%} " +ZSH_THEME_GIT_PROMPT_DIRTY=" %{$fg_bold[yellow]%}✗%{$fg_bold[cyan]%})" +ZSH_THEME_GIT_PROMPT_CLEAN="%{$fg_bold[cyan]%})" +__zsh_prompt + +EOF +)" + +# Add RC snippet and custom bash prompt +if [ "${RC_SNIPPET_ALREADY_ADDED}" != "true" ]; then + echo "${rc_snippet}" >> /etc/bash.bashrc + echo "${codespaces_bash}" >> "${user_rc_path}/.bashrc" + echo 'export PROMPT_DIRTRIM=4' >> "${user_rc_path}/.bashrc" + if [ "${USERNAME}" != "root" ]; then + echo "${codespaces_bash}" >> "/root/.bashrc" + echo 'export PROMPT_DIRTRIM=4' >> "/root/.bashrc" + fi + chown ${USERNAME}:${group_name} "${user_rc_path}/.bashrc" + RC_SNIPPET_ALREADY_ADDED="true" +fi + +# Optionally install and configure zsh and Oh My Zsh! +if [ "${INSTALL_ZSH}" = "true" ]; then + if ! type zsh > /dev/null 2>&1; then + apt_get_update_if_needed + apt-get install -y zsh + fi + if [ "${ZSH_ALREADY_INSTALLED}" != "true" ]; then + echo "${rc_snippet}" >> /etc/zsh/zshrc + ZSH_ALREADY_INSTALLED="true" + fi + + # Adapted, simplified inline Oh My Zsh! install steps that adds, defaults to a codespaces theme. + # See https://github.com/ohmyzsh/ohmyzsh/blob/master/tools/install.sh for official script. + oh_my_install_dir="${user_rc_path}/.oh-my-zsh" + if [ ! -d "${oh_my_install_dir}" ] && [ "${INSTALL_OH_MYS}" = "true" ]; then + template_path="${oh_my_install_dir}/templates/zshrc.zsh-template" + user_rc_file="${user_rc_path}/.zshrc" + umask g-w,o-w + mkdir -p ${oh_my_install_dir} + git clone --depth=1 \ + -c core.eol=lf \ + -c core.autocrlf=false \ + -c fsck.zeroPaddedFilemode=ignore \ + -c fetch.fsck.zeroPaddedFilemode=ignore \ + -c receive.fsck.zeroPaddedFilemode=ignore \ + "https://github.com/ohmyzsh/ohmyzsh" "${oh_my_install_dir}" 2>&1 + echo -e "$(cat "${template_path}")\nDISABLE_AUTO_UPDATE=true\nDISABLE_UPDATE_PROMPT=true" > ${user_rc_file} + sed -i -e 's/ZSH_THEME=.*/ZSH_THEME="codespaces"/g' ${user_rc_file} + + mkdir -p ${oh_my_install_dir}/custom/themes + echo "${codespaces_zsh}" > "${oh_my_install_dir}/custom/themes/codespaces.zsh-theme" + # Shrink git while still enabling updates + cd "${oh_my_install_dir}" + git repack -a -d -f --depth=1 --window=1 + # Copy to non-root user if one is specified + if [ "${USERNAME}" != "root" ]; then + cp -rf "${user_rc_file}" "${oh_my_install_dir}" /root + chown -R ${USERNAME}:${group_name} "${user_rc_path}" + fi + fi +fi + +# Persist image metadata info, script if meta.env found in same directory +meta_info_script="$(cat << 'EOF' +#!/bin/sh +. /usr/local/etc/vscode-dev-containers/meta.env + +# Minimal output +if [ "$1" = "version" ] || [ "$1" = "image-version" ]; then + echo "${VERSION}" + exit 0 +elif [ "$1" = "release" ]; then + echo "${GIT_REPOSITORY_RELEASE}" + exit 0 +elif [ "$1" = "content" ] || [ "$1" = "content-url" ] || [ "$1" = "contents" ] || [ "$1" = "contents-url" ]; then + echo "${CONTENTS_URL}" + exit 0 +fi + +#Full output +echo +echo "Development container image information" +echo +if [ ! -z "${VERSION}" ]; then echo "- Image version: ${VERSION}"; fi +if [ ! -z "${DEFINITION_ID}" ]; then echo "- Definition ID: ${DEFINITION_ID}"; fi +if [ ! -z "${VARIANT}" ]; then echo "- Variant: ${VARIANT}"; fi +if [ ! -z "${GIT_REPOSITORY}" ]; then echo "- Source code repository: ${GIT_REPOSITORY}"; fi +if [ ! -z "${GIT_REPOSITORY_RELEASE}" ]; then echo "- Source code release/branch: ${GIT_REPOSITORY_RELEASE}"; fi +if [ ! -z "${BUILD_TIMESTAMP}" ]; then echo "- Timestamp: ${BUILD_TIMESTAMP}"; fi +if [ ! -z "${CONTENTS_URL}" ]; then echo && echo "More info: ${CONTENTS_URL}"; fi +echo +EOF +)" +if [ -f "${SCRIPT_DIR}/meta.env" ]; then + mkdir -p /usr/local/etc/vscode-dev-containers/ + cp -f "${SCRIPT_DIR}/meta.env" /usr/local/etc/vscode-dev-containers/meta.env + echo "${meta_info_script}" > /usr/local/bin/devcontainer-info + chmod +x /usr/local/bin/devcontainer-info +fi + +# Write marker file +mkdir -p "$(dirname "${MARKER_FILE}")" +echo -e "\ + PACKAGES_ALREADY_INSTALLED=${PACKAGES_ALREADY_INSTALLED}\n\ + LOCALE_ALREADY_SET=${LOCALE_ALREADY_SET}\n\ + EXISTING_NON_ROOT_USER=${EXISTING_NON_ROOT_USER}\n\ + RC_SNIPPET_ALREADY_ADDED=${RC_SNIPPET_ALREADY_ADDED}\n\ + ZSH_ALREADY_INSTALLED=${ZSH_ALREADY_INSTALLED}" > "${MARKER_FILE}" + +echo "Done!" diff --git a/containers/kubernetes-helm-k3d/.devcontainer/library-scripts/docker-in-docker-debian.sh b/containers/kubernetes-helm-k3d/.devcontainer/library-scripts/docker-in-docker-debian.sh new file mode 100755 index 0000000000..2d37efc302 --- /dev/null +++ b/containers/kubernetes-helm-k3d/.devcontainer/library-scripts/docker-in-docker-debian.sh @@ -0,0 +1,346 @@ +#!/usr/bin/env bash +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- +# +# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/docker-in-docker.md +# Maintainer: The VS Code and Codespaces Teams +# +# Syntax: ./docker-in-docker-debian.sh [enable non-root docker access flag] [non-root user] [use moby] [Engine/CLI Version] [Major version for docker-compose] + +ENABLE_NONROOT_DOCKER=${1:-"true"} +USERNAME=${2:-"automatic"} +USE_MOBY=${3:-"true"} +DOCKER_VERSION=${4:-"latest"} # The Docker/Moby Engine + CLI should match in version +DOCKER_DASH_COMPOSE_VERSION=${5:-"v1"} # v1 or v2 +MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc" + +set -e + +if [ "$(id -u)" -ne 0 ]; then + echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.' + exit 1 +fi + +# Determine the appropriate non-root user +if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then + USERNAME="" + POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)") + for CURRENT_USER in ${POSSIBLE_USERS[@]}; do + if id -u ${CURRENT_USER} > /dev/null 2>&1; then + USERNAME=${CURRENT_USER} + break + fi + done + if [ "${USERNAME}" = "" ]; then + USERNAME=root + fi +elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then + USERNAME=root +fi + +# Get central common setting +get_common_setting() { + if [ "${common_settings_file_loaded}" != "true" ]; then + curl -sfL "https://aka.ms/vscode-dev-containers/script-library/settings.env" 2>/dev/null -o /tmp/vsdc-settings.env || echo "Could not download settings file. Skipping." + common_settings_file_loaded=true + fi + if [ -f "/tmp/vsdc-settings.env" ]; then + local multi_line="" + if [ "$2" = "true" ]; then multi_line="-z"; fi + local result="$(grep ${multi_line} -oP "$1=\"?\K[^\"]+" /tmp/vsdc-settings.env | tr -d '\0')" + if [ ! -z "${result}" ]; then declare -g $1="${result}"; fi + fi + echo "$1=${!1}" +} + +# Function to run apt-get if needed +apt_get_update_if_needed() +{ + if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then + echo "Running apt-get update..." + apt-get update + else + echo "Skipping apt-get update." + fi +} + +# Checks if packages are installed and installs them if not +check_packages() { + if ! dpkg -s "$@" > /dev/null 2>&1; then + apt_get_update_if_needed + apt-get -y install --no-install-recommends "$@" + fi +} + +# Figure out correct version of a three part version number is not passed +find_version_from_git_tags() { + local variable_name=$1 + local requested_version=${!variable_name} + if [ "${requested_version}" = "none" ]; then return; fi + local repository=$2 + local prefix=${3:-"tags/v"} + local separator=${4:-"."} + local last_part_optional=${5:-"false"} + if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then + local escaped_separator=${separator//./\\.} + local last_part + if [ "${last_part_optional}" = "true" ]; then + last_part="(${escaped_separator}[0-9]+)?" + else + last_part="${escaped_separator}[0-9]+" + fi + local regex="${prefix}\\K[0-9]+${escaped_separator}[0-9]+${last_part}$" + local version_list="$(git ls-remote --tags ${repository} | grep -oP "${regex}" | tr -d ' ' | tr "${separator}" "." | sort -rV)" + if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "current" ] || [ "${requested_version}" = "lts" ]; then + declare -g ${variable_name}="$(echo "${version_list}" | head -n 1)" + else + set +e + declare -g ${variable_name}="$(echo "${version_list}" | grep -E -m 1 "^${requested_version//./\\.}([\\.\\s]|$)")" + set -e + fi + fi + if [ -z "${!variable_name}" ] || ! echo "${version_list}" | grep "^${!variable_name//./\\.}$" > /dev/null 2>&1; then + echo -e "Invalid ${variable_name} value: ${requested_version}\nValid values:\n${version_list}" >&2 + exit 1 + fi + echo "${variable_name}=${!variable_name}" +} + +# Ensure apt is in non-interactive to avoid prompts +export DEBIAN_FRONTEND=noninteractive + +# Install dependencies +check_packages apt-transport-https curl ca-certificates pigz iptables gnupg2 dirmngr +if ! type git > /dev/null 2>&1; then + apt_get_update_if_needed + apt-get -y install git +fi + +# Swap to legacy iptables for compatibility +if type iptables-legacy > /dev/null 2>&1; then + update-alternatives --set iptables /usr/sbin/iptables-legacy + update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy +fi + +# Source /etc/os-release to get OS info +. /etc/os-release +# Fetch host/container arch. +architecture="$(dpkg --print-architecture)" + +# Set up the necessary apt repos (either Microsoft's or Docker's) +if [ "${USE_MOBY}" = "true" ]; then + + # Name of open source engine/cli + engine_package_name="moby-engine" + cli_package_name="moby-cli" + + # Import key safely and import Microsoft apt repo + get_common_setting MICROSOFT_GPG_KEYS_URI + curl -sSL ${MICROSOFT_GPG_KEYS_URI} | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg + echo "deb [arch=${architecture} signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list +else + # Name of licensed engine/cli + engine_package_name="docker-ce" + cli_package_name="docker-ce-cli" + + # Import key safely and import Docker apt repo + curl -fsSL https://download.docker.com/linux/${ID}/gpg | gpg --dearmor > /usr/share/keyrings/docker-archive-keyring.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/${ID} ${VERSION_CODENAME} stable" > /etc/apt/sources.list.d/docker.list +fi + +# Refresh apt lists +apt-get update + +# Soft version matching +if [ "${DOCKER_VERSION}" = "latest" ] || [ "${DOCKER_VERSION}" = "lts" ] || [ "${DOCKER_VERSION}" = "stable" ]; then + # Empty, meaning grab whatever "latest" is in apt repo + engine_version_suffix="" + cli_version_suffix="" +else + # Fetch a valid version from the apt-cache (eg: the Microsoft repo appends +azure, breakfix, etc...) + docker_version_dot_escaped="${DOCKER_VERSION//./\\.}" + docker_version_dot_plus_escaped="${docker_version_dot_escaped//+/\\+}" + # Regex needs to handle debian package version number format: https://www.systutorials.com/docs/linux/man/5-deb-version/ + docker_version_regex="^(.+:)?${docker_version_dot_plus_escaped}([\\.\\+ ~:-]|$)" + set +e # Don't exit if finding version fails - will handle gracefully + cli_version_suffix="=$(apt-cache madison ${cli_package_name} | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${docker_version_regex}")" + engine_version_suffix="=$(apt-cache madison ${engine_package_name} | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${docker_version_regex}")" + set -e + if [ -z "${engine_version_suffix}" ] || [ "${engine_version_suffix}" = "=" ] || [ -z "${cli_version_suffix}" ] || [ "${cli_version_suffix}" = "=" ] ; then + echo "(!) No full or partial Docker / Moby version match found for \"${DOCKER_VERSION}\" on OS ${ID} ${VERSION_CODENAME} (${architecture}). Available versions:" + apt-cache madison ${cli_package_name} | awk -F"|" '{print $2}' | grep -oP '^(.+:)?\K.+' + exit 1 + fi + echo "engine_version_suffix ${engine_version_suffix}" + echo "cli_version_suffix ${cli_version_suffix}" +fi + +# Install Docker / Moby CLI if not already installed +if type docker > /dev/null 2>&1 && type dockerd > /dev/null 2>&1; then + echo "Docker / Moby CLI and Engine already installed." +else + if [ "${USE_MOBY}" = "true" ]; then + apt-get -y install --no-install-recommends moby-cli${cli_version_suffix} moby-buildx moby-engine${engine_version_suffix} + apt-get -y install --no-install-recommends moby-compose || echo "(*) Package moby-compose (Docker Compose v2) not available for OS ${ID} ${VERSION_CODENAME} (${architecture}). Skipping." + else + apt-get -y install --no-install-recommends docker-ce-cli${cli_version_suffix} docker-ce${engine_version_suffix} + fi +fi + +echo "Finished installing docker / moby!" + +# Install Docker Compose if not already installed and is on a supported architecture +if type docker-compose > /dev/null 2>&1; then + echo "Docker Compose v1 already installed." +else + target_compose_arch="${architecture}" + if [ "${target_compose_arch}" = "amd64" ]; then + target_compose_arch="x86_64" + fi + if [ "${target_compose_arch}" != "x86_64" ]; then + # Use pip to get a version that runs on this architecture + if ! dpkg -s python3-minimal python3-pip libffi-dev python3-venv > /dev/null 2>&1; then + apt_get_update_if_needed + apt-get -y install python3-minimal python3-pip libffi-dev python3-venv + fi + export PIPX_HOME=/usr/local/pipx + mkdir -p ${PIPX_HOME} + export PIPX_BIN_DIR=/usr/local/bin + export PYTHONUSERBASE=/tmp/pip-tmp + export PIP_CACHE_DIR=/tmp/pip-tmp/cache + pipx_bin=pipx + if ! type pipx > /dev/null 2>&1; then + pip3 install --disable-pip-version-check --no-cache-dir --user pipx + pipx_bin=/tmp/pip-tmp/bin/pipx + fi + ${pipx_bin} install --pip-args '--no-cache-dir --force-reinstall' docker-compose + rm -rf /tmp/pip-tmp + else + compose_v1_version="1" + find_version_from_git_tags compose_v1_version "https://github.com/docker/compose" "tags/" + echo "(*) Installing docker-compose ${compose_v1_version}..." + curl -fsSL "https://github.com/docker/compose/releases/download/${compose_v1_version}/docker-compose-Linux-x86_64" -o /usr/local/bin/docker-compose + chmod +x /usr/local/bin/docker-compose + fi +fi + +# Install docker-compose switch if not already installed - https://github.com/docker/compose-switch#manual-installation +current_v1_compose_path="$(which docker-compose)" +target_v1_compose_path="$(dirname "${current_v1_compose_path}")/docker-compose-v1" +if ! type compose-switch > /dev/null 2>&1; then + echo "(*) Installing compose-switch..." + compose_switch_version="latest" + find_version_from_git_tags compose_switch_version "https://github.com/docker/compose-switch" + curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch + chmod +x /usr/local/bin/compose-switch + # TODO: Verify checksum once available: https://github.com/docker/compose-switch/issues/11 + + # Setup v1 CLI as alternative in addition to compose-switch (which maps to v2) + mv "${current_v1_compose_path}" "${target_v1_compose_path}" + update-alternatives --install /usr/local/bin/docker-compose docker-compose /usr/local/bin/compose-switch 99 + update-alternatives --install /usr/local/bin/docker-compose docker-compose "${target_v1_compose_path}" 1 +fi +if [ "${DOCKER_DASH_COMPOSE_VERSION}" = "v1" ]; then + update-alternatives --set docker-compose "${target_v1_compose_path}" +else + update-alternatives --set docker-compose /usr/local/bin/compose-switch +fi + +# If init file already exists, exit +if [ -f "/usr/local/share/docker-init.sh" ]; then + echo "/usr/local/share/docker-init.sh already exists, so exiting." + exit 0 +fi +echo "docker-init doesnt exist, adding..." + +# Add user to the docker group +if [ "${ENABLE_NONROOT_DOCKER}" = "true" ]; then + if ! getent group docker > /dev/null 2>&1; then + groupadd docker + fi + + usermod -aG docker ${USERNAME} +fi + +tee /usr/local/share/docker-init.sh > /dev/null \ +<< 'EOF' +#!/bin/sh +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- + +set -e + +dockerd_start="$(cat << 'INNEREOF' + # explicitly remove dockerd and containerd PID file to ensure that it can start properly if it was stopped uncleanly + # ie: docker kill + find /run /var/run -iname 'docker*.pid' -delete || : + find /run /var/run -iname 'container*.pid' -delete || : + + ## Dind wrapper script from docker team, adapted to a function + # Maintained: https://github.com/moby/moby/blob/master/hack/dind + + export container=docker + + if [ -d /sys/kernel/security ] && ! mountpoint -q /sys/kernel/security; then + mount -t securityfs none /sys/kernel/security || { + echo >&2 'Could not mount /sys/kernel/security.' + echo >&2 'AppArmor detection and --privileged mode might break.' + } + fi + + # Mount /tmp (conditionally) + if ! mountpoint -q /tmp; then + mount -t tmpfs none /tmp + fi + + # cgroup v2: enable nesting + if [ -f /sys/fs/cgroup/cgroup.controllers ]; then + # move the processes from the root group to the /init group, + # otherwise writing subtree_control fails with EBUSY. + # An error during moving non-existent process (i.e., "cat") is ignored. + mkdir -p /sys/fs/cgroup/init + xargs -rn1 < /sys/fs/cgroup/cgroup.procs > /sys/fs/cgroup/init/cgroup.procs || : + # enable controllers + sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers \ + > /sys/fs/cgroup/cgroup.subtree_control + fi + ## Dind wrapper over. + + # Handle DNS + set +e + cat /etc/resolv.conf | grep -i 'internal.cloudapp.net' + if [ $? -eq 0 ] + then + echo "Setting dockerd Azure DNS." + CUSTOMDNS="--dns 168.63.129.16" + else + echo "Not setting dockerd DNS manually." + CUSTOMDNS="" + fi + set -e + + # Start docker/moby engine + ( dockerd $CUSTOMDNS > /tmp/dockerd.log 2>&1 ) & +INNEREOF +)" + +# Start using sudo if not invoked as root +if [ "$(id -u)" -ne 0 ]; then + sudo /bin/sh -c "${dockerd_start}" +else + eval "${dockerd_start}" +fi + +set +e + +# Execute whatever commands were passed in (if any). This allows us +# to set this script to ENTRYPOINT while still executing the default CMD. +exec "$@" +EOF + +chmod +x /usr/local/share/docker-init.sh +chown ${USERNAME}:root /usr/local/share/docker-init.sh diff --git a/containers/kubernetes-helm-k3d/.devcontainer/library-scripts/kubectl-helm-debian.sh b/containers/kubernetes-helm-k3d/.devcontainer/library-scripts/kubectl-helm-debian.sh new file mode 100755 index 0000000000..0981024fd1 --- /dev/null +++ b/containers/kubernetes-helm-k3d/.devcontainer/library-scripts/kubectl-helm-debian.sh @@ -0,0 +1,249 @@ +#!/usr/bin/env bash +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- +# +# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/kubectl-helm.md +# Maintainer: The VS Code and Codespaces Teams +# +# Syntax: ./kubectl-helm-debian.sh [kubectl verison] [Helm version] [minikube version] [kubectl SHA256] [Helm SHA256] [minikube SHA256] + +set -e + +KUBECTL_VERSION="${1:-"latest"}" +HELM_VERSION="${2:-"latest"}" +MINIKUBE_VERSION="${3:-"none"}" # latest is also valid +KUBECTL_SHA256="${4:-"automatic"}" +HELM_SHA256="${5:-"automatic"}" +MINIKUBE_SHA256="${6:-"automatic"}" +USERNAME=${7:-"automatic"} + +HELM_GPG_KEYS_URI="https://raw.githubusercontent.com/helm/helm/main/KEYS" +GPG_KEY_SERVERS="keyserver hkp://keyserver.ubuntu.com:80 +keyserver hkps://keys.openpgp.org +keyserver hkp://keyserver.pgp.com" + +if [ "$(id -u)" -ne 0 ]; then + echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.' + exit 1 +fi + +# Determine the appropriate non-root user +if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then + USERNAME="" + POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)") + for CURRENT_USER in ${POSSIBLE_USERS[@]}; do + if id -u ${CURRENT_USER} > /dev/null 2>&1; then + USERNAME=${CURRENT_USER} + break + fi + done + if [ "${USERNAME}" = "" ]; then + USERNAME=root + fi +elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then + USERNAME=root +fi + +USERHOME="/home/$USERNAME" +if [ "$USERNAME" = "root" ]; then + USERHOME="/root" +fi + + +# Get central common setting +get_common_setting() { + if [ "${common_settings_file_loaded}" != "true" ]; then + curl -sfL "https://aka.ms/vscode-dev-containers/script-library/settings.env" 2>/dev/null -o /tmp/vsdc-settings.env || echo "Could not download settings file. Skipping." + common_settings_file_loaded=true + fi + if [ -f "/tmp/vsdc-settings.env" ]; then + local multi_line="" + if [ "$2" = "true" ]; then multi_line="-z"; fi + local result="$(grep ${multi_line} -oP "$1=\"?\K[^\"]+" /tmp/vsdc-settings.env | tr -d '\0')" + if [ ! -z "${result}" ]; then declare -g $1="${result}"; fi + fi + echo "$1=${!1}" +} + +# Figure out correct version of a three part version number is not passed +find_version_from_git_tags() { + local variable_name=$1 + local requested_version=${!variable_name} + if [ "${requested_version}" = "none" ]; then return; fi + local repository=$2 + local prefix=${3:-"tags/v"} + local separator=${4:-"."} + local last_part_optional=${5:-"false"} + if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then + local escaped_separator=${separator//./\\.} + local last_part + if [ "${last_part_optional}" = "true" ]; then + last_part="(${escaped_separator}[0-9]+)?" + else + last_part="${escaped_separator}[0-9]+" + fi + local regex="${prefix}\\K[0-9]+${escaped_separator}[0-9]+${last_part}$" + local version_list="$(git ls-remote --tags ${repository} | grep -oP "${regex}" | tr -d ' ' | tr "${separator}" "." | sort -rV)" + if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "current" ] || [ "${requested_version}" = "lts" ]; then + declare -g ${variable_name}="$(echo "${version_list}" | head -n 1)" + else + set +e + declare -g ${variable_name}="$(echo "${version_list}" | grep -E -m 1 "^${requested_version//./\\.}([\\.\\s]|$)")" + set -e + fi + fi + if [ -z "${!variable_name}" ] || ! echo "${version_list}" | grep "^${!variable_name//./\\.}$" > /dev/null 2>&1; then + echo -e "Invalid ${variable_name} value: ${requested_version}\nValid values:\n${version_list}" >&2 + exit 1 + fi + echo "${variable_name}=${!variable_name}" +} + +# Function to run apt-get if needed +apt_get_update_if_needed() +{ + if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then + echo "Running apt-get update..." + apt-get update + else + echo "Skipping apt-get update." + fi +} + +# Checks if packages are installed and installs them if not +check_packages() { + if ! dpkg -s "$@" > /dev/null 2>&1; then + apt_get_update_if_needed + apt-get -y install --no-install-recommends "$@" + fi +} + +# Ensure apt is in non-interactive to avoid prompts +export DEBIAN_FRONTEND=noninteractive + +# Install dependencies +check_packages curl ca-certificates coreutils gnupg2 dirmngr bash-completion +if ! type git > /dev/null 2>&1; then + apt_get_update_if_needed + apt-get -y install --no-install-recommends git +fi + +architecture="$(uname -m)" +case $architecture in + x86_64) architecture="amd64";; + aarch64 | armv8*) architecture="arm64";; + aarch32 | armv7* | armvhf*) architecture="arm";; + i?86) architecture="386";; + *) echo "(!) Architecture $architecture unsupported"; exit 1 ;; +esac + +# Install the kubectl, verify checksum +echo "Downloading kubectl..." +if [ "${KUBECTL_VERSION}" = "latest" ] || [ "${KUBECTL_VERSION}" = "lts" ] || [ "${KUBECTL_VERSION}" = "current" ] || [ "${KUBECTL_VERSION}" = "stable" ]; then + KUBECTL_VERSION="$(curl -sSL https://dl.k8s.io/release/stable.txt)" +else + find_version_from_git_tags KUBECTL_VERSION https://github.com/kubernetes/kubernetes +fi +if [ "${KUBECTL_VERSION::1}" != 'v' ]; then + KUBECTL_VERSION="v${KUBECTL_VERSION}" +fi +curl -sSL -o /usr/local/bin/kubectl "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/${architecture}/kubectl" +chmod 0755 /usr/local/bin/kubectl +if [ "$KUBECTL_SHA256" = "automatic" ]; then + KUBECTL_SHA256="$(curl -sSL "https://dl.k8s.io/${KUBECTL_VERSION}/bin/linux/${architecture}/kubectl.sha256")" +fi +([ "${KUBECTL_SHA256}" = "dev-mode" ] || (echo "${KUBECTL_SHA256} */usr/local/bin/kubectl" | sha256sum -c -)) +if ! type kubectl > /dev/null 2>&1; then + echo '(!) kubectl installation failed!' + exit 1 +fi + +# kubectl bash completion +kubectl completion bash > /etc/bash_completion.d/kubectl + +# kubectl zsh completion +if [ -e "${USERHOME}}/.oh-my-zsh" ]; then + mkdir -p "${USERHOME}/.oh-my-zsh/completions" + kubectl completion zsh > "${USERHOME}/.oh-my-zsh/completions/_kubectl" + chown -R "${USERNAME}" "${USERHOME}/.oh-my-zsh" +fi + +# Install Helm, verify signature and checksum +echo "Downloading Helm..." +find_version_from_git_tags HELM_VERSION "https://github.com/helm/helm" +if [ "${HELM_VERSION::1}" != 'v' ]; then + HELM_VERSION="v${HELM_VERSION}" +fi +mkdir -p /tmp/helm +helm_filename="helm-${HELM_VERSION}-linux-${architecture}.tar.gz" +tmp_helm_filename="/tmp/helm/${helm_filename}" +curl -sSL "https://get.helm.sh/${helm_filename}" -o "${tmp_helm_filename}" +curl -sSL "https://github.com/helm/helm/releases/download/${HELM_VERSION}/${helm_filename}.asc" -o "${tmp_helm_filename}.asc" +export GNUPGHOME="/tmp/helm/gnupg" +mkdir -p "${GNUPGHOME}" +chmod 700 ${GNUPGHOME} +get_common_setting HELM_GPG_KEYS_URI +get_common_setting GPG_KEY_SERVERS true +curl -sSL "${HELM_GPG_KEYS_URI}" -o /tmp/helm/KEYS +echo -e "disable-ipv6\n${GPG_KEY_SERVERS}" > ${GNUPGHOME}/dirmngr.conf +gpg -q --import "/tmp/helm/KEYS" +if ! gpg --verify "${tmp_helm_filename}.asc" > ${GNUPGHOME}/verify.log 2>&1; then + echo "Verification failed!" + cat /tmp/helm/gnupg/verify.log + exit 1 +fi +if [ "${HELM_SHA256}" = "automatic" ]; then + curl -sSL "https://get.helm.sh/${helm_filename}.sha256" -o "${tmp_helm_filename}.sha256" + curl -sSL "https://github.com/helm/helm/releases/download/${HELM_VERSION}/${helm_filename}.sha256.asc" -o "${tmp_helm_filename}.sha256.asc" + if ! gpg --verify "${tmp_helm_filename}.sha256.asc" > /tmp/helm/gnupg/verify.log 2>&1; then + echo "Verification failed!" + cat /tmp/helm/gnupg/verify.log + exit 1 + fi + HELM_SHA256="$(cat "${tmp_helm_filename}.sha256")" +fi +([ "${HELM_SHA256}" = "dev-mode" ] || (echo "${HELM_SHA256} *${tmp_helm_filename}" | sha256sum -c -)) +tar xf "${tmp_helm_filename}" -C /tmp/helm +mv -f "/tmp/helm/linux-${architecture}/helm" /usr/local/bin/ +chmod 0755 /usr/local/bin/helm +rm -rf /tmp/helm +if ! type helm > /dev/null 2>&1; then + echo '(!) Helm installation failed!' + exit 1 +fi + +# Install Minikube, verify checksum +if [ "${MINIKUBE_VERSION}" != "none" ]; then + echo "Downloading minikube..." + if [ "${MINIKUBE_VERSION}" = "latest" ] || [ "${MINIKUBE_VERSION}" = "lts" ] || [ "${MINIKUBE_VERSION}" = "current" ] || [ "${MINIKUBE_VERSION}" = "stable" ]; then + MINIKUBE_VERSION="latest" + else + find_version_from_git_tags MINIKUBE_VERSION https://github.com/kubernetes/minikube + if [ "${MINIKUBE_VERSION::1}" != "v" ]; then + MINIKUBE_VERSION="v${MINIKUBE_VERSION}" + fi + fi + # latest is also valid in the download URLs + curl -sSL -o /usr/local/bin/minikube "https://storage.googleapis.com/minikube/releases/${MINIKUBE_VERSION}/minikube-linux-${architecture}" + chmod 0755 /usr/local/bin/minikube + if [ "$MINIKUBE_SHA256" = "automatic" ]; then + MINIKUBE_SHA256="$(curl -sSL "https://storage.googleapis.com/minikube/releases/${MINIKUBE_VERSION}/minikube-linux-${architecture}.sha256")" + fi + ([ "${MINIKUBE_SHA256}" = "dev-mode" ] || (echo "${MINIKUBE_SHA256} */usr/local/bin/minikube" | sha256sum -c -)) + if ! type minikube > /dev/null 2>&1; then + echo '(!) minikube installation failed!' + exit 1 + fi + # Create minkube folder with correct privs in case a volume is mounted here + mkdir -p "${USERHOME}/.minikube" + chown -R $USERNAME "${USERHOME}/.minikube" + chmod -R u+wrx "${USERHOME}/.minikube" +fi + +if ! type docker > /dev/null 2>&1; then + echo -e '\n(*) Warning: The docker command was not found.\n\nYou can use one of the following scripts to install it:\n\nhttps://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/docker-in-docker.md\n\nor\n\nhttps://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/docker.md' +fi + +echo -e "\nDone!" \ No newline at end of file diff --git a/containers/kubernetes-helm-k3d/.npmignore b/containers/kubernetes-helm-k3d/.npmignore new file mode 100644 index 0000000000..e1c966ce17 --- /dev/null +++ b/containers/kubernetes-helm-k3d/.npmignore @@ -0,0 +1,6 @@ +README.md +test-project +definition-manifest.json +.devcontainer/library-scripts/README.md +.vscode +.npmignore diff --git a/containers/kubernetes-helm-k3d/README.md b/containers/kubernetes-helm-k3d/README.md new file mode 100644 index 0000000000..6959362536 --- /dev/null +++ b/containers/kubernetes-helm-k3d/README.md @@ -0,0 +1,61 @@ +# Kubernetes - Minikube-in-Docker + +## Summary + +*Access an embedded minikube instance or remote a Kubernetes cluster from inside a dev container. Includes kubectl, Helm, minikube, and the Docker.* + +| Metadata | Value | +|----------|-------| +| *Contributors* | The VS Code team | +| *Categories* | Other | +| *Definition type* | Dockerfile | +| *Works in Codespaces* | Yes | +| *Container host OS support* | Linux, macOS, Windows | +| *Container OS* | Debian | +| *Languages, platforms* | Any | + +## Description + +> **Note:** If you're looking to reuse a local Kubernetes instance from Remote - Containers, you may find the [Kubernetes - Local Configuration](../kubernetes-helm) definition more interesting. + +Dev containers can be useful for all types of applications including those that also deploy into a container based-environment. While you can directly build and run the application inside the dev container you create, you may also want to test it by deploying a built container image into a local minikube or remote [Kubernetes](https://kubernetes.io/) cluster without affecting your dev container. + +This example illustrates how you can do this by using CLIs ([kubectl](https://kubernetes.io/docs/reference/kubectl/overview/), [Helm](https://helm.sh), Docker), the [Kubernetes extension](https://marketplace.visualstudio.com/items?itemName=ms-kubernetes-tools.vscode-kubernetes-tools), and the [Docker extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker) right from inside your dev container. This definition builds up from the [docker-in-docker](../docker-in-docker) container definition along with a [minikube](https://minikube.sigs.k8s.io/docs/) installation that can run right inside the container. It installs the Docker and Kubernetes extensions inside the container so you can use its full feature set with your project. + +## Using this definition with an existing folder + +A few notes on the definition: + +* The included `.devcontainer/Dockerfile` can be altered to work with other Debian/Ubuntu-based container images such as `node` or `python`. Just, update the `FROM` statement to reference the new base image. For example: + + ```Dockerfile + FROM node:lts + ``` + +* If you want minikube to automatically start when the dev container starts, uncomment the following line: + + ```json + "postStartCommand": "nohup bash -c 'minikube start &' > minikube.log 2>&1", + ``` + + This will log minikube output to `minikube.log` in your workspace folder, but you can update that part of the line above to a different path if you wish (e.g. `/tmp/minikube.log`). + +Beyond that, just follow these steps to use the definition: + +1. If this is your first time using a development container, please see getting started information on [setting up](https://aka.ms/vscode-remote/containers/getting-started) Remote-Containers or [creating a codespace](https://aka.ms/ghcs-open-codespace) using GitHub Codespaces. + +2. Start VS Code and open your project folder or connect to a codespace. + +3. Press F1 select and **Add Development Container Configuration Files...** command for **Remote-Containers** or **Codespaces**. + + > **Note:** If needed, you can drag-and-drop the `.devcontainer` folder from this sub-folder in a locally cloned copy of this repository into the VS Code file explorer instead of using the command. + +4. Select this definition. You may also need to select **Show All Definitions...** for it to appear. + +5. Finally, press F1 and run **Remote-Containers: Reopen Folder in Container** or **Codespaces: Rebuild Container** to start using the definition. + +## License + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. See [LICENSE](https://github.com/microsoft/vscode-dev-containers/blob/main/LICENSE). diff --git a/containers/kubernetes-helm-k3d/test-project/test-utils.sh b/containers/kubernetes-helm-k3d/test-project/test-utils.sh new file mode 100644 index 0000000000..6f1771133f --- /dev/null +++ b/containers/kubernetes-helm-k3d/test-project/test-utils.sh @@ -0,0 +1,149 @@ +#!/bin/bash +SCRIPT_FOLDER="$(cd "$(dirname $0)" && pwd)" +USERNAME=${1:-vscode} + +if [ -z $HOME ]; then + HOME="/root" +fi + +FAILED=() + +echoStderr() +{ + echo "$@" 1>&2 +} + +check() { + LABEL=$1 + shift + echo -e "\n🧪 Testing $LABEL" + if "$@"; then + echo "✅ Passed!" + return 0 + else + echoStderr "❌ $LABEL check failed." + FAILED+=("$LABEL") + return 1 + fi +} + +checkMultiple() { + PASSED=0 + LABEL="$1" + echo -e "\n🧪 Testing $LABEL." + shift; MINIMUMPASSED=$1 + shift; EXPRESSION="$1" + while [ "$EXPRESSION" != "" ]; do + if $EXPRESSION; then ((PASSED++)); fi + shift; EXPRESSION=$1 + done + if [ $PASSED -ge $MINIMUMPASSED ]; then + echo "✅ Passed!" + return 0 + else + echoStderr "❌ $LABEL check failed." + FAILED+=("$LABEL") + return 1 + fi +} + +checkOSPackages() { + LABEL=$1 + shift + echo -e "\n🧪 Testing $LABEL" + if dpkg-query --show -f='${Package}: ${Version}\n' "$@"; then + echo "✅ Passed!" + return 0 + else + echoStderr "❌ $LABEL check failed." + FAILED+=("$LABEL") + return 1 + fi +} + +checkExtension() { + # Happens asynchronusly, so keep retrying 10 times with an increasing delay + EXTN_ID="$1" + TIMEOUT_SECONDS="${2:-10}" + RETRY_COUNT=0 + echo -e -n "\n🧪 Looking for extension $1 for maximum of ${TIMEOUT_SECONDS}s" + until [ "${RETRY_COUNT}" -eq "${TIMEOUT_SECONDS}" ] || \ + [ ! -e $HOME/.vscode-server/extensions/${EXTN_ID}* ] || \ + [ ! -e $HOME/.vscode-server-insiders/extensions/${EXTN_ID}* ] || \ + [ ! -e $HOME/.vscode-test-server/extensions/${EXTN_ID}* ] || \ + [ ! -e $HOME/.vscode-remote/extensions/${EXTN_ID}* ] + do + sleep 1s + (( RETRY_COUNT++ )) + echo -n "." + done + + if [ ${RETRY_COUNT} -lt ${TIMEOUT_SECONDS} ]; then + echo -e "\n✅ Passed!" + return 0 + else + echoStderr -e "\n❌ Extension $EXTN_ID not found." + FAILED+=("$LABEL") + return 1 + fi +} + +checkCommon() +{ + PACKAGE_LIST="apt-utils \ + git \ + openssh-client \ + less \ + iproute2 \ + procps \ + curl \ + wget \ + unzip \ + nano \ + jq \ + lsb-release \ + ca-certificates \ + apt-transport-https \ + dialog \ + gnupg2 \ + libc6 \ + libgcc1 \ + libgssapi-krb5-2 \ + liblttng-ust0 \ + libstdc++6 \ + zlib1g \ + locales \ + sudo" + + # Actual tests + checkOSPackages "common-os-packages" ${PACKAGE_LIST} + checkMultiple "vscode-server" 1 "[ -d $HOME/.vscode-server/bin ]" "[ -d $HOME/.vscode-server-insiders/bin ]" "[ -d $HOME/.vscode-test-server/bin ]" "[ -d $HOME/.vscode-remote/bin ]" "[ -d $HOME/.vscode-remote/bin ]" + check "non-root-user" id ${USERNAME} + check "locale" [ $(locale -a | grep en_US.utf8) ] + check "sudo" sudo echo "sudo works." + check "zsh" zsh --version + check "oh-my-zsh" [ -d "$HOME/.oh-my-zsh" ] + check "login-shell-path" [ -f "/etc/profile.d/00-restore-env.sh" ] + check "code" which code +} + +reportResults() { + if [ ${#FAILED[@]} -ne 0 ]; then + echoStderr -e "\n💥 Failed tests: ${FAILED[@]}" + exit 1 + else + echo -e "\n💯 All passed!" + exit 0 + fi +} + +fixTestProjectFolderPrivs() { + if [ "${USERNAME}" != "root" ]; then + TEST_PROJECT_FOLDER="${1:-$SCRIPT_FOLDER}" + FOLDER_USER="$(stat -c '%U' "${TEST_PROJECT_FOLDER}")" + if [ "${FOLDER_USER}" != "${USERNAME}" ]; then + echoStderr "WARNING: Test project folder is owned by ${FOLDER_USER}. Updating to ${USERNAME}." + sudo chown -R ${USERNAME} "${TEST_PROJECT_FOLDER}" + fi + fi +} \ No newline at end of file diff --git a/containers/kubernetes-helm-k3d/test-project/test.sh b/containers/kubernetes-helm-k3d/test-project/test.sh new file mode 100755 index 0000000000..bbcbd484a1 --- /dev/null +++ b/containers/kubernetes-helm-k3d/test-project/test.sh @@ -0,0 +1,21 @@ +#!/bin/bash +cd $(dirname "$0") + +source test-utils.sh vscode + +# Run common tests +checkCommon + +# Actual tests +checkExtension "ms-azuretools.vscode-docker" +checkExtension "ms-kubernetes-tools.vscode-kubernetes-tools" +check "docker" docker ps -a +check "kubectl" kubectl version --client +check "helm" helm version --client +check "minikube start" minikube start +check "minikube remove" minikube delete +docker image prune -a -f + +# Report result +reportResults + From 97b1fcc76996200f3bb55c65e3309b5d2dcbb4d6 Mon Sep 17 00:00:00 2001 From: Kushal Azim Ekram Date: Mon, 16 May 2022 23:22:48 +0000 Subject: [PATCH 02/10] Modified script and dockerfile: install and verify k3d --- .../.devcontainer/Dockerfile | 4 +- .../library-scripts/kubectl-helm-debian.sh | 45 ++++++++----------- 2 files changed, 21 insertions(+), 28 deletions(-) diff --git a/containers/kubernetes-helm-k3d/.devcontainer/Dockerfile b/containers/kubernetes-helm-k3d/.devcontainer/Dockerfile index 8f576679c3..0fb0397e2c 100644 --- a/containers/kubernetes-helm-k3d/.devcontainer/Dockerfile +++ b/containers/kubernetes-helm-k3d/.devcontainer/Dockerfile @@ -16,8 +16,8 @@ COPY library-scripts/*.sh /tmp/library-scripts/ RUN apt-get update && /bin/bash /tmp/library-scripts/common-debian.sh "${INSTALL_ZSH}" "${USERNAME}" "${USER_UID}" "${USER_GID}" "${UPGRADE_PACKAGES}" "true" "true" \ && /bin/bash /tmp/library-scripts/docker-in-docker-debian.sh "true" "${USERNAME}" "${USE_MOBY}" \ && /bin/bash /tmp/library-scripts/kubectl-helm-debian.sh "latest" "latest" "latest" \ - && mkdir -p /home/${USERNAME}/.minikube \ - && chown ${USERNAME} /home/${USERNAME}/.minikube \ + && mkdir -p /home/${USERNAME}/.k3d \ + && chown ${USERNAME} /home/${USERNAME}/.k3d \ && apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/* /tmp/library-scripts/ VOLUME [ "/var/lib/docker" ] diff --git a/containers/kubernetes-helm-k3d/.devcontainer/library-scripts/kubectl-helm-debian.sh b/containers/kubernetes-helm-k3d/.devcontainer/library-scripts/kubectl-helm-debian.sh index 0981024fd1..4ec33ea944 100755 --- a/containers/kubernetes-helm-k3d/.devcontainer/library-scripts/kubectl-helm-debian.sh +++ b/containers/kubernetes-helm-k3d/.devcontainer/library-scripts/kubectl-helm-debian.sh @@ -7,16 +7,16 @@ # Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/kubectl-helm.md # Maintainer: The VS Code and Codespaces Teams # -# Syntax: ./kubectl-helm-debian.sh [kubectl verison] [Helm version] [minikube version] [kubectl SHA256] [Helm SHA256] [minikube SHA256] +# Syntax: ./kubectl-helm-debian.sh [kubectl verison] [Helm version] [k3d version] [kubectl SHA256] [Helm SHA256] [k3d SHA256] set -e KUBECTL_VERSION="${1:-"latest"}" HELM_VERSION="${2:-"latest"}" -MINIKUBE_VERSION="${3:-"none"}" # latest is also valid +K3D_VERSION="${3:-"none"}" # latest is also valid KUBECTL_SHA256="${4:-"automatic"}" HELM_SHA256="${5:-"automatic"}" -MINIKUBE_SHA256="${6:-"automatic"}" +K3D_SHA256="${6:-"automatic"}" USERNAME=${7:-"automatic"} HELM_GPG_KEYS_URI="https://raw.githubusercontent.com/helm/helm/main/KEYS" @@ -214,36 +214,29 @@ if ! type helm > /dev/null 2>&1; then exit 1 fi -# Install Minikube, verify checksum -if [ "${MINIKUBE_VERSION}" != "none" ]; then - echo "Downloading minikube..." - if [ "${MINIKUBE_VERSION}" = "latest" ] || [ "${MINIKUBE_VERSION}" = "lts" ] || [ "${MINIKUBE_VERSION}" = "current" ] || [ "${MINIKUBE_VERSION}" = "stable" ]; then - MINIKUBE_VERSION="latest" +# Install k3d with official installation method: +if [ "${K3D_VERSION}" != "none" ]; then + echo "Downloading k3d..." + if [ "${K3D_VERSION}" = "latest" ] || [ "${K3D_VERSION}" = "lts" ] || [ "${K3D_VERSION}" = "current" ] || [ "${K3D_VERSION}" = "stable" ]; then + # Install and check the hash + curl -sSL https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash else - find_version_from_git_tags MINIKUBE_VERSION https://github.com/kubernetes/minikube - if [ "${MINIKUBE_VERSION::1}" != "v" ]; then - MINIKUBE_VERSION="v${MINIKUBE_VERSION}" + find_version_from_git_tags K3D_VERSION https://github.com/kubernetes/K3D + if [ "${K3D_VERSION::1}" != "v" ]; then + K3D_VERSION="v${K3D_VERSION}" fi + # Install and check the hash + curl -sSL https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | TAG="${K3D_VERSION}" bash fi - # latest is also valid in the download URLs - curl -sSL -o /usr/local/bin/minikube "https://storage.googleapis.com/minikube/releases/${MINIKUBE_VERSION}/minikube-linux-${architecture}" - chmod 0755 /usr/local/bin/minikube - if [ "$MINIKUBE_SHA256" = "automatic" ]; then - MINIKUBE_SHA256="$(curl -sSL "https://storage.googleapis.com/minikube/releases/${MINIKUBE_VERSION}/minikube-linux-${architecture}.sha256")" - fi - ([ "${MINIKUBE_SHA256}" = "dev-mode" ] || (echo "${MINIKUBE_SHA256} */usr/local/bin/minikube" | sha256sum -c -)) - if ! type minikube > /dev/null 2>&1; then - echo '(!) minikube installation failed!' - exit 1 - fi + # Create minkube folder with correct privs in case a volume is mounted here - mkdir -p "${USERHOME}/.minikube" - chown -R $USERNAME "${USERHOME}/.minikube" - chmod -R u+wrx "${USERHOME}/.minikube" + mkdir -p "${USERHOME}/.k3d" + chown -R $USERNAME "${USERHOME}/.k3d" + chmod -R u+wrx "${USERHOME}/.k3d" fi if ! type docker > /dev/null 2>&1; then echo -e '\n(*) Warning: The docker command was not found.\n\nYou can use one of the following scripts to install it:\n\nhttps://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/docker-in-docker.md\n\nor\n\nhttps://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/docker.md' fi -echo -e "\nDone!" \ No newline at end of file +echo -e "\nDone!" From 755f37156394125f63bcf670b8e6e358bbf605e7 Mon Sep 17 00:00:00 2001 From: Nico J Date: Tue, 17 May 2022 10:48:47 -0700 Subject: [PATCH 03/10] Updated volumes path, postStartCommand and Test k3d checks --- .../.devcontainer/devcontainer.json | 14 +++++++------- .../kubernetes-helm-k3d/test-project/test.sh | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/containers/kubernetes-helm-k3d/.devcontainer/devcontainer.json b/containers/kubernetes-helm-k3d/.devcontainer/devcontainer.json index 4a22c4f8bd..5a2e80b5f6 100644 --- a/containers/kubernetes-helm-k3d/.devcontainer/devcontainer.json +++ b/containers/kubernetes-helm-k3d/.devcontainer/devcontainer.json @@ -1,10 +1,10 @@ { - "name": "Kubernetes - Minikube-in-Docker", + "name": "Kubernetes - k3d-in-Docker", "dockerFile": "Dockerfile", "runArgs": ["--privileged"], "mounts": [ - "source=minikube-var-lib-docker,target=/var/lib/docker,type=volume", - "source=minikube-config,target=/home/vscode/.minikube,type=volume", + "source=k3d-var-lib-docker,target=/var/lib/docker,type=volume", + "source=k3d-config,target=/home/vscode/.k3d,type=volume", ], "overrideCommand": false, @@ -23,9 +23,9 @@ // Use 'postCreateCommand' to run commands after the container is created. // "postCreateCommand": "kubectl version", - // Use 'postStartCommand' to run commands after the container is created like starting minikube. - // "postStartCommand": "nohup bash -c 'minikube start &' > minikube.log 2>&1", + // Use 'postStartCommand' to run commands after the container is created like starting k3d. + "postStartCommand": "k3d cluster create > k3d.log 2>&1", - // Minikube does not like running as root, so use a non-root user. + // k3d does not like running as root, so use a non-root user. "remoteUser": "vscode" -} +} \ No newline at end of file diff --git a/containers/kubernetes-helm-k3d/test-project/test.sh b/containers/kubernetes-helm-k3d/test-project/test.sh index bbcbd484a1..751fb01270 100755 --- a/containers/kubernetes-helm-k3d/test-project/test.sh +++ b/containers/kubernetes-helm-k3d/test-project/test.sh @@ -12,8 +12,8 @@ checkExtension "ms-kubernetes-tools.vscode-kubernetes-tools" check "docker" docker ps -a check "kubectl" kubectl version --client check "helm" helm version --client -check "minikube start" minikube start -check "minikube remove" minikube delete +check "k3d start" k3d cluster start +check "k3d stop" k3d cluster stop docker image prune -a -f # Report result From 36f74b3e4d37369787130a45e5d59632f8075e0c Mon Sep 17 00:00:00 2001 From: Kushal Azim Ekram Date: Tue, 17 May 2022 19:02:41 +0000 Subject: [PATCH 04/10] Added k3d delete test. Comment postStartCommand. Modify kubectl version to updated kubectl version --client=true --- .../kubernetes-helm-k3d/.devcontainer/devcontainer.json | 6 +++--- containers/kubernetes-helm-k3d/test-project/test.sh | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/containers/kubernetes-helm-k3d/.devcontainer/devcontainer.json b/containers/kubernetes-helm-k3d/.devcontainer/devcontainer.json index 5a2e80b5f6..b4acd8760f 100644 --- a/containers/kubernetes-helm-k3d/.devcontainer/devcontainer.json +++ b/containers/kubernetes-helm-k3d/.devcontainer/devcontainer.json @@ -21,11 +21,11 @@ // "forwardPorts": [], // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "kubectl version", + // "postCreateCommand": "kubectl version --client=true --output=yaml", // Use 'postStartCommand' to run commands after the container is created like starting k3d. - "postStartCommand": "k3d cluster create > k3d.log 2>&1", + // "postStartCommand": "k3d cluster create > k3d.log 2>&1", // k3d does not like running as root, so use a non-root user. "remoteUser": "vscode" -} \ No newline at end of file +} diff --git a/containers/kubernetes-helm-k3d/test-project/test.sh b/containers/kubernetes-helm-k3d/test-project/test.sh index 751fb01270..1831d0fd50 100755 --- a/containers/kubernetes-helm-k3d/test-project/test.sh +++ b/containers/kubernetes-helm-k3d/test-project/test.sh @@ -10,10 +10,11 @@ checkCommon checkExtension "ms-azuretools.vscode-docker" checkExtension "ms-kubernetes-tools.vscode-kubernetes-tools" check "docker" docker ps -a -check "kubectl" kubectl version --client +check "kubectl" kubectl version --client=true --output=yaml check "helm" helm version --client check "k3d start" k3d cluster start check "k3d stop" k3d cluster stop +check "k3d delete" k3d cluster delete docker image prune -a -f # Report result From e6e4327d8682afe51020461a14077d17a0bdf4d7 Mon Sep 17 00:00:00 2001 From: Kushal Azim Ekram Date: Tue, 17 May 2022 19:09:49 +0000 Subject: [PATCH 05/10] Updated readme with k3d specific information. --- containers/kubernetes-helm-k3d/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/containers/kubernetes-helm-k3d/README.md b/containers/kubernetes-helm-k3d/README.md index 6959362536..ac19e06982 100644 --- a/containers/kubernetes-helm-k3d/README.md +++ b/containers/kubernetes-helm-k3d/README.md @@ -1,8 +1,8 @@ -# Kubernetes - Minikube-in-Docker +# Kubernetes - K3d-in-Docker ## Summary -*Access an embedded minikube instance or remote a Kubernetes cluster from inside a dev container. Includes kubectl, Helm, minikube, and the Docker.* +*Access an embedded k3d instance or remote a Kubernetes cluster from inside a dev container. Includes kubectl, Helm, k3d, and the Docker.* | Metadata | Value | |----------|-------| @@ -18,9 +18,9 @@ > **Note:** If you're looking to reuse a local Kubernetes instance from Remote - Containers, you may find the [Kubernetes - Local Configuration](../kubernetes-helm) definition more interesting. -Dev containers can be useful for all types of applications including those that also deploy into a container based-environment. While you can directly build and run the application inside the dev container you create, you may also want to test it by deploying a built container image into a local minikube or remote [Kubernetes](https://kubernetes.io/) cluster without affecting your dev container. +Dev containers can be useful for all types of applications including those that also deploy into a container based-environment. While you can directly build and run the application inside the dev container you create, you may also want to test it by deploying a built container image into a local k3d or remote [Kubernetes](https://kubernetes.io/) cluster without affecting your dev container. -This example illustrates how you can do this by using CLIs ([kubectl](https://kubernetes.io/docs/reference/kubectl/overview/), [Helm](https://helm.sh), Docker), the [Kubernetes extension](https://marketplace.visualstudio.com/items?itemName=ms-kubernetes-tools.vscode-kubernetes-tools), and the [Docker extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker) right from inside your dev container. This definition builds up from the [docker-in-docker](../docker-in-docker) container definition along with a [minikube](https://minikube.sigs.k8s.io/docs/) installation that can run right inside the container. It installs the Docker and Kubernetes extensions inside the container so you can use its full feature set with your project. +This example illustrates how you can do this by using CLIs ([kubectl](https://kubernetes.io/docs/reference/kubectl/overview/), [Helm](https://helm.sh), Docker), the [Kubernetes extension](https://marketplace.visualstudio.com/items?itemName=ms-kubernetes-tools.vscode-kubernetes-tools), and the [Docker extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker) right from inside your dev container. This definition builds up from the [docker-in-docker](../docker-in-docker) container definition along with a [k3d](https://k3d.io/) installation that can run right inside the container. It installs the Docker and Kubernetes extensions inside the container so you can use its full feature set with your project. ## Using this definition with an existing folder @@ -32,13 +32,13 @@ A few notes on the definition: FROM node:lts ``` -* If you want minikube to automatically start when the dev container starts, uncomment the following line: +* If you want k3d to automatically start when the dev container starts, uncomment the following line: ```json - "postStartCommand": "nohup bash -c 'minikube start &' > minikube.log 2>&1", + "postStartCommand": "k3d cluster create > k3d.log 2>&1", ``` - This will log minikube output to `minikube.log` in your workspace folder, but you can update that part of the line above to a different path if you wish (e.g. `/tmp/minikube.log`). + This will log k3d output to `k3d.log` in your workspace folder, but you can update that part of the line above to a different path if you wish (e.g. `/tmp/k3d.log`). Beyond that, just follow these steps to use the definition: From 1413ed66f594556f979a8f3b694e279f317a3610 Mon Sep 17 00:00:00 2001 From: Siva Mullapudi Date: Tue, 17 May 2022 12:36:27 -0700 Subject: [PATCH 06/10] Add example steps on deploying an app to k8s cluster --- containers/kubernetes-helm-k3d/README.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/containers/kubernetes-helm-k3d/README.md b/containers/kubernetes-helm-k3d/README.md index ac19e06982..9d98fee30d 100644 --- a/containers/kubernetes-helm-k3d/README.md +++ b/containers/kubernetes-helm-k3d/README.md @@ -2,7 +2,7 @@ ## Summary -*Access an embedded k3d instance or remote a Kubernetes cluster from inside a dev container. Includes kubectl, Helm, k3d, and the Docker.* +*Access an embedded k3d instance or remote a Kubernetes cluster from inside a dev container. Includes kubectl, Helm, k3d, and Docker.* | Metadata | Value | |----------|-------| @@ -54,6 +54,28 @@ Beyond that, just follow these steps to use the definition: 5. Finally, press F1 and run **Remote-Containers: Reopen Folder in Container** or **Codespaces: Rebuild Container** to start using the definition. +## Getting started with Kubernetes Deployments + +Deploy an application into the local k3d cluster or remote kubernetes cluster by creating a Kubernetes Deployment object. + +```bash + +# Create a Deployment based on the YAML file +kubectl apply -f https://k8s.io/examples/application/deployment.yaml + +# Display information about the Deployment +kubectl describe deployment nginx-deployment + +# List the Pods created by the deployment +kubectl get pods -l app=nginx + +# Delete the deployment by name +kubectl delete deployment nginx-deployment + +``` + +Refer to the [Kubernetes documentation](https://kubernetes.io/docs/tasks/run-application/run-stateless-application-deployment/) for a detailed walkthrough on deploying applications to a Kubernetes cluster. + ## License Copyright (c) Microsoft Corporation. All rights reserved. From 020a202d3fc277050aeaa1bf271dea4ef4aa3a9b Mon Sep 17 00:00:00 2001 From: Kushal Azim Ekram Date: Tue, 17 May 2022 23:01:32 +0000 Subject: [PATCH 07/10] Fixed small markdown lint errors --- containers/kubernetes-helm-k3d/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/containers/kubernetes-helm-k3d/README.md b/containers/kubernetes-helm-k3d/README.md index 9d98fee30d..fefed6c58b 100644 --- a/containers/kubernetes-helm-k3d/README.md +++ b/containers/kubernetes-helm-k3d/README.md @@ -35,7 +35,7 @@ A few notes on the definition: * If you want k3d to automatically start when the dev container starts, uncomment the following line: ```json - "postStartCommand": "k3d cluster create > k3d.log 2>&1", + "postStartCommand": "k3d cluster create > k3d.log 2>&1", ``` This will log k3d output to `k3d.log` in your workspace folder, but you can update that part of the line above to a different path if you wish (e.g. `/tmp/k3d.log`). @@ -80,4 +80,4 @@ Refer to the [Kubernetes documentation](https://kubernetes.io/docs/tasks/run-app Copyright (c) Microsoft Corporation. All rights reserved. -Licensed under the MIT License. See [LICENSE](https://github.com/microsoft/vscode-dev-containers/blob/main/LICENSE). +Licensed under the MIT License. See [LICENSE](https://github.com/microsoft/vscode-dev-containers/blob/main/LICENSE). From fe2b4289141581311a01edbab46330bd87980508 Mon Sep 17 00:00:00 2001 From: Siva Mullapudi Date: Tue, 17 May 2022 16:16:50 -0700 Subject: [PATCH 08/10] Linter fix --- containers/kubernetes-helm-k3d/test-project/test-utils.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/containers/kubernetes-helm-k3d/test-project/test-utils.sh b/containers/kubernetes-helm-k3d/test-project/test-utils.sh index 6f1771133f..c1eb0be4df 100644 --- a/containers/kubernetes-helm-k3d/test-project/test-utils.sh +++ b/containers/kubernetes-helm-k3d/test-project/test-utils.sh @@ -146,4 +146,4 @@ fixTestProjectFolderPrivs() { sudo chown -R ${USERNAME} "${TEST_PROJECT_FOLDER}" fi fi -} \ No newline at end of file +} From fb6c83bfc3b90c40b20897ec3ef984c90c05e7dc Mon Sep 17 00:00:00 2001 From: Kushal Azim Ekram Date: Wed, 18 May 2022 11:36:04 -0700 Subject: [PATCH 09/10] Removed hardcoded vscode user. Replaced with remoteUser env variable --- containers/kubernetes-helm-k3d/.devcontainer/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/containers/kubernetes-helm-k3d/.devcontainer/devcontainer.json b/containers/kubernetes-helm-k3d/.devcontainer/devcontainer.json index b4acd8760f..582331a7ce 100644 --- a/containers/kubernetes-helm-k3d/.devcontainer/devcontainer.json +++ b/containers/kubernetes-helm-k3d/.devcontainer/devcontainer.json @@ -4,7 +4,7 @@ "runArgs": ["--privileged"], "mounts": [ "source=k3d-var-lib-docker,target=/var/lib/docker,type=volume", - "source=k3d-config,target=/home/vscode/.k3d,type=volume", + "source=k3d-config,target=/home/${remoteUser}/.k3d,type=volume" ], "overrideCommand": false, From bf33644eea27a07adcbabcc0b7f8466eff3219fd Mon Sep 17 00:00:00 2001 From: Nico J Date: Wed, 18 May 2022 11:38:33 -0700 Subject: [PATCH 10/10] Use $HOME in Dockerfile instead of hardcoding usr path --- containers/kubernetes-helm-k3d/.devcontainer/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/containers/kubernetes-helm-k3d/.devcontainer/Dockerfile b/containers/kubernetes-helm-k3d/.devcontainer/Dockerfile index 0fb0397e2c..dbd730c4b8 100644 --- a/containers/kubernetes-helm-k3d/.devcontainer/Dockerfile +++ b/containers/kubernetes-helm-k3d/.devcontainer/Dockerfile @@ -16,8 +16,8 @@ COPY library-scripts/*.sh /tmp/library-scripts/ RUN apt-get update && /bin/bash /tmp/library-scripts/common-debian.sh "${INSTALL_ZSH}" "${USERNAME}" "${USER_UID}" "${USER_GID}" "${UPGRADE_PACKAGES}" "true" "true" \ && /bin/bash /tmp/library-scripts/docker-in-docker-debian.sh "true" "${USERNAME}" "${USE_MOBY}" \ && /bin/bash /tmp/library-scripts/kubectl-helm-debian.sh "latest" "latest" "latest" \ - && mkdir -p /home/${USERNAME}/.k3d \ - && chown ${USERNAME} /home/${USERNAME}/.k3d \ + && mkdir -p $HOME/.k3d \ + && chown ${USERNAME} $HOME/.k3d \ && apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/* /tmp/library-scripts/ VOLUME [ "/var/lib/docker" ]