grab-profiles.sh 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. #!/usr/bin/env bash
  2. # Copyright 2015 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. # This script grabs profiles from running components.
  16. # Usage: `hack/grab-profiles.sh`.
  17. set -o errexit
  18. set -o nounset
  19. set -o pipefail
  20. function grab_profiles_from_component {
  21. local requested_profiles=$1
  22. local mem_pprof_flags=$2
  23. local binary=$3
  24. local tunnel_port=$4
  25. local path=$5
  26. local output_prefix=$6
  27. local timestamp=$7
  28. echo "binary: $binary"
  29. for profile in ${requested_profiles}; do
  30. case ${profile} in
  31. cpu)
  32. go tool pprof "-pdf" "${binary}" "http://localhost:${tunnel_port}${path}/debug/pprof/profile" > "${output_prefix}-${profile}-profile-${timestamp}.pdf"
  33. ;;
  34. mem)
  35. # There are different kinds of memory profiles that are available that
  36. # had to be grabbed separately: --inuse-space, --inuse-objects,
  37. # --alloc-space, --alloc-objects. We need to iterate over all requested
  38. # kinds.
  39. for flag in ${mem_pprof_flags}; do
  40. go tool pprof "-${flag}" "-pdf" "${binary}" "http://localhost:${tunnel_port}${path}/debug/pprof/heap" > "${output_prefix}-${profile}-${flag}-profile-${timestamp}.pdf"
  41. done
  42. ;;
  43. esac
  44. done
  45. }
  46. KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
  47. source "${KUBE_ROOT}/hack/lib/init.sh"
  48. server_addr=""
  49. kubelet_addresses=""
  50. kubelet_binary=""
  51. master_binary=""
  52. scheduler_binary=""
  53. scheduler_port="10251"
  54. controller_manager_port="10252"
  55. controller_manager_binary=""
  56. requested_profiles=""
  57. mem_pprof_flags=""
  58. profile_components=""
  59. output_dir="."
  60. tunnel_port="${tunnel_port:-1234}"
  61. args=$(getopt -o s:mho:k:c -l server:,master,heapster,output:,kubelet:,scheduler,controller-manager,help,inuse-space,inuse-objects,alloc-space,alloc-objects,cpu,kubelet-binary:,master-binary:,scheduler-binary:,controller-manager-binary:,scheduler-port:,controller-manager-port: -- "$@")
  62. if [[ $? ]]; then
  63. >&2 echo "Error in getopt"
  64. exit 1
  65. fi
  66. HEAPSTER_VERSION="v0.18.2"
  67. MASTER_PPROF_PATH=""
  68. HEAPSTER_PPROF_PATH="/api/v1/namespaces/kube-system/services/monitoring-heapster/proxy"
  69. KUBELET_PPROF_PATH_PREFIX="/api/v1/proxy/nodes"
  70. SCHEDULER_PPROF_PATH_PREFIX="/api/v1/namespaces/kube-system/pods/kube-scheduler/proxy"
  71. CONTROLLER_MANAGER_PPROF_PATH_PREFIX="/api/v1/namespaces/kube-system/pods/kube-controller-manager/proxy"
  72. eval set -- "${args}"
  73. while true; do
  74. case $1 in
  75. -s|--server)
  76. shift
  77. if [ -z "$1" ]; then
  78. >&2 echo "empty argument to --server flag"
  79. exit 1
  80. fi
  81. server_addr=$1
  82. shift
  83. ;;
  84. -m|--master)
  85. shift
  86. profile_components="master ${profile_components}"
  87. ;;
  88. --master-binary)
  89. shift
  90. if [ -z "$1" ]; then
  91. >&2 echo "empty argument to --master-binary flag"
  92. exit 1
  93. fi
  94. master_binary=$1
  95. shift
  96. ;;
  97. -h|--heapster)
  98. shift
  99. profile_components="heapster ${profile_components}"
  100. ;;
  101. -k|--kubelet)
  102. shift
  103. profile_components="kubelet ${profile_components}"
  104. if [ -z "$1" ]; then
  105. >&2 echo "empty argument to --kubelet flag"
  106. exit 1
  107. fi
  108. kubelet_addresses="$1 $kubelet_addresses"
  109. shift
  110. ;;
  111. --kubelet-binary)
  112. shift
  113. if [ -z "$1" ]; then
  114. >&2 echo "empty argument to --kubelet-binary flag"
  115. exit 1
  116. fi
  117. kubelet_binary=$1
  118. shift
  119. ;;
  120. --scheduler)
  121. shift
  122. profile_components="scheduler ${profile_components}"
  123. ;;
  124. --scheduler-binary)
  125. shift
  126. if [ -z "$1" ]; then
  127. >&2 echo "empty argument to --scheduler-binary flag"
  128. exit 1
  129. fi
  130. scheduler_binary=$1
  131. shift
  132. ;;
  133. --scheduler-port)
  134. shift
  135. if [ -z "$1" ]; then
  136. >&2 echo "empty argument to --scheduler-port flag"
  137. exit 1
  138. fi
  139. scheduler_port=$1
  140. shift
  141. ;;
  142. -c|--controller-manager)
  143. shift
  144. profile_components="controller-manager ${profile_components}"
  145. ;;
  146. --controller-manager-binary)
  147. shift
  148. if [ -z "$1" ]; then
  149. >&2 echo "empty argument to --controller-manager-binary flag"
  150. exit 1
  151. fi
  152. controller_manager_binary=$1
  153. shift
  154. ;;
  155. --controller-manager-port)
  156. shift
  157. if [ -z "$1" ]; then
  158. >&2 echo "empty argument to --controller-manager-port flag"
  159. exit 1
  160. fi
  161. controller_manager_port=$1
  162. shift
  163. ;;
  164. -o|--output)
  165. shift
  166. if [ -z "$1" ]; then
  167. >&2 echo "empty argument to --output flag"
  168. exit 1
  169. fi
  170. output_dir=$1
  171. shift
  172. ;;
  173. --inuse-space)
  174. shift
  175. requested_profiles="mem ${requested_profiles}"
  176. mem_pprof_flags="inuse_space ${mem_pprof_flags}"
  177. ;;
  178. --inuse-objects)
  179. shift
  180. requested_profiles="mem ${requested_profiles}"
  181. mem_pprof_flags="inuse_objects ${mem_pprof_flags}"
  182. ;;
  183. --alloc-space)
  184. shift
  185. requested_profiles="mem ${requested_profiles}"
  186. mem_pprof_flags="alloc_space ${mem_pprof_flags}"
  187. ;;
  188. --alloc-objects)
  189. shift
  190. requested_profiles="mem ${requested_profiles}"
  191. mem_pprof_flags="alloc_objects ${mem_pprof_flags}"
  192. ;;
  193. --cpu)
  194. shift
  195. requested_profiles="cpu ${requested_profiles}"
  196. ;;
  197. --help)
  198. shift
  199. echo "Recognized options:
  200. -o/--output,
  201. -s/--server,
  202. -m/--master,
  203. -h/--heapster,
  204. --inuse-space,
  205. --inuse-objects,
  206. --alloc-space,
  207. --alloc-objects,
  208. --cpu,
  209. --help"
  210. exit 0
  211. ;;
  212. --)
  213. shift
  214. break;
  215. ;;
  216. esac
  217. done
  218. if [[ -z "${server_addr}" ]]; then
  219. >&2 echo "Server flag is required"
  220. exit 1
  221. fi
  222. if [[ -z "${profile_components}" ]]; then
  223. >&2 echo "Choose at least one component to profile"
  224. exit 1
  225. fi
  226. if [[ -z "${requested_profiles}" ]]; then
  227. >&2 echo "Choose at least one profiling option"
  228. exit 1
  229. fi
  230. gcloud compute ssh "${server_addr}" --ssh-flag=-nN --ssh-flag=-L"${tunnel_port}":localhost:8080 &
  231. echo "Waiting for tunnel to be created..."
  232. kube::util::wait_for_url http://localhost:"${tunnel_port}"/healthz
  233. SSH_PID=$(pgrep -f "/usr/bin/ssh.*${tunnel_port}:localhost:8080")
  234. kube::util::trap_add "kill $SSH_PID" EXIT
  235. kube::util::trap_add "kill $SSH_PID" SIGTERM
  236. requested_profiles=$(echo "${requested_profiles}" | xargs -n1 | LC_ALL=C sort -u | xargs)
  237. profile_components=$(echo "${profile_components}" | xargs -n1 | LC_ALL=C sort -u | xargs)
  238. kubelet_addresses=$(echo "${kubelet_addresses}" | xargs -n1 | LC_ALL=C sort -u | xargs)
  239. echo "requested profiles: ${requested_profiles}"
  240. echo "flags for heap profile: ${mem_pprof_flags}"
  241. timestamp=$(date +%Y%m%d%H%M%S)
  242. binary=""
  243. for component in ${profile_components}; do
  244. case ${component} in
  245. master)
  246. path=${MASTER_PPROF_PATH}
  247. binary=${master_binary}
  248. ;;
  249. controller-manager)
  250. path="${CONTROLLER_MANAGER_PPROF_PATH_PREFIX}-${server_addr}:${controller_manager_port}"
  251. binary=${controller_manager_binary}
  252. ;;
  253. scheduler)
  254. path="${SCHEDULER_PPROF_PATH_PREFIX}-${server_addr}:${scheduler_port}"
  255. binary=${scheduler_binary}
  256. ;;
  257. heapster)
  258. rm heapster
  259. wget https://github.com/kubernetes/heapster/releases/download/${HEAPSTER_VERSION}/heapster
  260. kube::util::trap_add 'rm -f heapster' EXIT
  261. kube::util::trap_add 'rm -f heapster' SIGTERM
  262. binary=heapster
  263. path=${HEAPSTER_PPROF_PATH}
  264. ;;
  265. kubelet)
  266. path="${KUBELET_PPROF_PATH_PREFIX}"
  267. if [[ -z "${kubelet_binary}" ]]; then
  268. binary="${KUBE_ROOT}/_output/local/bin/linux/amd64/kubelet"
  269. else
  270. binary=${kubelet_binary}
  271. fi
  272. ;;
  273. esac
  274. if [[ "${component}" == "kubelet" ]]; then
  275. for node in ${kubelet_addresses//[,;]/' '}; do
  276. grab_profiles_from_component "${requested_profiles}" "${mem_pprof_flags}" "${binary}" "${tunnel_port}" "${path}/${node}/proxy" "${output_dir}/${component}" "${timestamp}"
  277. done
  278. else
  279. grab_profiles_from_component "${requested_profiles}" "${mem_pprof_flags}" "${binary}" "${tunnel_port}" "${path}" "${output_dir}/${component}" "${timestamp}"
  280. fi
  281. done