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
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.nameandio.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.nameandio.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.
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
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.
Please note the dependency on alias=(cpidsearch)
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.nameandio.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.nameandio.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.
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
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 ./
}