Containers are used for packaging software and all its dependencies before deployment.
Before the era of containers, software developers had to deal with compatibility issues during deployment. These could occur when software functions properly during the development phase but fails to function due to dependency issues in the production environment. With containers, however, all the software dependencies used for development can be shipped and used in the production environment.
After building your container image and running an instance of it, you might need to access the container for debugging or to try a hot fix, which will require you to access the container environment. To interact with any running container, you need to get into its shell to perform any task.
This article will show you how to get a shell into a running Docker container or Kubernetes pod. It will also help you understand the importance of doing so and how to use flags to achieve your task.
Reasons to get into running container shells
Here are some of the noteworthy reasons you might need to get into a running container shell:
To debug your applications in development: If you encounter errors while running your application inside a running container, you can use a container shell to debug your application instead of rebuilding and redeploying the application container image.
To run commands inside your application container: Your application might be programmed to download files from a server. To confirm the length of the files that have been downloaded, you might need to run the
wc -l filenamecommand which is used to get the number of lines of any file. The
wc -lcommand can only be run in the container shell.
To investigate the internal state of the running container: Your running container might be broken due to some running processes that are taking too much processing power. To check the applications that are running inside your container, you will need to use the
ps auxcommand, which needs to be run in the container shell.
Getting into a running Docker container shell
Docker helps developers containerize their applications with all their dependencies. Its containers are widely used for local deployment and production deployment.
For this guide, you will run a Docker container that has a simple Python application. If you don’t already have Docker installed, follow these tutorials to learn how to install it on Linux, macOS, and Windows.
Cloning the sample GitHub application repository
The sample application that will run inside the container was built with Flask, a simple web development framework. The application has two endpoints: a GET endpoint that will return a greeting, and a GET endpoint that downloads a sample CSV file and stores it.
For this guide, you’ll need to clone the application with the Dockerfile from this GitHub repository. To clone the repository, run the command below:
git clone https://github.com/gravitational/devrel_container_guide.git
Next, change your directory into the cloned folder and type
ls to check its contents.
Building the Docker container image and running the container
The next step is to build the Docker image for the application. In the same directory as your cloned application and Dockerfile, run the
docker build command:
# -t is to tag, . is to specify the current directory docker build -t demo-image .
To run the Docker container image, use the command below:
docker run demo-image
You should see something similar to the following in your terminal:
Visit the URL shown in your terminal to see a Flask welcome page with a
hello world output, showing that the application inside the container is working.
To test the second endpoint, append
/download to the URL, ie
http://172.17.0.2:5000/download. Even though you will see a web page telling you the file download is done, let's verify the file was actually downloaded.
If you look at the example code under
demo.py, the command that is executed when the
download endpoint is hit is:
wget https://gist.githubusercontent.com/benarent/524f1745e49c0b416e4487bb85063fec/raw/80a537d4d1efdcef31443801aacc891a446f2bdd/SampleCSVFile_119kb.csv -O sample.csv. If you take a closer look at your terminal, you will find a 404 error stating that the
wget command is not found. This means there’s a possibility the
wget command was not installed in the Docker container. Perfect, a chance to test out our container debugging skills! Let's get into the container environment to confirm our hypothesis about
Getting into the Docker container
To get into an interactive Docker container environment to check whether the
wget command is installed there, you’ll use a command in the format of
docker exec -it container_name|container_id shellname
The exec command, with
-t flag is used to allocate a pseudo-TTY connected to the standard container input, and the
-i flag is used to create an interactive shell in the container. The
-t flag binds an interactive terminal to the standard input of the Docker container, giving you a terminal for typing input commands that are routed to the standard input of the container by the
-i flag. On Linux, TTY helps users interact with the system through the terminal. The terminal on Linux interacts with a virtual TTY, also known as a pseudo-TTY.
docker exec -it container_name|container_id bash, Docker will execute a command that binds an interactive bash terminal to your Docker container. In order to get the id of the container running our demo image simply open a new terminal and run
docker ps -a. This should show you a list of all the currently running containers. Look for our container named
Once you have the container id, type
docker exec -it your_container_id bash. After executing the command, you will see something similar to the following, indicating that you are inside the container's working directory (app):
Now that you are inside the container shell, you can install the
wget command with
apt update && apt install wget. Then, exit the container shell by typing
exit. Once again, using your web browser visit the download endpoint at
http://172.17.0.2:5000/download. You will see an output similar to the following, which confirms that the file was downloaded:
You might now want to check the file’s length. To do so, you will need to move back into the shell of the container using the previous command,
docker exec -it your_container_id bash.
When inside the Docker container, type
ls to check the files in the working directory. You will notice that there is now a
sample.csv file, which is the file that was downloaded. To check the length of the file, run
cat sample.csv. You’ll see that the file has ten lines.
Getting a shell into a Kubernetes pod
Kubernetes is a container orchestration platform for managing containers automatically. Kubernetes works with pods, which can be likened to houses with containers running inside them.
To get into a shell of a pod running on Kubernetes, you’ll first deploy the previously built
demo-image container image on Kubernetes and then move into a shell of the pod running a container.
Deploying a container image on Kubernetes
Then, you need to define a deployment template to specify details about the container. The content below is a template for creating the
demo-image pod. Save it in a file with the name
apiVersion: v1 kind: Pod metadata: name: demoapp labels: name: demoapp spec: containers: - name: demoimage image: idowuilekura/teleport_demo resources: limits: memory: "128Mi" cpu: "500m" ports: - containerPort: 5000
Create the pod by running this command in the same directory:
kubectl create -f demopod.yaml
To get the status of the pod, run the
kubectl get pods command. You should see the something like this in your terminal, showing that the pod is running:
NAME READY STATUS RESTARTS AGE demoapp 1/1 Running 0 42s
Getting into a shell of a container running inside a pod
You now have a new container running inside the Kubernetes pod. However, since Kubernetes deployed a new container, the changes made to the Docker container in the previous steps aren’t available again. You will need to install the
wget command inside the new container image.
To get into a shell of a container running on Kubernetes, you will use the command
kubectl exec -it nameofpod terminal_name. It is similar to the command that you ran for Docker containers. You can also use
kubectl exec --stdin --tty nameofpod -- name_of_terminal, which will bind a pseudo-TTY and route any command in the terminal to the standard input of the container.
Next, run the command
kubectl exec --stdin --tty demoapp -- bash to move into the container image.
You can use the
ls command to check the contents of the files in your Docker container, which will show the
demo.py file. Install the
wget command with
apt update && apt install wget.
You can also explore the container environment further if you wish to.
Securing your Kubernetes containers against unwanted access
Moving into the shell of a container on Kubernetes is useful for debugging and other activities, but you don't want everyone to have access to a container shell. It can lead to disastrous results, such as your application being stopped and tampered with.
Setting up role-based access in your environment is a good way to disable this functionality. Role-based access control (RBAC) can help limit how external users interact with your containers. To learn more about RBAC and how to implement it, you can check out this tutorial.
Monitoring access to Kubernetes shells with Teleport
It’s good practice to monitor access to your container shell and the activities users are performing. Teleport is one of the tools that can help you do so. It is an identity-aware, multiprotocol access proxy for accessing Kubernetes clusters easily and securely. Teleport consolidates connectivity, authentication, authorization, and auditing of Kubernetes clusters into a single platform, which helps to improve security and agility.
Teleport issues users with short-lived kubeconfigs and certificates using single sign-on (SSO), and switches between clusters without logging in twice. Admins can use roles to implement policies, and organizations can achieve compliance by capturing
If you are interested in learning about using Teleport for Kubernetes access, you can check out this tutorial from Teleport.
This article showed the importance of getting into the shell of a running Docker container or Kubernetes pod and how to do it. It also touched on the importance of restricting access with RBAC in Kubernetes and how to know who is accessing your cluster with Teleport.
Teleport offers an improved and streamlined Kubernetes experience for securely accessing Kubernetes clusters remotely and getting into the shells of containers and pods. It lets you easily view the status of your Kubernetes cluster. To learn more about Teleport for Kubernetes access, check out this resource.
Passkeys for Infrastructure
By Ben Arent
SFTP: a More Secure Successor to SCP
By Andrew LeFevre
SELinux, Dragons and Other Scary Things
By Jakub Nyckowski