Docker 学习与实践
文章目录
- Docker 学习与实践
- Docker基本概念
- Docker 镜像
- Docker 容器
- Docker Registry
- Docker Registry 公开服务
- Docker Registry 私有服务
- Docker 镜像使用
- 获取镜像
- 列出镜像
- 删除本地镜像
- Dockerfile 定制镜像
- FROM
- RUN
- CMD
- LABEL
- EXPOSE
- ENV
- ADD
- COPY
- ENTRYPOINT
- USER
- WORKDIR
- ARG
- 总结
Docker 学习与实践
Docker基本概念
Docker是一个新的容器化的技术,它轻巧,且易移植;
Docker 包括三个基本概念:
镜像(Image )
容器(Container )
仓库(Repository )
理解了这三个概念,就理解了 Docker 的整个生命周期。
Docker 镜像
Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)
Docker 容器
镜像(Image ) 和容器(Container ) 的关系,就像是面向对象程序设计中的 类 和 实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等
Docker Registry
镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。
一个 Docker Registry 中可以包含多个仓库(Repository ) ;每个仓库可以包含多个标签(Tag ) ;每个标签对应一个镜像。
通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。
我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。
Docker Registry 公开服务
Docker Registry 公开服务是开放给用户使用、允许用户管理镜像的 Registry 服务,最常使用的 Registry 公开服务是官方的 Docker Hub,这也是默认的 Registry
Docker Registry 私有服务
docker-registry 是官方提供的工具,可以用于构建私有的镜像仓库
http://dockerhub.***.com
Docker 镜像使用
获取镜像
从 Docker 镜像仓库获取镜像的命令是 docker pull 。
其命令格式为:
docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
镜像名称的格式。
Docker 镜像仓库地址:地址的格式一般是 <域名/IP>[:端口号] 。默认地址是 Docker Hub。
仓库名:如之前所说,这里的仓库名是两段式名称,即 <用户名>/<软件名> 。对于 Docker Hub,如果不给出用户名,则默认为 library ,也就是官方镜像
比如:
$ docker pull ubuntu:16.04
16.04: Pulling from library/ubuntu
bf5d46315322: Pull complete
9f13e0ac480c: Pull complete
e8988b5b3097: Pull complete
40af181810e7: Pull complete
e6f7c7e5c03e: Pull complete
Digest: sha256:147913621d9cdea08853f6ba9116c2e27a3ceffecf3b492983ae97c3d643fbbe
Status: Downloaded newer image for ubuntu:16.04
上面的命令中没有给出 Docker 镜像仓库地址,因此将会从 Docker Hub 获取镜像。而镜像名称是 ubuntu:16.04 ,因此将会获取官方镜像 library/ubuntu 仓库中标签16.04 的镜像。
列出镜像
要想列出已经下载下来的镜像,可以使用 docker image ls 命令。
$ docker image ls
列表包含了 仓库名 、 标签 、 镜像 ID 、创建时间 以及 所占用的空间镜像
ID则是镜像的唯一标识,一个镜像可以对应多个标签
删除本地镜像
如果要删除本地的镜像,可以使用 docker image rm 命令
其格式为:
$ docker image rm [选项] <镜像1> [<镜像2> …]
Dockerfile 定制镜像
每个镜像都由很多层次构成,Docker 使用 Union FS 将这些不同的层结合到一个镜像中去。Dockerfile 是一个文本文件,其内包含了一条条的指令
FROM
1)功能为指定基础镜像,并且必须是第一条指令。
2)如果不以任何镜像为基础(表示一个空白的镜像),那么写法为:FROM scratch:
如果你以 scratch 为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作
为镜像第一层开始存在语法:
FROM <image>
FROM <image>:<tag>
FROM <image>:<digest>
三种写法,其中<tag>和<digest> 是可选项,如果没有选择,那么默认值为latest
RUN
功能为运行指定的命令
RUN命令有两种格式
1. RUN <command>
2. RUN ["executable", "param1", "param2"]
1)第一种后边直接跟shell命令
在linux操作系统上默认 /bin/sh -c
在windows操作系统上默认 cmd /S /C
2)第二种是类似于函数调用。
可将executable理解成为可执行文件,后面就是两个参数。
3)两种写法比对:
RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME
RUN ["/bin/bash", “-c”, “echo hello”]
注意:多行命令不要写多个RUN,原因是Dockerfile中每一个指令都会建立一层.多少个RUN就构建了多少层镜像,会造成镜像的臃肿、多层,不仅仅增加了构件部署的时间,还容易出错。RUN书写时的换行符是
Union FS 是有最大层数限制的,比如 AUFS,曾经是最大不得超过 42 层,现在是不得超过127 层。
CMD
功能为容器启动时要运行的命令
语法有三种写法
- CMD [“executable”,“param1”,“param2”]
- CMD [“param1”,“param2”]
- CMD command param1 param2
第三种比较好理解了,就时shell这种执行方式和写法
第一种和第二种其实都是可执行文件加上参数的形式
举例说明两种写法:
CMD [ "sh", "-c", "echo $HOME" ]
CMD [ "echo", "$HOME" ]
注:这里边包括参数的一定要用双引号,就是",不能是单引号。千万不能写成单引号。
原因是参数传递后,docker解析的是一个JSON array
RUN & CMD
不要把RUN和CMD搞混了。RUN是构件容器时就运行的命令以及提交运行结果
CMD是容器启动时执行的命令,在构件时并不运行,构件时紧紧指定了这个命令到底是个什么样子
LABEL
功能是为镜像指定标签
语法:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
一个Dockerfile种可以有多个LABEL,
EXPOSE
功能为暴漏容器运行时的监听端口给外部,但是EXPOSE并不会使容器访问主机的端口,如果想使得容器与主机的端口有映射关系,必须在容器启动的时候加上 -P参数
ENV
功能为设置环境变量
语法有两种
1. ENV <key> <value>
2. ENV <key>=<value> ...
两者的区别就是第一种是一次设置一个,第二种是一次设置多个
ADD
一个复制命令,把文件复制到镜像中。
如果把虚拟机与容器想象成两台linux服务器的话,那么这个命令就类似于scp,只是scp需要加用户名和密码的权限验证,而ADD不用。
语法如下:
1. ADD <src>... <dest>
2. ADD ["<src>",... "<dest>"]
路径的填写可以是容器内的绝对路径,也可以是相对于工作目录的相对路径
可以是一个本地文件或者是一个本地压缩文件,还可以是一个url
如果把写成一个url,那么ADD就类似于wget命令
如以下写法都是可以的:
ADD test relativeDir/
ADD test /relativeDir
ADD http://example.com/foobar /
尽量不要把写成一个文件夹,如果是一个文件夹了,复制整个目录的内容,包括文件系统元数据
COPY
看这个名字就知道,又是一个复制命令
语法如下:
1. COPY <src>... <dest>
2. COPY ["<src>",... "<dest>"]
COPY与ADD的区别: COPY的只能是本地文件,其他用法一致
ENTRYPOINT
功能是启动时的默认命令
语法如下:
- ENTRYPOINT [“executable”, “param1”, “param2”]
- ENTRYPOINT command param1 param2
第一种就是可执行文件加参数
第二种就是写shell
与CMD比较说明(这俩命令太像了,而且还可以配合使用):
相同点:
1)只能写一条,如果写了多条,那么只有最后一条生效
2)容器启动时才运行,运行时机相同
不同点:
1)ENTRYPOINT不会被运行的command覆盖,而CMD则会被覆盖
2)如果我们在Dockerfile种同时写了ENTRYPOINT和CMD,并且CMD指令不是一个完整的可执行命令,那么CMD指定的内容将会作为ENTRYPOINT的参数
VOLUME
可实现挂载功能,可以将内地文件夹或者其他容器种得文件夹挂在到这个容器种
语法为:
VOLUME ["/data"]
说明:["/data"]可以是一个JsonArray ,也可以是多个值。
所以如下几种写法都是正确的
VOLUME ["/var/log/"]
VOLUME /var/log
VOLUME /var/log /var/db
一般的使用场景为需要持久化存储数据时,容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失。所以当数据需要持久化时用这个命令。
USER
设置启动容器的用户,可以是用户名或UID,所以,只有下面的两种写法是正确的
USER daemo
USER UID
注意:如果设置了容器以daemon用户去运行,那么RUN, CMD 和 ENTRYPOINT 都会以这个用户去运行
WORKDIR
语法:
WORKDIR /path/to/workdir
设置工作目录,对RUN,CMD,ENTRYPOINT,COPY,ADD生效。如果不存在则会创建,也可以设置多次。如:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
pwd执行的结果是/a/b/c
WORKDIR也可以解析环境变量;如:
ENV DIRPATH /path
WORKDIR DIRNAME
RUN pwd
pwd的执行结果是/path/$DIRNAME
ARG
语法:
ARG <name>[=<default value>]
设置变量命令,ARG命令定义了一个变量,在docker build创建镜像的时候,使用 --build-arg =来指定参数
如果用户在build镜像时指定了一个参数没有定义在Dockerfile种,那么将有一个Warning
总结
下一节讲述docker容器的实例实践