Skip to main content

5.1.5.2. Aliases

This section will be useful for optimizing connection requests. Let's look at several options for connecting to the ETCD cluster.

  • (alias=cidsearch) Container ID lookup
  • (alias=cpidsearch) Container PID lookup
  • (alias=etcdctl) Direct connection
  • (alias=ectl) Connection via crictl
  • (alias=nectl) Connection via nsenter
  • (alias=kectl) Connection via kubelet
Note

Please note that all commands except section 5.1.5.2.5 (Connection via kubectl) are executed on nodes where the ETCD instance is deployed.

5.1.5.2.1. Container ID lookup

This alias helps quickly find the container ID by labels io.kubernetes.pod.name and io.kubernetes.pod.namespace

cidsearch() {
crictl ps \
--label io.kubernetes.pod.name="$1" \
--label io.kubernetes.pod.namespace="$2" \
-o json | jq -r '.containers[].id'
}

5.1.5.2.2. Container PID lookup

This alias helps quickly find the container PID by labels io.kubernetes.container.name and io.kubernetes.pod.namespace

cpidsearch() {
crictl inspect \
$(cidsearch "$1" "$2") | jq .info.pid
}

5.1.5.2.3. Direct connection

Direct connection is suitable when we know which node the ETCD instance is on, and the certificates are in the host filesystem.

Connection

alias etcdctl='etcdctl \
--cert=/etc/kubernetes/pki/etcd/peer.crt \
--key=/etc/kubernetes/pki/etcd/peer.key \
--cacert=/etc/kubernetes/pki/etcd/ca.crt'

Cluster member list

etcdctlMembers() {
etcdctl member list \
--write-out=json | jq \
-r '[.members[].clientURLs[]] | join(",")'
}

Current revision

etcdctlRevision() {
etcdctl \
--endpoints=$(etcdctlMembers) \
endpoint status \
-w json | jq \
-r .[].Status.header.revision
}

Connection

alias etcdctl='etcdctl \
--cert=/etc/kubernetes/pki/etcd/peer.crt \
--key=/etc/kubernetes/pki/etcd/peer.key \
--cacert=/etc/kubernetes/pki/etcd/ca.crt'

Compaction

alias etcdctlCompaction='etcdctl \
--endpoints=$(etcdctlMembers) \
compaction $(etcdctlRevision)'

Defragmentation

alias etcdctlDefrag='etcdctl \
--endpoints=$(etcdctlMembers) \
defrag'

5.1.5.2.4. Connection via crictl

Connection via container is suitable when the application is running as a container and all data is mounted inside the container filesystem.

Note

To ensure requests are sent to the correct container, specify the Namespace and PodName you want to interact with.

export SEARCH_NAMESPACE=undefined
export SEARCH_POD_NAME=undefined
info

Please note the dependency on alias=(cidsearch, ectlflagsearch) listed below

Container ID lookup

cidsearch() {
crictl ps \
--label io.kubernetes.pod.name="$1" \
--label io.kubernetes.pod.namespace="$2" \
-o json | jq -r '.containers[].id'
}

Flags for connecting to etcdctl

alias function that substitutes flags specifying the PEER certificate, PEER key, ETCD cluster CA certificate, and ENDPOINT.

ectlflagsearch() {
ETCD_ARGS=$( \
crictl inspect $(cidsearch "$1" "$2") | jq -r \
'.info.runtimeSpec.process.args[]' ) ; \
echo -n \
'--cert='$(grep --\
'--peer-cert-file=' <<< $ETCD_ARGS | sed 's/[^=]*=//') \
'--key='$(grep --\
'--peer-key-file=' <<< $ETCD_ARGS | sed 's/[^=]*=//') \
'--cacert='$(grep --\
'--trusted-ca-file=' <<< $ETCD_ARGS | sed 's/[^=]*=//') \
'--endpoints='$(grep --\
'--advertise-client-urls=' <<< $ETCD_ARGS | sed 's/[^=]*=//')
}

Connection

alias ectl='crictl exec \
-ti $(cidsearch ${SEARCH_POD_NAME} ${SEARCH_NAMESPACE}) \
etcdctl \
$(ectlflagsearch ${SEARCH_POD_NAME} ${SEARCH_NAMESPACE})'

Cluster member list

ectlMembers() {
ectl member list \
--write-out=json | jq \
-r '[.members[].clientURLs[]] | join(",")'
}

Current revision

ectlRevision() {
ectl \
endpoint status \
--cluster \
-w json | jq -r \
'[.[].Status.header.revision] | join(" ")'
}

Compaction

alias ectlCompaction='ectl \
compaction $(ectlRevision) \
--cluster'

Defragmentation

alias ectlDefrag='ectl \
defrag \
--cluster'

5.1.5.2.5. Connection via nsenter

To use etcdctl located inside the process namespace of a running container, you first need to get the CONTAINER_ID. Based on this identifier, you can determine the process PID. Next, we'll create a nectl alias (to avoid conflicts with other aliases). Each time this alias is called, we'll update the data about the current container and process. It's also important to specify the path to the certificates.

info

Please note the dependency on alias=(cpidsearch)

Note

To ensure requests are sent to the correct container, specify the Namespace and PodName you want to interact with.

export SEARCH_NAMESPACE=undefined
export SEARCH_POD_NAME=undefined

Container ID lookup

This alias helps quickly find the container ID by labels io.kubernetes.container.name and io.kubernetes.pod.namespace

cidsearch() {
crictl ps \
--label io.kubernetes.pod.name="$1" \
--label io.kubernetes.pod.namespace="$2" \
-o json | jq -r '.containers[].id'
}

Container PID lookup

This alias helps quickly find the container PID by labels io.kubernetes.container.name and io.kubernetes.pod.namespace

