upgrade-aliases.sh 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. #!/usr/bin/env bash
  2. # Copyright 2018 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. # !!!EXPERIMENTAL!!! Upgrade a K8s cluster from routes to IP aliases for
  16. # node connectivity on GCE. This is only for migration.
  17. set -o errexit
  18. set -o nounset
  19. set -o pipefail
  20. if [[ "${KUBERNETES_PROVIDER:-gce}" != "gce" ]]; then
  21. echo "ERR: KUBERNETES_PROVIDER must be gce" >&2
  22. exit 1
  23. fi
  24. KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/../..
  25. source "${KUBE_ROOT}/hack/lib/util.sh"
  26. source "${KUBE_ROOT}/cluster/kube-util.sh"
  27. # Print the number of routes used for K8s cluster node connectivity.
  28. #
  29. # Assumed vars:
  30. # PROJECT
  31. function get-k8s-node-routes-count() {
  32. local k8s_node_routes_count
  33. k8s_node_routes_count=$(gcloud compute routes list \
  34. --project="${PROJECT}" --filter='description=k8s-node-route' \
  35. --format='value(name)' | wc -l)
  36. echo -n "${k8s_node_routes_count}"
  37. }
  38. # Detect the subnetwork where the K8s cluster resides.
  39. #
  40. # Assumed vars:
  41. # KUBE_MASTER
  42. # PROJECT
  43. # ZONE
  44. # Vars set:
  45. # IP_ALIAS_SUBNETWORK
  46. function detect-k8s-subnetwork() {
  47. local subnetwork_url
  48. subnetwork_url=$(gcloud compute instances describe \
  49. "${KUBE_MASTER}" --project="${PROJECT}" --zone="${ZONE}" \
  50. --format='value(networkInterfaces[0].subnetwork)')
  51. if [[ -n ${subnetwork_url} ]]; then
  52. IP_ALIAS_SUBNETWORK=${subnetwork_url##*/}
  53. fi
  54. }
  55. # Set IP_ALIAS_SUBNETWORK's allowSubnetCidrRoutesOverlap to a boolean value.
  56. # $1: true or false for the desired allowSubnetCidrRoutesOverlap.
  57. #
  58. # Assumed vars:
  59. # IP_ALIAS_SUBNETWORK
  60. # GCE_API_ENDPOINT
  61. # PROJECT
  62. # REGION
  63. function set-allow-subnet-cidr-routes-overlap() {
  64. local allow_subnet_cidr_routes_overlap
  65. allow_subnet_cidr_routes_overlap=$(gcloud compute networks subnets \
  66. describe "${IP_ALIAS_SUBNETWORK}" --project="${PROJECT}" --region="${REGION}" \
  67. --format='value(allowSubnetCidrRoutesOverlap)')
  68. local allow_overlap=$1
  69. if [ "${allow_subnet_cidr_routes_overlap,,}" = "${allow_overlap}" ]; then
  70. echo "Subnet ${IP_ALIAS_SUBNETWORK}'s allowSubnetCidrRoutesOverlap is already set as $1"
  71. return
  72. fi
  73. echo "Setting subnet \"${IP_ALIAS_SUBNETWORK}\" allowSubnetCidrRoutesOverlap to $1"
  74. local fingerprint
  75. fingerprint=$(gcloud compute networks subnets describe \
  76. "${IP_ALIAS_SUBNETWORK}" --project="${PROJECT}" --region="${REGION}" \
  77. --format='value(fingerprint)')
  78. local access_token
  79. access_token=$(gcloud auth print-access-token)
  80. local request="{\"allowSubnetCidrRoutesOverlap\":$1, \"fingerprint\":\"${fingerprint}\"}"
  81. local subnetwork_url
  82. subnetwork_url="${GCE_API_ENDPOINT}projects/${PROJECT}/regions/${REGION}/subnetworks/${IP_ALIAS_SUBNETWORK}"
  83. until curl -s --header "Content-Type: application/json" --header "Authorization: Bearer ${access_token}" \
  84. -X PATCH -d "${request}" "${subnetwork_url}" --output /dev/null; do
  85. printf "."
  86. sleep 1
  87. done
  88. }
  89. # Add secondary ranges to K8s subnet.
  90. #
  91. # Assumed vars:
  92. # IP_ALIAS_SUBNETWORK
  93. # PROJECT
  94. # REGION
  95. # CLUSTER_IP_RANGE
  96. # SERVICE_CLUSTER_IP_RANGE
  97. function add-k8s-subnet-secondary-ranges() {
  98. local secondary_ranges
  99. secondary_ranges=$(gcloud compute networks subnets describe "${IP_ALIAS_SUBNETWORK}" \
  100. --project="${PROJECT}" --region="${REGION}" \
  101. --format='value(secondaryIpRanges)')
  102. if [[ "${secondary_ranges}" =~ "pods-default" && "${secondary_ranges}" =~ "services-default" ]]; then
  103. echo "${secondary_ranges} already contains both pods-default and services-default secondary ranges"
  104. return
  105. fi
  106. echo "Adding secondary ranges: pods-default (${CLUSTER_IP_RANGE}), services-default (${SERVICE_CLUSTER_IP_RANGE})"
  107. until gcloud compute networks subnets update "${IP_ALIAS_SUBNETWORK}" \
  108. --project="${PROJECT}" --region="${REGION}" \
  109. --add-secondary-ranges="pods-default=${CLUSTER_IP_RANGE},services-default=${SERVICE_CLUSTER_IP_RANGE}"; do
  110. printf "."
  111. sleep 1
  112. done
  113. }
  114. # Delete all K8s node routes.
  115. #
  116. # Assumed vars:
  117. # PROJECT
  118. function delete-k8s-node-routes() {
  119. local -a routes
  120. local -r batch=200
  121. routes=()
  122. while IFS=$'\n' read -r route; do
  123. routes+=( "${route}" )
  124. done < <(gcloud compute routes list \
  125. --project="${PROJECT}" --filter='description=k8s-node-route' \
  126. --format='value(name)')
  127. while (( "${#routes[@]}" > 0 )); do
  128. echo Deleting k8s node routes "${routes[*]::${batch}}"
  129. gcloud compute routes delete --project "${PROJECT}" --quiet "${routes[@]::${batch}}"
  130. routes=( "${routes[@]:${batch}}" )
  131. done
  132. }
  133. detect-project
  134. detect-master
  135. k8s_node_routes_count=$(get-k8s-node-routes-count)
  136. if [[ "${k8s_node_routes_count}" -eq 0 ]]; then
  137. echo "No k8s node routes found and IP alias should already be enabled. Exiting..."
  138. exit 0
  139. fi
  140. echo "Found ${k8s_node_routes_count} K8s node routes. Proceeding to upgrade them to IP aliases based connectivity..."
  141. detect-k8s-subnetwork
  142. if [ -z "${IP_ALIAS_SUBNETWORK}" ]; then
  143. echo "No k8s cluster subnetwork found. Exiting..."
  144. exit 1
  145. fi
  146. echo "k8s cluster sits on subnetwork \"${IP_ALIAS_SUBNETWORK}\""
  147. set-allow-subnet-cidr-routes-overlap true
  148. add-k8s-subnet-secondary-ranges
  149. echo "Changing K8s master envs and restarting..."
  150. export KUBE_GCE_IP_ALIAS_SUBNETWORK=${IP_ALIAS_SUBNETWORK}
  151. export KUBE_GCE_NODE_IPAM_MODE="IPAMFromCluster"
  152. export KUBE_GCE_ENABLE_IP_ALIASES=true
  153. export SECONDARY_RANGE_NAME="pods-default"
  154. export STORAGE_BACKEND="etcd3"
  155. export STORAGE_MEDIA_TYPE="application/vnd.kubernetes.protobuf"
  156. export ETCD_IMAGE=3.3.10-1
  157. export ETCD_VERSION=3.3.10
  158. # Upgrade master with updated kube envs
  159. "${KUBE_ROOT}/cluster/gce/upgrade.sh" -M -l
  160. delete-k8s-node-routes
  161. set-allow-subnet-cidr-routes-overlap false