Kubectl Exec Flags

Posted June 8, 2021 by quy-le ‐ 5 min read

What exactly does the -t and -i flags in kubectl exec means?

 1$ kubectl help exec
 2Execute a command in a container.
 3
 4Examples:
 5  # Switch to raw terminal mode, sends stdin to 'bash' in ruby-container from pod mypod
 6  # and sends stdout/stderr from 'bash' back to the client
 7  kubectl exec mypod -c ruby-container -i -t -- bash -il
 8 
 9  # Get output from running 'date' command from the first pod of the deployment mydeployment, using the first container
10by default
11  kubectl exec deploy/mydeployment -- date
12  
13Options:
14  -i, --stdin=false: Pass stdin to the container
15  -t, --tty=false: Stdin is a TTY

A program works by this flow: [Accept input data] => [Process] => [Return]. When a Unix program started up, by default there will be 3 file descriptors (“channels”) attaches to the process (stdin, stdout and stderr, fd=0,1,2).

  • The process can choose to listen on the stdin for input data (e.g.: sh/bash/vi command listens on stdin for user input-ed commands) or not (e.g.: date/ls/cd commands).
  • And also, process can print the result into stdout/stderr (e.g.: ls/pwd command) or print nothing (e.g.: cd command).

For commands (which will be executed inside the container) that DON’T NEED to accept any input from user’s terminal, we can execute it directly without -i -t flags as below. Exec command simply execute the command inside the container and print the result (if exists) back to the user’s terminal.

 1$ kc exec nettools-5-2869s date   
 2kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
 3Sun Jun  6 07:07:44 UTC 2021
 4
 5$ kc exec nettools-5-2869s -- date
 6Sun Jun  6 07:07:52 UTC 2021
 7
 8# => With or without 2 dashes (--) is the same, but with dashes is preferred, especially if the input command has arguments.
 9
10$ kc exec nettools-5-2869s -- sleep 1
11# Exec command ends after 1s without printing anything else to the terminal (sleep command doesn't write anything to stdout/stderr).

For commands (which will be executed inside the container) that NEED to accept any input from user’s terminal, we have to provide -i flags for exec command.

  • -i means passing user’s input from the terminal into the stdin of the command being executed in the container. Also, the stdout/stderr of the executing command (inside container) will be forwarded back to the user’s terminal (stdout/stderr respectively). E.g.: kc exec pod1 -i -- sh => Pass anything user has typed (on their terminal stdin) into the stdin of sh command inside the container. So the sh command can “see” what user has typed and execute those. Also, the result from sh will be forwarded back and printed on user’s terminal now.
 1$ kc exec nettools-5-2869s -i -- sh
 2pwd   # Command I typed in the terminal being passed into the sh's stdin
 3/home/nuser
 4cd /   # Command I typed in the terminal being passed into the sh's stdin
 5ls   # Command I typed in the terminal being passed into the sh's stdin
 6bin
 7# [...]
 8usr
 9var
10whoami   # Command I typed in the terminal being passed into the sh's stdin
11whoami: unknown uid 1000510000
12exit   # Command I typed in the terminal being passed into the sh's stdin
13command terminated with exit code 1
  • -i is enough to interact with the command being executed inside the container but to get more from it, we need to init/upgrade to TTY session too (still looking for what is the benefits here though), so -t flags is also needed. Note:

    • I don’t have pods with TTY enabled on k8s so switching to Docker here.
    • Actually it’s PTS here, not TTY as we will see below: https://www.golinuxcloud.com/difference-between-pty-vs-tty-vs-pts-linux/#PTS
     1# Case 1: Run container without -t option enabled.
     2$ docker run --rm --name nt -d lnquy/nettools:0.0.7
     3$ docker exec nt tty
     4not a tty   # Exec without -t => inside container is not a TTY
     5$ docker exec -t nt tty
     6/dev/pts/0  # Exec with -t => inside container is a TTY (PTS) now
     7
     8# Case 2: Run container with -t option enabled.
     9$ docker run --rm --name nt -d -t lnquy/nettools:0.0.7
    10$ docker exec nt tty
    11not a tty
    12$ docker exec -t nt tty
    13/dev/pts/1  # TTY with diferent id now, /dev/pts/0 was reserved from docker run -t, I guess
    14$  docker exec nt ls /dev/pts
    150
    16ptmx
    17# We don't see 1 because the session ended after tty command executed and exited on line #12
    18
    19
    20# If we use -t alone in exec, the TTY still can be created, but we canot sending any data into the container stdin
    21# which makes the TTY session useless.
    22# => Use combined -it or not using it at all.
    23$ docker exec -t nt sh
    24~ $   # Show TTY established, but cannot input anything.
    25$ docker exec -t nt bash
    26bash-4.4$   # Same as above
    

When using combined -it, it means establishing a TTY session to the container (-t) and also link the container stdin/stdout/stderr with user’s terminal stdin/stdout/stderr respectively (-i).

  • When user input anything on their terminal’s stdin, these data will be forwarded into container’s stdin.
  • The command running inside container accept those data, process/execute it and returns the result back in container’s stdout/stderror which will be forwarded back to user terminal’s stdout/stderr.

=> Use combined -it or not using it at all.

 1$ docker exec -it nt bash
 2bash-4.4$ pwd
 3/home/nuser
 4bash-4.4$ cd /
 5bash-4.4$ ls
 6bin    dev    etc    home   lib    media  mnt    proc   root   run    sbin   srv    sys    tmp    usr    var
 7bash-4.4$ whoami
 8nuser
 9bash-4.4$ exit
10exit