flexvolume_node_setup.sh 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. #!/usr/bin/env bash
  2. # Copyright 2017 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. # Sets up FlexVolume drivers on GCE COS instances using mounting utilities packaged in a Google
  16. # Container Registry image.
  17. # The user-provided FlexVolume driver(s) must be under /flexvolume of the image filesystem.
  18. # For example, the driver k8s/nfs must be located at /flexvolume/k8s~nfs/nfs .
  19. #
  20. # This script should be used on a clean instance, with no FlexVolume installed.
  21. # Should not be run on instances with an existing full or partial installation.
  22. # Upon failure, the script will clean up the partial installation automatically.
  23. #
  24. # Must be executed under /home/kubernetes/bin with sudo.
  25. # Warning: kubelet will be restarted upon successful execution.
  26. set -o errexit
  27. set -o nounset
  28. set -o pipefail
  29. MOUNTER_IMAGE=${1:-}
  30. MOUNTER_PATH=/home/kubernetes/flexvolume_mounter
  31. VOLUME_PLUGIN_DIR=/home/kubernetes/flexvolume
  32. usage() {
  33. echo "usage: $0 imagename[:tag]"
  34. echo " imagename Name of a Container Registry image. By default the latest image is used."
  35. echo " :tag Container Registry image tag."
  36. exit 1
  37. }
  38. if [ -z "${MOUNTER_IMAGE}" ]; then
  39. echo "ERROR: No Container Registry mounter image is specified."
  40. echo
  41. usage
  42. fi
  43. # Unmounts a mount point lazily. If a mount point does not exist, continue silently,
  44. # and without error.
  45. umount_silent() {
  46. umount -l "$1" &> /dev/null || /bin/true
  47. }
  48. # Waits for kubelet to restart for 1 minute.
  49. kubelet_wait() {
  50. timeout=60
  51. kubelet_readonly_port=10255
  52. until [[ $timeout -eq 0 ]]; do
  53. printf "."
  54. if [[ $( curl -s http://localhost:${kubelet_readonly_port}/healthz ) == "ok" ]]; then
  55. return 0
  56. fi
  57. sleep 1
  58. timeout=$(( timeout-1 ))
  59. done
  60. # Timed out waiting for kubelet to become healthy.
  61. return 1
  62. }
  63. flex_clean() {
  64. echo
  65. echo "An error has occurred. Cleaning up..."
  66. echo
  67. umount_silent ${VOLUME_PLUGIN_DIR}
  68. rm -rf ${VOLUME_PLUGIN_DIR}
  69. umount_silent ${MOUNTER_PATH}/var/lib/kubelet
  70. umount_silent ${MOUNTER_PATH}
  71. rm -rf ${MOUNTER_PATH}
  72. if [[ -n ${IMAGE_URL:-} ]]; then
  73. docker rmi -f "${IMAGE_URL}" &> /dev/null || /bin/true
  74. fi
  75. if [[ -n ${MOUNTER_DEFAULT_NAME:-} ]]; then
  76. docker rm -f "${MOUNTER_DEFAULT_NAME}" &> /dev/null || /bin/true
  77. fi
  78. }
  79. trap flex_clean ERR
  80. # Generates a bash script that wraps all calls to the actual driver inside mount utilities
  81. # in the chroot environment. Kubelet sees this script as the FlexVolume driver.
  82. generate_chroot_wrapper() {
  83. if [ ! -d ${MOUNTER_PATH}/flexvolume ]; then
  84. echo "Failed to set up FlexVolume driver: cannot find directory '/flexvolume' in the mount utility image."
  85. exit 1
  86. fi
  87. for driver_dir in "${MOUNTER_PATH}/flexvolume"/*; do
  88. if [ -d "$driver_dir" ]; then
  89. filecount=$(cd "$driver_dir"; find . -mindepth 1 -maxdepth 1 -print0 | xargs -0 -n1 basename | wc -l)
  90. if [ "$filecount" -gt 1 ]; then
  91. echo "ERROR: Expected 1 file in the FlexVolume directory but found $filecount."
  92. exit 1
  93. fi
  94. driver_file=$(cd "$driver_dir"; find . -mindepth 1 -maxdepth 1 -print0 | xargs -0 -n1 basename | head -n 1)
  95. # driver_path points to the actual driver inside the mount utility image,
  96. # relative to image root.
  97. # wrapper_path is the wrapper script location, which is known to kubelet.
  98. driver_path=flexvolume/$( basename "$driver_dir" )/${driver_file}
  99. wrapper_dir=${VOLUME_PLUGIN_DIR}/$( basename "$driver_dir" )
  100. wrapper_path=${wrapper_dir}/${driver_file}
  101. mkdir -p "$wrapper_dir"
  102. cat >"$wrapper_path" <<EOF
  103. #!/usr/bin/env bash
  104. chroot ${MOUNTER_PATH} ${driver_path} "\$@"
  105. EOF
  106. chmod 755 "$wrapper_path"
  107. echo "FlexVolume driver installed at ${wrapper_path}"
  108. fi
  109. done
  110. }
  111. echo
  112. echo "Importing mount utility image from Container Registry..."
  113. echo
  114. METADATA=http://metadata.google.internal/computeMetadata/v1
  115. SVC_ACCT_ENDPOINT=$METADATA/instance/service-accounts/default
  116. ACCESS_TOKEN=$(curl -s -H 'Metadata-Flavor: Google' $SVC_ACCT_ENDPOINT/token | cut -d'"' -f 4)
  117. PROJECT_ID=$(curl -s -H 'Metadata-Flavor: Google' $METADATA/project/project-id)
  118. IMAGE_URL=gcr.io/${PROJECT_ID}/${MOUNTER_IMAGE}
  119. MOUNTER_DEFAULT_NAME=flexvolume_mounter
  120. sudo -u "${SUDO_USER}" docker login -u _token -p "$ACCESS_TOKEN" https://gcr.io > /dev/null
  121. sudo -u "${SUDO_USER}" docker run --name=${MOUNTER_DEFAULT_NAME} "${IMAGE_URL}"
  122. docker export ${MOUNTER_DEFAULT_NAME} > /tmp/${MOUNTER_DEFAULT_NAME}.tar
  123. docker rm ${MOUNTER_DEFAULT_NAME} > /dev/null
  124. docker rmi "${IMAGE_URL}" > /dev/null
  125. echo
  126. echo "Loading mount utilities onto this instance..."
  127. echo
  128. mkdir -p ${MOUNTER_PATH}
  129. tar xf /tmp/${MOUNTER_DEFAULT_NAME}.tar -C ${MOUNTER_PATH}
  130. # Bind the kubelet directory to one under flexvolume_mounter
  131. mkdir -p ${MOUNTER_PATH}/var/lib/kubelet
  132. mount --rbind /var/lib/kubelet/ ${MOUNTER_PATH}/var/lib/kubelet
  133. mount --make-rshared ${MOUNTER_PATH}/var/lib/kubelet
  134. # Remount the flexvolume_mounter environment with /dev enabled.
  135. mount --bind ${MOUNTER_PATH} ${MOUNTER_PATH}
  136. mount -o remount,dev,exec ${MOUNTER_PATH}
  137. echo
  138. echo "Setting up FlexVolume driver..."
  139. echo
  140. mkdir -p ${VOLUME_PLUGIN_DIR}
  141. mount --bind ${VOLUME_PLUGIN_DIR} ${VOLUME_PLUGIN_DIR}
  142. mount -o remount,exec ${VOLUME_PLUGIN_DIR}
  143. generate_chroot_wrapper
  144. echo
  145. echo "Restarting Kubelet..."
  146. echo
  147. systemctl restart kubelet.service
  148. if kubelet_wait; then
  149. echo
  150. echo "FlexVolume is ready."
  151. else
  152. echo "ERROR: Timed out after 1 minute waiting for kubelet restart."
  153. fi