cpidsearch() {
crictl inspect \
$(cidsearch "$1" "$2") | jq .info.pid
}

Cluster member list

nectlMembers() {
nectl member list \
--write-out=json | jq \
-r '[.members[].clientURLs[]] | join(",")'
}

Current revision

nectlMembers() {
nectl member list \
--write-out=json | jq \
-r '[.members[].clientURLs[]] | join(",")'
}

Connection

alias nectl='nsenter \
-m -n -t \
$(cpidsearch ${SEARCH_CONTAINER_NAME} ${SEARCH_NAMESPACE}) \
etcdctl \
--cert=/etc/kubernetes/pki/etcd/peer.crt \
--key=/etc/kubernetes/pki/etcd/peer.key \
--cacert=/etc/kubernetes/pki/etcd/ca.crt'

Compaction

alias nectlCompaction='nectl \
--endpoints=$(nectlMembers) \
compaction $(nectlRevision)'

Defragmentation

alias nectlDefrag='nectl \
--endpoints=$(nectlMembers) \
defrag'

5.1.5.2.5. Connection via kubectl

Connection via kubectl is suitable when the application is running as a pod in the k8s cluster, all data is mounted inside the container filesystem, and operations are performed through kube-api.

Note

To ensure requests are sent to the correct container, specify the Namespace and PodName you want to interact with.

export SEARCH_NAMESPACE=undefined
export SEARCH_POD_NAME=undefined
info

Please note the dependency on alias=(kectlflagsearch) listed below

Flags for connecting to kectl

alias function that substitutes flags specifying the PEER certificate, PEER key, ETCD cluster CA certificate, and ENDPOINT.

kectlflagsearch() {
ETCD_ARGS=$( kubectl get pod \
-n ${SEARCH_NAMESPACE} \
${SEARCH_POD_NAME} \
-o yaml) ; \
echo -n \
'--cert='$(grep --\
'--peer-cert-file=' <<< $ETCD_ARGS | sed 's/[^=]*=//') \
'--key='$(grep --\
'--peer-key-file=' <<< $ETCD_ARGS | sed 's/[^=]*=//') \
'--cacert='$(grep --\
'--trusted-ca-file=' <<< $ETCD_ARGS | sed 's/[^=]*=//') \
'--endpoints='$(grep --\
'--advertise-client-urls=' <<< $ETCD_ARGS |
sed 's/[^=]*=//' |
sed 's/$(POD_NAME)/'${SEARCH_POD_NAME}'/' |
sed 's/$(POD_NAMESPACE)/'${SEARCH_NAMESPACE}'/')
}

Connection

alias kectl='kubectl exec -it \
-n ${SEARCH_NAMESPACE} \
${SEARCH_POD_NAME} \
-- \
etcdctl \
$(kectlflagsearch ${SEARCH_POD_NAME} ${SEARCH_NAMESPACE})'

Cluster member list

kectlMembers() {
kectl member list \
--write-out=json | jq \
-r '[.members[].clientURLs[]] | join(",")'
}

Current revision

kectlRevision() {
kectl \
endpoint status \
--cluster \
-w json | jq -r \
'[.[].Status.header.revision] | join(" ")'
}

Compaction

alias kectlCompaction='kectl \
compaction $(kectlRevision) \
--cluster'

Defragmentation

alias kectlDefrag='kectl \
defrag \
--cluster'

Getting the data-dir path

kgdatadirpath() {
jq -r '.spec.containers[0].command[], .spec.containers[0].args[]? | select(startswith("--data-dir"))' <<< "$(kubectl get pod -n "$1" "$2" -o json)" |
awk -F= '{print $2}' | head -n1
}

Downloading a backup file

This function will download the backup file from the data-dir to the local machine in the current directory.

dlbackupfile() {
local POD_JSON=$(kubectl get pod -n "$1" "$2" -o json)
local DATA_DIR_PATH=$(jq -r '.spec.containers[0].command[], .spec.containers[0].args[]? | select(startswith("--data-dir"))' <<< "$POD_JSON" |
awk -F= '{print $2}' | head -n1)
local MOUNT_PATH=$DATA_DIR_PATH
while [[ -n "$MOUNT_PATH" ]]; do
local MOUNT_NAME=$(jq -r --arg path "$MOUNT_PATH" '.spec.containers[0].volumeMounts[] | select(.mountPath==$path) | .name' <<< "$POD_JSON") ;
[[ -n "$MOUNT_NAME" ]] && break
MOUNT_PATH=${MOUNT_PATH%/*}
done
local VOLUME_JSON=$(jq -r --arg name "$MOUNT_NAME" '.spec.volumes[] | select(.name==$name)' <<< "$POD_JSON")
local NODE_IP=$(kubectl get node "$(jq -r .spec.nodeName <<< "$POD_JSON")" -o json | jq -r '.status.addresses[] | select(.type=="ExternalIP") | .address')
if jq -e '.hostPath' <<< "$VOLUME_JSON" > /dev/null; then
local PVC_MOUNT_PATH=$(jq -r '.hostPath.path' <<< "$VOLUME_JSON")
else
local PVC_NAME=$(jq -r '.persistentVolumeClaim.claimName' <<< "$VOLUME_JSON")
local VOLUME_NAME=$(kubectl get pvc -n "$1" "$PVC_NAME" -o json | jq -r .spec.volumeName)
local PVC_MOUNT_PATH=$(ssh "$3@$NODE_IP" "sudo lsblk -o MOUNTPOINT | grep '$VOLUME_NAME'")
fi
rsync --rsync-path="sudo rsync" $3@$NODE_IP:${PVC_MOUNT_PATH}${DATA_DIR_PATH#"$MOUNT_PATH"}/$4 ./
}