Resources

Using kubectl exec | Shell Commands & Examples

November 30, 2021

kubectl exec lets you start a shell session to containers running in your Kubernetes cluster. It’s a bit like SSH for Kubernetes. Here’s what you need to know to use this command as part of your cluster management procedures, including the cases where it makes the most sense.

James Walker
Software Engineer

Kubernetes is a container orchestrator that lets you automate deployments across multiple physical machines. Starting a shell session to a container in a Kubernetes cluster isn’t the same as using Secure Shell (SSH) on a physical server. Although containers should be stateless and capable of running without intervention, sometimes you may need a shell to debug issues or extract data.

<terminal inline>kubectl exec<terminal inline> lets you connect to containers inside your cluster. It’s part of the full kubectl CLI utility for interacting with Kubernetes installations. The <terminal inline>exec<terminal inline> command streams a shell session into your terminal, similar to <terminal inline>ssh<terminal inline> or <terminal inline>docker exec<terminal inline>.

Here’s the simplest invocation to get a shell to the <terminal inline>demo-pod<terminal inline> pod:


kubectl exec -it demo-pod -- /bin/sh

kubectl will connect to your cluster, run <terminal inline>/bin/sh<terminal inline> inside the first container within the <terminal inline>demo-pod<terminal inline> pod, and forward your terminal’s input and output streams to the container’s process. In this article, you will examine the scenarios where <terminal inline>kubectl exec<terminal inline> is useful, what each section of the command does, and how you can customize the shell connection.

When to Use kubectl exec

Managing containerized workloads in a Kubernetes cluster requires different processes than those used for applications on a traditional bare-metal server. Because you must drill down from the cluster host to the container instances that deploy your system, there is an extra layer between you and your software.

Kubernetes’s strength is its ability to distribute replicas across physical machines (nodes). Even if you could use SSH for management, you’d have to keep track of which node was running each container. <terminal inline>kubectl exec<terminal inline> lets you specify the container to connect to without worrying about the Kubernetes node it’s on.

Starting a shell inside a container is most commonly used when you’re debugging a problem. After exhausting other avenues of inquiry, such as the logs produced by a container, you may have no other option than to inspect it from the inside.

By running the shell commands, you can see the container’s entire file system and check if the environment is as you expected. It can also help you identify whether a critical file is missing or locked, or find instances of misconfigured environment variables.

Actions to Avoid When Using kubectl exec

Since <terminal inline>kubectl exec<terminal inline> gives you full shell access, there’s nothing to stop you from modifying the container, too. This allows you to add extra software packages to aid in your debugging. The extra software packages are sometimes necessary when you are connected to a container that uses a minimal base image where common tools may be missing.

Nonetheless, you should refrain from substantially altering the container’s environment. Don’t update existing software packages or use <terminal inline>kubectl exec<terminal inline> as a way to replace your application’s source code. These operations would depart from the model of immutability and reproducibility that’s the foundation of the container movement. Instead, you should rebuild your container image then deploy the new version into your Kubernetes cluster.

To summarize, <terminal inline>kubectl exec<terminal inline> is a helpful tool when you want to inspect the state of a container in your cluster. It shouldn’t generally be used to alter the state, except in specific cases where you’re adding extra debugging packages or fixing a one-off problem in the environment.

kubectl exec Syntax

Unlike a simple <terminal inline>ssh user@server<terminal inline> command, kubectl exec requires a few extra arguments to set up an interactive shell session. Let’s break down the command shown above:


kubectl exec -it demo-pod -- /bin/sh

This specifies that you want to run the <terminal inline>/bin/sh<terminal inline> command in the first container within your <terminal inline>demo-pod<terminal inline> pod. The <terminal inline>--<terminal inline> separates the command to run from the <terminal inline>kubectl<terminal inline> arguments. Anything after the <terminal inline>--<terminal inline> will be passed to the container, as opposed to <terminal inline>kubectl<terminal inline>.

The <terminal inline>-it<terminal inline> is equivalent to using the <terminal inline>--stdin<terminal inline> (<terminal inline>-i<terminal inline>) and <terminal inline>--tty<terminal inline> (<terminal inline>-t<terminal inline>) flags. These instruct kubectl to route your terminal’s <terminal inline>stdin<terminal inline> input stream to the container (<terminal inline>-i<terminal inline>) and treat it as a TTY (<terminal inline>-t<terminal inline>). This sets up an interactive session where you can supply input to the process inside the container. Without these flags, you’d see a read-only output stream.

