Cette rubrique explique comment utiliser Crash Diagnostics (Crashd) pour diagnostiquer les clusters de charge de travail instables ou ne répondant pas basés sur Photon OS dans Tanzu Kubernetes Grid avec un cluster de gestion autonome.
Pour savoir comment utiliser Crashd pour diagnostiquer les clusters de charge de travail déployés par un superviseur vSphere with Tanzu, reportez-vous à la section Comment collecter un bundle de journaux de diagnostics à partir d'un cluster invité Tanzu Kubernetes sur vSphere with Tanzu dans la base de connaissances VMware.
Crashd examine le cluster de charge de travail de démarrage que le processus tanzu cluster create
crée localement à l'aide de kind
avant de déployer le cluster sur l'infrastructure du cloud.
Crashd est un projet open source qui facilite le dépannage des problèmes de clusters Kubernetes.
Crashd utilise un fichier de script écrit en Starlark, un langage de type Python, qui interagit avec vos clusters de gestion ou de charge de travail pour collecter des informations sur l'infrastructure et le cluster.
Crashd peut collecter des diagnostics à partir des infrastructures prises en charge, notamment :
Crashd récupère la sortie à partir des commandes exécutées par le script et ajoute la sortie à un fichier tar
. Le fichier tar
est ensuite enregistré localement pour une analyse plus approfondie.
Tanzu Kubernetes Grid inclut des fichiers binaires signés pour Crashd et un fichier de script de diagnostics pour les clusters de charge de travail Photon OS.
Pour installer ou mettre à niveau crashd
, suivez les instructions ci-dessous.
Téléchargez Crashd pour votre plate-forme.
Utilisez la commande tar
pour décompresser le fichier binaire pour votre plate-forme.
Linux :
tar -xvf crashd-linux-amd64-v0.3.7-vmware.6.tar.gz
macOS :
tar -xvf crashd-darwin-amd64-v0.3.7-vmware.6.tar.gz
L'étape précédente crée un répertoire nommé crashd
avec les fichiers suivants :
crashd
crashd/args
crashd/diagnostics.crsh
crashd/crashd-PLATFORM-amd64-v0.3.7+vmware.6
Déplacez le fichier binaire dans le dossier /usr/local/bin
.
Linux :
mv ./crashd/crashd-linux-amd64-v0.3.7+vmware.6 /usr/local/bin/crashd
macOS :
mv ./crashd/crashd-darwin-amd64-v0.3.7+vmware.6 /usr/local/bin/crashd
Lorsque Crashd s'exécute, il récupère les valeurs d'argument d'un fichier args
et les transmet à un fichier de script, diagnostics.crsh
. Le script exécute des commandes pour extraire des informations qui peuvent aider à diagnostiquer les problèmes sur les clusters de charge de travail Photon OS.
Avant d'exécuter le script Crashd diagnostics.crsh
, votre machine locale doit avoir les programmes suivants sur son chemin d'exécution :
kubectl
scp
ssh
RemarqueLors de l'examen des problèmes liés à un cluster de démarrage, vous aurez besoin de la commande
kind
(v0.7.0 ou version ultérieure) installée localement.
De plus, avant de pouvoir exécuter Crashd, vous devez suivre les étapes suivantes :
kubeconfig
pour le cluster de gestion à l'aide de la commande tanzu mc kubeconfig get <management-cluster-name>
.kubeconfig
, le fichier public-key
, le fichier diagnostics.crsh
et le fichier args
se trouvent au même emplacement.Supprimez tous les clusters kind
locaux autres que celui qui a été créé pour déployer le cluster de charge de travail que vous dépannez :
docker ps
pour identifier le cluster kind
en cours d'exécution.kind
en exécutant kind delete cluster --name CLUSTER-NAME
.Accédez à l'emplacement dans lequel vous avez téléchargé et décompressé le bundle Crashd.
Dans un éditeur de texte, remplacez le fichier d'arguments existant args
par le code ci-dessous. Ce fichier contient les paires clé/valeur à transmettre au script CrashD :
# ######################################################
# Crashd script argument file
#
# This file defines CLI argument values that are passed
# Crashd when running scripts for troubleshooting TKG
# clusters.
# ######################################################
# target: specifies cluster to target.
# Valid targets are: {bootstrap, mgmt, workload}
target=mgmt
# infra: the underlying infrastructure used by the TKG cluster.
# Valid values are: {vsphere, aws, azure}
infra=vsphere
# workdir: a local directory where collected files are staged.
workdir=./workdir
# ssh_user: the user ID used for SSH connections to cluster nodes.
ssh_user=capv
# ssh_pk_file: the path to the private key file created to SSH
# into cluster nodes.
ssh_pk_file=./capv.pem
# ######################################################
# Management Cluster
# The following arguments are used to collect information
# from a management cluster or named workload clusters.
# ######################################################
# mgmt_cluster_config: the kubeconfig file path for the management cluster.
mgmt_cluster_config=./tkg_cluster_config
# ######################################################
# Workload Cluster
# The following arguments are used to collect information
# from one or more workload clusters that are managed
# by the management cluster configured above.
# ######################################################
# workload_clusters: a comma separated list of workload cluster names
# [uncomment below]
#workload_clusters=tkg-cluster-wc-498
# workload_cluster_ns: the namespace where the workload cluster
# is hosted in the management plane.
# Note: it's actually the namespace in which the secrets/${workload_cluster_name}-kubeconfig
# is created in the management cluster.
# [uncomment below]
#workload_cluster_ns=default
Enregistrez le chemin d'accès local à un fichier de clé privée SSH. Si vous ne disposez pas déjà d'une paire de clés SSH ou si vous souhaitez en générer une nouvelle, exécutez ssh-keygen
comme décrit dans la section Créer une paire de clés SSH. Par exemple :
ssh-keygen -t rsa -b 4096 -C "[email protected]"
Lorsque vous y êtes invité, entrez un chemin d'accès local pour l’emplacement du fichier. Pour plus d’informations sur la création des paires de clés SSH.
Définissez les arguments suivants dans le fichier args
:
target
: Définissez cette valeur sur :
bootstrap
pour diagnostiquer un cluster de gestion autonome de démarrage localmgmt
pour diagnostiquer un cluster de gestion autonome déployéworkload
pour diagnostiquer un ou plusieurs clusters de charge de travailinfra
: Infrastructure sous-jacente de votre cluster : aws
, azure
ou vsphere
.workdir
: Emplacement de collecte des fichiers.ssh_user
: Utilisateur SSH utilisé pour accéder aux machines du cluster. Pour les clusters s'exécutant sur vSphere, le nom d'utilisateur est capv
.ssh_pk_file
: Chemin d’accès à votre fichier de clé privée SSH.mgmt_cluster_config
Chemin du fichier kubeconfig pour le cluster de gestion.Pour diagnostiquer les clusters de charge de travail, annulez la mise en commentaire et définissez les éléments suivants en plus des arguments répertoriés ci-dessus :
workload_clusters
: Liste séparée par des virgules de noms de cluster de charge de travail à partir desquels collecter des informations de diagnostic.workload_cluster_ns
: Espace de noms dans lequel secrets/WORKLOAD-CLUSTER-NAME-kubeconfig
est créé dans le cluster de gestion.Créez un fichier de script Crashd diagnostics.crsh
contenant le code dans le fichier de diagnosticsdiagnostics.crsh
ci-dessous.
Exécutez la commande crashd
à partir de l'emplacement où se trouvent le fichier de script diagnostics.crsh
et le fichier d'argument args
.
crashd run --args-file args diagnostics.crsh
Le cas échéant, vous pouvez surveiller la sortie de Crashd. Par défaut, la commande crashd
s'exécute en silence jusqu'à ce qu'elle se termine. Cependant, vous pouvez utiliser l'indicateur --debug
pour afficher sur l'écran des messages de journal semblables aux messages suivants :
crashd run --debug --args-file args diagnostics.crsh
DEBU[0003] creating working directory ./workdir/tkg-kind-12345
DEBU[0003] kube_capture(what=objects)
DEBU[0003] Searching in 20 groups
...
DEBU[0015] Archiving [./workdir/tkg-kind-12345] in bootstrap.tkg-kind-12345.diagnostics.tar.gz
DEBU[0015] Archived workdir/tkg-kind-12345/kind-logs/docker-info.txt
DEBU[0015] Archived workdir/tkg-kind-12345/kind-logs/tkg-kind-12345-control-plane/alternatives.log
DEBU[0015] Archived workdir/tkg-kind-12345/kind-logs/tkg-kind-12345-control-plane/containerd.log
diagnostics.crsh
Dans le téléchargement du bundle CrashD, remplacez le fichier diagnostics.crsh
existant par le code suivant, en tant que script à transmettre à la commande crashd run
:
def capture_node_diagnostics(nodes):
capture(cmd="sudo df -i", resources=nodes)
capture(cmd="sudo crictl info", resources=nodes)
capture(cmd="df -h /var/lib/containerd", resources=nodes)
capture(cmd="sudo systemctl status kubelet", resources=nodes)
capture(cmd="sudo systemctl status containerd", resources=nodes)
capture(cmd="sudo journalctl -xeu kubelet", resources=nodes)
capture(cmd="sudo journalctl -xeu containerd", resources=nodes)
capture(cmd="sudo cat /var/log/cloud-init-output.log", resources=nodes)
capture(cmd="sudo cat /var/log/cloud-init.log", resources=nodes)
def capture_windows_node_diagnostics(nodes):
capture(cmd="Get-CimInstance -ClassName Win32_LogicalDisk", file_name="disk_info.out", resources=nodes)
capture(cmd="(Get-ItemProperty -Path c:\\windows\\system32\\hal.dll).VersionInfo.FileVersion",file_name="windows_version_info.out", resources=nodes)
capture(cmd="cat C:\\k\\StartKubelet.ps1 ; cat C:\\var\\lib\\kubelet\\kubeadm-flags.env", resources=nodes)
capture(cmd="Get-Service Kubelet | select * ", resources=nodes)
capture(cmd="Get-Service Containerd | select * ", resources=nodes)
capture(cmd="Get-Service ovs* | select * ", resources=nodes)
capture(cmd="Get-Service antrea-agent | select * ", resources=nodes)
capture(cmd="Get-Service kube-proxy | select * ", resources=nodes)
capture(cmd="Get-Service Kubelet | select * ", resources=nodes)
capture(cmd="Get-HNSNetwork", resources=nodes)
capture(cmd="& 'c:\\Program Files\\containerd\\crictl.exe' -r 'npipe:////./pipe/containerd-containerd' info", resources=nodes)
capture(cmd="Get-MpPreference | select ExclusionProcess", resources=nodes)
capture(cmd="cat c:\\var\\log\\kubelet\\kubelet.exe.INFO", resources=nodes)
capture(cmd="cat c:\\var\\log\\antrea\\antrea-agent.exe.INFO", resources=nodes)
capture(cmd="cat c:\\var\\log\\kube-proxy\\kube-proxy.exe.INFO", resources=nodes)
capture(cmd="cat 'c:\\Program Files\\Cloudbase Solutions\\Cloudbase-Init\\log\\cloudbase-init-unattend.log'", resources=nodes)
capture(cmd="cat 'c:\\Program Files\\Cloudbase Solutions\\Cloudbase-Init\\log\\cloudbase-init.log'", resources=nodes)
copy_from(path="C:\\Windows\\System32\\Winevt\\Logs\\System.evtx", resources=nodes)
copy_from(path="C:\\Windows\\System32\\Winevt\\Logs\\Application.evtx", resources=nodes)
copy_from(path="c:\\openvswitch\\var\\log\\openvswitch\\ovs-vswitchd.log", resources=nodes)
copy_from(path="c:\\openvswitch\\var\\log\\openvswitch\\ovsdb-server.log", resources=nodes)
# fetches a suitable capi provider, for either capa or others (capv/capz),
# to be used for enumerating cluster machines
def fetch_provider(iaas, workload_cluster_name, ssh_cfg, kube_cfg, namespace, filter_labels):
# workaround: vsphere and azure use same provider as they work similarly (see issue #162)
if iaas == "vsphere" or iaas == "azure":
provider = capv_provider(
workload_cluster=workload_cluster_name,
namespace=namespace,
ssh_config=ssh_cfg,
mgmt_kube_config=kube_cfg,
labels=filter_labels
)
else:
provider = capa_provider(
workload_cluster=workload_cluster_name,
namespace=namespace,
ssh_config=ssh_cfg,
mgmt_kube_config=kube_cfg,
labels=filter_labels
)
return provider
# retrieves linux management provider for linux nodes
def fetch_mgmt_provider_linux(infra, ssh_cfg, kube_cfg, ns):
return fetch_provider(infra, '', ssh_cfg, kube_cfg, ns, ["kubernetes.io/os=linux"])
# retrieves windows mgmt provider for windows nodes
def fetch_mgmt_provider_windows(infra, ssh_cfg, kube_cfg, ns):
return fetch_provider(infra, '', ssh_cfg, kube_cfg, ns, ["kubernetes.io/os=windows"])
# retrieves linux workload provider for linux nodes
def fetch_workload_provider_linux(infra, wc_cluster, ssh_cfg, kube_cfg, ns):
return fetch_provider(infra, wc_cluster, ssh_cfg, kube_cfg, ns, ["kubernetes.io/os=linux"])
# retrieves windows workload provider for windodws nodes
def fetch_workload_provider_windows(infra, wc_cluster, ssh_cfg, kube_cfg, ns):
return fetch_provider(infra, wc_cluster, ssh_cfg, kube_cfg, ns, ["kubernetes.io/os=windows"])
def diagnose_mgmt_cluster(infra):
# validation
args.ssh_user
args.ssh_pk_file
args.mgmt_cluster_config
if len(infra) == 0:
print("Infra argument not provided")
return
wd = "{}/tkg-mgmt-cluster".format(args.workdir)
conf = crashd_config(workdir=wd)
ssh_conf = ssh_config(username=args.ssh_user, private_key_path=args.ssh_pk_file)
kube_conf = kube_config(path=args.mgmt_cluster_config)
# fetch linux mgmt node diagnostics
mgmt_provider_linux = fetch_mgmt_provider_linux(infra, ssh_conf, kube_conf, '')
lin_nodes = resources(provider=mgmt_provider_linux)
capture_node_diagnostics(lin_nodes)
# fetch win mgmt node diagnostics
mgmt_provider_win = fetch_mgmt_provider_windows(infra, ssh_conf, kube_conf, '')
win_nodes = resources(provider=mgmt_provider_win)
if len(win_nodes) > 0:
capture_windows_node_diagnostics(win_nodes)
#add code to collect pod info from cluster
set_defaults(kube_config(capi_provider = mgmt_provider_linux))
pods_ns=[
"capi-kubeadm-bootstrap-system",
"capi-kubeadm-control-plane-system",
"capi-system",
"capi-webhook-system",
"cert-manager",
"tkg-system",
"kube-system",
"tkr-system",
"capa-system",
"capv-system",
"capz-system",
]
if infra == "vsphere":
pods_ns.append("tkg-system-networking")
pods_ns.append("avi-system")
kube_capture(what="logs", namespaces=pods_ns)
kube_capture(what="objects", kinds=["pods", "services"], namespaces=pods_ns)
kube_capture(what="objects", kinds=["deployments", "replicasets"], groups=["apps"], namespaces=pods_ns)
kube_capture(what="objects", kinds=["apps"], groups=["kappctrl.k14s.io"], namespaces=["tkg-system"])
kube_capture(what="objects", kinds=["tanzukubernetesreleases"], groups=["run.tanzu.vmware.com"])
kube_capture(what="objects", kinds=["configmaps"], namespaces=["tkr-system"])
kube_capture(what="objects", categories=["cluster-api"])
kube_capture(what="objects", groups=["ipam.cluster.x-k8s.io"])
if infra == "vsphere":
kube_capture(what="objects", kinds=["akodeploymentconfigs"])
archive(output_file="tkg-mgmt.diagnostics.tar.gz", source_paths=[conf.workdir])
def diagnose_workload_cluster(infra, name):
# validation
args.infra
args.ssh_user
args.ssh_pk_file
args.mgmt_cluster_config
workload_ns = args.workload_cluster_ns
if len(infra) == 0:
print("Infra argument not provided")
return
wd = "{}/{}".format(args.workdir, name)
conf = crashd_config(workdir=wd)
ssh_conf = ssh_config(username=args.ssh_user, private_key_path=args.ssh_pk_file)
kube_conf = kube_config(path=args.mgmt_cluster_config)
# fetch linux workload node diagnostics
wc_provider_linux = fetch_workload_provider_linux(infra, name, ssh_conf, kube_conf, workload_ns)
lin_nodes = resources(provider=wc_provider_linux)
capture_node_diagnostics(lin_nodes)
# fetch win workload node diagnostics
wc_provider_win = fetch_workload_provider_windows(infra, name, ssh_conf, kube_conf, workload_ns)
win_nodes = resources(provider=wc_provider_win)
if len(win_nodes) > 0:
capture_windows_node_diagnostics(win_nodes)
#add code to collect pod info from cluster
set_defaults(kube_config(capi_provider = wc_provider_linux))
pods_ns=["default", "kube-system", "tkg-system"]
if infra == "vsphere":
pods_ns.append("tkg-system-networking")
pods_ns.append("avi-system")
kube_capture(what="logs", namespaces=pods_ns)
kube_capture(what="objects", kinds=["pods", "services"], namespaces=pods_ns)
kube_capture(what="objects", kinds=["deployments", "replicasets"], groups=["apps"], namespaces=pods_ns)
kube_capture(what="objects", kinds=["apps"], groups=["kappctrl.k14s.io"], namespaces=["tkg-system"])
if infra == "vsphere":
kube_capture(what="objects", kinds=["akodeploymentconfigs"])
archive(output_file="{}.diagnostics.tar.gz".format(name), source_paths=[conf.workdir])
# extract diagnostic info from local kind boostrap cluster
def diagnose_bootstrap_cluster():
p = prog_avail_local("kind")
if p == "":
print("Error: kind is not available")
return
clusters=get_tkg_bootstrap_clusters()
if len(clusters) == 0:
print("No tkg-kind bootstrap cluster found")
return
pod_ns=[
"caip-in-cluster-system",
"capi-kubeadm-bootstrap-system",
"capi-kubeadm-control-plane-system",
"capi-system",
"capi-webhook-system",
"capv-system",
"capa-system",
"capz-system",
"cert-manager",
"tkg-system",
"tkg-system-networking",
"avi-system",
]
# for each tkg-kind cluster:
# - capture kind logs, export kubecfg, and api objects
for kind_cluster in clusters:
wd = "{}/{}".format(args.workdir, kind_cluster)
run_local("kind export logs --name {} {}/kind-logs".format(kind_cluster, wd))
kind_cfg = capture_local(
cmd="kind get kubeconfig --name {0}".format(kind_cluster),
workdir="./",
file_name="{}.kubecfg".format(kind_cluster)
)
conf = crashd_config(workdir=wd)
set_defaults(kube_config(path=kind_cfg))
kube_capture(what="objects", kinds=["pods", "services"], namespaces=pod_ns)
kube_capture(what="objects", kinds=["deployments", "replicasets"], groups=["apps"], namespaces=pod_ns)
kube_capture(what="objects", categories=["cluster-api"])
kube_capture(what="objects", kinds=["akodeploymentconfigs"])
archive(output_file="bootstrap.{}.diagnostics.tar.gz".format(kind_cluster), source_paths=[conf.workdir])
# return tkg clusters in kind (tkg-kind-xxxx)
def get_tkg_bootstrap_clusters():
clusters = run_local("kind get clusters").split('\n')
result = []
for cluster in clusters:
if cluster.startswith("tkg-kind"):
result.append(cluster)
return result
def check_prereqs():
# validate args
args.workdir
p = prog_avail_local("ssh")
if p == "":
print("Error: ssh is not available")
return False
p = prog_avail_local("scp")
if p == "":
print("Error: scp is not available")
return False
p = prog_avail_local("kubectl")
if p == "":
print("Error: kubectl is not available")
return False
return True
def diagnose(target, infra):
# validation
if not check_prereqs():
print("Error: One or more prerequisites are missing")
return
# run diagnostics
if target == "bootstrap":
diagnose_bootstrap_cluster()
elif target == "mgmt":
diagnose_mgmt_cluster(infra)
elif target == "workload":
for name in args.workload_clusters.split(","):
diagnose_workload_cluster(infra, name)
else:
print("Error: unknown target {}".format(target))
diagnose(args.target, args.infra)