共计 14587 个字符,预计需要花费 37 分钟才能阅读完成。
Docker 使用 Go 语言开发,基于 Linux 内核的 cgroup、namespace 以及 AUFS 等技术对进程进行封装隔离,是一种操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。
Docker 则使用宿主机内核提供的隔离机制创建沙盒环境,容器内的应用进程直接运行于宿主的内核。因为容器内没有虚拟硬件和内核,容器在启动时间、执行效率、内存占用以及镜像大小等方面相对于传统虚拟机都拥有很大优势。
Docker 容器将程序及其运行环境打包在一起,镜像创建后可以在任何安装了 Docker 的系统上运行,无需配置运行环境,加之较小的镜像体积极大方便了协作开发和部署。
使用 Dockerfile 将镜像构建过程透明化,也便于开发和运维人员理解程序的运行环境。
Docker 相对于虚拟机的优势来源于它运行与宿主内核而减少了开销,这使得 Docker 不能虚拟不同的内核环境。也就是说我们可以很容易地在 Windows 操作系统上启动一个 Linux 虚拟机,但是在 Windows 上启动一个基于 Linux 的 Docker 容器则是很困难的事情。
docker 官方已经发布了 docker for mac
及docker for windows
。目前 docker for mac
使用 MAC OS 内核提供的 HyperKit
虚拟化技术代替了 docker-toolbox 采用的使用 Linux 虚拟机提供支持的方式。
What’s Docker
cgroup 和 namespace 是 Linux 内核提供的两种隔离机制,是 Docker 虚拟化的技术基础:
- cgroup: 全名 Control Groups, Linux 内核提供的用于监控和管理进程组占用资源的机制。这里的资源包括 CPU,内存和 IO 等硬件资源。
- namespace: 为某个进程提供独立的空间,包括独立的:
- 进程树:进程拥有独立的 init 进程及其下进程树
- 文件系统:进程拥有独立的根目录
/
及其下目录树 - 用户: 进程可以定义自己的用户,组和权限系统
- 协议栈: 进程可以拥有独立的 ip 地址及 tcp/udp 端口空间
- 其它
在了解隔离机制之后我们可以了解 Docker 中的两个核心概念:
- 容器:容器的本质是进程,它拥有独立的命名空间。因此容器表现很像一个虚拟操作系统,拥有自己的进程树,文件系统等。
- 镜像:镜像是容器运行依赖的文件系统,就像每个 Linux 操作系统时都需要挂载 root 文件系统
/
,镜像就是容器的 root 文件系统。
Docker 采用服务端 / 客户端架构:
- 守护进程(dockerd): Docker 服务端每个 dockerd 下可以运行多个容器,此外还提供了镜像和容器管理的功能。
- 客户端: 通过 API 与 dockerd 通信进行操作,官方提供了命令行客户端以及 Go 和 Python 语言的 SDK
- 宿主机:用于运行 dockerd 及其容器的操作系统环境
- Registry:Docker 镜像存储中心,用于管理和共享 docker 镜像。官方存储中心 DockerHub 中提供了大量官方和第三方镜像。
Docker 采用 UnionFS 技术将镜像设计为分层结构,即一个镜像分为多层,每一层在上一层的基础上构建(即存储增量)。在容器中只能看到所有层叠加后的结果,隐藏了分层的结构。因为镜像层会被其它层依赖,为了保证下层能正常工作,镜像层在创建后就无法进行修改。
Get Started
Docker 目前分为免费的社区版(CE)和付费的商业版(EE)两种, 这里我们选用社区版。Docker 官网上提供了各种常用操作系统的安装说明:
- MAC
- Ubuntu
- Centos
- Debian
- Windows
下面看一个简单的示例:
finley@mbp:$ uname
Darwin
finley@mbp:$ docker run -it Ubuntu
root@528ab91753d6:/# uname
Linux
在执行 docker run
命令后发现我们已经从宿主机 Mac 的终端进入到了 Linux 终端中。这个运行中的 ”Linux” 就是容器,启动这个虚拟的 Linux 环境所需的文件即是镜像。
上面的示例中我们使用 docker 代替了 ubuntu 虚拟机,对比之下 docker 在镜像大小,启动时间和运行内存占用方面都具有巨大的优势。
因为启动 docker 容器的开销和启动相应进程的开销基本相同,因此完全可以使用 docker 代替原生进程,避免复杂的编译安装配置过程。
$ docker run -p 6379:6379 -d redis
3a5748eef653
$ redis-cli
127.0.0.1:6379> keys *
(empty list or set)
这个示例中我们一键安装并启动了 redis-server。
在终端中输入 docker
命令则会显示所有命令和使用帮助, 在 docker 命令后添加 --help
选项可以查看该命令的帮助信息,如 docker run --help
可以查看 run 命令的帮助。
镜像
本节将简单介绍如何搜索和管理镜像,为介绍容器做准备。更多关于镜像的构建和共享的内容将在下文中介绍。
docker images
docker images
命令用于显示本地所有镜像:
REPOSITORY | TAG | IMAGE ID | CREATED | SIZE |
---|---|---|---|---|
ubuntu | latest | 00fd29ccc6f1 | 3 weeks ago | 111MB |
redis | latest | 1e70071f4af4 | 4 weeks ago | 107MB |
和其它软件一样 docker 镜像也可以演进出不同版本,tag 用于标识镜像的版本。
repository 代表同一镜像多个版本的集合, 它的值是一个 URI 用于全局唯一标识一组镜像,如 ”registry.cn-hangzhou.aliyuncs.com/acs/agent”。
对于 DockerHub 中的镜像则会省略仓库的地址,诸如 dorowu/ubuntu-desktop-lxde-vnc
和ubuntu
就是 DockerHub 中的镜像。
由此可见,repository
和 tag
可以唯一标识 docker 镜像。
除此之外每个镜像还拥有一个摘要 (DIGEST),docker images --digest
可以显示镜像的摘要。
docker search
DockerHub 是 docker 官方提供的公有仓库,docker search
命令用于根据关键字搜索 DockerHub 中的镜像:
format: docker search TERM
demo: docker search ubuntu
NAME | DESCRIPTION | STARS | OFFICIAL | AUTOMATED |
---|---|---|---|---|
ubuntu | Ubuntu is a … | 7076 | [OK] | |
dorowu/ubuntu-desktop-lxde-vnc | Ubuntu with openssh-server and NoVNC | 156 | [OK] |
docker pull
docker pull
命令用于从远程下载镜像,可以通过 NAME:TAG
或NAME@DIGEST
的格式来指明目标镜像。
当只提供了镜像 NAME 时,默认下载 tag 为 latest
的镜像。
$docker pull ubuntu
$docker pull ubuntu:16.04
$docker pull ubuntu@sha256:fbaf303d18563e57a3c1a0005356ad102509b60884f3aa89ef9a90c0ea5d1212
NAME 也可以是私有仓库中一个 REPOSITORY 的 URI。
docker rmi
docker rmi
用于删除镜像,可以使用 IMAGE ID
或REPOSITORY:TAG
来标记一个容器。
容器
docker run
docker run
命令用于新建一个容器并启动,是最重要的和最常用的 docker 命令之一。
format: docker run IMAGE CMD ARGS
docker run
命令的标准执行流程包括:
- 检查本地是否包含指定的镜像,若不存在就从公有仓库下载
- 在只读的基础镜像层上挂载一个可读写层,创建容器的文件系统
- 根据文件系统启动容器
- 将容器与宿主机桥接
- 用指定的身份登录容器,并在指定目录下执行
CMD ARGS
参数指定的命令 - 在命令执行完成后关闭容器
docker 容器在命令执行完毕后会自动退出,容器的生存周期仅决定于执行命令所需的时间。如果在容器中执行 bash
等长期运行的命令,就可以保证容器长期运行。
docker run
命令默认会把标准输出流 (stdout) 重定向到终端,并与容器保持连接状态(attach)。
在 attach 状态下,容器退出之前 doceker run
命令不会返回,而是在终端回显容器的输出。若发出 kill
信号 (如ctrl + c
快捷键)杀死docekr run
, 那么容器也会提前退出。
容器对文件系统的修改在可读写层,不会对镜像产生影响,除非使用 docker commit
创建新的镜像层。容器退出后其文件系统仍将保存在磁盘中,下次启动后会保留所有修改。
打开终端
docker run
命令默认将容器的标准输出流重定向到终端,但是没有将终端的标准输入流 (stdin) 重定向到容器。也就是说,容器无法���收我们在终端中输入的命令。
使用 -i
或--interactive
选项会保持容器的输入流 (stdin) 打开,即使 docker run
不与容器保持 attach 状态。
docker run -i ubuntu bash
命令可以打开一个 ubuntu 终端, 该终端也可以接受我们输入的指令。
和标准的 Linux 系统一样,docker 镜像也为用户指定了默认终端。使用 -t
或--tty
选项会打开一个虚拟终端(Pseudo-TTY)。
也就是说,docker run -it ubuntu
命令可以轻松地打开一个可交互 ubuntu 虚拟环境。
后台运行
docker run
命令默认与容器保持连接状态 (attach), -d
或--detach
选项可以与容器断开连接。docker run
命令在显示容器 ID 后立即返回,容器则会在后台运行。
上文 redis-server 的示例即使用了 -d
选项,docker run
立即返回,redis-server 在后台继续运行。
$ docker run -p 6379:6379 -d redis
3a5748eef653
$ redis-cli
127.0.0.1:6379>
端口映射
如上文中 redis-server 示例,我们经常使用 docker 容器提供服务,因此需要 docker 容器监听宿主机的某个端口。
docker run -p 6379:6379 -d redis
将对宿主机 TCP6379 端口的访问映射到容器的 TCP6379 端口。
-p 6379:6379/udp
则可以映射 udp 访问 (虽然对 redis-server 来说没有意义)。多个-p
选项可以映射多个端口docker run -p 80:8080 -p 8080:8081 -d my_server
.
端口映射是将对宿主机某个端口的访问映射到容器的某个端口上,容器访问宿主机端口不需要配置端口映射。
挂载数据卷
-v
选项可以将宿主机上某个目录挂载到容器中的某个目录
$ ls ~/myvol
history.txt
$ docker run -it -v ~/myvol:/app ubuntu
root@e690c508219e:/# ls /app
history.txt
上述指令将宿主机目录 ~/myvol
挂载到镜像的 /app
目录下,/app
目录下原来的内容会被隐藏而是显示宿主机目录 ~/myvol
下的内容。
这种方式我们称为在容器上挂载了数据卷,对数据卷的读写独立于容器之外:
- 容器对数据卷的修改将立即存储到数据卷所在的 (即宿主机的文件系统) 上
- 除非指明删除数据卷,否则容器删除不会对数据卷产生影响
- 其它进程对数据卷的修改将立即生效
若数据卷 ~/myvol
或挂载点 /app
不存在的时候,docker 会自动创建空目录。
docker 提供了独立于容器的数据卷管理功能,参考 docker volume。
为容器命名
每个容器都拥有一个唯一的 CONTAINER ID
来标识,但 ID 不便于记忆和使用。因此在 docker run
创建容器时可以使用 --name
选项来为容器指定一个名称。
在某个 dockerd 中容器名称是唯一的,我们可以使用容器名来唯一指定容器。
示例:docker run --name my_ubuntu -it ubuntu
退出时自动删除
docker run --rm
选项会在容器退出时自动删除容器。使用该命令时需谨慎,容器一旦删除便不可恢复。
自定义工作目录
docker run -w PATH
选项会在启动容器时,使用 PATH 参数指定的路径作为工作目录。
docker create
docker create
命令与 docker run
指令极为相似,区别在于 docker run
创建容器后自动启动容器,而 docker create
不自动启动容器需要使用 docker start
命令来启动。
docker ps
docker ps
命令用于显示容器的信息,默认情况下显示运行中的容器:
finley@mbp $ docker ps
CONTAINER ID | IMAGE | COMMAND | CREATED | STATUS | PORTS | NAMES |
---|---|---|---|---|---|---|
3a5748eef653 | redis | “docker-entrypoint…” | 3 hours ago | Up 3 hours | 0.0.0.0:6379->6379/tcp | redis-server |
c10921921bfb | ubuntu | “/bin/bash” | 3 hours ago | Up 52 seconds | my_ubuntu |
-a
选项可以显示包括已停止容器在内的所有容器信息。
docker start
docker start
命令用于启动一个已停止的容器,默认情况下不与容器连接 (attach) 也不将输入重定向到容器。
$ docker run --name redis-server -p 6379:6379 redis
$ docker stop redis-server # 此时已经存在一个名为 redis-server 的已停止容器
$ docker start redis-server
redis-server
$ redis-cli
127.0.0.1:6379>
若使用 -a
或--attach
选项将 docker start
与容器连接(attach), 终端将回显容器输出。
-i
或 --interactive
选项则会将输入重定向到容器。
$ docker run --name my_ubuntu -it ubuntu
root@c10921921bfb # exit
# 此时已经存在一个名为 my_ubuntu 的已停止容器
$ docker start -ai my_ubuntu
root@c10921921bfb:/#
docker exec
docker exec
用于让一个正在运行的容器执行命令,命令执行完成后 docker exec
将返回容器继续运行。
$ docker run --name my_ubuntu -d ubuntu
$ docker exec my_ubuntu ls
home bin ...
默认情况下 docker exec
与容器连接,-d
或 --detach
选项可以不与容器连接而在后台执行命令。
与 docker run
命令类似,-i
选项用于将标准输入重定向到容器以便接收用户输入,-t
选项可以打开终端。
$docker exec -it my_ubuntu bash
root@c10921921bfb:/#
docker attach
docker attach
命令用于与容器连接,即将容器输出流重定向到终端,终端输入流重定向到容器。
$ docker attach my_ubuntu
# 再按一次回车
root@c10921921bfb:/#
当容器没有输出时终端中没有回显,可能令用户误以为卡死。attach 之后再次输入回车,bash 将回显命令行提示符。
attach 状态下 ctrl + c
快捷键会发送 SIGKILL
信号中止容器,而 ctrl + p, ctrl + q
快捷键会退出 attach 容器继续运行。
docker stop
docker stop
用于终止容器的运行
$docker stop redis-server
docker stop
命令会先发送 SIGTERM
信号要求容器中的进程执行退出操作,若达到超时时间 (默认 10s) 容器仍未退出则会发送 SIGKILL
信号强制退出。
-t
或 -time
选项可以秒为单位设置强制杀死之前的等待时间:
$docker stop -t 20 redis-server
docker kill
docker kill
命令将直接向容器发送 SIGKILL
命令停止容器:
$docker kill redis-server
-s
或 --signal
选项可以向容器发送指定的信号:
docker kill -s SIGINT my_ubuntu
docker cp
docker cp
命令负责在运行的容器和宿主机之间复制文件:
# format: docker cp FROM TO
$ docker cp test.txt my_ubuntu:/root/test.txt
$ docker cp my_ubuntu:/root/test.txt test.txt
docker rm
docker rm
用于删除一个镜像,通过镜像 ID 或镜像名来指定要删除的镜像, 默认情况下只能删除已退出的镜像:
$ docker stop my_ubuntu
$ docker rm my_ubuntu
-f
或 --force
选项可以强制删除运行中的镜像。
-v
或 --volumes
选项将删除所有挂载的数据卷。
docker volume
docker volume
系列指令用于独立的管理数据卷, 请先阅读 docker run: 挂载数据卷
create
将宿主机上一个目录创建为数据卷:
# format: docker volume create PATH
$ docker volume create myvol
ls
查看所有数据卷:
docker volume ls
DRIVER VOLUME NAME
local 0c28b79a9b3f
local myvol
inspect
查看某个数据卷的详细信息:
docker volume inspect myvol
[
{"CreatedAt": "2018-01-16T09:04:16Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/myvol/_data",
"Name": "myvol",
"Options": {},
"Scope": "local"
}
]
rm
删除某个数据卷:
docker volume remove myvol
myvol
prune
删除所有未被使用的数据卷:
docker volume prune
WARNING! This will remove all volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Total reclaimed space: 0B
使用数据卷
docker run
和 docker create
命令可以使用 -v
或--volume
选项来使用数据卷:
docker run -d -it -v myvol:/app ubuntu
docker 会优先寻找数据卷列表中的 myvol 而不是当前目录下的 myvol 子目录。
若找不到 myvol 数据卷且当前目录下也不存在 myvol 子目录,docker 会自动创建 myvol 数据卷不会再当前目录下创建子目录。
--mount
选项虽然语法复杂,但是可以配置更多选项:
docker run -it --mount source=my_volume,target=/app ubuntu
构建镜像
上文中已经介绍了如何获取和使用已有镜像,接下来介绍如何构建自己的镜像。
我们可以将自己的程序及其运行环境打包成 Docker 容器,部署到服务器或者共享给其它开发者免去配置环境的烦恼。
docker diff
前文已经提到过 Docker 镜像采用分层结构,容器运行时无法修改镜像的内容,而是在镜像层上挂载了一个可读写层。
docker diff
命令可以查看容器对镜像的修改:
$ docker run --name my_ubuntu -it ubuntu
# if exists: docker start -ai my_ubuntu
root@c10921921bfb:~# echo "Hello, from finley" > hello.txt
root@c10921921bfb:~# exit
➜ ~ docker diff my_ubuntu
C /root
A /root/.bash_history
A /root/hello.txt
我们打开一个 ubuntu 容器在 /root
目录中创建了 hello.txt
文件,并在其中写入 ”Hello, from finley”。
通过 docker diff
可以看出这个操作产生了三个影响:
- 工作目录修改为
/root
, C 代表变更工作目录 - 命令历史
.bash_history
文件改变, A 代表文件或目录内容发生改变 - 修改了文件
hello.txt
docker commit
docker commit
命令根据容器对镜像的修改创建新的镜像层
# format: docker commit CONTAINER REPOSITORY[:TAG]
$docker commit my_ubuntu my_ubuntu:2018_01_14
sha256:8096f47d8d6b80e52e617030938c7a83a9d50bafd73915d6952675e7126bb38a
$docker images
REPOSITORY | TAG | IMAGE ID | CREATED | SIZE |
---|---|---|---|---|
my_ubuntu | 2018_01_14 | 8096f47d8d6b | Less than a second ago | 111MB |
-a
或 --author
选项可以指定容器的作者,-m
或 --message
可以添加备注信息:
$docker commit \
-a "finley<finley@finley.pw>" \
-m "say hello" \
my_ubuntu my_ubuntu:2018_01_14
-c
或 --change
选项可以添加一系列 Dockerfile 指令,关于 Dockerfile 的内容我们将在下文介绍。
docker tag
docker tag
命令用于为镜像创建一个别名。
# format: docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
$ docker tag ubuntu my_ubuntu
TARGET_IMAGE 可以是私有仓库 REPOSITORY 的 URI,tag 命令经常被用来协助将镜像推送到私有仓库。
docker history
docker history
命令用于显示镜像各层的信息,即查看 commit 历史:
$ docker history ubuntu
Dockerfile
docker commit
命令虽然可以很方便的创建新的镜像,但是我们在容器内操作 (特别是尝试性的操作) 可能会在新镜像内产生无关的内容,如命令历史和日志等。
Dockerfile 是控制镜像构建过程的脚本,使用 Dockerfile 可以有效避免镜像中包含无关内容。
Dockerfile 中包含多行指令,每个指令会在镜像中创建一层。
FROM nginx
RUN echo '<h1>Hello from finley!</h1>' > /usr/share/nginx/html/index.html
$ docker build -t nginx_hello .
Step 1/2 : FROM nginx
---> 3f8a4339aadd
Step 2/2 : RUN echo '<h1>Hello from finley!</h1>' > /usr/share/nginx/html/index.html
---> Running in 2b3c5df09f9c
---> a918263d0f2f
Removing intermediate container 2b3c5df09f9c
Successfully built a918263d0f2f
Successfully tagged nginx_hello:latest
$ docker run --name nginx_hello -p 80:80 -d --rm nginx_hello
$ curl localhost
<h1>Hello from finley!</h1>
上面示例中我们以 nginx 为基础构建了一个新镜像,并启动它提供服务。
在具体介绍 Dockerfile 的指令之前,我们先介绍一下 docker build
命令。
docker build
指令用于根据 Dockerfile 构建镜像,通常该指令需要一个 PATH 参数来指定某个目录做为构建上下文(context)。
-f
或 --file
选项用于在构建上下文指定 Dockerfile 文件的路径,默认为PATH/Dockerfile
。
-t
或 --tag
选项用于为镜像指定标签,默认情况下名称仍然与基础镜像相同,而 -t NAME:TAG
则会指定容器的名称。
除了使用一个目录作为构建上下文之外,也可以使用 tar 压缩包、git 仓库作为上下文,甚至从标准输入中读取 Dockerfile 或 tar 进行构建。
接下来介绍常用的 Dockerfile 命令:
FROM
FROM
指令用于指定构建容器的基础镜像,标记镜像的语法与 docker pull
命令相同。
除了使用已存在的镜像作为基础镜像之外还有一个特殊的镜像scratch
, 它是一个空镜像。
我们可以把静态编译的可执行文件放入空白镜像中,由内核直接执行可以极大的降低镜像的体积。
RUN
RUN
命令在镜像中创建一个容器并执行指定指令,执行结束后 commit 修改作为镜像的一层。
上文示例中的 Step2 展示了 RUN
指令运行的过程:
- 创建一个中间容器(intermediate container): 2b3c5df09f9c
- 运行命令
echo '<h1>Hello from finley!</h1>' > /usr/share/nginx/html/index.html
- 将修改提交,产生新的容器: a918263d0f2f
- 删除中间容器:2b3c5df09f9c
RUN
命令有两种参数格式:
- 命令行式:
RUN ls -al
- 函数调用式:
RUN ["ls", "-al"]
在实际执行过程中命令行式指令会被映射为RUN ["sh", "-c", "ls", "-al"]
。
因为每个 RUN
指令都会生成一层镜像,因此最好用 &&
将多条指令连接而不是写多条 RUN
指令。
COPY
COPY from to
指令将文件或目录从构建上下文 (context) 将文件复制到镜像内部。
COPY ./config.json /root/config.json
WORKDIR
WORKDIR path
命令用于指定容器的默认工作目录。
WORKDIR
命令对 Dockerfile 中的后续命令都有影响,除非有另一条 WORKDIR
命令修改了工作目录
上文已经介绍过每条 RUN
指令都会创建一个临时容器,因此 RUN cd PATH &&...
只对同一条 RUN
中的后续指令有效。
USER
USER
命令用于指定容器中的当前用户:
RUN groupadd -r redis && useradd -r -g redis redis
USER redis
RUN redis-server
和 WORKDIR
命令一样,USER
指令直到下一条 USER
指令之前始终有效。
CMD
CMD
命令用于指定启动容器的指令, 和 RUN
命令一样有两种格式。
EXPOSE
EXPOSE
命令用于声明需要暴露哪些接口,注意 EXPOSE
命令没有建立端口映射,需要在创建容器时启动端口映射。
ENV
ENV
命令用于为容器设置环境变量:
ENV DEBUG=on VERSION='1.0'
ENTRYPOINT
ENTRYPOINT
指令和 CMD 一样,用于指定启动容器的指令。当指定了 ENTRYPOINT 之后,CMD 命令的内容将被作为参数传递给 ENTRYPOINT 指定的指令。
首先创建一个容器:
FROM ubuntu
CMD ls
$ docker build -t ls:v1 .
$ docker run --rm ls:v1
bin boot dev etc home lib ...
如果我们试图传递 -al
选项给 ls 以显示更详细的信息:
$ docker docker run --rm ls -al
container_linux.go:265: starting container process caused "exec: \"-al\": executable file not found in $PATH"
根据 docker run
的语法我们试图让 ls
镜像执行 -al
命令代替默认命令,这当然行不通。
用 ENTRYPOINT 代替 CMD:
FROM ubuntu
ENTRYPOINT ["ls"]
重新创建:
$ docker build -t ls:v2 .
$ docker run --rm ls:v2 -al
total 72
drwxr-xr-x 1 root root 4096 Jan 14 13:29 .
drwxr-xr-x 1 root root 4096 Jan 14 13:29 ..
-rwxr-xr-x 1 root root 0 Jan 14 13:29 .dockerenv
drwxr-xr-x 2 root root 4096 Dec 1 21:53 bin
drwxr-xr-x 2 root root 4096 Apr 12 2016 boot
drwxr-xr-x 5 root root 340 Jan 14 13:29 dev
ENTRYPOINT 通常用于在执行容器 CMD 做一些准备工作,比如官方 redis 镜像中:
FROM alpine:3.4
...
RUN addgroup -S redis && adduser -S -G redis redis
...
ENTRYPOINT ["docker-entrypoint.sh"]
docker run --entrypoint CMD
可以用来更改容器的 ENTRYPOINT。
共享镜像
现在我们已经了解如何构造自己的镜像,接下来的问题是如何将镜像分享给其它开发者或者部署到服务器。
docker export
docker export
命令用于导出容器的快照, 默认输出到标准输出流,需要将输出重定向到文件进行保存。
# format: docker export CONTAINER > TAR
$ docker export my_ubuntu > my_ubuntu.tar
或者使用 -o
或--output
选项
$ docker export -o my_ubuntu.tar my_ubuntu
docker export
命令导出时会新建一个空白镜像然后将容器文件系统的内容写入,不包含容器基础镜像各层和 tag 等信息。
docker save
docker save
用于将镜像存储为 tar 压缩包,默认导出到标准输出流需要重定向以写入文件
# format: docker save IMAGE > TAR
$ docker save ubuntu > ubuntu.tar
或者使用 -o
或--output
选项
$ docker save -o ubuntu.tar ubuntu
docker save
命令会将镜像各层及其 tag 信息导出到文件。
docker import
docker import
命令用于导入 tar 格式的快照,生成的镜像只有一层不导入各层和 tag 信息。
$ docker import my_ubuntu.tar my_ubuntu:v2
该指令与 docker export
相对用于导入容器镜像,但也可以导入 docker save
生成的 tar 文件。
docker load
docker load
用于导入 tar 格式的镜像副本,导入时保留各层和 tag 等元数据,因此不需要指定镜像名和 tag。
默认从标准输入流导入:
$ cat ubuntu.tar | docker load
或者使用 -i
或--input
选项:
docker load -i ubuntu.tar
docker load
命令与 docker save
命令相对,因为缺少元数据不能导入 docker export
生成的 tar 文件。
Registry
虽然 docker 支持以文件的形式导入导出镜像,但这种方式对于共享镜像来说仍十分不便。
Docker 官方提供了一个 registry 镜像,我们可以使用它轻松搭建私有仓库。
$ mkdir registry
$ docker run -d \
-p 5000:5000 \
-v registry:/var/lib/registry \
registry
-v
选项将 ./registry
目录挂载到了容器中,这个目录将用来实际存储镜像。
docker 默认采用 HTTPS 方式推送和拉取镜像,本文不再介绍如何为私有仓库配置 HTTPS 证书。
私有仓库可以配置权限认证,仅授权用户才能推送或拉取镜像,这里也不再详细介绍权限认证相关功能。
docker push
docker push
命令用于将镜像推送到仓库,推送到的仓库由镜像的 REPOSITORY 属性决定。
$ docker tag ubuntu 127.0.0.1:5000/finley/my_ubuntu:v1
$ docker docker push 127.0.0.1:5000/finley/my_ubuntu:v1
The push refers to a repository [127.0.0.1:5000/finley/my_ubuntu]
f17fc24fb8d0: Mounted from registry/my_ubuntu
6458f770d435: Mounted from registry/my_ubuntu
5a876f8f1a3d: Mounted from registry/my_ubuntu
d2f8c05d353b: Mounted from registry/my_ubuntu
48e0baf45d4d: Mounted from registry/my_ubuntu
v1: digest: sha256:f871d0805ee3ce1c52b0608108dbdf1b447a34d22d5c7278a3a9dd78fc12c663 size: 1357
$ curl 127.0.0.1:5000/v2/_catalog
{"repositories":["registry/my_ubuntu"]}
首先,使用 docker tag
命令给想要推送的镜像 unbuntu:latest
创建一个别名127.0.0.1:5000/registry/my_ubuntu:v1
。
在这个 URI 中,127.0.0.1:5000
是 Registry 的地址,finley
是私有仓库中的一个命名空间,my_ubuntu
是私有仓库中的一个 REPOSITORY。
访问 127.0.0.1:5000/v2/_catalog
来查看私有仓库中的镜像。
更多 Docker 相关教程见以下内容:
Docker 安装应用(CentOS 6.5_x64) http://www.linuxidc.com/Linux/2014-07/104595.htm
Ubuntu 16.04 服务器上配置使用 Docker http://www.linuxidc.com/Linux/2017-06/145176.htm
Ubuntu 15.04 下安装 Docker http://www.linuxidc.com/Linux/2015-07/120444.htm
Docker 安装实例 http://www.linuxidc.com/Linux/2017-04/142666.htm
Docker 创建基础镜像 http://www.linuxidc.com/Linux/2017-05/144112.htm
在 Ubuntu 15.04 上如何安装 Docker 及基本用法 http://www.linuxidc.com/Linux/2015-09/122885.htm
Ubuntu 16.04 上 Docker 使用手记 http://www.linuxidc.com/Linux/2016-12/138490.htm
使用 Docker 分分钟启动常用应用 http://www.linuxidc.com/Linux/2017-04/142649.htm
Ubuntu 16.04 下 Docker 修改配置文件不生效解决办法 http://www.linuxidc.com/Linux/2017-05/143862.htm
Docker 的详细介绍:请点这里
Docker 的下载地址:请点这里
本文永久更新链接地址:http://www.linuxidc.com/Linux/2018-01/150348.htm