第四节:docker镜像原理剖析和制作镜像两种方式 (通过容器 和 通过Dockerfile)

一. 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 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 
原文地址:https://www.cnblogs.com/yaopengfei/p/13643320.html