From b126fd8c295a5af70da129a495573bc938b1c37f Mon Sep 17 00:00:00 2001 From: Kevin Oberlies Date: Tue, 29 Oct 2024 12:50:41 -0700 Subject: [PATCH] feat: Buildkite pipeline for building dev docker images [ES-9318] (#1873) * feat: Change Dockerfile base images to Wolfi Running the docker image with a mounted `/rally/.rally` directory that already contains the configuration file didn't work. So I had to change how we parse the logging config and rally.ini files. Now we delay the parsing of the environment variables to read time, to make running from docker and outside of docker compatible with each other. Added buildkite jobs to build both release and development docker images --- .buildkite/dev-docker/pipeline.yml | 54 ++++++++- .buildkite/dev-docker/run.sh | 86 ++++++++++++--- .buildkite/release-docker/pipeline.yml | 33 +++++- .buildkite/release-docker/run.sh | 76 ++++++++++--- build-dev-docker-manifest.sh | 98 +++++++++++++++++ build-dev-docker.sh | 103 ++++++++++++++++++ .../{Dockerfile-dev => dev/Dockerfile} | 16 +-- .../Dockerfile} | 15 +-- docker/docker-compose-tests.yml | 2 +- it/__init__.py | 2 +- it/docker_dev_image_test.py | 5 +- release-docker-manifest.sh | 96 ++++++++++++++++ release-docker-test.sh | 17 ++- release-docker.sh | 37 ++++--- 14 files changed, 564 insertions(+), 76 deletions(-) create mode 100755 build-dev-docker-manifest.sh create mode 100755 build-dev-docker.sh rename docker/Dockerfiles/{Dockerfile-dev => dev/Dockerfile} (92%) rename docker/Dockerfiles/{Dockerfile-release => release/Dockerfile} (91%) create mode 100755 release-docker-manifest.sh diff --git a/.buildkite/dev-docker/pipeline.yml b/.buildkite/dev-docker/pipeline.yml index 3f7d599a9..a58d5a0e9 100644 --- a/.buildkite/dev-docker/pipeline.yml +++ b/.buildkite/dev-docker/pipeline.yml @@ -1,3 +1,53 @@ steps: - - label: ":wave: Greetings" # Label (with rich emojis https://ela.st/bk-emoji). - command: "echo 'My first pipeline!'" # Command to run (evaluated by Bash). + - input: "Build parameters" + if: build.source != "schedule" + fields: + - text: "BUILD_FROM_BRANCH" + key: "BUILD_FROM_BRANCH" + default: "" + hint: "The branch to build from e.g. 'master'. Leave blank to build from the current branch: $BUILDKITE_BRANCH." + required: false + - select: "PUBLIC_DOCKER_REPO" + key: "PUBLIC_DOCKER_REPO" + hint: "Push the Docker image to the public Docker registry (default: No)." + default: "false" + options: + - label: "Yes" + value: "true" + - label: "No" + value: "false" + - select: "PUSH_LATEST" + key: "PUSH_LATEST" + hint: "Push the -latest tag to the registry." + default: "true" + options: + - label: "Yes" + value: "true" + - label: "No" + value: "false" + - wait + - label: ":docker: Build Docker Artifacts for Rally amd64" + command: bash .buildkite/dev-docker/run.sh build amd64 + key: "amd64" + agents: + machineType: "n2-standard-8" + image: family/core-ubuntu-2204 + zone: "us-central1-a" + provider: "gcp" + - label: ":docker: Build Docker Artifacts for Rally arm64" + command: bash .buildkite/dev-docker/run.sh build arm64 + key: "arm64" + agents: + machineType: "t2a-standard-8" + image: family/core-ubuntu-2204-aarch64 + zone: "us-central1-a" + provider: "gcp" + - label: ":docker: build docker manifest" + command: bash .buildkite/dev-docker/run.sh manifest both + key: "manifest" + depends_on: + - "amd64" + - "arm64" + agents: + zone: "us-central1-a" + provider: "gcp" diff --git a/.buildkite/dev-docker/run.sh b/.buildkite/dev-docker/run.sh index aef729a2f..5d8d2dbe4 100644 --- a/.buildkite/dev-docker/run.sh +++ b/.buildkite/dev-docker/run.sh @@ -5,25 +5,79 @@ set -eo pipefail source .buildkite/retry.sh set +x -RELEASE_VERSION=$(buildkite-agent meta-data get RELEASE_VERSION) + +BUILD_FROM_BRANCH=$(buildkite-agent meta-data get BUILD_FROM_BRANCH --default "${BUILDKITE_BRANCH}") +PUSH_LATEST=$(buildkite-agent meta-data get PUSH_LATEST) +PUBLIC_DOCKER_REPO=$(buildkite-agent meta-data get PUBLIC_DOCKER_REPO) + +if [[ $# -lt 1 ]]; then + echo "Usage: $0 (build|manifest) ..." + exit 1 +fi + +ACTION="$1" + # login to docker registry -DOCKER_PASSWORD=$(vault read -field token /secret/ci/elastic-rally/release/docker-hub-rally) -retry 5 docker login -u elasticmachine -p $DOCKER_PASSWORD +if [[ $PUBLIC_DOCKER_REPO == "true" ]]; then + VAULT_PATH="secret/ci/elastic-rally/release/docker-hub-rally" + DOCKER_REGISTRY="docker.io" + PASSWORD_FIELD="token" +else + VAULT_PATH="kv/ci-shared/elasticsearch-benchmarks/cloud/docker-registry-api-credentials" + DOCKER_REGISTRY="docker.elastic.co" + PASSWORD_FIELD="password" +fi + +DOCKER_USERNAME=$(retry 5 vault kv get -field username "${VAULT_PATH}") +DOCKER_PASSWORD=$(retry 5 vault kv get -field "${PASSWORD_FIELD}" "${VAULT_PATH}") +retry 5 docker login -u "${DOCKER_USERNAME}" -p "${DOCKER_PASSWORD}" ${DOCKER_REGISTRY} unset DOCKER_PASSWORD +unset DOCKER_USERNAME + +build_docker_image() { + tmp_dir=$(mktemp --directory) + pushd "$tmp_dir" + git clone https://github.com/elastic/rally + pushd rally + # checkout the version from the buildkite branch, but build it from the branch we specified + if [[ ! -z "${BUILDKITE_BRANCH}" ]]; then + git checkout "${BUILDKITE_BRANCH}" + else + git checkout "${BUILD_FROM_BRANCH}" + fi + echo "Docker commit: $(git --no-pager log --oneline -n1)" -tmp_dir=$(mktemp --directory) -pushd "$tmp_dir" -git clone https://github.com/elastic/rally -pushd rally -git checkout "${RELEASE_VERSION}" -git --no-pager show + set -x + export TERM=dumb + export LC_ALL=en_US.UTF-8 + ./build-dev-docker.sh "$BUILD_FROM_BRANCH" "$ARCH" "$PUSH_LATEST" "$PUBLIC_DOCKER_REPO" -set -x -export TERM=dumb -export LC_ALL=en_US.UTF-8 -./release-docker.sh "$RELEASE_VERSION" + popd + popd + rm -rf "$tmp_dir" +} -popd -popd -rm -rf "$tmp_dir" +build_docker_manifest() { + set -x + export TERM=dumb + export LC_ALL=en_US.UTF-8 + ./build-dev-docker-manifest.sh "$BUILD_FROM_BRANCH" "$PUSH_LATEST" "$PUBLIC_DOCKER_REPO" +} +case "$ACTION" in + "build") + if [[ $# -lt 2 ]]; then + echo "Usage: $0 build [amd64|arm64]" + exit 1 + fi + ARCH="$2" + build_docker_image + ;; + "manifest") + build_docker_manifest + ;; + *) + echo "Unknown action: $ACTION" + exit 1 + ;; +esac diff --git a/.buildkite/release-docker/pipeline.yml b/.buildkite/release-docker/pipeline.yml index dfdc2a106..60f50b811 100644 --- a/.buildkite/release-docker/pipeline.yml +++ b/.buildkite/release-docker/pipeline.yml @@ -1,3 +1,7 @@ +agents: + provider: "gcp" + zone: "us-central1-a" + steps: - input: "Build parameters" fields: @@ -5,10 +9,35 @@ steps: key: "RELEASE_VERSION" default: "" hint: "The version to release e.g. '2.8.0'." + - select: "PUSH_LATEST" + key: "PUSH_LATEST" + hint: "Update the latest tag in the registry." + # True, because we want the scheduled pipeline to update the latest tag, eventually + default: "true" + options: + - label: "Yes" + value: "true" + - label: "No" + value: "false" - wait - label: "Release Docker Artifacts for Rally" - command: bash .buildkite/release-docker/run.sh + command: bash .buildkite/release-docker/run.sh build amd64 + # Run on GCP to use `docker` + key: "amd64" + agents: + machineType: "n2-standard-8" + image: family/core-ubuntu-2204 + - label: "Release Docker Artifacts for Rally" + command: bash .buildkite/release-docker/run.sh build arm64 # Run on GCP to use `docker` + key: "arm64" agents: - provider: gcp + machineType: "t2a-standard-8" + image: family/core-ubuntu-2204-aarch64 + - label: ":docker: build docker manifest" + command: bash .buildkite/release-docker/run.sh manifest + key: "manifest" + depends_on: + - "amd64" + - "arm64" diff --git a/.buildkite/release-docker/run.sh b/.buildkite/release-docker/run.sh index 98c4dc598..44276d482 100644 --- a/.buildkite/release-docker/run.sh +++ b/.buildkite/release-docker/run.sh @@ -6,23 +6,67 @@ source .buildkite/retry.sh set +x RELEASE_VERSION=$(buildkite-agent meta-data get RELEASE_VERSION) +PUSH_LATEST=$(buildkite-agent meta-data get PUSH_LATEST) + +if [[ $# -lt 1 ]]; then + echo "Usage: $0 (build|manifest)" + exit 1 +fi + +ACTION="$1" + # login to docker registry -DOCKER_PASSWORD=$(vault read -field token /secret/ci/elastic-rally/release/docker-hub-rally) +DOCKER_PASSWORD=$(retry 5 vault kv get -field token /secret/ci/elastic-rally/release/docker-hub-rally) retry 5 docker login -u elasticmachine -p $DOCKER_PASSWORD unset DOCKER_PASSWORD -tmp_dir=$(mktemp --directory) -pushd "$tmp_dir" -git clone https://github.com/elastic/rally -pushd rally -git checkout "${RELEASE_VERSION}" -git --no-pager show - -set -x -export TERM=dumb -export LC_ALL=en_US.UTF-8 -./release-docker.sh "$RELEASE_VERSION" - -popd -popd -rm -rf "$tmp_dir" +build_docker_image() { + tmp_dir=$(mktemp --directory) + pushd "$tmp_dir" + git clone https://github.com/elastic/rally + pushd rally + + # checkout the latest version, to make sure we get the latest docker security fixes + if [[ ! -z "${BUILDKITE_BRANCH}" ]]; then + git checkout "${BUILDKITE_BRANCH}" + else + git checkout "${RELEASE_VERSION}" + fi + + git "Docker commit: $(git --no-pager log --oneline -n1)" + + set -x + export TERM=dumb + export LC_ALL=en_US.UTF-8 + ./release-docker.sh "$RELEASE_VERSION" "$ARCH" "$PUSH_LATEST" + + popd + popd + rm -rf "$tmp_dir" +} + +build_docker_manifest() { + set -x + export TERM=dumb + export LC_ALL=en_US.UTF-8 + ./release-docker-manifest.sh "$RELEASE_VERSION" "$PUSH_LATEST" +} + + +case "$ACTION" in + "build") + if [[ $# -lt 2 ]]; then + echo "Usage: $0 build [amd64|arm64]" + exit 1 + fi + ARCH="$2" + build_docker_image + ;; + "manifest") + build_docker_manifest + ;; + *) + echo "Unknown action: $ACTION" + exit 1 + ;; +esac diff --git a/build-dev-docker-manifest.sh b/build-dev-docker-manifest.sh new file mode 100755 index 000000000..d28e2d597 --- /dev/null +++ b/build-dev-docker-manifest.sh @@ -0,0 +1,98 @@ +#!/usr/bin/env bash + +# Licensed to Elasticsearch B.V. under one or more contributor +# license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright +# ownership. Elasticsearch B.V. licenses this file to you under +# the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Prerequisites for releasing: + +# Logged in on Docker Hub (docker login) + +# fail this script immediately if any command fails with a non-zero exit code +set -eu + +function push_failed { + echo "Error while pushing Docker image. Did you \`docker login\`?" +} + +if [[ $# -eq 0 ]] ; then + echo "ERROR: $0 requires the Rally branch to build from as a command line argument and you didn't supply it." + echo "For example: $0 master true" + exit 1 +fi +export RALLY_BRANCH=$1 +export PUSH_LATEST=$2 +export PUBLIC_DOCKER_REPO=$3 +if [[ $PUBLIC_DOCKER_REPO == "true" ]]; then + export RALLY_DOCKER_IMAGE="elastic/rally" +else + export RALLY_DOCKER_IMAGE="docker.elastic.co/es-perf/rally" +fi + +export RALLY_LICENSE=$(awk 'FNR>=2 && FNR<=2' LICENSE | sed 's/^[ \t]*//') + +export GIT_SHA=$(git rev-parse --short HEAD) +export DATE=$(date +%Y%m%d) + +export RALLY_VERSION="${RALLY_BRANCH}-${GIT_SHA}-${DATE}" +export MAIN_BRANCH=$(git remote show origin | sed -n '/HEAD branch/s/.*: //p') + +if [[ $RALLY_BRANCH == $MAIN_BRANCH ]]; then + export DOCKER_TAG_LATEST="dev-latest" +else + export DOCKER_TAG_LATEST="${RALLY_BRANCH}-latest" +fi + +echo "========================================================" +echo "Pulling Docker images for Rally $RALLY_VERSION " +echo "========================================================" + +docker pull ${RALLY_DOCKER_IMAGE}:${RALLY_VERSION}-amd64 +docker pull ${RALLY_DOCKER_IMAGE}:${RALLY_VERSION}-arm64 + +echo "=======================================================" +echo "Creating Docker manifest image for Rally $RALLY_VERSION" +echo "=======================================================" + +docker manifest create ${RALLY_DOCKER_IMAGE}:${RALLY_VERSION} \ + --amend ${RALLY_DOCKER_IMAGE}:${RALLY_VERSION}-amd64 \ + --amend ${RALLY_DOCKER_IMAGE}:${RALLY_VERSION}-arm64 + +trap push_failed ERR +echo "=======================================================" +echo "Publishing Docker image ${RALLY_DOCKER_IMAGE}:$RALLY_VERSION " +echo "=======================================================" +docker manifest push ${RALLY_DOCKER_IMAGE}:${RALLY_VERSION} + +trap - ERR + +if [[ $PUSH_LATEST == "true" ]]; then + echo "=======================================================" + echo "Creating Docker manifest image for Rally $DOCKER_TAG_LATEST" + echo "=======================================================" + + docker manifest create ${RALLY_DOCKER_IMAGE}:${DOCKER_TAG_LATEST} \ + --amend ${RALLY_DOCKER_IMAGE}:${DOCKER_TAG_LATEST}-amd64 \ + --amend ${RALLY_DOCKER_IMAGE}:${DOCKER_TAG_LATEST}-arm64 + + trap push_failed ERR + echo "=======================================================" + echo "Publishing Docker image ${RALLY_DOCKER_IMAGE}:${DOCKER_TAG_LATEST}" + echo "=======================================================" + docker manifest push ${RALLY_DOCKER_IMAGE}:${DOCKER_TAG_LATEST} +fi + +trap - ERR diff --git a/build-dev-docker.sh b/build-dev-docker.sh new file mode 100755 index 000000000..c0b642050 --- /dev/null +++ b/build-dev-docker.sh @@ -0,0 +1,103 @@ +#!/usr/bin/env bash + +# Licensed to Elasticsearch B.V. under one or more contributor +# license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright +# ownership. Elasticsearch B.V. licenses this file to you under +# the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Prerequisites for releasing: + +# Logged in on Docker Hub (docker login) + +# fail this script immediately if any command fails with a non-zero exit code +set -eu + +function push_failed { + echo "Error while pushing Docker image. Did you \`docker login\`?" +} + +if [[ $# -ne 4 ]] ; then + echo "ERROR: $0 requires the Rally branch to build, the architecture, and whether to push the latest \ + as command line arguments and they weren't supplied." + echo "For example: $0 master amd64 true true" + exit 1 +fi +export RALLY_BRANCH=$1 +export ARCH=$2 +export PUSH_LATEST=$3 +export PUBLIC_DOCKER_REPO=$4 + +if [[ $PUBLIC_DOCKER_REPO == "true" ]]; then + export RALLY_DOCKER_IMAGE="elastic/rally" +else + export RALLY_DOCKER_IMAGE="docker.elastic.co/es-perf/rally" +fi + +export RALLY_LICENSE=$(awk 'FNR>=2 && FNR<=2' LICENSE | sed 's/^[ \t]*//') + +export GIT_SHA=$(git rev-parse --short HEAD) +export DATE=$(date +%Y%m%d) + +export RALLY_VERSION="${RALLY_BRANCH}-${GIT_SHA}-${DATE}-${ARCH}" +export RALLY_VERSION_TAG="${RALLY_VERSION}" +export MAIN_BRANCH=$(git remote show origin | sed -n '/HEAD branch/s/.*: //p') + +if [[ $RALLY_BRANCH == $MAIN_BRANCH ]]; then + export DOCKER_TAG_LATEST="dev-latest-${ARCH}" +else + export DOCKER_TAG_LATEST="${RALLY_BRANCH}-latest-${ARCH}" +fi + +# Make new temporary directory to checkout the `RALLY_BRANCH` branch +tmp_dir=$(mktemp --directory) +pushd "$tmp_dir" +git clone https://github.com/elastic/rally +pushd rally +git checkout "${RALLY_BRANCH}" +echo "Rally commit: $(git --no-pager log --oneline -n1)" +popd +popd +rally_dir="${tmp_dir}/rally" + + +echo "========================================================" +echo "Building Docker image for Rally $RALLY_VERSION " +echo "========================================================" + +docker build -t ${RALLY_DOCKER_IMAGE}:${RALLY_VERSION} --build-arg RALLY_VERSION --build-arg RALLY_LICENSE -f docker/Dockerfiles/dev/Dockerfile ${rally_dir} + +echo "=======================================================" +echo "Testing Docker image for Rally release $RALLY_VERSION " +echo "=======================================================" + +./release-docker-test.sh dev + +echo "=======================================================" +echo "Publishing Docker image ${RALLY_DOCKER_IMAGE}:$RALLY_VERSION " +echo "=======================================================" + +trap push_failed ERR +docker push ${RALLY_DOCKER_IMAGE}:${RALLY_VERSION} + +if [[ $PUSH_LATEST == "true" ]]; then + echo "============================================" + echo "Publishing Docker image ${RALLY_DOCKER_IMAGE}:${DOCKER_TAG_LATEST}" + echo "============================================" + + docker tag ${RALLY_DOCKER_IMAGE}:${RALLY_VERSION} ${RALLY_DOCKER_IMAGE}:${DOCKER_TAG_LATEST} + docker push ${RALLY_DOCKER_IMAGE}:${DOCKER_TAG_LATEST} +fi + +trap - ERR diff --git a/docker/Dockerfiles/Dockerfile-dev b/docker/Dockerfiles/dev/Dockerfile similarity index 92% rename from docker/Dockerfiles/Dockerfile-dev rename to docker/Dockerfiles/dev/Dockerfile index de506a8c0..9bc3ceefc 100644 --- a/docker/Dockerfiles/Dockerfile-dev +++ b/docker/Dockerfiles/dev/Dockerfile @@ -1,9 +1,14 @@ FROM docker.elastic.co/wolfi/python:3.12.3-dev AS builder +ARG RALLY_VERSION +ARG RALLY_LICENSE + +ENV RALLY_RUNNING_IN_DOCKER=True + USER root RUN apk update -RUN apk add curl git gcc pigz bash zstd bzip2 gzip +RUN apk add curl git gcc pigz bash zstd bzip2 gzip openssh # pbzip2 doesn't have a package for wolfi, so we build it from source RUN apk add bzip2-dev make wget @@ -15,15 +20,6 @@ RUN cd /tmp && \ make install && \ rm -r /tmp/pbzip2-1.1.13/ -FROM docker.elastic.co/wolfi/python:3.12.3-dev -ARG RALLY_VERSION -ARG RALLY_LICENSE - -ENV RALLY_RUNNING_IN_DOCKER=True - -USER root -COPY --from=builder /usr/bin/ /usr/bin/ - RUN addgroup --gid 1000 rally && \ adduser --system --home /rally --ingroup rally --no-create-home --uid 1000 --shell /bin/bash rally diff --git a/docker/Dockerfiles/Dockerfile-release b/docker/Dockerfiles/release/Dockerfile similarity index 91% rename from docker/Dockerfiles/Dockerfile-release rename to docker/Dockerfiles/release/Dockerfile index ff6be8f1c..ef14479a3 100644 --- a/docker/Dockerfiles/Dockerfile-release +++ b/docker/Dockerfiles/release/Dockerfile @@ -1,9 +1,13 @@ FROM docker.elastic.co/wolfi/python:3.12.3-dev AS builder +ARG RALLY_VERSION +ARG RALLY_LICENSE + +ENV RALLY_RUNNING_IN_DOCKER=True USER root RUN apk update -RUN apk add curl git gcc pigz bash zstd bzip2 gzip +RUN apk add curl git gcc pigz bash zstd bzip2 gzip openssh # pbzip2 doesn't have a package for wolfi, so we build it from source RUN apk add bzip2-dev make wget @@ -16,15 +20,6 @@ RUN cd /tmp && \ make install && \ rm -r /tmp/pbzip2-1.1.13/ -FROM docker.elastic.co/wolfi/python:3.12.3-dev -ARG RALLY_VERSION -ARG RALLY_LICENSE - -ENV RALLY_RUNNING_IN_DOCKER=True - -USER root -COPY --from=builder /usr/bin/ /usr/bin/ - RUN addgroup --gid 1000 rally && \ adduser --system --home /rally --ingroup rally --no-create-home --uid 1000 --shell /bin/bash rally diff --git a/docker/docker-compose-tests.yml b/docker/docker-compose-tests.yml index 758a1608f..8728b3a42 100644 --- a/docker/docker-compose-tests.yml +++ b/docker/docker-compose-tests.yml @@ -1,7 +1,7 @@ version: '2.2' services: rally: - image: elastic/rally:${RALLY_VERSION} + image: ${RALLY_DOCKER_IMAGE}:${RALLY_VERSION_TAG} container_name: rally command: ${TEST_COMMAND} volumes: diff --git a/it/__init__.py b/it/__init__.py index 9e6d5b4c8..3e7dcf835 100644 --- a/it/__init__.py +++ b/it/__init__.py @@ -250,7 +250,7 @@ def build_docker_image(): command = ( f"docker build -t elastic/rally:{rally_version} --build-arg RALLY_VERSION --build-arg RALLY_LICENSE " - f"-f {ROOT_DIR}/docker/Dockerfiles/Dockerfile-dev {ROOT_DIR}" + f"-f {ROOT_DIR}/docker/Dockerfiles/dev/Dockerfile {ROOT_DIR}" ) if process.run_subprocess_with_logging(command, env=env_variables) != 0: diff --git a/it/docker_dev_image_test.py b/it/docker_dev_image_test.py index 4830a33dd..adcefff89 100644 --- a/it/docker_dev_image_test.py +++ b/it/docker_dev_image_test.py @@ -59,10 +59,13 @@ def run_docker_compose_test(test_command): def run_docker_compose_up(test_command): env_variables = os.environ.copy() env_variables["TEST_COMMAND"] = test_command + env_variables["RALLY_DOCKER_IMAGE"] = "elastic/rally" env_variables["RALLY_VERSION"] = version.__version__ + env_variables["RALLY_VERSION_TAG"] = version.__version__ return process.run_subprocess_with_logging( - f"docker-compose -f {it.ROOT_DIR}/docker/docker-compose-tests.yml up --abort-on-container-exit", env=env_variables + f"docker-compose -f {it.ROOT_DIR}/docker/docker-compose-tests.yml up --abort-on-container-exit", + env=env_variables, ) diff --git a/release-docker-manifest.sh b/release-docker-manifest.sh new file mode 100755 index 000000000..b7019fdb3 --- /dev/null +++ b/release-docker-manifest.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash + +# Licensed to Elasticsearch B.V. under one or more contributor +# license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright +# ownership. Elasticsearch B.V. licenses this file to you under +# the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Prerequisites for releasing: + +# Logged in on Docker Hub (docker login) + +# fail this script immediately if any command fails with a non-zero exit code +set -eu + +function push_failed { + echo "Error while pushing Docker image. Did you \`docker login\`?" +} + +if [[ $# -eq 0 ]] ; then + echo "ERROR: $0 requires the Rally version to push as a command line argument and you didn't supply it." + echo "For example: $0 master true" + exit 1 +fi +export RALLY_VERSION=$1 +export PUSH_LATEST=$2 +export RALLY_LICENSE=$(awk 'FNR>=2 && FNR<=2' LICENSE | sed 's/^[ \t]*//') + +export GIT_SHA=$(git rev-parse --short HEAD) +export DATE=$(date +%Y%m%d) + +export RALLY_VERSION_TAG="${RALLY_VERSION}-${DATE}" +export DOCKER_TAG_VERSION="${RALLY_VERSION}" +export DOCKER_TAG_LATEST="latest" + +echo "========================================================" +echo "Pulling Docker images for Rally $RALLY_VERSION_TAG " +echo "========================================================" + +docker pull elastic/rally:${RALLY_VERSION_TAG}-amd64 +docker pull elastic/rally:${RALLY_VERSION_TAG}-arm64 + +echo "=======================================================" +echo "Creating Docker manifest image for Rally $RALLY_VERSION_TAG" +echo "=======================================================" + +docker manifest create elastic/rally:${RALLY_VERSION_TAG} \ + --amend elastic/rally:${RALLY_VERSION_TAG}-amd64 \ + --amend elastic/rally:${RALLY_VERSION_TAG}-arm64 + +trap push_failed ERR +echo "=======================================================" +echo "Publishing Docker image elastic/rally:$RALLY_VERSION_TAG" +echo "=======================================================" +docker manifest push elastic/rally:${RALLY_VERSION_TAG} +trap - ERR + +if [[ $PUSH_LATEST == "true" ]]; then + echo "=======================================================" + echo "Creating Docker manifest image for Rally $DOCKER_TAG_VERSION" + echo "=======================================================" + + docker manifest create elastic/rally:${DOCKER_TAG_VERSION} \ + --amend elastic/rally:${RALLY_VERSION_TAG}-amd64 \ + --amend elastic/rally:${RALLY_VERSION_TAG}-arm64 + + echo "=======================================================" + echo "Creating Docker manifest image for Rally $DOCKER_TAG_LATEST" + echo "=======================================================" + + docker manifest create elastic/rally:${DOCKER_TAG_LATEST} \ + --amend elastic/rally:${RALLY_VERSION_TAG}-amd64 \ + --amend elastic/rally:${RALLY_VERSION_TAG}-arm64 + + echo "=======================================================" + echo "Publishing Docker image elastic/rally:${DOCKER_TAG_LATEST}" + echo "=======================================================" + + trap push_failed ERR + docker manifest push elastic/rally:${DOCKER_TAG_VERSION} + docker manifest push elastic/rally:${DOCKER_TAG_LATEST} +fi + +trap - ERR + diff --git a/release-docker-test.sh b/release-docker-test.sh index 8b8965c40..6c04368ba 100755 --- a/release-docker-test.sh +++ b/release-docker-test.sh @@ -20,6 +20,7 @@ set -e readonly MIN_DOCKER_MEM_BYTES=$(expr 6 \* 1024 \* 1024 \* 1024) +readonly RALLY_DOCKER_IMAGE="${RALLY_DOCKER_IMAGE:-elastic/rally}" function check_prerequisites { exit_if_docker_not_running @@ -101,21 +102,25 @@ function test_docker_release_image { docker_compose down info "Testing Rally docker image uses the right version" - actual_version=$(docker run --rm elastic/rally:${RALLY_VERSION} esrally --version | cut -d ' ' -f 2,2) + if [[ "${DEVELOPMENT}" == "YES" ]]; then + actual_version=${RALLY_VERSION} + else + actual_version=$(docker run --rm ${RALLY_DOCKER_IMAGE}:${RALLY_VERSION_TAG} esrally --version | cut -d ' ' -f 2,2) + fi if [[ ${actual_version} != ${RALLY_VERSION} ]]; then echo "Rally version in Docker image: [${actual_version}] doesn't match the expected version [${RALLY_VERSION}]" exit 1 fi info "Testing Rally docker image version label is correct" - actual_version=$(docker inspect --format '{{ index .Config.Labels "org.label-schema.version"}}' elastic/rally:${RALLY_VERSION}) + actual_version=$(docker inspect --format '{{ index .Config.Labels "org.label-schema.version"}}' ${RALLY_DOCKER_IMAGE}:${RALLY_VERSION_TAG}) if [[ ${actual_version} != ${RALLY_VERSION} ]]; then echo "org.label-schema.version label in Rally Docker image: [${actual_version}] doesn't match the expected version [${RALLY_VERSION}]" exit 1 fi info "Testing Rally docker image license label is correct" - actual_license=$(docker inspect --format '{{ index .Config.Labels "license"}}' elastic/rally:${RALLY_VERSION}) + actual_license=$(docker inspect --format '{{ index .Config.Labels "license"}}' ${RALLY_DOCKER_IMAGE}:${RALLY_VERSION_TAG}) if [[ ${actual_license} != ${RALLY_LICENSE} ]]; then echo "license label in Rally Docker image: [${actual_license}] doesn't match the expected license [${RALLY_LICENSE}]" exit 1 @@ -159,4 +164,10 @@ function tear_down { trap "tear_down" EXIT +if [[ $# -gt 0 && $1 -eq "dev" ]] ; then + export DEVELOPMENT="YES" +else + export DEVELOPMENT="NO" +fi + main diff --git a/release-docker.sh b/release-docker.sh index afec4cd4e..59dadedc5 100755 --- a/release-docker.sh +++ b/release-docker.sh @@ -28,38 +28,47 @@ function push_failed { echo "Error while pushing Docker image. Did you \`docker login\`?" } -if [[ $# -eq 0 ]] ; then - echo "ERROR: $0 requires the Rally version to push as a command line argument and you didn't supply it." - echo "For example: $0 1.1.0" +if [[ $# -ne 3 ]] ; then + echo "ERROR: $0 requires the Rally version, architecture, and whether to update the \ + latest tag as command line arguments and you didn't supply them." + echo "For example: $0 1.1.0 amd64 true" exit 1 fi export RALLY_VERSION=$1 +export ARCH=$2 +export PUSH_LATEST=$3 export RALLY_LICENSE=$(awk 'FNR>=2 && FNR<=2' LICENSE | sed 's/^[ \t]*//') +export DATE=$(date +%Y%m%d) + +export RALLY_VERSION_TAG="${RALLY_VERSION}-${DATE}-${ARCH}" +export DOCKER_TAG_LATEST="latest-${ARCH}" echo "========================================================" -echo "Building Docker image for Rally release $RALLY_VERSION " +echo "Building Docker image Rally release $RALLY_VERSION_TAG " echo "========================================================" -docker build -t elastic/rally:${RALLY_VERSION} --build-arg RALLY_VERSION --build-arg RALLY_LICENSE -f docker/Dockerfiles/Dockerfile-release $PWD +docker build -t elastic/rally:${RALLY_VERSION_TAG} --build-arg RALLY_VERSION --build-arg RALLY_LICENSE -f docker/Dockerfiles/release/Dockerfile $PWD echo "=======================================================" -echo "Testing Docker image for Rally release $RALLY_VERSION " +echo "Testing Docker image Rally release $RALLY_VERSION_TAG " echo "=======================================================" -./release-docker-test.sh +RALLY_DOCKER_IMAGE="elastic/rally" ./release-docker-test.sh echo "=======================================================" -echo "Publishing Docker image elastic/rally:$RALLY_VERSION " +echo "Publishing Docker image elastic/rally:$RALLY_VERSION_TAG" echo "=======================================================" trap push_failed ERR -docker push elastic/rally:${RALLY_VERSION} +docker push elastic/rally:${RALLY_VERSION_TAG} -echo "============================================" -echo "Publishing Docker image elastic/rally:latest" -echo "============================================" +if [[ $PUSH_LATEST == "true" ]]; then + echo "============================================" + echo "Publishing Docker image elastic/rally:$DOCKER_TAG_LATEST" + echo "============================================" -docker tag elastic/rally:${RALLY_VERSION} elastic/rally:latest -docker push elastic/rally:latest + docker tag elastic/rally:${RALLY_VERSION_TAG} elastic/rally:${DOCKER_TAG_LATEST} + docker push elastic/rally:${DOCKER_TAG_LATEST} +fi trap - ERR