push 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. #!/usr/bin/env bash
  2. # shellcheck source=arches.sh
  3. source ./hooks/arches.sh
  4. export DOCKER_CLI_EXPERIMENTAL=enabled
  5. # Join a list of args with a single char.
  6. # Ref: https://stackoverflow.com/a/17841619
  7. join() { local IFS="$1"; shift; echo "$*"; }
  8. set -ex
  9. echo ">>> Starting local Docker registry when needed..."
  10. # Docker Buildx's `docker-container` driver is needed for multi-platform
  11. # builds, but it can't access existing images on the Docker host (like the
  12. # cross-compiled ones we just built). Those images first need to be pushed to
  13. # a registry -- Docker Hub could be used, but since it's not trivial to clean
  14. # up those intermediate images on Docker Hub, it's easier to just run a local
  15. # Docker registry, which gets cleaned up automatically once the build job ends.
  16. #
  17. # https://docs.docker.com/registry/deploying/
  18. # https://hub.docker.com/_/registry
  19. #
  20. # Use host networking so the buildx container can access the registry via
  21. # localhost.
  22. #
  23. # First check if there already is a registry container running, else skip it.
  24. # This will only happen either locally or running it via Github Actions
  25. #
  26. if ! timeout 5 bash -c 'cat < /dev/null > /dev/tcp/localhost/5000'; then
  27. # defaults to port 5000
  28. docker run -d --name registry --network host registry:2
  29. fi
  30. # Docker Hub sets a `DOCKER_REPO` env var with the format `index.docker.io/user/repo`.
  31. # Strip the registry portion to construct a local repo path for use in `Dockerfile.buildx`.
  32. LOCAL_REGISTRY="localhost:5000"
  33. REPO="${DOCKER_REPO#*/}"
  34. LOCAL_REPO="${LOCAL_REGISTRY}/${REPO}"
  35. echo ">>> Pushing images to local registry..."
  36. for arch in "${arches[@]}"; do
  37. docker_image="${DOCKER_REPO}:${DOCKER_TAG}-${arch}"
  38. local_image="${LOCAL_REPO}:${DOCKER_TAG}-${arch}"
  39. docker tag "${docker_image}" "${local_image}"
  40. docker push "${local_image}"
  41. done
  42. echo ">>> Setting up Docker Buildx..."
  43. # Same as earlier, use host networking so the buildx container can access the
  44. # registry via localhost.
  45. #
  46. # Ref: https://github.com/docker/buildx/issues/94#issuecomment-534367714
  47. #
  48. # Check if there already is a builder running, else skip this and use the existing.
  49. # This will only happen either locally or running it via Github Actions
  50. #
  51. if ! docker buildx inspect builder > /dev/null 2>&1 ; then
  52. docker buildx create --name builder --use --driver-opt network=host
  53. fi
  54. echo ">>> Running Docker Buildx..."
  55. tags=("${DOCKER_REPO}:${DOCKER_TAG}")
  56. # If the Docker tag starts with a version number, assume the latest release
  57. # is being pushed. Add an extra tag (`latest` or `alpine`, as appropriate)
  58. # to make it easier for users to track the latest release.
  59. if [[ "${DOCKER_TAG}" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
  60. if [[ "${DOCKER_TAG}" == *alpine ]]; then
  61. tags+=("${DOCKER_REPO}:alpine")
  62. else
  63. tags+=("${DOCKER_REPO}:latest")
  64. fi
  65. fi
  66. tag_args=()
  67. for tag in "${tags[@]}"; do
  68. tag_args+=(--tag "${tag}")
  69. done
  70. # Docker Buildx takes a list of target platforms (OS/arch/variant), so map
  71. # the arch list to a platform list (assuming the OS is always `linux`).
  72. declare -A arch_to_platform=(
  73. [amd64]="linux/amd64"
  74. [armv6]="linux/arm/v6"
  75. [armv7]="linux/arm/v7"
  76. [arm64]="linux/arm64"
  77. )
  78. platforms=()
  79. for arch in "${arches[@]}"; do
  80. platforms+=("${arch_to_platform[$arch]}")
  81. done
  82. platform="$(join "," "${platforms[@]}")"
  83. # Run the build, pushing the resulting images and multi-arch manifest list to
  84. # Docker Hub. The Dockerfile is read from stdin to avoid sending any build
  85. # context, which isn't needed here since the actual cross-compiled images
  86. # have already been built.
  87. docker buildx build \
  88. --network host \
  89. --build-arg LOCAL_REPO="${LOCAL_REPO}" \
  90. --build-arg DOCKER_TAG="${DOCKER_TAG}" \
  91. --platform "${platform}" \
  92. "${tag_args[@]}" \
  93. --push \
  94. - < ./docker/Dockerfile.buildx