目录
一、什么是docker镜像
Docker 包含三个基本概念,分别是镜像(Image)、容器(Container)和仓库(Repository)。镜像是 Docker 运行容器的前提,仓库是存放镜像的场所。
Docker 镜像可以看作是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。由于 Docker 使用一个统一文件系统,Docker 进程认为整个文件系统是以读写方式挂载的。 但是所有的变更都发生顶层的可写层,而下层的原始的只读镜像文件并未变化。由于镜像不可写,所以镜像是无状态的。
镜像的分层结构

二、镜像的构建
docker commit
•docker commit 构建新镜像三部曲(从已经创建的容器中更新镜像,并且提交这个镜像)
•运行容器
•修改容器
•将容器保存为新的镜像
1 docker pull busybox ##拉取busybox
2 docker images ##查看镜像
3 docker info
4 docker search busybox
5 docker history busybox:latest
6 docker ps
7 docker rm -f demo ##删除容器
直接以busybox命名的为官方镜像。其他的为个人或组织上传的镜像。
docker指令
查看容器的创建历史
docker run -it --name demo busybox #交互式运行容器,按ctrl+d退出
docker ps
docker ps -a #看到容器运行已经停止
docker start demo
docker attach demo #进入容器看到建立的文件还在,按住ctrl+p+q 相当于打入后台
docker stop demo
docker rm demo
docker commit demo demo:v1 #提交,将容器保存为新的镜像
docker rmi demo:v1 #删除镜像
基础镜像是不能打到后台,采用交互式。应用镜像可以打入后台运行。
ps列出当前运行的容器,加-a列出所有包含已经停掉的。删除容器,就会被释放,新做的更改就不在了
提交后,再删除容器,重新拉取提交后的修改文件还在
删除容器和镜像
缺点:
•效率低、可重复性弱、容易出错
•使用者无法对镜像进行审计,存在安全隐患。
由查看demo:v1的历史和其他镜像历史可以发现,只有sh不知道具体做了什么更改,也就是无法审计。
dockerfile
提高重复性,通过建立Dockerfile的方式。
mkdir docker ##建立一个空目录
cd docker/
ls
vim Dockerfile
ll
docker build --help #构建,默认会读取Dockerfile的文件
docker build -t demo:v1 . #构建镜像;从当前加载数据
docker images
docker history demo:v1 从v1中可以看到做了什么
docker run --rm -it demo:v1
vim Dockerfile 多加了一层
docker build -t demo:v2 . 之前都是缓存
docker history demo:v2 ##查看镜像的分层结构
建立空目录,建立Dockerfile文件
建立docker容器
方便审计
--rm 操作后就自动删除,退出后容器自动释放
缓存特性,当在最后添加指令时,重新建立时,前几部将用原来的
其实执行过程中,每一步还是执行commit,Dockfile其实就是将原来的操作逻辑,以文件的形式描述出来。
Dockerfile详解
dockerfile常用指令
FROM 指定base镜像,如果本地不存在会从远程仓库下载。
MAINTAINER 设置镜像的作者,比如用户邮箱等。
COPY 把文件从build context复制到镜像 支持两种形式:COPY src dest 和 COPY ["src", "dest"] src必须指定build context中的文件或目录
ADD 用法与COPY类似,不同的是src可以是归档压缩文件,文件会被自动解压到dest,也可以自动下载URL并拷贝到镜像: ADD html.tar /var/www ADD http://ip/html.tar /var/www
ENV 设置环境变量,变量可以被后续的指令使用: ENV HOSTNAME sevrer1.example.com
EXPOSE 如果容器中运行应用服务,可以把服务端口暴露出去: EXPOSE 80
VOLUME 申明数据卷,通常指定的是应用的数据挂在点: VOLUME ["/var/www/html"]
WORKDIR 为RUN、CMD、ENTRYPOINT、ADD和COPY指令设置镜像中的当前工作目录,如果目录不存在会自动创建
RUN 在容器中运行命令并创建新的镜像层,常用于安装软件包: RUN yum install -y vim
CMD 与 ENTRYPOINT 这两个指令都是用于设置容器启动后执行的命令,但CMD会被docker run后面的命令行覆盖,而ENTRYPOINT不会被忽略,一定会被执行。 docker run后面的参数可以传递给ENTRYPOINT指令当作参数。 Dockerfile中只能指定一个ENTRYPOINT,如果指定了很多,只有最后一个有效。
MAINTAINER
COPY 拷贝文件要放到Dockerfile相同的目录下,只能访问相对路径
ADD 文件会被自动解压到dest
ENV :设置环境变量,变量可以被后续的指令使用
EXPOSE 暴露端口
-p冒号前的为宿主机端口,冒号后为容器暴露端口。
VOLUME: 申明数据卷,卷就是用来分离数据的,把数据持久化我们的指定路径(本地和远程都行)。通常指定的是应用的数据挂载点
docker inspect demo #看容器的详尽信息
本地的生成新的数据卷挂接到容器内的/data目录, 自动做了持久化,相当于在容器内写的数据自动持久化到了我们的宿主机。当然在本地更改数据,也会同步到我们的容器中。
卷的删除
CMD:用于运行程序
Shell和exec格式的区别
# cat Dockerfile
FROM busybox
ENV name world
ENTRYPOINT echo "hello, $name"
Shell格式底层会调用/bin/sh -c来执行命令,可以解析变量,而下面的exec格式不会
采用以下格式是会报错的。
需要改写成以下形式:
# cat Dockerfile
FROM busybox
ENV name world
ENTRYPOINT ["/bin/sh", "-c", "echo hello, $name"
我们需要加/bin/sh
CMD和ENTRYPOINT是可以替换的。
Exec格式时,ENTRYPOINT可以通过CMD提供额外参数,CMD的额外参数可以在容器启动时动态替换。在shell格式时ENTRYPOINT会忽略任何CMD或docker run提供的参数。
# cat Dockerfile
FROM busybox
ENTRYPOINT ["/bin/echo", "hello"]
CMD ["world"]
docker run --rm demo:v8 linux
docker run --rm demo:v8 redhat
docker run --rm demo:v8 redhat linux #会把CMD覆盖掉,但是ENTRYPOINT是不动的,必须要执行的
bash把最后的CMD指令覆盖了。
docker打包一个完整的镜像
编写Dockerfile文件,并将之前的镜像都删除。
删除之前已经退出的容器
运行容器
数据挂载位置
我们可以发现我们封装的镜像很大,比官方的镜像还要大,所以封装的意义就没有了,因此我们需要对镜像进行优化。
三、镜像的优化
之前的很大
镜像的优化方法:
• 选择最精简的基础镜像• 减少镜像的层数• 清理镜像构建的中间产物• 注意优化网络请求• 尽量去用构建缓存• 使用多阶段构建镜像
减少镜像的层数并清理镜像构建的中间产物
减少了200M效果还是明显的。对比发现层数减少了。
多阶段构建镜像
第一阶段构建 build 第二阶段copy
比基础镜像只多了4M ,缩减效果很明显,但是和官方的还是有差距。
选择最精简的基础镜像
基础镜像差距很大。
我们从github上寻找谷歌的base镜像来构建
下载下来后倒入。
docker load -i base-debian10.tar #把真机传输过来的base镜像,指定打包到系统里
所有的容器材料都在这
docker run --rm -it demo:v3 bash ##打开bash要覆盖掉nginx的进程
ldd /usr/local/nginx/sbin/nginx #二进制程序在运行时会调用系统的函数库
排错可以查看日志
可以运行
我们可以从github寻找,直接搜索distroless nginx就可以