Docker Multiple Containers

Docker Multiple Containers

Once you learn how to get a container up and running in Docker, you can then move on to running and managing multiple containers in the same docker engine for your environment. Much like anything else, practicing setting up containers, interacting with them, and tearing them down once done will get you comfortable with the process and workflow for managing containers. In this tutorial, we’ll practice by setting up 3 individual containers. One will be MySQL, another Nginx, and the last Apache.


MySQL Container

First up, we can spin up a MySQL container in Docker.

docker container run -d -p 3306:3306 --name db -e MYSQL_RANDOM_ROOT_PASSWORD=yes mysql
Unable to find image 'mysql:latest' locally
latest: Pulling from library/mysql
d121f8d1c412: Pull complete
f3cebc0b4691: Pull complete
1862755a0b37: Pull complete
489b44f3dbb4: Pull complete
690874f836db: Pull complete
baa8be383ffb: Pull complete
55356608b4ac: Pull complete
dd35ceccb6eb: Pull complete
162d8291095c: Pull complete
5e500ef7181b: Pull complete
af7528e958b6: Pull complete
Digest: sha256:e1bfe11693ed2052cb3b4e5fa356c65381129e87e38551c6cd6ec532ebe0e808
1309c4b670f02dfffe5ef3ae0c405867fdad81b61bb3a60f08018273d035830b

Apache Container

Now that MySQL is up and running, let’s get the Apache webserver started.

docker container run -d -p 8080:80 --name webserver httpd
Unable to find image 'httpd:latest' locally latest: Pulling from library/httpd                                                                                                                           d121f8d1c412: Already exists 
9cd35c2006cf: Pull complete 
b6b9dec6e0f8: Pull complete
fc3f9b55fcc2: Pull complete
802357647f64: Pull complete
Digest: sha256:5ce7c20e45b407607f30b8f8ba435671c2ff80440d12645527be670eb8ce1961
Status: Downloaded newer image for httpd:latest
d2659ccf4b39ad461b0352af1b096f5835726c8042f32916febd948e0c819482

Nginx Container

The last container we will launch is an Nginx Container.


docker container run -d -p 80:80 --name proxy nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
d121f8d1c412: Already exists
ebd81fc8c071: Pull complete
655316c160af: Pull complete
d15953c0e0f8: Pull complete
2ee525c5c3cc: Pull complete
Digest: sha256:c628b67d21744fce822d22fdcc0389f6bd763daac23a6b77147d0712ea7102d0
Status: Downloaded newer image for nginx:latest
5f65da618b6aae8e9cd223f7bba046c2efaf9573753fd9c40cdabca12593adfe

List Containers

Ok, all of those prior steps went well. Let’s view the running containers with the docker container ls command.

docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
5f65da618b6a        nginx               "/docker-entrypoint.…"   11 seconds ago      Up 10 seconds       0.0.0.0:80->80/tcp                  proxy
d2659ccf4b39        httpd               "httpd-foreground"       27 seconds ago      Up 26 seconds       0.0.0.0:8080->80/tcp                webserver
1309c4b670f0        mysql               "docker-entrypoint.s…"   40 seconds ago      Up 37 seconds       0.0.0.0:3306->3306/tcp, 33060/tcp   db

Test Port 80

We can test port 80 which our Nginx container is running on using both curl at the command line and also in a web browser. Looking Good!

curl http://localhost

StatusCode        : 200
StatusDescription : OK
Content           : <!DOCTYPE html>
                    <html>
                    <head>
                    <title>Welcome to nginx!</title>
                    <style>
                        body {
                            margin: 0 auto;
                            font-family: Tahoma, Verdana, Arial, sans-serif;
                        }                                                                                                                                                        </style>                                                                                                                                                     <...                                                                                                                                     RawContent        : HTTP/1.1 200 OK                                                                                                                                              Connection: keep-alive
                    Accept-Ranges: bytes
                    Content-Length: 612
                    Content-Type: text/html
                    Date: Wed, 30 Sep 2020 20:58:08 GMT
                    ETag: "5f32b03b-264"
                    Last-Modified: Tue, 11 Aug 2020 ...
