Docker基础知识 (2) - Hello world、Docker 容器、Docker 镜像
1. Hello world
Docker 在容器中运行应用程序,一般的开发语言教程,都有一个 Hello World 示例,我们的 Docker 容器介绍也从 Hello World 开始。
1) Hello world 示例
$ docker run ubuntu /bin/echo "Hello world"
Hello world
各个参数解析:
docker: Docker 命令。
run: Docker 命令下的 Action (动作或操作),表示运行一个容器。
ubuntu:表示运行的镜像,Docker 首先从本地主机上查找镜像是否存在,如果不存在,Docker 就会从镜像仓库 Docker Hub 下载公共镜像。 默认情况下会下载 TAG 为 latest 的镜像,示例里是 Ubuntu 20.04.3 LTS。
/bin/echo "Hello world": 在容器里执行 Linux 命令 /bin/echo
以上命令完整的意思是:Docker 以 ubuntu 镜像创建一个新容器,然后在容器里执行 bin/echo "Hello world",然后输出结果。
docker run 是创建一个容器并运行一个命令,如果要创建一个容器但不运行命令,可以使用 docker create。
注:命令执行时,如需 root 权限的,切换到 root 或 root 组用户下运行,下同。
2) 交互式容器
通过 docker 的两个参数 -i -t,让 docker 运行的容器实现 "对话" 的能力:
$ docker run -i -t ubuntu /bin/bash
root@46ff069b5f64:/#
各个参数解析:
-t: 在新容器内指定一个伪终端或终端。
-i: 允许你对容器内的标准输入 (STDIN) 进行交互。
注意第二行 root@46ff069b5f64:/#,此时我们已进入一个 ubuntu 系统的容器
在容器中运行命令 cat 和 ls 分别查看当前系统的版本信息和当前目录下的文件列表
root@46ff069b5f64:/#cat /etc/issue
Ubuntu 20.04.3 LTS \n \l
root@46ff069b5f64:/#
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
可以通过运行 exit 命令或者使用 CTRL+D 来退出容器。
root@46ff069b5f64:/# exit
exit
[root@localhost /]#
退出容器,返回到当前的主机中。
3) 后台运行容器
使用以下命令创建一个以进程方式运行的容器
$ docker run -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"
64b3215d2e86f3db9fda639acfbe4009815d182fe08614cd9051b7763d7b2a6a
在输出中,没有看到期望的 "hello world",而是一串长字符 "64b3215d2e86 ... ",这个长字符串叫做容器 ID,对每个容器来说都是唯一的,我们可以通过容器 ID 来查看对应的容器发生了什么。
使用 docker ps 查看运行的容器列表:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
64b3215d2e86 ubuntu "/bin/s ..." ... ... ... brave_wozniak
注:64 位的容器 ID 列表显示了前 12 位。可以使用 docker ps -a 命令查看全部容器列表,包含停止运行的容器。容器名称 brave_wozniak 是 docker 自动指定的。
输出详情介绍:
CONTAINER ID: 容器 ID。
IMAGE: 使用的镜像。
COMMAND: 启动容器时运行的命令。
CREATED: 容器的创建时间。
STATUS: 容器状态。状态有 7 种:
created(已创建)
restarting(重启中)
running 或 Up(运行中)
removing(迁移中)
paused(暂停)
exited(停止)
dead(死亡)
PORTS: 容器的端口信息和使用的连接类型(tcp\udp)。
NAMES: 自动分配的容器名称。
在宿主主机内使用 docker logs 命令,查看容器内的标准输出:
$ docker logs 64b3215d2e86
4) 进入容器
使用 -d 参数时,容器启动后会进入后台。此时想要进入容器,可以通过以下指令进入:
(1) docker attach
(2) docker exec:推荐大家使用 docker exec 命令,因为此命令会退出容器终端,但不会导致容器的停止。
attach 命令:
$ docker attach 64b3215d2e86
注:从这个容器退出,会导致容器的停止。
exec 命令:
$ docker exec -it 64b3215d2e86 /bin/bash
注: 从这个容器退出,容器不会停止。更多参数说明请使用 docker exec --help 命令查看。
5) 停止容器
使用 docker stop "CONTAINER ID" 命令来停止容器:
$ docker stop 639d4e201537
639d4e201537
也可以使用 docker stop "NAMES" 命令来停止容器:
$ docker stop loving_hypatia
2. Docker 容器
上文通过 Hello world 示例,演示了 docker run 在容器里运行应用程序,同时使用了 ubuntu 镜像。也简单介绍了如何运行交互式容器、后台运行容器、进入后台运行的容器及停止容器。
这里我们将通过一个 Web 应用示例,介绍一些 Docker 容器的其它操作和功能。
1) Python Web 应用 (Flask)
$ docker run -d -P --name webtest01 training/webapp python app.py
aeb5c373a4f70cf534540a1d9e21d2db0985fa0935a93199c32a4cb9703cfce6
参数说明:
-d: 让容器在后台运行。
-P: 将容器内部使用的网络端口随机映射到主机上。
--name: 指定容器名称为 webtest01。
使用 docker ps 查看运行的容器列表:
$ docker ps
CONTAINER ID IMAGE ... PORTS NAMES
aeb5c373a4f7 training/webapp ... 0.0.0.0:49157->5000/tcp webtest01
Docker 开放了 5000 端口(默认 Python Flask 端口)映射到主机端口 49157 上。
浏览器访问 http://192.168.0.10:49157 (这个 IP 地址是在前文安装 CentOS 时,设置的静态 IP 地址),页面显示:
Hello world!
2) 设置指定端口
通过 -p 参数来设置指定端口,注意是小写的 p,大写的 P 是随机映射端口。
$ docker run -d -p 5000:5000 --name webtest02 training/webapp python app.py
可以绑定 IP 地址,格式如下:
$ docker run -d -p 192.168.0.10:5000:5000 --name webtest02 training/webapp python app.py
3904176f769d618dda5fb3332fe39b2d60ebae46318de030784568e12eebe804
使用 docker ps 查看运行的容器列表:
$ docker ps
CONTAINER ID IMAGE ... PORTS NAMES 3904176f769d training/webapp ... 192.168.0.10:5000->5000/tcp webtest02 aeb5c373a4f7 training/webapp ... 0.0.0.0:49157->5000/tcp webtest01
浏览器访问 http://192.168.0.10:5000 (这个 IP 地址是在前文安装 CentOS 时,设置的静态 IP 地址),页面显示:
Hello world!
3) 查看容器的端口映射
使用 docker port [ID 或者名字] 可以查看容器的端口映射。
$ docker port webtest01
5000/tcp -> 0.0.0.0:49157
5000/tcp -> :::49157
$ docker port webtest02
5000/tcp -> 127.0.0.1:5000
4) 查看容器内的程序日志
可以使用 docker logs [ID或者名字] 查看容器内部的标准输出。
$ docker logs -f webtest02
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit) 192.168.0.2 - - [07/Jul/2022 00:00:18] "GET / HTTP/1.1" 200 - 192.168.0.2 - - [07/Jul/2022 00:00:20] "GET / HTTP/1.1" 200 - 192.168.0.2 - - [07/Jul/2022 00:00:20] "GET / HTTP/1.1" 200 - 192.168.0.2 - - [07/Jul/2022 00:00:21] "GET / HTTP/1.1" 200 -
-f: 让 docker logs 像使用 tail -f 一样来输出容器内部的标准输出。
5) 查看容器内的进程
可以使用 docker top [ID或者名字] 查看容器内部运行的进程
$ docker top webtest02
UID PID PID ... TIME CMD
root 5589 5570 ... 00:00:00 python app.py
6) 检查容器详细信息
可以使用 docker inspect [ID或者名字] 查看容器详细信息,它会返回一个 JSON 格式的输出。
$ docker inspect webtest02
[ { "Id": "3904176f769d618dda5fb3332fe39b2d60ebae46318de030784568e12eebe804", "Created": "2022-07-06T23:59:05.249257511Z", "Path": "python", "Args": [ "app.py" ], ... ]
7) 重启容器
运行 docker stop webtest02,停止 webtest02。
使用命令 docker start [ID或者名字] 启动已经停止的容器。
$ docker start webtest02
webtest02
查询最后一次创建的容器:
$ docker ps -l
CONTAINER ID IMAGE PORTS NAMES
3904176f769d training/webapp ... 192.168.0.10:5000->5000/tcp webtest02
正在运行的容器,可以使用 docker restart [ID或者名字] 命令来重启。
8) 导出容器
要导出本地某个容器,可以使用 docker export 命令。
$ docker export webtest02 > webtest02_export.tar
导出容器 webtest02 快照到本地文件 webtest02_export.tar 中。
9) 导入容器快照
可以使用 docker import 从容器快照文件中再导入为镜像,以下实例将快照文件 webtest02_export.tar 导入到镜像 training/webapp:v1:
$ cat webtest02_export.tar | docker import - training/webapp:v1
查看导入的容器快照:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE training/webapp v1 36ed53a7958f 51 seconds ago 324MB ubuntu latest 9b9cb95443b5 8 months ago 72.8MB training/webapp latest 6fae60ef3446 7 years ago 349MB
注:training/webapp:v1 已经在镜像列表里。
也可以通过指定 URL 或者某个目录来导入,例如:
$ docker import http://example.com/webtest02_export.tar training/webapp:v1
10) 移除容器
可以使用 docker rm [ID或者名字] 命令来删除容器。
$ docker rm webtest01
webtest01
删除容器时,容器必须是停止状态,否则会报如下错误。
Error response from daemon: You cannot remove a running container aeb5c373a4f70cf534540a1d9e21d2db0985fa0935a93199c32a4. Stop the container before attempting removal or force remove
下面的命令可以清理掉所有处于终止状态的容器。
$ docker container prune
3. Docker 镜像
当运行容器时,使用的镜像如果在本地中不存在,docker 就会自动从 docker 镜像仓库中下载,默认是从 Docker Hub 公共镜像源下载。
1) 列出镜像列表
可以使用 docker images 来列出本地主机上的镜像。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu latest ba6acccedd29 8 months ago 72.8MB hello-world latest feb5d9fea6a5 9 months ago 13.3kB training/webapp latest 6fae60ef3446 7 years ago 349MB
各项说明:
REPOSITORY:表示镜像的仓库源
TAG:镜像的标签
IMAGE ID:镜像ID
CREATED:镜像创建时间
SIZE:镜像大小
同一仓库源可以有多个 TAG,代表这个仓库源的不同个版本,如 ubuntu 仓库源里,有 15.10、14.04 等多个不同的版本,使用 REPOSITORY:TAG 来定义不同的镜像。
如果要使用版本为 15.10 的 ubuntu 系统镜像来运行容器时,命令如下:
$ docker run -t -i ubuntu:15.10 /bin/bash
root@9b9cb95443b5:/#
参数说明:
-i: 交互式操作。
-t: 终端。
ubuntu:15.10: 这是指用 ubuntu 15.10 版本镜像为基础来启动容器。
/bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。
如果不指定一个镜像的版本标签,例如你只使用 ubuntu,docker 将默认使用 ubuntu:latest 镜像。
2) 获取一个新的镜像
当我们在本地主机上使用一个不存在的镜像时 Docker 就会自动下载这个镜像。如果我们想预先下载这个镜像,可以使用 docker pull 命令来下载,命令格式如下。
$ docker pull ubuntu:15.10
15.10: Pulling from library/ubuntu 6599cadaf950: Pull complete 23eda618d451: Pull complete f0be3084efe9: Pull complete 52de432f084b: Pull complete a3ed95caeb02: Pull complete Digest: sha256:15b79a6654811c8d992ebacdfbd5152fcf3d165e374e264076aa435214a947a3 Status: Downloaded newer image for ubuntu:15.10
下载完成后,可以直接使用这个镜像来运行容器。
3) 查找镜像
可以从 Docker Hub 网站 ( https://hub.docker.com/ ) 搜索镜像。
也可以使用 docker search 命令来搜索镜像。比如需要一个 httpd 的镜像来作为 web 服务。可以通过 docker search 命令搜索 httpd 来寻找适合的镜像,命令格式如下。
$ docker search httpd
NAME DESCRIPTION STARS OFFICIAL AUTOMATED httpd The Apache HTTP Server Project 4070 [OK] centos/httpd-24-centos7 Platform for running Apache … 44 centos/httpd 35 [OK] hypoport/httpd-cgi httpd-cgi 2 [OK] solsson/httpd-openidc mod_auth_openidc on official … 2 [OK] ...
各项说明:
NAME: 镜像仓库源的名称
DESCRIPTION: 镜像的描述
STARS: 类似 Github 里面的 star,表示点赞、喜欢的意思。
OFFICIAL: 是否 docker 官方发布
AUTOMATED: 自动构建。
4) 查看镜像详细信息
可以使用 docker inspect [REPOSITORY:TAG] 查看镜像详细信息,它会返回一个 JSON 格式的输出。
$ docker inspect ubuntu
[ { "Id": "sha256:9b9cb95443b5f846cd3c8cfa3f64e63b6ba68de2618a08875a119c81a8f96698", "RepoTags": [ "ubuntu:latest" ], "RepoDigests": [ "ubuntu@sha256:02521a2d079595241c6793b2044f02eecf294034f31d6e235ac4b2b54ffc41f3" ], ... ]
5) 查看镜像历史
可以使用 docker history [REPOSITORY:TAG] 查看镜像历史。
$ docker history ubuntu
IMAGE CREATED CREATED BY SIZE ba6acccedd29 8 months ago /bin/sh -c #(nop) CMD ["bash"] 0B <missing> 8 months ago /bin/sh -c #(nop) ADD file:5d68d27cc15a80653… 72.8MB
6) 更新镜像
更新镜像之前,需要使用镜像来创建一个容器。
$ docker run -t -i ubuntu /bin/bash
root@a1c24a6cd008:/#
在运行的容器内安装 ping 软件(本文 Ubuntu 的 latest 版本是 20.04.3 LTS),在完成操作之后,输入 exit 命令来退出这个容器。
$ apt-get update
$ apt install iputils-ping
$ exit
通过命令 docker commit 来提交更新过的容器副本,命令格式如下。
$ docker commit -m="Install iputils-ping" -a="Tester" a1c24a6cd008 tester/ubuntu:20.04.ping
sha256:927000729bfb64f7bda2fd5f249113b926e1647498a161bd1746d05b599567e4
参数说明:
-m: 提交的描述信息
-a: 指定镜像作者
a1c24a6cd008: 容器 ID
tester/ubuntu:20.04.ping: 指定要创建的目标镜像名
查看镜像列表:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE tester/ubuntu 20.04.ping 927000729bfb About a minute ago 95.4MB ubuntu latest ba6acccedd29 8 months ago 72.8MB hello-world latest feb5d9fea6a5 9 months ago 13.3kB training/webapp latest 6fae60ef3446 7 years ago 349MB
使用新镜像 tester/ubuntu 来启动一个容器
$ docker run -t -i tester/ubuntu:20.04.ping /bin/bash
root@0861e95c1a59:/# ping www.baidu.com PING www.a.shifen.com (36.152.44.95) 56(84) bytes of data. 64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=1 ttl=55 time=16.1 ms 64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=2 ttl=55 time=15.8 ms 64 bytes from 36.152.44.95 (36.152.44.95): icmp_seq=3 ttl=55 time=15.4 ms
7) 创建镜像
使用命令 docker build,从零开始来创建一个新的镜像。需要创建一个 Dockerfile 文件,内容如下:
FROM centos:6.7 MAINTAINER Tester "tester@docker.com" RUN /bin/echo 'root:123456' | chpasswd RUN useradd develop RUN /bin/echo 'develop:123456' | chpasswd RUN /bin/echo -e "LANG=\"en_US.UTF-8\"" >/etc/default/local EXPOSE 22 EXPOSE 80 CMD /usr/sbin/sshd -D
说明:
FROM:指定使用哪个镜像源
RUN:指令告诉 docker 在镜像内执行命令
使用 Dockerfile 文件,通过 docker build 命令来构建一个镜像,命令格式如下。
$ docker build -t tester/centos:6.7 .
Sending build context to Docker daemon 2.048kB Step 1/9 : FROM centos:6.7 6.7: Pulling from library/centos cbddbc0189a0: Pull complete Digest: sha256:4c952fc7d30ed134109c769387313ab864711d1bd8b4660017f9d27243622df1 Status: Downloaded newer image for centos:6.7 ---> 9f1de3c6ad53 ... Step 9/9 : CMD /usr/sbin/sshd -D ---> Running in 4d67b1f3f0c6 Removing intermediate container 4d67b1f3f0c6 ---> f5bff2907032 Successfully built f5bff2907032 Successfully tagged tester/centos:6.7
参数说明:
-t :指定要创建的目标镜像名
. :Dockerfile 文件所在目录,可以指定 Dockerfile 的绝对路径
查看镜像列表:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE tester/centos 6.7 f5bff2907032 About a minute ago 191MB tester/ubuntu v2 48c392bf562a 8 minutes ago 137MB ubuntu latest ba6acccedd29 8 months ago 72.8MB centos 6.7 9f1de3c6ad53 3 years ago 191MB training/webapp latest 6fae60ef3446 7 years ago 349MB
使用新的镜像来创建容器:
$ docker run -t -i tester/centos:6.7 /bin/bash
[root@1eb692acaefd /]# id develop
uid=500(develop) gid=500(develop) groups=500(develop)
可以看到新镜像已经包含新创建的用户 develop。
8) 设置镜像标签
可以使用 docker tag 命令,为镜像添加一个新的标签,命令格式如下。
$ docker tag f5bff2907032 tester/centos:dev
参数说明:
f5bff2907032:镜像ID
tester/centos:dev:用户名称/镜像源名(repository name):标签名(tag)
查看镜像列表:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE tester/centos 6.7 f5bff2907032 12 minutes ago 191MB tester/centos dev f5bff2907032 12 minutes ago 191MB tester/ubuntu v2 48c392bf562a 20 minutes ago 137MB ubuntu latest ba6acccedd29 8 months ago 72.8MB centos 6.7 9f1de3c6ad53 3 years ago 191MB training/webapp latest 6fae60ef3446 7 years ago 349MB
IMAGE ID 为 f5bff2907032 的镜像多一个标签 dev。
9)删除镜像
使用 docker rmi [名称:tag] 命令删除镜像,命令格式如下。
$ docker rmi hello-world
Untagged: hello-world:latest Untagged: hello-world@sha256:13e367d31ae85359f42d637adf6da428f76d75dc9afeb3c21faea0d976f5c651 Deleted: sha256:feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412 Deleted: sha256:e07ee1baac5fae6a26f30cabfe54a36d3402f96afda318fe0a96cec4ca393359