一. docker镜像原理剖析
灵魂三问:
1. docker 镜像的本质是什么?
2. docker中一个centos镜像大约200M左右,为什么一个centos系统的iso安装文件要好几个G?
3. docker中一个tomcat镜像大约500M左右,为什么一个tomcat安装包不足100M呢?
1. 操作系统扫盲
操作系统由:进程调度子系统、进程通信子系统、内存管理子系统、设备管理子系统、文件管理子系统、网络通信子系统、作业控制子系统组成。
Linux的文件管理子系统由bootfs和rootfs组成。
(1). bootfs:包含bootloader(引导加载程序)和 kernel(内核)
(2). rootfs: root文件系统,包含的就是典型 Linux 系统中的/dev,/proc,/bin,/etc等标准目录和文件
PS: 不同的linux发行版,bootfs基本一样,而rootfs不同,如ubuntu,centos等
2. 镜像原理
(1). Docker镜像是由特殊的文件系统叠加而成,最底端是 bootfs,并使用宿主机的bootfs;第二层是 root文件系统rootfs,称为base image;然后再往上可以叠加其他的镜像文件。
(2). 统一文件系统(Union File System)技术能够将不同的层整合成一个文件系统,为这些层提供了一个统一的视角,这样就隐藏了多层的存在,在用户的角度看来,只存在一个文件系统。
(3). 一个镜像可以放在另一个镜像的上面。位于下面的镜像称为父镜像,最底部的镜像成为基础镜像。
(4). 当从一个镜像启动容器时,Docker会在最顶层加载一个读写文件系统作为容器。
3. 解答灵魂三问
(1). docker 镜像的本质是什么?
答:是一个分层的文件系统。
(2). docker中一个centos镜像大约200M左右,为什么一个centos系统的iso安装文件要好几个G?
答:centos的iso文件包括bootfs和rootfs,而docker的centos镜像复用操作系统的bootfs。
(3). docker中一个tomcat镜像大约500M左右,为什么一个tomcat安装包不足100M呢?
答:docker中的镜像是分层的,tomcat虽然只有70多M,但是它需要依赖父镜像和基础镜像,所有整个对外暴露的tomcat镜像大约500M左右。
二. 容器转为镜像
1. 容器变为镜像
(1). 指令
docker commit <containerId> 镜像名称:版本号
注:不加版本号的话,默认为latest
将容器制作为镜像,容器内挂载目录(数据卷)下的文件不会被包含!!!其它非挂在目录下的文件都会被一起打包转为容器。
(2). 案例
在一个名为mycentoscon1的centos容器中的工作目录下,新建一个11.txt文件,然后把这个容器转为一个镜像,名为myowincentos1。
2. 如何移动迁移镜像
(1). 把镜像制成压缩包
指令:
docker save -o 压缩文件名称 镜像名称:版本号
(2). 再把压缩包转为镜像
指令:
docker load -i 压缩文件名称
三. 通过Dockerfile制作镜像
1. 制作镜像的指令
docker build -f dockerfile文件路径 -t 镜像名称:版本号 .
(1). -f dockerfile文件路径 : dockerfile文件可以自定义命名,比如:ypfdockerfile,只要指定路径即可。
注:如果在当前目录下,且名字就叫 Dockerfile,可以省略 【 -f dockerfile文件路径】 即简版指令为 【docker build -t 镜像名称:版本号 .】
(2). 如果不指定版本号,默认为latest
(3). 指令最后必须有: 1个空格+1个点
2. 什么是Dockerfile文件
Dockerfile 是一个文本文件,包含了一条条的指令,每一条指令构建一层,基于基础镜像,最终构建出一个新的镜像。他有以下作用
(1).对于开发人员:可以为开发团队提供一个完全一致的开发环境。
(2).对于测试人员:可以直接拿开发时所构建的镜像或者通过Dockerfile文件构建一个新的镜像开始工作了。
(3).对于运维人员:在部署时,可以实现应用的无缝移植。
一张图说明几个核心配置
分享几个Dockerfile案例:
A.自己制作一个nginx镜像
FROM centos:7.6 RUN yum -y install gcc make pcre-devel zlib-devel tar zlib WORKDIR /nginx COPY nginx-1.15.2.tar.gz /nginx RUN tar -zxvf nginx-1.15.2.tar.gz RUN cd nginx-1.15.2 && ./configure && make && make install EXPOSE 8080 COPY nginx.sh /nginx.sh RUN chmod 755 /nginx.sh CMD [“/nginx.sh”]
B.自己制作一个core webapi镜像
#1.依赖两个基础镜像 FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster #2.制作人 MAINTAINER ypf <ypf@qq.com> #3.指定程序运行的端口(也可以在项目中通过UseUrls指定, 或者发布容器的时候通过--env ASPNETCORE_URLS=xxx动态指定) ENV ASPNETCORE_URLS=http://*:9000 #4.容器对外暴露的端口 EXPOSE 9000 #5.指定默认工作目录 WORKDIR /userapi #6. 将当前目录(Dockerfile文件下)的所有文件拷贝到镜像的userapi工作目录下 COPY . /userapi/ #7.启动容器的时候执行shell命令:dotnet webapi1.dll,即运行该项目 ENTRYPOINT ["dotnet", "webapi1.dll"]
C. 自定义一个centos镜像
#1.定义依赖镜像(宿主机中没有话则去下载) FROM centos:7 #2.定义作者信息(可以不写) MAINTAINER ypf <ypf@qq.com> #3. 执行安装vim的命令(-y表示安装过程中不提示) RUN yum install -y vim #4. 定义默认的工作目录 WORKDIR /ypfusr #5 定义容器启动执行的命令 CMD /bin/bash
3. 剖析
(1). FROM
定义构建新镜像所需依赖的父镜像(基础镜像)。
FROM centos:7.6
(2). MAINTAINER 或 LABEL
定义镜像的作者。
MAINTAINER ypf <ypf@qq.com> # 或者用 LABEL (推荐) LABEL maintainer="ypf"
(3) .ENV
设置环境变量
# 设置asp.net项目启动端口为8000(程序中不设置的情况下用) ENV ASPNETCORE_URLS=http://*:8000 # 设置Java环境 ENV JAVA_HOME /usr/local/jdk1.11.0 # 设置mysql的密码 ENV MYSQL_ROOT_PASSWORD 123456
(4). EXPOSE
声明容器运行的端口。
PS:在通过docker run 指令构建容器的要通过-p 将宿主机的端口和容器端口进行映射。
(5). RUN
指定构建镜像所需要运行的shell命令
#解压并安装 RUN tar -zxvf nginx-1.15.2.tar.gz RUN cd nginx-1.15.2 && ./configure && make && make install # 安装vim RUN yum install -y vim
(6). WORKDIR
指定工作目录,发布成容器时,默认进入的就是这里指定目录。
#定义默认的工作目录
WORKDIR /ypfusr
(7). VOLUME
指定生成容器时挂载宿主机的目录
VOLUME ["/var/lib/mysql"]
注:基本上不在Dockerfile文件中使用,而是在构建容器的时候通过 -v 指令来设置。
(8) . ADD
拷贝文件或目录到镜像中 (此处要测试一下,如果镜像中的目录不存在是否会自动创建???)
#将当前目录中xx1.tar.gz 复制到镜像中的/home/test文件夹下,并自动解压 ADD xx1.tar.gz /home/test #下载xx2到镜像中的/home/test文件夹中 ADD https://xxx.com/xx2.tar.gz /home/test #将当前目录下的start.sh 复制到镜像中的目录中 ADD ./start.sh /start.sh
PS:当拷贝的是压缩包或者URL的时候,会自动解压或自动下载。
(9). COPY
拷贝文件或目录到镜像中,同ADD,但不支持自动下载和解压。
# 将当前目录下的start.sh 复制到镜像中的目录中
COPY ./start.sh /start.sh
注:ADD和COPY的共同特点是 只能复制Dockerfile所在目录下的文件,如果目标镜像中的路径不存在,会自动创建。
(10). CMD
启动容器时执行的shell命令。
# 启动容器时候下面指令效果等效: # ENTRYPOINT ["dotnet", "webapi1.dll"] # ENTRYPOINT dotnet webapi1.dll # CMD ["dotnet", "webapi1.dll"] # CMD dotnet webapi1.dll
(11). ENTRYPOINT
启动容器时执行的shell命令。同CMD类似,只是由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖,而且,这些命令行参数会被当作参数传递给ENTRYPOINT指定的程序。
# 启动容器时候下面指令效果等效: # ENTRYPOINT ["dotnet", "webapi1.dll"] # ENTRYPOINT dotnet webapi1.dll # CMD ["dotnet", "webapi1.dll"] # CMD dotnet webapi1.dll
注:如果存在多个ENTRYPOINT,仅最有一个生效。
(12). HEALTHCHECK
健康检查
HEALTHCHECK --interval=5m --timeout=3s --retries=3 CMD curl -f http:/xxxx/ || exit 1
参数说明:
--interval=DURATION (default: 30s):每隔多长时间探测一次,默认30秒
-- timeout= DURATION (default: 30s):服务响应超时时长,默认30秒
-- start-period= DURATION (default: 0s):服务启动多久后开始探测,默认0秒
-- retries=N (default: 3):认为检测失败几次为宕机,默认3次
一些返回值的说明:
0:容器成功是健康的,随时可以使用
1:不健康的容器无法正常工作
2:保留不使用此退出代码
(13). USER
为RUN、CMD、ENTRYPOINT执行shell命令指定用户
USER <user>[:<usergroup>] USER <UID>[:<UID>] USER ypf
(14). ARG
构建参数,与 ENV 作用一至。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。
构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。
格式:ARG <参数名>[=<默认值>]
#Dockerfile文件中
ARG user=ypf #构建镜像的时候覆盖 docker build --build-arg user=lmr webapi1 .
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。