Running Docker images
Overview
Teaching: 10 min
Exercises: 25 minQuestions
How do you run an image?
How can you access it?
Objectives
Run a Docker image.
Fetch logs from running a container.
Obtain a shell inside a container.
This is an introduction to running and accessing pre-built Docker images.
Where do images come from?
Docker (the organisation) hosts a central registry of images: https://hub.docker.com/explore/. You can easily use third party registries, or run your own.
Docker Hub is like any other application or source code repository. There are some official images (e.g. ubuntu
), but anyone can push anything to it under a prefix (user or organisation name).
Running Docker images interactively
First fetch an image:
docker pull rockylinux:9
9: Pulling from library/rockylinux
4c81ef64b3e1: Pull complete
Digest: sha256:d7be1c094cc5845ee815d4632fe377514ee6ebcf8efaed6892889657e5ddaaa6
Status: Downloaded newer image for rockylinux:9
docker.io/library/rockylinux:9
rockylinux
: The name of the Docker image that you want to run:9
: The version/tag of the Docker image (default is:latest
)
Then run it:
docker run -it rockylinux:9 bash
[root@2b5f11235d99 /]#
You now have a bash shell inside your Docker container.
-it
: Run “interactively”bash
: The arguments to pass to the Docker image (most images have a default so this can often be omitted)
Make some changes inside the container:
echo hello world > hello.txt
ls
afs bin dev etc hello.txt home lib lib64
lost+found media mnt opt proc root run
sbin srv sys tmp usr var
The default user in the rockylinux
image is root
, so you can install things:
dnf install -y wget
Exit the container:
exit
Now run the same command again:
docker run -it rockylinux:9 bash
List the files again:
ls
afs bin dev etc home lib lib64
lost+found media mnt opt proc root run
sbin srv sys tmp usr var
hello.txt
is missing. This is a completely new container.
Exit the container:
exit
Running Docker images in the background (-d
/--detach
)
Running images interactively is a useful for testing or development, for example if you want to test some installation instructions for OMERO, or check whether OMERO will compile with an updated system library.
Often you will want to run an image in the background.
First pull
the nginx
image:
docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
b16f1b166780: Pull complete
c9a20772aff4: Pull complete
5c242ffc14bb: Pull complete
bf2e7af999d2: Pull complete
5cbad9890292: Pull complete
4cf85f4d417b: Pull complete
99f78d9a3fb1: Pull complete
Digest: sha256:fb39280b7b9eba5727c884a3c7810002e69e8f961cc373b89c92f14961d903a0
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
Pulling an image will download the image if it does not exist, or update it if it does. The latter is a like git pull
on a branch.
Now run it in the background using the -d
/--detach
flag:
docker run -d --name my-nginx nginx
b9ba7a701e1f59a9366ac7b88899d81a9262aeb671ac1d0cab7344ddfe8bb3ef
All containers have an ID. --name
is used to give a human-readable name my-nginx
to the running container.
List all running containers:
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b9ba7a701e1f nginx "/docker-entrypoint.…" About a minute ago Up About a minute 80/tcp my-nginx
What happens if you run another container with the same name?
docker run -d --name my-nginx nginx
docker: Error response from daemon: Conflict. The container name "/my-nginx" is already in use by container "b9ba7a701e1f59a9366ac7b88899d81a9262aeb671ac1d0cab7344ddfe8bb3ef". You have to remove (or rename) that container to be able to reuse that name.
See 'docker run --help'.
Listing containers (ps
)
List running containers using the ps
command:
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d90cdd419eb6 nginx "/docker-entrypoint.…" 4 seconds ago Up 3 seconds 80/tcp my-nginx
List containers including those that aren’t running:
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d90cdd419eb6 nginx "/docker-entrypoint.…" 52 seconds ago Up 51 seconds 80/tcp my-nginx
a7a77a946eaa rockylinux:9 "bash" 2 minutes ago Exited (0) 2 minutes ago great_khorana
Stopping and removing containers (stop
, rm
)
Stop the Nginx container:
docker stop my-nginx
my-nginx
And delete it:
docker rm my-nginx
my-nginx
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a7a77a946eaa rockylinux:9 "bash" 2 minutes ago Exited (0) 2 minutes ago great_khorana
Connecting to a port (-p
/--publish
)
In the output of docker ps
you might have noticed 80/tcp
. This indicates Nginx is listening on port 80 inside the container, but to access it from outside the container you must setup port-forwarding using the -p
/--publish
argument.
Syntax: -p external-host-port-number:internal-container-port-number
docker run -d --name my-nginx -p 12345:80 nginx
8f52b7ddfd8fea65112945cd346b38024fa465938bf6b07f99a204a878b397ac
List running containers again:
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
829209f5ed46 nginx "nginx -g 'daemon ..." 2 seconds ago Up 1 second 0.0.0.0:12345->80/tcp my-nginx
This time you can see 0.0.0.0:12345->80/tcp
, which indicates port 12345 on the server running docker will be forwarded to port 80 in the container. Open http://localhost:12345 and you should see a Welcome to nginx!
page.
If you have multiple ports you can pass the -p
argument multiple times. Docker can automatically setup port forwarding for you if you pass the -P
flag:
docker rm -f my-nginx
docker run -d --name my-nginx -P nginx
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
69f7daadf908 nginx "nginx -g 'daemon ..." 4 seconds ago Up 3 seconds 0.0.0.0:32768->80/tcp my-nginx
This time open http://localhost:32768 (change 32768
to whichever port Docker has chosen for you).
Accessing the container directly
Most containers are written to only run one application so won’t have SSH enabled. If you need to access a container, e.g. for debugging, use the exec
command.
For example, cat the nginx.conf
file in the container:
docker exec my-nginx cat /etc/nginx/nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
...
You can run bash interactively inside the container:
docker exec -it my-nginx bash
root@69f7daadf908:/#
id
exit
uid=0(root) gid=0(root) groups=0(root)
In general you should not need to use docker exec
on a production container.
Viewing container outputs and logs
A well designed container will print out its logs to stdout. These can be viewed with the logs
command:
docker logs my-nginx
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2025/06/10 12:02:07 [notice] 1#1: using the "epoll" event method
2025/06/10 12:02:07 [notice] 1#1: nginx/1.27.5
2025/06/10 12:02:07 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14)
2025/06/10 12:02:07 [notice] 1#1: OS: Linux 5.10.76-linuxkit
2025/06/10 12:02:07 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2025/06/10 12:02:07 [notice] 1#1: start worker processes
2025/06/10 12:02:07 [notice] 1#1: start worker process 30
2025/06/10 12:02:07 [notice] 1#1: start worker process 31
2025/06/10 12:02:07 [notice] 1#1: start worker process 32
2025/06/10 12:02:07 [notice] 1#1: start worker process 33
172.17.0.1 - - [10/Jun/2025:12:02:49 +0000] "GET / HTTP/1.1" 200 615 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36" "-"
2025/06/10 12:02:50 [error] 32#32: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 172.17.0.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "localhost:12345", referrer: "http://localhost:12345/"
172.17.0.1 - - [10/Jun/2025:12:02:50 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "http://localhost:12345/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36" "-"
172.17.0.1 - - [10/Jun/2025:12:02:57 +0000] "\x16\x03\x01\x07\x12\x01\x00\x07\x0E\x03\x03+\xEB\xF2\x9A\xE7P\xDE_\xD1\xF3\xD6\x0E\xA1P?\xAE\x98v\x11J\xCA\xCC\xF4u\xC6\x86!\xDE\xD8\xEB\x98\x83 \xFF\x90\xDA\x5C\xCC\xA1c\xD9\x0F\xC4'\x9E\x04\xACu\xFE\xF7\x80=\xBB\xB0\xB6\xEF\x9B\x1B`ax\x0B\xC4\x13\xEA\x00 \xEA\xEA\x13\x01\x13\x02\x13\x03\xC0+\xC0/\xC0,\xC00\xCC\xA9\xCC\xA8\xC0\x13\xC0\x14\x00\x9C\x00\x9D\x00/\x005\x01\x00\x06\xA5zz\x00\x00\xFF\x01\x00\x01\x00\x00+\x00\x07\x06" 400 157 "-" "-" "-"
172.17.0.1 - - [10/Jun/2025:12:02:57 +0000] "\x16\x03\x01\x06\xF2\x01\x00\x06\xEE\x03\x03\xC4*" 400 157 "-" "-" "-"
172.17.0.1 - - [10/Jun/2025:12:02:57 +0000] "\x16\x03\x01\x07\x12\x01\x00\x07\x0E\x03\x03\x02yJ\xFAv\x17\xBC\xD7\x0E_C.\xFC\xB3\x06\x1C\xEB\x16\xA2\xBC\xA0Hkd\x22\xC6\xF9\x16\x82\xDC\xE2Z \xDF\xE7\xAC+\xC3\xF8'\x82T\xBE\xC3\xDD\x00Pu\x96r\xC4R\xEC\xDF\xA7\xF6\xD8{\xDEg4\xE2\xF4r\x03\x00 JJ\x13\x01\x13\x02\x13\x03\xC0+\xC0/\xC0,\xC00\xCC\xA9\xCC\xA8\xC0\x13\xC0\x14\x00\x9C\x00\x9D\x00/\x005\x01\x00\x06\xA5\xAA\xAA\x00\x00\x00\x1B\x00\x03\x02\x00\x02D\xCD\x00\x05\x00\x03\x02h2\x00\x12\x00\x00\x00" 400 157 "-" "-" "-"
172.17.0.1 - - [10/Jun/2025:12:02:57 +0000] "\x16\x03\x01\x06\xD2\x01\x00\x06\xCE\x03\x03m+\x92n\xF5\xAA;\xED\xBB9\x97\x05]V\xAA\xEF<\x0F\xAD\xBA\x99\xF2\x9F\x7F\x80\x15\x97{\x91\xDD\xAE\x14 \x97n`\xF85wf\xA4\xF2\xD2\x12n\x8C&a\xD4\x1E\xAC\x84\x9D\x18\xBA\xB2\x0CI1," 400 157 "-" "-" "-"
Following docker logs in real-time
All docker commands have a built-in
--help
argument. Can you rundocker logs
so that when you visit http://localhost:NNNNN you see a log message immediately?Solution
docker logs -f my-nginx
Adding content to a running docker container
The docker cp
command can copy files to and from a running container.
For example, copy the nginx.conf file to your computer:
docker cp my-nginx:/etc/nginx/nginx.conf .
ls
Create a new local file called nginx-new-index.html, and copy this into the Nginx html directory:
docker cp nginx-new-index.html my-nginx:/usr/share/nginx/html/index.html
Refresh your browser, you should see your new index page.
There are other ways of sharing files with a docker container, these will be covered later.
Key Points
Docker Hub is a repository of prebuilt Docker images
docker run
always creates a new container
docker ps
lists containers
docker logs
will fetch application logs in a well-designed containerWhen developing or testing
docker exec
anddocker cp
may be useful