Generic Top

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

Docker works on the principle of packaging applications and all their required dependencies into lightweight containers. In addition to being deployed on local clusters during testing, we can also deploy these lightweight containers in the production environment.

In this tutorial, we'll look into executing the commands in the Docker container using different users.

First, we'll learn to access the Docker container using a root user to get some extra privileges. We'll also discuss setting up passwords for the root and non-root users to secure the container from vulnerable sources.

2. Setup a Docker Container

Before we move forward, let's first create a Dockerfile to add a user john:

FROM ubuntu:16.04
RUN apt-get update 
RUN useradd -m john
USER john
CMD /bin/bash

Here, we used “ubuntu:16.04” as the base image. Let's build the image using the docker build command:

$ docker build -t baeldung .
Sending build context to Docker daemon  2.048kB
Step 1/5 : FROM ubuntu:16.04
16.04: Pulling from library/ubuntu
58690f9b18fc: Pull complete 
...
Step 5/5 : CMD /bin/bash
 ---> Running in d04af94585e2
Removing intermediate container d04af94585e2
 ---> 312faa93c781
Successfully built 312faa93c781
Successfully tagged baeldung:latest

We'll now run a Docker container using the baeldung image:

$ docker run -id --name baeldung baeldung
34dbc77279a2a6244b0e4ee87890d79e814128391c6a4387d2e2fd10fa6e8f20

Let's verify that the container is running as expected using the docker ps command:

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS               NAMES
34dbc77279a2        baeldung            "/bin/sh -c /bin/bash"   About a minute ago   Up About a minute                       baeldung

Here, we can see that the Docker container is running without any issue.

3. Access the Docker Container

Docker containers are designed to be accessed as root users to execute commands that non-root users can't execute. We can run a command in a running container using the docker exec. We'll use the -i and -t option of the docker exec command to get the interactive shell with TTY terminal access.

3.1. Using the Non-Root User

The Docker container “baeldung” is up and running. We'll now use the docker exec command to access it:

$ docker exec -it baeldung bash

Notice carefully the Dockerfile that we created earlier. We added a new user john which is set as a default user for all the containers running using that Docker image. Let's verify this using the whoami command:

$ whoami
john

Now, if we try to install any packages into the container, we'll get the following error message:

$ apt-get update
Reading package lists... Done
W: chmod 0700 of directory /var/lib/apt/lists/partial failed - SetupAPTPartialDirectory (1: Operation not permitted)
E: Could not open lock file /var/lib/apt/lists/lock - open (13: Permission denied)
E: Unable to lock directory /var/lib/apt/lists/

In this case, the non-root user cannot access the lock file. In general, this user will have restricted access to the container.

Let's now exit the container and re-login using the root user.

3.2. Using the Root User

In order to exec using the root user inside the Docker container, we'll use the –u option:

$ docker exec -it -u 0 baeldung bash

Using the “-u” option of the docker exec command, we define the id of the root user. We can also use the user name in this command:

$ docker exec -it -u root baeldung bash

In order to check the current user details, we'll run the whoami command:

$ whoami
root

This time, we've entered the container as a root user. Now, we can perform any operations on the container:

$ apt-get update
Hit:1 http://security.ubuntu.com/ubuntu xenial-security InRelease
Hit:2 http://archive.ubuntu.com/ubuntu xenial InRelease
Hit:3 http://archive.ubuntu.com/ubuntu xenial-updates InRelease
Hit:4 http://archive.ubuntu.com/ubuntu xenial-backports InRelease
Reading package lists... Done  

It can be seen from the above output that the update command succeeded, and the root user has access to the lock file. With the root user's full privileges, we can change any file without any problem.

As an alternative, we can also access the Docker container as root. In this case, we'll use the nsenter command to access the Docker container. To use the nsenter command, we must know the PID of the running container.

Let's take a look at the command to get the PID of the container:

$ docker inspect --format {{.State.Pid}} baeldung
6491

Once we have the PID, we'll use this PID with the nsenter command in the following way:

$ nsenter --target 6491 --mount --uts --ipc --net --pid

This allows us to access the Docker container as a root user and run any command to access any file.

4. Using sudo Command Inside the Container

Docker containers typically run with root as the default user. To share resources with different privileges, we may need to create additional users inside a Docker container.

Here, we'll create a Dockerfile and add a new user. Importantly, we'll also install the sudo package in the Docker container while building the image. When this user needs extra privileges, it can access them using the sudo command.

Let's check out the Dockerfile:

FROM ubuntu:16.04
RUN apt-get update && apt-get -y install sudo
RUN useradd -m john && echo "john:john" | chpasswd && adduser john sudo
USER john
CMD /bin/bash

This Dockerfile uses the image “ubuntu:16.04” as the base image, installs the sudo package, and creates a new user, “john“. We are using the chpasswd command to add a password to the john user. After that, we use it as a default user.

Let's run the command to build the image:

$ docker build -t baeldung .

The above command will create the baeldung image. Now, let's run the container using the baeldung image:

$ docker run -id --name baeldung baeldung
b0f83a7e8b49ddf043c80792f21d5c483c0c5ab56c700815a83b0a40e5292754

The default user of the container is john, so we'll use that to access the container:

$ docker exec -it baeldung bash
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

Let's run the whoami command to find out the user name of the logged-in user:

$ whoami
john

This confirms that we logged in as a non-root user. If we run the apt-get update command, we will run into the same permission-related issue we faced in section 3.2.

This time, we'll use the sudo command to get the privilege for the non-root user john:

$ sudo apt-get update
[sudo] password for john: 
Get:1 http://security.ubuntu.com/ubuntu xenial-security InRelease [99.8 kB]
Hit:2 http://archive.ubuntu.com/ubuntu xenial InRelease 
Get:3 http://archive.ubuntu.com/ubuntu xenial-updates InRelease [99.8 kB]
Get:4 http://archive.ubuntu.com/ubuntu xenial-backports InRelease [97.4 kB]
Fetched 297 kB in 1s (178 kB/s)
Reading package lists... Done

By using this approach, we can run any command within non-root accounts using the sudo command.

5. Conclusion

In this article, we demonstrated how to run commands inside a Docker container with different users. First, we discussed the role of root and non-root users in a running Docker container. Then, we learned how to access the Docker container as a root user to gain extra privileges.

Ideally, we should not allow root access to the Docker container. This adds more security concerns. Instead, we should create a separate user to access the containers. This is a standard security step in the container world.

Generic bottom

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> CHECK OUT THE COURSE
Generic footer banner
2 Comments
Oldest
Newest
Inline Feedbacks
View all comments
Comments are closed on this article!