k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/build/common.sh (about) 1 #!/usr/bin/env bash 2 3 # Copyright 2014 The Kubernetes Authors. 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 # shellcheck disable=SC2034 # Variables sourced in other scripts. 18 19 # Common utilities, variables and checks for all build scripts. 20 set -o errexit 21 set -o nounset 22 set -o pipefail 23 24 # Unset CDPATH, having it set messes up with script import paths 25 unset CDPATH 26 27 USER_ID=$(id -u) 28 GROUP_ID=$(id -g) 29 30 DOCKER_OPTS=${DOCKER_OPTS:-""} 31 IFS=" " read -r -a DOCKER <<< "docker ${DOCKER_OPTS}" 32 DOCKER_HOST=${DOCKER_HOST:-""} 33 GOPROXY=${GOPROXY:-""} 34 35 # This will canonicalize the path 36 KUBE_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/.. && pwd -P) 37 38 source "${KUBE_ROOT}/hack/lib/init.sh" 39 40 # Constants 41 readonly KUBE_BUILD_IMAGE_REPO=kube-build 42 KUBE_BUILD_IMAGE_CROSS_TAG="$(cat "${KUBE_ROOT}/build/build-image/cross/VERSION")" 43 readonly KUBE_BUILD_IMAGE_CROSS_TAG 44 45 readonly KUBE_DOCKER_REGISTRY="${KUBE_DOCKER_REGISTRY:-registry.k8s.io}" 46 KUBE_BASE_IMAGE_REGISTRY="${KUBE_BASE_IMAGE_REGISTRY:-registry.k8s.io/build-image}" 47 readonly KUBE_BASE_IMAGE_REGISTRY 48 49 # This version number is used to cause everyone to rebuild their data containers 50 # and build image. This is especially useful for automated build systems like 51 # Jenkins. 52 # 53 # Increment/change this number if you change the build image (anything under 54 # build/build-image) or change the set of volumes in the data container. 55 KUBE_BUILD_IMAGE_VERSION_BASE="$(cat "${KUBE_ROOT}/build/build-image/VERSION")" 56 readonly KUBE_BUILD_IMAGE_VERSION_BASE 57 readonly KUBE_BUILD_IMAGE_VERSION="${KUBE_BUILD_IMAGE_VERSION_BASE}-${KUBE_BUILD_IMAGE_CROSS_TAG}" 58 59 # Make it possible to override the `kube-cross` image, and tag independent of `KUBE_BASE_IMAGE_REGISTRY` 60 KUBE_CROSS_IMAGE="${KUBE_CROSS_IMAGE:-"${KUBE_BASE_IMAGE_REGISTRY}/kube-cross"}" 61 readonly KUBE_CROSS_IMAGE 62 KUBE_CROSS_VERSION="${KUBE_CROSS_VERSION:-"${KUBE_BUILD_IMAGE_CROSS_TAG}"}" 63 readonly KUBE_CROSS_VERSION 64 65 # Here we map the output directories across both the local and remote _output 66 # directories: 67 # 68 # *_OUTPUT_ROOT - the base of all output in that environment. 69 # *_OUTPUT_SUBPATH - location where golang stuff is built/cached. Also 70 # persisted across docker runs with a volume mount. 71 # *_OUTPUT_BINPATH - location where final binaries are placed. If the remote 72 # is really remote, this is the stuff that has to be copied 73 # back. 74 # OUT_DIR can come in from the Makefile, so honor it. 75 readonly LOCAL_OUTPUT_ROOT="${KUBE_ROOT}/${OUT_DIR:-_output}" 76 readonly LOCAL_OUTPUT_SUBPATH="${LOCAL_OUTPUT_ROOT}/dockerized" 77 readonly LOCAL_OUTPUT_BINPATH="${LOCAL_OUTPUT_SUBPATH}/bin" 78 readonly LOCAL_OUTPUT_GOPATH="${LOCAL_OUTPUT_SUBPATH}/go" 79 readonly LOCAL_OUTPUT_IMAGE_STAGING="${LOCAL_OUTPUT_ROOT}/images" 80 81 # This is a symlink to binaries for "this platform" (e.g. build tools). 82 readonly THIS_PLATFORM_BIN="${LOCAL_OUTPUT_ROOT}/bin" 83 84 readonly KUBE_GO_PACKAGE=k8s.io/kubernetes 85 readonly REMOTE_ROOT="/go/src/${KUBE_GO_PACKAGE}" 86 readonly REMOTE_OUTPUT_ROOT="${REMOTE_ROOT}/_output" 87 readonly REMOTE_OUTPUT_SUBPATH="${REMOTE_OUTPUT_ROOT}/dockerized" 88 readonly REMOTE_OUTPUT_BINPATH="${REMOTE_OUTPUT_SUBPATH}/bin" 89 readonly REMOTE_OUTPUT_GOPATH="${REMOTE_OUTPUT_SUBPATH}/go" 90 91 # This is the port on the workstation host to expose RSYNC on. Set this if you 92 # are doing something fancy with ssh tunneling. 93 readonly KUBE_RSYNC_PORT="${KUBE_RSYNC_PORT:-}" 94 95 # This is the port that rsync is running on *inside* the container. This may be 96 # mapped to KUBE_RSYNC_PORT via docker networking. 97 readonly KUBE_CONTAINER_RSYNC_PORT=8730 98 99 # These are the default versions (image tags) for their respective base images. 100 readonly __default_distroless_iptables_version=v0.5.4 101 readonly __default_go_runner_version=v2.3.1-go1.22.3-bookworm.0 102 readonly __default_setcap_version=bookworm-v1.0.2 103 104 # These are the base images for the Docker-wrapped binaries. 105 readonly KUBE_GORUNNER_IMAGE="${KUBE_GORUNNER_IMAGE:-$KUBE_BASE_IMAGE_REGISTRY/go-runner:$__default_go_runner_version}" 106 readonly KUBE_APISERVER_BASE_IMAGE="${KUBE_APISERVER_BASE_IMAGE:-$KUBE_GORUNNER_IMAGE}" 107 readonly KUBE_CONTROLLER_MANAGER_BASE_IMAGE="${KUBE_CONTROLLER_MANAGER_BASE_IMAGE:-$KUBE_GORUNNER_IMAGE}" 108 readonly KUBE_SCHEDULER_BASE_IMAGE="${KUBE_SCHEDULER_BASE_IMAGE:-$KUBE_GORUNNER_IMAGE}" 109 readonly KUBE_PROXY_BASE_IMAGE="${KUBE_PROXY_BASE_IMAGE:-$KUBE_BASE_IMAGE_REGISTRY/distroless-iptables:$__default_distroless_iptables_version}" 110 readonly KUBECTL_BASE_IMAGE="${KUBECTL_BASE_IMAGE:-$KUBE_GORUNNER_IMAGE}" 111 112 # This is the image used in a multi-stage build to apply capabilities to Docker-wrapped binaries. 113 readonly KUBE_BUILD_SETCAP_IMAGE="${KUBE_BUILD_SETCAP_IMAGE:-$KUBE_BASE_IMAGE_REGISTRY/setcap:$__default_setcap_version}" 114 115 # Get the set of master binaries that run in Docker (on Linux) 116 # Entry format is "<binary-name>,<base-image>". 117 # Binaries are placed in /usr/local/bin inside the image. 118 # `make` users can override any or all of the base images using the associated 119 # environment variables. 120 # 121 # $1 - server architecture 122 kube::build::get_docker_wrapped_binaries() { 123 ### If you change any of these lists, please also update DOCKERIZED_BINARIES 124 ### in build/BUILD. And kube::golang::server_image_targets 125 local targets=( 126 "kube-apiserver,${KUBE_APISERVER_BASE_IMAGE}" 127 "kube-controller-manager,${KUBE_CONTROLLER_MANAGER_BASE_IMAGE}" 128 "kube-scheduler,${KUBE_SCHEDULER_BASE_IMAGE}" 129 "kube-proxy,${KUBE_PROXY_BASE_IMAGE}" 130 "kubectl,${KUBECTL_BASE_IMAGE}" 131 ) 132 133 echo "${targets[@]}" 134 } 135 136 # --------------------------------------------------------------------------- 137 # Basic setup functions 138 139 # Verify that the right utilities and such are installed for building Kube. Set 140 # up some dynamic constants. 141 # Args: 142 # $1 - boolean of whether to require functioning docker (default true) 143 # 144 # Vars set: 145 # KUBE_ROOT_HASH 146 # KUBE_BUILD_IMAGE_TAG_BASE 147 # KUBE_BUILD_IMAGE_TAG 148 # KUBE_BUILD_IMAGE 149 # KUBE_BUILD_CONTAINER_NAME_BASE 150 # KUBE_BUILD_CONTAINER_NAME 151 # KUBE_DATA_CONTAINER_NAME_BASE 152 # KUBE_DATA_CONTAINER_NAME 153 # KUBE_RSYNC_CONTAINER_NAME_BASE 154 # KUBE_RSYNC_CONTAINER_NAME 155 # DOCKER_MOUNT_ARGS 156 # LOCAL_OUTPUT_BUILD_CONTEXT 157 # shellcheck disable=SC2120 # optional parameters 158 function kube::build::verify_prereqs() { 159 local -r require_docker=${1:-true} 160 kube::log::status "Verifying Prerequisites...." 161 kube::build::ensure_tar || return 1 162 kube::build::ensure_rsync || return 1 163 if ${require_docker}; then 164 kube::build::ensure_docker_in_path || return 1 165 if kube::build::is_osx; then 166 kube::build::docker_available_on_osx || return 1 167 fi 168 kube::util::ensure_docker_daemon_connectivity || return 1 169 170 if (( KUBE_VERBOSE > 6 )); then 171 kube::log::status "Docker Version:" 172 "${DOCKER[@]}" version | kube::log::info_from_stdin 173 fi 174 fi 175 176 KUBE_GIT_BRANCH=$(git symbolic-ref --short -q HEAD 2>/dev/null || true) 177 KUBE_ROOT_HASH=$(kube::build::short_hash "${HOSTNAME:-}:${KUBE_ROOT}:${KUBE_GIT_BRANCH}") 178 KUBE_BUILD_IMAGE_TAG_BASE="build-${KUBE_ROOT_HASH}" 179 KUBE_BUILD_IMAGE_TAG="${KUBE_BUILD_IMAGE_TAG_BASE}-${KUBE_BUILD_IMAGE_VERSION}" 180 KUBE_BUILD_IMAGE="${KUBE_BUILD_IMAGE_REPO}:${KUBE_BUILD_IMAGE_TAG}" 181 KUBE_BUILD_CONTAINER_NAME_BASE="kube-build-${KUBE_ROOT_HASH}" 182 KUBE_BUILD_CONTAINER_NAME="${KUBE_BUILD_CONTAINER_NAME_BASE}-${KUBE_BUILD_IMAGE_VERSION}" 183 KUBE_RSYNC_CONTAINER_NAME_BASE="kube-rsync-${KUBE_ROOT_HASH}" 184 KUBE_RSYNC_CONTAINER_NAME="${KUBE_RSYNC_CONTAINER_NAME_BASE}-${KUBE_BUILD_IMAGE_VERSION}" 185 KUBE_DATA_CONTAINER_NAME_BASE="kube-build-data-${KUBE_ROOT_HASH}" 186 KUBE_DATA_CONTAINER_NAME="${KUBE_DATA_CONTAINER_NAME_BASE}-${KUBE_BUILD_IMAGE_VERSION}" 187 DOCKER_MOUNT_ARGS=(--volumes-from "${KUBE_DATA_CONTAINER_NAME}") 188 LOCAL_OUTPUT_BUILD_CONTEXT="${LOCAL_OUTPUT_IMAGE_STAGING}/${KUBE_BUILD_IMAGE}" 189 190 kube::version::get_version_vars 191 kube::version::save_version_vars "${KUBE_ROOT}/.dockerized-kube-version-defs" 192 193 # Without this, the user's umask can leak through. 194 umask 0022 195 } 196 197 # --------------------------------------------------------------------------- 198 # Utility functions 199 200 function kube::build::docker_available_on_osx() { 201 if [[ -z "${DOCKER_HOST}" ]]; then 202 if [[ -S "/var/run/docker.sock" ]] || [[ -S "$(docker context inspect --format '{{.Endpoints.docker.Host}}' | awk -F 'unix://' '{print $2}')" ]]; then 203 kube::log::status "Using docker on macOS" 204 return 0 205 fi 206 207 kube::log::status "No docker host is set." 208 kube::log::status "It looks like you're running Mac OS X, but Docker for Mac cannot be found." 209 kube::log::status "See: https://docs.docker.com/engine/installation/mac/ for installation instructions." 210 return 1 211 fi 212 } 213 214 function kube::build::is_osx() { 215 [[ "$(uname)" == "Darwin" ]] 216 } 217 218 function kube::build::is_gnu_sed() { 219 [[ $(sed --version 2>&1) == *GNU* ]] 220 } 221 222 function kube::build::ensure_rsync() { 223 if [[ -z "$(which rsync)" ]]; then 224 kube::log::error "Can't find 'rsync' in PATH, please fix and retry." 225 return 1 226 fi 227 } 228 229 function kube::build::ensure_docker_in_path() { 230 if [[ -z "$(which docker)" ]]; then 231 kube::log::error "Can't find 'docker' in PATH, please fix and retry." 232 kube::log::error "See https://docs.docker.com/installation/#installation for installation instructions." 233 return 1 234 fi 235 } 236 237 function kube::build::ensure_tar() { 238 if [[ -n "${TAR:-}" ]]; then 239 return 240 fi 241 242 # Find gnu tar if it is available, bomb out if not. 243 TAR=tar 244 if which gtar &>/dev/null; then 245 TAR=gtar 246 else 247 if which gnutar &>/dev/null; then 248 TAR=gnutar 249 fi 250 fi 251 if ! "${TAR}" --version | grep -q GNU; then 252 echo " !!! Cannot find GNU tar. Build on Linux or install GNU tar" 253 echo " on Mac OS X (brew install gnu-tar)." 254 return 1 255 fi 256 } 257 258 function kube::build::has_docker() { 259 which docker &> /dev/null 260 } 261 262 function kube::build::has_ip() { 263 which ip &> /dev/null && ip -Version | grep 'iproute2' &> /dev/null 264 } 265 266 # Detect if a specific image exists 267 # 268 # $1 - image repo name 269 # $2 - image tag 270 function kube::build::docker_image_exists() { 271 [[ -n $1 && -n $2 ]] || { 272 kube::log::error "Internal error. Image not specified in docker_image_exists." 273 exit 2 274 } 275 276 [[ $("${DOCKER[@]}" images -q "${1}:${2}") ]] 277 } 278 279 # Delete all images that match a tag prefix except for the "current" version 280 # 281 # $1: The image repo/name 282 # $2: The tag base. We consider any image that matches $2* 283 # $3: The current image not to delete if provided 284 function kube::build::docker_delete_old_images() { 285 # In Docker 1.12, we can replace this with 286 # docker images "$1" --format "{{.Tag}}" 287 for tag in $("${DOCKER[@]}" images "${1}" | tail -n +2 | awk '{print $2}') ; do 288 if [[ "${tag}" != "${2}"* ]] ; then 289 V=3 kube::log::status "Keeping image ${1}:${tag}" 290 continue 291 fi 292 293 if [[ -z "${3:-}" || "${tag}" != "${3}" ]] ; then 294 V=2 kube::log::status "Deleting image ${1}:${tag}" 295 "${DOCKER[@]}" rmi "${1}:${tag}" >/dev/null 296 else 297 V=3 kube::log::status "Keeping image ${1}:${tag}" 298 fi 299 done 300 } 301 302 # Stop and delete all containers that match a pattern 303 # 304 # $1: The base container prefix 305 # $2: The current container to keep, if provided 306 function kube::build::docker_delete_old_containers() { 307 # In Docker 1.12 we can replace this line with 308 # docker ps -a --format="{{.Names}}" 309 for container in $("${DOCKER[@]}" ps -a | tail -n +2 | awk '{print $NF}') ; do 310 if [[ "${container}" != "${1}"* ]] ; then 311 V=3 kube::log::status "Keeping container ${container}" 312 continue 313 fi 314 if [[ -z "${2:-}" || "${container}" != "${2}" ]] ; then 315 V=2 kube::log::status "Deleting container ${container}" 316 kube::build::destroy_container "${container}" 317 else 318 V=3 kube::log::status "Keeping container ${container}" 319 fi 320 done 321 } 322 323 # Takes $1 and computes a short has for it. Useful for unique tag generation 324 function kube::build::short_hash() { 325 [[ $# -eq 1 ]] || { 326 kube::log::error "Internal error. No data based to short_hash." 327 exit 2 328 } 329 330 local short_hash 331 if which md5 >/dev/null 2>&1; then 332 short_hash=$(md5 -q -s "$1") 333 else 334 short_hash=$(echo -n "$1" | md5sum) 335 fi 336 echo "${short_hash:0:10}" 337 } 338 339 # Pedantically kill, wait-on and remove a container. The -f -v options 340 # to rm don't actually seem to get the job done, so force kill the 341 # container, wait to ensure it's stopped, then try the remove. This is 342 # a workaround for bug https://github.com/docker/docker/issues/3968. 343 function kube::build::destroy_container() { 344 "${DOCKER[@]}" kill "$1" >/dev/null 2>&1 || true 345 if [[ $("${DOCKER[@]}" version --format '{{.Server.Version}}') = 17.06.0* ]]; then 346 # Workaround https://github.com/moby/moby/issues/33948. 347 # TODO: remove when 17.06.0 is not relevant anymore 348 DOCKER_API_VERSION=v1.29 "${DOCKER[@]}" wait "$1" >/dev/null 2>&1 || true 349 else 350 "${DOCKER[@]}" wait "$1" >/dev/null 2>&1 || true 351 fi 352 "${DOCKER[@]}" rm -f -v "$1" >/dev/null 2>&1 || true 353 } 354 355 # --------------------------------------------------------------------------- 356 # Building 357 358 359 function kube::build::clean() { 360 if kube::build::has_docker ; then 361 kube::build::docker_delete_old_containers "${KUBE_BUILD_CONTAINER_NAME_BASE}" 362 kube::build::docker_delete_old_containers "${KUBE_RSYNC_CONTAINER_NAME_BASE}" 363 kube::build::docker_delete_old_containers "${KUBE_DATA_CONTAINER_NAME_BASE}" 364 kube::build::docker_delete_old_images "${KUBE_BUILD_IMAGE_REPO}" "${KUBE_BUILD_IMAGE_TAG_BASE}" 365 366 V=2 kube::log::status "Cleaning all untagged docker images" 367 "${DOCKER[@]}" rmi "$("${DOCKER[@]}" images -q --filter 'dangling=true')" 2> /dev/null || true 368 fi 369 370 if [[ -d "${LOCAL_OUTPUT_ROOT}" ]]; then 371 kube::log::status "Removing _output directory" 372 # this ensures we can clean _output/local/go/cache which is not rw by default 373 chmod -R +w "${LOCAL_OUTPUT_ROOT}" 374 rm -rf "${LOCAL_OUTPUT_ROOT}" 375 fi 376 } 377 378 # Set up the context directory for the kube-build image and build it. 379 function kube::build::build_image() { 380 mkdir -p "${LOCAL_OUTPUT_BUILD_CONTEXT}" 381 # Make sure the context directory owned by the right user for syncing sources to container. 382 chown -R "${USER_ID}":"${GROUP_ID}" "${LOCAL_OUTPUT_BUILD_CONTEXT}" 383 384 cp /etc/localtime "${LOCAL_OUTPUT_BUILD_CONTEXT}/" 385 chmod u+w "${LOCAL_OUTPUT_BUILD_CONTEXT}/localtime" 386 387 cp "${KUBE_ROOT}/build/build-image/Dockerfile" "${LOCAL_OUTPUT_BUILD_CONTEXT}/Dockerfile" 388 cp "${KUBE_ROOT}/build/build-image/rsyncd.sh" "${LOCAL_OUTPUT_BUILD_CONTEXT}/" 389 dd if=/dev/urandom bs=512 count=1 2>/dev/null | LC_ALL=C tr -dc 'A-Za-z0-9' | dd bs=32 count=1 2>/dev/null > "${LOCAL_OUTPUT_BUILD_CONTEXT}/rsyncd.password" 390 chmod go= "${LOCAL_OUTPUT_BUILD_CONTEXT}/rsyncd.password" 391 392 kube::build::docker_build "${KUBE_BUILD_IMAGE}" "${LOCAL_OUTPUT_BUILD_CONTEXT}" 'false' "--build-arg=KUBE_CROSS_IMAGE=${KUBE_CROSS_IMAGE} --build-arg=KUBE_CROSS_VERSION=${KUBE_CROSS_VERSION}" 393 394 # Clean up old versions of everything 395 kube::build::docker_delete_old_containers "${KUBE_BUILD_CONTAINER_NAME_BASE}" "${KUBE_BUILD_CONTAINER_NAME}" 396 kube::build::docker_delete_old_containers "${KUBE_RSYNC_CONTAINER_NAME_BASE}" "${KUBE_RSYNC_CONTAINER_NAME}" 397 kube::build::docker_delete_old_containers "${KUBE_DATA_CONTAINER_NAME_BASE}" "${KUBE_DATA_CONTAINER_NAME}" 398 kube::build::docker_delete_old_images "${KUBE_BUILD_IMAGE_REPO}" "${KUBE_BUILD_IMAGE_TAG_BASE}" "${KUBE_BUILD_IMAGE_TAG}" 399 400 kube::build::ensure_data_container 401 kube::build::sync_to_container 402 } 403 404 # Build a docker image from a Dockerfile. 405 # $1 is the name of the image to build 406 # $2 is the location of the "context" directory, with the Dockerfile at the root. 407 # $3 is the value to set the --pull flag for docker build; true by default 408 # $4 is the set of --build-args for docker. 409 function kube::build::docker_build() { 410 kube::util::ensure-docker-buildx 411 412 local -r image=$1 413 local -r context_dir=$2 414 local -r pull="${3:-true}" 415 local build_args 416 IFS=" " read -r -a build_args <<< "$4" 417 readonly build_args 418 local -ra build_cmd=("${DOCKER[@]}" buildx build --load -t "${image}" "--pull=${pull}" "${build_args[@]}" "${context_dir}") 419 420 kube::log::status "Building Docker image ${image}" 421 local docker_output 422 docker_output=$(DOCKER_CLI_EXPERIMENTAL=enabled "${build_cmd[@]}" 2>&1) || { 423 cat <<EOF >&2 424 +++ Docker build command failed for ${image} 425 426 ${docker_output} 427 428 To retry manually, run: 429 430 DOCKER_CLI_EXPERIMENTAL=enabled ${build_cmd[*]} 431 432 EOF 433 return 1 434 } 435 } 436 437 function kube::build::ensure_data_container() { 438 # If the data container exists AND exited successfully, we can use it. 439 # Otherwise nuke it and start over. 440 local ret=0 441 local code=0 442 443 code=$(docker inspect \ 444 -f '{{.State.ExitCode}}' \ 445 "${KUBE_DATA_CONTAINER_NAME}" 2>/dev/null) || ret=$? 446 if [[ "${ret}" == 0 && "${code}" != 0 ]]; then 447 kube::build::destroy_container "${KUBE_DATA_CONTAINER_NAME}" 448 ret=1 449 fi 450 if [[ "${ret}" != 0 ]]; then 451 kube::log::status "Creating data container ${KUBE_DATA_CONTAINER_NAME}" 452 # We have to ensure the directory exists, or else the docker run will 453 # create it as root. 454 mkdir -p "${LOCAL_OUTPUT_GOPATH}" 455 # We want this to run as root to be able to chown, so non-root users can 456 # later use the result as a data container. This run both creates the data 457 # container and chowns the GOPATH. 458 # 459 # The data container creates volumes for all of the directories that store 460 # intermediates for the Go build. This enables incremental builds across 461 # Docker sessions. The *_cgo paths are re-compiled versions of the go std 462 # libraries for true static building. 463 local -ra docker_cmd=( 464 "${DOCKER[@]}" run 465 --volume "${REMOTE_ROOT}" # white-out the whole output dir 466 --volume /usr/local/go/pkg/linux_386_cgo 467 --volume /usr/local/go/pkg/linux_amd64_cgo 468 --volume /usr/local/go/pkg/linux_arm_cgo 469 --volume /usr/local/go/pkg/linux_arm64_cgo 470 --volume /usr/local/go/pkg/linux_ppc64le_cgo 471 --volume /usr/local/go/pkg/darwin_amd64_cgo 472 --volume /usr/local/go/pkg/darwin_386_cgo 473 --volume /usr/local/go/pkg/windows_amd64_cgo 474 --volume /usr/local/go/pkg/windows_386_cgo 475 --name "${KUBE_DATA_CONTAINER_NAME}" 476 --hostname "${HOSTNAME}" 477 "${KUBE_BUILD_IMAGE}" 478 chown -R "${USER_ID}":"${GROUP_ID}" 479 "${REMOTE_ROOT}" 480 /usr/local/go/pkg/ 481 ) 482 "${docker_cmd[@]}" 483 fi 484 } 485 486 # Run a command in the kube-build image. This assumes that the image has 487 # already been built. 488 function kube::build::run_build_command() { 489 kube::log::status "Running build command..." 490 kube::build::run_build_command_ex "${KUBE_BUILD_CONTAINER_NAME}" -- "$@" 491 } 492 493 # Run a command in the kube-build image. This assumes that the image has 494 # already been built. 495 # 496 # Arguments are in the form of 497 # <container name> <extra docker args> -- <command> 498 function kube::build::run_build_command_ex() { 499 [[ $# != 0 ]] || { echo "Invalid input - please specify a container name." >&2; return 4; } 500 local container_name="${1}" 501 shift 502 503 local -a docker_run_opts=( 504 "--name=${container_name}" 505 "--user=$(id -u):$(id -g)" 506 "--hostname=${HOSTNAME}" 507 "-e=GOPROXY=${GOPROXY}" 508 "${DOCKER_MOUNT_ARGS[@]}" 509 ) 510 511 local detach=false 512 513 [[ $# != 0 ]] || { echo "Invalid input - please specify docker arguments followed by --." >&2; return 4; } 514 # Everything before "--" is an arg to docker 515 until [ -z "${1-}" ] ; do 516 if [[ "$1" == "--" ]]; then 517 shift 518 break 519 fi 520 docker_run_opts+=("$1") 521 if [[ "$1" == "-d" || "$1" == "--detach" ]] ; then 522 detach=true 523 fi 524 shift 525 done 526 527 # Everything after "--" is the command to run 528 [[ $# != 0 ]] || { echo "Invalid input - please specify a command to run." >&2; return 4; } 529 local -a cmd=() 530 until [ -z "${1-}" ] ; do 531 cmd+=("$1") 532 shift 533 done 534 535 docker_run_opts+=( 536 --env "KUBE_FASTBUILD=${KUBE_FASTBUILD:-false}" 537 --env "KUBE_BUILDER_OS=${OSTYPE:-notdetected}" 538 --env "KUBE_VERBOSE=${KUBE_VERBOSE}" 539 --env "KUBE_BUILD_WITH_COVERAGE=${KUBE_BUILD_WITH_COVERAGE:-}" 540 --env "KUBE_BUILD_PLATFORMS=${KUBE_BUILD_PLATFORMS:-}" 541 --env "KUBE_CGO_OVERRIDES=' ${KUBE_CGO_OVERRIDES[*]:-} '" 542 --env "KUBE_STATIC_OVERRIDES=' ${KUBE_STATIC_OVERRIDES[*]:-} '" 543 --env "FORCE_HOST_GO=${FORCE_HOST_GO:-}" 544 --env "GO_VERSION=${GO_VERSION:-}" 545 --env "GOTOOLCHAIN=${GOTOOLCHAIN:-}" 546 --env "GOFLAGS=${GOFLAGS:-}" 547 --env "GOGCFLAGS=${GOGCFLAGS:-}" 548 --env "SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH:-}" 549 ) 550 551 # use GOLDFLAGS only if it is set explicitly. 552 if [[ -v GOLDFLAGS ]]; then 553 docker_run_opts+=( 554 --env "GOLDFLAGS=${GOLDFLAGS:-}" 555 ) 556 fi 557 558 if [[ -n "${DOCKER_CGROUP_PARENT:-}" ]]; then 559 kube::log::status "Using ${DOCKER_CGROUP_PARENT} as container cgroup parent" 560 docker_run_opts+=(--cgroup-parent "${DOCKER_CGROUP_PARENT}") 561 fi 562 563 # If we have stdin we can run interactive. This allows things like 'shell.sh' 564 # to work. However, if we run this way and don't have stdin, then it ends up 565 # running in a daemon-ish mode. So if we don't have a stdin, we explicitly 566 # attach stderr/stdout but don't bother asking for a tty. 567 if [[ -t 0 ]]; then 568 docker_run_opts+=(--interactive --tty) 569 elif [[ "${detach}" == false ]]; then 570 docker_run_opts+=("--attach=stdout" "--attach=stderr") 571 fi 572 573 local -ra docker_cmd=( 574 "${DOCKER[@]}" run "${docker_run_opts[@]}" "${KUBE_BUILD_IMAGE}") 575 576 # Clean up container from any previous run 577 kube::build::destroy_container "${container_name}" 578 "${docker_cmd[@]}" "${cmd[@]}" 579 if [[ "${detach}" == false ]]; then 580 kube::build::destroy_container "${container_name}" 581 fi 582 } 583 584 function kube::build::rsync_probe { 585 # Wait until rsync is up and running. 586 local tries=20 587 while (( tries > 0 )) ; do 588 if rsync "rsync://k8s@${1}:${2}/" \ 589 --password-file="${LOCAL_OUTPUT_BUILD_CONTEXT}/rsyncd.password" \ 590 &> /dev/null ; then 591 return 0 592 fi 593 tries=$(( tries - 1)) 594 sleep 0.1 595 done 596 597 return 1 598 } 599 600 # Start up the rsync container in the background. This should be explicitly 601 # stopped with kube::build::stop_rsyncd_container. 602 # 603 # This will set the global var KUBE_RSYNC_ADDR to the effective port that the 604 # rsync daemon can be reached out. 605 function kube::build::start_rsyncd_container() { 606 IPTOOL=ifconfig 607 if kube::build::has_ip ; then 608 IPTOOL="ip address" 609 fi 610 kube::build::stop_rsyncd_container 611 V=3 kube::log::status "Starting rsyncd container" 612 kube::build::run_build_command_ex \ 613 "${KUBE_RSYNC_CONTAINER_NAME}" -p 127.0.0.1:"${KUBE_RSYNC_PORT}":"${KUBE_CONTAINER_RSYNC_PORT}" -d \ 614 -e ALLOW_HOST="$(${IPTOOL} | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' | tr '\n' ' ')" \ 615 -- /rsyncd.sh >/dev/null 616 617 local mapped_port 618 if ! mapped_port=$("${DOCKER[@]}" port "${KUBE_RSYNC_CONTAINER_NAME}" "${KUBE_CONTAINER_RSYNC_PORT}" 2> /dev/null | cut -d: -f 2) ; then 619 kube::log::error "Could not get effective rsync port" 620 return 1 621 fi 622 623 local container_ip 624 container_ip=$("${DOCKER[@]}" inspect --format '{{ .NetworkSettings.IPAddress }}' "${KUBE_RSYNC_CONTAINER_NAME}") 625 626 # Sometimes we can reach rsync through localhost and a NAT'd port. Other 627 # times (when we are running in another docker container on the Jenkins 628 # machines) we have to talk directly to the container IP. There is no one 629 # strategy that works in all cases so we test to figure out which situation we 630 # are in. 631 if kube::build::rsync_probe 127.0.0.1 "${mapped_port}"; then 632 KUBE_RSYNC_ADDR="127.0.0.1:${mapped_port}" 633 return 0 634 elif kube::build::rsync_probe "${container_ip}" "${KUBE_CONTAINER_RSYNC_PORT}"; then 635 KUBE_RSYNC_ADDR="${container_ip}:${KUBE_CONTAINER_RSYNC_PORT}" 636 return 0 637 fi 638 639 kube::log::error "Could not connect to rsync container." 640 return 1 641 } 642 643 function kube::build::stop_rsyncd_container() { 644 V=3 kube::log::status "Stopping any currently running rsyncd container" 645 unset KUBE_RSYNC_ADDR 646 kube::build::destroy_container "${KUBE_RSYNC_CONTAINER_NAME}" 647 } 648 649 function kube::build::rsync { 650 local -a rsync_opts=( 651 --archive 652 "--password-file=${LOCAL_OUTPUT_BUILD_CONTEXT}/rsyncd.password" 653 ) 654 if (( KUBE_VERBOSE >= 6 )); then 655 rsync_opts+=("-iv") 656 fi 657 if (( KUBE_RSYNC_COMPRESS > 0 )); then 658 rsync_opts+=("--compress-level=${KUBE_RSYNC_COMPRESS}") 659 fi 660 V=3 kube::log::status "Running rsync" 661 rsync "${rsync_opts[@]}" "$@" 662 } 663 664 # This will launch rsyncd in a container and then sync the source tree to the 665 # container over the local network. 666 function kube::build::sync_to_container() { 667 kube::log::status "Syncing sources to container" 668 669 kube::build::start_rsyncd_container 670 671 # rsync filters are a bit confusing. Here we are syncing everything except 672 # output only directories and things that are not necessary like the git 673 # directory and generated files. The '- /' filter prevents rsync 674 # from trying to set the uid/gid/perms on the root of the sync tree. 675 # As an exception, we need to sync generated files in staging/, because 676 # they will not be re-generated by 'make'. Note that the 'H' filtered files 677 # are hidden from rsync so they will be deleted in the target container if 678 # they exist. This will allow them to be re-created in the container if 679 # necessary. 680 kube::build::rsync \ 681 --delete \ 682 --filter='- /_tmp/' \ 683 --filter='- /_output/' \ 684 --filter='- /' \ 685 "${KUBE_ROOT}/" "rsync://k8s@${KUBE_RSYNC_ADDR}/k8s/" 686 687 kube::build::stop_rsyncd_container 688 } 689 690 # Copy all build results back out. 691 function kube::build::copy_output() { 692 kube::log::status "Syncing out of container" 693 694 kube::build::start_rsyncd_container 695 696 # The filter syntax for rsync is a little obscure. It filters on files and 697 # directories. If you don't go in to a directory you won't find any files 698 # there. Rules are evaluated in order. The last two rules are a little 699 # magic. '+ */' says to go in to every directory and '- /**' says to ignore 700 # any file or directory that isn't already specifically allowed. 701 # 702 # We are looking to copy out all of the built binaries along with various 703 # generated files. 704 kube::build::rsync \ 705 --prune-empty-dirs \ 706 --filter='- /_temp/' \ 707 --filter='+ /vendor/' \ 708 --filter='+ /staging/***/Godeps/**' \ 709 --filter='+ /_output/dockerized/bin/**' \ 710 --filter='+ zz_generated.*' \ 711 --filter='+ generated.proto' \ 712 --filter='+ *.pb.go' \ 713 --filter='+ types.go' \ 714 --filter='+ */' \ 715 --filter='- /**' \ 716 "rsync://k8s@${KUBE_RSYNC_ADDR}/k8s/" "${KUBE_ROOT}" 717 718 kube::build::stop_rsyncd_container 719 }