一. 什么是docker 镜像

就是把业务代码,可运行环境进行整体的打包

二. 如何创建docker镜像:

现在docker官方共有仓库里面有大量的镜像,所以最基础的镜像,我们可以在公有仓库直接拉取,因为这些镜像都是原厂维护,可以得到即使的更新和修护。

Dockerfile:

我们如果想去定制这些镜像,我们可以去编写Dockerfile,然后重新bulid,最后把它打包成一个镜像,这种方式是最为推荐的方式包括我们以后去企业当中去实践应用的时候也是推荐这种方式。

Commit :

当然还有另外一种方式,就是通过镜像启动一个容器,然后进行操作,最终通过commit这个命令commit一个镜像,但是不推荐这种方式,虽然说通过commit这个命令像是操作虚拟机的模式,但是容器毕竟是容器,它不是虚拟机,最好还是使用dockerfile创建。

三. 镜像的分层结构

仓库是用来存放镜像的,镜像是用来初始化容器的

rhel>oel> centos ubuntu debian系统

红帽和centos的区别

1.Centos是redhat的克隆版本,是把redhat的源代码拿来编译然然后发行的发行版本。但是基本的命令和使用方法是一样。
2.centos是免费的版本,不向用户提供任何的服务,你么用户在使用工程中出现的各种问题,Centos是不负责任的。而redhat对某些服务是提供收费的,在所提供的服务中出现问题。redhat是负责解决的。
3.CentOS独有的yum命令支持在线升级,可以即时更新系统,不像RedHat那样需要花钱购买支持服务!也就是说redhat的服务是需要收费的,而Centos是完全免费的。
4.CentOS修正了许多RedHat AS的BUG。

Linux-> kernel-> diy->app不容的系统内核都是相同的(版本可能不同)但是文件系统不同

采用分层结构的最大好处是:共享资源

镜像的分层结构图示:

aix docker镜像 docker的镜像_docker


优点:

共享宿主机的kernel

base镜像提供的是最小的Linux发行版,

同一docker主机支持运行多种Linux发行版

aix docker镜像 docker的镜像_Dockerfile_02


Copy-on-Write 可写容器层

正常我们对容器进行写操作都是container这一层,下面都是只读的,但是当我们想修改下面image镜像层的时候,他是会将东西拷贝到container中然后在进行修改。
容器层以下所有镜像层都是只读的docker从上往下依次查找文件容器层保存镜像变化的部分,并不会对镜像本身进行任何修改一个镜像最多127层

四. 镜像的构建

docker commit 构建新镜像三部曲

(1)运行容器
(2)修改容器
(3)将容器保存为新的镜像
缺点:
·效率低、可重复性弱、容易出错
·使用者无法对镜像进行审计,存在安全隐患

创建容器,以ubuntu为例
(1)拉取镜像,创建容器并运行

[root@server1 ~]# docker pull ubuntu.tar  ##添加镜像
[root@server1 ~]# docker images  ##查看拉取的镜像
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
game2048            latest              19299002fdbe        2 years ago         55.5MB
ubuntu              latest              07c86167cdc4        3 years ago         188MB
rhel7               latest              0a3eb3fde7fd        5 years ago      
[root@server1 ~]# docker run -it --name vm2 ubuntu bash      ##创建并运行容器 -it:以交互式方式打开
root@a4aca5fcecc3:/# ls
bin   dev  home  lib64  mnt  proc  run   srv  tmp  var
boot  etc  lib   media  opt  root  sbin  sys  usr
root@a4aca5fcecc3:/# uname -r
3.10.0-862.el7.x86_64       ##与宿主机内核版本一致
root@a4aca5fcecc3:/#     
root@a4aca5fcecc3:/# touch file{1..10}
root@a4aca5fcecc3:/# ls
bin   etc     file2  file5  file8  lib    mnt   root  srv  usr
boot  file1   file3  file6  file9  lib64  opt   run   sys  var
dev   file10  file4  file7  home   media  proc  sbin  tmp
root@a4aca5fcecc3:/# exit
exit
[root@server1 ~]# docker rm vm2     ##删除此容器,此时容器内创建的文件均没有保存
vm2

删除容器vm2,重新用ubuntu镜像创建并运行容器时,之前创建的文件消失,因为上次的操作全部写在容器层,镜像层的内容只读。当上次的容器释放之后,写在容器层的内容也会随之消失。
(2)使用docker commit保存修改后的镜像为新镜像
先修改镜像

[root@server1 ~]# docker run -it --name vm2 ubuntu bash
root@8e0d11ca1b95:/# ls
bin   dev  home  lib64  mnt  proc  run   srv  tmp  var
boot  etc  lib   media  opt  root  sbin  sys  usr
root@8e0d11ca1b95:/# touch file{1..10}
root@8e0d11ca1b95:/# ls
bin   etc     file2  file5  file8  lib    mnt   root  srv  usr
boot  file1   file3  file6  file9  lib64  opt   run   sys  var
dev   file10  file4  file7  home   media  proc  sbin  tmp
root@8e0d11ca1b95:/# exit
exit

使用docker commit保存修改后的镜像为新镜像

[root@server1 ~]# docker commit vm2 ubuntu:v1      ##将此容器重新打包为一个镜像
sha256:593a662c6eedf8afc483f305ff9369ee9c8bddd8c71fca0718178d2895d1ea0d
[root@server1 ~]# docker images
REPOSITORY                      TAG                        IMAGE ID            CREATED             SIZE
ubuntu                          v1                          593a662c6eed        14 seconds ago      188MB
[root@server1 ~]# docker rm vm2      ##删除创建的容器
vm2
[root@server1 ~]# docker run -it --name vm2 ubuntu:v1      ##运行此容器
root@306c2ef91b50:/# ls      ##创建的文件依然存在
bin   etc     file2  file5  file8  lib    mnt   root  srv  usr
boot  file1   file3  file6  file9  lib64  opt   run   sys  var
dev   file10  file4  file7  home   media  proc  sbin  tmp
root@306c2ef91b50:/# exit
exit

使用容器创建镜像。容器就是在镜像层的最上方存在一个可写的容器层。将容器打包镜像,就是将该可写的容器层,变成一个只读的镜像层,和下层的所有镜像层一起作为新镜像的镜像层
(3)查看镜像的构造历史

[root@server1 ~]# docker history ubuntu:v1
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
593a662c6eed        6 minutes ago       /bin/bash                                       29B                 
07c86167cdc4        3 years ago         /bin/sh -c #(nop) CMD ["/bin/bash"]             0B                  
<missing>           3 years ago         /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$…   1.9kB               
<missing>           3 years ago         /bin/sh -c echo '#!/bin/sh' > /usr/sbin/poli…   195kB               
<missing>           3 years ago         /bin/sh -c #(nop) ADD file:b9504126dc5590898…   188MB
docker commit命令参数说明:
-m: 提交的描述信息
-a: 指定镜像作者

使用Dockerfile创建镜像

什么是 Dockerfile?
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。

使用 Dockerfile 定制简单镜像

mkdir docker
cd docker/
vim Dockerfile    #创建一个Dockerfile
FROM ubuntu
RUN touch file{1..10}
docker build -t ubuntu:v1 .    #在 Dockerfile 文件的存放目录下,执行构建动作构建镜像
docker history ubuntu:v1    #查看镜像的分层结构

注:在镜像构建时,由于构建镜像会拉取该目录下的所有数据,所以不要直接在根目录下进行构建

构建镜像的代码中,有提到指令最后一个 .上下文路径(当前路径),那么什么是上下文路径呢?

上下文路径,是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build 命令得知这个路径后,会将路径下的所有内容打包。

解析:由于 docker 的运行模式是 C/S。我们本机是 C,docker 引擎是 S。实际的构建过程是在 docker 引擎下完成的,所以这个时候无法用到我们本机的文件。这就需要把我们本机的指定目录下的文件一起打包提供给 docker 引擎使用。

如果未说明最后一个参数,那么默认上下文路径就是 Dockerfile 所在的位置。

注意:上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成过程缓慢。

Dockerfile中的指令详解

FROM

FROM:定制的镜像都是基于 FROM 的镜像,这里的 nginx 就是定制需要的基础镜像。后续的操作都是基于 nginx。

RUN

RUN:用于执行后面跟着的命令行命令。有以下俩种格式:
shell 格式:

RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的 shell 命令。

exec 格式:

RUN ["可执行文件", "参数1", "参数2"]
# 例如:
# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline

COPY

复制指令,从上下文目录(即Dockerfile所在的目录)中复制文件或者目录到容器里指定路径。
格式:

COPY [--chown=<user>:<group>] <源路径1>...  <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",...  "<目标路径>"]

[–chown=:]:可选参数,用户改变复制到容器内文件的拥有者和属组。
<源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:
COPY hom* /mydir/
COPY hom?.txt /mydir/
<目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。

ADD

ADD 指令和 COPY 的使用格式一致(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:

ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>
ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。

CMD
类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:

CMD 在docker run 时运行。
RUN 是在 docker build。

作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。

注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。

格式:

CMD <shell 命令> 
CMD ["<可执行文件或命令>","<param1>","<param2>",...] 
CMD ["<param1>","<param2>",...]  # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数

推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh。

ENTRYPOINT

类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
但是, 如果运行 docker run 时使用了 --entrypoint 选项,此选项的参数可当作要运行的程序覆盖 ENTRYPOINT 指令指定的程序。

优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。

注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。

格式:

ENTRYPOINT ["<executeable>","<param1>","<param2>",...]

可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。

示例:

假设已通过 Dockerfile 构建了 nginx:test 镜像:

FROM nginx

ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参

不传参运行

docker run  nginx:test

容器内会默认运行以下命令,启动主进程。

nginx -c /etc/nginx/nginx.conf

传参运行

docker run  nginx:test -c /etc/nginx/new.conf

容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)

nginx -c /etc/nginx/new.conf

ENV

设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
格式:

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

以下示例设置 NODE_VERSION = 7.2.0 , 在后续的指令中可以通过 $NODE_VERSION 引用:

ENV NODE_VERSION 7.2.0

RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
  && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"

ARG

构建参数,与 ENV 作用一至。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。

构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。
格式:

ARG <参数名>[=<默认值>]

VOLUME
定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。

作用:
避免重要的数据,因容器重启而丢失,这是非常致命的。
避免容器不断变大。

格式:

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

在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。

EXPOSE
仅仅只是声明端口。

作用:
帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。

格式:

EXPOSE <端口1> [<端口2>...]

WORKDIR
指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。

docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。

格式:

WORKDIR <工作目录路径>

USER
用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。

格式:

USER <用户名>[:<用户组>]

HEALTHCHECK
用于指定某个程序或者指令来监控 docker 容器服务的运行状态。

格式:

HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。

ONBUILD
用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这是执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。

格式:

ONBUILD <其它指令>