目录
4.2.3 守护式容器(让docker 在后台保持运行状态)
一 关于对镜像和容器的理解
Docker镜像好比操作系统的镜像(iso)
Docker容器好比安装完成的操作系统
# docker镜像文件运行起来之后就是我们所说的docker容器
Docker 中的三个概念:镜像,容器,仓库
1、镜像(image):Docker 镜像就是一个只读的模板,镜像可以用来创建 Docker 容器。Docker 提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用。
镜像是一种文件结构。Dockerfile中的每条命令都会在文件系统中创建一个新的层次结构,文件系统在这些层次上构建起来,镜像就构建于这些联合的文件系统之上。Docker官方网站专门有一个页面来存储所有可用的镜像,网址是:index.docker.io。
2、容器( Container):容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。可以把容器看做是一个简易版的 Linux 环境,Docker 利用容器来运行应用。镜像是只读的,容器在启动的时候创建一层可写层作为最上层。
3、仓库:仓库是集中存放镜像文件的场所,仓库注册服务器(Registry)上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。目前,最大的公开仓库是 Docker Hub,存放了数量庞大的镜像供用户下载。
Docker仓库用来保存我们的images,当我们创建了自己的image之后我们就可以使用push命令将它上传到公有或者私有仓库,这样下次要在另外一台机器上使用这个image时候,只需要从仓库上pull下来就可以了。Docker 仓库的概念跟 Git 类似,注册服务器可以理解为 GitHub 这样的托管服务。
那到底什么是Docker镜像呢?
Docker 镜像是由文件系统叠加而成(是一种文件的存储形式)。最底端是一个文件引 导系统,即 bootfs,这很像典型的 Linux/Unix 的引导文件系统。Docker 用户几乎永远不会和 引导系统有什么交互。实际上,当一个容器启动后,它将会被移动到内存中,而引导文件系 统则会被卸载,以留出更多的内存供磁盘镜像使用。Docker 容器启动是需要一些文件的, 而这些文件就可以称为 Docker 镜像。
Docker 把应用程序及其依赖,打包在 image 文件里面。只有通过这个文件,才能生成 Docker 容器。image 文件可以看作是容器的模板。Docker 根据 image 文件生成容器的实例。同一个 image 文件,可以生成多个同时运行的容器实例。
image 是二进制文件。实际开发中,一个 image 文件往往通过继承另一个 image 文件,加上一些个性化设置而生成。举例来说,你可以在 Ubuntu 的 image 基础上,往里面加入 Apache 服务器,形成你的 image。
image 文件是通用的,一台机器的 image 文件拷贝到另一台机器,照样可以使用。一般来说,为了节省时间,我们应该尽量使用别人制作好的 image 文件,而不是自己制作。即使要定制,也应该基于别人的 image 文件进行加工,而不是从零开始制作。
为了方便共享,image 文件制作完成后,可以上传到网上的仓库。Docker 的官方仓库 Docker Hub 是最重要、最常用的 image 仓库。此外,出售自己制作的 image 文件也是可以的。
二、Docker 基础命令
2.1 启动 docker
systemctl start docker
2.2 关闭/停止 docker
systemctl stop docker
2.3 重启 docker
systemctl restart docker
2.4 开机启动 docker
systemctl enable docker
2.5 查看 docker 版本信息
docker version
2.6 查看 docker 系统信息,包括镜像和容器数
docker info
2.7 查看 docker 运行状态
systemctl status docker
如果在运行中,输入命令后,会看到绿色的 active
:
不再运行时,输入命令后,会发现绿色的 active
消失了,还会提示当前的 docker
状态是 inactive(dead)
(死亡):
2.8 Docker 帮助命令
docker --help
# 查看docker命令命令帮助文档
docker 具体命令 --help
三、 Docker镜像操作
3.1、查看本地所有镜像
docker images
# 或
docker image ls
可选参数说明:
-a 列出所有镜像
-q 只显示镜像ID
标题说明:
REPOSITORY:镜像所在的仓库名称
TAG:镜像标签
IMAGEID:镜像ID
CREATED:镜像的创建日期(不是获取该镜像的日期)
SIZE:镜像大小
同一个仓库源可以有多个tag版本(如mysql 有5.7;8.0版本)。一般我们使用repository:tag 来定义不同镜像,如果不指定tag版本,默认最新版本。(例如使用ubuntu,docker默认使用ubuntu:latest镜像)
为了区分同一个仓库下的不同镜像,Docker 提供了一种称为标签(Tag)的功能。每个 镜像在列出来时都带有一个标签,例如latest、 12.10、12.04 等等。
在运行同一个仓库中的不同镜像时,可以通过在仓库名后面加上一个冒号和标签名 来指定该仓库中的某一具体的镜像,例如 docker run –name custom_container_name –i –t docker.io/ubunto:12.04 /bin/bash,表明从镜像 Ubuntu:12.04 启动一个容器,而这个镜像的操作系统就是 Ubuntu:12.04。在构建容器时指定仓库的标签也是一个好习惯。
3.2 查看镜像、容器、数据卷所占用的空间
docker system df
3.3 查看远程仓库镜像
docker search [镜像名]
--limit [数量]:列出前几个
3.4 拉取镜像
Docker维护了镜像仓库,分为共有和私有两种,共有的官方仓库Docker Hub(Docker Hub)是最重要最常用的镜像仓库。私有仓库(Private Registry)是开发者或者企业自建的镜像存储库,通常用来保存企业 内部的 Docker 镜像,用于内部开发流程和产品的发布、版本控制。
从开发仓库中拉取镜像
docker image pull library/hello-world
上面代码中,docker image pull是抓取 image 文件的命令。library/hello-world是 image 文件在仓库里面的位置,其中library是 image 文件所在的组,hello-world是 image 文件的名字。
从 Docker 镜像仓库获取镜像,拉取到本地
由于 Docker 官方提供的 image 文件,都放在library组里面,所以它的是默认组,可以省略。因此,从docker仓库拉取镜像命令可以写成下面这样
docker pull [镜像名]
docker pull [镜像名]:tag
不加 tag
(版本号),即默认拉取 docker
仓库中该镜像的最新版本,相当于命令 docker pull [镜像名]:latest
。
3.5 删除镜像
- 当前镜像没有被任何容器使用才可以删除。
# 删除一个镜像
docker rmi -f 镜像名/镜像ID
# 删除多个镜像:其镜像ID或镜像用空格隔开即可
docker rmi -f 镜像名/镜像ID 镜像名/镜像ID 镜像名/镜像ID
# 删除全部镜像:-a 意思为显示全部,-q 意思为只显示ID
docker rmi -f $(docker images -aq)
强制删除镜像:
docker image rm 镜像名/镜像ID
# 删除所有仓库名为 redis 的镜像
docker image rm $(docker image ls -q redis)
# 删除所有在 mongo:3.2 之前的镜像
docker image rm $(docker image ls -q -f before=mongo:3.2)
3.6 镜像标签
有时候,我们需要对一个镜像进行分类或版本迭代操作。比如一个微服务已经打为 docker 标签,但是根据环境进行区分为 develop 环境与 alpha 环境,这时候,我们就可以使用 tag ,来对镜像做一个标签添加,从而进行区分;版本迭代逻辑也一样,根据不同的 tag 进行区分。
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
参数
参数 | 描述 |
---|---|
SOURCE_IMAGE | 要打标签的源镜像,格式为 REPOSITORY[:TAG],其中 TAG 是可选的 |
TARGET_IMAGE | 目标镜像的名称和标签,格式为 REPOSITORY[:TAG] |
# 如果省略 TAG,则会为镜像默认打上 latest TAG
docker tag aaa bbb
# 上面的操作等价于下面这行语句
docker tag aaa:latest bbb:latest
# 将名为 myimage 版本为 latest 的本地镜像打标签为 myimage:v2.0
docker tag myimage:latest myimage:v2.0
四 Docker容器操作
4.1 查看容器
语法:docker ps [options]
作用:列出当前所有正在运行
的容器
-a
:列出当前所有正在运行的容器 + 历史上运行过得容器(已停止的)
-l
:显示最近创建的容器
-n
:显示最近n个创建的容器
-q
:静默模式,只显示容器编号
docker ps -a // 查看全部容器
docker ps -l // 查看最新容器docker container ls #列出本机正在运行的容器
docker container ls --all # 列出本机所有容器,包括已经终止运行的
4.2 容器的创建与启动
docker创建容器可以用docker create命令来执行,
docker create -it debian:latest
但是通过docker create命令创建的容器是停止的,我们可以用 docker ps -a -q 命令来查看哪些是停止状态的容器。docker create 创建的容器需要用docker start命令来启动容器, 因此平常不用
直接创建并且启动一个容器:
先创建在启动比较麻烦,可以用docker run命令来实现直接创建启动一个容器的,其实docker run命令等价于先执行docker create然后执行docker start命令。
语法
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]docker run [option] 镜像名 [向启动容器中传入的命令]
常用可选参数说明:
-i 表示以“交互模式”运行容器,表示让容器的标准输入保持打开, 通常与 -t 同时使用
-t 表示让docker分配一个伪输入终端(pseudo-tty)并绑定到容器的标准输入上,同时容器启动后会进入其命令行,通常与 -i 同时使用。
-d 则会创建一个守护式容器在后台运行 (护式运行)
--name 为创建的容器命名,不使用则会随机分配一个名称
--volume,-v 绑定一个卷。表示目录映射关系(前者是宿主机目录,后者是映射到宿主机上的目录,即 宿主机目录:容器中目录),可以使用多个-v 做多个目录或文件映射。注意:最好做目录映射,在宿主机上做修改,然后可以共享到容器上。
-p :小写,指定端口映射,格式为:主机(宿主)端口:容器内映射端口 。可以使用多个-p 做多个端口映射 docker run -p ip:hostPort:containerPort redis
-P: 大写,随机端口映射,容器内部端口随机映射到主机的高端口
-e 为容器设置环境变量
--network=host 表示将主机的网络环境映射到容器中,容器的网络与主机相同
当使用docker run命令创建启动容器时,Docker在后台运行的标准操作有下面几个步骤
- 检测本地是否存在指定的镜像,不存在就从公有仓库下载
- 利用镜像创建并启动一个容器
- 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
- 从地址池配置一个IP地址给容器
- 执行用户指定的应用程序
- 执行完毕后终止容器
示例:
使用docker镜像 nginx:latest 以后台模式启动一个容器,并将容器命名为my-nginx, 同时将容器80端口映射到主机8081端口,可以通过浏览器访问 http://主机IP:8081
docker run --name my-nginx -p 8081:80 -d nginx:latest
使用镜像 nginx:latest 以交互模式启动一个容器,在容器内执行/bin/bash命令
docker run -it nginx:latest /bin/bash
4.2.1 docker挂载目录
数据挂载:简单来讲,就是将容器内的数据与外部宿主机文件绑定起来,类似一个双持久化,当容器删除时,宿主机文件数据目录仍在,下次启动容器只要将数据目录指向宿主机数据所在位置即可恢复
通过-v参数,冒号前为宿主机目录,必须为绝对路径,冒号后为镜像内挂载的路径
docker run -it -v /home/dock/Downloads:/usr/Downloads ubuntu64 /bin/bash
如果要挂载多个宿主机目录,可以写多个 -v
docker run -it -v [宿主机目录1]:[docker目录1] -v [宿主机目录2]:[docker目录2] ubuntu64 /bin/bash
4.2.2 交互式容器
例如,创建一个交互式容器,并命名为mycentos
docker run -it --name=mycentos centos /bin/bash
在容器中可以随意执行linux命令,就是一个ubuntu的环境,当执行exit命令退出时,该容器也随之停止。
4.2.3 守护式容器(让docker 在后台保持运行状态)
在实际应用中我们更多的是需要容器在后台以守护状态(Daemonized)形式运行,我们可以使用-d参数来实现容器的后台守护状态运行
docker容器之后台运行 - 进击的davis - 博客园 (cnblogs.com)
例如,创建一个守护式容器,并命名为mycentos2
docker run -dit --name=mycentos2 centos
创建一个守护式容器:如果对于一个需要长期运行的容器来说,我们可以创建一个守护式容器。在容器内部exit退出时,容器也不会停止。注意:如果想要docker 在后台运行,退出时应该
Ctrl + p + q
否则dockers容器会退出关闭
4.2.4 设置开机自动启动容器
启动容器时,使用 docker run 命令时,添加参数 --restart=always 便表示该容器随 docker 服务启动而自动启动。
docker run -itd --name redis002 -p 8888:6379 --restart=always redis:5.0.5 /bin/bash
4.3 进入容器
进入已运行的容器
docker exec 命令
语法:
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
其中 CONTAINER 可以是 容器名或容器id
OPTIONS说明:
-d : 分离模式: 在后台运行
-i : 即使没有附加也保持STDIN 打开
-t : 分配一个伪终端
/bin/bash:交互路径
docker exec -it mycentos2 /bin/bash
在容器名称 mycentos2 中开启一个交互模式的终端
docker exec -it 721eb23901ce /bin/bash
使用容器ID 721eb23901ce 开启一个交互模式的终端
4.4、退出容器
方法一:使用exit命令
直接退出:未添加-d(持久化运行容器)时,执行此参数容器会被关闭
在容器内部,通过"exit"命令可以安全地退出容器,并返回到主机系统。这个命令会将容器停止并删除它。这个方法适用于不需要保留容器状态或文件系统更改的情况。如果需要保留容器状态或文件系统更改,可以使用第二种方法。
方法二:使用Ctrl+P+Q组合键
无论是否添加 -d 参数,执行此命令,容器都不会被关闭
另一种退出Docker容器的方法是使用Ctrl+P, Ctrl+Q组合键。这个方法可以将容器放入后台运行,而不停止它或删除它。通过这种方法,你可以保留容器状态,并在需要时重新进入。
4.5 容器启动、重启、停止、删除
docker start [容器名/容器ID]:启动已经停止运行的容器
docker restart [容器名/容器ID]:重启容器
docker stop [容器名/容器ID]:停止正在运行的容器
docker kill [容器名/容器ID]:强制停止正在运行的容器
docker rm [容器名/容器ID]:删除已经停止的容器
docker rm -f [容器名/容器ID]:强制删除容器
docker rm -f $(docker ps -aq):一次性删除多个容器(谨慎使用)docker stop ID && docker rm ID :停止然后
Docker之容器的创建、启动、终止、删除、迁移等 | Linux–不是那么难
4. 6 容器日志、进程、进入命令行
# 查看容器日志:
docker logs [容器ID]
docker logs -f --tail=要查看末尾多少行(默认all) [容器ID]
#查看容器内运行的进程
docker top [容器ID]
#查看容器内部细节
docker inspect [容器ID]
4.7 容器重命名
docker rename 容器ID/容器名 新容器名
4.8 更新容器启动配置
不想删容器,又想让这个容器设置开机自启动,那么我们修改其启动配置即可。
docker update --restart=always 容器Id/容器名
# 或
docker container update --restart=always 容器Id/容器名
4.9 在容器和主机之间复制文件/文件夹
# 从宿主机拷文件到容器里面
docker cp <本地文件路径> <容器名称或ID>:<容器内目标路径>
# 从容器里面拷文件到宿主机
docker cp <容器名称或ID>:<容器内文件路径> <本地目标路径>
【注意】:不管容器有没有启动,拷贝命令都会生效。如果拷贝的内容有重复,会直接覆盖,不会询问。
五 容器镜像的创建,镜像/容器的导入导出
基于Dockerfile创建镜像 和 镜像的导入导出_docker 导入镜像-CSDN博客
六 Docker 报错问题:
1 、Pytorch下运行Dataloader报错, num_workers设置与docker的shared memory相关问题
如下面的截图错误:
只要是下面这两个错误
错误1: ERROR: Unexpected bus error encountered in worker. This might be caused by insufficient shared memory (shm).
错误2:RuntimeError: DataLoader worker (pid 2212) is killed by signal: Bus error. It is possible that dataloader's workers are out of shared memory. Please try to raise your shared memory limit.
产生错误的原因:
最可能的原因是,Docker的共享内存不足。由于在docker镜像中默认限制了shm(shared memory), 然而数据处理时pythorch则使用了shm。这就导致了在运行多线程时会将超出限制的DataLoader并直接被kill掉。这个原因可以从docker的说明文档中可以看出:
--oom-kill-disable=false:Whether to disable OOM Killer for the container or not.
这个命令表示是否要kill超出内存的程序,以免崩溃。
dataloader从RAM中找本轮迭代要用的batch,如果找到了就使用。如果没找到,就要num_worker个worker继续加载batch到内存,直到dataloader在RAM中找到目标batch。num_worker设置得大,好处是寻batch速度快,因为下一轮迭代的batch很可能在上一轮/上上一轮…迭代时已经加载好了。坏处是内存开销大,也加重了CPU负担(worker加载数据到RAM的进程是CPU复制的嘛)。num_workers的经验设置值是自己电脑/服务器的CPU核心数,如果CPU很强、RAM也很充足,就可以设置得更大些。
【Q&A】pytorch中的worker如何工作的 - 小塞 - 博客园
解决办法
方法1(测试过可用):在Dataloader中将num_worker设置为0。意味着每一轮迭代时,dataloader不再有自主加载数据到RAM这一步骤(因为没有worker了),而是在RAM中找batch,找不到时再加载相应的batch。
方法2:batch size设置得过大,shared memory不够(因为docker限制了shm)。因此改成更小的batchsize, 这样多线程就不会导致超出docker内存不够了。
方法3(推荐):重新调整docker的运行内存。退出docker后,重新运行docker并指定更大的共享内存。
docker run -m='16g' -memory-swap="20g" # 这个命令没测试过
或者在起Docker容器时,设置 --ipc=host 或者 --shm-size
--shm-size 8G 命令测试过
docker run --runtime=nvidia --shm-size 8G -it --rm dev:v1 /bin/bash
docker中内存相关的命令
关于docker内存相关的命令:(docker中有很多与内存相关的命令,如kernel-memory,oom等,这里列出常用的几个)
命令 | 说明 |
---|---|
-m, --memory="" | Memory limit (format: []). Number is a positive integer. Unit can be one of b, k, m, or g. Minimum is 4M. |
--memory-swap="" | 总内存设置:内存+交换内存;Total memory limit (memory + swap, format: []). Number is a positive integer. Unit can be one of b, k, m, or g. |
--shm-size="" | 共享内存 Size of /dev/shm. The format is . number must be greater than 0. Unit is optional and can be b (bytes), k (kilobytes), m (megabytes), or g (gigabytes). If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses 64m. |
关于其中的交换内存(swap)和共享内存(shm)的区别,可以看这篇文章: