k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cluster/gce/gci/flexvolume_node_setup.sh (about)

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