一、操作镜像部分
1.获取镜像
Dockerpull的命令格式如下:
docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
在上述展示中,还运行了拉取后的官方镜像。命令为:docker run,其后添加的-it是两个命令,-i表示交互式操作,-t表示终端。上述在运行容器后还使用了linux中的一些命令(日志查看、创建文件)证明容器创建成功。
2.列出镜像
操作展示如下:
可以看出docekr images 和 docker image ls的功能相同,都是列出已下载的镜像。
在上述由于虚悬镜像(dangling image)产生的原因主要是在构建或更新Docker镜像时,一些未被引用的中间层镜像或者由于镜像的仓库名和标签都被设置为<none>而产生的。而我还没有遇到取消或失败构建镜像的情况,因此我的展示结果中没有虚悬镜像。
同理,由于我的docker中目前还没有中间层镜像,所以docker image ls -a 的展示结果与docker image ls 的结果完全相同。
列出部分镜像:
如果镜像构建时,定义了 LABEL,还可以通过 LABEL 来过滤。命令格式如下:
docker image ls -f label=com.example.version=0.1
由于我在镜像构建时没有定义LABEL因此不做展示。
以特定格式显示:
3.删除本地镜像
通过ID删除本地镜像:
为了方便后续演示,我使用自己创建的Dockerfile文件重新创建了两个node类型的image。
Dockerfile内容展示如下:
构建命令如下:分别构建了一个名为docker和名为nginx的18-alpine类型的image。
于我的本地镜像中之前是有一个名为docker的镜像,且类型与上述新创建的第一个镜像相同,因此出现了虚悬镜像。在docker desktop查看如下:
在终端中查看如下:(可以发现创建时间的显示更加详细了)
通过镜像名称删除镜像:
上述展示是通过docker image rm nginx命令删除了刚刚通过Dockerfile创建的18-alpine类型的nginx镜像。通过digest删除镜像展示如下:
因为当我们使用上面命令删除镜像的时候,实际上是在要求删除某个标签的镜像。所以首先需要做的是将满足我们要求的所有镜像标签都取消,这就是我们看到的 Untagged 的信息。因为一个镜像可以对应多个标签,因此当我们删除了所指定的标签后,可能还有别的标签指向了这个镜像,如果是这种情况,那么 Delete 行为就不会发生。所以并非所有的 docker image rm 都会产生删除镜像的行为,有可能仅仅是取消了某个标签而已。
这就可以解释为什么在上述结果的展示中,我们通过docker image rm 中的digest删除命令后发现nginx的digest消失了,但是它并没有被删除。(关键部分已用红框标出)
用 docker image ls 命令来配合删除镜像:docker image rm $(docker image ls -q redis)可以删除所有名称为redis的镜像,docker image rm $(docker image ls -q -f before=mongo:3.2)可以删除所有在mongo:3.2之前创建的镜像。
4.利用 commit 理解镜像构成
docker run --name webserver -d -p 81:80 nginx
由于我的80端口被系统占用,无法结束任务,因此我映射到了主机的81端口部分,展示如下:
更改网页内容,展示如下:
利用docker diff webserver查看具体改动
运用docker commit 命令创建镜像:
命令格式:docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]
展示如下:
上述展示中,我创建了一个作者为thp、名称为webserverimage的镜像、其标签是v1.0。
现查看其历史记录:
运行刚刚创建的镜像webserverimage:v1.0并映射到82端口
b查看如下,可以发现如81端口更改后显示的结果相同。
使用 docker commit 意味着所有对镜像的操作都是黑箱操作,生成的镜像也被称为 黑箱镜像,换句话说,就是除了制作镜像的人知道执行过什么命令、怎么生成的镜像,别人根本无从得知。
5.使用Dockerfile定制镜像
创建Dockerfile:
通过Dockerfile构建镜像:
Docker build 命令期望的上下文是一个目录,而不是一个文件。如果在路径部分(红框圈出部分)给出了Dockerfile的路径则会报错,无法识别。如果当前路径就是Dockerfile文件所在路径,也可以用“.”来代替,展示如下:
当通过Dockerfile构建image的时候,用户会指定构建镜像上下文的路径,docker build 命令得知这个路径后,会将路径下的所有内容打包,然后上传给 Docker 引擎。这样 Docker 引擎收到这个上下文包后,展开就会获得构建镜像所需的一切文件。
docker build命令格式为:docker build [选项] <上下文路径/URL/->,其中[选项]部分可以是一系列可选的参数,用于定制构建过程。<上下文路径/URL/->指Dockerfile所在的路径。常用的选项如下:
-t, --tag: 用于指定构建镜像的标签(名称和版本)。例如,-t my-image:latest。
--build-arg:设置构建时的变量。这些变量可以在 Dockerfile 中使用 ARG 指令来定义。
--no-cache: 不使用缓存,从头开始构建镜像。
--pull: 在构建前尝试拉取镜像的最新版本。
--compress: 使用 gzip 压缩构建的镜像层。
--file: 指定 Dockerfile 的路径,默认为当前目录下的 'Dockerfile'。
docker build 的其他用法
1)直接用 Git repo 进行构建
命令如下:
docker build -t hello-world GitHub - docker-library/hello-world
运行这个命令后,Docker首先会克隆指定的Git仓库;然后Docker会在克隆下来的仓库中查找Dockerfile;最后,构建好的镜像会被标记为hello-world:latest。此外,如果 Dockerfile 不在仓库的根目录下,或想要指定一个特定的 Dockerfile,你可以使用 --file 或 -f 选项来指定 Dockerfile 的路径,命令为:docker build -t hello-world -f path/to/Dockerfile GitHub - docker-library/hello-world(红色部分即想要指定的Dockerfile。)
2) 用给定的 tar 压缩包构建
命令为:docker build http://server/context.tar.gz Docker 会从提供的 URL下载 .tar.gz 归档文件。下载完成后,Docker 会解压这个 .tar.gz 文件,将其内容解压到一个临时目录中。Docker 会在解压后的构建上下文中查找名为 Dockerfile 的文件。一旦找到 Dockerfile,Docker 就会按照其中定义的指令逐步构建镜像。构建过程完成后,Docker 会创建一个新的 Docker 镜像,并根据 Dockerfile 中的指令或构建命令中的 -t 或 --tag 参数为其打标签。构建好的镜像会被保存到本地 Docker 镜像仓库中,以供后续使用。
3)从标准输入中读取 Dockerfile 进行构建
命令为:docker build - < Dockerfile 或者 cat Dockerfile | docker build –
命令解释如下:
- (破折号):这个符号在 Unix 和 Linux 环境中通常用来表示标准输入(stdin)。在这个上下文中,它告诉 docker build 命令,Dockerfile 的内容将从命令行中直接输入,而不是从文件系统中某个位置的文件读取。
<:这是 shell 的重定向操作符,用于将文件的内容发送到命令的标准输入。
4) 从标准输入中读取上下文压缩包进行构建
命令为:docker build - < context.tar.gz
6.其他制作镜像的方式
1) 从 rootfs 压缩包导入
格式为:docker import [
选项
] <
文件
>|<URL>|- [<
仓库名
>[:<
标签
>]]
这条命令自动下载了 ubuntu-16.04-x86_64.tar.gz 文件,并且作为根文件系统展开导入,并保存为镜像 openvz/ubuntu:16.04。在蓝色方框中可以查看到这个导入的镜像;在橙色方框中可以查看历史记录观察到导入的文件连接。
2) Docker的镜像导入和导出docker save 和docker load
可以从上述终端的最下方发现saveimagefile1的文件类型是一个POSIX tar 归档文件。这意味着 saveimagefile1 包含了使用 tar 格式打包的数据。需要注意的是,如果多次运用docker save 命令且均保存为相同的文件名,那么之前保存的文件会被覆盖。
使用gzip方式压缩textnginx镜像后,我进行了load(加载)操作,但是在镜像查看中发现仍然只有一个textnginx镜像且没有出现虚悬镜像、history查看中也没有最新的操作。
查询后发现:
首先,当你使用 docker load 命令解压一个 Docker 镜像的存档文件(例如,由 docker save 创建的 .tar 或 .tar.gz 文件)时,Docker 会将镜像数据加载回 Docker 守护进程的本地镜像存储库中。这个过程并不涉及将文件解压到某个具体的文件系统目录;相反,它是将镜像的数据和结构恢复到 Docker 的内部存储系统中。因此目录中没有出现相关的image文件是正常的。
其次,通过 docker images 命令查看镜像列表,如果发现该镜像在压缩再解压后仍然没有其他变化,这是正常的现象。Docker 的 save 和 load 命令被设计用来完整地备份和恢复镜像。这意味着在压缩(save)和解压(load)过程中,镜像的所有层、元数据、配置和历史记录都应该保持不变。
最后,通过docker history命令查看镜像的历史信息发现没有变化。这是因为在使用 docker save 和 docker load 命令前后,镜像的内容本身没有发生变化(即没有新的层被添加或修改),那么 docker history 命令的输出自然也不会有任何新的记录。这是因为 docker history 显示的是镜像的构建历史,只有当镜像的构建过程中添加了新的层(例如,通过 docker build 过程中的新指令),历史记录中才会出现新的条目。
3)主机之间的文件迁移
如果我们结合上述两个压缩命令以及 ssh 甚至 pv 的话,利用 Linux 强大的管道,我们可以写一个命令完成从一个机器将镜像迁移到另一个机器,并且带进度条的功能,命令如下:
docker save <镜像名> | bzip2 | pv | ssh <用户名>@<主机名> 'cat | docker load'
二、操作容器部分
1.启动容器
从上述演示可以看出,在没有将容器与本地docker进行悬挂时,无法从容器中直接访问宿主机中已有的docker。
当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:1.检查本地是否存在指定的镜像,不存在就从 registry 下载2.利用镜像创建并启动一个容器、分配一个文件系统,并在只读的镜像层外面挂载一层可读写层3.从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去4.从地址池配置一个 ip 地址给容器5.执行用户指定的应用程序6.执行完毕后容器被终止
启动已经终止的容器:
查看本地现有的容器,可以发现除了名为docker
linuxtool的容器,其余容器皆未启动。
可以看到,web2和webserver两个容器均已启动。
2.后台运行容器
由于后台运行的容器输出的hello world不能直接在终端中看到,因此查看日志。展示如下:
由于日志中的hello world过多,因此只展示了一部分。
3.终止容器
在docker中可以运用docker start [容器名]启动一个容器,运用docker stop [容器名]终止一个容器。
4.进入容器
attach命令与exec命令演示
注:上述蓝色和绿色文字描述有一定错误,应为“列出所有运行的容器”并非“所有容器”。
经过上述命令对比发现:docker ps 和docker container ls 的命令的功能相同。经查询后发现如下:
1)docker ps和docker container ls两个命令在功能上是等价的,它们都可以用来列出当前正在运行的Docker容器。
2)docker ps:这个命令是Docker早期版本中的主要命令,用于查看正在运行的容器。
3)docker container ls:在Docker 1.13及更高版本中,为了对Docker命令进行更好的组织和分类,引入了一组新的命令格式,其中docker container是管理容器相关操作的命令组,ls是其下的一个子命令,专门用于列出容器。因此,docker container ls是在较新版本的Docker中引入的,旨在提供更清晰、更结构化的命令体系。
在使用中发现,如果运用docker attach命令进入一个nginx类型的容器想要与之交互时,便会出现无法交互的情况(不清楚是否为个例),问题形式展示如下:
键盘输入的任何字符均不显示,只能control+C强制退出,这样还会终止该容器。运用exec命令进入则没有这种情况。展示如下:
上述展示中运用了一些linux的命令,验证是否可以交互。
5.导出和导入容器
命令格式如下:
docker export 7691a814370e > ubuntu.tar和cat ubuntu.tar | docker import - test/ubuntu:v1.0
此外,也可以通过指定 URL 或者某个目录来导入,命令格式如下:
docker import http://example.com/exampleimage.tgz example/imagerepo
其中,http://example.com/exampleimage.tgz 是要导入的 .tgz 归档文件的 URL,example/imagerepo为为新导入的 Docker 镜像指定的本地名称和标签。
使用 docker import 来导入一个容器快照到本地镜像库的方式会丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),容器快照文件导入时可以重新指定标签等元数据信息。
6.删除容器
通过上述展示可以看出,docker container rm -f和docker rm -f 命令均可以删除一个正在运行中的容器,从绿色方框中可以看出。
如果一个容器没有运行,则使用docker container rm或docker rm 命令删除即可。此外,如果想要删除所有没有运行的容器,可以使用docker container prune命令删除这些容器。
三、Docker仓库部分
1.从Docker仓库中拉取镜像
1)搜索官方仓库中的镜像
命令:docker search
上述展示了搜索ubuntu和centos相关的镜像,并截取了部分镜像。此外,根据是否是官方提供,可将镜像分为两类。
一种是类似 centos 这样的镜像,被称为基础镜像或根镜像。这些基础镜像由 Docker 公司创建、验证、支持、提供。这样的镜像往往使用单个单词作为名字。
还有一种类型,比如 ansible/centos7-ansible 镜像,它是由 Docker Hub 的注册用户创建并维护的,往往带有用户名称前缀。可以通过前缀 username/ 来指定使用某个用户提供的镜像,比如 ansible 用户。
另外,在查找的时候通过 --filter=stars=N 参数可以指定仅显示收藏数量为 N 以上的镜像。
2)下载镜像
用户也可以在登录后通过 docker push 命令来将自己的镜像推送到 Docker Hub。命令为:docker tag [镜像] username/镜像名+标签
3)自动构建镜像
自动构建(Automated Builds)可以自动触发构建镜像,方便升级镜像。(现需付费)
要配置自动构建,包括如下的步骤:
登录 Docker Hub;在 Docker Hub 点击右上角头像,在账号设置(Account Settings)中关联(Linked Accounts)目标网站;在 Docker Hub 中新建或选择已有的仓库,在 Builds 选项卡中选择 Configure Automated Builds;选取一个目标网站中的项目(需要含 Dockerfile)和分支;指定 Dockerfile 的位置,并保存。之后,可以在 Docker Hub 的仓库页面的 Timeline 选项卡中查看每次构建的状态。
2.私有仓库
安装并运行一个容器作为私有仓库。
重新为已有的镜像添加标签:
使用docker push上传标记的镜像,并用curl命令查看是否推送成功。
从本地拉取镜像:
四、数据管理
1.创建一个数据卷
数据卷是一个可供一个或多个容器使用的特殊目录,它绕过UFS,可以提供很多有用的特性:数据卷可以在容器之间共享和重用、对数据卷的修改会立马生效、对数据卷的更新,不会影响镜像、数据卷默认会一直存在,即使容器被删除。
2.启动一个挂载数据卷的容器
上述命令首先在后台启动了一个新的 nginx:alpine 容器,并命名为 web,之后将之前创建的my-vol数据卷挂载到容器的 /usr/share/nginx/html 目录。这样,容器内 Nginx 服务的任何暴露端口都会被映射到宿主机的随机端口上。
使用docker inspect web命令查看web容器的数据卷信息如下:
数据卷是被设计用来持久化数据的,它的生命周期独立于容器,Docker 不会在容器被删除后自动删除 数据卷,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的 数据卷。如果需要在删除容器的同时移除数据卷。可以在删除容器的时候使用 docker rm -v 这个命令。
此外,无主的数据卷可能会占据很多空间,要清理请使用docker volume prune命令。
验证数据卷独立于容器展示如下:
3.挂载一个本地主机文件作为数据卷
为了方便查看容器中的历史消息记录情况,本演示将Windows路径下的text.docx文件挂载到容器内的/root/.bash_history路径。这样虽然不很合适,但是方便查看容器内bash shell的历史命令记录。可以从上述演示中看出,当退出容器后text.docx文件内的内容发生了变化。
五、使用网络
1.外部访问容器
容器的外部访问是指从Docker宿主机以外的系统或设备访问运行在Docker容器中的应用程序或服务。使用了外部访问之后,我们就可以在任意一台可以访问到宿主机的设备或电脑上,用过http://<宿主机ip>:<映射的端口号>的方式来访问宿主机容器中的Nginx服务器提供的默认欢迎页面。
-p 则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。支持的格式有 ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort。
映射所有接口地址,可以使用 hostPort:containerPort 格式将本地的 80 端口映射到容器的 80 端口。命令为:docker run -d -p 80:80 nginx:alpine
可以使用 ip:hostPort:containerPort 格式指定映射使用一个特定地址,比如当 localhost 的地址为 127.0.0.1时,命令应为:docker run -d -p 127.0.0.1:80:80 nginx:alpine。
映射到指定地址的任意端口,使用 ip::containerPort 绑定 localhost 的任意端口到容器的 80 端口,本地主机会自动分配一个端口。命令为:docker run -d -p 127.0.0.1::80 nginx:alpine 还可以使用 udp 标记来指定 udp 端口,命令为:docker run -d -p 127.0.0.1:80:80/udp nginx:alpine
由于在之前镜像commit部分已有过对指定端口的演示,在此仅演示容器的外部访问。
此时,在本地访问该容器演示如下:
主机地址查看以及外部访问(此处用自己的电脑演示),可以发现外部可以访问到该容器。
2.查看映射端口配置
通过docker port <容器名> <端口> 可以查看该容器在该端口的映射情况。上述演示中就可以看出,stupefied_merkle这个容器的80端口映射到了宿主机的32768端口上。
容器有自己的内部网络和 ip 地址(使用 docker inspect 查看,Docker 还可以有一个可变的网络配置。),此外,-p 标记可以多次使用来绑定多个端口。使用方法为:-p <a> -p <b> ……
3.容器互联
通过运用docker network inspect <networkname>的方式查看桥连接网络中连接的容器情况。可以看出,两个容器确实已经加入到了桥连接网络中。(红框和绿框)
在使用ping命令验证互联性时发现一些容器上默认是没有ping工具的,需要我们自行下载该工具。当你执行 ping 命令时,它会默认持续不断地发送 ICMP 回声请求并显示响应,可以使用 -c 选项来限制发送的请求数量。下面展示在webserver上ping dockertext容器。
在dockertext 容器中ping webserver容器;
发现均可以ping通,证明两容器实现了互联。
六、使用Dockerfile创建镜像
由于在镜像部分已经演示了如何通过Dockerfile定制镜像,因此在此处只罗列出了Dockerfile中的一些操作指令。