一、Docker镜像原理


docker 的镜像实际上由一层一层的文件系统组成,这种层级的文件系统 UnionFS 。


bootfs(boot fifile system) 主要包含 bootloader 和 kernel, bootloader 主要是引导加载 kernel, Linux 刚启


动时会加载 bootfs 文件系统,在 Docker 镜像的最底层是 bootfs 。这一层与我们典型的 Linux/Unix 系统是


一样的,包含 boot 加载器和内核。当 boot 加载完成之后整个内核就都在内存中了,此时内存的使用权已


由 bootfs 转交给内核,此时系统也会卸载 bootfs 。


rootfs (root fifile system) ,在 bootfs 之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标


准目录和文件。 rootfs 就是各种不同的操作系统发行版,比如 Ubuntu , Centos 等等。




dockerfile 安装phalcon dockerfile 安装ossfs_nginx


分层理解

我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层一层的在下载!

dockerfile 安装phalcon dockerfile 安装ossfs_docker_02


为什么 Docker 镜像要采用这种分层的结构呢?


最大的好处,我觉得莫过于是资源共享了!比如有多个镜像都从相同的 Base 镜像构建而来,那么宿主机 只需在磁盘上保留一份base 镜像,同时内存中也只需要加载一份 base 镜像,这样就可以为所有的容器服 务了,而且镜像的每一层都可以被共享。 查看镜像分层的方式可以通过


docker image inspect 命令! 所有的 Docker 镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之 上,创建新的镜像层。



举一个简单的例子,假如基于 Ubuntu Linux 16.04 创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加 Python 包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。 该镜像当前已经包含 3 个镜像层,如下图所示(这只是一个用于演示的很简单的例子)


dockerfile 安装phalcon dockerfile 安装ossfs_docker_03


在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了 一个简单的例子,每个镜像层包含 3 个文件,而镜像包含了来自两个镜像层的 6 个文件


 

dockerfile 安装phalcon dockerfile 安装ossfs_数据_04


上图中的镜像层跟之前图中的略有区别,主要目的是便于展示文件。


下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有 6 个文件,这是因为最上层中的文件 7 是文件 5 的一个更新版本。



dockerfile 安装phalcon dockerfile 安装ossfs_docker_05



这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新 镜像层添加到镜像当中。


Docker 通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统 一的文件系统。


Linux 上可用的存储引擎有 AUFS 、 Overlay2 、 Device Mapper 、 Btrfs 以及 ZFS 。顾名思义,每种存储 引擎都基于 Linux 中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。


Docker 在 Windows 上仅支持 windowsfifilter 一种存储引擎,该引擎基于 NTFS 文件系统之上实现了分 层和 CoW[1] 。


下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图



dockerfile 安装phalcon dockerfile 安装ossfs_nginx_06


 Docker镜像特点


Docker 镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!


这一层就是我们通常说的容器层,容器之下的都叫镜像层!



------------------------------------------------------------------------------------------------------------------------------


二、镜像Commit


docker commit 从容器创建一个新的镜像


#docker commit -m="描述镜像的信息"  -a ="作者"  容器id  要创建的目标镜像名:[标签名]



# 测试-->先从镜像仓库下载一个官方的Tomcat



dockerfile 安装phalcon dockerfile 安装ossfs_nginx_07


 发现Tomcat下的Webapps里面是没有Root的目录的, 所以访问IP:8080 是404页面..

dockerfile 安装phalcon dockerfile 安装ossfs_docker_08

此时我们可以使用exec -it 容器id /bin/bash 进入tomcat容器内部,将webapps.dist里面的文件复制到webapps文件中,使得该文件里有Root, 并且将DOSC删掉.

docker ps # 查看容器
id docker exec -it 容器id /bin/bash /usr/local/tomcat # cd webapps/ 
/usr/local/tomcat/webapps # ls -l # 查看是否存在 docs文件夹 
/usr/local/tomcat/webapps # curl localhost:8080/docs/ # 可以看到 docs 返回的内容
/usr/local/tomcat/webapps # rm -rf docs # 删除它 
/usr/local/tomcat/webapps # curl localhost:8080/docs/ # 再次访问返回404

#提交自制的强化版的Tomcat  , 此时我们的webapps里面已经有Root并且没有DOCS了.