Whereas SSH automatically starts a shell process and binds your terminal’s input and output streams, kubectl makes each of these aspects customizable. You don’t have to start a shell in the container; you could run an arbitrary process instead, supply it some interactive input, and receive its output:


kubectl exec -it demo-pod -- node my-script.js

Cluster Connections

Like all other kubectl commands, <terminal inline>exec<terminal inline> works with the cluster connection defined by your <terminal inline>KUBECONFIG<terminal inline> environment variable. This should reference a kubeconfig file containing your cluster’s connection details.


export KUBECONFIG=.kube/demo-cluster.yaml
kubectl exec -it demo-pod -- /bin/sh

The specified container name must exist within the default cluster namespace. Use the global <terminal inline>--namespace<terminal inline> flag to change this when you’re referencing a container in a different namespace:


kubectl exec --namespace demo-namespace -it demo-pod -- /bin/sh

Pods and Containers

Containers in a Kubernetes cluster reside within Pods. As each Pod can incorporate several containers, <terminal inline>kubectl exec<terminal inline> supports an additional argument to let you specify a Pod and container to connect to:


kubectl exec -it demo-pod -c demo-container -- /bin/sh

In this example, your connection would be to the <terminal inline>demo-container<terminal inline> container within the <terminal inline>demo-pod<terminal inline> pod. In the previous steps, we omitted the container name and only indicated the pod. In this case, kubectl automatically connects to the container with the <terminal inline>kubectl.kubernetes.io/default-container<terminal inline> annotation or the first container in the Pod when the annotations are not used.

You can also directly reference a higher-level resource, such as a deployment. This reference lets you rapidly connect to a container without needing to know its exact name:


kubectl exec -it deployment/demo-deployment -- /bin/sh

The command above would give you a shell session to the first container within the <terminal inline>demo-deployment<terminal inline> deployment. It removes the need to run <terminal inline>kubectl get pods<terminal inline> to discover Pod names before you use <terminal inline>exec<terminal inline>.

Advanced Options

<terminal inline>kubectl exec<terminal inline> supports a couple of extra options that let you customize its operation:

  • <terminal inline>--quiet<terminal inline> (<terminal inline>-q<terminal inline>): This disables all output from kubectl itself. You’ll only see output produced by the process running in the container.
  • <terminal inline>--pod-running-timeout<terminal inline>: This lets you customize the timeout before kubectl gives up trying to connect when no matching Pods are running. The default value of <terminal inline>1m0s<terminal inline> means kubectl will wait for up to a minute for a Pod to be available.

These arguments should be passed to the kubectl portion of the command before the -- separator that commences the in-container section.

Alternatives to kubectl exec

<terminal inline>kubectl exec<terminal inline> is the best option for getting a shell to a Kubernetes container. It’s designed specifically for this purpose and circumvents all the issues of identifying the correct physical node to connect to.

If you really need an alternative, perhaps because you must connect from a system without kubectl, you could consider running an SSH daemon inside your container. Beware that this increases your security attack surface and goes against the idea of each container having one single purpose.

Another option is setting up a web-based Kubernetes dashboard. Many popular options, including the official dashboard, are capable of providing interactive shell sessions within your browser.

Final Thoughts

The <terminal inline>kubectl exec<terminal inline> command lets you start a shell session inside containers running in your Kubernetes cluster. This command lets you inspect the container’s file system, check the state of the environment, and perform advanced debugging tools when logs alone don’t provide enough information.

Manual use of shell commands should be your last resort for managing your containers. Day-to-day monitoring of Kubernetes metrics and critical events is better served by dedicated platforms, such as ContainIQ, which lets you use prebuilt dashboards to keep tabs on your cluster’s health.

Looking for an out-of-the-box monitoring solution?

With a simple one-line install, ContainIQ allows you to monitor the health of your cluster with pre-built dashboards and easy-to-set alerts.

Article by

James Walker

Software Engineer

James Walker is the founder of Heron Web, a UK-based digital agency providing bespoke software development services to SMEs. He has experience managing complete end-to-end web development workflows with DevOps, CI/CD, Docker, and Kubernetes. James also writes technical articles on programming and the software development lifecycle, using the insights acquired from his industry career. He's currently a regular contributor to CloudSavvy IT and has previously written for DigitalJournal.com, OnMSFT.com, and other technology-oriented publications.

Read More