Docker Quick Start Guide
Docker Workflow
The rough flow up to starting a container is as follows.
- Write code.
- Build a Docker image.
- Push the image to a repository.
- Download the image in the production environment.
- Start the container.
docker pull: Download a Docker Image
First, as a way to use something already created up to step 2, let’s look at the docker pull command.
You can download images uploaded to Docker Hub. You can also download images from a separately built Docker registry other than Docker Hub.
The command for downloading an image has the following format.
docker pull [image name](:version)
For example, pulling nginx looks like this.
$ docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
5b1423465504: Pull complete
1cdde8b981f2: Pull complete
6c0b05f215c0: Pull complete
004f1937a10a: Pull complete
fd61d71c75fe: Pull complete
717bf61a04cf: Pull complete
Digest: sha256:b95a99feebf7797479e0c5eb5ec0bdfa5d9f504bc94da550c2f58e839ea6914f
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
You can also specify a version by adding a tag after the image name. If nothing is specified, the latest version (latest) is used.
To specify a version for nginx, use the following.
$ docker pull nginx:1.21.1
docker images: List Docker Images
You can check the list of downloaded or created images with the following command.
docker images
For example, the command output is displayed as follows.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest fc5ec3f147e4 13 days ago 135MB
docker rmi: Delete a Docker Image
Images that are no longer needed can be deleted with the following command.
docker rmi [image ID|image name]
For example, deleting nginx with rmi looks like this.
$ docker rmi nginx
Untagged: nginx:latest
Untagged: nginx@sha256:b95a99feebf7797479e0c5eb5ec0bdfa5d9f504bc94da550c2f58e839ea6914f
Deleted: sha256:fc5ec3f147e43825672b6b308944040fa0ba4a547f4b50e911770f0d154eeed0
Deleted: sha256:3e85098616c4513b241d95d1a0c49740da10d191738bdd6b9220eab71ad15ddb
Deleted: sha256:714a2b51cf12dfc0219555fc2c71ff56a99da0f257fc1e81fbdc722d55821519
Deleted: sha256:ca9b331c8e9078528f222eacfdff111fc19a511e3f6282d307780b2d06da0e2a
Deleted: sha256:082aa9054c2265e06a3a62ab2afdbeb22768565808c7e5143f4652a997825b06
Deleted: sha256:f5355920965616631532773783ab892ba7d5b686833964b34968bd64d22b5521
Deleted: sha256:21ec097e7be7f53b7882fa719131a83be79e5b65e73993fa54929e5065e5b3e5
After deleting it, check whether it was actually removed.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
You can confirm that nginx was deleted by the rmi command above.
docker run: Run Docker
To start a container from a Docker image, run the following command.
docker run [image name] (options)
You can start it without adding any options, but the following options are available for more convenient use.
Only commonly used options are listed here, so refer to the official Docker documentation for other options.
| Option | Meaning | Example |
|---|---|---|
--name |
Specify container name | docker run --name "test" nginx |
-d |
Run in the background | docker run -d nginx |
-it (shell specified) |
Print results to the console | docker run -it nginx bash |
-p host:container |
Port mapping | docker run -p 8080:80 nginx |
-v host:container |
Directory sharing | docker run -v /test1:/test2 nginx |
-e |
Set environment variables | docker run -e foo=bar nginx |
-w |
Specify working directory inside the container | docker run -it -w=/tmp/work nginx bash |
As an example, the startup settings and execution command are as follows.
docker run --name my-nginx -p 8080:80 -v ~/develop/docker:/usr/share/nginx/html -e foo=bar -w /tmp/work -it nginx bash
- Image used: nginx
- Container name: my-bash
- Port: maps container port 80 to host port 8080
- Directory: mounts the host’s
~/develop/dockerto the container’s/usr/share/nginx/html - Environment variable: sets
footobar - Working directory:
/tmp/work - Prints results to the console
- Specifies bash as the shell
docker ps: List Containers
The command for listing containers is as follows. In this case, only running containers are displayed.
docker ps
Let’s list the running containers.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
caf5180d8506 nginx "/docker-entrypoint...." 4 minutes ago Up 7 seconds 0.0.0.0:8080->80/tcp my-nginx
If there are no running containers, it will be displayed as follows.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
If you want to see all containers, including stopped containers, add the -a option.
docker ps -a
When you add the -a option, stopped containers can also be checked as follows.
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
caf5180d8506 nginx "/docker-entrypoint...." 6 minutes ago Exited (0) 32 seconds ago my-nginx
Stop Docker Execution: docker stop
To stop a running container, execute the following command.
docker stop [container ID|container name]
The container ID and container name here are the leftmost and rightmost columns, CONTAINER ID and NAME, printed when running docker ps above.
For practice, start nginx first.
$ docker run --name my-nginx -p 8080:80 -v ~/develop/docker:/usr/share/nginx/html -d nginx
caf5180d85067eae71a9ee6f4bb52e8222cc7f6a54b4b318384d0cd2c8794a63
After it starts, stop the container.
$ docker stop my-nginx
my-nginx
docker logs: Check Container Execution Logs
The method for viewing container execution logs is as follows.
docker logs [container ID|container name]
Based on the container shown by running docker ps above, enter the command as follows.
$ docker logs caf5180d8506
/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: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
... omitted ...
2022/09/05 18:20:28 [notice] 1#1: start worker process 27
2022/09/05 18:20:28 [notice] 1#1: start worker process 28
docker inspect: View Container Metadata
To view container metadata, use the following command.
docker inspect [container ID|container name]
When the command is actually executed, it is printed as follows.
% docker inspect caf5180d8506
[
{
"Id": "caf5180d85067eae71a9ee6f4bb52e8222cc7f6a54b4b318384d0cd2c8794a63",
"Created": "2022-09-05T18:10:41.606382836Z",
"Path": "/docker-entrypoint.sh",
"Args": [
"nginx",
"-g",
"daemon off;"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 5950,
"ExitCode": 0,
... omitted ...
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
}
}
]
docker exec: Execute in Docker
To enter a currently running container that was started in the background, use the following command. At this time, you must specify a shell.
docker exec -it [container ID|container name] [shell name]
Enter the my-nginx container by specifying bash.
$ docker exec -it my-nginx bash
root@61dc29dec3e4:/tmp/work#
docker rm: Delete a Container
Stopped containers can be deleted with the following command.
docker rm [container ID|container name]
Let’s delete the my-nginx container used above.
$ docker rm my-nginx
my-nginx
Batch Delete Containers and Images
As explained above, images can be deleted with docker rmi, and containers can be deleted with docker rm. These commands require specifying each deletion target, so they are inconvenient when you want to delete items in bulk. Bulk deletion methods are as follows.
Delete stopped containers and anonymous images:
docker system prune
Delete all containers, including running containers:
docker rm -vf $(docker ps -a -q)
Delete all images:
docker rmi -f $(docker images -a -q)
Creating a Docker Image
Above, we pulled a repository from Docker Hub as a way to download a Docker image.
There are several other ways to obtain a Docker image, and here we will look at the following two points.
- Create an image from a container.
- Describe it in a Dockerfile.
Create an Image from a Container
When a new package is downloaded inside a container, the container becomes different from the container created from the image used at startup. The following command creates an image that can create a container with those new additions.
docker commit [container ID] [new container name]
docker container ls
Let’s look at the items displayed when running the docker container ls command.
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2axaf8tx4gjd registry "/entrypoint.sh /etc..." 7 weeks ago Up 7 weeks 0.0.0.0:5000->5000/tcp devkuma-private-registry
This command displays running containers and exited containers.
| Item | Description |
|---|---|
| CONTAINER ID | Unique identifier for identifying a container |
| IMAGE | Docker image used to create the container |
| COMMAND | Application process executed in the container |
| CREATED | Time elapsed since container creation |
| STATUS Up | Container execution status such as Up (running) or Exited (stopped) |
| PORTS | Connection relationship between host ports and container ports (port forwarding) |
| NAMES | Container name |
Write in a Dockerfile
You can create an image by writing image settings in a Dockerfile. It is a required configuration file when creating a Docker image. An image is created from the instructions written in this file.
The Dockerfile is as follows.
Dockerfile
FROM centos:7
RUN echo "now building..."
RUN yum -y install httpd
RUN sed -i '/#ServerName/a ServerName www.example.com:80' /etc/httpd/conf/httpd.conf
EXPOSE 80
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
Looking at this file, you can see that the Dockerfile is written with commands such as FROM, RUN, and ADD, along with their arguments. The meanings and usage of commands such as FROM, RUN, and ADD are shown in the table below. Only commonly used ones are listed here as well, so refer to the official documentation for the rest.
| Command | Meaning | Usage |
|---|---|---|
| FROM | Specify base image | FROM [image name] or FROM [image name]:[tag] |
| RUN | Execute command | RUN [command] |
| CMD | Command executed when the container starts | CMD [command] or CMD ["executable binary", "parameter 1", "parameter 2"] |
| EXPOSE | Expose port | EXPOSE [port] |
| VOLUME | Mount | VOLUME ["/data"] |
| ADD | Add file/directory | ADD [source] [destination] |
| COPY | Copy file/directory | COPY [source] [destination] |
| WORKDIR | Specify working directory | WORKDIR [directory path] |
| ENV | Set environment variable | ENV [key]=[value] |
Instruction
FROM
- Specifies the base image for the Docker image.
When specifying mysql, write the following.
FROM mysql
COPY
- Copies a file or directory from the host computer to the Docker container.
- It runs only once when the image is built.
COPY ./cnf/my.cnf /etc/mysql/conf.d/my.cnf
RUN
- Defines a command executed in Docker for the Docker image.
- Like COPY, it runs only once when the image is built.
- It is not used unless there is a specific instruction.
The following compiles Test.java with javac.
RUN javac Test.java
ADD
It is basically the same as COPY, with the following additional features.
- If the source is a remote URL, it downloads it and copies it to the destination.
- If the source is a commonly used compressed file format such as zip, it extracts it.
- If the source is a remote URL plus a compressed file format, it does not extract it.
CMD
- Specifies the process or command executed in the container. This is the command executed every time the image runs.
- Only one CMD can be created in a Dockerfile. If multiple are created, only the last command is executed.
The following runs mysqld.
CMD ["mysqld"]
Docker Build: docker build
Looking at the Dockerfile commands above, you can do things similar to options in docker run.
To build an image using the Dockerfile written this way, use the following command.
docker build [Dockerfile path]
By default, the file name Dockerfile is used. To change the file name, you need to add the -f option during build.
When this build is executed, the image is created as if each line (layer) of the Dockerfile is executed one by one.
You can see this from the output when the build is executed. Running the Dockerfile above produces the following.
$ docker build .
[+] Building 89.3s (8/8) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 252B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/centos:7 5.0s
=> [1/4] FROM docker.io/library/centos:7@sha256:c73f515d06b0fa07bb18d8202035e739a494ce760aa73129f60f4bf2bd22b407 49.1s
=> => resolve docker.io/library/centos:7@sha256:c73f515d06b0fa07bb18d8202035e739a494ce760aa73129f60f4bf2bd22b407 0.0s
=> => sha256:c73f515d06b0fa07bb18d8202035e739a494ce760aa73129f60f4bf2bd22b407 1.20kB / 1.20kB 0.0s
=> => sha256:73f11afcbb50d8bc70eab9f0850b3fa30e61a419bc48cf426e63527d14a8373b 530B / 530B 0.0s
=> => sha256:c9a1fdca3387618f8634949de4533419327736e2f5c618e3bfebe877aa331352 2.77kB / 2.77kB 0.0s
=> => sha256:6717b8ec66cd6add0272c6391165585613c31314a43ff77d9751b53010e531ec 108.37MB / 108.37MB 46.2s
=> => extracting sha256:6717b8ec66cd6add0272c6391165585613c31314a43ff77d9751b53010e531ec 2.6s
=> [2/4] RUN echo "now building..." 0.3s
=> [3/4] RUN yum -y install httpd 34.3s
=> [4/4] RUN sed -i '/#ServerName/a ServerName www.example.com:80' /etc/httpd/conf/httpd.conf 0.2s
=> exporting to image 0.2s
=> => exporting layers 0.2s
=> => writing image sha256:b32d2ca733218ab8a1d1840b775d2baed16cab3e1775477ae3839e990ffbc479 0.0s
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
From this output, you can see that each line (layer) is executed one by one on top of the base image written with FROM, just as written in the Dockerfile.
You can check whether a new image was created.
% docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> b32d2ca73321 13 minutes ago 417MB
Here, you can see that REPOSITORY and TAG are not specified and are shown as <none>.
You can also check the above contents again with the following command.
docker history [image ID|image name]
$ docker history b32d2ca73321
IMAGE CREATED CREATED BY SIZE COMMENT
b32d2ca73321 9 minutes ago CMD ["/usr/sbin/httpd" "-D" "FOREGROUND"] 0B buildkit.dockerfile.v0
<missing> 9 minutes ago EXPOSE map[80/tcp:{}] 0B buildkit.dockerfile.v0
<missing> 9 minutes ago RUN /bin/sh -c sed -i '/#ServerName/a Server... 11.8kB buildkit.dockerfile.v0
<missing> 9 minutes ago RUN /bin/sh -c yum -y install httpd # buildk... 117MB buildkit.dockerfile.v0
<missing> 9 minutes ago RUN /bin/sh -c echo "now building..." # buil... 0B buildkit.dockerfile.v0
<missing> 6 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 6 months ago /bin/sh -c #(nop) LABEL org.label-schema.sc... 0B
<missing> 6 months ago /bin/sh -c #(nop) ADD file:5b1e63a3cb041177b... 301MB
Push the Created Image
Let’s look at how to publish an image created this way to Docker Hub.
First, you need a Docker Hub account, so create one at the following site.
To publish the image, you first need to specify a tag. Add a tag using the username registered on Docker Hub as shown below.
docker tag [Image ID] [DockerHub username]/[repository name]
To tag the image newly created above, run the following command.
docker tag b32d2ca73321 devkuma/centos7
When executed, no output is displayed.
% docker tag b32d2ca73321 devkuma/centos7
If you list the images, you can see that REPOSITORY and TAG are set as specified.
% docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
devkuma/centos7 latest b32d2ca73321 17 minutes ago 417MB
Before pushing, you need to log in to Docker Hub, so run the following command to log in.
docker login
% docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: devkuma
Password:
Login Succeeded
Logging in with your password grants your terminal complete access to your account.
For better security, log in with a limited-privilege personal access token. Learn more at https://docs.docker.com/go/access-tokens/
user@AL02263852 docker
If you have completed up to this point, you can upload the repository to Docker Hub.
docker push [DockerHub username]/[repository name]
Now run the following command.
$ docker push devkuma/centos7
Using default tag: latest
The push refers to repository [docker.io/devkuma/centos7]
5818d7ffd9ac: Pushed
085e94a3a50e: Pushed
6a9a145374b8: Pushed
65f23ff12f4d: Mounted from library/centos
latest: digest: sha256:2845b5f6439dff6a80ed8ed45a10cfd39e19d8178182fe043db939ccc3b7f982 size: 1156
Managing Multiple Containers (docker-compose)
When you want to start and stop multiple containers, running docker run and docker stop for each one takes a lot of time. docker-compose solves this by managing them in bulk. This method writes information for multiple containers in a YAML file (docker-compose.yaml) and manages them.
An example file is as follows.
docker-compose.yaml
version: '3'
services:
db:
image: postgres
web:
build: .
command: bundle exec rails s -p 3000 -b '0.0.0.0'
volumes:
- .:/myapp
ports:
- "3000:3000"
depends_on:
- db
Details are not explained here, but roughly, the version property contains the docker-compose version, and the services property contains information about the servers to start. In this file, it is written to start a DB server and a web server. The contents under it are also similar to what is written in a Dockerfile. For details, refer to the official Docker documentation.
After writing this YAML file, you can start the containers by running the following command.
docker-compose –f [yaml file path] up
For started containers, run the following command to stop the containers listed in the YAML file.
docker-compose -f [yaml file path] dowm
To collect and view the logs of multiple containers started this way, run the following command.
dokcer-compose -f [yaml file path] logs
There are cases where you want to start multiple web servers, such as when configuring server clustering. Starting multiple containers that perform the same role is called creating replicas. Let’s look at how to start multiple container replicas with docker-compose.
To start multiple containers, you need to change the port settings in the YAML file above. In particular, specify a range so that ports do not overlap between containers.
docker-compose2.yaml
version: '3'
services:
db:
image: postgres
web:
build: .
command: bundle exec rails s -p 3000 -b '0.0.0.0'
volumes:
- .:/myapp
ports:
- "3000-3004:3000"
depends_on:
- db
If you change the contents as shown, host-side ports 3000, 3001, 3002, 3003, and 3004 are assigned, so a set of five replicas can be created. Use this docker-compose file to start them, but add the --scale option when running the up command and specify the number of replicas.
docker-compose –f [yaml file path] up –scale [container name]=[number of replicas]
Network
Containers defined with docker-compose can communicate with each other by default. However, they cannot be accessed from other locations, meaning containers other than those written in the YAML file. This is because a network namespace is created and assigned to the container when the container starts.
When containers are started individually and no special settings are configured, a network namespace is created so they are connected to the default Bridge network. Meanwhile, container groups created by docker-compose have a separate Bridge network configured and a network namespace is created so they connect to that Bridge network.
Therefore, containers created by docker-compose and containers created individually cannot communicate.
To solve this problem and connect them, the network must be configured. This is not explained here; it will be covered later.
To view the network list, run the following command.
docker network ls
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
7f8103f64ff5 bridge bridge local
540c2f32637b host host local
a0053c593c0e none null local
From this output, you can see that there are several types in the DRIVER column. These correspond to network modes. Docker networks have the following four modes.
- bridge
- Because IPs are assigned from the DockerBridge network inside the host, the IP range is separate from the host.
- host
- Because IPs are assigned from the host’s IP range and host ports are used, port mapping with options such as
-pis not possible.
- Because IPs are assigned from the host’s IP range and host ports are used, port mapping with options such as
- null
- It is not linked to either the Bridge or host, and no IP is assigned. Therefore, it becomes unreachable.
- overlay
- Used when there are multiple hosts.
To create a new network, run the following command.
docker network create –driver bridge [network name]
To delete a network, run the following command.
docker network rm [network name]
Storage
Containers can have short lifecycles, and data is stored on the host rather than in the container.
For this purpose, as specified with -v in the docker run command, specify the host folder and container folder and perform the mount.