docker commit -a="alenwong" -m="this its no docs tomcat"  tomcatnew:1.1

[root@localhost alenwong]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED          SIZE
tomcat                latest    46cfbf1293b1   43 hours ago     668MB
nginx                 latest    4cdc5dd7eaad   2 weeks ago      133MB
mysql                 5.7       09361feeb475   4 weeks ago      447MB
portainer/portainer   latest    580c0e4e98b0   4 months ago     79.1MB
hello-world           latest    d1165f221234   4 months ago     13.3kB
centos                latest    300e315adb2f   7 months ago     209MB
[root@localhost alenwong]# docker commit -a="alenwong" -m="thisits no docs tomcat" 46cfbf1293b1 tomcatnew:1.1

提交完成后,直接启动新的镜像容器,访问就有页面了。

dockerfile 安装phalcon dockerfile 安装ossfs_nginx_09

 三、数据容器卷


问题:你安装一个 MySQL ,结果你把容器删了,就相当于删库跑路了,这 TM 也太扯了吧!


所以我们希望容器之间有可能可以共享数据, Docker 容器产生的数据,如果不通过 docker commit 生成 新的镜像,使得数据作为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了!这样是行 不通的! 为了能保存数据在Docker 中我们就可以使用卷!让数据挂载到我们本地!这样数据就不会因为容器删除 而丢失了。



卷就是目录或者文件,存在一个或者多个容器中,由 docker 挂载到容器,但不属于联合文件系统,因此 能够绕过 Union File System , 提供一些用于持续存储或共享数据的特性:


卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此 Docker 不会在容器删除时删除其挂 载的数据卷。


特点:


1、数据卷可在容器之间共享或重用数据


2、卷中的更改可以直接生效


3、数据卷中的更改不会包含在镜像的更新中


4、数据卷的生命周期一直持续到没有容器使用它为止


方式一,挂载

docker run -it -v 服务器绝对路径目录:容器内目录 镜像名

这里现在Linux主机创建一个文件夹进行测试

[root@localhost alenwong]# cd /home/
[root@localhost home]# ls 
alenwong
[root@localhost home]# mkdir guazaitest
[root@localhost home]# ll
总用量 4
drwx------. 16 alenwong alenwong 4096 7月  25 11:40 alenwong
drwxr-xr-x.  2 root     root        6 7月  25 13:05 guazaitest   #创建一个挂载测试文件夹

#docker run -it -v 宿主机绝对路径:需要挂载的容器路径   镜像名  操作后台
[root@localhost home]# docker run -it -v /home/guazaitest:/home centos /bin/bash #挂载指令
[root@88145a9d4692 /]# cd /home/
[root@88145a9d4692 home]# touch test2.txt
[root@88145a9d4692 home]# ls
test2.txt

在创建了test2.txt后 到第二个session窗口 看看Linux是否有这个文件?

dockerfile 安装phalcon dockerfile 安装ossfs_数据_10

 挂载成功。可以通过docker insepct 容器id 查看 是否挂载成功: 如下图

dockerfile 安装phalcon dockerfile 安装ossfs_数据_11


测试容器停止退出后,主机修改数据也是会同步!


1. 停止容器


2. 在宿主机上修改文件,增加些内容


3. 启动刚才停止的容器


4. 然后查看对应的文件,发现数据依旧同步! ok


停止了


dockerfile 安装phalcon dockerfile 安装ossfs_数据_12


 修改文件

 

dockerfile 安装phalcon dockerfile 安装ossfs_nginx_13

启动再查看后...

dockerfile 安装phalcon dockerfile 安装ossfs_数据_14

 匿名与具名挂载

# 匿名挂载 
-v 容器内路径
docker run -d -P --name nginx01 -v /etc/nginx nginx

# 匿名挂载的缺点,就是不好维护,通常使用命令 docker volume维护
docker volume ls

# 具名挂载 -v 卷名:/容器内路径 
docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx nginx 

# 查看挂载的路径 
[root@kuangshen ~]# docker volume inspect nginxconfig 
[ 
    { 
        "CreatedAt": "2020-05-13T17:23:00+08:00", 
        "Driver": "local", 
        "Labels": null, 
        "Mountpoint": "/var/lib/docker/volumes/nginxconfig/_data", 
        "Name": "nginxconfig", 
        "Options": null, 
        "Scope": "local" 
                            } ]

