Skip to content

Instantly share code, notes, and snippets.

@peixian
Created April 18, 2023 22:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peixian/a26e733625baddd0be48648a69bf89a8 to your computer and use it in GitHub Desktop.
Save peixian/a26e733625baddd0be48648a69bf89a8 to your computer and use it in GitHub Desktop.
#!/bin/bash
#########################################################################################################################################
# This file takes in a kubectl context, namespace, pod selector, and erlang cookie and opens a non-hidden connection to the target pod. #
# It assumes that your deploy uses the pod IP as an IP address and atom, in the shape of :"SERVICE@<INTERNAL_KUBE_IP>" #
# It modifies either `iptables` or `pfctl` depending on your system. #
# Sources: #
# - https://quan.io/2019/09/02/using-erlangs-observer-in-kubernetes-for-an-elixir-release/ #
# - https://gist.github.com/avocade/2fe5f6c01832154eb51f05a2fef692ce #
# - https://www.openbsdhandbook.com/pf/cheat_sheet/ #
#########################################################################################################################################
set -e
function cleanup {
echo " - Stopping kubectl proxy."
kill $! &> /dev/null
}
trap cleanup EXIT
while getopts "n:l:c:ec:u:" opt; do
case "$opt" in
n) K8S_NAMESPACE="--namespace=${OPTARG}"
;;
l) K8S_SELECTOR=${OPTARG}
;;
c) K8S_CONTEXT=${OPTARG}
;;
ec) ERL_COOKIE=${OPTARG}
;;
u) ERL_USER=${OPTARG}
esac
done
if [ ! $ERL_COOKIE ]; then
ERL_COOKIE=""
fi
# Required part of config
if [ ! $K8S_SELECTOR ]; then
echo "[E] You need to specify Kubernetes selector with '-l' option."
exit 1
fi
echo " - Selecting pod with '-l ${K8S_SELECTOR} ${K8S_NAMESPACE:-default}' selector."
POD_NAME=$(kubectl get pods --context ${K8S_CONTEXT} -l ${K8S_SELECTOR} ${K8S_NAMESPACE} -o jsonpath='{.items[0].metadata.name}')
echo " - Resolving Erlang node port on a pod '${POD_NAME}'."
EPMD_OUTPUT=$(echo ${POD_NAME} | xargs -o -I my_pod kubectl --context ${K8S_CONTEXT} exec my_pod ${K8S_NAMESPACE} -i -t -- /app/erts-13.1.2/bin/epmd -names | tail -n 1)
echo " - Got output from epmd: "
echo " - ${EPMD_OUTPUT}"
eval 'EPMD_OUTPUT=($EPMD_OUTPUT)'
if [ ! $ERL_USER ]; then
RANDOM_SUFFIX=$(echo $RANDOM | md5sum | head -c 4)
ERL_USER="debug-${RANDOM_SUFFIX}"
fi
# Strip newlines from last element of output
OTP_PORT=${EPMD_OUTPUT[4]//[$'\t\r\n ']}
echo " - Connecting on port ${OTP_PORT} as user '${ERL_USER}' with cookie '${ERL_COOKIE}'."
# Kill epmd on local node to free 4369 port
killall epmd || true
# Replace it with remote nodes epmd and proxy remove erlang app port
echo "kubectl --context ${K8S_CONTEXT} port-forward ${POD_NAME} ${K8S_NAMESPACE} 4369 ${OTP_PORT}"
kubectl --context ${K8S_CONTEXT} port-forward $POD_NAME $K8S_NAMESPACE 4369 $OTP_PORT &
sleep 1
echo "kubectl --context ${K8S_CONTEXT} get pod ${POD_NAME} -n ${K8S_NAMESPACE} --template '{{.status.podIP}}'"
POD_IP=$(kubectl --context ${K8S_CONTEXT} get pod ${POD_NAME} ${K8S_NAMESPACE} --template '{{.status.podIP}}')
POD_DEPLOYMENT=$(kubectl --context ${K8S_CONTEXT} get pod ${POD_NAME} ${K8S_NAMESPACE} --template '{{.spec.subdomain}}')
ERLANG_NODE="${POD_DEPLOYMENT}@${POD_IP}"
echo "connecting to $ERLANG_NODE"
function control_c {
echo -en "\n## Caught SIGINT; Clean up pfctl and Exit \n"
# UNCOMMENT THE FOLLOWING LINE FOR LINUX
# sudo iptables -t nat -D OUTPUT -d 10.90.4.143 -j DNAT --to-destination 127.0.0.1
# UNCOMMENT THE FOLLOWING LINE FOR BSD
sudo pfctl -f /etc/pf.conf
rm ./tmp_pf_rule.conf
exit $?
}
trap control_c SIGINT
trap control_c SIGTERM
# UNCOMMENT THE FOLLOWING LINES FOR LINUX
# --------------------------------------
# echo "Setting IP tables"
# sudo iptables -t nat -A OUTPUT -d 10.90.4.143 -j DNAT --to-destination 127.0.0.1
# USE THE FOLLOWING LINES FOR BSD SYSTEMS
# ---------------------------------------
echo "Enabling pcftl"
sudo pfctl -E || true
echo "Setting new rule on pfctl"
sudo ifconfig lo0 alias $POD_IP
echo "rdr pass on lo0 inet proto tcp from any to $POD_IP port 4369 -> 127.0.0.1" > ./tmp_pf_rule.conf
echo "rdr pass on lo0 inet proto tcp from any to $POD_IP port $OTP_PORT -> 127.0.0.1" >> ./tmp_pf_rule.conf
sudo pfctl -f /etc/pf.conf -f tmp_pf_rule.conf
# Start the iex session
echo "iex --name $ERL_USER@$POD_IP --cookie $ERL_COOKIE --hidden -e \"Node.connect(:\"$ERLANG_NODE\"); :observer.start\""
iex --name $ERL_USER@$POD_IP --cookie $ERL_COOKIE --hidden -e "Node.connect(:\"$ERLANG_NODE\"); :observer.start"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment