Docker基础入门
Docker基础入门
第 1 章:核心概念与安装配置
本章首先介绍Docker 的三大核心概念:
- 镜像 (Image)
- 容器(Container)
- 仓库(Repository)
只有理解了这三个核心概念,才能顺利地理解Docker容器的整个生命周期。
随后,将介绍如何在CentOS操作系统上安装Docker。
1.1 核心概念
Docker 大部分的操作都围绕着它的三大核心概念: 镜像、容器和仓库 。因此,准确把握这三大核心概念对于掌握Docker技术尤为重要。
1. Docker 镜像
Docker 镜像类似于虚拟机镜像,可以将它理解为一个只读的模板。
例如,一个镜像可以包含一个基本的操作系统环境,里面仅安装了Apache应用程序(或用户需要的其他软件)。 可以把它称为一个Apache镜像。
镜像是创建Docker容器的基础。
通过版本管理和增量的文件系统, Docker 提供了一套十分简单的机制来创建和更新现有的镜像,用户甚至可以从网上下载一个已经做好的应用镜像,并直接使用。
2. Docker 容器
Docker 容器类似于一个轻量级的沙箱, Docker利用容器来运行和隔离应用。
容器是从镜像创建的应用运行实例。 它可以启动、开始、停止、 删除,而这些容器都是彼此相互隔离、互不可见的。
可以把容器看作一个简易版的 Linux 系统环境(包括root用户权限、进程空间、用户空间和网络空间等)以及运行在其中的应用程序打包而成的盒子。
注:镜像自身是只读的。 容器从镜像启动的时候,会在镜像的最上层创建一个可写层。
3. Docker 仓库
Docker 仓库类似于代码仓库,是Docker集中存放镜像文件的场所。
有时候我们会将Docker仓库和仓库注册服务器(Registry)混为一谈,并不严格区分。 实际上,仓库注册服务器是存放仓库的地方,其上往往存放着多个仓库。 每个仓库集中存放某一类镜像,往往包括多个镜像文件,通过不同的标签(tag)来进行区分。 例如存放Ubuntu 操作系统镜像的仓库,被称为 Ubuntu 仓库,其中可能包括 16.04、 18.04 等不同版本的镜像。仓库注册服务器的示例如图2-1所示。
根据所存储的镜像公开分享与否, Docker仓库可以分为公开仓库(Public)和私有仓库(Private)两种形式。
目前,最大的公开仓库是官方提供的Docker Hub,其中存放着数量庞大的镜像供用户下载。 国内不少云服务提供商(如腾讯云、 阿里云等)也提供了仓库的本地源,可以提供稳定的国内访问。
当然,用户如果不希望公开分享自己的镜像文件, Docker 也支持用户在本地网络内创建 一个只能自己访问的私有仓库。
当用户创建了自己的镜像之后就可以使用push命令将它上传到指定的公有或者私有仓 库。 这样用户下次在另外一台机器上使用该镜像时,只需要将其从仓库上pull下来就可以了。
注意:可以看出, Docker利用仓库管理镜像的设计理念与 Git代码仓库的概念非常相似,实际上Docker 设计上借鉴了 Git 的很多优秀思想。
1.2 安装Docker 引擎
Docker引擎是使用 Docker容器的核心组件,可以在主流的操作系统和云平台上使用,包括Linux操作系统(如 Ubuntu、Debian, CentOS、 Red.hat 等), macOS 和 Windows 操作系统, 以及IBM、亚马逊、微软等知名云平台。
用户可以访问Docker官网的 Get Docker ( )页面,查看获取Docker 的方式,以及Docker支持的平台类型,如图 2-2所示。
目前Docker 支持 Docker 引擎、 Docker Hub、 Docker Cloud 等多种服务。
- Docker 引擎: 包括支持在桌面系统或云平台安装 Docker,以及为企业提供简单安全 弹性的容器集群编排和管理;
- DockerHub: 官方提供的云托管服务,可以提供公有或私有的镜像仓库;
- DockerCloud : 官方提供的容器云服务,可以完成容器的部署与管理,可以完整地支 持容器化项目,还有CI、 CD功能。
1.CentOS 环境下安装 Docker
Docker 目前支持 CentOS 7 及以后的版本。 系统的要求跟 Ubuntu 情况类似, 64 位操作 系统,内核版本至少为3.10。
首先,为了方便添加软件源,以及支持devicemapper存储类型,安装如下软件包:
$ sudo yum update
$ sudo yum instal l -y yum-utils \
device-mapper-persistent-data \
lvm2
添加Docker 稳定版本的 yum软件源:
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
之后更新yum软件源缓存,并安装Docker:
sudo yum update
sudo yum install -y docker-ce
最后,确认Docker服务启动正常:
sudo systernctl start docker
2.通过脚本安装
用户还可以使用官方提供的 shell 脚本来在 Linux 系统上安装 Docker 的最新正式版本,该脚本会自动检测系统信息并进行相应配置:
curl -fsSL https://get.docker.com/ | sh
或者:
wget -qO- https://get.docker.com/ | sh
如果想尝鲜最新功能,可以使用下面的脚本来安装最新的“尝鲜”版本。 但要注意,非稳定版本往往意味着功能还不够稳定,不要在生产环境中使用:
curl -fsSL https://test.docker.com/ | sh
另外, 也可以从store.docker.com/search?offering=community&q=&type=edition找到各个平台上的Docker安装包,自行下载使用。
1.3 配置Docker服务
为了避免每次使用 Docker 命令时都需要切换到特权身份,可以将当前用户加入安装中自动创建的docker用户组,代码如下:
sudo usermod -aG docker USER_NAME
用户更新组信息,退出并重新登录后即可生效。
Docker 服务启动时实际上是调用了dockerd命令,支持多种启动参数。 因此,用户可以直接通过执行dockerd命令来启动Docker服务,如下面的命令启动Docker服务,开启 Debug 模式,并监听在本地的 2376端口:
dockerd -D -H tcp://127.0.0.1:2376
这些选项可以写入/etc/docker/路径下的 daemon.json 文件中,由 dockerd服务启动时读取:
对于CentOS、 RedHat等系统,服务通过 systemd来管理,配置文件路径为/etc/systemd/ system/docker.service.d/docker.conf。更新配置后需要通过 systemctl 命令来管理 Docker 服务:
sudo systemctl daemon-reload
sudo systemctl start docker.service
此外,如果服务工作不正常,可以通过查看Docker 服务的日志信息来确定问题,例如在RedHat 系统上日志文件可能为/var/log/messages,在CentOS 系统上可以执行命令:
journalctl -u docker.service
每次重启 Docker服务后,可以通过查看Docker信息(docker info命令),确保服务已经正常运行。
第 2 章:使用Docker镜像
镜像是Docker三大核心概念中最重要的, 自 Docker诞生之日起镜像就是相关社区最为热门的关键词。
Docker 运行容器前需要本地存在对应的镜像, 如果镜像不存在,Docker 会尝试先从默认镜像仓库下载(默认使用 DockerHub 公共注册服务器中的仓库,用户也可以通过配置, 使用自定义的镜像仓库。
本章将围绕镜像这一核心概念介绍具体操作, 包括如何使用pull命令从国内仓库中下载镜像到本地;如何查看本地已有的镜像信息和管理镜像标签;如何在远端仓库使用 search 命令进行搜索和过滤;如何删除镜像标签和镜像文件;如何创建用户定制的镜像并且保存为外部文件。 最后,还将介绍如何往国内仓库中推送自己的镜像。
2.1 配置国内镜像源并获取镜像
镜像是运行容器的前提, 官方的DockerHub网站已经提供了数十万个镜像供大家开放下载。但由于DockerHub仓库在国内访问需要加速器,所以需要配置国内镜像源。本节主要介绍Docker镜像的pull子命令。
首先进入/etc/docker/daemon.json文件中添加一下镜像:
[root@open-Euler1 docker]# cat /etc/docker/daemon.json
{
"registry-mirrors": [
"https://docker.m.daocloud.io",
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com",
"https://docker.nju.edu.cn"
]
}
可以使用docker [image] pull 命令直接从配置的镜像源来下载镜像。 该命令的格式为
docker [image] pull NAME[:TAG]
其中, NAME是镜像仓库名称(用来区分镜像), TAG是镜像的标签(往往用来表示版本信息)。 通常情况下,描述一个镜像需要包括 “名称+标签“ 信息。
例如, 获取一个Ubuntu 18.04系统的基础镜像可以使用如下的命令:
docker pull ubuntu:18.04
18. 04: Pulling from library/ubuntu
......
Digest: sha256:e27e9d7f7f28d67aa9e2d7540bdc2b33254b452ee8e60f388875e5b7d9b2b696
S七atus: Downloaded newer image for ubuntu:18.04
对于Docker镜像来说, 如果不显式指定TAG, 则默认会选择latest标签,这会下载仓库中最新版本的镜像。
下面的例子将从Ubuntu仓库下载一个最新版本的Ubuntu操作系统的镜像:
docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
......
Digest: sha256:e27e9d7f7f28d67aa9e2d7540bdc2b33254b452ee8e60f388875e5b7d9b2b696
Status: Downloaded newer image for ubuntu:latest
该命令实际上下载的就是 ubuntu:latest镜像。
注意:一般来说, 镜像的latest 标签意味着该镜像的内容会跟踪最新版本的变更而变化, 内 容是不稳定的。因此,从稳定性上考虑,不要在生产环境中忽略镜像的标签信息或使用默认的latest 标记的镜像。
下载过程中可以看出 ,镜像文件一般由若干层(layer)组成 ,6c953ac5d795这样的串是层的唯一id(实际上完整的id包括256比特,64个十六进制字符组成)。使用docker pull命令下载中会获取并输出镜像的各层信息。当不同的镜像包括相同的层时,本地仅存储了层的一份内容,减小了存储空间。
大家可能会想到,在不同的镜像仓库服务器的情况下,可能会出现镜像重名的情况。
严格地讲,镜像的仓库名称中还应该添加仓库地址(即registry, 注册服务器)作为前缀,只是默认使用的是官方DockerHub服务,该前缀可以忽略。
不过Docker 会通过你在
daemon.json
中配置的
registry-mirrors
列表来尝试下载
ubuntu
镜像,而不是直接从 Docker Hub 下载。如果第一个镜像站点不可用,Docker 会自动尝试列表中的下一个,直到镜像被成功下载或列表中的所有镜像站点都尝试过。
总之,通过这种方式,你可以简化
docker pull
命令,不需要为每个镜像手动添加前缀,同时还能享受到加速下载的好处。
pull子命令支持的选项主要包括:
-a, –all-tags=true|false:是否获取仓库中的所有镜像,默认为否;
–disable-content-trust:取消镜像的内容校验,默认为真。
另外,有时需要使用镜像代理服务来加速Docker镜像获取过程 ,可以在Docker服务启动配置中增加–registry-mirror=proxy_URL来指定镜像代理服务地址
下载镜像到本地后,即可随时使用该镜像了,例如利用该镜像创建一个容器,在其中运 行bash应用,执行打印 “Hello World"命令:
docker run -it ubuntu:18.04 bash
root@65663247040f:/# echo "Hello World"
Hello World
roo七@65663247040f:/# exit
2.2 查看镜像信息
本节主要介绍Docker镜像的ls、tag和inspect子命令。
1. 使用images命令列出镜像
使用docker images或docker image ls 命令可以列出本地主机上已有镜像的基本信息。
例如,下面的命令列出了上一小节中下载的镜像信息:
[root@open-Euler1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
wordpress latest 458dad822ff7 3 weeks ago 701MB
nginx latest b52e0b094bc0 4 weeks ago 192MB
busybox latest 31311c5853a2 5 months ago 4.27MB
reg.yym.com/library/busybox latest 31311c5853a2 5 months ago 4.27MB
myubuntu 18.04 f9a80a55f492 21 months ago 63.2MB
ubuntu 18.04 f9a80a55f492 21 months ago 63.2MB
reg.yym.com/openlab/ubuntu 18.04 f9a80a55f492 21 months ago 63.2MB
mysql 5.6 dd3b2a5dcb48 3 years ago 303MB
在列出信息中,可以看到几个字段信息:
- 来自于哪个仓库,比如ubuntu表示ubuntu系列的基础镜像;
- 镜像的标答信息,比如 18.04、latest表示不同的版本信息。 标签只是标记,并不能标 识镜像内容;
- 镜像的ID(唯一标识镜像),如果两个镜像的ID相同,说明它们实际上指向了同一 个镜像,只是具有不同标签名称而已;
- 创建时间,说明镜像最后的更新时间;
- 镜像大小,优秀的镜像往往体积都较小。
其中镜像的ID信息十分重要,它唯一标识了镜像。在使用镜像ID的时候,一般可以使用该ID的前若干个字符组成的可区分串来替代完整的ID。
TAG 信息用于标记来自同一个仓库的不同镜像。例如ubuntu 仓库中有多个镜像,通过 TAG 信息来区分发行版本,如18.04、18.10 等。
镜像大小信息只是表示了该镜像的逻辑体积大小,实际上由于相同的镜像层本地只会存储一份,物理上占用的存储空间会小于各镜像逻辑体积之和。
images子命令主要支持如下选项,用户可以自行进行尝试:
- -a, –all=true | false: 列出所有(包括临时文件)镜像文件,默认为否;
- –digests=true | false: 列出镜像的数字摘要值,默认为否;
- -f, –filter=[] : 过滤列出的镜像,如dangling=true只显示没有被使用的镜像;也可指定带有特定标注的镜像等;
- –format=“TEMPLATE” : 控制输出格式,如. ID代表ID信息,.Repository 代表仓库信息等;
- –no-trunc=true | false: 对输出结果中太长的部分是否进行截断,如镜像的ID 信息,默认为是;
- -q, –quiet=true | false: 仅输出ID信息, 默认为否。
更多子命令选项还可以通过man docker-images来查看。
2. 使用tag命令添加镜像标签
为了方便在后续工作中使用特定镜像,还可以使用docker tag命令来为本地镜像任意添加新的标签。 例如,添加一个新的myubuntu:latest镜像标签:
docker tag ubuntu:18.04 myubuntu:18.04
再次使用docker images列出本地主机上镜像信息,可以看到多了一个myubuntu:18.04标签的镜像:
[root@open-Euler1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
wordpress latest 458dad822ff7 3 weeks ago 701MB
nginx latest b52e0b094bc0 4 weeks ago 192MB
reg.yym.com/library/busybox latest 31311c5853a2 5 months ago 4.27MB
busybox latest 31311c5853a2 5 months ago 4.27MB
myubuntu 18.04 f9a80a55f492 21 months ago 63.2MB
ubuntu 18.04 f9a80a55f492 21 months ago 63.2MB
reg.yym.com/openlab/ubuntu 18.04 f9a80a55f492 21 months ago 63.2MB
mysql 5.6 dd3b2a5dcb48 3 years ago 303MB
之后,用户就可以直接使用myubuntu:18.04来表示这个镜像了。
注意:这些myubuntu:18.04镜像的ID跟ubuntu:18.04是完全一致的,它们实际上指向了同一个镜像文件,只是别名不同而巳。docker tag命令添加的标签实际上起到了类似链接的作用。
3.使用inspect命令查看详细信息
[root@open-Euler1 ~]# docker inspect ubuntu:18.04
[
{
"Id": "sha256:f9a80a55f492e823bf5d51f1bd5f87ea3eed1cb31788686aa99a2fb61a27af6a",
"RepoTags": [
"myubuntu:18.04",
"ubuntu:18.04",
"reg.yym.com/openlab/ubuntu:18.04"
],
"RepoDigests": [
"reg.yym.com/openlab/ubuntu@sha256:0891d22f55fab66664581bbfca80601dfc9d6e8fff8f65a493e9f96644e29417"
],
"Parent": "",
"Comment": "",
"Created": "2023-05-30T09:32:09.432301537Z",
"DockerVersion": "20.10.21",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/bash"
],
"Image": "sha256:e24e6fe4d70b767b0621c909f548dab783f946ef6d9346ecc2272730b821a402",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.opencontainers.image.ref.name": "ubuntu",
"org.opencontainers.image.version": "18.04"
}
},
"Architecture": "amd64",
"Os": "linux",
"Size": 63156473,
"GraphDriver": {
"Data": {
"MergedDir": "/var/lib/docker/overlay2/926b8629b6c6a80e8f5763650a82542ebc1a730897eac9969eb9941f8058ce9b/merged",
"UpperDir": "/var/lib/docker/overlay2/926b8629b6c6a80e8f5763650a82542ebc1a730897eac9969eb9941f8058ce9b/diff",
"WorkDir": "/var/lib/docker/overlay2/926b8629b6c6a80e8f5763650a82542ebc1a730897eac9969eb9941f8058ce9b/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:548a79621a426b4eb077c926eabac5a8620c454fb230640253e1b44dc7dd7562"
]
},
"Metadata": {
"LastTagTime": "2025-03-09T16:15:06.918305625+08:00"
}
}
]
4.使用history命令查看镜像历史
既然镜像文件由多个层组成, 那么怎么知道各个层的内容具体是什么呢?这时候可以使用history子命令, 该命令将列出各层的创建信息。
例如,查看ubuntu:18.04 镜像的创建过程,可以使用如下命令:
[root@open-Euler1 ~]# docker history ubuntu:18.04
IMAGE CREATED CREATED BY SIZE COMMENT
f9a80a55f492 21 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 21 months ago /bin/sh -c #(nop) ADD file:3c74e7e08cbf9a876… 63.2MB
<missing> 21 months ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B
<missing> 21 months ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B
<missing> 21 months ago /bin/sh -c #(nop) ARG LAUNCHPAD_BUILD_ARCH 0B
<missing> 21 months ago /bin/sh -c #(nop) ARG RELEASE 0B
注意, 过长的命令被自动截断了,可以使用前面提到的–no-trunc选项来输出完整的命令。
2.3 搜寻镜像
本节主要介绍Docker 镜像的search子命令。 使用docker search命令可以搜索Docker Hub官方仓库中的镜像。语法为docker search [option] keyword。支持的命令选项主要包括:
例如, 搜索官方提供的带nginx关键字的镜像,如下所示:
2.4 删除和清理镜像
本节主要介绍Docker镜像的rm和prune子命令。
1.使用标签删除镜像
使用docker rmi或docker image rm命令可以删除镜像,命令格式为docker rmi IMAGE [IMAGE … ], 其中 IMAGE可以为标签或 ID 。
支持选项包括:
例如, 要删除掉myubuntu:latest镜像, 可以使用如下命令:
docker rmi myubuntu:18.04
大家可能会想到,本地的ubuntu:18.04镜像是否会受到此命令的影响。 无须担心, 当同一个镜像拥有多个标签的时候, docker rmi 命令只是删除了该镜像多个标签中的指定标签而已,并不影响镜像文件。 因此上述操作相当于只是删除了镜像f9a80a55f492的一 个标签副本而已。
但当镜像只剩下一个标签的时候就要小心了, 此时再使用docker rmi命令会彻底删除镜像。
例如通过执行docker rmi命令来删除只有一个标签的镜像,可以看出会删除这个镜像文件的所有文件层:
[root@open-Euler1 ~]# docker rmi busybox:latest
Untagged: busybox:latest
Untagged: busybox@sha256:498a000f370d8c37927118ed80afe8adc38d1edcbfc071627d17b25c88efcab0
2. 使用镜像ID来删除镜像
当使用docker rmi 命令,并且后面跟上镜像的ID(也可以是能进行区分的部分ID串前缀)时,会先尝试删除所有指向该镜像的标签,然后删除该镜像文件本身。
注意,当有该镜像创建的容器存在时,镜像文件默认是无法被删除的,例如:先利用ubuntu:18.04镜像创建一个简单的容器来输出一段话:
使用docker ps -a命令可以看到本机上存在的所有容器:
可以看到, 后台存在一个退出状态的容器,是刚基于ubuntu:18.04镜像创建的。试图删除该镜像,Docker会提示有容器正在运行, 无法删除:
如果要想强行删除镜像,可以使用-f参数:
注意,通常并不推荐使用-f参数来强制删除一个存在容器依赖的镜像。正确的做法是,先删除依赖该镜像的所有容器,再来删除镜像。
首先删除容器a21c0840213e:
然后使用ID来删除镜像, 此时会正常打印出删除的各层信息:
3. 清理镜像
使用Docker一段时间后, 系统中可能会遗留一些临时的镜像文件, 以及一些没有被使用的镜像, 可以通过docker image prune命令来进行清理。
支待选项包括:
例如,如下命令会自动清理临时的遗留镜像文件层,最后会提示释放的存储空间:
2.5 存出和载入镜像
本节主要介绍 Docker 镜像的 save 和 load子命令。 用户可以使用 docker [image] save 和 docker [image] load命令来存出和载人镜像。
1. 存出镜像
如果要导出镜像到本地文件,可以使用docker [image] save命令。 该命令支持-o、-output string 参数, 导出镜像到指定的文件中。
例如,导出本地的ubuntu:18.04 镜像为文件ubuntu_18.04.tar,如下所示:
[root@open-Euler1 ~]# docker save -o ubuntu_18.04.tar ubuntu:18.04
[root@open-Euler1 ~]# ll
total 645544
-rw-------. 1 root root 884 Jan 10 11:11 anaconda-ks.cfg
-rw-r--r-- 1 root root 9150593 Mar 1 11:03 apache-tomcat-8.0.30.tar.gz
-rw-r--r-- 1 root root 30720 Mar 8 12:09 backup.tar
-rw-r--r-- 1 root root 586290688 Mar 8 12:56 discuz.tar
-rw-r--r-- 1 root root 27 Mar 2 17:11 index.html
-rw------- 1 root root 65541632 Mar 9 16:26 ubuntu_18.04.tar
之后,用户就可以通过复制ubuntu_18.04.tar文件将该镜像分享给他人。
2. 载入镜像
可以使用docker [image] load将导出的 tar 文件再导人到本地镜像库。支持-i、-input string 选项,从指定文件中读入镜像内容。
例如,从文件ubuntu_18.04.tar 导人镜像到本地镜像列表,如下所示:
docker load -i ubuntu_18.04.tar
或者
docker load < ubuntu_18.04.tar
这将导入镜像及其相关的元数据信息(包括标签等)。导入成功后,可以使用docker images命令进行查看, 与原镜像一致。
第 3 章:操作Docker容器
容器 是Docker 的另一个核心概念。 简单来说,容器是镜像的一个运行实例。所不同的是,镜像是静态的只读文件,而容器带有运行时需要的可写文件层,同时,容器中的应用进程处于运行状态。
如果认为虚拟机是模拟运行的一整套操作系统(包括内核、 应用运行态环境和其他系统环境)和跑在上面的应用。 那么 Docker 容器就是独立运行的一个(或一组)应用,以及它们必需的运行环境。
本章将具体介绍围绕容器的重要操作,包括创建一个容器、 启动容器、终止一个容器、进入容器内执行操作、删除容器和通过导入导出容器来实现容器迁移等。
3.1 创建容器
从现在开始,忘掉“臃肿”的虚拟机吧,对容器的操作就像直接操作应用一样简单和快速。
本节主要介绍Docker容器的 create、 start、 run,、wait 和 logs 子命令。
1. 新建容器
可以使用docker [container] create 命令创建一个容器,例如:
[root@open-Euler2 ~]# docker create -it busybox:latest
22c599d83bcb4393f2a7c4749a809c86d1735ddeb3b720356db57213e2e9f2e9
[root@open-Euler2 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
22c599d83bcb busybox:latest "sh" 4 seconds ago Created musing_sutherland
[root@open-Euler2 ~]#
使用docker [container] create 命令新建的容器处于停止状态,可以使用 docker [container] start 命令来启动它。
由于容器是整个Docker技术栈的核心, create命令和后续的run命令支持的选项都 十分复杂,需要在实践中不断体会。
选项主要包括如下几大类: 与容器运行模式相关、与容器环境配置相关、与容器资源限制和安全保护相关,参见表4-1~表4-3。
2. 启动容器
使用docker [container] start 命令来启动一个已经创建的容器。例如,启动刚创建的busybox容器,然后通过docker ps命令,可以查看到一个运行中的容器:
[root@open-Euler2 ~]# docker start 22c599d83bcb #通过容器id启动
22c599d83bcb
[root@open-Euler2 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
22c599d83bcb busybox:latest "sh" 6 minutes ago Up 14 seconds musing_sutherland
3. 新建并启动容器
除了创建容器后通过start命令来启动也可以直接新建并启动容器。
所需要的命令主要为 docker [container]run ,等价于先执行docker [container] create 命令,再执行docker [container] start 命令。
例如,下面的命令输出一个“Hello World!“之后容器自动终止:
[root@open-Euler2 ~]# docker run ubuntu /bin/echo 'Hello World!'
Hello World!
[root@open-Euler2 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7f620e289a32 ubuntu "/bin/echo 'Hello Wo…" 46 seconds ago Exited (0) 45 seconds ago zen_chaum
这跟在本地直接执行/bin/echo ‘Hello World!” 相比几乎感觉不出任何区别。
当利用 docker [container] run来创建并启动容器时, Docker在后台运行的标准操作包括:
- 检查本地是否存在指定的镜像,不存在就从公有仓库下载;
- 利用镜像创建一个容器,并启动该容器;
- 分配一个文件系统给容器,并在只读的镜像层外面挂载一层可读写层;
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去;
- 从网桥的地址池配置一个IP地址给容器;
- 执行用户指定的应用程序;
- 执行完毕后容器被自动终止。
下面的命令启动一个bash终端,允许用户进行交互:
[root@open-Euler2 ~]# docker run -it ubuntu /bin/bash
root@28d877face35:/#
其中, -t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上, -i 则让容器的标准输入保持打开。 更多的命令选项可以通过man docker-run命令来查看。
在交互模式下,用户可以通过所创建的终端来输人命令,例如:
root@28d877face35:/# pwd
/
root@28d877face35:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@28d877face35:/# ps
PID TTY TIME CMD
1 pts/0 00:00:00 bash
10 pts/0 00:00:00 ps
在容器内用ps命令查看进程,可以看到,只运行了bash应用,并没有运行其他无关的进程。 用户可以按Ctrl+d或输入exit 命令来退出容器。
对于所创建的 bash 容器,当用户使用exit命令退出 bash 进程之后,容器也会自动退出。 这是因为对于容器来说,当其中的应用退出后,容器的使命完成,也就没有继续运行的必要了。
4. 守护态运行
更多的时候,需要让Docker容器在后台以守护态(Daemonized)形式运行。 此时,可以通过添加-d参数来实现。
例如,下面的命令会在后台运行容器:
[root@open-Euler2 ~]# docker run -itd ubuntu:latest
552e48e07720bf063b6f4c4208c04188d98afee57c9a0f3cf6d4fec5ca1d5d9b
[root@open-Euler2 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
552e48e07720 ubuntu:latest "/bin/bash" 4 seconds ago Up 3 seconds frosty_dirac
5. 查看容器输出
要获取容器的输出信息,可以通过docker [container] logs命令。
例如,查看某容器的输出可以使用如下命令:
[root@open-Euler2 ~]# docker logs 552e48e07720
root@552e48e07720:/# pwd
/
root@552e48e07720:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@552e48e07720:/# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 09:23 pts/0 00:00:00 /bin/bash
root 10 1 0 09:25 pts/0 00:00:00 ps -ef
root@552e48e07720:/#
exit
3.2 停止容器
本节主要介绍Docker容器的 pause/unpause、 stop 和 prune 子命令。
1. 暂停容器
可以使用docker [container] pause CONTAINER [CONTAINER … ]命令来暂停一个运行中的容器。
例如,启动一个容器,并将其暂停:
[root@open-Euler2 ~]# docker run --name test1 --rm -it ubuntu bash
root@3d0b00932ba4:/# (这里可以用ctrl+p然后ctrl+q后台运行该容器)
[root@open-Euler2 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3d0b00932ba4 ubuntu "bash" 19 seconds ago Up 19 seconds test1
[root@open-Euler2 ~]# docker pause test1
test1
[root@open-Euler2 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3d0b00932ba4 ubuntu "bash" 43 seconds ago Up 43 seconds (Paused) test1
处于 paused 状态的容器,可以使用 docker [container] unpause CONTAINER [CONTAINER … ] 命令来恢复到运行状态。
2. 终止容器
可以使用docker [container] stop 来终止一个运行中的容器。 该命令的格式为 docker [container] stop [-t | –time [=10]] [CONTA工NER… ] 。
该命令会首先向容器发送SIGTERM信号,等待一段超时时间后(默认为 10 秒),再发送SIGKILL 信号来终止容器:
[root@open-Euler2 ~]# docker stop 3d0b00932ba4
3d0b00932ba4
此时,执行docker container prune 命令,会自动清除掉所有处于停止状态的容器。
此外,还可以通过docker [container] kill 直接发送SIGKILL信号来强行终止容器。
当 Docker 容器中指定的应用终结时,容器也会自动终止。 例如,对于上一章节中只启动了一个终端的容器,用户通过exit命令或Ctrl+d来退出终端时,所创建的容器立刻终止,处于stopped状态。
可以用docker ps -qa命令看到所有容器的 ID。 例如:
[root@open-Euler1 ~]# docker ps -aq
2b7d17d89536
62a2df1db920
处于终止状态的容器,可以通过docker [container] start命令来重新启动:
[root@open-Euler2 ~]# docker run -itd ubuntu
5301c6e2b355b1459af95e73214b9f2abd1eb86c044e6a771214150335f78dd7
[root@open-Euler2 ~]# docker stop 5301c6e2b355
5301c6e2b355
[root@open-Euler2 ~]# docker start 5301c6e2b355
5301c6e2b355
[root@open-Euler2 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5301c6e2b355 ubuntu "/bin/bash" 5 minutes ago Up 4 seconds loving_hamilton
注意: Docker 容器在后台运行时,通常依赖于一个前台进程。如果这个进程退出,容器就会自动停止。这通常是容器自动关闭的最常见原因。如果你在创建容器时没有指定一个前台运行的命令,容器启动后没有前台进程在运行,它就会立即退出。例如,如果你只运行了
docker run -d ubuntu
而没有指定要运行的命令,容器会启动然后立即停止。
docker [container] restart 命令会将一个运行态的容器先终止,然后再重新启动:
[root@open-Euler2 ~]# docker restart 5301c6e2b355
5301c6e2b355
[root@open-Euler2 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5301c6e2b355 ubuntu "/bin/bash" 17 minutes ago Up 5 seconds loving_hamilton
3.3 进入容器
在使用-d参数时,容器启动后会进入后台,用户无法看到容器中的信息,也无法进 操作。
这个时候如果需要进入容器进行操作,推荐使用官方的attach或exec命令。
1. attach 命令
attach 是 Docker自带的命令,命令格式为:
docker [container] attach [–detach-keys[=[]]] [–no-stdin] [–sig-proxy[=true]] CONTAINER
这个命令支持三个主要选项:
下面示例如何使用该命令:
[root@open-Euler2 ~]# docker run -itd ubuntu
724bce51d10962c460c0fea34233b70c7df48cf4177a7bb3eaae5e8b2b58b330
[root@open-Euler2 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
724bce51d109 ubuntu "/bin/bash" 6 seconds ago Up 5 seconds laughing_haslett
[root@open-Euler2 ~]# docker attach 724bce51d109
root@724bce51d109:/#
docker attach
的限制
- 同步显示 :当多个终端窗口使用
docker attach
命令连接到同一个容器时,所有窗口都会同步显示相同的输出。这意味着,如果一个窗口执行了一个命令,其输出会出现在所有连接的窗口中。- 阻塞问题 :如果容器中的某个前台进程阻塞了(例如,等待用户输入),所有通过
docker attach
连接的会话都会被阻塞。这导致其他窗口无法执行操作,直到阻塞的命令被解除。- 退出行为 :当你通过
docker attach
进入容器并运行 bash 时,如果你退出 bash(例如,通过输入exit
),容器会因为没有前台进程在运行而停止。这是因为 Docker 容器在没有前台进程运行时会自动停止。
2.exec 命令
从Docker 的 1.3.0 版本起, Docker提供了一个更加方便的工具exec命令,可以在运行中容器内直接执行任意命令。
该命令的基本格式为:
比较重要的参数有:
例如,进入到刚创建的容器中,并启动一个bash:
[root@open-Euler2 ~]# docker exec -it 163622efdbfb bash
root@163622efdbfb:/# exit
[root@open-Euler2 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
163622efdbfb ubuntu "/bin/bash" 9 minutes ago Up 9 minutes sad_mclaren
可以看到会打开一个新的bash终端,在不影响容器内其他应用的前提下,用户可以与容器进行交互。在退出这个终端后docker容器依旧在运行。
注意:通过指定-it参数来保持标准输入打开,并且分配一个伪终端。 通过exec命令对容器执行操作是最为推荐的方式。
3.4 删除容器
可以使用docker [container) rm命令来删除处于终止或退出状态的容器,命令格式为
主要支持的选项包括:
例如,查看容器信息,并删除:
[root@open-Euler2 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
163622efdbfb ubuntu "/bin/bash" 15 minutes ago Up 15 minutes sad_mclaren
[root@open-Euler2 ~]# docker rm -f 163622efdbfb
3.5 导入和导出容器
某些时候,需要将容器从一个系统迁移到另外一个系统,此时可以使用 Docker 的导入和导出功能,这也是Docker自身提供的一个重要特性。
1. 导出容器
导出容器是指,导出一个已经创建的容器到一个文件,不管此时这个容器是否处于运行状态。 可以使用docker [container] export 命令,该命令格式为:
其中,可以通过-O选项来指定导出的tar文件名,也可以直接通过重定向来实现。
首先,查看所有的容器,如下所示:
[root@open-Euler2 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6f90ba016d87 ubuntu "/bin/bash" 3 seconds ago Exited (0) 2 seconds ago tender_galileo
163622efdbfb ubuntu "/bin/bash" 30 minutes ago Up 30 minutes sad_mclaren
分别导出容器163622efdbfb和6f90ba016d87 容器到文件test_for_run.tar文件和test_for_stop.tar文件:
[root@open-Euler2 ~]# docker export -o test_for_stop.tar 6f90ba016d87
[root@open-Euler2 ~]# ls
anaconda-ks.cfg docker docker-28.0.1.tgz test_for_stop.tar
[root@open-Euler2 ~]# docker export 163622efdbfb > test_for_run.tar
[root@open-Euler2 ~]# ls
anaconda-ks.cfg docker docker-28.0.1.tgz test_for_run.tar test_for_stop.tar
之后,可将导出的tar文件传输到其他机器上,然后再通过导人命令导入到系统中,实现容器的迁移。
2. 导入容器
导出的文件又可以使用docker [container] import 命令导入变成镜像,该命令格式为:
下面将导出的test_for_run.tar和test_for_stop.tar文件导入到系统中:
从本地文件导入
[root@open-Euler2 ~]# docker import test_for_run.tar test/ubuntu:latest
sha256:2870932093027479e25dd3ba0ce271e2f5165ab6888211f5da5cfde67871714e
从本地文件导入
[root@open-Euler2 ~]# cat test_for_stop.tar | docker import - test1/ubuntu:latest
sha256:e2a387d82e57fc391ec26eff072da08afe93b82c48c321e6f8b61040636c8c44
[root@open-Euler2 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
test1/ubuntu latest e2a387d82e57 About a minute ago 78.1MB
test/ubuntu latest 287093209302 2 minutes ago 78.1MB
ubuntu latest a04dc4851cbc 5 weeks ago 78.1MB
busybox latest 31311c5853a2 5 months ago 4.27MB
reg.yym.com/library/busybox latest 31311c5853a2 5 months ago 4.27MB
实际上,既可以使用docker load命令来导入镜像存储文件到本地镜像库,也可以使用docker [container] import 命令来导入一个容器快照到本地镜像库。这两者的区别在于:容器快照文件将丢弃所有的历史记录和元数据信息(仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积更大。 此外,从容器快照文件导入时可以重新指定标签等元数据信息。
3.6 查看容器
本节主要介绍Docker容器的 inspect、 top 和 stats 子命令。
1 . 查看容器详情
查看容器详情可以使用docker container inspect [OPTIONS] CONTAINER [CONTAINER . .. ]子命令。
例如,查看某容器的具体信息,会以json格式返回包括容器Id、 创建时间、路径、状态、镜像、配置等在内的各项信息:
[root@open-Euler2 ~]# docker inspect 163622efdbfb
[
{
"Id": "163622efdbfb20af07e9e6683329b10040cec7908da3aba32816198f74992cc9",
"Created": "2025-03-09T10:10:41.968207238Z",
"Path": "/bin/bash",
"Args": [],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 5297,
"ExitCode": 0,
"Error": "",
"StartedAt": "2025-03-09T10:10:42.088967496Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:a04dc4851cbcbb42b54d1f52a41f5f9eca6a5fd03748c3f6eb2cbeb238ca99bd",
"ResolvConfPath": "/var/lib/docker/containers/163622efdbfb20af07e9e6683329b10040cec7908da3aba32816198f74992cc9/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/163622efdbfb20af07e9e6683329b10040cec7908da3aba32816198f74992cc9/hostname",
"HostsPath": "/var/lib/docker/containers/163622efdbfb20af07e9e6683329b10040cec7908da3aba32816198f74992cc9/hosts",
"LogPath": "/var/lib/docker/containers/163622efdbfb20af07e9e6683329b10040cec7908da3aba32816198f74992cc9/163622efdbfb20af07e9e6683329b10040cec7908da3aba32816198f74992cc9-json.log",
"Name": "/sad_mclaren",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "bridge",
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"ConsoleSize": [
53,
131
],
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "host",
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": [],
"BlkioDeviceWriteBps": [],
"BlkioDeviceReadIOps": [],
"BlkioDeviceWriteIOps": [],
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": null,
"Ulimits": [],
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware",
"/sys/devices/virtual/powercap"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/3706374a37c42283828eddcc48dae753e2163b75bccd434ab95646f25f832fd8-init/diff:/var/lib/docker/overlay2/b84437fb662c47b2bd81a8cbd37c8fd5942cc53bda52ad4c04ca5ad9ee5734c5/diff",
"MergedDir": "/var/lib/docker/overlay2/3706374a37c42283828eddcc48dae753e2163b75bccd434ab95646f25f832fd8/merged",
"UpperDir": "/var/lib/docker/overlay2/3706374a37c42283828eddcc48dae753e2163b75bccd434ab95646f25f832fd8/diff",
"WorkDir": "/var/lib/docker/overlay2/3706374a37c42283828eddcc48dae753e2163b75bccd434ab95646f25f832fd8/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "163622efdbfb",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": true,
"OpenStdin": true,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/bash"
],
"Image": "ubuntu",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.opencontainers.image.ref.name": "ubuntu",
"org.opencontainers.image.version": "24.04"
}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "54ef1aa90e578ab95a9312a67535bcc54301fe61fecb0d359d2d7108156d4f1a",
"SandboxKey": "/var/run/docker/netns/54ef1aa90e57",
"Ports": {},
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "411700c6f651957227448d3ed62631fa6b4225767abde9188c0aaa7e8a3fbe63",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"MacAddress": "02:42:ac:11:00:02",
"NetworkID": "510077d34566ca7d2e3594e34653a4b07424e460fd9fe8b4d0769fe7e6e8d758",
"EndpointID": "411700c6f651957227448d3ed62631fa6b4225767abde9188c0aaa7e8a3fbe63",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"DriverOpts": null,
"DNSNames": null
}
}
}
}
]
2. 查看容器内进程
查看容器内进程可以使用docker [container] top [OPTIONS] CONTAINER [CONTAINER . .. ] 子命令。
这个子命令类似于Linux 系统中的 top命令,会打印出容器内的进程信息,包括PID、 用户、时间、命令等。 例如,查看某容器内的进程信息,命令如下:
[root@open-Euler2 ~]# docker top 163622efdbfb
UID PID PPID C STIME TTY TIME CMD
root 5297 5276 0 18:10 pts/0 00:00:00 /bin/bash
3. 查看统计信息
查看统计信息可以使用docker [container] stats [OPTIONS] [CONTAINER … ] 子命令,会动态显示CPU、内存、存储、网络等使用情况的统计信息。
支持选项包括:
例如,查看当前运行中容器的系统资源使用统计:
[root@open-Euler2 ~]# docker stats 163622efdbfb
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
163622efdbfb sad_mclaren 0.00% 592KiB / 1.394GiB 0.04% 1.44kB / 0B 0B / 0B 1
3.7 其他容器命令
本节主要介绍Docker容器的 cp、 diff、 port和update子命令。
1. 复制文件
container cp 命令支持在容器和主机之间复制文件。命令格式为docker [container] cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH |-。 支持的选项包括:
例如,将本地的路径data复制到test容器的/tmp路径下:
[root@open-Euler2 ~]# docker container cp test.txt 163622efdbfb:/tmp/
Successfully copied 2.05kB to 163622efdbfb:/tmp/
2. 查看变更
container diff 查看容器内文件系统的变更。 命令格式为 docker [container] diff CONTAINER。
例如,查看指定容器内的数据修改:
[root@open-Euler2 ~]# docker container diff 163622efdbfb
C /root
A /root/.bash_history
C /tmp
A /tmp/test.txt
3. 查看端口映射
container port 命令可以查看容器的端口映射情况。 命令格式为docker container port CONTAINER [PRIVATE_PORT[/PROTO]] 。例如,查看指定容器的端口映射情况:
[root@open-Euler2 ~]# docker container port 163622efdbfb
9000/tcp -> 0.0.0.0:9000
4. 更新配置
container update 命令可以更新容器的一些运行时配置,主要是一些资源限制份额。 命令格式为docker [container] update [OPTIONS] CONTAINER [CONTAINER .. . ] 。
支持的选项包括: