本节记录一下Docker镜像、容器数据卷和Dockerfile解析
一、Docker镜像
首先我们明确一下docker镜像的定义: 镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
这里就需要提到提几个概念了:
- UnionFS(联合文件系统):它是是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
-
Docker镜像加载原理:docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
到这里了就有个问题,平时我们安装进虚拟机的CentOS都是好几个G,为什么docker这里才200M?因为对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供 rootfs 就行了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。Ubuntu和centos相比而言,就是内核相同,但是定制的软件不相同而已。
采用分层结构的优点:共享资源
二、容器数据卷
容器数据卷的存在就是为做数据的持久化。
卷就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持续存储或共享数据的特性。 卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷
特点:
1:数据卷可在容器之间共享或重用数据
2:卷中的更改可以直接生效
3:数据卷中的更改不会包含在镜像的更新中
4:数据卷的生命周期一直持续到没有容器使用它为止
数据卷的添加方式:
(1)直接命令添加
- docker run -it -v /宿主机绝对路径目录:/容器内目录 镜像名
☁ ~ docker run -it -v /HostDataVolume:/ContainerDataVolume centos
经过这样的一个命令之后,我们在host的根目录下面就有了HostDataVolume文件夹,在容器里面就有了ContainerDataVolume这个文件夹了。
- 现在我们看看数据卷是不是挂在成功:
docker inspect + 镜像ID
宿主机与容器之间数据的共享
在HostDataVolume里面增加一个文本host.txt。我们可以发现在ContainerDataVolume里面也出先了host.txt。容器退出之后,主机修改后数据是否同步
首先是采用exit,先退出容器。然后随便在HostDataVolume文件夹中建立一个文本,然后看看再去容器里面看看有什么变化没有。
☁ ~ docker start 容器ID
☁ ~ docker attach 容器ID
就能去容器centos里面发现,我们还是有这个文本。就算是容器关闭了,但是我们在主机里面进行的操作,都同步到了容器里面。
-
docker run -it -v /宿主机绝对路径目录:/容器内目录: ro镜像名
这里的ro就是read only 的意思,也就是说我们在host里面做的增删改能够同步到容器里面去,但是容器所对应的文件里面的是不能进行一个增删改的。
(2)Dockerfile添加
Dockerfile会在第三个部分进行一个详细的说明。
采用Dockerfile添加的步骤一个例子如下:
Step 1:现在根目录下面建立一个文件夹mydocker
Step 2:使用vim创建一个Dockerfile文件,内容如下:
FROM centos
VOLUME ["/dataVolumeContainer1","/dataVolumeContainer2"]
CMD echo "Finished, -------success1"
CMD /bin/bash
Step 3:采用Docker build来生成一个新的镜像。
docker build -f /mydocker/Dockerfile -t User/centos .
建立完成之后,我们用docker ps发现我们自动生成的镜像。
Step 4:可以采用docker run了
docker run - it User/centos
三、Dockerfile解析
Dockerfile就是用来构建Docker镜像的构建文件,由一系列命令和参数构成的脚本。注意它的本质就是一个脚本。
3.1、Dockerfile的内容基础知识
- 每个保留字命令必须是大写,而且后面至少要跟一个参数
- 指令从上到下的顺序执行
-
每条指令都会创建一个新的镜像层,并且对镜像进行一个提交的操作
Docker执行Dockerfile的大致流程如下:
(1)docker从基础的镜像实例出一个容器
(2)执行一条指令,同时对容器进行修改
(3)执行类似docker commit的操作提交一个新的镜像层
(4)docker再基于刚刚创建的新的镜像实例出一个新的容器
(5)经过这样的循环过程,一层一层的建立,我们的镜像就建立ok了。
从应用软件的角度来看待Dockerfile、Docker镜像和Docker容器,它们三个就代表了不同的阶段,是Docker体系的基石。
名称 | 类比1 | 类比2 |
---|---|---|
Dockerfile | 软件的原材料 | 面向开发 |
Docker镜像 | 软件的交付品 | 交付的标准 |
Docker容器 | 软件的运行态 | 涉及部署与运维 |
3.2、Dockerfile的保留字命令
Dockerfile的保留字命令的总结见下面的思维导图:
四、案例学习、动手实践
Case1
Flask的docker打包
step1:先建立文件 identidock,里面放Dockerfile文件,app文件夹下面放 identidock.py文件
├── identidock
│ ├── Dockerfile
│ └── app
│ └── identidock.py
step2:写Dockerfile和 identidock.py
identidock.py如下:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return "hello_world"
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
Dockerfile文件如下
FROM python:3.4
RUN pip install FLask==0.10.1
WORKDIR /app
COPY app /app
CMD ["python","identidock.py"]
step3:构建镜像docker build -t flask-test .
☁ identidock docker build -t flask-test .
Sending build context to Docker daemon 3.584kB
Step 1/5 : FROM python:3.4
---> 8c62b065252f
Step 2/5 : RUN pip install FLask==0.10.1
---> Running in cee1dd8c54de
DEPRECATION: Python 3.4 support has been deprecated. pip 19.1 will be the last one supporting it. Please upgrade your Python as Python 3.4 won't be maintained after March 2019 (cf PEP 429).
Collecting FLask==0.10.1
Downloading https://files.pythonhosted.org/packages/db/9c/149ba60c47d107f85fe52564133348458f093dd5e6b57a5b60ab9ac517bb/Flask-0.10.1.tar.gz (544kB)
Collecting Werkzeug>=0.7 (from FLask==0.10.1)
Downloading https://files.pythonhosted.org/packages/24/4d/2fc4e872fbaaf44cc3fd5a9cd42fda7e57c031f08e28c9f35689e8b43198/Werkzeug-0.15.1-py2.py3-none-any.whl (328kB)
Collecting Jinja2>=2.4 (from FLask==0.10.1)
Downloading https://files.pythonhosted.org/packages/7f/ff/ae64bacdfc95f27a016a7bed8e8686763ba4d277a78ca76f32659220a731/Jinja2-2.10-py2.py3-none-any.whl (126kB)
Collecting itsdangerous>=0.21 (from FLask==0.10.1)
Downloading https://files.pythonhosted.org/packages/76/ae/44b03b253d6fade317f32c24d100b3b35c2239807046a4c953c7b89fa49e/itsdangerous-1.1.0-py2.py3-none-any.whl
Collecting MarkupSafe>=0.23 (from Jinja2>=2.4->FLask==0.10.1)
Downloading https://files.pythonhosted.org/packages/99/c9/5d5dcf2aa90f1d4500e92467a04f63b3708ee6e5764b40b2445e767ab8dc/MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl
Building wheels for collected packages: FLask
Building wheel for FLask (setup.py): started
Building wheel for FLask (setup.py): finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/e1/f2/be/1c4f307a41aad7e632f79c0242a2714ecde24b663da3519665
Successfully built FLask
Installing collected packages: Werkzeug, MarkupSafe, Jinja2, itsdangerous, FLask
Successfully installed FLask-0.10.1 Jinja2-2.10 MarkupSafe-1.1.1 Werkzeug-0.15.1 itsdangerous-1.1.0
Removing intermediate container cee1dd8c54de
---> 84afa5451c1b
Step 3/5 : WORKDIR /app
---> Running in 91bad6e440ab
Removing intermediate container 91bad6e440ab
---> 3a3b34824bf1
Step 4/5 : COPY app /app
---> caee6e674596
Step 5/5 : CMD ["python","identidock.py"]
---> Running in 3d0cdf7d7a81
Removing intermediate container 3d0cdf7d7a81
---> 7dc330367971
Successfully built 7dc330367971
Successfully tagged flask-test:latest
采用docker images看一下验证一下就行了。
☁ app docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
flask-test latest 7dc330367971 12 minutes ago 935MB
step4:运行容器了
☁ identidock docker run -it -p 5000:5000 7dc330367971
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 337-801-390
最后我们去网页看看就知道,现在运行ok了。
Case2
需求如下:
自己定义一个centos的镜像,当我们采用该镜像生成容器的时候,满足下面的要求:
1、登录的路径是/usr/local
2、安装vim、net-tools等工具(容器里面是没有这些,所以我们在这里的话就进行一个安装的操作)
step 1:写Dockerfile如下
FROM centos
MAINTAINER yourname<yourname@gmail.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim net-tools
EXPOSE 80
CMD /bin/bash
step 2:构建镜像
注意后面那个点表明了我们是在当前的目录下面build的。
docker build -t newcentos:8.0 .
现在我们就来看看生成的新的镜像是不是出来了。这里可以看出来我们新生成的镜像比原来的镜像大了150mb。
☁ mydocker docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
newcentos 8.0 e7784fdf444b 17 seconds ago 352MB
centos latest 9f38484d220f 2 months ago 202MB
step 3:实例化镜像,生成一个容器
☁ mydocker docker run -it newcentos:8.0
[root@674942d556fa local]#
[root@674942d556fa local]# pwd
/usr/local
现在我们就看到了,一进入到了容器,那么我么你的当前路径就是/usr/local。
这样我们就生成了一个自己定义的一个centos镜像了。
Case 3:一个比较综合的例子
参考资料:
1、https://www.docker.com/
2、https://www.bilibili.com/video/av17854410?from=search&seid=2496603295204351706