参考:https://yeasy.gitbook.io/docker_practice、https://www.bilibili.com/video/BV1YRWse1ESD/?spm_id_from=333.1007.top_right_bar_window_custom_collection.content.click
# 一、Docker 简介
# 1.1 什么是 docker
Docker 使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核的 cgroup,namespace,以及 OverlayFS 类的 Union FS 等技术,对进程进行封装隔离,属于 操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。
Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。
# 1.2 为什么要用 docker
作为一种新兴的虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。
- 更高效的利用系统资源
由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。
- 更快速的启动时间
传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。
- 一致的运行环境
开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而 Docker 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 「这段代码在我机器上没问题啊」 这类问题。
- 持续交付和部署
对开发和运维(DevOps)人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。
使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 Dockerfile 来进行镜像构建,并结合 持续集成 (Continuous Integration) 系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合 持续部署 (Continuous Delivery/Deployment) 系统进行自动部署。
而且使用 Dockerfile 使镜像构建透明化,不仅仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像。
- 更轻松的迁移
由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。
- 更轻松的维护和扩展
Docker 使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,Docker 团队同各个开源项目团队一起维护了一大批高质量的 官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。
- 对比传统虚拟机总结
特性 | 容器 | 虚拟机 |
---|---|---|
启动 | 秒级 | 分钟级 |
硬盘使用 | 一般为 MB | 一般为 GB |
性能 | 接近原生 | 弱于 |
系统支持量 | 单机支持上千个容器 | 一般几十个 |
# 二、基本概念
# 2.1 镜像
我们都知道,操作系统分为内核 和用户空间。对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 Ubuntu:18.04 就包含了完整的一套 Ubuntu 18.04 最小系统的 root 文件系统。Docker 镜像不包含任何动态数据,其内容在构建之后也不会被改变。
# 2.2 容器
镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
容器的实质是进程,但与直接在宿主执行的进程不同,容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。
# 2.3 仓库
镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。
一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个 标签(Tag);每个标签对应一个镜像。
通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:< 标签 > 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。
最常使用的 Registry 公开服务是官方的 Docker Hub,这也是默认的 Registry,并拥有大量的高质量的 官方镜像。
除了使用公开服务外,用户还可以在本地搭建私有 Docker Registry。Docker 官方提供了 Docker Registry 镜像,可以直接使用做为私有 Registry 服务。
# 三、使用镜像
# 3.1 获取镜像
从 Docker 镜像仓库获取镜像的命令是 docker pull。其命令格式为:
$ docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签] |
-
具体的选项可以通过 docker pull --help 命令看到
-
Docker 镜像仓库地址:地址的格式一般是 <域名 / IP>[: 端口号]。默认地址是 Docker Hub (docker.io)。
-
仓库名:仓库名是两段式名称,即 <用户名>/< 软件名 >。对于 Docker Hub,如果不给出用户名,则默认为 library,也就是官方镜像。
(base) ember@ember-Victus-by-HP-Laptop:~$ docker pull ubuntu:18.04 | |
18.04: Pulling from library/ubuntu | |
7c457f213c76: Pull complete | |
Digest: sha256:152dc042452c496007f07ca9127571cb9c29697f42acbfad72324b2bb2e43c98 | |
Status: Downloaded newer image for ubuntu:18.04 | |
docker.io/library/ubuntu:18.04 |
# 3.2 列出镜像
要想列出已经下载下来的镜像,可以使用 docker image ls
或者 docker images
命令。
(base) ember@ember-Victus-by-HP-Laptop:~$ docker images | |
REPOSITORY TAG IMAGE ID CREATED SIZE | |
pytorch/pytorch latest bbb948040751 8 months ago 7.6GB | |
ubuntu 18.04 f9a80a55f492 16 months ago 63.2MB | |
hello-world latest d2c94e258dcb 17 months ago 13.3kB | |
(base) ember@ember-Victus-by-HP-Laptop:~$ docker image ls | |
REPOSITORY TAG IMAGE ID CREATED SIZE | |
pytorch/pytorch latest bbb948040751 8 months ago 7.6GB | |
ubuntu 18.04 f9a80a55f492 16 months ago 63.2MB | |
hello-world latest d2c94e258dcb 17 months ago 13.3kB | |
(base) ember@ember-Victus-by-HP-Laptop:~$ |
列表包含了 仓库名、标签、镜像 ID、创建时间 以及 所占用的空间。
其他显示 docker 镜像的命令:
docker system df # 查看镜像、容器、数据卷所占用的空间 | |
docker image ls ubuntu # 根据仓库名列出镜像 | |
docker image ls ubuntu:18.04 #列出特定的某个镜像 |
# 3.3 运行镜像
有了镜像后,我们就能够以这个镜像为基础启动并运行一个容器。以上面的 ubuntu:18.04 为例,如果我们打算启动里面的 bash 并且进行交互式操作的话,可以执行下面的命令。
(base) ember@ember-Victus-by-HP-Laptop:~$ docker run -it --rm ubuntu:18.04 bash | |
root@e9a46d9a85a7:/# cat /etc/os-release | |
NAME="Ubuntu" | |
VERSION="18.04.6 LTS (Bionic Beaver)" | |
ID=ubuntu | |
ID_LIKE=debian | |
PRETTY_NAME="Ubuntu 18.04.6 LTS" | |
VERSION_ID="18.04" | |
HOME_URL="https://www.ubuntu.com/" | |
SUPPORT_URL="https://help.ubuntu.com/" | |
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" | |
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" | |
VERSION_CODENAME=bionic | |
UBUNTU_CODENAME=bionic | |
root@e9a46d9a85a7:/# exit | |
exit | |
(base) ember@ember-Victus-by-HP-Laptop:~$ |
docker run 就是运行容器的命令,主要使用到的参数如下
-
-it:这是两个参数,一个是 -i:交互式操作,一个是 -t 终端。我们这里打算进入 bash 执行一些命令并查看返回结果,因此我们需要交互式终端。
-
–rm:这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动 docker rm。我们这里只是随便执行个命令,看看结果,不需要排障和保留结果,因此使用 --rm 可以避免浪费空间。
-
ubuntu:18.04:这是指用 ubuntu:18.04 镜像为基础来启动容器。
-
bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 bash。
进入容器后,我们可以在 Shell 下操作,执行任何所需的命令。这里,我们执行了 cat /etc/os-release,这是 Linux 常用的查看当前系统版本的命令,从返回的结果可以看到容器内是 Ubuntu 18.04.1 LTS 系统。
最后我们通过 exit 退出了这个容器。
# 3.4 删除镜像
如果要删除本地的镜像,可以使用 docker image rm 命令,其格式为:
$ docker image rm [选项] <镜像1> [<镜像2> ...] |
其中,<镜像> 可以是 镜像短 ID、镜像长 ID、镜像名 或者 镜像摘要。我们可以用镜像的完整 ID,也称为长 ID,来删除镜像。使用脚本的时候可能会用长 ID,但是人工输入就太累了,所以更多的时候是用短 ID 来删除镜像。docker image ls 默认列出的就已经是短 ID 了,一般取前 3 个字符以上,只要足够区分于别的镜像就可以了。
docker image rm 501 # 使用短 ID 来删除镜像 | |
docker image rm centos # 使用镜像名 & lt; 仓库名 >:< 标签 > 来删除镜像 |
# 3.5 制作镜像
(1) docker commit
todo
(2) Dockerfile
todo
# 四、操作容器
# 4.1 启动容器
启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(exited)的容器重新启动。
(1)新建并启动
所需要的命令主要为 docker run
。
例如,下面的命令输出一个 “Hello World”,之后终止容器。
(base) ember@ember-Victus-by-HP-Laptop:~$ docker run ubuntu:18.04 /bin/echo 'Hello world' | |
Hello world |
下面的命令则启动一个 bash 终端,允许用户进行交互。
(base) ember@ember-Victus-by-HP-Laptop:~$ docker run ubuntu:18.04 /bin/echo 'Hello world' | |
Hello world | |
(base) ember@ember-Victus-by-HP-Laptop:~$ docker run -it ubuntu:18.04 bash | |
root@c28d053628f4:/# pwd | |
/ | |
root@c28d053628f4:/# ls | |
bin dev home lib64 mnt proc run srv tmp var | |
boot etc lib media opt root sbin sys usr |
当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:
-
检查本地是否存在指定的镜像,不存在就从 registry 下载
-
利用镜像创建并启动一个容器
-
分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
-
从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
-
从地址池配置一个 ip 地址给容器
-
执行用户指定的应用程序
-
执行完毕后容器被终止
(2)启动已终止的容器
可以利用 docker container start
命令,直接将一个已经终止(exited)的容器启动运行。
# 4.2 查看正在运行中的容器
可以通过 docker container ls
或者 docker ps
命令来查看容器信息。不添加 -a
参数表示仅查询正在运行的容器,添加 -a
参数表示查询所有容器。
(base) ember@ember-Victus-by-HP-Laptop:~$ docker container ls | |
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES | |
f46a0966d2f0 ubuntu "/bin/bash" 2 minutes ago Up 2 minutes pedantic_ride | |
(base) ember@ember-Victus-by-HP-Laptop:~$ docker container ls -a | |
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES | |
f46a0966d2f0 ubuntu "/bin/bash" 35 seconds ago Up 34 seconds pedantic_ride | |
2017ea1579ba ubuntu "bash" About a minute ago Exited (0) About a minute ago heuristic_ritchie | |
a6ebe91f0963 ubuntu "bash" About a minute ago Exited (0) About a minute ago funny_ganguly | |
1ea1d2fdc98f ubuntu "/bin/bash" About a minute ago Exited (0) About a minute ago fervent_antonelli | |
8a22936923b9 ubuntu "/bin/bash" 3 minutes ago Exited (0) 2 minutes ago keen_galois | |
42ef1554542d ubuntu "bash" 4 minutes ago Exited (0) 4 minutes ago affectionate_torvalds | |
af4b52cb7f4d ubuntu "/bin/bash" 4 minutes ago Exited (0) 4 minutes ago modest_ritchie | |
9004e2682944 ubuntu "/bin/bash" 29 minutes ago Exited (0) 25 minutes ago suspicious_shockley | |
f2ee1fb9dbd3 ubuntu:18.04 "/bin/echo 'Hello wo…" 36 minutes ago Exited (0) 36 minutes ago focused_ride | |
9de4edc03c66 ubuntu:18.04 "/bin/echo 'Hello wo…" 37 minutes ago Exited (0) 37 minutes ago loving_poincare | |
c28d053628f4 ubuntu:18.04 "bash" 40 minutes ago Exited (0) 37 minutes ago nifty_diffie | |
482b8943345d ubuntu:18.04 "/bin/echo 'Hello wo…" 41 minutes ago Exited (0) 41 minutes ago agitated_galois | |
e56c41136583 hello-world "/hello" 2 hours ago Exited (0) 2 hours ago vibrant_carver | |
066f72347a3b pytorch/pytorch "bash" 3 days ago Exited (0) 3 days ago dazzling_poitras | |
a1d4426c8152 bbb948040751 "/bin/bash" 11 days ago Exited (137) 11 days ago confident_edison | |
51dd9da96e61 bbb948040751 "/bin/bash" 11 days ago Exited (0) 11 days ago nervous_williamson | |
9c03918a1e27 pytorch/pytorch:latest "/bin/bash" 12 days ago Exited (0) 12 days ago test |
# 4.3 守护态运行
更多的时候,需要让 Docker 在后台运行而不是直接把执行命令的结果输出在当前宿主机下。此时,可以通过添加 -d 参数来实现。下面举两个例子来说明一下。
如果不使用 -d 参数运行容器。
(base) ember@ember-Victus-by-HP-Laptop:~$ docker run ubuntu:18.04 /bin/echo 'Hello world' | |
Hello world |
容器会把输出的结果 (STDOUT) 打印到宿主机上面。如果使用了 -d 参数运行容器。
(base) ember@ember-Victus-by-HP-Laptop:~$ docker run -d ubuntu:18.04 /bin/echo 'Hello world' | |
f2ee1fb9dbd3936b7cdc2e7dac5a53e86e5e8122acb0dcef43ba4fc47ea6ccb6 | |
(base) ember@ember-Victus-by-HP-Laptop:~$ docker logs f2ee1fb9dbd3936b7cdc2e7dac5a53e86e5e8122acb0dcef43ba4fc47ea6ccb6 | |
Hello world |
此时容器会在后台运行并不会把输出的结果 (STDOUT) 打印到宿主机上面 (输出结果可以用 docker logs 查看)。
# 4.4 进入容器
在使用 -d
参数时,容器启动后会进入后台。
某些时候需要进入容器进行操作,包括使用 docker attach
命令或 docker exec
命令,推荐使用 docker exec
命令。
(1) attach
命令
(base) ember@ember-Victus-by-HP-Laptop:~$ docker run -dit ubuntu | |
9004e2682944ba4750772867e417a04348f1ff8b4bd8f83e629ef2052bf66844 | |
(base) ember@ember-Victus-by-HP-Laptop:~$ docker container ls | |
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES | |
9004e2682944 ubuntu "/bin/bash" 49 seconds ago Up 48 seconds suspicious_shockley | |
(base) ember@ember-Victus-by-HP-Laptop:~$ docker attach 9004 | |
root@9004e2682944:/# exit | |
exit | |
(base) ember@ember-Victus-by-HP-Laptop:~$ docker container ls | |
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES |
注意: 如果从这个 stdin 中 exit
,会导致容器的停止。
注:标准输入文件(stdin),通常对应终端的键盘;标准输出文件(stdout)和标准错误输出文件(stderr),这两个文件都对应终端的屏幕。
(2) exec
命令
(base) ember@ember-Victus-by-HP-Laptop:~$ docker run -dit ubuntu | |
7d49eb33ae2cca32be243690101b7640b312dee06f76f7fb083970410ccb0c76 | |
(base) ember@ember-Victus-by-HP-Laptop:~$ docker container ls | |
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES | |
7d49eb33ae2c ubuntu "/bin/bash" 7 seconds ago Up 7 seconds modest_saha | |
(base) ember@ember-Victus-by-HP-Laptop:~$ docker exec -it 7d49 bash | |
root@7d49eb33ae2c:/# exit | |
exit | |
(base) ember@ember-Victus-by-HP-Laptop:~$ docker container ls | |
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES | |
7d49eb33ae2c ubuntu "/bin/bash" 3 minutes ago Up 3 minutes modest_saha |
如果从这个 stdin 中 exit
,不会导致容器的停止。这就是为什么推荐使用 docker exec
的原因。
# 4.5 停止容器
可以使用 docker container stop
来终止一个运行中的容器。
此外,当 Docker 容器中指定的应用终结时,容器也自动终止。
例如对于上一章节中只启动了一个终端的容器,用户通过 exit 命令或 Ctrl+d 来退出终端时,所创建的容器立刻终止。
终止状态的容器可以用 docker container ls -a 命令看到。例如
(base) ember@ember-Victus-by-HP-Laptop:~$ docker container ls -a | |
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES | |
f2ee1fb9dbd3 ubuntu:18.04 "/bin/echo 'Hello wo…" 3 minutes ago Exited (0) 3 minutes ago focused_ride | |
9de4edc03c66 ubuntu:18.04 "/bin/echo 'Hello wo…" 4 minutes ago Exited (0) 4 minutes ago loving_poincare | |
c28d053628f4 ubuntu:18.04 "bash" 8 minutes ago Exited (0) 4 minutes ago nifty_diffie | |
482b8943345d ubuntu:18.04 "/bin/echo 'Hello wo…" 9 minutes ago Exited (0) 9 minutes ago agitated_galois | |
e56c41136583 hello-world "/hello" About an hour ago Exited (0) About an hour ago vibrant_carver | |
066f72347a3b pytorch/pytorch "bash" 3 days ago Exited (0) 3 days ago dazzling_poitras | |
a1d4426c8152 bbb948040751 "/bin/bash" 11 days ago Exited (137) 11 days ago confident_edison | |
51dd9da96e61 bbb948040751 "/bin/bash" 11 days ago Exited (0) 11 days ago nervous_williamson | |
9c03918a1e27 pytorch/pytorch:latest "/bin/bash" 12 days ago Exited (0) 12 days ago test |
处于终止状态的容器,可以通过 docker container start
命令来重新启动。
此外, docker container restart
命令会将一个运行态的容器终止,然后再重新启动它。
# 4.6 导出和导入
(1)导出容器
如果要导出本地某个容器,可以使用 docker export
命令。
(base) ember@ember-Victus-by-HP-Laptop:~$ docker container ls | |
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES | |
7d49eb33ae2c ubuntu "/bin/bash" 3 minutes ago Up 3 minutes modest_saha | |
(base) ember@ember-Victus-by-HP-Laptop:~$ docker export 7d49 > /home/ember/project/docker/test/ubuntu.tar |
这样将导出容器快照到本地文件。
(2)导入容器快照
可以使用 docker import
从容器快照文件中再导入为镜像,例如
(base) ember@ember-Victus-by-HP-Laptop:~$ cat /home/ember/project/docker/test/ubuntu.tar | docker import - test/ubuntu:v1.0 | |
sha256:819f39358ac6614e347c95e5ab2f948fae449b11e12c045a429a4ff0ad3c2c89 | |
(base) ember@ember-Victus-by-HP-Laptop:~$ docker images | |
REPOSITORY TAG IMAGE ID CREATED SIZE | |
test/ubuntu v1.0 819f39358ac6 23 seconds ago 78.1MB | |
ubuntu latest 59ab366372d5 9 days ago 78.1MB | |
pytorch/pytorch latest bbb948040751 8 months ago 7.6GB | |
ubuntu 18.04 f9a80a55f492 16 months ago 63.2MB | |
hello-world latest d2c94e258dcb 17 months ago 13.3kB |
# 4.7 删除容器
可以使用 docker container rm
来删除一个处于终止状态的容器。例如
(base) ember@ember-Victus-by-HP-Laptop:~$ docker container ls -a | |
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES | |
7d49eb33ae2c ubuntu "/bin/bash" 12 minutes ago Exited (137) 11 seconds ago modest_saha | |
(base) ember@ember-Victus-by-HP-Laptop:~$ docker container rm 7d49 | |
7d49 | |
(base) ember@ember-Victus-by-HP-Laptop:~$ docker container ls -a | |
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES |
# 五、访问仓库
docker search # 查找官方仓库中的镜像 | |
docker pull # 拉取官方镜像 | |
docker push # 将镜像推送到仓库 |
私有仓库:todo