tips for using docker run
Share on facebook
Share on twitter
Share on linkedin

Getting Started with Docker Run

KeithThompson
KeithThompson

Docker is a technology that quickly went from inception to being a backbone technology for many industries and companies. This rapid growth has meant almost everyone working in technology from development to DevOps needs to have a basic understanding of how to use Docker. The first step for anyone who wants to learn Docker should be to learn how to use docker run. This post will teach you the ins-and-outs of getting started with Docker using docker run.

The Docker Hello World

As when starting with almost any technology topic, we’re going to begin by running a “hello, world” program. This is such a common thing to do that Docker (the company) maintains a “hello-world” image. Let’s run our hello world and break down exactly what is happening:Note: Make sure you can connect to Docker before running this command.

$ docker run hello-worldUnable to find image 'hello-world:latest' locallylatest: Pulling from library/hello-world1b930d010525: Pull completeDigest: sha256:2557e3c07ed1e38f26e389462d03ed943586f744621577a99efb77324b0fe535Status: Downloaded newer image for hello-world:latestHello from Docker!This message shows that your installation appears to be working correctly.To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.    (amd64) 3. The Docker daemon created a new container from that image which runs the    executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it    to your terminal.To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bashShare images, automate workflows, and more with a free Docker ID: https://hub.docker.com/For more examples and ideas, visit: https://docs.docker.com/get-started/

This is a pretty helpful message, partially explaining what happened. The main thing that isn’t explained in this message is that the container ran the executable that printed this output and then immediately stopped running. This is one of the fundamental ideas when working with containers: Each container only runs one process — and when the process stops, so does the container.

Breaking Down the docker run Command

In our hello world, we used the docker run command with a single positional argument (hello-world) that represents the name of the image we would like to use to create the container. This is the base for all docker run commands, and we’ll be looking at the main options we can pass to this command to make it more useful and achieve specific results.

Adding Interactivity

Containers are great for trying out new technologies without needing to install things to your local workstation. If you wanted to learn Python, but you don’t want to mess with your local Python installation, you could run a Python container in interactive mode, and it would function similar to what you would experience on a Linux server. Let’s create a container that has Python 3.7 pre-installed so we can take it for a spin. If we take a look at all of the available options for docker run (via docker run --help), we’ll see there is a -i option, so let’s use that and see what happens. Since we want a specific version of Python, we’ll add the 3.7 tag to our image name using a colon (:):

$ docker run -i --name python37 python:3.7Unable to find image 'python:3.7' locally3.7: Pulling from library/python741437d97401: Pull complete34d8874714d7: Pull complete0a108aa26679: Pull complete7f0334c36886: Pull complete65c95cb8b3be: Pull complete9107d7193263: Pull completedd6f212ec984: Pull complete43288b101abf: Pull completef68aede0db03: Pull completeDigest: sha256:fb877e7ea5c40de100534c6d6f515c486247bfd899cb2767f2de0e876a8127faStatus: Downloaded newer image for python:3.7

We’re once again left with a prompt that appears to be hanging, but we’re actually in a Python REPL (Read, Evaluate, Print, Loop), so we can type Python code in and it will be run. This isn’t quite what we want, so let’s hit Ctrl-D to exit from this prompt and try again. This time, we’ll also add the -t flag to create a pseudo-TTY so we can see the prompt we’ve connected to.We did name this container so it’s not randomly generated and it’s easy for us to remove. Let’s remove the python37 container before creating it again with the TTY:

$ docker rm python37python37$ docker run -it --name python37 python:3.7Python 3.7.2 (default, Feb  6 2019, 12:04:03)[GCC 6.3.0 20170516] on linuxType "help", "copyright", "credits" or "license" for more information.>>>

Since the default command for the python:3.7 image the python3 binary, we’re dropped into a REPL and this is exactly what we’d expect to see. It’s incredibly common to want to attach to a container to see what is going on within, and the -i and -t flags are necessary for that (commonly written as -it).

Backgrounding a Container

Running a container and having it immediately terminate is occasionally useful. We can use this approach to run a specific piece of work in a sandbox environment, but more often than not, we want to run a container for an extended period of time. When we want to run a server within a container, we need to consider two primary things:

  1. The process must be running in the foreground of the container. This means the image won’t daemonize the process.
  2. We need to daemonize the container using the -d flag.

Let’s use the nginx image from Docker Hub and run it in the background.

