diff --git a/scripts/docker-release/Dockerfile-release b/scripts/docker-release/Dockerfile-release index f1600df77..4545d0a96 100644 --- a/scripts/docker-release/Dockerfile-release +++ b/scripts/docker-release/Dockerfile-release @@ -34,4 +34,6 @@ RUN echo Building image for Terraform ${TERRAFORM_VERSION} && \ unzip terraform_${TERRAFORM_VERSION}_linux_amd64.zip -d /bin && \ rm -f terraform_${TERRAFORM_VERSION}_linux_amd64.zip terraform_${TERRAFORM_VERSION}_SHA256SUMS* +LABEL "com.hashicorp.terraform.version"="${TERRAFORM_VERSION}" + ENTRYPOINT ["/bin/terraform"] diff --git a/scripts/docker-release/README.md b/scripts/docker-release/README.md index 2224aa6da..afcdfe4b6 100644 --- a/scripts/docker-release/README.md +++ b/scripts/docker-release/README.md @@ -1,37 +1,77 @@ # Terraform Docker Release Build -This directory contains configuration to drive the Dockerhub automated build -for Terraform. This is different than the root Dockerfile (which produces -the "full" image on Dockerhub) because it uses the release archives from -releases.hashicorp.com. It is therefore not possible to use this configuration -to build an image for a commit that hasn't been released. +This directory contains configuration to drive the docker image releases for +Terraform. -## How it works +Two different types of image are produced for each Terraform release: -Dockerhub runs the `hooks/build` script to trigger the build. That uses -`git describe` to identify the tag corresponding to the current `HEAD`. If -the current commit _isn't_ tagged with a version number corresponding to -a Terraform release already on releases.hashicorp.com, the build will fail. +* A "light" image that includes just the release binary that should match + what's on releases.hashicorp.com. -## What it produces +* A "full" image that contains all of the Terraform source code and a binary + built from that source. -This configuration is used to produce the "latest", "light", and "beta" -tags in Dockerhub, as well as specific version tags. +The latter can be produced for any arbitrary commit by running `docker build` +in the root of this repository. The former requires that the release archive +already be deployed on releases.hashicorp.com. -* "latest" and "light" are synonyms, and are built from a branch in this -repository called "stable". -* "beta" is built from a branch called "beta". +## Build and Release -All of these branches should be updated only to _tagged_ commits, and only when -it is desirable to create a new release image. +The scripts in this directory are intended for running the steps to build, +tag, and push the two images for a tagged and released version of Terraform. +They expect to be run with git `HEAD` pointed at a release tag, whose name +is used to determine the version to build. The version number indicated +by the tag that `HEAD` is pointed at will be referred to below as +the _current version_. -## The `full` and `master` images image +* `build.sh` builds locally both of the images for the current version. + This operates on the local docker daemon only, and produces tags that + include the current version number. -This configuration does not produce the "full" image. That is instead produced -by the `Dockerfile` in the repository root, driven by updates to the "stable" -branch. +* `tag.sh` updates the `latest`, `light` and `full` tags to refer to the + images for the current version, which must've been already produced by + an earlier run of `build.sh`. This operates on the local docker daemon + only. -The "master" tag is updated for _every_ commit to the master branch of -the Terraform core repository. It is not recommended to use these images for -any production use, but they can be useful for testing bleeding-edge features -that are not yet included in a release. +* `push.sh` pushes the current version tag and the `latest`, `light` and + `full` tags up to dockerhub for public consumption. This writes images + to dockerhub, and so it requires docker credentials that have access to + write into the `hashicorp/terraform` repository. + +### Releasing a new "latest" version + +In the common case where a release is going to be considered the new latest +stable version of Terraform, the helper script `release.sh` orchestrates +all of the necessary steps to release to dockerhub: + +``` +$ git checkout v0.10.0 +$ scripts/docker-release/release.sh +``` + +Behind the scenes this script is running `build.sh`, `tag.sh` and `push.sh` +as described above, with some extra confirmation steps to verify the +correctness of the build. + +This script is interactive and so isn't suitable for running in automation. +For automation, run the individual scripts directly. + +### Releasing a beta version or a patch to an earlier minor release + +The `release.sh` wrapper is not appropriate in two less common situations: + +* The version being released is a beta or other pre-release version, with + a version number like `v0.10.0-beta1` or `v0.10.0-rc1`. + +* The version being released belongs to a non-current minor release. For + example, if the current stable version is `v0.10.1` but the version + being released is `v0.9.14`. + +In both of these cases, only the specific version tag should be updated, +which can be done as follows: + +``` +$ git checkout v0.11.0-beta1 +$ scripts/docker-release/build.sh +$ docker push hashicorp/terraform:0.11.0-beta1 +``` diff --git a/scripts/docker-release/build.sh b/scripts/docker-release/build.sh new file mode 100755 index 000000000..8442e8a68 --- /dev/null +++ b/scripts/docker-release/build.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +# This script builds two docker images for the version referred to by the +# current git HEAD. +# +# After running this, run tag.sh if the images that are built should be +# tagged as the "latest" release. + +set -eu + +BASE="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd "$BASE" + +if [ "$#" -eq 0 ]; then + # We assume that this is always running while git HEAD is pointed at a release + # tag or a branch that is pointed at the same commit as a release tag. If not, + # this will fail since we can't build a release image for a commit that hasn't + # actually been released. + VERSION="$(git describe)" +else + # This mode is here only to support release.sh, which ensures that the given + # version matches the current git tag. Running this script manually with + # an argument can't guarantee correct behavior since the "full" image + # will be built against the current work tree regardless of which version + # is selected. + VERSION="$1" +fi + +echo "-- Building release docker images for version $VERSION --" +echo "" +VERSION_SLUG="${VERSION#v}" + +docker build --no-cache "--build-arg=TERRAFORM_VERSION=${VERSION_SLUG}" -t hashicorp/terraform:${VERSION_SLUG} -f "Dockerfile-release" . +docker build --no-cache -t "hashicorp/terraform:${VERSION_SLUG}-full" ../../ diff --git a/scripts/docker-release/hooks/build b/scripts/docker-release/hooks/build deleted file mode 100755 index faed92fb2..000000000 --- a/scripts/docker-release/hooks/build +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -# This script assumes that its working directory is the parent directory, -# where the Dockerfile-release file is located, since that's how Dockerhub -# runs hooks. - -set -eu - -# We assume that this is always running while git HEAD is pointed at a release -# tag or a branch that is pointed at the same commit as a release tag. If not, -# this will fail since we can't build a release image for a commit that hasn't -# actually been released. -VERSION="$(git describe)" - -echo "Building release docker images for version $VERSION" -VERSION_SLUG="${VERSION#v}" - -docker build "--build-arg=TERRAFORM_VERSION=${VERSION_SLUG}" -t ${IMAGE_NAME} -f "Dockerfile-release" . diff --git a/scripts/docker-release/push.sh b/scripts/docker-release/push.sh new file mode 100755 index 000000000..e65cd61bc --- /dev/null +++ b/scripts/docker-release/push.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# This script pushes the docker images for the given version of Terraform, +# along with the "light", "full" and "latest" tags, up to docker hub. +# +# You must already be logged in to docker using "docker login" before running +# this script. + +set -eu + +VERSION="$1" +VERSION_SLUG="${VERSION#v}" + +echo "-- Pushing tags $VERSION_SLUG, light, full and latest up to dockerhub --" +echo "" + +docker push "hashicorp/terraform:$VERSION_SLUG" +docker push "hashicorp/terraform:light" +docker push "hashicorp/terraform:full" +docker push "hashicorp/terraform:latest" diff --git a/scripts/docker-release/release.sh b/scripts/docker-release/release.sh new file mode 100755 index 000000000..a297748df --- /dev/null +++ b/scripts/docker-release/release.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash + +# This script is an interactive wrapper around the scripts build.sh, tag.sh +# and push.sh intended for use during official Terraform releases. +# +# This script should be used only when git HEAD is pointing at the release tag +# for what will become the new latest *stable* release, since it will update +# the "latest", "light", and "full" tags to refer to what was built. +# +# To release a specific version without updating the various symbolic tags, +# use build.sh directly and then manually push the single release tag it +# creates. This is appropriate both when publishing a beta version and if, +# for some reason, it's necessary to (re-)publish and older version. + +set -eu + +BASE="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd "$BASE" + +# We assume that this is always running while git HEAD is pointed at a release +# tag or a branch that is pointed at the same commit as a release tag. If not, +# this will fail since we can't build a release image for a commit that hasn't +# actually been released. +VERSION="$(git describe)" +VERSION_SLUG="${VERSION#v}" + +# Verify that the version is already deployed to releases.hashicorp.com. +if curl --output /dev/null --silent --head --fail "https://releases.hashicorp.com/terraform/${VERSION_SLUG}/terraform_${VERSION_SLUG}_SHA256SUMS"; then + echo "===== Docker image release for Terraform $VERSION =====" + echo "" +else + cat >&2 <&2 Aborting due to inconsistent version output. + exit 1 +fi +echo "" + +# Update the latest, light and full tags to point to the images we just built. +./tag.sh "$VERSION" + +# Last chance to bail out +echo "-- Prepare to Push --" +echo "" +echo "The following Terraform images are available locally:" +docker images --format "{{.ID}}\t{{.Tag}}" hashicorp/terraform +echo "" +read -p "Ready to push the tags $VERSION_SLUG, light, full, and latest up to dockerhub? " -n 1 -r +echo "" +if ! [[ $REPLY =~ ^[Yy]$ ]]; then + echo >&2 "Aborting because reply wasn't positive." + exit 1 +fi +echo "" + +# Actually upload the images +./push.sh "$VERSION" + +echo "" +echo "-- All done! --" +echo "" +echo "Confirm the release at https://hub.docker.com/r/hashicorp/terraform/tags/" +echo "" diff --git a/scripts/docker-release/tag.sh b/scripts/docker-release/tag.sh new file mode 100755 index 000000000..88bd95f73 --- /dev/null +++ b/scripts/docker-release/tag.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +# This script tags the version number given on the command line as being +# the "latest" on the local system only. +# +# The following tags are updated: +# - light (from the tag named after the version number) +# - full (from the tag named after the version number with "-full" appended) +# - latest (as an alias of light) +# +# Before running this the build.sh script must be run to actually create the +# images that this script will tag. +# +# After tagging, use push.sh to push the images to dockerhub. + +set -eu + +VERSION="$1" +VERSION_SLUG="${VERSION#v}" + +echo "-- Updating tags to point to version $VERSION --" +echo "" + +docker tag "hashicorp/terraform:${VERSION_SLUG}" "hashicorp/terraform:light" +docker tag "hashicorp/terraform:${VERSION_SLUG}" "hashicorp/terraform:latest" +docker tag "hashicorp/terraform:${VERSION_SLUG}-full" "hashicorp/terraform:full"