diff --git a/.github/workflows/docker-images.yml b/.github/workflows/docker-images.yml index adbb0278f1..b428032144 100644 --- a/.github/workflows/docker-images.yml +++ b/.github/workflows/docker-images.yml @@ -7,6 +7,9 @@ on: push: branches: [main, release] +env: + DOCKER_BUILDKIT: 1 + jobs: superchain: name: jsii/superchain @@ -17,8 +20,8 @@ jobs: matrix: node: ['10', '14'] env: - # Node version whose images will be aliased to 'nightly' and 'latest' - DEFAULT_NODE_MAJOR_VERSION: 10 + # Node version whose images will be aliased without the -nodeXX segment + DEFAULT_NODE_MAJOR_VERSION: 12 steps: - name: Check out uses: actions/checkout@v2.3.4 @@ -58,48 +61,151 @@ jobs: # Ensure we run with bash, because that's the syntax we're using here... shell: bash + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + with: + platforms: arm64 + + - name: Set up docker buildx + id: buildx + if: steps.should-run.outputs.result == 'true' + uses: docker/setup-buildx-action@v1 + + # We only restore GH cache if we are not going to publish the result (i.e: PR validation) + - name: Set up layer cache + if: steps.should-run.outputs.result == 'true' && github.event_name != 'push' + uses: actions/cache@v2 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ hashFiles('superchain/*') }}-${{ github.sha }} + restore-keys: |- + ${{ runner.os }}-buildx-${{ hashFiles('superchain/*') }}- + ${{ runner.os }}-buildx- + + - name: Determine build time + id: build-time + if: steps.should-run.outputs.result == 'true' + run: |- + echo "::set-output name=value::$(date -u +'%Y-%m-%dT%H:%M:%SZ')" + - name: Build Image if: steps.should-run.outputs.result == 'true' run: |- - docker build \ - --pull \ - --build-arg BUILD_TIMESTAMP="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \ - --build-arg COMMIT_ID='${{ github.sha }}' \ - --build-arg NODE_MAJOR_VERSION=${{ matrix.node }} \ - --tag "jsii/superchain:node${{ matrix.node }}-nightly" \ - ./superchain - - name: Test Image + docker buildx build \ + --builder ${{ steps.buildx.outputs.name }} \ + --platform linux/amd64,linux/arm64 \ + --target superchain \ + --cache-from type=local,src=/tmp/.buildx-cache \ + --cache-to type=local,dest=/tmp/.buildx-cache-out \ + --pull \ + --build-arg BUILD_TIMESTAMP="${{ steps.build-time.outputs.value }}" \ + --build-arg COMMIT_ID='${{ github.sha }}' \ + --build-arg NODE_MAJOR_VERSION=${{ matrix.node }} \ + -f superchain/Dockerfile \ + . + + # Replace the cache so it does not grow forever + - name: Update layer cache + if: always() && steps.should-run.outputs.result == 'true' + run: |- + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-out /tmp/.buildx-cache + + # Testing sequentially, because in parallel it's too slow due to IO contention + - name: Test Image (AMD64) + if: steps.should-run.outputs.result == 'true' + run: |- + docker buildx build \ + --builder ${{ steps.buildx.outputs.name }} \ + --platform linux/amd64 \ + --target superchain \ + --cache-from type=local,src=/tmp/.buildx-cache \ + --cache-to type=local,dest=/tmp/.buildx-cache \ + --build-arg BUILD_TIMESTAMP="${{ steps.build-time.outputs.value }}" \ + --build-arg COMMIT_ID='${{ github.sha }}' \ + --build-arg NODE_MAJOR_VERSION=${{ matrix.node }} \ + -f superchain/Dockerfile \ + . + - name: Test Image (ARM64) if: steps.should-run.outputs.result == 'true' run: |- - docker run \ - --rm \ - --tty \ - --network=host \ - -v${{ github.workspace }}:${{ github.workspace }} \ - -w${{ github.workspace }} \ - "jsii/superchain:node${{ matrix.node }}-nightly" \ - bash -c "yarn install --frozen-lockfile && yarn build && yarn test" + docker buildx build \ + --builder ${{ steps.buildx.outputs.name }} \ + --platform linux/arm64 \ + --target superchain \ + --cache-from type=local,src=/tmp/.buildx-cache \ + --cache-to type=local,dest=/tmp/.buildx-cache \ + --build-arg BUILD_TIMESTAMP="${{ steps.build-time.outputs.value }}" \ + --build-arg COMMIT_ID='${{ github.sha }}' \ + --build-arg NODE_MAJOR_VERSION=${{ matrix.node }} \ + -f superchain/Dockerfile \ + . # Only when puhsing to main/release from now on - name: Publish (nightly) if: steps.should-run.outputs.result == 'true' && github.event_name == 'push' && github.ref != 'refs/heads/release' run: |- - docker push jsii/superchain:node${{ matrix.node }}-nightly + docker buildx build \ + --builder ${{ steps.buildx.outputs.name }} \ + --platform linux/amd64,linux/arm64 \ + --target superchain \ + --cache-from type=local,src=/tmp/.buildx-cache \ + --cache-to type=local,dest=/tmp/.buildx-cache \ + --push \ + --build-arg BUILD_TIMESTAMP="${{ steps.build-time.outputs.value }}" \ + --build-arg COMMIT_ID='${{ github.sha }}' \ + --build-arg NODE_MAJOR_VERSION=${{ matrix.node }} \ + --tag "jsii/superchain:1-buster-slim-node${{ matrix.node }}-nightly"\ + -f superchain/Dockerfile \ + . # If the current version is the default version, also tag this with the unqualified ':nightly' label if [[ "${{ matrix.node }}" == "$DEFAULT_NODE_MAJOR_VERSION" ]]; then - docker tag jsii/superchain:node${{ matrix.node }}-nightly jsii/superchain:nightly - docker push jsii/superchain:nightly + docker buildx build \ + --builder ${{ steps.buildx.outputs.name }} \ + --platform linux/amd64,linux/arm64 \ + --target superchain \ + --cache-from type=local,src=/tmp/.buildx-cache \ + --cache-to type=local,dest=/tmp/.buildx-cache \ + --push \ + --build-arg BUILD_TIMESTAMP="${{ steps.build-time.outputs.value }}" \ + --build-arg COMMIT_ID='${{ github.sha }}' \ + --build-arg NODE_MAJOR_VERSION=${{ matrix.node }} \ + --tag "jsii/superchain:1-buster-slim-nightly" \ + -f superchain/Dockerfile \ + . fi - name: Publish (latest) if: steps.should-run.outputs.result == 'true' && github.event_name == 'push' && github.ref == 'refs/heads/release' run: |- # Alias 'nodeX-nightly's to 'nodeX', then push - docker tag jsii/superchain:node${{ matrix.node }}-nightly jsii/superchain:node${{ matrix.node }} - docker push jsii/superchain:node${{ matrix.node }} + docker buildx build \ + --builder ${{ steps.buildx.outputs.name }} \ + --platform linux/amd64,linux/arm64 \ + --target superchain \ + --cache-from type=local,src=/tmp/.buildx-cache \ + --cache-to type=local,dest=/tmp/.buildx-cache \ + --push \ + --build-arg BUILD_TIMESTAMP="${{ steps.build-time.outputs.value }}" \ + --build-arg COMMIT_ID='${{ github.sha }}' \ + --build-arg NODE_MAJOR_VERSION=${{ matrix.node }} \ + --tag "jsii/superchain:1-buster-slim-node${{ matrix.node }}" \ + -f superchain/Dockerfile \ + . - # If the current version is the default version, also tag this with the unqualified ':latest' label + # If the current version is the default version, also tag this with the unqualified ':1-*' label if [[ "${{ matrix.node }}" == "$DEFAULT_NODE_MAJOR_VERSION" ]]; then - docker tag jsii/superchain:node${{ matrix.node }} jsii/superchain:latest - docker push jsii/superchain:latest + docker buildx build \ + --builder ${{ steps.buildx.outputs.name }} \ + --platform linux/amd64,linux/arm64 \ + --target superchain \ + --cache-from type=local,src=/tmp/.buildx-cache \ + --cache-to type=local,dest=/tmp/.buildx-cache \ + --push \ + --build-arg BUILD_TIMESTAMP="${{ steps.build-time.outputs.value }}" \ + --build-arg COMMIT_ID='${{ github.sha }}' \ + --build-arg NODE_MAJOR_VERSION=${{ matrix.node }} \ + --tag "jsii/superchain:1-buster-slim" \ + -f superchain/Dockerfile \ + . fi diff --git a/superchain/.dockerignore b/superchain/.dockerignore new file mode 100644 index 0000000000..5a72d66cb1 --- /dev/null +++ b/superchain/.dockerignore @@ -0,0 +1,2 @@ +/.dockerignore +/build-local.sh diff --git a/superchain/Dockerfile b/superchain/Dockerfile index b630412ee5..4555403533 100644 --- a/superchain/Dockerfile +++ b/superchain/Dockerfile @@ -1,116 +1,249 @@ -FROM public.ecr.aws/amazonlinux/amazonlinux:2 +######################################################################################################################## +# Introduction +######################################################################################################################## +# This is a multi-stage build, which eventually results in a squashed image. +# The image intended for release/use is the one obtained using `docker build --target=superchain ...`. +# +# Stages are as follows +# 1. [bindist] Prepare a bunch of binary distributions +# 2. [staging] Prepare the superchain staging image +# 3. [superchain] Squash into a single layer +# 4. [test] Run tests on the superchain stage +# +# Multi-stage build allows several of these steps to run in parallel up to some point. It makes the build cache usage +# more efficient, and allows us to run cross-architecture builds in the most efficient possible manner, by running the +# "platform-independent" elements within the build platform, which does not require any kind of emulation. + + +######################################################################################################################## +# Prepare install images of "manual" binary distributions (runs on BUILD platform for speed) +######################################################################################################################## +FROM --platform=${BUILDPLATFORM} public.ecr.aws/debian/debian:10 as bindist + +# Build & target platforms, they are provided by buildx and will look like "linux/amd64" or "linux/arm64" +ARG BUILDPLATFORM +ARG TARGETPLATFORM + +# We require a couple of tools to be available in order to work here... +RUN apt-get update && apt-get install -y curl gpg tar zsh + +# We'll be using zsh substitutions, so ensuring this is the shell we use +SHELL ["/bin/zsh", "-c"] + +# Prepare maven binary distribution +ARG M2_VERSION="3.8.2" +ENV M2_DISTRO="https://www.apache.org/dist/maven/maven-3" +RUN set -eo pipefail \ + && curl -sL "${M2_DISTRO}/${M2_VERSION}/binaries/apache-maven-${M2_VERSION}-bin.tar.gz" \ + -o /tmp/apache-maven.tar.gz \ + && curl -sL "${M2_DISTRO}/${M2_VERSION}/binaries/apache-maven-${M2_VERSION}-bin.tar.gz.asc" \ + -o /tmp/apache-maven.tar.gz.asc \ + && mkdir -p /tmp/gpg-maven && chmod go-rwx /tmp/gpg-maven \ + && curl -sL "https://www.apache.org/dist/maven/KEYS" | gpg --homedir /tmp/gpg-maven --import \ + && gpg --homedir /tmp/gpg-maven --verify /tmp/apache-maven.tar.gz.asc /tmp/apache-maven.tar.gz \ + && mkdir -p /opt/apache/maven \ + && tar xzf /tmp/apache-maven.tar.gz -C /opt/apache/maven --strip-components=1 + +# Prepare .NET Core distribution +ARG DOTNET_CHANNEL="3.1" +ENV DOTNET_FEED="https://dotnetcli.azureedge.net/dotnet" +RUN DOTNET_VERSION=$(curl -fSsL "${DOTNET_FEED}/Sdk/${DOTNET_CHANNEL}/latest.version") \ + && DOTNET_ASSET="dotnet-sdk-${DOTNET_VERSION}-linux-${${TARGETPLATFORM#linux/}/amd64/x64}.tar.gz" \ + && curl -fSsL "${DOTNET_FEED}/Sdk/${DOTNET_VERSION}/${DOTNET_ASSET}" \ + -o /tmp/dotnet.tar.gz \ + && mkdir -p /opt/microsoft/dotnet \ + && tar zxf /tmp/dotnet.tar.gz -C /opt/microsoft/dotnet + +# Prepare PowerShell LTS distribution +ENV POWERSHELL_RELEASES="https://github.com/PowerShell/PowerShell/releases" +RUN POWERSHELL_RELEASE=$(curl -fSsL "https://aka.ms/powershell-release?tag=lts" -o /dev/null -w %{url_effective}) \ + && POWERSHELL_VERSION=${POWERSHELL_RELEASE#${POWERSHELL_RELEASES}/tag/v} \ + && ASSET="powershell-${POWERSHELL_VERSION}-linux-${${TARGETPLATFORM#linux/}/amd64/x64}.tar.gz" \ + && curl -fSsL "${POWERSHELL_RELEASES}/download/v${POWERSHELL_VERSION}/${ASSET}" \ + -o /tmp/powershell.tar.gz \ + && mkdir -p /opt/microsoft/powershell \ + && tar zxf /tmp/powershell.tar.gz -C /opt/microsoft/powershell \ + && chmod +x /opt/microsoft/powershell/pwsh + +# Prepare Go distribution +ARG GO_VERSION="1.16.7" +RUN curl -fSsL "https://golang.org/dl/go${GO_VERSION}.linux-${TARGETPLATFORM#linux/}.tar.gz" -o /tmp/go.tar.gz \ + && mkdir -p /opt/golang/go \ + && tar -xzf /tmp/go.tar.gz -C /opt/golang/go --strip-components=1 + +######################################################################################################################## +# Set up the image +######################################################################################################################## +FROM public.ecr.aws/debian/debian:10-slim as staging + +# Build & target platforms, they are provided by buildx and will look like "linux/amd64" or "linux/arm64" +ARG BUILDPLATFORM +ARG TARGETPLATFORM + +SHELL ["/bin/bash", "-c"] # Set locale and some other interesting environment variables ENV LANG="C.UTF-8" \ LC_ALL="C.UTF-8" \ CHARSET="UTF-8" \ \ - DOTNET_CLI_TELEMETRY_OPTOUT="true" \ DOTNET_RUNNING_IN_CONTAINER="true" \ - DOTNET_NOLOGO="true" \ DOTNET_USE_POLLING_FILE_WATCHER="true" \ NUGET_XMLDOC_MODE="skip" \ \ - GEM_HOME="/usr/local/bundle" \ - BUNDLE_SILENCE_ROOT_WARNING="1" \ - \ - M2_VERSION="3.6.3" \ - M2_HOME="/usr/local/apache-maven" \ - M2="/usr/local/apache-maven/bin" \ - MAVEN_OPTS="-Xms256m -Xmx512m" \ + M2_HOME="/opt/apache/maven" \ + M2="/opt/apache/maven/bin" \ \ - GOROOT="/usr/local/go" \ - GITHUB_CLI_VERSION="1.9.2" - -# Install deltarpm as it can speed up the upgrade processes, and tar as it's needed for installing Maven -# Also upgrading anything already installed, and adding some common dependencies for included tools -RUN yum -y upgrade \ - && yum -y install deltarpm tar \ - make system-rpm-config yum-utils \ - git gzip openssl rsync unzip which zip \ - && yum clean all && rm -rf /var/cache/yum - -# Install .NET Core, mono & PowerShell -COPY gpg/mono.asc /tmp/mono.asc -RUN rpm --import "https://packages.microsoft.com/keys/microsoft.asc" \ - && rpm -Uvh "https://packages.microsoft.com/config/centos/7/packages-microsoft-prod.rpm" \ - && rpm --import /tmp/mono.asc && rm -f /tmp/mono.asc \ - && curl -sSL "https://download.mono-project.com/repo/centos7-stable.repo" \ - | tee /etc/yum.repos.d/mono-centos7-stable.repo \ - && yum -y install dotnet-sdk-3.1 mono-devel powershell \ - && yum-config-manager --disable packages-microsoft-com-prod \ - && yum-config-manager --disable mono-centos7-stable \ - && yum clean all && rm -rf /var/cache/yum + GOROOT="/opt/golang/go" + +# Installing the system dependencies we need... +RUN apt-get update \ + && apt-get -y install \ + apt-transport-https \ + build-essential \ + ca-certificates \ + curl \ + dirmngr \ + git \ + gnupg \ + gzip \ + libicu63 \ + libssl-dev \ + openssl \ + rsync \ + sudo \ + unzip \ + zip \ + && rm -rf /var/lib/apt/lists/* + +# Install mono +COPY superchain/gpg/mono.asc /tmp/mono.asc +RUN apt-key add /tmp/mono.asc && rm /tmp/mono.asc \ + && echo "deb https://download.mono-project.com/repo/debian stable-buster main" \ + > /etc/apt/sources.list.d/mono-official-stable.list \ + && apt-get update \ + && apt-get -y install mono-devel \ + && rm -rf /var/lib/apt/lists/* # Install Python 3 -RUN yum -y install python3 python3-pip \ +RUN apt-get update \ + && apt-get -y install python3 python3-pip python3-venv \ && python3 -m pip install --no-input --upgrade pip \ && python3 -m pip install --no-input --upgrade awscli black setuptools twine wheel \ && rm -rf $(pip cache dir) \ - && yum clean all && rm -rf /var/cache/yum - -# Install JDK8 (Corretto) -RUN amazon-linux-extras enable corretto8 \ - && yum -y install java-1.8.0-amazon-corretto-devel \ - && yum clean all && rm -rf /var/cache/yum + && rm -rf /var/lib/apt/lists/* -# Install Maven -RUN curl -sL https://www.apache.org/dist/maven/maven-3/${M2_VERSION}/binaries/apache-maven-${M2_VERSION}-bin.tar.gz \ - -o /tmp/apache-maven.tar.gz \ - && curl -sL https://www.apache.org/dist/maven/maven-3/${M2_VERSION}/binaries/apache-maven-${M2_VERSION}-bin.tar.gz.asc\ - -o /tmp/apache-maven.tar.gz.asc \ - && mkdir -p /tmp/gpg-maven && chmod go-rwx /tmp/gpg-maven \ - && curl -sL https://www.apache.org/dist/maven/KEYS | gpg --homedir /tmp/gpg-maven --import \ - && gpg --homedir /tmp/gpg-maven --verify /tmp/apache-maven.tar.gz.asc /tmp/apache-maven.tar.gz \ - && mkdir -p /usr/local && (cd /usr/local && tar xzf /tmp/apache-maven.tar.gz) \ - && mv /usr/local/apache-maven-${M2_VERSION} /usr/local/apache-maven \ - && for BIN in $(find /usr/local/apache-maven/bin -type f -executable); \ - do \ - ln -s $BIN /usr/local/bin/$(basename $BIN); \ - done \ - && rm -rf /tmp/apache-maven.tar.gz /tmp/apache-maven.tar.gz.asc /tmp/gpg-maven -COPY m2-settings.xml /root/.m2/settings.xml - -# Install Go -RUN curl -sL https://golang.org/dl/go1.16.linux-amd64.tar.gz -o /tmp/go.tar.gz \ - && mkdir -p /usr/local && (cd /usr/local && tar -xzf /tmp/go.tar.gz) -ENV PATH="$GOROOT/bin:$PATH" +# Install Rust (required for https://pypi.org/project/cryptography/ in certain circumstances... like ARM64 arch) +ENV RUSTUP_HOME=/usr/local/rustup \ + CARGO_HOME=/usr/local/cargo +RUN set -eo pipefail \ + && curl -fSsL "https://sh.rustup.rs" | sh -s -- -y --no-modify-path --profile=minimal \ + && echo "source ${CARGO_HOME}/env" >> /etc/profile.d/cargo.sh \ + && chmod -R a+rw ${CARGO_HOME} +ENV PATH=$PATH:${CARGO_HOME}/bin -# Install GCC -RUN yum -y install gcc +# Install JDK8 (Amazon Corretto 8) +COPY superchain/gpg/corretto.asc /tmp/corretto.asc +RUN apt-key add /tmp/corretto.asc && rm /tmp/corretto.asc \ + && echo "deb https://apt.corretto.aws stable main" > /etc/apt/sources.list.d/amazon-corretto.list \ + && apt-get update \ + && mkdir -p /usr/share/man/man1 \ + && apt-get -y install java-1.8.0-amazon-corretto-jdk \ + && rm -rf /usr/share/man/man1 \ + && rm -rf /var/lib/apt/lists/* # Install Docker -RUN amazon-linux-extras install docker \ - && yum clean all && rm -rf /var/cache/yum +COPY superchain/gpg/docker.asc /tmp/docker.asc +RUN apt-key add /tmp/docker.asc && rm /tmp/docker.asc \ + && echo "deb https://download.docker.com/linux/debian buster stable" > /etc/apt/sources.list.d/docker.list \ + && apt-get update \ + && apt-get -y install docker-ce docker-ce-cli containerd.io \ + && rm -rf /var/lib/apt/lists/* VOLUME /var/lib/docker -# Install Node 10+ (configurable with '--build-arg NODE_MAJOR_VERSION=xxx') -# (Put this as late as possible in the Dockerfile so we get to reuse the layer cache -# for most of the multiple builds). -ARG NODE_MAJOR_VERSION=10 +# Install GitHub CLI +ARG GITHUB_CLI_VERSION="1.13.1" +RUN BASE="https://github.com/cli/cli/releases/download" \ + && echo "${BASE}/v${GITHUB_CLI_VERSION}/gh_${GITHUB_CLI_VERSION}_linux_${TARGETPLATFORM#linux/}.deb" \ + && curl -fSsL "${BASE}/v${GITHUB_CLI_VERSION}/gh_${GITHUB_CLI_VERSION}_linux_${TARGETPLATFORM#linux/}.deb" \ + -o /tmp/gh.deb \ + && apt-get update \ + && apt-get -y install /tmp/gh.deb \ + && rm /tmp/gh.deb \ + && rm -rf /var/lib/apt/lists/* -RUN curl -sL https://rpm.nodesource.com/setup_${NODE_MAJOR_VERSION}.x | bash - \ - && yum -y install nodejs \ - && yum clean all && rm -rf /var/cache/yum \ - && npm set unsafe-perm true +# Install .NET Core and PowerShell +COPY --from=bindist /opt/microsoft/dotnet /opt/microsoft/dotnet +RUN ln -s /opt/microsoft/dotnet/dotnet /usr/bin/dotnet +COPY --from=bindist /opt/microsoft/powershell /opt/microsoft/powershell +RUN ln -s /opt/microsoft/powershell/pwsh /usr/bin/pwsh -# Install Yarn -RUN curl -sSL https://dl.yarnpkg.com/rpm/yarn.repo | tee /etc/yum.repos.d/yarn.repo \ - && yum -y install yarn \ - && yum clean all && rm -rf /var/cache/yum +# Install Maven +COPY --from=bindist /opt/apache/maven ${M2_HOME} +COPY superchain/m2-settings.xml /root/.m2/settings.xml -# Install GitHub CLI -RUN curl -sL https://github.com/cli/cli/releases/download/v${GITHUB_CLI_VERSION}/gh_${GITHUB_CLI_VERSION}_linux_amd64.tar.gz | \ - tar -xzv --strip-components=2 gh_${GITHUB_CLI_VERSION}_linux_amd64/bin/gh \ - && mv gh /usr/bin/ +# Install Go +COPY --from=bindist /opt/golang/go ${GOROOT} + +# Install Node 10+ (configurable with '--build-arg NODE_MAJOR_VERSION=xxx') and yarn +# (Put this as late as possible in the Dockerfile so we get to reuse the layer cache +# for most of the multiple builds). +ARG NODE_MAJOR_VERSION="12" +COPY superchain/gpg/nodesource.asc /tmp/nodesource.asc +COPY superchain/gpg/yarn.asc /tmp/yarn.asc +RUN apt-key add /tmp/nodesource.asc && rm /tmp/nodesource.asc \ + && echo "deb https://deb.nodesource.com/node_${NODE_MAJOR_VERSION}.x buster main" \ + > /etc/apt/sources.list.d/nodesource.list \ + && apt-key add /tmp/yarn.asc && rm /tmp/yarn.asc \ + && echo "deb https://dl.yarnpkg.com/debian stable main" > /etc/apt/sources.list.d/yarnpkg.list \ + && apt-get update \ + && apt-get -y install nodejs yarn \ + && rm -rf /var/lib/apt/lists/* # Install some configuration -COPY ssh_config /root/.ssh/config +COPY superchain/ssh_config /root/.ssh/config RUN chmod 600 /root/.ssh/config -COPY dockerd-entrypoint.sh /usr/local/bin/ +COPY superchain/dockerd-entrypoint.sh /usr/local/bin/ + +# Create the image's non-root user, and enable no-password sudo +RUN adduser --shell /bin/bash --gecos "Docker User" --disabled-password superchain \ + && adduser superchain sudo \ + && echo "%sudo ALL = (ALL) NOPASSWD: ALL" >> /etc/sudoers.d/nopasswd \ + && chmod 0440 /etc/sudoers.d/nopasswd +COPY --chown=superchain:superchain superchain/m2-settings.xml /home/superchain/.m2/settings.xml +COPY --chown=superchain:superchain superchain/ssh_config /home/superchain/.ssh/config +RUN chmod 600 /home/superchain/.ssh/config # Add the source used to build this Docker image (to facilitate re-builds, forensics) -COPY . /docker-source +COPY superchain /docker-source + +CMD ["/bin/bash"] + +######################################################################################################################## +# Creating squashed image +######################################################################################################################## +FROM scratch as superchain +# Set locale and some other interesting environment variables +ENV LANG="C.UTF-8" \ + LC_ALL="C.UTF-8" \ + CHARSET="UTF-8" \ + \ + DOTNET_CLI_TELEMETRY_OPTOUT="true" \ + DOTNET_RUNNING_IN_CONTAINER="true" \ + DOTNET_NOLOGO="true" \ + DOTNET_USE_POLLING_FILE_WATCHER="true" \ + NUGET_XMLDOC_MODE="skip" \ + \ + M2_HOME="/opt/apache/maven" \ + M2="/opt/apache/maven/bin" \ + MAVEN_OPTS="-Xms256m -Xmx512m" \ + \ + GOROOT="/opt/golang/go" \ + RUSTUP_HOME="/usr/local/rustup" \ + CARGO_HOME="/usr/local/cargo" +ENV PATH="${PATH}:${CARGO_HOME}/bin:${GOROOT}/bin:${M2}" + +COPY --from=staging / / ## Image Metadata ARG BUILD_TIMESTAMP @@ -118,9 +251,27 @@ ARG COMMIT_ID LABEL org.opencontainers.image.created=${BUILD_TIMESTAMP} \ org.opencontainers.image.title="jsii/superchain" \ org.opencontainers.image.description="An image to build cross-language artifacts with AWS jsii" \ - org.opencontainers.image.url="https://github.com/aws/jsii/tree/main/superchain" \ + org.opencontainers.image.url="https://github.com/aws/jsii/tree/main/superchain" \ org.opencontainers.image.source="https://github.com/aws/jsii.git" \ org.opencontainers.image.revision=$COMMIT_ID \ org.opencontainers.image.authors="Amazon Web Services (https://aws.amazon.com)" +USER superchain:superchain + CMD ["/bin/bash"] + +######################################################################################################################## +# Running tests +######################################################################################################################## +FROM superchain as test +ENV CI=true +COPY --chown=superchain:superchain . /tmp/source +WORKDIR /tmp/source +# Make sure we start fresh (symlinks from outside the build may cause issues, e.g: python venvs) +RUN git clean -fqdx +# Install all dependencies again +RUN yarn install --frozen-lockfile +# Build the code +RUN yarn build +# Test the code +RUN yarn test diff --git a/superchain/README.md b/superchain/README.md index ea6acd4b99..e155ff7eda 100644 --- a/superchain/README.md +++ b/superchain/README.md @@ -1,9 +1,9 @@ # Superchain -An [`amazonlinux:2`][al2]-based Docker image bundling all the SDKs and tools +A [`debian:10-slim`][debian]-based Docker image bundling all the SDKs and tools required in order to package [jsii] projects in all supported languages. -[al2]: https://hub.docker.com/_/amazonlinux +[debian]: https://hub.docker.com/_/debian [jsii]: https://github.com/aws/jsii ## Included Language SDKs @@ -14,21 +14,50 @@ SDK | Version `.NET SDK` | `>= 3.1.101` `mono` | `>= 6.8.0.105` `Javascript` | `node >= 10.19.0` OR `node >= 14.16.0` with `npm >= 6.14.11` (see [NodeJS and NPM](#nodejs-and-npm)) -`PowerShell` | `pwsh >= 6.2.3` -`Python 3` | `python3 >= 3.7.4` with `pip3 >= 20.0.2` +`PowerShell` | `pwsh >= 7.1.3` +`Python 3` | `python3 >= 3.7.3` with `pip3 >= 20.0.2` `Go` | `go >= 1.16` +## Image tags + +Maintained image tags are named using the following pattern: + +``` +jsii/superchain:-(-node)(-nightly) +``` + +- `` is the major line of the jsii toolchain + - The only supported value is `1` +- `` is the base image tag (e.g: `buster-slim`) + - The only supported value is `buster-slim` +- `` is the major version of node contained in the image + - `10` corresponds to node 10.x + - `12` corresponds to node 12.x, this is the default + - `14` corresponds to node 14.x + - `10` corresponds to node 12.x +- `-nightly` images are released from the `HEAD` of the [`aws/jsii`][jsii] + repository and should typically not be used for production workloads + +The previous image tags are no longer updated and should no longer be used: + +- `:latest` (users should migrate to `:1-buster-slim`) +- `:nightly` (users should migrate to `:1-buster-slim-nightly`) +- `:node10` (users should migrate to `:1-buster-slim-node10`) +- `:node10-nightly` (users should migrate to `:1-buster-slim-node10-nightly`) +- `:node14` (users shoudl migrate to `:1-buster-slim-node14`) +- `:node14-nightly` (users shoudl migrate to `:1-buster-slim-node14-nightly`) + ## NodeJS and NPM We build multiple versions of this image, for different versions of Node. They are available as: -* `jsii/superchain:node10[-nightly]` -* `jsii/superchain:node14[-nightly]` +* `jsii/superchain:node10(-buster-slim|-nightly)` +* `jsii/superchain:node14(-buster-slim|-nightly)` The following labels are also available, and are aliases for the Node 10 images: * `jsii/superchain:nightly` -* `jsii/superchain:latest` +* `jsii/superchain:latest-buster-slim` If you are building this image from source, you can control the Node version with the `NODE_MAJOR_VERSION` build argument: @@ -55,22 +84,10 @@ Tool / Utility | Version ## License -Amazon Linux is available under the [GNU General Public License, version -2.0][gpl2.0]. Individual software packages are available under their own -licenses; `run rpm -qi [package name]` or check -`/usr/share/doc/[package name]-*` and `/usr/share/licenses/[package name]-*` for -details. - -As with all Docker images, these likely also contain other software which may be -under other licenses (such as Bash, etc from the base distribution, along with +As with all Docker images, these also contain software which may be distributed +under various licenses (such as Bash, etc from the base distribution, along with any direct or indirect dependencies of the primary software being contained). -Some additional license information which was able to be auto-detected might be -found in [the repo-info repository's `amazonlinux/` directory][repo-info-al2]. - As for any pre-built image usage, it is the image user's responsibility to ensure that any use of this image complies with any relevant licenses for all software contained within. - -[gpl2.0]: https://github.com/aws/amazon-linux-docker-images/blob/master/LICENSE -[repo-info-al2]: https://github.com/docker-library/repo-info/tree/master/repos/amazonlinux diff --git a/superchain/build-local.sh b/superchain/build-local.sh index c050121d4f..ae12f7bff8 100755 --- a/superchain/build-local.sh +++ b/superchain/build-local.sh @@ -21,9 +21,12 @@ fi # Now on to building the image docker build \ - --pull \ + --target superchain \ + --build-arg BUILDPLATFORM=linux/amd64 \ + --build-arg TARGETPLATFORM=linux/amd64 \ --build-arg BUILD_TIMESTAMP=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \ + --build-arg REGISTRY="docker.io/library" \ --build-arg COMMIT_ID=${COMMIT_ID} \ - --build-arg NODE_MAJOR_VERSION=10 \ -t "jsii/superchain:local" \ - . + -f ${PWD}/Dockerfile \ + .. diff --git a/superchain/gpg/corretto.asc b/superchain/gpg/corretto.asc new file mode 100644 index 0000000000..b0198ed751 --- /dev/null +++ b/superchain/gpg/corretto.asc @@ -0,0 +1,30 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2.0.22 (GNU/Linux) + +mQINBF3pShkBEADJzglehQDFlc1+9VFubVPzpq8ZYtzmJkNjf09scOUzaKZOm3Ar +mPh9Rufk4mB7t1LP4JeHAKAS17ggCHGVxRGXAAQ9Laf8ibX4SiFO3Ehyyl3smuFf +ZhexBnvc7vRc4EUlKqarCQRUlaraDOrmq7WbhXdvCgc4u2uBLwUjAd3PHQUByAZw +lsEQzpQnehNomjrE0pO6ms9AhmpbXlf/yr14EXvlo4lTd8QUdvS+AOCYfrHb9WGO +IEsyyDuzuf2grV/QFpoi0VBhTCyiNYXla2AfCreMGlOCYsjw1nU93OyAqF3SaTOC +o52yrzcb2NpbBDwRXOHNwe1md+DbRwEfkaWr5I91FqRpgEeawqyxY1miJRHduhsz +WTgTMBF/EQfmTspD2YBX/BjNJTrdDXYvACX8slVV/vBnpi+dEpVEK3hh21ij991S +lv8YoFnoC7XP44C7WNpVQpGW9ZWpnjLCvm3DMKW0r3Vfb3XDYhnHI1Q14Pxn0cwf +x1L2RA4doyWd1TRZBFBe2f0vSkZT0YFaibKaKi6AkDIMU/+u+/e3wWbYXqzsSITj +ffMkpMMNSwxbm8JqnsudjuzdEsYAiBUcFMwWysQDcyu63un2OmLKLfKxy19vCpS1 +8mkNy95JuO4jZtu+IiinvSSjlbJmslu3uK3/cTRsWaB7BRtHewE7SugMOwARAQAB +tEhBbWF6b24gU2VydmljZXMgTExDIChBbWF6b24gQ29ycmV0dG8gcmVsZWFzZSkg +PGNvcnJldHRvLXRlYW1AYW1hem9uLmNvbT6JAjEEEwECABsFAl3pShkCGy8FCQlm +AYAFFQgKCQsCHgECF4AACgkQoSJUKrBPJOOJDg/6AqmntaxDWX6qfR++0qwtD9Lp +vgONFvA+9AYQeGt7OX79O/SSPy97Kvn6DYRBdelShTAH60DbXCUs42sIRFqRjmHY +HfIgOkUJjWoJz9oQnY+mzAKbOohCrR+YIvyCegFb0dboDaqSQ4w68+d1is7L84pz +ZB2j0nrQDbFihPmR+epfHkLUGGywuZHCdEFfD8nXMOJeVbgSzf7Vhl8ZrydIkZTI +7aASG5MkDO/GuVpEGQYAnH9h/jzJlfUKndswC6UFcM5Ol07pDPdHVBAi9q1SyxDe +uSS1NgDW7OW7zgpB+4/PrZKKiEP/fBAWa9nFSLwTaMdsoaAuQAmmgbqYfy3XXKK7 +IBaKSnJpQDvNb0vmXJEY3qX2Bfh0p1KCeaQhYwIJi8rPQWC24fiLY9bdCIlkbbPQ +CSNOEq9nUWRg9KbUGmd/PWSkT6Jheyq3BZBF1YPYEt8o/l437HHd08lREqH0sana +Hb72GZTi2RUrNBBp5C1e8MqllXE6RKmri2m0TSBHR5C4ZLII9duyA839dYIA4KGU +nmetZckuRuwHFmd3/YWtMEfn47UedzhVT16z3OvBipHU1BKzLGcvUFXrUKvpJQlh +dNPUQh+wb91EzItjkJ96m+N+81iQdN3yd8cE38NTA8b+Qc7tmTYxwNZxcv16FxLA +y2VhKc09A8RwSI69vDs= +=ZNRH +-----END PGP PUBLIC KEY BLOCK----- diff --git a/superchain/gpg/docker.asc b/superchain/gpg/docker.asc new file mode 100644 index 0000000000..ee7872e5d0 --- /dev/null +++ b/superchain/gpg/docker.asc @@ -0,0 +1,62 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +YT90qFF93M3v01BbxP+EIY2/9tiIPbrd +=0YYh +-----END PGP PUBLIC KEY BLOCK----- diff --git a/superchain/gpg/nodesource.asc b/superchain/gpg/nodesource.asc new file mode 100644 index 0000000000..1dc1d1016b --- /dev/null +++ b/superchain/gpg/nodesource.asc @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 +Comment: GPGTools - https://gpgtools.org + +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 +=CLGF +-----END PGP PUBLIC KEY BLOCK----- diff --git a/superchain/gpg/yarn.asc b/superchain/gpg/yarn.asc new file mode 100644 index 0000000000..e8d9cabb89 --- /dev/null +++ b/superchain/gpg/yarn.asc @@ -0,0 +1,243 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +=IgpF +-----END PGP PUBLIC KEY BLOCK-----