打包镜像

1
docker build -t 镜像名  Dockerfile文件的位置

FROM

1
2
3
FROM tomcat 

FROM 指定此docker需要依赖的docker image

RUN

分层执行shell脚本命令

1
2
3
RUN unzip my-shop-web-admin-1.0.0-SNAPSHOT.zip

RUN rm -rf my-shop-web-admin-1.0.0-SNAPSHOT.zip

COPY

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

1
2
3
COPY <源路径>... <目标路径>

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

<源路径> 可以是多个,甚至可以是通配符,

1
COPY hom* /mydir/

<目标路径> 可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用WORKDIR 指令来指定)。目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。

1
COPY ./my-shop-web-admin-1.0.0-SNAPSHOT.zip /usr/local/tomcat/webapps/ROOT

ADD

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

如果 <源路径> 为一个 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,ADD 指令将会自动解压缩这个压缩文件到 <目标路径> 去。

1
ADD  ./myshop.tar.gz    /usr/local/tomcat/webapps/ROOT

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

CMD

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

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

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

在运行时可以指定新的命令来替代镜像设置中的这个默认命令,比如,ubuntu 镜像默认的 CMD/bin/bash,如果我们直接 docker run -it ubuntu 的话,会直接进入 bash。我们也可以在运行时指定运行别的命令,如 docker run -it ubuntu cat /etc/os-release。这就是用 cat /etc/os-release 命令替换了默认的/bin/bash 命令了,输出了系统版本信息。

WORKDIR

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

1
WORKDIR /usr/local/tomcat/webapps/ROOT

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

之前提到一些初学者常犯的错误是把 Dockerfile 等同于 Shell 脚本来书写,这种错误的理解还可能会导致出现下面这样的错误:

1
2
RUN cd /app
RUN echo "hello" > world.txt

如果将这个 Dockerfile 进行构建镜像运行后,会发现找不到 /app/world.txt 文件,或者其内容不是 hello。原因其实很简单,在 Shell 中,连续两行是同一个进程执行环境,因此前一个命令修改的内存状态,会直接影响后一个命令;而在 Dockerfile 中,这两行 RUN 命令的执行环境根本不同,是两个完全不同的容器。这就是对 Dockerfile 构建分层存储的概念不了解所导致的错误。

之前说过每一个 RUN 都是启动一个容器、执行命令、然后提交存储层文件变更。第一层 RUN cd /app 的执行仅仅是当前进程的工作目录变更,一个内存上的变化而已,其结果不会造成任何文件变更。而到第二层的时候,启动的是一个全新的容器,跟第一层的容器更完全没关系,自然不可能继承前一层构建过程中的内存变化。

因此如果需要改变以后各层的工作目录的位置,那么应该使用 WORKDIR 指令。

EXPOSE

格式为 EXPOSE <端口1> [<端口2>...]EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。

要将 EXPOSE 和在运行时使用 -p <宿主端口>:<容器端口> 区分开来。-p,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。

ENV

这个指令很简单,就是设置环境变量而已,无论是后面的其它指令,如 RUN,还是运行时的应用,都可以直接使用这里定义的环境变量。

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

数据卷 (达到负载均衡的效果 )

数据卷是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:

  • 数据卷可以在容器之间共享和重用
  • 数据卷的修改会立马生效
  • 数据卷的更新,不会影响镜像
  • 数据卷 默认会一直存在,即使容器被删除

注意:数据卷 的使用,类似于 Linux 下对目录或文件进行 mount,镜像中的被指定为挂载点的目录中的文件会隐藏掉,能显示看的是挂载的 数据卷。

启动一个挂载数据卷的容器

在用 docker run 命令的时候,使用 –mount 标记来将 数据卷 挂载到容器里。在一次 docker run 中可以挂载多个数据卷。

下面创建一个名为 web 的容器,并加载一个 数据卷 到容器的 /weapp 目录。

1
2
3
4
5
6
7
docker run -p 8081:8080 --name myshop -d -v /usr/local/docker/tomcat/ROOT:/usr/local/tomcat/webapps/ROOT myshop

docker run 启动一个容器
-p(端口映射) 宿主机端口:容器默认端口
--name 容器名字
-d 以守护状态运行在后台运行容器
-v 数据卷路径:挂载的路径

压缩

1
2
3
unzip 压缩包     zip解压缩

tar -czvf 文件名 压缩的文件 gz压缩

Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
FROM tomcat 
RUN echo "hello docker" > index.html
FROM tomcat

WORKDIR /usr/local/tomcat/webapps/ROOT

COPY ./my-shop-web-admin-1.0.0-SNAPSHOT.zip /usr/local/tomcat/webapps/ROOT

RUN unzip my-shop-web-admin-1.0.0-SNAPSHOT.zip

RUN rm -rf my-shop-web-admin-1.0.0-SNAPSHOT.zip

WORKDIR /usr/local/tomcat/