grab-profiles.sh 8.3 KB

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