# 怎么判断挂载的是卷名而不是本机目录名? 
不是/开始就是卷名,是/开始就是目录名

# 改变文件的读写权限 
# ro: readonly 
# rw: readwrite 
# 指定容器对我们挂载出来的内容的读写权限 
docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx:ro nginx 
docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx:rw nginx

ro = 只读权限
rw = 读写权限

但是用MYSQL的话,只要删除容器,那么数据就会丢失,显然不可行,这里我们进入

方式二、DockerFile方式进行学习


DockerFile 是用来构建 Docker 镜像的构建文件,是由一些列命令和参数构成的脚本


#命令:


docker build -f dockerfile的绝对路径 -t 镜像名称:版本号 .  (注意那个点不要漏了)


[root@localhost docker-test-volume]# pwd
/home/docker-test-volume
[root@localhost docker-test-volume]# vim dockerfile1 
[root@localhost docker-test-volume]# cat dockerfile1 
FROM centos #来自centos基底
VOLUME ["volumn01","VOLUMN02"] #挂载路径
CMD echo "---------------end----------"
CMD /bin/bash


#docker build -f 是dockerfile的绝对路径  -t 是目标镜像名字 : 版本号 即TAG
[root@localhost docker-test-volume]# docker build -f /home/docker-test-volume/dockerfile1  -t alenwong/centos:1.0 .

#执行过程
Sending build context to Docker daemon  2.048kB
Step 1/4 : FROM centos
 ---> 300e315adb2f
Step 2/4 : VOLUME ["volumn01","VOLUMN02"]
 ---> Running in ddcd857cec8b
Removing intermediate container ddcd857cec8b
 ---> 07a38f5a1f62
Step 3/4 : CMD echo "---------------end----------"
 ---> Running in 9589d8def621
Removing intermediate container 9589d8def621
 ---> c856b8b4975f
Step 4/4 : CMD /bin/bash
 ---> Running in d6fc4d6b0cff
Removing intermediate container d6fc4d6b0cff
 ---> 8f2c3218f044
Successfully built 8f2c3218f044
Successfully tagged alenwong/centos:1.0
[root@localhost docker-test-volume]#

创建成功

dockerfile 安装phalcon dockerfile 安装ossfs_docker_15

 如何找到这个容器对应的服务器路径呢?? 我们先找到目前运行中的容器..看看id,然后

docker inspect 这个容器id 就可以找到卷挂载的路径了.

dockerfile 安装phalcon dockerfile 安装ossfs_数据_16

 在Linux卷目录中同步成功

dockerfile 安装phalcon dockerfile 安装ossfs_docker_17

 数据卷容器

--volumes-form

 

dockerfile 安装phalcon dockerfile 安装ossfs_docker_18

 先启动一个父容器

dockerfile 安装phalcon dockerfile 安装ossfs_docker_19

 再创建docker02和03 让他们继承docker01  --volumes-form

[root@localhost docker-test-volume]# docker ps
CONTAINER ID   IMAGE                 COMMAND        CREATED      STATUS       PORTS                                       NAMES
da182c3fdf28   portainer/portainer   "/portainer"   4 days ago   Up 3 hours   0.0.0.0:8088->9000/tcp, :::8088->9000/tcp   distracted_torvalds
[root@localhost docker-test-volume]# clear
[root@localhost docker-test-volume]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED          SIZE
alenwong/centos       1.0       b32442cbdd6c   36 minutes ago   209MB
tomcatnew             1.1       3507faca9348   2 hours ago      670MB
tomcat                latest    46cfbf1293b1   45 hours ago     668MB
nginx                 latest    4cdc5dd7eaad   2 weeks ago      133MB
mysql                 5.7       09361feeb475   4 weeks ago      447MB
portainer/portainer   latest    580c0e4e98b0   4 months ago     79.1MB
hello-world           latest    d1165f221234   4 months ago     13.3kB
centos                latest    300e315adb2f   7 months ago     209MB
[root@localhost docker-test-volume]# docker run -it --name docker01 b32442cbdd6c

#创建docker02
[root@localhost docker-test-volume]# docker run -it --name docker02 --volumes-from docker01 alenwong/centos:1.0
[root@0274106f2c4d /]# [root@localhos

