1. Docs
  2. Self-Hosted
  3. Troubleshooting

Troubleshooting Kubernetes

We provide a read-only script k8s-diagnostics-collector.sh that collects Kubernetes logs, events, and API objects from a single namespace. It packages everything into a .tar.gz bundle you can send to Tines support to help diagnose issues with your deployment (for example pods that restart, crash, or fail health checks).

The bundle includes kubectl context and version information, pod status, resource usage, namespace events, container logs, and namespaced Kubernetes objects. Secrets and ConfigMaps are excluded because they may contain credentials or sensitive configuration.

When you contact support, include:

  • Tines version — the Helm chart version and/or application version you have deployed

  • Kubernetes platform — where the cluster runs, for example Google Kubernetes Engine (GKE), Amazon EKS, Microsoft Azure Kubernetes Service (AKS), or another distribution

Review the bundle and remove sensitive information before sending it to support. Container logs and exported objects may contain sensitive data you do not want to share. Pay close attention to app secrets, passwords, and tokens.

Quickstart

You need kubectl configured for the target cluster. Install it from the Kubernetes documentation if it is not already on your PATH.

Download the script, make it executable, and run it against your Tines namespace:

curl -fsSL -O https://assets.sh.tines.com/collectors/k8s/k8s-diagnostics-collector.sh
chmod +x k8s-diagnostics-collector.sh
./k8s-diagnostics-collector.sh --namespace your-tines-namespace

The script prints the current kubectl context and asks you to confirm before collecting any data. When it finishes, it creates an archive named k8s-namespace-debug-<namespace>-<timestamp>.tar.gz.

Send that archive to your Tines support contact after reviewing its contents and removing anything sensitive.


Manual collection

This section walks through the same read-only diagnostic collection performed by k8s-diagnostics-collector.sh, but as individual commands you can run yourself. Use this when you prefer not to run the script, need to collect only part of the bundle, or want to inspect output as you go.

The automated script is equivalent to running every section below in order and packaging the result into a .tar.gz archive.

What is collected

  • Current kubectl context and client/server version

  • Pod status for all pods in the namespace

  • Current CPU and memory usage for all pods (kubectl top; requires metrics-server)

  • Namespace events (probe failures, OOMKills, scheduling, and so on)

  • Container logs for every pod (current and previous for regular containers; current for init containers)

  • All namespaced Kubernetes API objects except Secrets and ConfigMaps

What is not collected

  • Secrets (may contain credentials)

  • ConfigMaps (may contain sensitive application configuration)

  • Cluster-wide resources outside the target namespace

  • Historical metrics or live profiling data

Prerequisites

  • kubectl installed and configured for the target cluster

  • Permission to read pods, logs, events, and other namespace resources in the target namespace

  • bash, date, mkdir, tar, and standard Unix utilities on your PATH


1. Set environment variables

Define these once at the start of your shell session. Every section below reuses them.

# Required: namespace to collect from
NAMESPACE="your-namespace"

# Optional: max log lines per container (default in the script is 5000)
LOG_TAIL=5000

# Output directory and archive names (timestamp keeps each run unique)
TIMESTAMP="$(date +%Y%m%d-%H%M%S)"
OUT_DIR="k8s-namespace-debug-${NAMESPACE}-${TIMESTAMP}"
ARCHIVE="${OUT_DIR}.tar.gz"

2. Confirm kubectl context

Purpose: Verify you are connected to the intended cluster before collecting any data.

kubectl config current-context

Review the output. Switch context if needed:

kubectl config use-context <context-name>

Optionally store the context name for your records:

CONTEXT="$(kubectl config current-context)"
echo "Using context: ${CONTEXT}"

3. Verify the namespace exists

Purpose: Fail fast if the namespace name is wrong or you lack access.

kubectl get namespace "${NAMESPACE}"

4. Create the output directory

Purpose: Prepare the folder layout used by the script (logs/ and objects/ subdirectories).

mkdir -p "${OUT_DIR}/logs" "${OUT_DIR}/objects"

5. Write collection metadata

Purpose: Record when the bundle was collected and which options were used.

{
  echo "collected_at=${TIMESTAMP}"
  echo "namespace=${NAMESPACE}"
  echo "log_tail=${LOG_TAIL}"
} > "${OUT_DIR}/metadata.txt"

6. Save kubectl context

Purpose: Capture which cluster/context the data came from.

Command: kubectl config current-context

Output file: ${OUT_DIR}/context.txt

kubectl config current-context > "${OUT_DIR}/context.txt" 2>&1

7. Save kubectl client and server version

Purpose: Document kubectl and API server versions for compatibility troubleshooting.

Command: kubectl version --output=yaml

Output file: ${OUT_DIR}/kubectl-version.yaml

kubectl version --output=yaml > "${OUT_DIR}/kubectl-version.yaml" 2>&1

8. Save pod status

Purpose: Snapshot pod names, phases, nodes, restart counts, and IP addresses.

Command: kubectl get pods -o wide

Output file: ${OUT_DIR}/pods.txt

kubectl -n "${NAMESPACE}" get pods -o wide > "${OUT_DIR}/pods.txt" 2>&1

9. Save pod resource usage

Purpose: Capture current CPU and memory usage for every pod in the namespace. Requires metrics-server in the cluster; the command fails harmlessly if it is not installed.

