#!/bin/bash # Copyright 2018 PingCAP, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # See the License for the specific language governing permissions and # limitations under the License. #* --------------------------------------------------------------------- */ #* log configure */ #* --------------------------------------------------------------------- */ ### Define logging color COLOR_ORIGIN="\033[0m" COLOR_GREEN="\033[32m" COLOR_YELLOW="\033[33m" COLOR_RED="\033[31m" ### Define logging level LOGGER_LEVEL="3" ### Define common logger function logger() { cur_level=$1 cur_type=$2 cur_color=$3 shift && shift && shift cur_msg=$* [[ ${LOGGER_LEVEL} -lt ${cur_level} ]] && return 0 pre_fix="${cur_color}[${cur_type}][$(date +%F)][$(date +%T)]" pos_fix="${COLOR_ORIGIN}" echo -e "${pre_fix} ${cur_msg} ${pos_fix}" } ### Define notice logger function notice() { logger 3 "NOTICE" ${COLOR_GREEN} $* } ### Define warning logger function warning() { logger 2 "WARNING" ${COLOR_YELLOW} $* } ### Define fatal logger function fatal() { logger 1 "FATAL" ${COLOR_RED} $* exit 1 } ########################################################################## function print_help() { echo "\ ${1:-Debug tool for container.} Usage: container_debug [OPTIONS] [ARG] Options: -i The container's identity, possible values are 'containerID' or 'containerName' -s The service name defined in docker-compose -w Run pprof via a web interface for go program -p The binary path of the debugged process in its own container -h Print help infomation When you enter the debug container, you can find the pid of the debugged process through the ps command, then you can find the binary of the debugged process through this path /proc/\${pid}/root/\${binary_path}. \${binary_path} represents the binary path of the debugged process in its own container. \${pid} represents the process id of the debugged process as seen in the debug container. " >&2 exit } ###############################variable define################################## WORKSPACE=$(cd $(dirname $0)/..; pwd) DEBUG_IMAGE=${DEBUG_IMAGE:-uhub.service.ucloud.cn/pingcap/tidb-debug:latest} SUFFIX=$(uuidgen|cut -d'-' -f1|tr '[A-Z]' '[a-z]') DEBUG_CONTAINER_NAME=debug-${SUFFIX} TMP_FILE=$(mktemp /tmp/binary.XXXXXX) ################################################################################ if [[ $# -eq 0 ]] then print_help fi function cleanup() { notice "start to clean tmp file ${TMP_FILE}" [[ -f ${TMP_FILE} ]] && rm -f ${TMP_FILE} } ### register signal processing function trap cleanup EXIT ### change workspace cd $WORKSPACE optstring=":i:s:p:wh" while getopts "$optstring" opt; do case $opt in i) container_id=${OPTARG} ;; s) service_name=${OPTARG} ;; p) binary_path=${OPTARG} ;; w) web=true ;; h) print_help ;; \?) fatal "Invalid option: -$OPTARG" >&2 ;; :) fatal "Option -$OPTARG requires an argument" >&2 ;; esac done if [[ -z ${service_name} && -z ${container_id} ]] then fatal "please use -s or -i options to select the target container" >&2 elif [[ ! -z ${container_id} ]] then ### If both -s and -i options are specified, the -i option is preferred cid=${container_id} else cprefix=$(basename $(pwd)|tr -Cd '[A-Za-z0-9]'|tr '[A-Z]' '[a-z]') cid="${cprefix}_${service_name}_1" docker ps | grep ${cid} >/dev/null [[ $? -ne 0 ]] && fatal "not found docker-compose service ${service_name}, please confirm the correct docker-compose service name" >&2 fi if [[ ! -z ${binary_path} ]] then binary_name=$(basename ${binary_path}) docker cp ${cid}:${binary_path} ${TMP_FILE} if [[ $? -ne 0 ]] then ### not found binary in container, reset variable ${binary_name} binary_name= warning "not found ${binary_path} in container ${cid}, please specify the correct binary path in container" >&2 fi fi if [[ ! -z ${web} ]] then ### starts a web server for graphic visualizations of golang program profiles ### generate a random web port ### TODO: Test whether this port has been used wport=${RANDOM} [[ ${wport} -lt 10000 ]] && wport=$((wport+10000)) ### get the container exposed port cport=$(docker port ${cid}|grep -E '[0-9]{5}'|awk -F: '{print $NF}') notice "starts a web server on localhost:${wport}" pprof -http=:${wport} ${TMP_FILE} http://localhost:${cport}/debug/pprof/profile else ### enter debug container to debug the specified container docker_run_args=(-ti --rm --name=${DEBUG_CONTAINER_NAME}) docker_run_args+=(--pid=container:${cid}) docker_run_args+=(--network=container:${cid}) docker_run_args+=(--ipc=container:${cid}) docker_run_args+=(--cap-add=SYS_PTRACE) docker_run_args+=(--privileged=true) if [[ ! -z ${binary_name} && -e ${TMP_FILE} ]] then docker_run_args+=(-v ${TMP_FILE}:/${binary_name}) else notice "you can access the debugged container ${cid} file system through this path /proc/\${DEBUGGED_PROCESS_PID}/root" fi docker_run_args+=($DEBUG_IMAGE) docker run ${docker_run_args[@]} fi