#创建docker03
[root@localhost docker-test-volume]# docker run -it --name docker03 --volumes-from docker01 alenwong/centos:1.0
[root@44ed54af47d2 /]# cd home/ 
#进入容器后,看看挂载的数据卷
[root@44ed54af47d2 /]# ls -l
total 0
lrwxrwxrwx.   1 root root   7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x.   5 root root 360 Jul 25 06:47 dev
drwxr-xr-x.   1 root root  66 Jul 25 06:47 etc
drwxr-xr-x.   2 root root   6 Nov  3  2020 home
lrwxrwxrwx.   1 root root   7 Nov  3  2020 lib -> usr/lib
lrwxrwxrwx.   1 root root   9 Nov  3  2020 lib64 -> usr/lib64
drwx------.   2 root root   6 Dec  4  2020 lost+found
drwxr-xr-x.   2 root root   6 Nov  3  2020 media
drwxr-xr-x.   2 root root   6 Nov  3  2020 mnt
drwxr-xr-x.   2 root root   6 Nov  3  2020 opt
dr-xr-xr-x. 230 root root   0 Jul 25 06:47 proc
dr-xr-x---.   2 root root 162 Dec  4  2020 root
drwxr-xr-x.  11 root root 163 Dec  4  2020 run
lrwxrwxrwx.   1 root root   8 Nov  3  2020 sbin -> usr/sbin
drwxr-xr-x.   2 root root   6 Nov  3  2020 srv
dr-xr-xr-x.  13 root root   0 Jul 25 03:32 sys
drwxrwxrwt.   7 root root 145 Dec  4  2020 tmp
drwxr-xr-x.  12 root root 144 Dec  4  2020 usr
drwxr-xr-x.  20 root root 262 Dec  4  2020 var
drwxr-xr-x.   2 root root   6 Jul 25 06:43 volumn01  #数据卷
drwxr-xr-x.   2 root root   6 Jul 25 06:43 volumn02  #数据卷
#在docker03 里的volumn01创建文件...
[root@44ed54af47d2 /]# cd volumn01
[root@44ed54af47d2 volumn01]# ls
[root@44ed54af47d2 volumn01]# touch docker03

在子容器docker03的数据卷目录内 创建了一个文件..看看父容器是否有

dockerfile 安装phalcon dockerfile 安装ossfs_docker_20

 注意:容器之间配置信息的传递,数据卷的生命周期一直持续到没有容器使用它为止。


存储在本机的文件则会一直保留! (即系 只要有一个容器有这个文件, 这个文件会一直保留, 哪怕你突然删除其中一个容器。  但是删除其中一个文件,即会同步删除了。)


DockerFile正式学习

DockerFel基础知识:


1 、每条保留字指令都必须为大写字母且后面要跟随至少一个参数


2 、指令按照从上到下,顺序执行


3 、 # 表示注释


4 、每条指令都会创建一个新的镜像层,并对镜像进行提交


流程:

1、docker从基础镜像运行一个容器

2、执行一条指令并且对容器做出修改

3、执行类似docker commit 的操作提交一个新的镜像层

4、Docker再基于刚刚提交的镜像运行一个新容器

5、执行dockerfile中的下一条指令知道所有指令都执行完成!

说明:

从应用软件的角度来看,DockerFile,docker镜像与docker容器分别代表软件的三个不同阶段。

  • DcokerFile是软件的原材料(代码)
  • Dcoker镜像则是软件的交付品(.apk)
  • Dcoker容器则是软件的运行转改(客户下载安装执行)

DockerFile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可。

dockerfile 安装phalcon dockerfile 安装ossfs_数据_21

DockerFile指令

FROM                     #基础镜像,当前新镜像是基于哪个镜像的

MAINTAINER         #镜像维护者的姓名+邮箱地址

RUN                       #容器构建时需要运行的命令

EXPOSE               #当前容器对外保留出的端口

WORKDIR            #指定在创建容器后,终端默认登陆进来的工作目录, 一个落脚点

ENV                     #构建过程中设置环境变量的

ADD                    #将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL或解压tar压缩包

COPY                 #类似ADD , 拷贝文件和目录到镜像中

VOLUME           # 容器数据卷,用于数据保存和持久化的工作

