push 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #!/bin/bash
  2. source ./hooks/arches.sh
  3. export DOCKER_CLI_EXPERIMENTAL=enabled
  4. # Join a list of args with a single char.
  5. # Ref: https://stackoverflow.com/a/17841619
  6. join() { local IFS="$1"; shift; echo "$*"; }
  7. set -ex
  8. echo ">>> Starting local Docker registry..."
  9. # Docker Buildx's `docker-container` driver is needed for multi-platform
  10. # builds, but it can't access existing images on the Docker host (like the
  11. # cross-compiled ones we just built). Those images first need to be pushed to
  12. # a registry -- Docker Hub could be used, but since it's not trivial to clean
  13. # up those intermediate images on Docker Hub, it's easier to just run a local
  14. # Docker registry, which gets cleaned up automatically once the build job ends.
  15. #
  16. # https://docs.docker.com/registry/deploying/
  17. # https://hub.docker.com/_/registry
  18. #
  19. # Use host networking so the buildx container can access the registry via
  20. # localhost.
  21. #
  22. docker run -d --name registry --network host registry:2 # defaults to port 5000
  23. # Docker Hub sets a `DOCKER_REPO` env var with the format `index.docker.io/user/repo`.
  24. # Strip the registry portion to construct a local repo path for use in `Dockerfile.buildx`.
  25. LOCAL_REGISTRY="localhost:5000"
  26. REPO="${DOCKER_REPO#*/}"
  27. LOCAL_REPO="${LOCAL_REGISTRY}/${REPO}"
  28. echo ">>> Pushing images to local registry..."
  29. for arch in ${arches[@]}; do
  30. docker_image="${DOCKER_REPO}:${DOCKER_TAG}-${arch}"
  31. local_image="${LOCAL_REPO}:${DOCKER_TAG}-${arch}"
  32. docker tag "${docker_image}" "${local_image}"
  33. docker push "${local_image}"
  34. done
  35. echo ">>> Setting up Docker Buildx..."
  36. # Same as earlier, use host networking so the buildx container can access the
  37. # registry via localhost.
  38. #
  39. # Ref: https://github.com/docker/buildx/issues/94#issuecomment-534367714
  40. #
  41. docker buildx create --name builder --use --driver-opt network=host
  42. echo ">>> Running Docker Buildx..."
  43. tags=("${DOCKER_REPO}:${DOCKER_TAG}")
  44. # If the Docker tag starts with a version number, assume the latest release
  45. # is being pushed. Add an extra tag (`latest` or `alpine`, as appropriate)
  46. # to make it easier for users to track the latest release.
  47. if [[ "${DOCKER_TAG}" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
  48. if [[ "${DOCKER_TAG}" == *alpine ]]; then
  49. tags+=(${DOCKER_REPO}:alpine)
  50. else
  51. tags+=(${DOCKER_REPO}:latest)
  52. fi
  53. fi
  54. tag_args=()
  55. for tag in "${tags[@]}"; do
  56. tag_args+=(--tag "${tag}")
  57. done
  58. # Docker Buildx takes a list of target platforms (OS/arch/variant), so map
  59. # the arch list to a platform list (assuming the OS is always `linux`).
  60. declare -A arch_to_platform=(
  61. [amd64]="linux/amd64"
  62. [armv6]="linux/arm/v6"
  63. [armv7]="linux/arm/v7"
  64. [arm64]="linux/arm64"
  65. )
  66. platforms=()
  67. for arch in ${arches[@]}; do
  68. platforms+=("${arch_to_platform[$arch]}")
  69. done
  70. platforms="$(join "," "${platforms[@]}")"
  71. # Run the build, pushing the resulting images and multi-arch manifest list to
  72. # Docker Hub. The Dockerfile is read from stdin to avoid sending any build
  73. # context, which isn't needed here since the actual cross-compiled images
  74. # have already been built.
  75. docker buildx build \
  76. --network host \
  77. --build-arg LOCAL_REPO="${LOCAL_REPO}" \
  78. --build-arg DOCKER_TAG="${DOCKER_TAG}" \
  79. --platform "${platforms}" \
  80. "${tag_args[@]}" \
  81. --push \
  82. - < ./docker/Dockerfile.buildx
  83. # Add an extra arch-specific tag for `arm32v6`; Docker can't seem to properly
  84. # auto-select that image on ARMv6 platforms like Raspberry Pi 1 and Zero
  85. # (https://github.com/moby/moby/issues/41017).
  86. #
  87. # Note that we use `arm32v6` instead of `armv6` to be consistent with the
  88. # existing bitwarden_rs tags, which adhere to the naming conventions of the
  89. # Docker per-architecture repos (e.g., https://hub.docker.com/u/arm32v6).
  90. # Unfortunately, these per-arch repo names aren't always consistent with the
  91. # corresponding platform (OS/arch/variant) IDs, particularly in the case of
  92. # 32-bit ARM arches (e.g., `linux/arm/v6` is used, not `linux/arm32/v6`).
  93. #
  94. # TODO: It looks like this issue should be fixed starting in Docker 20.10.0,
  95. # so this step can be removed once fixed versions are in wider distribution.
  96. #
  97. # Tags:
  98. #
  99. # testing => testing-arm32v6
  100. # testing-alpine => <ignored>
  101. # x.y.z => x.y.z-arm32v6, latest-arm32v6
  102. # x.y.z-alpine => <ignored>
  103. #
  104. if [[ "${DOCKER_TAG}" != *alpine ]]; then
  105. image="${DOCKER_REPO}":"${DOCKER_TAG}"
  106. # Fetch the multi-arch manifest list and find the digest of the armv6 image.
  107. filter='.manifests|.[]|select(.platform.architecture=="arm" and .platform.variant=="v6")|.digest'
  108. digest="$(docker manifest inspect "${image}" | jq -r "${filter}")"
  109. # Pull the armv6 image by digest, retag it, and repush it.
  110. docker pull "${DOCKER_REPO}"@"${digest}"
  111. docker tag "${DOCKER_REPO}"@"${digest}" "${image}"-arm32v6
  112. docker push "${image}"-arm32v6
  113. if [[ "${DOCKER_TAG}" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
  114. docker tag "${image}"-arm32v6 "${DOCKER_REPO}:latest"-arm32v6
  115. docker push "${DOCKER_REPO}:latest"-arm32v6
  116. fi
  117. fi