$ docker run -d nginxUnable to find image 'nginx:latest' locallylatest: Pulling from library/nginx6ae821421a7d: Pull completeda4474e5966c: Pull completeeb2aec2b9c9f: Pull completeDigest: sha256:dd2d0ac3fff2f007d99e033b64854be0941e19a2ad51f174d9240dda20d9f534Status: Downloaded newer image for nginx:latest14850ff85876c48ef2260f97313dadbd5ca32766ae3352416db60e82f4e772f2$

After the new image is downloaded, we’ll get dropped back into our standard prompt because we daemonized the container. We can see it is still running by using the docker ps command:

$ docker psCONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS               NAMES14850ff85876        nginx               "nginx -g 'daemon of…"   About a minute ago   Up About a minute   80/tcp              vigorous_mccarthy$

This output lets us know a few things:

  1. Our container’s ID (14850ff85876 in this case)
  2. The image used to create the container
  3. The command that is running within the container
  4. Ports that are exposed within the container
  5. The name of the container, which we can use as an alternative to the ID if we want to interact with this container

If we had run our command without the -d, we would have had our prompt appear to hang, when in reality we would be seeing the stdout logging from the NGINX process running in the foreground. As you can imagine, we don’t usually want to run server containers in the foreground unless we’re using the container for some development purpose.

Exposing Ports

As it stands right now, we can’t actually access our NGINX container’s content from the Docker host. To achieve this, we’ll need to map ports from our Docker host to ports within our container. The docker run command makes this easy by providing the --publish or -p option. We can use this option multiple times if there are multiple ports we need access to (such as 80 and 443 for HTTP and HTTPS). Let’s remove our NGINX container and recreate it exposing the ports:Note: your container name will be different than mine, find it by running docker ps.

$ docker stop vigorous_mccarthyvigorous_mccarthy$ docker run -d -p 8080:80 -p 4443:443 nginx6753df583a62c8c71db68a83c64acb71832a25572df8cdc1c63f7ad80cfb465a$ docker psCONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                         NAMES6753df583a62        nginx               "nginx -g 'daemon of…"   7 seconds ago       Up 6 seconds        0.0.0.0:8080->80/tcp, 0.0.0.0:4443->443/tcp   xenodochial_mccarthy

For each port we’d like to map back to the Docker host, we can use another -p option where we’re mapping HOST_PORT:CONTAINER_PORT. Now we’re able to get more use out of running servers inside of Docker containers.

Setting Environment Variables

Finally, the last common thing we’ll want to do when working with docker run is set an environment variable within the container. Environment variables are commonly used to configure the services running within the containers, and we once again have a simple flag to allow us to set these values: the --env or -e flag. Just like the -p flag, we can use this option multiple times to set multiple environment variables, but we’ll also be setting them using an equal sign = instead of a colon. If we wanted to run a PostgreSQL database, we could use the official postgres image, which allows us to specify some environment variables before creating a container to configure the initial database that will be created. Let’s create a linuxacademy database for the la_test user using environment variables. This command will combine a lot of what we’ve learned and we’ll separate it out onto multiple lines to make it a little easier to read:

$ docker run -d   --name postgres   -p 5432:5432   -e POSTGRES_USER=la_test   -e POSTGRES_PASSWORD=secret_password   -e POSTGRES_DB=linuxacademy   postgres3359c68bf647b471252de6196a26a5132fb0492f14fcb6d17a3238553ad11d13$

Now we have a database container running what we configured using environment variables. Using a PostgreSQL client, you could connect to the linuxacademy database using the Docker host’s IP address, the user of la_test,  and the password of secret_password. If you happen to have psql installed, it would look something like this (substitute your Docker host’s IP address for 192.168.99.100):

$ psql postgres://la_test:secret_password@192.168.99.100:5432/linuxacademypsql (11.1, server 10.4 (Debian 10.4-2.pgdg90+1))Type "help" for help.linuxacademy=# q$

Deepening Your Docker Understanding

I hope this post has provided you with a better understanding of how you can utilize the docker run command to create containers that do what you expect them to do, but this is just the beginning. If you’d like to learn even more about Docker, you should check out this free eBook or these hands-on courses below:

Good luck, and happy learning!

Recommended

Get more insights, news, and assorted awesomeness around all things cloud learning.

Sign In
Welcome Back!

Psst…this one if you’ve been moved to ACG!

Get Started
Who’s going to be learning?