[TOC]
介绍
在接触Docker之前,一直使用自建的开发环境来工作。
对于个人来说就是在换电脑的时候麻烦,换电脑了开发环境就得重新部署一次。差不得得要个半天时间…
对于公司团队来说更加麻烦了,每个同事部署的环境不一致,Windows系统与*nix系统的不兼容等.代码跑起来有差异。
Docker是一个类似于虚拟机的设计,一种新兴化的虚拟化方式。
特性 | Docker | 虚拟机 |
---|---|---|
启动 | 秒级 | 分钟级 |
硬盘使用 | 一般为MB | 一般为GB |
性能 | 接近原生 | 弱于原生 |
系统支持量 | 单主机支持上千个容器 | 一般几十个 |
Docker有三个关键概念:镜像(images)、容器(container)、仓库(registry)。其中镜像与容器两者关系类似于面向对象设计中的类
和实例
一样
镜像是静态的定义,容器是镜像运行是的实体
镜像加速:官方Docker Hub拉取镜像网络不稳定,推荐两个镜像仓库
安装
略~
使用Docker
镜像
拉取镜像
1 | docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签] |
具体的选项可以通过 docker pull --help
命令看到,这里我们说一下镜像名称的格式。
- Docker 镜像仓库地址:地址的格式一般是
<域名/IP>[:端口号]
。默认地址是 Docker Hub。 - 仓库名:如之前所说,这里的仓库名是两段式名称,即
<用户名>/<软件名>
。对于 Docker Hub,如果不给出用户名,则默认为library
,也就是官方镜像。
举个🌰
1 | $ docker pull ubuntu:16.04 |
运行
有了镜像之后,就能够以这个镜像为基础启动并运行一个容器。
1 | $ docker run -it --rm \ |
docker run
就是运行容器的命令
-it
:这是两个参数,一个是-i
:交互式操作,一个是-t
终端。我们这里打算进入bash
执行一些命令并查看返回结果,因此我们需要交互式终端。--rm
:这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动docker rm
。我们这里只是随便执行个命令,看看结果,不需要排障和保留结果,因此使用--rm
可以避免浪费空间。ubuntu:16.04
:这是指用ubuntu:16.04
镜像为基础来启动容器。bash
:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是bash
。
进入容器后,我们可以在 Shell 下操作,执行任何所需的命令。这里,我们执行了 cat /etc/os-release
,这是 Linux 常用的查看当前系统版本的命令,从返回的结果可以看到容器内是 Ubuntu 16.04.4 LTS
系统。
最后我们通过 exit
退出了这个容器。
常用命令
列出镜像
1
$ docker image ls
查看镜像、容器、数据卷所占用空间
1
$ docker system df
列出所有(包含中间层)镜像
1
$ docker image ls -a
容器
启动容器
启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(stopped
)的容器重新启动。
因为 Docker 的容器实在太轻量级了,很多时候用户都是随时删除和新创建容器。
所需要的命令主要为 docker run
。
例如,下面的命令输出一个 “Hello World”,之后终止容器。
1 | $ docker run ubuntu:14.04 /bin/echo 'Hello world' |
这跟在本地直接执行 /bin/echo 'hello world'
几乎感觉不出任何区别。
下面的命令则启动一个 bash 终端,允许用户进行交互。
1 | $ docker run -t -i ubuntu:14.04 /bin/bash |
其中,-t
选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上, -i
则让容器的标准输入保持打开。
在交互模式下,用户可以通过所创建的终端来输入命令,例如
1 | [email protected]:/# pwd |
当利用 docker run
来创建容器时,Docker 在后台运行的标准操作包括:
- 检查本地是否存在指定的镜像,不存在就从公有仓库下载
- 利用镜像创建并启动一个容器
- 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
- 从地址池配置一个 ip 地址给容器
- 执行用户指定的应用程序
- 执行完毕后容器被终止
启动已终止容器
可以利用 docker container start
命令,直接将一个已经终止的容器启动运行。
后台运行
更多的时候,需要让 Docker 在后台运行而不是直接把执行命令的结果输出在当前宿主机下。此时,可以通过添加 -d
参数来实现。
1 | $ docker run -d ubuntu:17.10 /bin/sh -c "while true; do echo hello world; sleep 1; done" |
终止容器
可以使用 docker container stop
来终止一个运行中的容器。
此外,当 Docker 容器中指定的应用终结时,容器也自动终止。
例如对于上一章节中只启动了一个终端的容器,用户通过 exit
命令或 Ctrl+d
来退出终端时,所创建的容器立刻终止。
终止状态的容器可以用 docker container ls -a
命令看到。例如
1 | docker container ls -a |
处于终止状态的容器,可以通过 docker container start
命令来重新启动。
此外,docker container restart
命令会将一个运行态的容器终止,然后再重新启动它。
进入容器
在使用 -d
参数时,容器启动后会进入后台。
某些时候需要进入容器进行操作,包括使用 docker attach
命令或 docker exec
命令,推荐大家使用 docker exec
命令,原因会在下面说明。
1.attach
命令
docker attach
是 Docker 自带的命令。下面示例如何使用该命令。
1 | $ docker run -dit ubuntu |
注意: 如果从这个 stdin 中 exit,会导致容器的停止。
2.exec
命令
-i -t 参数
docker exec
后边可以跟多个参数,这里主要说明 -i
-t
参数。
只用 -i
参数时,由于没有分配伪终端,界面没有我们熟悉的 Linux 命令提示符,但命令执行结果仍然可以返回。
当 -i
-t
参数一起使用时,则可以看到我们熟悉的 Linux 命令提示符。
1 | $ docker run -dit ubuntu |
如果从这个 stdin 中 exit,不会导致容器的停止。这就是为什么推荐大家使用 docker exec
的原因。
更多参数说明请使用 docker exec --help
查看。
导出、导入容器
导出容器
使用
docker export
命令.1
2
3
4$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7691a814370e ubuntu:14.04 "/bin/bash" 36 hours ago Exited (0) 21 hours ago test
$ docker export 7691a814370e > ubuntu.tar导入容器
可以使用
docker import
从容器快照文件中再导入为镜像,例如1
2
3
4$ cat ubuntu.tar | docker import - test/ubuntu:v1.0
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
test/ubuntu v1.0 9d37a6082e97 About a minute ago 171.3 MB此外,也可以通过指定 URL 或者某个目录来导入,例如
1
$ docker import http://example.com/exampleimage.tgz example/imagerepo
注:用户既可以使用 docker load 来导入镜像存储文件到本地镜像库,也可以使用 docker import 来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。此外,从容器快照文件导入时可以重新指定标签等元数据信息。
容器常用命令
新建并启动
1
$ docker run -it ubuntu:16.10
查看容器
1
$ docker container ls
启动已终止容器
1
$ docker container start [containerID]
后台运行容器
1
$ docker run -itd ubuntu:18.10 #添加 -d 参数
终止容器
1
$ docker container stop [containerID]
进入容器
1
2$ docker attach xxx
$ docker exec -i xxx iterm导出和导入容器
1
2
3
4
5#导出
$ docker export containerID > xxx.tar
#导入
$ cat ubuntu.tar | docker import - mytest/ubuntu:v1.0
$ docker import http://example.com/ubuntu.tgz mynewtest/image删除容器
1
2
3$ docker container rm [containerID]
#清理所有终止状态容器
$ docker container prune
Docker数据管理
数据卷(volume)
数据卷
是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:
数据卷
可以在容器之间共享和重用- 对
数据卷
的修改会立马生效 - 对
数据卷
的更新,不会影响镜像 数据卷
默认会一直存在,即使容器被删除
注意:
数据卷
的使用,类似于 Linux 下对目录或文件进行 mount,镜像中的被指定为挂载点的目录中的文件会隐藏掉,能显示看的是挂载的数据卷
。
创建一个数据卷
1 | $ docker volume create my-vol |
查看所有的 数据卷
1 | $ docker volume ls |
在主机里使用以下命令可以查看指定 数据卷
的信息
1 | $ docker volume inspect my-vol |
启动一个挂载数据卷的容器
在用 docker run
命令的时候,使用 --mount
标记来将 数据卷
挂载到容器里。在一次 docker run
中可以挂载多个 数据卷
。
下面创建一个名为 web
的容器,并加载一个 数据卷
到容器的 /webapp
目录。
1 | $ docker run -d -P \ |
查看数据卷的具体信息
在主机里使用以下命令可以查看 web
容器的信息
1 | $ docker inspect web |
数据卷
信息在 “Mounts” Key 下面
1 | "Mounts": [ |
删除数据卷
1 | $ docker volume rm my-vol |
数据卷
是被设计用来持久化数据的,它的生命周期独立于容器,Docker 不会在容器被删除后自动删除 数据卷
,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的 数据卷
。如果需要在删除容器的同时移除数据卷。可以在删除容器的时候使用 docker rm -v
这个命令。
无主的数据卷可能会占据很多空间,要清理请使用以下命令
1 | $ docker volume prune |
挂载主机目录
挂载一个主机目录作为数据卷
使用 --mount
标记可以指定挂载一个本地主机的目录到容器中去。
1 | $ docker run -d -P \ |
上面的命令加载主机的 /src/webapp
目录到容器的 /opt/webapp
目录。这个功能在进行测试的时候十分方便,比如用户可以放置一些程序到本地目录中,来查看容器是否正常工作。本地目录的路径必须是绝对路径,以前使用 -v
参数时如果本地目录不存在 Docker 会自动为你创建一个文件夹,现在使用 --mount
参数时如果本地目录不存在,Docker 会报错。
Docker 挂载主机目录的默认权限是 读写
,用户也可以通过增加 readonly
指定为 只读
。
1 | $ docker run -d -P \ |
加了 readonly
之后,就挂载为 只读
了。如果你在容器内 /opt/webapp
目录新建文件,会显示如下错误
1 | /opt/webapp # touch new.txt |
查看数据卷的具体信息
在主机里使用以下命令可以查看 web
容器的信息
1 | $ docker inspect web |
挂载主机目录
的配置信息在 “Mounts” Key 下面
1 | "Mounts": [ |
挂载一个本地主机文件作为数据卷
--mount
标记也可以从主机挂载单个文件到容器中
1 | $ docker run --rm -it \ |
这样就可以记录在容器输入过的命令了。
网络
外部访问容器
容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P
或 -p
参数来指定端口映射。
当使用 -P
标记时,Docker 会随机映射一个 49000~49900
的端口到内部容器开放的网络端口。
使用 docker container ls
可以看到,本地主机的 49155 被映射到了容器的 5000 端口。此时访问本机的 49155 端口即可访问容器内 web 应用提供的界面。
1 | $ docker run -d -P training/webapp python app.py |
同样的,可以通过 docker logs
命令来查看应用的信息。
1 | $ docker logs -f nostalgic_morse |
-p
则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。支持的格式有 ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort
。
映射所有接口地址
使用 hostPort:containerPort
格式本地的 5000 端口映射到容器的 5000 端口,可以执行
1 | $ docker run -d -p 5000:5000 training/webapp python app.py |
此时默认会绑定本地所有接口上的所有地址。
映射到指定地址的指定端口
可以使用 ip:hostPort:containerPort
格式指定映射使用一个特定地址,比如 localhost 地址 127.0.0.1
1 | $ docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py |
映射到指定地址的任意端口
使用 ip::containerPort
绑定 localhost 的任意端口到容器的 5000 端口,本地主机会自动分配一个端口。
1 | $ docker run -d -p 127.0.0.1::5000 training/webapp python app.py |
还可以使用 udp
标记来指定 udp
端口
1 | $ docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py |
查看映射端口配置
使用 docker port
来查看当前映射的端口配置,也可以查看到绑定的地址
1 | $ docker port nostalgic_morse 5000 |
注意:
- 容器有自己的内部网络和 ip 地址(使用
docker inspect
可以获取所有的变量,Docker 还可以有一个可变的网络配置。) -p
标记可以多次使用来绑定多个端口
例如
1 | $ docker run -d \ |
或者
1 | $ docker container run -p 8000:3000 -it koa-demo /bin/bash |