diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 57efb576..1d0c099d 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -54,7 +54,7 @@ Environment variables are centralized in `cicd/env-github-actions.sh` - always s All Dockerfiles follow the pattern `src/docker/Dockerfile-{flavor}` where flavor corresponds to OS distributions: -- `azurelinux3`, `bookworm`, `jammy`, `noble` (Linux variants) +- `alpine`, `azurelinux3`, `bookworm`, `jammy`, `noble` (Linux variants) - `ubi8`, `ubi9` (Red Hat Enterprise Linux) - `win-ltsc2022`, `win-ltsc2025` (Windows Server) @@ -211,7 +211,7 @@ All container flavors include standardized tool versions (defined in `cicd/env-g ### Base Image Selection - Prefer official base images from Microsoft, Red Hat, or Canonical -- Support multiple OS flavors: azurelinux3, bookworm, jammy, noble, ubi8, ubi9 +- Support multiple OS flavors: alpine, azurelinux3, bookworm, jammy, noble, ubi8, ubi9 - Use minimal/slim variants when available - Include Windows support with ltsc2022 and ltsc2025 variants diff --git a/.github/workflows/pipeline.yaml b/.github/workflows/pipeline.yaml index 7544b3e3..4a27e8f9 100644 --- a/.github/workflows/pipeline.yaml +++ b/.github/workflows/pipeline.yaml @@ -319,6 +319,11 @@ jobs: fail-fast: false matrix: include: + # Alpine Linux + - os: alpine + platform: linux/amd64 + - os: alpine + platform: linux/arm64 # Azure Linux 3 - os: azurelinux3 platform: linux/amd64 @@ -461,6 +466,8 @@ jobs: fail-fast: false matrix: os: [ + # Alpine Linux + alpine, # Azure Linux 3 azurelinux3, # Debian Bookworm @@ -1040,7 +1047,7 @@ jobs: # Rate limiting on Azure DevOps SaaS APIs is triggered quickly by integration tests, so we need to limit the number of parallel jobs max-parallel: 3 matrix: - os: [azurelinux3, bookworm, jammy, noble, ubi8, ubi9] + os: [alpine, azurelinux3, bookworm, jammy, noble, ubi8, ubi9] steps: - name: Checkout uses: actions/checkout@v4.2.2 diff --git a/README.md b/README.md index 8dd6729f..c8c7ad80 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ We broke through 2,000,000 container pulls in August! 🎉 - 📵 Can run air-gapped (no internet access). - 🔄 Agent register and restart itself. - 🔧 Packaged with common automation tools ([jq](https://github.com/stedolan/jq), [PowerShell Core](https://github.com/PowerShell/PowerShell), [Python 3](https://python.org), [rsync](https://rsync.samba.org), ...). -- 🖥️ Available with [Azure Linux](https://github.com/microsoft/azurelinux), [Debian](https://debian.org), [Ubuntu](https://ubuntu.com), [Red Hat Enterprise Linux](https://access.redhat.com/products/red-hat-enterprise-linux) and [Windows Server](https://www.microsoft.com/en-us/windows-server) +- 🖥️ Available with [Alpine Linux](https://alpinelinux.org), [Azure Linux](https://github.com/microsoft/azurelinux), [Debian](https://debian.org), [Ubuntu](https://ubuntu.com), [Red Hat Enterprise Linux](https://access.redhat.com/products/red-hat-enterprise-linux) and [Windows Server](https://www.microsoft.com/en-us/windows-server) ## Best practices for safety diff --git a/docs/content/docs/_index.md b/docs/content/docs/_index.md index 0e595df4..5c48166a 100644 --- a/docs/content/docs/_index.md +++ b/docs/content/docs/_index.md @@ -12,7 +12,7 @@ Blue Agent is self-hosted Azure Pipelines agent in Kubernetes, cheap to run, sec - 📵 Can run air-gapped (no internet access). - 🔄 Agent register and restart itself. - 🔧 Packaged with common automation tools ([jq](https://github.com/stedolan/jq), [PowerShell Core](https://github.com/PowerShell/PowerShell), [Python 3](https://python.org), [rsync](https://rsync.samba.org), ...). -- 🖥️ Available with [Azure Linux](https://github.com/microsoft/azurelinux), [Debian](https://debian.org), [Ubuntu](https://ubuntu.com), [Red Hat Enterprise Linux](https://access.redhat.com/products/red-hat-enterprise-linux) and [Windows Server](https://www.microsoft.com/en-us/windows-server) +- 🖥️ Available with [Alpine Linux](https://alpinelinux.org), [Azure Linux](https://github.com/microsoft/azurelinux), [Debian](https://debian.org), [Ubuntu](https://ubuntu.com), [Red Hat Enterprise Linux](https://access.redhat.com/products/red-hat-enterprise-linux) and [Windows Server](https://www.microsoft.com/en-us/windows-server) ## Best practices for safety diff --git a/docs/content/docs/advanced-topics/bicep-deployment.md b/docs/content/docs/advanced-topics/bicep-deployment.md index 182126b5..c7cf746b 100644 --- a/docs/content/docs/advanced-topics/bicep-deployment.md +++ b/docs/content/docs/advanced-topics/bicep-deployment.md @@ -12,7 +12,7 @@ Bicep is a deployment language for Azure, allowing to easily deploy resources on | `autoscalingMinReplicas` | Minimum number of replicas the agent should have | `0` | | `autoscalingPollingInterval` | Minimum number of replicas the agent should have; Warning, a low value will cause rate limiting or throttling, and can cause high load on the Azure DevOps API | `10` | | `extraEnv` | Extra environment variables to pass to the agent | `[]` | -| `imageFlavor` | Flavor of the container image, represents the Linux distribution. Allowed values: `azurelinux3`, `bookworm`, `jammy`, `noble`, `ubi8`, `ubi9` | `bookworm` | +| `imageFlavor` | Flavor of the container image, represents the Linux distribution. Allowed values: `alpine`, `azurelinux3`, `bookworm`, `jammy`, `noble`, `ubi8`, `ubi9` | `bookworm` | | `imageName` | Name of the container image | `clemlesne/blue-agent` | | `imageRegistry` | Registry of the container image. Allowed values: `docker.io`, `ghcr.io` | `ghcr.io` | | `imageVersion` | Version of the container image, it is recommended to use a specific version like "1.0.0" instead of "latest" | `main` | diff --git a/docs/content/docs/advanced-topics/build-python.md b/docs/content/docs/advanced-topics/build-python.md index 0f9a4eeb..e2540026 100644 --- a/docs/content/docs/advanced-topics/build-python.md +++ b/docs/content/docs/advanced-topics/build-python.md @@ -120,6 +120,7 @@ Blue Agent provides Python pre-installed with specific versions optimized for ea | Flavor | Python Version | Installation Method | | ------------- | -------------- | ------------------- | +| `alpine` | 3.13 | Built from source | | `azurelinux3` | 3.12 | Built from source | | `bookworm` | 3.13 | Built from source | | `jammy` | 3.13 | Built from source | diff --git a/docs/content/docs/advanced-topics/docker-in-docker.md b/docs/content/docs/advanced-topics/docker-in-docker.md index d94724d6..ea2f7416 100644 --- a/docs/content/docs/advanced-topics/docker-in-docker.md +++ b/docs/content/docs/advanced-topics/docker-in-docker.md @@ -17,6 +17,7 @@ Linux systems are supported, but not Windows: | `Ref` | Container build inside of the agent with BuildKit | | ------------------------------------------------ | ------------------------------------------------- | +| `ghcr.io/clemlesne/blue-agent:alpine-main` | ✅ | | `ghcr.io/clemlesne/blue-agent:azurelinux3-main` | ✅ | | `ghcr.io/clemlesne/blue-agent:bookworm-main` | ✅ | | `ghcr.io/clemlesne/blue-agent:jammy-main` | ✅ | diff --git a/docs/content/docs/advanced-topics/helm-deployment.md b/docs/content/docs/advanced-topics/helm-deployment.md index 20a62984..42548068 100644 --- a/docs/content/docs/advanced-topics/helm-deployment.md +++ b/docs/content/docs/advanced-topics/helm-deployment.md @@ -23,7 +23,7 @@ Helm is a package manager for Kubernetes, allowing to easily deploy applications | `extraVolumeMounts` | Additional volume mounts for the agent container | `[]` | | `extraVolumes` | Additional volumes for the agent pod | `[]` | | `fullnameOverride` | Overrides release fullname | `""` | -| `image.flavor` | Container image tag, can be `bookworm`, `jammy`, `noble`, `ubi8`, `ubi9`, `win-ltsc2022`, or `win-ltsc2025` | `bookworm` | +| `image.flavor` | Container image tag, can be `alpine`, `bookworm`, `jammy`, `noble`, `ubi8`, `ubi9`, `win-ltsc2022`, or `win-ltsc2025` | `bookworm` | | `image.isWindows` | Turn on is the agent is a Windows-based system | `false` | | `image.pullPolicy` | Container image pull policy | `IfNotPresent` | | `image.repository` | Container image repository | `ghcr.io/clemlesne/blue-agent` | diff --git a/docs/content/docs/getting-started.md b/docs/content/docs/getting-started.md index ab7a6930..b3ac9e6d 100644 --- a/docs/content/docs/getting-started.md +++ b/docs/content/docs/getting-started.md @@ -86,16 +86,17 @@ For detailed information about template container behavior, common errors, and t OS support is generally called "flavor" in this documentation. The following table shows the supported flavors and their characteristics. -| `Ref` | OS | `Size` | `Arch` | Support | -| ------------------------------------------------ | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | -| `ghcr.io/clemlesne/blue-agent:azurelinux3-main` | [Azure Linux 3](https://github.com/microsoft/azurelinux) | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/clemlesne/blue-agent/azurelinux3-main?label=) | `amd64`, `arm64/v8` | [See Microsoft Azure documentation.](https://learn.microsoft.com/en-us/azure/aks/support-policies) | -| `ghcr.io/clemlesne/blue-agent:bookworm-main` | [Debian Bookworm (12)](https://www.debian.org/releases/bookworm) slim | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/clemlesne/blue-agent/bookworm-main?label=) | `amd64`, `arm64/v8` | [See Debian LTS wiki.](https://wiki.debian.org/LTS) | -| `ghcr.io/clemlesne/blue-agent:noble-main` | [Ubuntu Noble (24.04)](https://www.releases.ubuntu.com/noble) minimal | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/clemlesne/blue-agent/noble-main?label=) | `amd64`, `arm64/v8` | [See Ubuntu LTS wiki.](https://wiki.ubuntu.com/Releases) | -| `ghcr.io/clemlesne/blue-agent:jammy-main` | [Ubuntu Jammy (22.04)](https://www.releases.ubuntu.com/jammy) minimal | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/clemlesne/blue-agent/jammy-main?label=) | `amd64`, `arm64/v8` | [See Ubuntu LTS wiki.](https://wiki.ubuntu.com/Releases) | -| `ghcr.io/clemlesne/blue-agent:ubi9-main` | [Red Hat UBI 9](https://developers.redhat.com/articles/ubi-faq) minimal | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/clemlesne/blue-agent/ubi9-main?label=) | `amd64`, `arm64/v8` | [See Red Hat product life cycles.](https://access.redhat.com/product-life-cycles/?product=Red%20Hat%20Enterprise%20Linux) | -| `ghcr.io/clemlesne/blue-agent:ubi8-main` | [Red Hat UBI 8](https://developers.redhat.com/articles/ubi-faq) minimal | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/clemlesne/blue-agent/ubi8-main?label=) | `amd64`, `arm64/v8` | [See Red Hat product life cycles.](https://access.redhat.com/product-life-cycles/?product=Red%20Hat%20Enterprise%20Linux) | -| `ghcr.io/clemlesne/blue-agent:win-ltsc2022-main` | [Windows Server 2022](https://learn.microsoft.com/en-us/windows-server) Core | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/clemlesne/blue-agent/win-ltsc2022-main?label=) | `amd64` | [See base image servicing lifecycles.](https://learn.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/base-image-lifecycle) | -| `ghcr.io/clemlesne/blue-agent:win-ltsc2025-main` | [Windows Server 2025](https://learn.microsoft.com/en-us/windows-server) Core | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/clemlesne/blue-agent/win-ltsc2025-main?label=) | `amd64` | [See base image servicing lifecycles.](https://learn.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/base-image-lifecycle) | +| `Ref` | OS | `Size` | `Arch` | Support | +| ------------------------------------------------ | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ghcr.io/clemlesne/blue-agent:alpine-main` | [Alpine Linux (3.21)](https://alpinelinux.org/posts/Alpine-3.21.0-released.html) | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/clemlesne/blue-agent/alpine-main?label=) | `amd64`, `arm64/v8` | [See Alpine Linux wiki.](https://alpinelinux.org/releases) | +| `ghcr.io/clemlesne/blue-agent:azurelinux3-main` | [Azure Linux 3](https://github.com/microsoft/azurelinux) | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/clemlesne/blue-agent/azurelinux3-main?label=) | `amd64`, `arm64/v8` | [See Microsoft Azure documentation.](https://learn.microsoft.com/en-us/azure/aks/support-policies) | +| `ghcr.io/clemlesne/blue-agent:bookworm-main` | [Debian Bookworm (12)](https://www.debian.org/releases/bookworm) slim | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/clemlesne/blue-agent/bookworm-main?label=) | `amd64`, `arm64/v8` | [See Debian LTS wiki.](https://wiki.debian.org/LTS) | +| `ghcr.io/clemlesne/blue-agent:noble-main` | [Ubuntu Noble (24.04)](https://www.releases.ubuntu.com/noble) minimal | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/clemlesne/blue-agent/noble-main?label=) | `amd64`, `arm64/v8` | [See Ubuntu LTS wiki.](https://wiki.ubuntu.com/Releases) | +| `ghcr.io/clemlesne/blue-agent:jammy-main` | [Ubuntu Jammy (22.04)](https://www.releases.ubuntu.com/jammy) minimal | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/clemlesne/blue-agent/jammy-main?label=) | `amd64`, `arm64/v8` | [See Ubuntu LTS wiki.](https://wiki.ubuntu.com/Releases) | +| `ghcr.io/clemlesne/blue-agent:ubi9-main` | [Red Hat UBI 9](https://developers.redhat.com/articles/ubi-faq) minimal | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/clemlesne/blue-agent/ubi9-main?label=) | `amd64`, `arm64/v8` | [See Red Hat product life cycles.](https://access.redhat.com/product-life-cycles/?product=Red%20Hat%20Enterprise%20Linux) | +| `ghcr.io/clemlesne/blue-agent:ubi8-main` | [Red Hat UBI 8](https://developers.redhat.com/articles/ubi-faq) minimal | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/clemlesne/blue-agent/ubi8-main?label=) | `amd64`, `arm64/v8` | [See Red Hat product life cycles.](https://access.redhat.com/product-life-cycles/?product=Red%20Hat%20Enterprise%20Linux) | +| `ghcr.io/clemlesne/blue-agent:win-ltsc2022-main` | [Windows Server 2022](https://learn.microsoft.com/en-us/windows-server) Core | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/clemlesne/blue-agent/win-ltsc2022-main?label=) | `amd64` | [See base image servicing lifecycles.](https://learn.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/base-image-lifecycle) | +| `ghcr.io/clemlesne/blue-agent:win-ltsc2025-main` | [Windows Server 2025](https://learn.microsoft.com/en-us/windows-server) Core | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/clemlesne/blue-agent/win-ltsc2025-main?label=) | `amd64` | [See base image servicing lifecycles.](https://learn.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/base-image-lifecycle) | ## Docker Hub images diff --git a/docs/content/docs/security.md b/docs/content/docs/security.md index 29ef94b5..126da255 100644 --- a/docs/content/docs/security.md +++ b/docs/content/docs/security.md @@ -14,6 +14,7 @@ Scanned systems: | `Ref` | Vulnerability scans with Snyk | | ------------------------------------------------ | ----------------------------- | +| `ghcr.io/clemlesne/blue-agent:alpine-main` | ✅ | | `ghcr.io/clemlesne/blue-agent:azurelinux3-main` | ✅ | | `ghcr.io/clemlesne/blue-agent:bookworm-main` | ✅ | | `ghcr.io/clemlesne/blue-agent:jammy-main` | ✅ | diff --git a/src/bicep/main.bicep b/src/bicep/main.bicep index 1d71a9eb..3c42b9b5 100644 --- a/src/bicep/main.bicep +++ b/src/bicep/main.bicep @@ -11,6 +11,7 @@ param autoscalingPollingInterval int = 10 param extraEnv array = [] @description('Flavor of the container image, represents the Linux distribution') @allowed([ + 'alpine' 'azurelinux3' 'bookworm' 'jammy' diff --git a/src/docker/Dockerfile-alpine b/src/docker/Dockerfile-alpine new file mode 100644 index 00000000..20f1d0da --- /dev/null +++ b/src/docker/Dockerfile-alpine @@ -0,0 +1,302 @@ +# syntax=docker/dockerfile:1 +# check=skip=UndefinedVar + +FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.21@sha256:d600a99dbc2076ceadc60c4ba60afc294e7916a652cffd88a0f62630d1b3c1fa AS base + +# Source platform from buildx "platform" argument +ARG TARGETPLATFORM + +# Configure local user +ENV USER=root +ENV HOME=/app-root + +# Avoid Python cache during build +ENV PYTHONDONTWRITEBYTECODE=1 + +# Ensure reliable Python pip installation +ENV PIP_DISABLE_PIP_VERSION_CHECK=1 +ENV PIP_QUIET=1 +ENV PIP_RETRIES=8 +ENV PIP_TIMEOUT=120 + +# Install: +# - Azure CLI system requirements (C/Rust build tools for libs non pre-built on this platform, plus GNU coreutils for entrypoint) +# - Azure Pipelines agent system requirements +# - dbus, fuse-overlayfs, iptables, for BuildKit +# - gzip, make, tar, unzip, wget, zip, zstd, dnsutils, rsync, gnupg, findutils, ca-certificates, for developer ease-of-life +# - zsh, for inter-operability +RUN --mount=target=/var/cache/apk,type=cache,id=apk-${TARGETPLATFORM},sharing=locked \ + apk update \ + && apk add \ + bash \ + build-base \ + ca-certificates \ + cargo \ + coreutils \ + curl \ + dbus \ + findutils \ + fuse-overlayfs \ + gcompat \ + git \ + git-lfs \ + gnupg \ + gzip \ + icu \ + icu-libs \ + iptables \ + iputils \ + jq \ + libffi-dev \ + linux-headers \ + lsb-release \ + openssl \ + openssl-dev \ + py3-pip \ + rsync \ + shadow \ + sudo \ + tar \ + unzip \ + wget \ + zip \ + zsh \ + zstd \ + && find / -depth -type d -name __pycache__ -exec rm -rf {} \; 2> /dev/null \ + # Replace timeout from BusyBox with GNU coreutils version + && ln -sf /usr/bin/timeout /bin/timeout + +# Copy helper script, then verify installation +COPY arch.sh . +RUN chmod +x arch.sh \ + && bash arch.sh + +# Persist Python version +ARG PYTHON_313_VERSION_MAJOR_MINOR +ARG PYTHON_313_VERSION_PATCH +ENV PYTHON_VERSION=${PYTHON_313_VERSION_MAJOR_MINOR}.${PYTHON_313_VERSION_PATCH} + +FROM base AS rootlesskit + +# Install Go, then verify installation +ARG GO_VERSION +ENV GO_VERSION=${GO_VERSION} +RUN rm -rf /usr/local/go \ + && curl -LsSf --retry 8 --retry-all-errors --connect-timeout 120 https://go.dev/dl/go${GO_VERSION}.linux-$(ARCH_X64=amd64 bash arch.sh).tar.gz | tar -xz -C /usr/local +ENV PATH="${PATH}:/usr/local/go/bin" +RUN go version + +# Install RootlessKit, then verify installation +ARG ROOTLESSKIT_VERSION +ENV ROOTLESSKIT_VERSION=${ROOTLESSKIT_VERSION} +RUN --mount=target=/rootlesskit-${ROOTLESSKIT_VERSION},type=cache,id=rootlesskit-${ROOTLESSKIT_VERSION}-${TARGETPLATFORM},sharing=locked \ + git clone --depth 1 --branch v${ROOTLESSKIT_VERSION} https://github.com/rootless-containers/rootlesskit.git rootlesskit \ + # Ugly but that's work + && cp -r rootlesskit/* rootlesskit-${ROOTLESSKIT_VERSION} \ + && rm -rf rootlesskit \ + && cd rootlesskit-${ROOTLESSKIT_VERSION} \ + && make \ + && make install \ + && cd .. \ + && rootlesskit --version \ + && rootlessctl --version + +FROM base AS python + +# Build Python from source, then verify installation +ARG PYTHON_VERSION +ENV PYTHON_VERSION=${PYTHON_VERSION} +RUN --mount=target=/var/cache/apk,type=cache,id=apk-${TARGETPLATFORM},sharing=locked --mount=target=/Python-${PYTHON_VERSION},type=cache,id=python-${PYTHON_VERSION}-${TARGETPLATFORM},sharing=locked \ + apk update \ + && apk add \ + bzip2 \ + bzip2-dev \ + dpkg \ + dpkg-dev \ + expat \ + expat-devel \ + gdb \ + gdbm-devel \ + glibc-devel \ + libffi-devel \ + libstdc++-devel \ + libuuid-devel \ + libxml2-devel \ + ncurses-devel \ + readline-dev \ + sqlite \ + sqlite-dev \ + tk-dev \ + xz-dev \ + zlib-dev \ + && curl -LsSf --retry 8 --retry-all-errors --connect-timeout 120 https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz -o python.tgz \ + && tar -xzf python.tgz \ + && rm python.tgz \ + && cd Python-${PYTHON_VERSION} \ + && gcc_arch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)" \ + && ./configure \ + --build=$gcc_arch \ + --enable-optimizations \ + --with-ensurepip=install \ + --with-lto \ + && make profile-removal \ + && extra_cflags="$(dpkg-buildflags --get CFLAGS)" \ + && ldflags="$(dpkg-buildflags --get LDFLAGS)" \ + && make -j $(nproc) "EXTRA_CFLAGS=${extra_cflags:-}" "LDFLAGS=${ldflags:-}" \ + && make install \ + && cd .. \ + && python3 --version \ + && python3 -m pip --version \ + && find / -depth -type d -name __pycache__ -exec rm -rf {} \; 2> /dev/null + +FROM base + +# Install Python, then verify installation +COPY --from=python /usr/local/bin/python${PYTHON_313_VERSION_MAJOR_MINOR} /usr/local/bin/python${PYTHON_313_VERSION_MAJOR_MINOR} +COPY --from=python /usr/local/lib/python${PYTHON_313_VERSION_MAJOR_MINOR} /usr/local/lib/python${PYTHON_313_VERSION_MAJOR_MINOR} +COPY --from=python /usr/local/include/python${PYTHON_313_VERSION_MAJOR_MINOR} /usr/local/include/python${PYTHON_313_VERSION_MAJOR_MINOR} +RUN ln -s /usr/local/bin/python${PYTHON_313_VERSION_MAJOR_MINOR} /usr/local/bin/python3 \ + && ln -s /usr/local/bin/python${PYTHON_313_VERSION_MAJOR_MINOR} /usr/local/bin/python \ + && python --version \ + && python3 --version \ + && python${PYTHON_313_VERSION_MAJOR_MINOR} --version \ + && python3 -m pip --version \ + # BusyBox env sets a minimal $PATH, local bin requires to be explicited + && echo 'export PATH=/usr/local/bin:$PATH' > /etc/profile.d/localbin.sh + +# Install Python build tools +RUN --mount=target=/${USER}/.cache/pip,type=cache,id=pip-${PYTHON_313_VERSION_MAJOR_MINOR}-${TARGETPLATFORM},sharing=locked \ + python3 -m pip install \ + --upgrade \ + pip setuptools wheel \ + && find / -depth -type d -name __pycache__ -exec rm -rf {} \; 2> /dev/null + +# Install Azure CLI, then verify installation +ARG AZURE_CLI_VERSION +ENV AZURE_CLI_VERSION=${AZURE_CLI_VERSION} +RUN --mount=target=/${USER}/.cache/pip,type=cache,id=pip-${PYTHON_313_VERSION_MAJOR_MINOR}-${TARGETPLATFORM},sharing=locked \ + python3 -m pip install \ + azure-cli==${AZURE_CLI_VERSION} \ + && az version \ + && rm -rf ${HOME}/.azure ${HOME}/.cache/pip \ + && find / -depth -type d -name __pycache__ -exec rm -rf {} \; 2> /dev/null + +FROM base AS awscli + +# Install AWS CLI from sources as bins are published with glibc, then verify installation +# See: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-source-install.html +ARG AWS_CLI_VERSION +ENV AWS_CLI_VERSION=${AWS_CLI_VERSION} +RUN --mount=target=/var/cache/apk,type=cache,id=apk-${TARGETPLATFORM},sharing=locked \ + apk add \ + cmake \ + g++ \ + gcc \ + libc-dev \ + && curl -LsSf --retry 8 --retry-all-errors --connect-timeout 120 https://awscli.amazonaws.com/awscli-${AWS_CLI_VERSION}.tar.gz | tar -xz \ + && cd awscli-${AWS_CLI_VERSION} \ + && ./configure \ + --prefix=/usr/local/aws-cli/ \ + --with-download-deps \ + && make \ + && make install \ + && /usr/local/aws-cli/bin/aws --version + +FROM base + +# Copy AWS CLI bins, then verify installation +COPY --from=awscli /usr/local/aws-cli/ /usr/local/aws-cli/ +ENV PATH="${PATH}:/usr/local/aws-cli/bin" +RUN aws --version + +# Install Google Cloud CLI, then verify installation +ARG GCLOUD_CLI_VERSION +ENV GCLOUD_CLI_VERSION=${GCLOUD_CLI_VERSION} +RUN curl -LsSf --retry 8 --retry-all-errors --connect-timeout 120 https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-${GCLOUD_CLI_VERSION}-linux-$(ARCH_X64=x86_64 ARCH_ARM64=arm bash arch.sh).tar.gz | tar -xz -C /usr/local \ + && /usr/local/google-cloud-sdk/install.sh \ + --additional-components beta \ + --quiet \ + && ln -s /usr/local/google-cloud-sdk/bin/gcloud /usr/bin/gcloud \ + && ln -s /usr/local/google-cloud-sdk/bin/gsutil /usr/bin/gsutil \ + && gcloud version \ + && rm -rf /usr/local/google-cloud-sdk/.install ${HOME}/.config/gcloud \ + && find / -depth -type d -name __pycache__ -exec rm -rf {} \; 2> /dev/null + +# TODO: Install PowerShell here once it'll be distribued with both X64 and ARM64 targets (only X64 today, see: https://github.com/PowerShell/PowerShell/issues/25762) + +# Install YQ, then verify installation +ARG YQ_VERSION +ENV YQ_VERSION=${YQ_VERSION} +RUN curl -LsSf --retry 8 --retry-all-errors --connect-timeout 120 https://github.com/mikefarah/yq/releases/download/v${YQ_VERSION}/yq_linux_$(ARCH_X64=amd64 bash arch.sh) -o /usr/bin/yq \ + && chmod +x /usr/bin/yq \ + && yq --version + +# Install Tini, then verify installation +# TODO: Use binary from GitHub releases once ARM64 build will be available (see: https://github.com/krallin/tini/releases) +ARG TINI_VERSION +ENV TINI_VERSION=${TINI_VERSION} +RUN --mount=target=/var/cache/apk,type=cache,id=apk-${TARGETPLATFORM},sharing=locked \ + apk add --no-cache \ + tini~=${TINI_VERSION} \ + && tini --version +ENTRYPOINT ["/sbin/tini", "--"] + +# Install BuildKit, then verify installation +ARG BUILDKIT_VERSION +ENV BUILDKIT_VERSION=${BUILDKIT_VERSION} +RUN mkdir buildkit \ + && curl -LsSf --retry 8 --retry-all-errors --connect-timeout 120 https://github.com/moby/buildkit/releases/download/v${BUILDKIT_VERSION}/buildkit-v${BUILDKIT_VERSION}.linux-$(ARCH_X64=amd64 bash arch.sh).tar.gz | tar -xz -C buildkit \ + && mv buildkit/bin/* /usr/local/bin \ + && rm -rf buildkit \ + && buildctl --version \ + && buildkitd --version + +# Install RootlessKit, then verify installation +COPY --from=rootlesskit /usr/local/bin/rootless* /usr/bin/ +RUN rootlesskit --version \ + && rootlessctl --version + +# Install Azure Pipelines Agent sources, then verify installation +ARG AZP_AGENT_VERSION +ENV AZP_AGENT_VERSION=${AZP_AGENT_VERSION} +ENV AZP_HOME=${HOME}/azp-agent +# Disable agent auto-updates +# See: https://github.com/microsoft/azure-pipelines-agent/blob/b5ff4408239f3e938560f8b2e3848df76489a8d0/src/Agent.Listener/Agent.cs#L354C24-L354C24 +ENV agent.disableupdate="1" +RUN mkdir -p ${AZP_HOME} \ + && curl -LsSf --retry 8 --retry-all-errors --connect-timeout 120 https://download.agent.dev.azure.com/agent/${AZP_AGENT_VERSION}/vsts-agent-linux-musl-$(bash arch.sh)-${AZP_AGENT_VERSION}.tar.gz | tar -xz -C ${AZP_HOME} \ + && cd ${AZP_HOME} \ + && chmod +x run-docker.sh config.sh \ + && AGENT_ALLOW_RUNASROOT="1" bash run-docker.sh --version \ + && rm -rf _diag \ + # Allow local user to R/W to agent home + && chmod -R a+w . +ENV AZP_WORK=${HOME}/azp-work +ENV AZP_CUSTOM_CERT_PEM=${HOME}/azp-custom-certs + +# Cleanup helper script +RUN rm arch.sh + +# Reset Python cache flag +ENV PYTHONDONTWRITEBYTECODE= + +# Reset Python pip reliability configs +ENV PIP_DISABLE_PIP_VERSION_CHECK= +ENV PIP_QUIET= +ENV PIP_RETRIES= +ENV PIP_TIMEOUT= + +# Configure local user +RUN mkdir -p /run/user/0 ${HOME}/.local/tmp ${HOME}/.local/share/buildkit \ + && chown -R ${USER} /run/user/0 ${HOME} \ + && echo ${USER}:100000:65536 | tee /etc/subuid | tee /etc/subgid +USER 0:0 +ENV XDG_RUNTIME_DIR=/run/user/0 +ENV TMPDIR=${HOME}/.local/tmp +ENV BUILDKIT_HOST=unix:///run/user/0/buildkit/buildkitd.sock + +# Install Azure Pipelines Agent startup script +WORKDIR ${AZP_HOME} +COPY start.sh . +# Run as exec form, so that it can receive signals from Tini +CMD ["bash", "start.sh"] diff --git a/src/docker/Dockerfile-win-ltsc2022 b/src/docker/Dockerfile-win-ltsc2022 index 07a2499e..d3799217 100644 --- a/src/docker/Dockerfile-win-ltsc2022 +++ b/src/docker/Dockerfile-win-ltsc2022 @@ -1,7 +1,7 @@ # syntax=docker/dockerfile:1 # check=skip=UndefinedVar,WorkdirRelativePath -FROM mcr.microsoft.com/dotnet/sdk:8.0-windowsservercore-ltsc2022@sha256:a5daa91a8bbf6dbbdfde03490343c3234b356dcbb0740cd33fd1417b34670c38 +FROM mcr.microsoft.com/dotnet/sdk:9.0-windowsservercore-ltsc2022@sha256:39d675f110817d12b616fa1bef354661ce8c0819fc863103bcc63fb7555f2782 # Configure local user USER ContainerAdministrator diff --git a/src/docker/Dockerfile-win-ltsc2025 b/src/docker/Dockerfile-win-ltsc2025 index f60233a3..ff0370dc 100644 --- a/src/docker/Dockerfile-win-ltsc2025 +++ b/src/docker/Dockerfile-win-ltsc2025 @@ -1,7 +1,7 @@ # syntax=docker/dockerfile:1 # check=skip=UndefinedVar,WorkdirRelativePath -FROM mcr.microsoft.com/dotnet/sdk:8.0-windowsservercore-ltsc2025@sha256:652a620efd3bd34523396ee6517bd216f340019ced415871ed196bde7bbfdf0d +FROM mcr.microsoft.com/dotnet/sdk:9.0-windowsservercore-ltsc2025@sha256:e54b43c9e7a314d7b831a536160e9641829dc69f0f0c5e48ccf09ac544704eea # Configure local user USER ContainerAdministrator diff --git a/src/docker/start.sh b/src/docker/start.sh index 57620010..f540d263 100644 --- a/src/docker/start.sh +++ b/src/docker/start.sh @@ -111,43 +111,36 @@ unregister() { write_header "Adding custom SSL certificates" -if [ -d "$AZP_CUSTOM_CERT_PEM" ] && [ "$(ls -A $AZP_CUSTOM_CERT_PEM)" ]; then - echo "Searching for *.crt in $AZP_CUSTOM_CERT_PEM" - - # Debian-based systems - if [ -s /etc/debian_version ]; then - cert_path="/usr/local/share/ca-certificates" - mkdir -p $cert_path - - # Copy certificates to the certificate path - cp $AZP_CUSTOM_CERT_PEM/*.crt $cert_path +copy_and_show() { + local src_dir=$1 + local dest_dir=$2 + mkdir -p "$dest_dir" + cp "$src_dir"/*.crt "$dest_dir"/ + for cert_file in "$src_dir"/*.crt; do + echo "Adding certificate $(basename "$cert_file")" + openssl x509 -inform PEM -in "$cert_file" -noout -issuer -subject -dates + done +} - # Display certificates information - for cert_file in $AZP_CUSTOM_CERT_PEM/*.crt; do - echo "Certificate $(basename $cert_file)" - openssl x509 -inform PEM -in $cert_file -noout -issuer -subject -dates - done +if [ -d "$AZP_CUSTOM_CERT_PEM" ] && [ "$(ls -A "$AZP_CUSTOM_CERT_PEM")" ]; then + echo "Searching for *.crt in $AZP_CUSTOM_CERT_PEM" + # Debian-family or Alpine + if [ -f /etc/debian_version ] || [ -f /etc/alpine-release ]; then + copy_and_show "$AZP_CUSTOM_CERT_PEM" /usr/local/share/ca-certificates echo "Updating certificates keychain" update-ca-certificates - fi - - # RHEL-based systems - if [ -s /etc/redhat-release ]; then - cert_path="/etc/ca-certificates/trust-source/anchors" - mkdir -p $cert_path - - # Copy certificates to the certificate path - cp $AZP_CUSTOM_CERT_PEM/*.crt $cert_path - - # Display certificates information - for cert_file in $AZP_CUSTOM_CERT_PEM/*.crt; do - echo "Certificate $(basename $cert_file)" - openssl x509 -inform PEM -in $cert_file -noout -issuer -subject -dates - done + # RHEL-family + elif [ -f /etc/redhat-release ]; then + copy_and_show "$AZP_CUSTOM_CERT_PEM" /etc/ca-certificates/trust-source/anchors echo "Updating certificates keychain" update-ca-trust extract + + # Unknown distro + else + echo "Unrecognised distribution – manual certificate installation required" >&2 + exit 1 fi else echo "No custom SSL certificate provided" diff --git a/test/pipeline/java-install.yaml b/test/pipeline/java-install.yaml index e690224b..a99bb214 100644 --- a/test/pipeline/java-install.yaml +++ b/test/pipeline/java-install.yaml @@ -19,7 +19,17 @@ jobs: - version_${{ parameters.version }} steps: - bash: | - curl -LsSf https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.2+13/OpenJDK21U-jdk_x64_linux_hotspot_21.0.2_13.tar.gz -o ${{ variables.archive_path }} + # Detect distro + if ldd --version 2>&1 | grep -qi musl; then + suffix="alpine-linux" # musl = Alpine + else + suffix="linux" # glibc distros + fi + + # Build download URL + url="https://github.com/adoptium/temurin21-binaries/releases/download/21.0.2+13/OpenJDK21U-jdk_x64_${suffix}_hotspot_21.0.2_13.tar.gz" + echo "Fetching ${url}" + curl -LsSf "${url}" -o "${{ variables.archive_path }}" displayName: Download Eclipse Temurin - task: JavaToolInstaller@0 diff --git a/test/pipeline/root.yaml b/test/pipeline/root.yaml index d0260aa0..29a4f5eb 100644 --- a/test/pipeline/root.yaml +++ b/test/pipeline/root.yaml @@ -23,6 +23,10 @@ jobs: echo "Using apt-get" sudo apt-get update sudo apt-get install -y wget + elif command -v apk &> /dev/null; then + echo "Using apk" + sudo apk update + sudo apk add --no-cache wget elif command -v microdnf &> /dev/null; then echo "Using microdnf" sudo microdnf install -y wget @@ -31,7 +35,7 @@ jobs: sudo tdnf update -y sudo tdnf install -y wget else - echo "No suported package manager" + echo "No supported package manager" exit 1 fi displayName: Test package installation