From dbad10f0048b0f8cae3957e6c44b60c8717ca080 Mon Sep 17 00:00:00 2001 From: Ximon Eighteen <3304436+ximon18@users.noreply.github.com> Date: Mon, 29 Aug 2022 09:36:43 +0200 Subject: [PATCH] Cross project pkg workflow consistency (#894) In no particular order: * Generalize references to Krill where they are not Krill specific. * Make argument order consistent with Routinator. * Various comment tidying and harmless changes for consistency with (e.g. argument order) the Routinator pkg workflow. * Trigger the pkg workflow for all v* tags as this is simpler than matching specific version patterns and is consistent with the Routinator pkg workflow. * Don't use ubuntu-latest as we unexpected changes may be introduced when latest moves up to the next Ubuntu release. * Use the same latest DEB/RPM tool versions and features as the Routinator pkg workflow. * Parameterize the Docker repo to push to. Don't assume it matches the GH repo name. * Docker repo name must be lowercase. * Ensure executables copied into the Docker image have the executable permission. * Let the compiler choose the right target in the Dockerfile. * Work around GitHub misapplication of secret protection to the dockerbasetag workflow job output. * Upgrade to actions/cache@3 --- .github/workflows/pkg.yml | 240 ++++++++++++++++++-------------------- Dockerfile | 64 +++++----- README.md | 1 - 3 files changed, 149 insertions(+), 156 deletions(-) diff --git a/.github/workflows/pkg.yml b/.github/workflows/pkg.yml index feb49afa..eb6b55da 100644 --- a/.github/workflows/pkg.yml +++ b/.github/workflows/pkg.yml @@ -1,8 +1,8 @@ -# GitHub Actions workflow for building and testing Krill O/S packages. +# GitHub Actions workflow for building and testing our O/S packages. # # Workflow speed: # =============== -# This workflow uses GitHub Actions caching to avoid rebuilding Rust cargo-deb, cargo generate-rpm and Krill compiled +# This workflow uses GitHub Actions caching to avoid rebuilding Rust cargo-deb, cargo generate-rpm and our compiled # dependencies on every run. At the time of writing the GH cache contents expire after a week if not used so the next # build may be much slower as it will have to re-download/build/install lots of Rust crates. # @@ -40,7 +40,7 @@ # Docker packaging: # ================= # Docker packaging was originally done using Docker Hub but long delays and repeated spurious failures caused us to -# migrate Docker packaging to GitHub Actions which is now part of this workflow. +# migrate Docker packaging to GitHub Actions and which is now part of this workflow. # # Images use an Alpine base image for reduced image size and thus download time, and also for faster and simpler # installation of dependencies (apk add is way faster and simpler than apt install for example). However Alpine is @@ -55,13 +55,13 @@ # manifest is then also pushed to Docker Hub. # # Building of both x86-64 and non-x86-64 architecture images are handled by a single Dockerfile which supports two -# modes of operation. In the default 'build' mode Krill is compiled within the Docker container and only the final -# artifacts are kept in the final Docker image. In the alternate 'copy' mode Krill binaries are copied into the +# modes of operation. In the default 'build' mode our app is compiled within the Docker container and only the final +# artifacts are kept in the final Docker image. In the alternate 'copy' mode our binaries are copied into the # build container and compilation within the container is skipped. # # Multi-arch image creation is NOT done using Docker Buildkit multi-arch support because (a) that does not support # configuring the different invocations of the Dockerfile differently (e.g. with MODE=copy for the non-x86-64 cases -# and providing different the binaries to copy in to the image in each case) and (b) because it compiles Krill in +# and providing different the binaries to copy in to the image in each case) and (b) because it compiles our app in # parallel for each architecture at once on a single GitHub Actions runner host which is VERY SLOW even for just a # couple of architectures. Instead we leverage the GitHub Actions matrix building support to build each image in # parallel. This means however that we have to manually invoke the `docker manifest` command as it is not handled @@ -94,8 +94,7 @@ # workflow runs), (b) we are "limited" to base images/architectures supported by Cargo Cross (but there are quite # a few of these) and (c) if the base Cargo Cross image doesn't include packages or tooling needed by `cargo build` # then building will fail. For these reasons cross compilation is done as a pre-job in this workflow (so that it can -# run on the GitHub runner Host rather than inside a Docker container) and cross-compiled packages enable the Krill -# `static-openssl` feature. +# run on the GitHub runner Host rather than inside a Docker container). # # Non-x86-64 testing: # =================== @@ -117,21 +116,17 @@ # Such 'internal' artifacts are named with a 'tmp-' prefix and are ignored by the separate manual external process # for publishing to packages.nlnetlabs.nl. - name: Packaging env: - DOCKER_REPO: nlnetlabs + DOCKER_REPO: ${{ github.repository_owner }} on: push: branches: - main - - # Triggering on tags is used to build and push appropriately tagged Docker images tags: - - 'v[0-9]+.[0-9]+.[0-9]+' - - 'v[0-9]+.[0-9]+.[0-9]+-rc[0-9]+' + - v* paths-ignore: - '.dockerignore' @@ -167,7 +162,7 @@ jobs: # # See: https://github.com/rust-embedded/cross#docker-in-docker cross: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 strategy: matrix: target: @@ -193,15 +188,12 @@ jobs: command: build args: --locked --release --features static-openssl --target ${{ matrix.target }} - # Upload cross compiled binaries as GitHub Actions artifacts for use by - # the `pkg` job below. We can't use job outputs as those are limited to - # 50 MB which we could easily exceed. We can't use actions/cache as cached - # items are not necessarily available on different operating systems as - # the cache mechanism uses different namespaces for different compression - # types and different compression types by operating system. As we don't - # want these artifacts to be packaged by the scripts that upload to - # packages.nlnetlabs.nl we prefix the artifact name with `tmp-` which will - # be ignored by packages.nlnetlabs.nl scripts. + # Upload cross compiled binaries as GitHub Actions artifacts for use by the `pkg` job below. We can't use job + # outputs as those are limited to 50 MB which we could easily exceed. We can't use actions/cache as cached items + # are not necessarily available on different operating systems as the cache mechanism uses different namespaces + # for different compression types and different compression types by operating system. As we don't want these + # artifacts to be packaged by the scripts that upload to packages.nlnetlabs.nl we prefix the artifact name with + # `tmp-` which will be ignored by packages.nlnetlabs.nl scripts. - name: Upload built binaries uses: actions/upload-artifact@v3 with: @@ -215,8 +207,7 @@ jobs: # Job: 'pkg' # ------------------------------------------------------------------------------------------------------------------- # Use the cargo-deb and cargo-generate-rpm Rust crates to build Debian and RPM packages respectively for installing - # Krill. - # See: + # our app. See: # - https://github.com/mmstick/cargo-deb # - https://github.com/cat-in-136/cargo-generate-rpm pkg: @@ -291,10 +282,10 @@ jobs: image: 'debian:buster' target: 'aarch64-unknown-linux-gnu' env: - CARGO_DEB_VER: 1.34.2 - CARGO_GENERATE_RPM_VER: 0.6.0 - # A Krill version of the form 'x.y.z-dev' denotes a dev build that is newer than the released x.y.z version but is - # not yet a new release. + CARGO_DEB_VER: 1.38.4 + CARGO_GENERATE_RPM_VER: 0.8.0 + # A version of the form 'x.y.z-dev' denotes a dev build that is newer than the released x.y.z version but is not + # yet a new release. NEXT_VER_LABEL: dev steps: - name: Set vars @@ -347,20 +338,20 @@ jobs: run: | case ${OS_NAME} in debian|ubuntu) - apt-get install -y build-essential jq libssl-dev lintian pkg-config + apt-get install -y build-essential jq lintian pkg-config libssl-dev ;; centos) yum install epel-release -y yum update -y - yum install -y jq openssl-devel rpmlint + yum install -y jq rpmlint openssl-devel yum groupinstall -y "Development Tools" ;; esac - # Speed up Krill Rust builds by caching unchanged built dependencies. + # Speed up Rust builds by caching unchanged built dependencies. # See: https://github.com/actions/cache/blob/master/examples.md#rust---cargo - name: Cache Dot Cargo - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: | ~/.cargo/registry @@ -371,14 +362,14 @@ jobs: # the tool that we are using. - name: Cache Cargo Deb if available id: cache-cargo-deb - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.cargo/bin/cargo-deb key: ${{ matrix.image }}-${{ matrix.pkg }}-${{ matrix.target }}-cargo-deb-${{ env.CARGO_DEB_VER }}-${{ endsWith(matrix.image, 'xenial')}} - name: Cache Cargo Generate RPM if available id: cache-cargo-generate-rpm - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.cargo/bin/cargo-generate-rpm key: ${{ matrix.image }}-${{ matrix.pkg }}-${{ matrix.target }}-cargo-generate-rpm-${{ env.CARGO_GENERATE_RPM_VER }} @@ -390,8 +381,8 @@ jobs: case ${OS_NAME} in debian|ubuntu) if [[ "${OS_REL}" == "xenial" ]]; then - # Disable use of the default lzma feature which causes XZ compression to be used - # which then causes Lintian to fail with error: + # Disable use of the default lzma feature which causes XZ compression to be used which then causes Lintian + # to fail with error: # E: krill: malformed-deb-archive newer compressed control.tar.xz # Passing --fast to cargo-deb to disable use of XZ compression didn't help. # See: https://github.com/kornelski/cargo-deb/issues/12 @@ -412,18 +403,6 @@ jobs: ;; esac - # NOTE: Unfortunately the wait action appears to be unreliable. The project GH issues include examples of it not - # working properly and I've had it finish without saying the waited on job completed but instead it just stopped - # and then the next build step executed prematurely and failed. - # - name: Wait on cross job - # if: ${{ matrix.target != 'x86_64' }} - # # Use v1.0.0 until https://github.com/lewagon/wait-on-check-action/issues/52 is resolved - # uses: lewagon/wait-on-check-action@v1.0.0 - # with: - # ref: ${{ github.ref }} - # repo-token: ${{ secrets.GITHUB_TOKEN }} - # check-name: cross (${{ matrix.target }}) - - name: Download cross compiled binaries if: ${{ matrix.target != 'x86_64' }} uses: actions/download-artifact@v3 @@ -474,16 +453,16 @@ jobs: # Finally, sometimes we want a version to be NEWER than the latest release but without having to decide what # higher semver number to bump to. In this case we do NOT want dash '-' to become '~' because `-` is treated as # higher and tilda is treated as lower. - KRILL_VER=$(cargo read-manifest | jq -r '.version') - KRILL_NEW_VER=$(echo $KRILL_VER | tr '-' '~') - PKG_KRILL_VER=$(echo $KRILL_NEW_VER | sed -e "s/~$NEXT_VER_LABEL/-$NEXT_VER_LABEL/") + APP_VER=$(cargo read-manifest | jq -r '.version') + APP_NEW_VER=$(echo $APP_VER | tr '-' '~') + PKG_APP_VER=$(echo $APP_NEW_VER | sed -e "s/~$NEXT_VER_LABEL/-$NEXT_VER_LABEL/") case ${OS_NAME} in debian|ubuntu) MAINTAINER="The NLnet Labs RPKI Team " - # Generate the RFC 5322 format date by hand instead of using date --rfc-email because that option doesn't exist - # on Ubuntu 16.04 and Debian 9 + # Generate the RFC 5322 format date by hand instead of using date --rfc-email because that option doesn't + # exist on Ubuntu 16.04 and Debian 9 RFC5322_TS=$(LC_TIME=en_US.UTF-8 date +'%a, %d %b %Y %H:%M:%S %z') # Generate the changelog file that Debian packages are required to have. @@ -491,8 +470,8 @@ jobs: if [ ! -d target/debian ]; then mkdir -p target/debian fi - echo "${MATRIX_PKG} (${PKG_KRILL_VER}) unstable; urgency=medium" >target/debian/changelog - echo " * See: https://github.com/NLnetLabs/krill/releases/tag/v${KRILL_NEW_VER}" >>target/debian/changelog + echo "${MATRIX_PKG} (${PKG_APP_VER}) unstable; urgency=medium" >target/debian/changelog + echo " * See: https://github.com/${{ env.GITHUB_REPOSITORY }}/releases/tag/v${APP_NEW_VER}" >>target/debian/changelog echo " -- maintainer ${MAINTAINER} ${RFC5322_TS}" >>target/debian/changelog if [[ "${CROSS_TARGET}" == "x86_64" ]]; then @@ -509,18 +488,21 @@ jobs: -e 's/^\[package\.metadata\.krillup-deb/[package.metadata.deb/' Cargo.toml fi - DEB_VER="${PKG_KRILL_VER}-1${OS_REL}" - cargo deb --variant ${VARIANT} --deb-version ${DEB_VER} -v ${EXTRA_CARGO_DEB_ARGS} -- --locked ${EXTRA_BUILD_ARGS} + DEB_VER="${PKG_APP_VER}-1${OS_REL}" + cargo deb --deb-version ${DEB_VER} --variant ${VARIANT} -v ${EXTRA_CARGO_DEB_ARGS} -- --locked ${EXTRA_BUILD_ARGS} ;; centos) - # Build Krill as cargo generate-rpm can't do this yet + # Build and strip our app binaries as cargo generate-rpm doesn't do this for us cargo build --release --locked -v ${EXTRA_BUILD_ARGS} - - # Strip Krill binaries as cargo generate-rpm can't do this yet find target/release -maxdepth 1 -type f -executable | xargs strip -s -v + # TODO: It might be possible to replace the hacky copying of the service file below with some clever use of + # `--set-metadata` when invoking cargo generate-rpm. Of particular interest is the new `--variant` command + # line argument which might enable us to work the same way as we do for cargo deb above. + # See: https://github.com/cat-in-136/cargo-generate-rpm/issues/18 + # Fix the version string to be used for the RPM package - sed -i -e "s/$KRILL_VER/$PKG_KRILL_VER/" Cargo.toml + sed -i -e "s/$APP_VER/$PKG_APP_VER/" Cargo.toml # Select the correct systemd service unit file for the target operating system case "${OS_NAME}:${OS_REL}" in @@ -553,7 +535,7 @@ jobs: ;; esac - cargo generate-rpm ${EXTRA_CARGO_GENERATE_RPM_ARGS} + cargo generate-rpm --set-metadata "version=\"${PKG_APP_VER}\"" ${EXTRA_CARGO_GENERATE_RPM_ARGS} ;; esac @@ -568,15 +550,14 @@ jobs: if [[ "${CROSS_TARGET}" == "x86_64" ]]; then EXTRA_LINTIAN_ARGS= else - EXTRA_LINTIAN_ARGS="--suppress-tags unstripped-binary-or-object" + EXTRA_LINTIAN_ARGS="--suppress-tags unstripped-binary-or-object,statically-linked-binary" fi lintian --version lintian -v ${EXTRA_LINTIAN_ARGS} target/debian/*.deb ;; centos) - # cargo generate-rpm creates RPMs that rpmlint considers to have - # errors so don't use the rpmlint exit code otherwise we will always - # abort the workflow. + # cargo generate-rpm creates RPMs that rpmlint considers to have errors so don't use the rpmlint exit code + # otherwise we will always abort the workflow. rpmlint target/generate-rpm/*.rpm || true ;; esac @@ -614,7 +595,6 @@ jobs: - 'ubuntu:focal' # ubuntu/20.04 - 'ubuntu:jammy' # ubuntu/22.04 # - 'debian:stretch' # debian/9 - LXC image is no longer available on images.linuxcontainers.org - - 'debian:buster' # debian/10 - 'debian:bullseye' # debian/11 - 'centos:7' @@ -624,12 +604,9 @@ jobs: - 'upgrade-from-published' target: - 'x86_64' - # if we later add a new O/S or variant we won't have yet ever published - # the package so can't do a test upgrade over last published version. In - # that case add lines here like so to disable the upgrade from published - # test for that O/S (remember to change debian:bullseye to the correct - # O/S name!): - # + # if we later add a new O/S or variant we won't have yet ever published the package so can't do a test upgrade + # over last published version. In that case add lines here like so to disable the upgrade from published test + # for that O/S (remember to change debian:bullseye to the correct O/S name!): # # exclude: # - image: 'debian:bullseye' @@ -686,8 +663,7 @@ jobs: run: | sg lxd -c "lxc info" - # Use of IPv6 sometimes prevents yum update being able to resolve - # mirrorlist.centos.org. + # Use of IPv6 sometimes prevents yum update being able to resolve mirrorlist.centos.org. - name: Disable LXD assignment of IPv6 addresses run: | sg lxd -c "lxc network set lxdbr0 ipv6.address none" @@ -698,12 +674,10 @@ jobs: # Debian 10 container. sg lxd -c "lxc launch ${LXC_IMAGE} -c security.nesting=true testcon" - # Run package update and install man and sudo support (missing in some - # LXC/LXD O/S images) but first wait for cloud-init to finish otherwise the - # network isn't yet ready. Don't use cloud-init status --wait as that isn't - # supported on older O/S's like Ubuntu 16.04 and Debian 9. Use the sudo - # package provided configuration files otherwise when using sudo we get an - # error that the root user isn't allowed to use sudo. + # Run package update and install man and sudo support (missing in some LXC/LXD O/S images) but first wait for + # cloud-init to finish otherwise the network isn't yet ready. Don't use cloud-init status --wait as that isn't + # supported on older O/S's like Ubuntu 16.04 and Debian 9. Use the sudo package provided configuration files + # otherwise when using sudo we get an error that the root user isn't allowed to use sudo. - name: Prepare container shell: bash run: | @@ -728,6 +702,21 @@ jobs: ;; esac + - name: Copy the newly built ${{ matrix.pkg }} package into the LXC container + run: | + case ${OS_NAME} in + debian|ubuntu) + DEB_FILE=$(ls -1 debian/*.deb) + sg lxd -c "lxc file push ${DEB_FILE} testcon/tmp/" + echo "PKG_FILE=$(basename $DEB_FILE)" >> $GITHUB_ENV + ;; + centos) + RPM_FILE=$(ls -1 generate-rpm/*.rpm) + sg lxd -c "lxc file push ${RPM_FILE} testcon/tmp/" + echo "PKG_FILE=$(basename $RPM_FILE)" >> $GITHUB_ENV + ;; + esac + - name: Install previously published ${{ matrix.pkg }} package if: ${{ matrix.mode == 'upgrade-from-published' }} run: | @@ -751,21 +740,6 @@ jobs: ;; esac - - name: Copy the newly built ${{ matrix.pkg }} package into the LXC container - run: | - case ${OS_NAME} in - debian|ubuntu) - DEB_FILE=$(ls -1 debian/*.deb) - sg lxd -c "lxc file push ${DEB_FILE} testcon/tmp/" - echo "PKG_FILE=$(basename $DEB_FILE)" >> $GITHUB_ENV - ;; - centos) - RPM_FILE=$(ls -1 generate-rpm/*.rpm) - sg lxd -c "lxc file push ${RPM_FILE} testcon/tmp/" - echo "PKG_FILE=$(basename $RPM_FILE)" >> $GITHUB_ENV - ;; - esac - - name: Install the newly built ${{ matrix.pkg }} package if: ${{ matrix.mode == 'fresh-install' }} run: | @@ -778,7 +752,7 @@ jobs: ;; esac - - name: Test the installed krill package + - name: Test the installed ${{ matrix.pkg }} package if: ${{ matrix.pkg == 'krill' }} run: | echo -e "\nKRILLC VERSION:" @@ -812,7 +786,7 @@ jobs: echo -e "\nKRILL MAN PAGE:" sg lxd -c "lxc exec testcon -- man -P cat krill" - - name: Test the installed krillup package + - name: Test the installed ${{ matrix.pkg }} package if: ${{ matrix.pkg == 'krillup' }} run: | echo -e "\nKRILLUP VERSION:" @@ -833,7 +807,7 @@ jobs: ;; esac - - name: Test the upgraded krill package + - name: Test the upgraded ${{ matrix.pkg }} package if: ${{ matrix.mode == 'upgrade-from-published' && matrix.pkg == 'krill' }} run: | echo -e "\nKRILLC VERSION:" @@ -871,6 +845,14 @@ jobs: matrix: # matrix field notes: # platform: used by Docker to use the right architecture base image. + # the set of supported values can be seen at: + # https://go.dev/doc/install/source#environment + # from: https://github.com/docker-library/official-images#architectures-other-than-amd64 + # from: https://docs.docker.com/desktop/multi-arch/ + # one must also take any "normalization" into account, e.g. arm64v8 -> arm64, see: + # https://github.com/containerd/containerd/blob/v1.4.3/platforms/database.go#L83 + # see also: + # https://stackoverflow.com/a/70889505 # shortname: used by us to tag the architecture specific "manifest" image. # crosstarget: (optional) used to download the correct cross-compiled binary that was produced earlier by the # 'cross' job above. @@ -897,7 +879,7 @@ jobs: crosstarget: 'aarch64-unknown-linux-musl' mode: 'copy' outputs: - dockerbasetag: ${{ steps.meta.outputs.tags }} + dockerbasetag: ${{ steps.gen_tag.outputs.encoded_tag }} steps: - name: Checkout repository uses: actions/checkout@v2 @@ -924,18 +906,6 @@ jobs: type=raw,value=latest,enable=${{ github.ref != 'refs/heads/main' && !contains(github.ref, '-') }} type=raw,value=test,enable=${{ !contains(github.ref, 'refs/tags/v') && github.ref != 'refs/heads/main' }} - # NOTE: Unfortunately the wait action appears to be unreliable. The project GH issues include examples of it not - # working properly and I've had it finish without saying the waited on job completed but instead it just stopped - # and then the next build step executed prematurely and failed. - # - name: Wait on cross job - # if: ${{ matrix.mode == 'copy' }} - # # Use v1.0.0 until https://github.com/lewagon/wait-on-check-action/issues/52 is resolved - # uses: lewagon/wait-on-check-action@v1.0.0 - # with: - # ref: ${{ github.ref }} - # repo-token: ${{ secrets.GITHUB_TOKEN }} - # check-name: cross (${{ matrix.crosstarget }}) - - name: Download cross compiled binaries if: ${{ matrix.mode == 'copy' }} uses: actions/download-artifact@v3 @@ -950,6 +920,22 @@ jobs: username: ${{ secrets.DOCKER_HUB_ID }} password: ${{ secrets.DOCKER_HUB_TOKEN }} + - name: Generate architecture specific Docker tag + id: gen_tag + run: | + LOWER_REPO_NAME=$(echo "${DOCKER_REPO}" | tr '[:upper:]' '[:lower:]') + TAG="${LOWER_REPO_NAME}/${{ steps.meta.outputs.tags }}" + echo "::set-output name=tag::$TAG" + echo "::set-output name=tag_with_arch::$TAG-${{ matrix.shortname }}" + + # Encode the tag value as base64 to avoid GitHub Actions refusing to pass the output on to the job that needs + # it with warning "Skip output 'dockerbasetag' since it may contain secret.". This can happen if the + # DOCKER_REPO value contains the DOCKER_HUB_ID value. E.g. if DOCKER_REPO were 'nlnetlabs' and the user to + # login to Docker Hub as is also 'nlnetlabs' then Docker thinks the latter, a secret, is being leaked via the + # workflow output 'dockerbasetag' defined above. + ENCODED_TAG=$(echo $TAG | base64) + echo "::set-output name=encoded_tag::$ENCODED_TAG" + # Build a single architecture specific Docker image with an explicit architecture extension in the Docker # tag value. We have to push it to Docker Hub otherwise we can't make the multi-arch manifest below. If the # image fails testing (or doesn't work but wasn't caught because it is non-x86-64 which we can't at the moment @@ -961,7 +947,7 @@ jobs: with: context: . platforms: ${{ matrix.platform }} - tags: ${{ env.DOCKER_REPO }}/${{ steps.meta.outputs.tags }}-${{ matrix.shortname }} + tags: ${{ steps.gen_tag.outputs.tag_with_arch }} build-args: | MODE=${{ matrix.mode }} CARGO_ARGS=${{ matrix.cargo_args }} @@ -969,14 +955,14 @@ jobs: - name: Save Docker image locally run: | - docker save -o /tmp/docker-${{ matrix.shortname }}-img.tar ${{ env.DOCKER_REPO }}/${{ steps.meta.outputs.tags }}-${{ matrix.shortname }} + docker save -o /tmp/docker-${{ matrix.shortname }}-img.tar ${{ steps.gen_tag.outputs.tag_with_arch }} # Do a basic sanity check of the created image using the test tag to select the image to run, but only if the # image is for the x86-64 architecture as we don't yet have a way to run non-x86-64 architecture images. - name: Test run (linux/amd64 images only) if: ${{ matrix.platform == 'linux/amd64' }} run: | - docker run --rm ${{ env.DOCKER_REPO }}/${{ steps.meta.outputs.tags }}-${{ matrix.shortname }} krillc --version + docker run --rm ${{ steps.gen_tag.outputs.tag_with_arch }} krillc --version # Upload the Docker image as a GitHub Actions artifact, handy when not publishing or investigating a problem - name: Upload built image to GitHub Actions @@ -991,7 +977,7 @@ jobs: with: context: . platforms: ${{ matrix.platform }} - tags: ${{ env.DOCKER_REPO }}/${{ steps.meta.outputs.tags }}-${{ matrix.shortname }} + tags: ${{ steps.gen_tag.outputs.tag_with_arch }} build-args: | MODE=${{ matrix.mode }} CARGO_ARGS=${{ matrix.cargo_args }} @@ -1033,15 +1019,21 @@ jobs: # # On push to refs/heads/main the Docker tag will be 'unstable' because of: # type=raw,value=unstable,enable=${{ github.ref == 'refs/heads/main' }} + - name: Decode encoded tag + id: decode_tag + run: | + DECODED_TAG=$(echo ${{ needs.docker.outputs.dockerbasetag }} | base64 -d) + echo "::set-output name=tag::$DECODED_TAG" + - name: Create multi-arch manifest run: | docker manifest create \ - ${{ env.DOCKER_REPO}}/${{ needs.docker.outputs.dockerbasetag }} \ - --amend ${{ env.DOCKER_REPO }}/${{ needs.docker.outputs.dockerbasetag }}-amd64 \ - --amend ${{ env.DOCKER_REPO }}/${{ needs.docker.outputs.dockerbasetag }}-armv6 \ - --amend ${{ env.DOCKER_REPO }}/${{ needs.docker.outputs.dockerbasetag }}-armv7 \ - --amend ${{ env.DOCKER_REPO }}/${{ needs.docker.outputs.dockerbasetag }}-arm64 + ${{ steps.decode_tag.outputs.tag }} \ + --amend ${{ steps.decode_tag.outputs.tag }}-amd64 \ + --amend ${{ steps.decode_tag.outputs.tag }}-armv6 \ + --amend ${{ steps.decode_tag.outputs.tag }}-armv7 \ + --amend ${{ steps.decode_tag.outputs.tag }}-arm64 - name: Publish multi-arch image to Docker Hub run: | - docker manifest push ${{ env.DOCKER_REPO }}/${{ needs.docker.outputs.dockerbasetag }} + docker manifest push ${{ steps.decode_tag.outputs.tag }} diff --git a/Dockerfile b/Dockerfile index b94b83da..88e88ab0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,13 @@ # This is a multi-stage Dockerfile, with a selectable first stage. With this # approach we get: # -# 1. Separation of dependencies needed to build Krill in the 'build' stage -# and those needed to run Krill in the 'final' stage, as we don't want the -# build-time dependencies to be included in the final Krill Docker image. +# 1. Separation of dependencies needed to build our app in the 'build' stage +# and those needed to run our app in the 'final' stage, as we don't want +# the build-time dependencies to be included in the final Docker image. # -# 2. Support for either building Krill for the architecture of the base image -# using MODE=build (the default) or for externally built Krill binaries -# (e.g. cross-compiled) using MODE=copy. +# 2. Support for either building our app for the architecture of the base +# image using MODE=build (the default) or for externally built app +# binaries (e.g. cross-compiled) using MODE=copy. # # In total there are four stages consisting of: # - Two possible first stages: 'build' or 'copy'. @@ -29,12 +29,12 @@ # ==== # Supported values: build (default), copy # -# By default this Dockerfile will build Krill from sources. If the sources +# By default this Dockerfile will build our app from sources. If the sources # have already been (cross) compiled by some external process and you wish to # use the resulting binaries from that process, then: # # 1. Create a directory on the host called 'dockerbin/$TARGETPLATFORM' -# containing the already compiled Krill binaries (where $TARGETPLATFORM +# containing the already compiled app binaries (where $TARGETPLATFORM # is a special variable set by Docker BuiltKit). # 2. Supply arguments `--build-arg MODE=copy` to `docker build`. ARG MODE=build @@ -44,11 +44,6 @@ ARG MODE=build # ======== # # Only used when MODE=build. -# -# This ARG is for internal use only. It exists so that the Krill E2E test can -# use a base image with a prepopulated Cargo build cache to accelerate the -# build process. This does NOT affect the base image of the final Docker -# image. ARG BASE_IMG=alpine:3.15 @@ -57,8 +52,8 @@ ARG BASE_IMG=alpine:3.15 # # Only used when MODE=build. # -# This ARG is intended for use by the Krill E2E test so that if needed it can -# control the features enabled when compiling Krill. +# This ARG can be used to control the features enabled when compiling the app +# or other compilation settings as necessary. ARG CARGO_ARGS @@ -71,13 +66,13 @@ ARG CARGO_ARGS # Docker stage: build # ----------------------------------------------------------------------------- # -# Builds Krill binaries from sources. +# Builds our app binaries from sources. FROM ${BASE_IMG} AS build ARG CARGO_ARGS -RUN apk --no-cache add rust cargo openssl-dev +RUN apk add --no-cache rust cargo openssl-dev -WORKDIR /tmp/krill +WORKDIR /tmp/build COPY . . # `CARGO_HTTP_MULTIPLEXING` forces Cargo to use HTTP/1.1 without pipelining @@ -95,7 +90,6 @@ COPY . . # actually causes the binaries to be placed in `/tmp/out/bin/`. `cargo install` # will create the output directory for us. RUN CARGO_HTTP_MULTIPLEXING=false cargo install \ - --target x86_64-alpine-linux-musl \ --locked \ --path . \ --root /tmp/out/ \ @@ -103,7 +97,7 @@ RUN CARGO_HTTP_MULTIPLEXING=false cargo install \ # ----------------------------------------------------------------------------- -# Build stage: copy +# Docker stage: copy # ----------------------------------------------------------------------------- # Only used when MODE=copy. # @@ -123,15 +117,21 @@ ONBUILD COPY dockerbin/$TARGETPLATFORM /tmp/out/bin/ # Docker stage: source # ----------------------------------------------------------------------------- # This is a "magic" build stage that "labels" a chosen prior build stage as the -# one that the build stage after this one should copy Krill binaries from. +# one that the build stage after this one should copy application binaries +# from. It also causes the ONBUILD COPY command from the 'copy' stage to be run +# if needed. Finally, we ensure binaries have the executable flag set because +# when copied in from outside they may not have the flag set, especially if +# they were uploaded as a GH actions artifact then downloaded again which +# causes file permissions to be lost. +# See: https://github.com/actions/upload-artifact#permission-loss FROM ${MODE} AS source - +RUN chmod a+x /tmp/out/bin/* # ----------------------------------------------------------------------------- # Docker stage: final # ----------------------------------------------------------------------------- # Create an image containing just the binaries, configs & scripts needed to run -# Krill, and not the things needed to build it. +# our app, and not the things needed to build it. # # The previous build stage from which binaries are copied is controlled by the # MODE ARG (see above). @@ -146,9 +146,9 @@ ARG RUN_USER_UID=1012 ARG RUN_USER_GID=1012 # Install required runtime dependencies -RUN apk --no-cache add bash libgcc openssl tini tzdata util-linux +RUN apk add --no-cache bash libgcc openssl tini tzdata util-linux -# Create the user and group to run the Krill daemon as +# Create the user and group to run the application as RUN addgroup -g ${RUN_USER_GID} ${RUN_USER} && \ adduser -D -u ${RUN_USER_UID} -G ${RUN_USER} ${RUN_USER} @@ -162,15 +162,17 @@ RUN chown -R ${RUN_USER}: . COPY docker/entrypoint.sh /opt/ RUN chown ${RUN_USER}: /opt/entrypoint.sh -# Run Krill as the defined user -USER $RUN_USER_UID +# Switch to our applications user +# This is commented out because it may cause issues for users upgrading from +# an earlier version of Krill, because those versions run Krill as root. +# USER $RUN_USER_UID -# Hint to operators the TCP port that the Krill daemon in this image listens on +# Hint to operators the TCP port that the application in this image listens on # (by default). EXPOSE 3000/tcp -# Use Tini to ensure that krillc responds to CTRL-C when run in the foreground -# without the Docker argument "--init" (which is actually another way of -# activating Tini, but cannot be enabled from inside the Docker image). +# Use Tini to ensure that our application responds to CTRL-C when run in the +# foreground without the Docker argument "--init" (which is actually another +# way of activating Tini, but cannot be enabled from inside the Docker image). ENTRYPOINT ["/sbin/tini", "--", "/opt/entrypoint.sh"] CMD ["krill", "-c", "/var/krill/data/krill.conf"] diff --git a/README.md b/README.md index d4fc8ff7..597840ac 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,6 @@ in RC1 and RC2: - Trim uploaded parent and repo responses #873 - XML generated for RFC 8183 communication starts with a line break #874 - RFC 8183 XML responses submitted via the UI are incorrectly escaped #875 -- Run as user 'krill' inside Docker containers, not 'root' #882 - API to upload repository response should not change #895 - API to add parent should not change #898