CMD                 #指定一个容器启动时要运行的命令,dockerFile中可以有多个CMD命令,但是只有最后一个生效。

ENTRYPOINT     #指定一个容器启动时要运行的命令,和CMD一样

CMD和ENTRYPOINT的区别


CMD Dockerfifile 中可以有多个 CMD 指令,但只有最后一个生效, CMD 会被 docker run 之后的参数 替换!


ENTRYPOINT docker run 之后的参数会被当做参数传递给 ENTRYPOINT ,之后形成新的命令组合(即是可以追加)


ONBUILD            #当构建一个被继承的DockerFile时运行命令,父镜像在子镜像继承后,父镜像ONBUILD被触发

dockerfile 安装phalcon dockerfile 安装ossfs_docker_22

构建DockerFile指令

docker build -f DockerFile路径  -t 镜像名字:tag版本号 .

注意:!!  当DockerFile文件名为 DockerFile后, 不需要-f docker build会自动去识别DockerFile文件!!!!

 试试用DockerFile创建一个增强的Centos

原本下载的Cetnos没有任何命令拆件。。。

dockerfile 安装phalcon dockerfile 安装ossfs_nginx_23

创建一个DockerFile文件进行增强

dockerfile 安装phalcon dockerfile 安装ossfs_nginx_24

 文件内容

 

dockerfile 安装phalcon dockerfile 安装ossfs_nginx_25

 利用DockerFile构建一个新的镜像

dockerfile 安装phalcon dockerfile 安装ossfs_nginx_26

 构建完成后, 看看自己造的centos。。已经有增强了。

dockerfile 安装phalcon dockerfile 安装ossfs_数据_27

查看镜像地的变更历史

 docker history 镜像id

dockerfile 安装phalcon dockerfile 安装ossfs_nginx_28

 练习: 自定义制作TOMCAT

先用rz上传 JDK和TOMCAT9 的压缩包

dockerfile 安装phalcon dockerfile 安装ossfs_数据_29

 2. 编写DockerFile文件

vim Dockerfile :

dockerfile 安装phalcon dockerfile 安装ossfs_nginx_30

 创建刚刚写的DockerFile镜像

dockerfile 安装phalcon dockerfile 安装ossfs_数据_31

 搞掂..即刻运行一下

dockerfile 安装phalcon dockerfile 安装ossfs_数据_32

 启动自定义tomcat!!!!!!!!!

docker images
REPOSITORY             TAG       IMAGE ID       CREATED             SIZE
diytomcatgogogo        latest    c904850b0018   5 minutes ago       614MB
alencentos/havetools   1.0       09d2bcc3a56d   About an hour ago   302MB
alenwong/centos        1.0       b32442cbdd6c   4 hours ago         209MB
tomcatnew              1.1       3507faca9348   6 hours ago         670MB
tomcat                 latest    46cfbf1293b1   2 days ago          668MB
nginx                  latest    4cdc5dd7eaad   2 weeks ago         133MB
mysql                  5.7       09361feeb475   4 weeks ago         447MB
portainer/portainer    latest    580c0e4e98b0   4 months ago        79.1MB
hello-world            latest    d1165f221234   4 months ago        13.3kB
centos                 latest    300e315adb2f   7 months ago        209MB

#启动容器
#第一个-v  挂载webapps到宿主机
#第二个-v  挂载日志.

[root@localhost dev]# docker run -d -p 9090:8080 --name mydiytomcat -v /home/dev/build/tomcat/test:/usr/local/apache-tomcat-9.0.50/webapps/test -v /home/dev/build/tomcat/tomcat9logs/:/usr/local/apache-tomcat-9.0.50/logs --privileged=true diytomcatgogogo
15698eb3eaa237056549cb38fd647fb76acdb01a4ecefb5222aa42e0b8900edd

测试可访问后,可以加入以下东西令页面有东西可以访问.

dockerfile 安装phalcon dockerfile 安装ossfs_nginx_33

#web.xml

<?xml version="1.0" encoding="UTF-8"?> 
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>test</display-name>

 </web-app>
#jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
<title>hello,alenwong</title> 
</head> 
<body> -----------welcome------------ 
<%=" my docker tomcat,kuangshen666 "%> <br> <br> <% System.out.println("-------my docker tomcat-------");%> </body> </html>