Notes14-Kubernetes Commands
Kubernetes Commands
Imperative kubectl, output and JSONPath, nodes, kubeadm, etcd, certificates, and the host tools you reach for when the API is down.
Kubernetes Commands Quick Notes
How to read this page
- Replace placeholders:
<ns>,<node>,<pod>,<deploy>, image tags, and file paths. - Context first: One shell can talk to several clusters.
kubectl config use-contextbefore any change. - Namespace on every command that targets a namespaced object, or set the context namespace once.
- Imperative when the object is simple.
--dry-run=client -o yamlwhen you must add a probe, a volume, or affinity.
Short names you can type: po Pod, svc Service, deploy Deployment, rs ReplicaSet, ds DaemonSet, sts StatefulSet, cm ConfigMap, ns Namespace, no Node, pv PersistentVolume, pvc PersistentVolumeClaim, sc StorageClass, ing Ingress, netpol NetworkPolicy, sa ServiceAccount, ep Endpoints, csr CertificateSigningRequest.
Context, namespace, and the shell
kubectl config get-contexts
kubectl config current-context
kubectl config use-context <context>
kubectl config set-context --current --namespace=<ns>
kubectl config view --minify | grep namespace
alias k=kubectl
export do="--dry-run=client -o yaml"
echo $KUBECONFIG
KUBECONFIG: If this variable is set, kubectl ignores~/.kube/configuntil you account for it.kalias: Optional.type kshows whether this shell already defines it.$do: Expand it yourself as--dry-run=client -o yamlif you would rather not rely on a variable. Example:kubectl create deployment web --image=nginx $do.
kubectl version
kubectl cluster-info
kubectl auth whoami
kubectl api-resources
kubectl api-resources --namespaced=false
kubectl api-versions
Imperative create
Generators write a correct object without a blank YAML file. Add --dry-run=client -o yaml and redirect to a file when you need a field the generator cannot set.
kubectl create namespace <ns>
kubectl create serviceaccount <sa> -n <ns>
kubectl run <pod> --image=<image> --port=80
kubectl run <pod> --image=busybox:1.36 --restart=Never --command -- sleep 3600
kubectl run <pod> --image=nginx \
--labels=app=web --env=COLOR=blue \
--requests=cpu=100m,memory=64Mi \
--limits=cpu=200m,memory=128Mi \
--dry-run=client -o yaml > pod.yaml
kubectl create deployment <deploy> --image=<image> --replicas=3 --port=80
kubectl create job <job> --image=busybox:1.36 -- echo hello
kubectl create cronjob <cron> --image=busybox:1.36 --schedule="*/5 * * * *" -- echo tick
kubectl create job <job> --from=cronjob/<cron>
kubectl expose deployment <deploy> --name=<svc> --port=80 --target-port=80
kubectl expose deployment <deploy> --type=NodePort --port=80 --name=<svc>
kubectl create service clusterip <svc> --tcp=80:80
kubectl create service nodeport <svc> --tcp=80:80 --node-port=30080
kubectl create service loadbalancer <svc> --tcp=80:80
kubectl create ingress <ing> --class=nginx \
--rule="shop.example.com/wear=wear:80"
kubectl create configmap <cm> \
--from-literal=key=value \
--from-file=app.conf=./app.conf \
--from-env-file=./app.env
kubectl create secret generic <secret> --from-literal=password='s3cr3t' --from-file=username=./user.txt
kubectl create secret tls <tls-secret> --cert=tls.crt --key=tls.key
kubectl create secret docker-registry <regcred> \
--docker-server=<registry> --docker-username=<user> --docker-password='<token>'
kubectl create token <sa> -n <ns> --duration=1h
kubectl create role <role> --verb=get,list,watch --resource=pods -n <ns>
kubectl create clusterrole <clusterrole> --verb=get,list --resource=nodes
kubectl create rolebinding <binding> --role=<role> --user=<user> -n <ns>
kubectl create rolebinding <binding> --clusterrole=view --user=<user> -n <ns>
kubectl create rolebinding <binding> --clusterrole=edit \
--serviceaccount=<ns>:<sa> -n <ns>
kubectl create clusterrolebinding <binding> --clusterrole=cluster-admin --user=<user>
kubectl create clusterrolebinding <binding> --clusterrole=<clusterrole> --group=<group>
kubectl create quota <quota> --hard=cpu=2,memory=2Gi,pods=10 -n <ns>
kubectl create poddisruptionbudget <pdb> --selector=app=web --min-available=1 -n <ns>
kubectl autoscale deployment <deploy> --min=2 --max=10 --cpu-percent=70
kubectl runcreates a Pod.kubectl create deploymentcreates a Deployment.--restart=Neveronkubectl runkeeps a bare Pod. Without it, current kubectl still creates a Pod. Usecreate deploymentwhen you want replicas.--command --onkubectl runreplaces the image entrypoint. Everything after--is the command.- RoleBinding can point at a ClusterRole (
--clusterrole=view). The grant applies only in-n. - ServiceAccount subject on a binding is
--serviceaccount=<namespace>:<name>.
Apply, edit, patch, delete, wait
kubectl apply -f file.yaml
kubectl apply -f ./dir/
kubectl apply -k ./overlays/prod
kubectl diff -f file.yaml
kubectl replace -f file.yaml
kubectl delete -f file.yaml
kubectl delete -f file.yaml --wait=false
kubectl edit deployment <deploy> -n <ns>
kubectl edit pod <pod> -n <ns>
kubectl scale deployment <deploy> --replicas=5
kubectl scale sts <sts> --replicas=3
kubectl delete pod <pod> -n <ns> --force --grace-period=0
kubectl delete pods -l app=web -n <ns>
kubectl wait --for=condition=Ready pod -l app=web -n <ns> --timeout=90s
kubectl wait --for=condition=available deployment/<deploy> -n <ns> --timeout=120s
kubectl wait --for=condition=complete job/<job> -n <ns> --timeout=120s
kubectl patch deployment <deploy> -p '{"spec":{"replicas":3}}'
kubectl patch node <node> -p '{"spec":{"unschedulable":true}}'
kubectl patch pv <pv> -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
kubectl patch pvc <pvc> -n <ns> -p '{"spec":{"resources":{"requests":{"storage":"10Gi"}}}}'
kubectl patch deployment <deploy> --type=json -p='[
{"op":"replace","path":"/spec/replicas","value":4}
]'
kubectl editon a Pod can change a few fields. Image, requests, and most ofspecon a running Pod are immutable. Delete the Pod or edit the Deployment.diffshows whatapplywould change. Run it before you overwrite a working object.- JSON patch (
--type=json) is the reliable way to replace one path. A strategic merge patch is the default-p.
Set image, env, resources, service account
kubectl set image deployment/<deploy> <container>=<image>:<tag>
kubectl set image deployment/<deploy> '*=nginx:1.27'
kubectl set env deployment/<deploy> COLOR=blue
kubectl set env deployment/<deploy> --from=configmap/<cm>
kubectl set env deployment/<deploy> PASSWORD- # remove the variable
kubectl set resources deployment/<deploy> -c=<container> \
--requests=cpu=100m,memory=128Mi \
--limits=cpu=500m,memory=256Mi
kubectl set serviceaccount deployment/<deploy> <sa>
kubectl set image records a new Pod template, so a Deployment rolls out. Confirm with kubectl rollout status.
Rollouts
kubectl rollout status deployment/<deploy>
kubectl rollout history deployment/<deploy>
kubectl rollout undo deployment/<deploy>
kubectl rollout undo deployment/<deploy> --to-revision=2
kubectl rollout pause deployment/<deploy>
kubectl rollout resume deployment/<deploy>
kubectl rollout restart deployment/<deploy>
kubectl rollout restart daemonset/<ds> -n kube-system
kubectl annotate deployment/<deploy> kubernetes.io/change-cause="bump image"
Labels, annotations, taints
kubectl label pod <pod> env=prod --overwrite
kubectl label node <node> disktype=ssd
kubectl label namespace <ns> pod-security.kubernetes.io/enforce=baseline
kubectl annotate pod <pod> owner=platform --overwrite
kubectl taint nodes <node> dedicated=batch:NoSchedule
kubectl taint nodes <node> dedicated=batch:NoSchedule-
kubectl taint nodes --all node-role.kubernetes.io/control-plane:NoSchedule-
kubectl taint nodes <node> node-role.kubernetes.io/control-plane:NoSchedule
Default StorageClass annotation (on the StorageClass, not the namespace):
kubectl annotate storageclass <sc> storageclass.kubernetes.io/is-default-class=true --overwrite
kubectl annotate storageclass <old> storageclass.kubernetes.io/is-default-class=false --overwrite
Remove a label by putting a trailing - on the key: kubectl label node <node> disktype-.
Get, describe, and events
kubectl get pods -n <ns> -o wide
kubectl get pods -A -o wide
kubectl get pods -n <ns> --show-labels
kubectl get pods -n <ns> -L app,env
kubectl get pods -n <ns> -w
kubectl get deploy,rs,po,svc -n <ns>
kubectl get nodes -o wide
kubectl get events -n <ns> --sort-by=.lastTimestamp
kubectl get events -A --field-selector type=Warning --sort-by=.lastTimestamp
kubectl describe pod <pod> -n <ns>
kubectl describe deploy <deploy> -n <ns>
kubectl describe node <node>
kubectl describe svc <svc> -n <ns>
kubectl explain pod.spec.containers
kubectl explain deployment.spec.strategy.rollingUpdate
kubectl explain ingress.spec --api-version=networking.k8s.io/v1
kubectl explain networkpolicy.spec.ingress.from --api-version=networking.k8s.io/v1
kubectl explain pods --recursive
k
Selectors:
kubectl get pods -l app=web
kubectl get pods -l 'env in (prod,stage),tier!=cache'
kubectl get pods --field-selector status.phase=Running
kubectl get pods -A --field-selector spec.nodeName=<node>
kubectl get pods -n <ns> --field-selector status.phase=Running,spec.nodeName=<node>
kubectl get pv --field-selector status.phase=Released
kubectl get events --field-selector involvedObject.name=<pod>
Sort and columns:
kubectl get pods --sort-by=.metadata.creationTimestamp
kubectl get pv --sort-by=.spec.capacity.storage
kubectl get pods -o custom-columns=NAME:.metadata.name,STATUS:.status.phase,IP:.status.podIP,NODE:.spec.nodeName
kubectl get nodes -o custom-columns=NAME:.metadata.name,VERSION:.status.nodeInfo.kubeletVersion,OS:.status.nodeInfo.operatingSystem
kubectl get pods -A -o custom-columns=NS:.metadata.namespace,NAME:.metadata.name,NODE:.spec.nodeName,STATUS:.status.phase
JSONPath
Single quotes around the expression so the shell leaves {, $, and \ alone. {.field} is one object. {range .items[*]}...{end} walks a list. {"\n"} and {"\t"} are literals. A missing key prints nothing.
kubectl get pod <pod> -o jsonpath='{.status.podIP}{"\n"}'
kubectl get pod <pod> -o jsonpath='{.spec.nodeName}{"\n"}'
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.phase}{"\n"}{end}'
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.nodeInfo.kubeletVersion}{"\n"}{end}'
kubectl get pod <pod> -o jsonpath='{range .spec.containers[*]}{.name}{" "}{.image}{"\n"}{end}'
kubectl get pods -o jsonpath='{.items[?(@.status.phase=="Running")].metadata.name}{"\n"}'
kubectl get secret <secret> -n <ns> -o jsonpath='{.data.password}' | base64 -d; echo
kubectl get csr <csr> -o jsonpath='{.status.certificate}' | base64 -d > user.crt
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.conditions[?(@.type=="Ready")].status}{"\n"}{end}'
kubectl -n kube-system get pod kube-apiserver-<node> -o jsonpath='{.spec.containers[0].command}{"\n"}'
Decode a whole Secret to YAML-friendly values:
kubectl get secret <secret> -n <ns> -o go-template='{{range $k,$v := .data}}{{$k}}={{$v | base64decode}}{{"\n"}}{{end}}'
Logs, exec, copy, debug, metrics
kubectl logs <pod> -n <ns>
kubectl logs <pod> -n <ns> -c <container>
kubectl logs <pod> -n <ns> -c <container> --previous
kubectl logs <pod> -n <ns> --all-containers --tail=50
kubectl logs deploy/<deploy> -n <ns> --prefix --tail=20
kubectl logs -l app=web -n <ns> --prefix --tail=20
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50
kubectl logs -n kube-system -l k8s-app=kube-proxy --tail=30
kubectl logs -n kube-system etcd-<node>
kubectl logs -n kube-system kube-apiserver-<node>
kubectl exec -n <ns> <pod> -- hostname
kubectl exec -it -n <ns> <pod> -c <container> -- sh
kubectl exec -n <ns> <pod> -- nslookup kubernetes.default
kubectl exec -n <ns> <pod> -- wget -qO- --timeout=2 http://<svc>.<ns>.svc.cluster.local
kubectl cp <ns>/<pod>:/path/in/pod ./local-file -c <container>
kubectl cp ./local-file <ns>/<pod>:/path/in/pod -c <container>
kubectl port-forward pod/<pod> 8080:80 -n <ns>
kubectl port-forward svc/<svc> 8080:80 -n <ns>
kubectl debug -it <pod> -n <ns> --image=busybox:1.36 --target=<container>
kubectl debug node/<node> -it --image=busybox:1.36
kubectl top nodes
kubectl top pods -A --sort-by=memory
kubectl top pod <pod> -n <ns> --containers
kubectl get apiservice v1beta1.metrics.k8s.io
kubectl get deploy -n kube-system metrics-server
A disposable client Pod:
kubectl run net --rm -it --restart=Never --image=busybox:1.36 -n <ns> -- sh
kubectl debug node starts a privileged Pod in the host namespaces and mounts the node root at /host. Use it when you cannot SSH and still need chroot /host to read kubelet files.
Workloads to list while you debug
kubectl get deploy,rs,ds,sts,job,cronjob -n <ns>
kubectl get hpa -n <ns>
kubectl describe hpa <hpa> -n <ns>
kubectl get pdb -A
kubectl describe pdb <pdb> -n <ns>
kubectl get sa -n <ns>
kubectl get quota,limits -n <ns>
kubectl describe quota -n <ns>
kubectl get cronjob <cron> -n <ns>
kubectl get pods -n <ns> -l job-name=<job>
Services, DNS, Ingress, Gateway
kubectl get svc -n <ns> -o wide
kubectl get endpoints -n <ns>
kubectl get endpointslices -n <ns> -l kubernetes.io/service-name=<svc>
kubectl get ingressclass
kubectl get ingress -A
kubectl describe ingress <ing> -n <ns>
kubectl get gatewayclass,gateway,httproute -A
kubectl describe httproute <route> -n <ns>
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl get svc kube-dns -n kube-system
kubectl get configmap coredns -n kube-system -o yaml
kubectl rollout restart deployment coredns -n kube-system
NetworkPolicy
kubectl get netpol -A
kubectl describe netpol <policy> -n <ns>
kubectl get pods -n <ns> --show-labels
There is no packet counter on the object. Test with wget or nc from a Pod in the source namespace.
Storage
kubectl get pv,pvc,sc -A
kubectl describe pvc <pvc> -n <ns>
kubectl describe pv <pv>
kubectl get volumeattachment
kubectl get pods -n <ns> -o wide
kubectl delete pvc <pvc> -n <ns> --wait=false
volumeattachment shows which node holds a disk. A multi-attach error on an RWO volume usually means a terminating Pod on another node still has it.
RBAC checks
kubectl get role,rolebinding -n <ns>
kubectl get clusterrole,clusterrolebinding
kubectl describe role <role> -n <ns>
kubectl describe rolebinding <binding> -n <ns>
kubectl describe clusterrole <clusterrole>
kubectl auth can-i create deployments -n <ns>
kubectl auth can-i delete nodes
kubectl auth can-i list secrets -n <ns> --as <user>
kubectl auth can-i get pods -n <ns> --as system:serviceaccount:<ns>:<sa>
kubectl auth can-i --list -n <ns>
kubectl auth can-i --list --as <user>
yes / no from auth can-i is the check that the binding matches the user you think it matches.
Certificates and kubeconfig
openssl genrsa -out user.key 2048
openssl req -new -key user.key -out user.csr -subj "/CN=<user>/O=<group>"
cat user.csr | base64 | tr -d '\n'
kubectl get csr
kubectl certificate approve <csr>
kubectl certificate deny <csr>
kubectl delete csr <csr>
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -dates -subject
openssl x509 -in user.crt -noout -subject -issuer -dates
kubeadm certs check-expiration
kubeadm certs renew all
kubectl config set-cluster <cluster> \
--server=https://<api>:6443 \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true
kubectl config set-credentials <user> \
--client-certificate=user.crt \
--client-key=user.key \
--embed-certs=true
kubectl config set-credentials <user> --token="<token>"
kubectl config set-context <user>@<cluster> \
--cluster=<cluster> --user=<user> --namespace=<ns>
kubectl config use-context <user>@<cluster>
kubectl config view --minify --flatten
kubectl config view --raw
CA hash for kubeadm join (hex only; prefix the join flag with sha256:):
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt \
| openssl rsa -pubin -outform der 2>/dev/null \
| openssl dgst -sha256 -hex | sed 's/^.* //'
Base64 helpers:
echo -n 's3cr3t' | base64
echo '<base64>' | base64 -d
echo -n avoids embedding a trailing newline in the Secret.
Nodes: cordon, drain, capacity
kubectl get nodes
kubectl describe node <node>
kubectl cordon <node>
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data --force
kubectl uncordon <node>
--ignore-daemonsets lets drain continue. It does not delete DaemonSet Pods. --force is for Pods that have no controller. Drain stops while a PodDisruptionBudget would be violated.
kubectl describe node <node> | sed -n '/Taints/,+8p'
kubectl describe node <node> | sed -n '/Allocated resources/,+12p'
kubectl describe node <node> | sed -n '/Conditions/,+12p'
kubectl get ds -A -o wide
kubeadm
kubeadm version
kubeadm init \
--apiserver-advertise-address=<node-ip> \
--pod-network-cidr=<cidr> \
--control-plane-endpoint=<lb-host>:6443 \
--kubernetes-version=v1.35.0 \
--upload-certs
mkdir -p $HOME/.kube
sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown "$(id -u):$(id -g)" $HOME/.kube/config
kubeadm token list
kubeadm token create --print-join-command
kubeadm token create --ttl 2h
kubeadm init phase upload-certs --upload-certs
kubeadm join <endpoint>:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash>
kubeadm join <endpoint>:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash> \
--control-plane --certificate-key <key>
kubeadm upgrade plan
kubeadm upgrade apply v1.35.0
kubeadm upgrade node
kubeadm reset
kubeadm config images list
kubeadm reset removes this node’s cluster install. Use it only on the node you intend to rejoin.
Control-plane upgrade, then each other node:
sudo apt-get update
sudo apt-cache madison kubeadm
sudo apt-get install -y kubeadm=<pkg-version>
sudo kubeadm upgrade plan
sudo kubeadm upgrade apply v1.35.0 # first control plane only
sudo apt-get install -y kubelet=<pkg-version> kubectl=<pkg-version>
sudo systemctl daemon-reload
sudo systemctl restart kubelet
Other control planes and workers use kubeadm upgrade node after drain, then the same kubelet package install, then kubectl uncordon.
sudo apt-mark hold kubelet kubeadm kubectl
sudo apt-mark unhold kubelet kubeadm kubectl
ls /etc/kubernetes/manifests
ls /etc/kubernetes/pki
etcdctl
Set the API version once per shell. Certificates below are the kubeadm defaults. Read /etc/kubernetes/manifests/etcd.yaml if this cluster uses different paths.
export ETCDCTL_API=3
export ETCDCTL_ENDPOINTS=https://127.0.0.1:2379
export ETCDCTL_CACERT=/etc/kubernetes/pki/etcd/ca.crt
export ETCDCTL_CERT=/etc/kubernetes/pki/etcd/server.crt
export ETCDCTL_KEY=/etc/kubernetes/pki/etcd/server.key
sudo -E etcdctl endpoint health
sudo -E etcdctl endpoint status --write-out=table
sudo -E etcdctl member list --write-out=table
sudo -E etcdctl snapshot save /opt/etcd-backup.db
sudo etcdctl snapshot status /opt/etcd-backup.db --write-out=table
sudo etcdctl snapshot restore /opt/etcd-backup.db --data-dir=/var/lib/etcd-restore
sudo -E keeps the ETCDCTL_* variables. After restore, point the etcd static Pod manifest hostPath and --data-dir at the new directory. The kubelet restarts etcd when that file changes.
Find the live paths when the lab is non-standard:
sudo grep -E 'data-dir|listen-client-urls|advertise-client-urls|cert-file|key-file|trusted-ca' \
/etc/kubernetes/manifests/etcd.yaml
When kubectl cannot reach the API
On the node:
sudo systemctl status kubelet containerd --no-pager
sudo systemctl restart kubelet
sudo systemctl enable --now kubelet containerd
sudo journalctl -u kubelet --since "20 min ago" --no-pager
sudo journalctl -u kubelet -u containerd -p err --since "1 hour ago" --no-pager
sudo crictl ps -a
sudo crictl pods
sudo crictl logs <container-id>
sudo crictl inspect <container-id>
sudo crictl images
ls /var/log/pods
ls /etc/cni/net.d
ls /opt/cni/bin
crictl reads /etc/crictl.yaml for the runtime socket. If it hangs, that file is missing or containerd is down.
Static Pod restart without deleting the definition: move the manifest out and back.
sudo mv /etc/kubernetes/manifests/kube-apiserver.yaml /tmp/
sleep 20
sudo mv /tmp/kube-apiserver.yaml /etc/kubernetes/manifests/
Health once the API answers again:
kubectl get --raw='/readyz?verbose'kubectl get --raw='/livez?verbose'
Host network and OS checks
hostname
hostnamectl
cat /sys/class/dmi/id/product_uuid
swapon --show
sudo swapoff -a
free -h
df -h
df -hi
ip addr
ip route
ss -lntup | grep -E '6443|2379|10250'
sysctl net.ipv4.ip_forward
sysctl net.bridge.bridge-nf-call-iptables
sudo modprobe overlay
sudo modprobe br_netfilter
ps aux | grep kubelet
ps aux | grep etcd
sudo containerd config dump | grep SystemdCgroup
Pod CIDR and bridge interfaces show up in ip addr and ip route after the CNI is healthy. ss showing nothing on 6443 means the apiserver process is not listening.
Helm and Kustomize
helm repo add <name> <url>
helm repo update
helm search repo <chart>
helm show values <repo>/<chart>
helm install <release> <repo>/<chart> -n <ns> --create-namespace -f values.yaml
helm install <release> <repo>/<chart> -n <ns> --set key=value
helm list -A
helm status <release> -n <ns>
helm get values <release> -n <ns>
helm get manifest <release> -n <ns>
helm history <release> -n <ns>
helm upgrade <release> <repo>/<chart> -n <ns> -f values.yaml
helm upgrade --install <release> <repo>/<chart> -n <ns> -f values.yaml
helm rollback <release> <revision> -n <ns>
helm uninstall <release> -n <ns>
kubectl kustomize ./overlays/prod
kubectl apply -k ./overlays/prod
kubectl diff -k ./overlays/prod
kubectl delete -k ./overlays/prod
kubectl apply -f on a directory does not run Kustomize. The flag is -k.
One-page change loop
kubectl config use-context <context>
kubectl config set-context --current --namespace=<ns>
kubectl get pods -o wide
kubectl describe pod <pod>
kubectl logs <pod> --previous
# fix with create / set / edit / apply
kubectl get pods -o wide
kubectl auth can-i <verb> <resource> --as <user> -n <ns>
For a node fix, finish on kubectl get nodes showing Ready, and uncordon if you drained.