Forms             : {}
Headers           : {[Connection, keep-alive], [Accept-Ranges, bytes], [Content-Length, 612], [Content-Type, text/html]...}
Images            : {}
InputFields       : {}
Links             : {@{innerHTML=nginx.org; innerText=nginx.org; outerHTML=<A href="http://nginx.org/">nginx.org</A>; outerText=nginx.org; tagName=A;
                    href=http://nginx.org/}, @{innerHTML=nginx.com; innerText=nginx.com; outerHTML=<A href="http://nginx.com/">nginx.com</A>;
                    outerText=nginx.com; tagName=A; href=http://nginx.com/}}
ParsedHtml        : System.__ComObject
RawContentLength  : 612

nginx is running as container


Test Port 8080

Testing port 8080 for the Apache server follows the same process whether with curl or the browser. Apache responds with a simple “It Works!”

curl http://localhost:8080

StatusCode        : 200
StatusDescription : OK
Content           : <html><body><h1>It works!</h1></body></html>

RawContent        : HTTP/1.1 200 OK
                    Keep-Alive: timeout=5, max=100
                    Connection: Keep-Alive
                    Accept-Ranges: bytes
                    Content-Length: 45
                    Content-Type: text/html
                    Date: Wed, 30 Sep 2020 21:03:11 GMT
                    ETag: "2d-432a5e4a73a80...
Forms             : {}
Headers           : {[Keep-Alive, timeout=5, max=100], [Connection, Keep-Alive], [Accept-Ranges, bytes], [Content-Length, 45]...}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : System.__ComObject
RawContentLength  : 45

apache running as container


Stop All The Containers

We want to clean up our Docker environment, so let’s stop all the running containers by name.

docker container stop db webserver proxy
db
webserver
proxy

Confirm Containers Are Exited

The status shows as exited so we know the containers are not running.

docker container ls -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES
5f65da618b6a        nginx               "/docker-entrypoint.…"   11 minutes ago      Exited (0) 59 seconds ago                       proxy
d2659ccf4b39        httpd               "httpd-foreground"       12 minutes ago      Exited (0) 58 seconds ago                       webserver
1309c4b670f0        mysql               "docker-entrypoint.s…"   12 minutes ago      Exited (0) 58 seconds ago                       db

Remove The Containers

No need to keep these containers around if we are done with the exercise, so let’s go ahead and remove them.

docker container rm db webserver proxy
db
webserver
proxy

Containers Are Gone

Confirming the continaers both running and not running are gone.

docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

Remove Images

While we’re cleaning things up, we can also remove the images we used to power the containers.

docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
httpd               latest              417af7dc28bc        2 weeks ago         138MB
nginx               latest              7e4d58f0e5f3        2 weeks ago         133MB
mysql               latest              e1d7dc9731da        2 weeks ago         544MB


docker image rm httpd nginx mysql
Deleted: sha256:ba0c2ff8d3620c0910832424efef02787214013b1c5b1d9dc9d87d638e2ceb71
Deleted: sha256:db9c97c9ad968b91c4499e5cca7435a155bfef6f5fb9c6cd5543481e47ff4f71
Deleted: sha256:8cdd4c6014e71c2f6ff38dadcaec2003b955230d38831e85db5a44fa38320e6b

Images Are Gone

Lastly, we check for any images in our Docker environment and sure enough, there are none. We have a nice clean environment to work with once again.

docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

Learn More


Summary

We can see launching more than one container is not all that hard. In the examples above we were able to get several containers up and running, test out their services, and then stop and remove them from Docker. Some takeaways include:

  • docker container ls -a and docker ps -a do the same thing. Both show all containers whether running or stopped.
  • When adding -d to docker run, you tell the container to run in detached mode. In other words, run in the background. No logs are displayed to the host terminal when configured this way.
  • docker container run -p 80:80 -d nginx and docker container run -p 8080:80 -d nginx will spin up two Nginx containers. There is no conflict even though both are listening on port 80 in the container. The left numbers which are the host port, are different (80 vs 8080).