diff --git a/.azure-pipelines/release.yml b/.azure-pipelines/release.yml index 1689b968c..b00d4be78 100644 --- a/.azure-pipelines/release.yml +++ b/.azure-pipelines/release.yml @@ -12,4 +12,5 @@ stages: - template: templates/stages/deploy-stage.yml parameters: snapReleaseChannel: beta + dockerTag: ${{variables['Build.SourceBranchName']}} - template: templates/stages/notify-failure-stage.yml diff --git a/.azure-pipelines/templates/stages/deploy-stage.yml b/.azure-pipelines/templates/stages/deploy-stage.yml index 1e7bb2def..8fc1ff4c6 100644 --- a/.azure-pipelines/templates/stages/deploy-stage.yml +++ b/.azure-pipelines/templates/stages/deploy-stage.yml @@ -5,6 +5,9 @@ parameters: values: - edge - beta +- name: dockerTag + type: string + default: nightly stages: - stage: Deploy @@ -59,3 +62,26 @@ stages: snapcraft upload --release=${{ parameters.snapReleaseChannel }} "${SNAP_FILE}" done displayName: Publish to Snap store + - job: publish_docker + pool: + vmImage: ubuntu-18.04 + steps: + - task: Docker@2 + inputs: + command: login + # The credentials used here are for the shared certbotbot account + # on Docker Hub. The credentials are stored in a service account + # which was created by following the instructions at + # https://docs.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints?view=azure-devops&tabs=yaml#sep-docreg. + # The name given to this service account must match the value + # given to containerRegistry below. "Grant access to all + # pipelines" should also be checked. To revoke these + # credentials, we can change the password on the certbotbot + # Docker Hub account or remove the account from the + # Certbot organization on Docker Hub. + containerRegistry: docker-hub + displayName: Login to Docker Hub + - bash: tools/docker/build.sh ${{ parameters.dockerTag }} + displayName: Build the Docker images + - bash: tools/docker/deploy.sh ${{ parameters.dockerTag }} + displayName: Deploy the Docker images diff --git a/tools/docker/LICENSE.txt b/tools/docker/LICENSE.txt deleted file mode 100644 index 9c14e2b17..000000000 --- a/tools/docker/LICENSE.txt +++ /dev/null @@ -1,190 +0,0 @@ - Copyright 2019 Electronic Frontier Foundation and others - - Licensed 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. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS diff --git a/tools/docker/README.md b/tools/docker/README.md index f4b9c6de4..02e61be9c 100644 --- a/tools/docker/README.md +++ b/tools/docker/README.md @@ -7,74 +7,29 @@ Docker is an amazingly simple and quick way to obtain a certificate. However, th For more information, please read [Certbot - Running with Docker](https://certbot.eff.org/docs/install.html#running-with-docker). -Certbot-Docker project + +Certbot Docker Tools ====================== Goal ---- -This project is used to publish a new version of the official Certbot Docker and related Certbot DNS plugins Dockers on DockerHub upon release of a new version of Certbot. -It leverages the AutoBuild features of DockerHub to coordinate this publication through a continous integration/deployment approach. +This code is used to build and deploy new versions of the Certbot and Certbot +DNS plugin Docker images to Docker Hub. High-level behavior ------------------- -When a new version tag (eg. v0.35.0) is pushed to this repository, it triggers a new build in each DockerHub project, to construct and publish the new version of the Docker -containing the Certbot version corresponding to the pushed tag. For example, after following the instructions for v0.35.0 below, after a few minutes the DockerHub projects will contain a new tag "v0.35.0", -whose Docker contains Certbot v0.35.0. +Running `./build.sh && ./deploy.sh ` causes the Docker images to be +built and deployed to Docker Hub where `` is the base of the tag that +should be given to the given images. The tag should either be `nightly` or a +git version tag like `v0.34.0`. The given tag is only the base of the tag +because the CPU architecture is also added to the tag. Configuration ------------- -To set up the publication process, the target DockerHub project must be configured appropriately. There are two types of DockerHub projects to take into account: -* the Docker project for Certbot core features (eg. certbot/certbot) -* a Docker project for Certbot DNS plugins (eg. certbot/dns-rfc2136) +To run these scripts you need: -1) Define a GitHub user with push rights to the current GIT repository. -2) Create the DockerHub project if necessary. -3) Activate the AutoBuild feature, using the current GIT repository as source (eg. https://github.com/certbot-docker/certbot-docker.git) and the user defined in 1). -4) Define a unique tag build rule in AutoBuild configuration: - - _For a Certbot core Docker_ -> Source: `/^(v[0-9.]+).*$/`, Tag: `{\1}`, Dockerfile: `Dockerfile`, Build context: `/core` - - _For a Certbot DNS plugin Docker_ -> Source: `/^(v[0-9.]+).*$/`, Tag: `{\1}`, Dockerfile: `Dockerfile`, Build context: `/plugin` - -Publication worfklow -------------------- - -Assuming the version to publish is `v0.35.0` - -1) Clone this repository locally, check out branch `master`, and ensure the workspace is clean. -2) (Optional) Execute `./build.sh v0.35.0` to test the Docker builds. -3) Execute `./deploy.sh v0.35.0` to trigger the publication of all Dockers with version `v0.35.0`. - -Scripts usage -------------- - -``` -./build.sh [VERSION] -``` - -This script will locally build all Dockers for the given version using the same runtime as DockerHub. -This can be used to test the build process before invoking the actual publication workflow. - -``` -./deploy.sh [VERSION] -``` - -This script will trigger the publication of all Dockers for the given version to DockerHub. To do so, this script will: -- update the relevant `README.md` files that will be used as descriptions in the DockerHub repositories, -- locally commit the modifications, -- tag this commit with the given version, -- push this tag and the updated `master` branch. - -Assuming the version to publish is `v0.35.0`, the following docker images will be created at DockerHub. - -- certbot/certbot:v0.35.0 *(amd64 architecture)* -- certbot/certbot:amd64-v0.35.0 -- certbot/certbot:arm32v6-v0.35.0 -- certbot/certbot:arm64v8-v0.35.0 -- certbot/certbot:latest *(amd64 architecture)* -- certbot/certbot:amd64-latest -- certbot/certbot:arm32v6-latest -- certbot/certbot:arm64v8-latest +1. An x86_64 machine with Docker installed and the Docker daemon running. You probably don't want to use the docker snap as these scripts have failed when using that in the past. +2. To be logged into Docker Hub with an account able to push to the Certbot and Certbot DNS Docker images on Docker Hub. diff --git a/tools/docker/build.sh b/tools/docker/build.sh index 765aa79c5..79617ca84 100755 --- a/tools/docker/build.sh +++ b/tools/docker/build.sh @@ -1,63 +1,63 @@ #!/bin/bash -set -euo pipefail +set -euxo pipefail IFS=$'\n\t' -# This script builds certbot docker and certbot dns plugins docker against a given release version of certbot. -# The build is done following the environment used by Dockerhub to handle its autobuild feature, and so can be -# used as a pre-deployment validation test. +# This script builds certbot docker and certbot dns plugins docker using the +# local Certbot files. The build is currently done following the environment used by +# Dockerhub since this code previously used Docker Hub's automated build feature. -# Usage: ./build.sh [VERSION] -# with [VERSION] corresponding to a released version of certbot, like `v0.34.0` +# Usage: ./build.sh [TAG] +# with [TAG] corresponding the base of the tag to give the Docker images. +# Values should be something like `v0.34.0` or `nightly`. The given value is +# only the base of the tag because the things like the CPU architecture are +# also added to the full tag. -trap Cleanup 1 2 3 6 +# As of writing this, runs of this script consistently fail in Azure +# Pipelines, but they are fixed by using Docker BuildKit. A log of the failures +# that were occurring can be seen at +# https://gist.github.com/2227a05622299ce17bff9b0da714a1ff. Since using +# BuildKit is supposed to offer benefits anyway (see +# https://docs.docker.com/develop/develop-images/build_enhancements/ for more +# information), let's use it. +# +# This variable is set inside the script itself rather than in something like +# the CI config to have a consistent experience when this script is run +# locally. +export DOCKER_BUILDKIT=1 + +WORK_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +REPO_ROOT="$(dirname "$(dirname "${WORK_DIR}")")" +source "$WORK_DIR/lib/common" + +trap Cleanup EXIT Cleanup() { - if [ ! -z "$WORK_DIR" ]; then - rm -rf "$WORK_DIR"/core/qemu-*-static || true - rm -rf "$WORK_DIR"/plugin/qemu-*-static || true - fi - popd 2> /dev/null || true + rm -rf "$REPO_ROOT"/qemu-*-static || true + for plugin in "${CERTBOT_PLUGINS[@]}"; do + rm -rf "$REPO_ROOT/certbot-$plugin"/qemu-*-static || true + done } Build() { DOCKER_REPO="$1" - CERTBOT_VERSION="$2" + TAG_BASE="$2" CONTEXT_PATH="$3" - DOCKERFILE_PATH="$CONTEXT_PATH/Dockerfile" - DOCKER_TAG="$CERTBOT_VERSION" + DOCKERFILE_DIR="$4" + DOCKERFILE_PATH="$DOCKERFILE_DIR/Dockerfile" pushd "$CONTEXT_PATH" - DOCKER_TAG="$DOCKER_TAG" DOCKER_REPO="$DOCKER_REPO" DOCKERFILE_PATH="$DOCKERFILE_PATH" bash hooks/pre_build - DOCKER_TAG="$DOCKER_TAG" DOCKER_REPO="$DOCKER_REPO" DOCKERFILE_PATH="$DOCKERFILE_PATH" bash hooks/build + DOCKER_TAG="$TAG_BASE" DOCKER_REPO="$DOCKER_REPO" DOCKERFILE_PATH="$DOCKERFILE_PATH" bash "$DOCKERFILE_DIR/hooks/pre_build" + DOCKER_TAG="$TAG_BASE" DOCKER_REPO="$DOCKER_REPO" DOCKERFILE_PATH="$DOCKERFILE_PATH" bash "$DOCKERFILE_DIR/hooks/build" popd } -WORK_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" - -CERTBOT_VERSION="$1" +TAG_BASE="$1" # Step 1: Certbot core Docker -Build "certbot/certbot" "$CERTBOT_VERSION" "$WORK_DIR/core" +Build "$DOCKER_HUB_ORG/certbot" "$TAG_BASE" "$REPO_ROOT" "$WORK_DIR/core" -# Step 2: Certbot dns plugins Dockers -CERTBOT_PLUGINS_DOCKER_REPOS=( - "certbot/dns-dnsmadeeasy" - "certbot/dns-dnsimple" - "certbot/dns-ovh" - "certbot/dns-cloudflare" - "certbot/dns-cloudxns" - "certbot/dns-digitalocean" - "certbot/dns-google" - "certbot/dns-luadns" - "certbot/dns-nsone" - "certbot/dns-rfc2136" - "certbot/dns-route53" - "certbot/dns-gehirn" - "certbot/dns-linode" - "certbot/dns-sakuracloud" -) - -for DOCKER_REPO in "${CERTBOT_PLUGINS_DOCKER_REPOS[@]}"; do - Build "${DOCKER_REPO}" "$CERTBOT_VERSION" "$WORK_DIR/plugin" +# Step 2: Certbot DNS plugins Docker images +for plugin in "${CERTBOT_PLUGINS[@]}"; do + Build "$DOCKER_HUB_ORG/$plugin" "$TAG_BASE" "$REPO_ROOT/certbot-$plugin" "$WORK_DIR/plugin" done Cleanup diff --git a/tools/docker/core/.gitignore b/tools/docker/core/.gitignore deleted file mode 100644 index 4cc493afa..000000000 --- a/tools/docker/core/.gitignore +++ /dev/null @@ -1 +0,0 @@ -qemu-*-static diff --git a/tools/docker/core/Dockerfile b/tools/docker/core/Dockerfile index a0dfb1c51..ff8c6386c 100644 --- a/tools/docker/core/Dockerfile +++ b/tools/docker/core/Dockerfile @@ -7,25 +7,18 @@ ARG QEMU_ARCH ENV QEMU_ARCH=${QEMU_ARCH} COPY qemu-${QEMU_ARCH}-static /usr/bin/ -ARG CERTBOT_VERSION -ENV CERTBOT_VERSION=${CERTBOT_VERSION} - ENTRYPOINT [ "certbot" ] EXPOSE 80 443 VOLUME /etc/letsencrypt /var/lib/letsencrypt WORKDIR /opt/certbot -# Retrieve certbot code -RUN mkdir -p src \ - && wget -O certbot-${CERTBOT_VERSION}.tar.gz https://github.com/certbot/certbot/archive/v${CERTBOT_VERSION}.tar.gz \ - && tar xf certbot-${CERTBOT_VERSION}.tar.gz \ - && cp certbot-${CERTBOT_VERSION}/CHANGELOG.md certbot-${CERTBOT_VERSION}/README.rst src/ \ - && cp certbot-${CERTBOT_VERSION}/letsencrypt-auto-source/pieces/dependency-requirements.txt . \ - && cp certbot-${CERTBOT_VERSION}/letsencrypt-auto-source/pieces/pipstrap.py . \ - && cp -r certbot-${CERTBOT_VERSION}/tools tools \ - && cp -r certbot-${CERTBOT_VERSION}/acme src/acme \ - && cp -r certbot-${CERTBOT_VERSION}/certbot src/certbot \ - && rm -rf certbot-${CERTBOT_VERSION}.tar.gz certbot-${CERTBOT_VERSION} +# Copy certbot code +COPY CHANGELOG.md README.rst src/ +COPY letsencrypt-auto-source/pieces/dependency-requirements.txt . +COPY letsencrypt-auto-source/pieces/pipstrap.py . +COPY tools tools +COPY acme src/acme +COPY certbot src/certbot # Generate constraints file to pin dependency versions RUN cat dependency-requirements.txt | tools/strip_hashes.py > unhashed_requirements.txt \ diff --git a/tools/docker/core/README.md b/tools/docker/core/README.md deleted file mode 100644 index 9267b8cc4..000000000 --- a/tools/docker/core/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# ![](https://certbot.eff.org/images/certbot-logo-1A.svg) -[![](https://img.shields.io/badge/current-v1.7.0-blue.svg)](https://github.com/certbot/certbot.git)   [![](https://travis-ci.com/certbot/certbot.svg?branch=1.7.x)](https://travis-ci.com/certbot/certbot) - -This is the Docker repository for Certbot Core. - -## Certbot DNS plugins - -* [dns-dnsmadeeasy](https://hub.docker.com/r/certbot/dns-dnsmadeeasy) -* [dns-dnsimple](https://hub.docker.com/r/certbot/dns-dnsimple) -* [dns-ovh](https://hub.docker.com/r/certbot/dns-ovh) -* [dns-cloudflare](https://hub.docker.com/r/certbot/dns-cloudflare) -* [dns-cloudxns](https://hub.docker.com/r/certbot/dns-cloudxns) -* [dns-digitalocean](https://hub.docker.com/r/certbot/dns-digitalocean) -* [dns-google](https://hub.docker.com/r/certbot/dns-google) -* [dns-luadns](https://hub.docker.com/r/certbot/dns-luadns) -* [dns-nsone](https://hub.docker.com/r/certbot/dns-nsone) -* [dns-rfc2136](https://hub.docker.com/r/certbot/dns-rfc2136) -* [dns-route53](https://hub.docker.com/r/certbot/dns-route53) -* [dns-gehirn](https://hub.docker.com/r/certbot/dns-gehirn) -* [dns-linode](https://hub.docker.com/r/certbot/dns-linode) -* [dns-sakuracloud](https://hub.docker.com/r/certbot/dns-sakuracloud) - -## Sources: - -* [docker](https://www.github.com/certbot-docker/certbot-docker.git) -* [certbot](https://www.github.com/certbot/certbot.git) diff --git a/tools/docker/core/hooks/build b/tools/docker/core/hooks/build index 9f3f035d9..4925dc269 100644 --- a/tools/docker/core/hooks/build +++ b/tools/docker/core/hooks/build @@ -4,8 +4,6 @@ set -ex WORK_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" source "$WORK_DIR/../../lib/common" -CERTBOT_VERSION=$(GetCerbotVersionFromTag "$DOCKER_TAG") - for TARGET_ARCH in "${ALL_TARGET_ARCH[@]}"; do - BuildDockerCoreImage "${TARGET_ARCH}" "${CERTBOT_VERSION}" + BuildDockerCoreImage "${TARGET_ARCH}" done diff --git a/tools/docker/core/hooks/post_push b/tools/docker/core/hooks/post_push index 6bac191fd..bc700783e 100644 --- a/tools/docker/core/hooks/post_push +++ b/tools/docker/core/hooks/post_push @@ -4,9 +4,7 @@ set -ex WORK_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" source "$WORK_DIR/../../lib/common" -CERTBOT_VERSION=$(GetCerbotVersionFromTag "$DOCKER_TAG") - for TARGET_ARCH in "${ALL_TARGET_ARCH[@]}"; do - TagDockerImageAliases "${TARGET_ARCH}" "${CERTBOT_VERSION}" - PushDockerImageAliases "${TARGET_ARCH}" "${CERTBOT_VERSION}" + TagDockerImageAliases "${TARGET_ARCH}" + PushDockerImageAliases "${TARGET_ARCH}" done diff --git a/tools/docker/core/hooks/push b/tools/docker/core/hooks/push index 4dc5ea080..0102c5d4d 100644 --- a/tools/docker/core/hooks/push +++ b/tools/docker/core/hooks/push @@ -4,8 +4,6 @@ set -ex WORK_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" source "$WORK_DIR/../../lib/common" -CERTBOT_VERSION=$(GetCerbotVersionFromTag "$DOCKER_TAG") - for TARGET_ARCH in "${ALL_TARGET_ARCH[@]}"; do - PushDockerImage "${TARGET_ARCH}" "${CERTBOT_VERSION}" + PushDockerImage "${TARGET_ARCH}" done diff --git a/tools/docker/deploy.sh b/tools/docker/deploy.sh index 9ff4f52e5..89802f264 100755 --- a/tools/docker/deploy.sh +++ b/tools/docker/deploy.sh @@ -1,35 +1,35 @@ #!/bin/bash -set -euo pipefail +set -euxo pipefail IFS=$'\n\t' -# This script deploys a new version of certbot dockers (core+plugins) regarding a released version of Certbot. -# The README.md is updated to include the reference of this new version, and a tag version is pushed to the -# Certbot Docker repository, triggering the DockerHub autobuild feature that will take care of the release. +# This script deploys new versions of Certbot and Certbot plugin docker images. +# This process is currently done using a similar approach to Docker Hub since +# this code previously used Docker Hub's automated build feature. -# Usage: ./deploy.sh [VERSION] -# with [VERSION] corresponding to a released version of certbot, like `v0.34.0` - -trap Cleanup 1 2 3 6 - -Cleanup() { - popd 2> /dev/null || true -} +# Usage: ./deploy.sh [TAG] +# with [TAG] corresponding the base of the tag to give the Docker images. +# Values should be something like `v0.34.0` or `nightly`. The given value is +# only the base of the tag because the things like the CPU architecture are +# also added to the full tag. WORK_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" -CERTBOT_DOCKER_VERSION="$1" # Eg. v0.35.0 or v0.35.0-1 -CERTBOT_VERSION=$(sed -E -e 's|(v[0-9+]\.[0-9]+\.[0-9]+).*|\1|g' <<< "$CERTBOT_DOCKER_VERSION") # Eg. v0.35.0 -BRANCH_NAME=$(sed -E -e 's|v(.*)\.[0-9]+|\1.x|g' <<< "$CERTBOT_VERSION") # Eg. 0.35.x +Deploy() { + DOCKER_REPO="$1" + TAG_BASE="$2" + DOCKERFILE_DIR="$3" + DOCKERFILE_PATH="$DOCKERFILE_DIR/Dockerfile" + DOCKER_TAG="$TAG_BASE" DOCKER_REPO="$DOCKER_REPO" DOCKERFILE_PATH="$DOCKERFILE_PATH" bash "$DOCKERFILE_DIR/hooks/push" + DOCKER_TAG="$TAG_BASE" DOCKER_REPO="$DOCKER_REPO" DOCKERFILE_PATH="$DOCKERFILE_PATH" bash "$DOCKERFILE_DIR/hooks/post_push" +} -sed -i -e "s|current-.*-blue\\.svg|current-$CERTBOT_VERSION-blue.svg|g" core/README.md -sed -i -e "s|branch=.*)\\]|branch=$BRANCH_NAME)]|g" core/README.md +TAG_BASE="$1" # Eg. v0.35.0 or nightly +source "$WORK_DIR/lib/common" -sed -i -e "s|current-.*-blue\\.svg|current-$CERTBOT_VERSION-blue.svg|g" plugin/README.md -sed -i -e "s|branch=.*)\\]|branch=$BRANCH_NAME)]|g" plugin/README.md +# Step 1: Certbot core Docker +Deploy "$DOCKER_HUB_ORG/certbot" "$TAG_BASE" "$WORK_DIR/core" -pushd "$WORK_DIR" - git commit -a -m "Release version $CERTBOT_DOCKER_VERSION" --allow-empty - git tag "$CERTBOT_DOCKER_VERSION" - git push - git push --tags -popd +# Step 2: Certbot DNS plugins Docker images +for plugin in "${CERTBOT_PLUGINS[@]}"; do + Deploy "$DOCKER_HUB_ORG/$plugin" "$TAG_BASE" "$WORK_DIR/plugin" +done diff --git a/tools/docker/lib/common b/tools/docker/lib/common index 35f473603..0654da54b 100644 --- a/tools/docker/lib/common +++ b/tools/docker/lib/common @@ -4,15 +4,33 @@ set -ex # Current supported architectures export ALL_TARGET_ARCH=(amd64 arm32v6 arm64v8) -# Architecture used in tags with no architecture especified (certbot/certbot:latest, certbot/cerbot:v0.35.0, ...) +# Architecture used in tags with no architecture specified (certbot/certbot:latest, certbot/certbot:v0.35.0, ...) export DEFAULT_ARCH=amd64 -# Returns certbot version (ex. v0.35.0 returns 0.35.0) -# Usage: GetCerbotVersionFromTag -GetCerbotVersionFromTag() { - TAG=$1 - echo "${TAG//v/}" -} +# Name of the Certbot Docker organizaation on GitHub. After creating +# repositories with the same names (e.g. "certbot", "dns-dnsmadeeasy", etc.) +# using a different account on Docker Hub, you can change this value to have +# the scripts modify those Docker repositories rather than the repositories for +# the official Certbot Docker images. +export DOCKER_HUB_ORG="certbot" + +# List of Certbot plugins +export CERTBOT_PLUGINS=( + "dns-dnsmadeeasy" + "dns-dnsimple" + "dns-ovh" + "dns-cloudflare" + "dns-cloudxns" + "dns-digitalocean" + "dns-google" + "dns-luadns" + "dns-nsone" + "dns-rfc2136" + "dns-route53" + "dns-gehirn" + "dns-linode" + "dns-sakuracloud" +) # Returns the translation from Docker to QEMU architecture # Usage: GetQemuArch [amd64|arm32v6|arm64v8] @@ -58,85 +76,85 @@ RegisterQemuHandlers() { docker run --rm --privileged multiarch/qemu-user-static:register --reset } -# Builds docker certbot core image for a specific architecture and certbot version (ex. 0.35.0). -# Usage: BuildDockerCoreImage [amd64|arm32v6|arm64v8] +# Builds docker certbot core image for a specific architecture. +# Usage: BuildDockerCoreImage [amd64|arm32v6|arm64v8] BuildDockerCoreImage() { ARCH=$1 - VERSION=$2 QEMU=$(GetQemuArch "$ARCH") docker build \ - --build-arg CERTBOT_VERSION="${VERSION}" \ --build-arg TARGET_ARCH="${ARCH}" \ --build-arg QEMU_ARCH="${QEMU}" \ -f "${DOCKERFILE_PATH}" \ - -t "${DOCKER_REPO}:${ARCH}-v${VERSION}" \ + -t "${DOCKER_REPO}:${ARCH}-${DOCKER_TAG}" \ . } -# Builds docker certbot plugin image for a specific architecture and certbot version (ex. 0.35.0). -# Usage: BuildDockerPluginImage [amd64|arm32v6|arm64v8] +# Builds docker certbot plugin image for a specific architecture and tag. +# Usage: BuildDockerPluginImage [amd64|arm32v6|arm64v8] BuildDockerPluginImage() { ARCH=$1 - VERSION=$2 - PLUGIN=$3 QEMU=$(GetQemuArch "$ARCH") + BASE_IMAGE="${DOCKER_HUB_ORG}/certbot:${TARGET_ARCH}-${DOCKER_TAG}" docker build \ - --build-arg CERTBOT_VERSION="${VERSION}" \ - --build-arg TARGET_ARCH="${ARCH}" \ + --build-arg BASE_IMAGE="${BASE_IMAGE}" \ --build-arg QEMU_ARCH="${QEMU}" \ - --build-arg PLUGIN_NAME="${PLUGIN}" \ -f "${DOCKERFILE_PATH}" \ - -t "${DOCKER_REPO}:${ARCH}-v${VERSION}" \ + -t "${DOCKER_REPO}:${ARCH}-${DOCKER_TAG}" \ . } -# Pushes docker image for a specific architecture and certbot version (ex. 0.35.0). -# Usage: BuildDockerCoreImage [amd64|arm32v6|arm64v8] +# Pushes docker image for a specific architecture. +# Usage: BuildDockerCoreImage [amd64|arm32v6|arm64v8] PushDockerImage() { ARCH=$1 - VERSION=$2 - docker push "${DOCKER_REPO}:${ARCH}-v${VERSION}" + docker push "${DOCKER_REPO}:${ARCH}-${DOCKER_TAG}" } -# Creates docker image "latest" tag for a specific architecture and certbot version. -# In case of default architecture, it also creates tags without architecture part. -# As an example, for version 0.35.0 in amd64 (default arquitecture): +# Creates any docker images aliases for a given architecture. +# If DOCKER_TAG tag is a version tag such as v0.35.0, the "latest" tag is also +# updated. In the case of the default architecture, tags without the +# architecture part are also created. +# As an example, for amd64 (the default architecture) and the tag v0.35.0, the +# following tags would be created: # - certbot/certbot:v0.35.0 # - certbot/certbot:latest # - certbot/certbot:amd64-latest -# For version 0.35.0 in arm32v6: +# For the architecture arm32v6 and the tag v0.35.0, only the following tag +# would be created: # - certbot/certbot:arm32v6-latest -# Usage: TagDockerImageAliases [amd64|arm32v6|arm64v8] +# For other tags such as "nightly", aliases are only created for the default +# architecture where the tag "nightly" would be used without an architecture +# part. +# Usage: TagDockerImageAliases [amd64|arm32v6|arm64v8] TagDockerImageAliases() { ARCH=$1 - VERSION=$2 - docker tag "${DOCKER_REPO}:${ARCH}-v${VERSION}" "${DOCKER_REPO}:${ARCH}-latest" + if [[ "${DOCKER_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + docker tag "${DOCKER_REPO}:${ARCH}-${DOCKER_TAG}" "${DOCKER_REPO}:${ARCH}-latest" + if [ "${ARCH}" == "${DEFAULT_ARCH}" ]; then + docker tag "${DOCKER_REPO}:${ARCH}-${DOCKER_TAG}" "${DOCKER_REPO}:latest" + fi + fi if [ "${ARCH}" == "${DEFAULT_ARCH}" ]; then - docker tag "${DOCKER_REPO}:${ARCH}-v${VERSION}" "${DOCKER_REPO}:v${VERSION}" - docker tag "${DOCKER_REPO}:${ARCH}-v${VERSION}" "${DOCKER_REPO}:latest" + docker tag "${DOCKER_REPO}:${ARCH}-${DOCKER_TAG}" "${DOCKER_REPO}:${DOCKER_TAG}" fi } -# Pushes docker "latest" image for a specific architecture and certbot version. -# In case of default architecture, it also pushes image without architecture part. -# As an example, for version 0.35.0 in amd64 (default arquitecture): -# - certbot/certbot:v0.35.0 -# - certbot/certbot:latest -# - certbot/certbot:amd64-latest -# For version 0.35.0 in arm32v6: -# - certbot/certbot:arm32v6-latest -# Usage: PushDockerImageAliases [amd64|arm32v6|arm64v8] +# Pushes docker images aliases created by the TagDockerImageAliases function. +# Usage: PushDockerImageAliases [amd64|arm32v6|arm64v8] PushDockerImageAliases() { ARCH=$1 - VERSION=$2 - docker push "${DOCKER_REPO}:${ARCH}-latest" + if [[ "${DOCKER_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + docker push "${DOCKER_REPO}:${ARCH}-latest" + if [ "${ARCH}" == "${DEFAULT_ARCH}" ]; then + docker push "${DOCKER_REPO}:latest" + fi + fi if [ "${ARCH}" == "${DEFAULT_ARCH}" ]; then - docker push "${DOCKER_REPO}:v${VERSION}" - docker push "${DOCKER_REPO}:latest" + docker push "${DOCKER_REPO}:${DOCKER_TAG}" fi } diff --git a/tools/docker/plugin/.gitignore b/tools/docker/plugin/.gitignore deleted file mode 100644 index 4cc493afa..000000000 --- a/tools/docker/plugin/.gitignore +++ /dev/null @@ -1 +0,0 @@ -qemu-*-static diff --git a/tools/docker/plugin/Dockerfile b/tools/docker/plugin/Dockerfile index 9369ba0d3..6bbbae7c1 100644 --- a/tools/docker/plugin/Dockerfile +++ b/tools/docker/plugin/Dockerfile @@ -1,20 +1,14 @@ -# Docker Arch (amd64, arm32v6, ...) -ARG TARGET_ARCH -ARG CERTBOT_VERSION -FROM certbot/certbot:${TARGET_ARCH}-v${CERTBOT_VERSION} +# Certbot image to build on (e.g. certbot/certbot:amd64-v0.35.0) +ARG BASE_IMAGE +FROM ${BASE_IMAGE} # Qemu Arch (x86_64, arm, ...) ARG QEMU_ARCH ENV QEMU_ARCH=${QEMU_ARCH} COPY qemu-${QEMU_ARCH}-static /usr/bin/ -ARG PLUGIN_NAME - -# Retrieve Certbot DNS plugin code -RUN wget -O certbot-${CERTBOT_VERSION}.tar.gz https://github.com/certbot/certbot/archive/v${CERTBOT_VERSION}.tar.gz \ - && tar xf certbot-${CERTBOT_VERSION}.tar.gz \ - && cp -r certbot-${CERTBOT_VERSION}/certbot-${PLUGIN_NAME} /opt/certbot/src/certbot-${PLUGIN_NAME} \ - && rm -rf certbot-${CERTBOT_VERSION}.tar.gz certbot-${CERTBOT_VERSION} +# Copy Certbot DNS plugin code +COPY . /opt/certbot/src/plugin # Install the DNS plugin -RUN pip install --constraint /opt/certbot/docker_constraints.txt --no-cache-dir --editable /opt/certbot/src/certbot-${PLUGIN_NAME} +RUN pip install --constraint /opt/certbot/docker_constraints.txt --no-cache-dir --editable /opt/certbot/src/plugin diff --git a/tools/docker/plugin/README.md b/tools/docker/plugin/README.md deleted file mode 100644 index 446be8da8..000000000 --- a/tools/docker/plugin/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# ![](https://certbot.eff.org/images/certbot-logo-1A.svg) -[![](https://img.shields.io/badge/current-v1.7.0-blue.svg)](https://github.com/certbot/certbot.git)   [![](https://travis-ci.com/certbot/certbot.svg?branch=1.7.x)](https://travis-ci.com/certbot/certbot) - -This is one of the Docker repository for the Certbot DNS plugins. - -## Certbot Core - -* [certbot](https://hub.docker.com/r/certbot/certbot) - -## Sources: - -* [docker](https://www.github.com/certbot-docker/certbot-docker.git) -* [certbot](https://www.github.com/certbot/certbot.git) diff --git a/tools/docker/plugin/hooks/build b/tools/docker/plugin/hooks/build index 4545bbb3a..684be6951 100644 --- a/tools/docker/plugin/hooks/build +++ b/tools/docker/plugin/hooks/build @@ -4,9 +4,6 @@ set -ex WORK_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" source "$WORK_DIR/../../lib/common" -CERTBOT_VERSION=$(GetCerbotVersionFromTag "$DOCKER_TAG") -PLUGIN_NAME=${DOCKER_REPO//*\//} - for TARGET_ARCH in "${ALL_TARGET_ARCH[@]}"; do - BuildDockerPluginImage "${TARGET_ARCH}" "${CERTBOT_VERSION}" "${PLUGIN_NAME}" + BuildDockerPluginImage "${TARGET_ARCH}" done diff --git a/tools/docker/plugin/hooks/post_push b/tools/docker/plugin/hooks/post_push index 6bac191fd..bc700783e 100644 --- a/tools/docker/plugin/hooks/post_push +++ b/tools/docker/plugin/hooks/post_push @@ -4,9 +4,7 @@ set -ex WORK_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" source "$WORK_DIR/../../lib/common" -CERTBOT_VERSION=$(GetCerbotVersionFromTag "$DOCKER_TAG") - for TARGET_ARCH in "${ALL_TARGET_ARCH[@]}"; do - TagDockerImageAliases "${TARGET_ARCH}" "${CERTBOT_VERSION}" - PushDockerImageAliases "${TARGET_ARCH}" "${CERTBOT_VERSION}" + TagDockerImageAliases "${TARGET_ARCH}" + PushDockerImageAliases "${TARGET_ARCH}" done diff --git a/tools/docker/plugin/hooks/push b/tools/docker/plugin/hooks/push index 4dc5ea080..0102c5d4d 100644 --- a/tools/docker/plugin/hooks/push +++ b/tools/docker/plugin/hooks/push @@ -4,8 +4,6 @@ set -ex WORK_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" source "$WORK_DIR/../../lib/common" -CERTBOT_VERSION=$(GetCerbotVersionFromTag "$DOCKER_TAG") - for TARGET_ARCH in "${ALL_TARGET_ARCH[@]}"; do - PushDockerImage "${TARGET_ARCH}" "${CERTBOT_VERSION}" + PushDockerImage "${TARGET_ARCH}" done