Docker学习(一)

Author Avatar
Patrick 7月 20, 2017

Docker 学习(一)

理解 Docker

基本概念:

  • 镜像
  • 容器

镜像

是一个特殊的文件系统,包含了容器运行时的依赖。

镜像是一层层构建的,前一层是后一层的基础。每一层构建完就不会再改变,后一层删除前一层文件的操作会保留文件,只是该文件会标记为已删除。

因为上面所说的特性,镜像是只读的。

容器

容器是镜像的实例,容器运行时在镜像层上创建一个存储层,该存储层会在容器消亡时消亡,该层中的数据也不会保留。

按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。

安装配置

不使用 sudo 命令执行 Docker

因为 Docker 运行时需要特殊权限,所以默认执行命令都必须在前面加上 sudo。

不使用 sudo 命令执行 Docker 方法:把用户放进 docker 用户组里面(等同于赋予它 root 权限)。

1
2
sudo useradd -aG docker $USER  # 还要注销重新登录
sudo service docker restart # 重启服务

基本命令

获取某个容器的信息

1
docker inspect 容器名/容器 ID

查看容器文件改变情况

1
docker diff 容器名/容器 ID

查看容器日志

1
docker logs 容器名/容器 ID

删除容器

1
docker rm 容器名/容器 ID

列出容器

1
2
3
docker ps        # 查看运行中的容器
docker ps -a # 查看所有容器
docker ps -aq # 查看所有容器,只显示容器 ID

删除镜像

1
docker rmi 镜像名/镜像 ID

下载/上传镜像

1
docker pull/push 镜像名[:TAG|@DIGEST]

创建容器

1
docker run

通过 Dockerfile 定制镜像

docker commit 命令可以通过容器产生镜像,但是要重复操作产生多个相同镜像却不方便,此时使用 Dockerfile 能解决这个问题。

Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。

使用 docker build 来构建镜像

格式为:

1
docker build [选项] <上下文路径/URL/->

其中常用到 -t 选项来指定构建出的镜像的名称。

当构建的时候,用户会指定构建镜像上下文的路径,docker build 命令得知这个路径后,会将路径下的所有内容打包,然后上传给 Docker 引擎。这样 Docker 引擎收到这个上下文包后,展开就会获得构建镜像所需的一切文件。

一般新建一个空文件夹并以该文件夹作为上下文路径来构建镜像。

例:

1
docker build -t myimage .

这里的“.“就是上下文路径,表示当前文件夹。

FROM 指定基础镜像

定制镜像一定要以一个镜像为基础,而 FROM 指令就是指定基础镜像,并且这是最基本的指令,并且必须是第一条指令。

RUN 执行命令

  • shell 格式:RUN <命令>
1
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
  • exec 格式:RUN ["可执行文件", "参数1", "参数2"]

注:因为每个 Dockerfile 的指令都会新建一层,而层数多并不是一件有意义的事情,因此应该用 && 连接多个命令在一条 RUN 指令里面执行,并且在每一层构建的最后删除掉无关文件。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
FROM debian:jessie

RUN buildDeps='gcc libc6-dev make' \
&& apt-get update \
&& apt-get install -y $buildDeps \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \
&& mkdir -p /usr/src/redis \
&& tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
&& make -C /usr/src/redis \
&& make -C /usr/src/redis install \
&& rm -rf /var/lib/apt/lists/* \
&& rm redis.tar.gz \
&& rm -r /usr/src/redis \
&& apt-get purge -y --auto-remove $buildDeps

COPY 复制文件

COPY 指令将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置。

格式:

  • COPY <源路径>... <目标路径>
  • COPY ["<源路径1>",... "<目标路径>"]

ADD 更高级的复制文件

ADD 指令和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。

比如 <源路径> 可以是一个 URL。

在 COPY 和 ADD 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD。

CMD 容器启动命令

那么在启动容器的时候,需要指定所运行的程序及参数。CMD 指令就是用于指定默认的容器主进程的启动命令的。

例如 ubuntu 镜像默认的 CMD 就是 /bin/bash

CMD 指令的格式和 RUN 相似,也是两种格式:

  • shell 格式:CMD <命令>
  • exec 格式:CMD ["可执行文件", "参数1", "参数2"...]
  • 参数列表格式:CMD ["参数1", "参数2"...](在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数)

ENTRYPOINT 入口点

格式和 CMD 相同。

ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数,但当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接的运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令。

ENV 设置环境变量

格式有两种:

  • ENV <key> <value>
  • ENV <key1>=<value1> <key2>=<value2>...

环境变量可以在其他的 Dockerfile 指令里面展开。

VOLUME 定义匿名卷

格式为:

  • VOLUME ["<路径1>", "<路径2>"...]
  • VOLUME <路径>

EXPOSE 声明端口

格式为 EXPOSE <端口1> [<端口2>...]

EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。

WORKDIR 指定工作目录

格式为 WORKDIR <工作目录路径>

使用 WORKDIR 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。

USER 指定当前用户

格式:USER <用户名>

USER 指令和 WORKDIR 相似,都是改变环境状态并影响以后的层。WORKDIR 是改变工作目录,USER 则是改变之后层的执行 RUN, CMD 以及 ENTRYPOINT 这类命令的身份。

当然,和 WORKDIR 一样,USER 只是帮助你切换到指定用户而已,这个用户必须是事先建立好的,否则无法切换。

ONBUILD 为他人做嫁衣裳

格式:ONBUILD <其它指令>

ONBUILD 是一个特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。

一般用于维护多个镜像,这样升级只用重新构建镜像即可,而不用修改每个的 Dockerfile

参考教程

Docker——从入门到实践
Docker 开发指南——O’REILLY