In this article, we’re going to be exploring in depth how to work with Docker containers from the command line. If you’re new to Docker I recommend checking out this introduction to get started with some of the concepts we’ll be using.
Creating a Container
To create a new container we’re going to need a base image to run or do anything inside of our container, for that we’ll start with the NGINX image from Dockerhub, so we can play with starting a basic server. The command syntax is pretty straight forward, and generally follows the form of
docker [type] [command] [properties/flags].
$ docker container create nginx
This checks your image cache before sending a request to Dockerhub for the latest NGINX image. If you were to run this again it’ll be much faster since it won’t need to be re-downloaded.
— Sorry to interrupt this program! 📺
If you're interested in learning Node in a comprehensive and structured way, I highly recommend you try Wes Bos' Learn Node course. Learning from a premium course like that is a serious investment in yourself.
Plus, this is an affiliate link, so if you purchase the course you help Alligator.io continue to exist at the same time! 🙏
Our container’s created but not running, we can see all of our containers by using
ls to list them, and the
-a flag to search for all, active and inactive. You could also use the older format
docker ps -a.
$ docker container ls -a
You should see a table with information about your new NGINX container, most importantly the
CONTAINER ID and
NAMES columns. We’ll use any of those two to start our new container.
You don't need to use the full ID, just enough to make sure it's unique, 3 or 4 characters is fine.
$ docker container start [Container_name/ID]
Listing your containers without the
-a flag should show your new active server. The problem now is that there’s no way to access it from the outside. We can establish a port with the
-p flag (short for publish) and pass it the port we want it available on and port the server is located on, which for NGINX is port 80 by default.
-p 4000:80 should let us access it on port 4000.
Instead of working with IDs or the auto generated name, let’s give it a name of our own with the
--name flag. Using the
run command is a nice shortcut for running
$ docker container run -p 4000:80 --name new_server nginx
Now you can visit your new server on either
localhost:4000, if you’re on mac, or with the IP that Docker gives you similar to
192.168.99.100 instead of localhost, if you’re on windows.
Stopping and Removing Containers
Now you have two running NGINX containers and only need the latest. We can stop it with the
stop command then remove it with
$ docker container stop [Container_name/ID] $ docker container rm [Container_name/ID]
Docker doesn’t want you to be able to stop and delete containers at the same time, since that could be done by accident, but you can force it if you need to with the
You can list more than one container at a time.
$ docker container rm [Container_name/ID] -f
Looking Inside Containers
Let’s get inside of a container and see what we’re really working with. There are two flags that will let us do this, the
-i flag will let us interact with our container and
-t to format the log output in a more useful way. It’s pretty common to just chain them together.
Alpine is a Linux based operating system that is very basic and perfect for a minimalist base image. We can use the
sh command to be immediately moved into a shell terminal inside our container.
$ docker container run -it --name new_project alpine sh
Now this should work just like any other shell terminal, run
ls to see all the files and start exploring this mini OS cut off from the rest of our machine.
|Creates a new container|
|Runs an existing container|
|Creates then starts a new container|
|Stops a running container|
|Deletes a stopped container|
|Logs all running containers|
|Logs all running containers (deprecated)|
|Opens a shell terminal|
|-a||–all||Forces log of all output|
|-p||–publish||Maps a container to a port|
|-f||–force||Forces a command|
|-i||Allows you to interact with a running container|
|-t||Formats output to be more readable|
Working with single containers is pretty simple to get the hang of, but the complexity will only grow as you start working with multiple containers per project and try to manage the relationships between them. That’s why it’s essential to get comfortable with the basic operations now.
In future articles, we’ll look deeper into creating our own images and getting projects to work inside our little oasis.