Command: kubectl top pods

Output file: ${OUT_DIR}/pods-top.txt

kubectl -n "${NAMESPACE}" top pods > "${OUT_DIR}/pods-top.txt" 2>&1

10. Save namespace events

Purpose: Collect scheduling, probe failure, OOMKill, and other cluster events for the namespace, ordered by time.

Command: kubectl get events --sort-by=.lastTimestamp

Output file: ${OUT_DIR}/events.txt

kubectl -n "${NAMESPACE}" get events --sort-by=.lastTimestamp \
  > "${OUT_DIR}/events.txt" 2>&1

11. Save namespace API objects (excluding Secrets and ConfigMaps)

Purpose: Export YAML for every namespaced resource type the API exposes, except Secrets and ConfigMaps.

Command: For each namespaced resource type, kubectl get <resource> -o yaml

Output directory: ${OUT_DIR}/objects/ (one file per resource type)

for RESOURCE in $(kubectl api-resources --namespaced=true --verbs=list -o name); do
  case "${RESOURCE}" in
    secrets|configmaps)
      continue
      ;;
  esac
  SAFE_NAME="${RESOURCE//\//_}"
  echo "Collecting ${RESOURCE} -> objects/${SAFE_NAME}.yaml"
  kubectl -n "${NAMESPACE}" get "${RESOURCE}" -o yaml \
    > "${OUT_DIR}/objects/${SAFE_NAME}.yaml" 2>&1
done

To collect a single resource type instead of everything, run one command directly. Example for Deployments:

kubectl -n "${NAMESPACE}" get deployments.apps -o yaml \
  > "${OUT_DIR}/objects/deployments.apps.yaml" 2>&1

12. Save container logs

Purpose: Capture application output from every pod. Regular containers get both current logs and previous (crashed) logs; init containers get current logs only. Each file is capped at ${LOG_TAIL} lines.

12a. Regular containers — current logs

Command: kubectl logs <pod> -c <container> --tail=<lines>

Output file pattern: ${OUT_DIR}/logs/<pod>__<container>__current.log

for pod in $(kubectl -n "${NAMESPACE}" get pods -o name); do
  POD="${pod#pod/}"
  for CONTAINER in $(kubectl -n "${NAMESPACE}" get pod "${POD}" \
    -o jsonpath='{.spec.containers[*].name}'); do
    kubectl -n "${NAMESPACE}" logs "${POD}" -c "${CONTAINER}" \
      --tail="${LOG_TAIL}" \
      > "${OUT_DIR}/logs/${POD}__${CONTAINER}__current.log" 2>&1
  done
done

12b. Regular containers — previous (crashed) logs

Command: kubectl logs <pod> -c <container> --previous --tail=<lines>

Output file pattern: ${OUT_DIR}/logs/<pod>__<container>__previous.log

No previous log exists if the container has never restarted; that command will fail harmlessly for those containers.

for pod in $(kubectl -n "${NAMESPACE}" get pods -o name); do
  POD="${pod#pod/}"
  for CONTAINER in $(kubectl -n "${NAMESPACE}" get pod "${POD}" \
    -o jsonpath='{.spec.containers[*].name}'); do
    kubectl -n "${NAMESPACE}" logs "${POD}" -c "${CONTAINER}" --previous \
      --tail="${LOG_TAIL}" \
      > "${OUT_DIR}/logs/${POD}__${CONTAINER}__previous.log" 2>&1
  done
done

12c. Init containers — current logs

Command: kubectl logs <pod> -c <init-container> --tail=<lines>

Output file pattern: ${OUT_DIR}/logs/<pod>__init-<init-container>__current.log

for pod in $(kubectl -n "${NAMESPACE}" get pods -o name); do
  POD="${pod#pod/}"
  for INIT_CONTAINER in $(kubectl -n "${NAMESPACE}" get pod "${POD}" \
    -o jsonpath='{.spec.initContainers[*].name}'); do
    kubectl -n "${NAMESPACE}" logs "${POD}" -c "${INIT_CONTAINER}" \
      --tail="${LOG_TAIL}" \
      > "${OUT_DIR}/logs/${POD}__init-${INIT_CONTAINER}__current.log" 2>&1
  done
done

12d. Single pod or container

To collect logs for one pod only, set POD and run the relevant command directly:

POD="my-pod-name"
CONTAINER="my-container"

kubectl -n "${NAMESPACE}" logs "${POD}" -c "${CONTAINER}" \
  --tail="${LOG_TAIL}" \
  > "${OUT_DIR}/logs/${POD}__${CONTAINER}__current.log" 2>&1

13. Create the archive

Purpose: Package the output directory into a single file for sharing with support, matching the script's deliverable.

Command: tar -czf

Output file: ${ARCHIVE}

tar -czf "${ARCHIVE}" "${OUT_DIR}"
echo "Created archive: ${ARCHIVE}"

Before sharing

Container logs and exported objects may contain sensitive application data. Review the contents of ${OUT_DIR} or ${ARCHIVE} and remove anything you do not want to share before sending the bundle to Tines support.

When you open a support request, include your Tines version (Helm chart and/or application version) and Kubernetes platform (for example GKE, EKS, or AKS).

Was this helpful?