common.sh 27 KB

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