common.sh 27 KB

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