In this article we will be running your first container, and learn how to inspect it. You will be able to witness the namespace isolation that you acquire from the Linux kernel.
what are containers
Containers are just a process (or a group of processes) running in isolation, which is achieved with Linux namespaces and control groups. Linux namespaces and control groups are features that are built into the Linux kernel. Other than the Linux kernel itself, there is nothing special about containers.
Open a terminal on your local computer and run this command:
C:\Users\Gabriel.ufot>docker container run -t ubuntu top
You use the docker container run command to run a container with the Ubuntu image by using the top command. The -t flag allocates a pseudo-TTY, which you need for the top command to work correctly.
The docker run command first starts a docker pull to download the Ubuntu image onto your host. After it is downloaded, it will start the container. The output for the running container should look like this:
C:\Users\Gabriel.ufot>docker container run -it ubuntu top top - 12:07:03 up 1:49, 0 users, load average: 0.05, 0.09, 0.0 Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zom %Cpu(s): 0.0 us, 0.1 sy, 0.0 ni, 99.8 id, 0.0 wa, 0.0 hi, 0 MiB Mem : 7849.0 total, 5867.2 free, 879.7 used, 1102.1 MiB Swap: 2048.0 total, 2048.0 free, 0.0 used. 6740.7 PID USER PR NI VIRT RES SHR S %CPU %MEM 1 root 20 0 7296 3372 2840 R 0.0 0.0
The -t flag allocates a pseudo-terminal for the container, which provides an interface to interact with the command prompt of the container. However, unlike the -i flag, the -t flag does not keep STDIN (Standard Input) open. This means that you won't be able to actively input or interact with the command prompt; you will only see the output of the top command.
top is a Linux utility that prints the processes on a system and orders them by resource consumption. Notice that there is only a single process in this output: it is the top process itself. You don't see other processes from the host in this list because of the PID namespace isolation.
Containers use Linux namespaces to provide isolation of system resources from other containers or the host. The PID namespace provides isolation for process IDs. If you run top while inside the container, you will notice that it shows the processes within the PID namespace of the container, which is much different than what you can see if you ran top on the host.
Even though we are using the Ubuntu image, it is important to note that the container does not have its own kernel. It uses the kernel of the host and the Ubuntu image is used only to provide the file system and tools available on an Ubuntu system.
Open a new terminal
When you open a new terminal, get the ID of the running container that you just created:
docker container ls
C:\Users\Gabriel.ufot>docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1a5cde7becd5 ubuntu "top" 28 seconds ago Up 25 seconds elastic_lamarr
Use that container ID to run bash inside that container by using the docker container exec command. Because you are using bash and want to interact with this container from your terminal, use the -it flag to run using interactive mode while allocating a psuedo-terminal:
C:\Users\Gabriel.ufot>docker exec -it 1a5cde7becd5 bash root@1a5cde7becd5:/#
You just used the docker container exec command to enter the container's namespaces with the bash process. Using docker container exec with bash is a common way to inspect a Docker container.
Notice the change in the prefix of your terminal, for example, root@1a5cde7becd5:/#. This is an indication that you are running bash inside the container.
From the same terminal, inspect the running processes:
$ ps -ef
root@1a5cde7becd5:/# ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 13:31 pts/0 00:00:01 top root 7 0 1 14:20 pts/1 00:00:00 bash root 15 7 0 14:20 pts/1 00:00:00 ps -ef
You should see only the top process, bash process, and your ps process.
for comparison, exit the container and run ps -ef or top on the host. These commands will work on Linux or Mac. For Windows, you can inspect the running processes by using tasklist.
C:\Users\Gabriel.ufot>exit exit >tasklist # Lots of processes!
PID is just one of the Linux namespaces that provides containers with isolation to system resources. Other Linux namespaces include:
- MNT: Mount and unmount directories without affecting other namespaces.
- NET: Containers have their own network stack.
- IPC: Isolated interprocess communication mechanisms such as message queues.
- User: Isolated view of users on the system.
- UTC: Set hostname and domain name per container.
These namespaces provide the isolation for containers that allow them to run together securely and without conflict with other containers running on the same system.
In the next lab, you'll see different uses of containers and the benefit of isolation as you run multiple containers on the same host.
Clean up the container running the top processes:
explore the docker store
When searching for images, you will find filters for Store and Community images. Store images include content that has been verified and scanned for security vulnerabilities by Docker. Go one step further and search for Certified images that are deemed enterprise-ready and are tested with Docker Enterprise Edition.
Run an NGINX server by using the official NGINX image from the Docker Store:
docker container run --detach --publish 8080:80 --name nginx nginx
C:\Users\Gabriel.ufot>docker container run --detach --publish 8080:80 --name nginx nginx 7552414e384f552db2f97e247c124e3ff17cd502db7be5bb1f503cb9534d53fe
The --detach flag will run this container in the background. The publish flag publishes port 80 in the container (the default port for NGINX) by using port 8080 on your host. Remember that the NET namespace gives processes of the container their own network stack. The --publish flag is a feature that can expose networking through the container onto the host.
port 80 is the default port for NGINX, because it is listed in the documentation on the Docker Store
You are also specifying the --name flag, which names the container. Every container has a name. If you don't specify one, Docker will randomly assign one for you
Because this is the first time you are running the NGINX container, it will pull down the NGINX image from the Docker Store. Subsequent containers created from the NGINX image will use the existing image located on your host.
NGINX is a lightweight web server. You can access it on port 8080 on your localhost.
Access the NGINX server on http://localhost:8080.
Run a MongoDB server.
You will use the official MongoDB image from the Docker Store. Then use the latest tag.
C:\Users\Gabriel.ufot>docker container run --detach --publish 8081:27017 --name mongo mongo:latest Unable to find image 'mongo:latest' locally latest: Pulling from library/mongo 9d19ee268e0d: Pull complete 84c1327991fa: Pull complete 1feec59ecd14: Pull complete 3af7480eaf55: Pull complete d7524ee16ced: Pull complete f4742175eefc: Pull complete 9d688a8d9c18: Pull complete 865b2fb03178: Pull complete f01ec0b7fbdb: Pull complete Digest: sha256:20f3adcaffe2193e49dd502c8299b770d49a1e0643e0e9db250d5c127b1e9ed8 Status: Downloaded newer image for mongo:latest 492eddd0fe36b1a4523119d9132176fe1a7baf31f3f29346a95b1e47c1923c35
Because this is the first time you are running a Mongo container, pull the Mongo image from the Docker Store. You use the --publish flag to expose the 27017 Mongo port on your host. You must use a port other than 8080 for the host mapping because that port is already exposed on your host. See the documentation on the Docker Store to get more information about using the Mongo image.
Access http://localhost:8081 to see some output from Mongo.
MongoDB is a NoSQL database server, not a web server. It uses its native protocol to handle data requests, not HTTP.
When you run the MongoDB container using the command docker container run --detach --publish 8081:27017 --name mongo mongo:latest, it correctly exposes the MongoDB port 27017 from the container to port 8081 on the host. This means you can use MongoDB client applications (e.g., MongoDB shell) to connect to the MongoDB server via localhost:8081 using the native MongoDB driver, not a web browser.
To interact with MongoDB using a web interface, you can use tools like MongoDB Compass or web-based admin interfaces like RockMongo or Mongo Express. However, these tools must be installed separately, and you will need to configure them to connect to the MongoDB server using the native MongoDB protocol, not HTTP.
In summary, you've successfully exposed the MongoDB port, but to interact with MongoDB, you need to use the MongoDB client applications, not a web browser. If you want a web-based interface to interact with MongoDB, you'll need to install and configure a suitable MongoDB admin tool.
Finally, check your running containers
docker container ls or
C:\Users\Gabriel.ufot>docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 492eddd0fe36 mongo:latest "docker-entrypoint.s…" 15 minutes ago Up 14 minutes 0.0.0.0:8081->27017/tcp mongo 7552414e384f nginx "/docker-entrypoint.…" About an hour ago Up About an hour 0.0.0.0:8080->80/tcp nginx 1a5cde7becd5 ubuntu "top" 6 days ago Up 8 seconds elastic_lamarr
You should see that you have an NGINX web server container and a MongoDB container running on your host. Note that you have not configured these containers to talk to each other.
You can see the nginx and mongo names that you gave to the containers and the random name (in this example, elastic_lamarr) that was generated for the Ubuntu container. You can also see that the port mappings that you specified with the --publish flag. For more information on these running containers, use the docker container inspect [container id] command.
Containers are self-contained and isolated, which means you can avoid potential conflicts between containers with different system or runtime dependencies. For example, you can deploy an app that uses Django 2 and another app that uses Django 3 on the same host. Or you can run multiple NGINX containers that all have port 80 as their default listening ports. (If you're exposing on the host by using the --publish flag, the ports selected for the host must be unique.) Isolation benefits are possible because of Linux namespaces.
Remember: You didn't have to install anything on your host (other than Docker) to run these processes! Each container includes the dependencies that it needs within the container, so you don't need to install anything on your host directly.
Running multiple containers on the same host gives us the ability to use the resources (CPU, memory, and so on) available on single host. This can result in huge cost savings for an enterprise.
In conclusion, this article provided a comprehensive introduction to Docker containers and how to run and inspect them. Containers, in essence, are isolated processes or groups of processes running within the Linux kernel's namespaces and control groups. They are not separate virtual machines; instead, they share the host system's kernel, making them lightweight and efficient.
Embrace the containerverse and witness the wonders of isolation and efficiency as you embark on your Docker journey. Whether you're a developer, system administrator, or DevOps enthusiast, mastering Docker will undoubtedly elevate your skills and enhance your software development and deployment workflows. So, take the leap into the world of containers, where possibilities are boundless, and innovation knows no limits. Happy containerizing!