1. 镜像的分层结构
1. base 镜像简单来说就是不依赖其他任何镜像,完全从0开始建起,
其他镜像都是建立在他的之上,可以比喻为大楼的地基,docker镜像的鼻祖。
base 镜像有两层含义:
(1)不依赖其他镜像,从 scratch 构建;
(2)其他镜像可以之为基础进行扩展。
所以,能称作 base 镜像的通常都是各种 Linux 发行版的 Docker 镜像,
比如 Ubuntu, Debian, CentOS 等。
- 镜像层数量可能会很多,所有镜像层会联合在一起组成一个统一的文件系统。如果不同层中有一个相同路径的文件,比如 /a,上层的 /a会覆盖下层的 /a,也就是说用户只能访问到上层中的文件 /a。在容器层中,用户看到的是一个叠加之后的文件系统。
- 添加文件:在容器中创建文件时,新文件被添加到容器层中。 读取文件:在容器中读取某个文件时,Docker会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后打开并读入内存。
- 修改文件:在容器中修改已存在的文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后修改之。
- 删除文件:在容器中删除文件时,Docker 也是从上往下依次在镜像层中查找此文件。找到后,会在容器层中记录下此删除操作。
- 只有当需要修改时才复制一份数据,这种特性被称作Copy-on-Write。可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改。这样就解释了我们前面提出的问题:容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享。
2. 镜像的构建
2.1 容器的简单操作
[root@server1 ~]# ls
busybox.tar game2048.tar mario.tar
[root@server1 ~]# docker load -i busybox.tar ##相当于一个最小系统
8a788232037e: Loading layer 1.37MB/1.37MB
Loaded image: busybox:latest
[root@server1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox latest 59788edf1f3e 2 years ago 1.15MB
[root@server1 ~]# docker run -it busybox
/ # ls
bin dev etc home proc root sys tmp usr var
/ # uname -r
3.10.0-957.el7.x86_64
/ # [root@server1 uname -r
3.10.0-957.el7.x86_64
[root@server1 ~]# docker history busybox:latest
[root@server1 ~]# docker ps -a ##查看进程和id
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0df8b43139da busybox "sh" About a minute ago Exited (0) About a minute ago pedantic_wu(随即生成的容器名字)
[root@server1 ~]# docker start 0df8b43139da ##通过id启动容器
0df8b43139da
[root@server1 ~]# docker container attach 0df8b43139da ##通过id进入容器
[root@server1 ~]# docker rm 0df8b43139da ##通过id删除容器
[root@server1 ~]# docker rm -f demo
[root@server1 ~]# docker run -it --rm busybox ##ctrl+d直接退出,清空
/ # [root@server1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
在进入容器还是存在刚才新建的文件
rm 参数—-> ctrl+d之后直接退出
2.2 commit提交
- docker commit 构建新镜像三部曲
运行容器
修改容器
将容器保存为新的镜像
- 缺点:
效率低、可重复性弱、容易出错
使用者无法对镜像进行审计,存在安全隐患
- 运行容器
# docker run -it --name test busybox
修改容器 (以下命令在容器内运行)
# echo helloworld > testfile
将容器保存为新的镜像
# docker commit test test:v1
查看镜像
# docker images test:v1
[root@server1 ~]# docker run -it --name demo busybox ##生成容器demo
/ # ls
bin etc file2 home root tmp var
dev file1 file3 proc sys usr
/ # [root@server1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cf8ac9c4e00f busybox "sh" 51 seconds ago Exited (0) 8 seconds ago demo
[root@server1 ~]# docker commit -m "add files" demo demo:v1 ##通过容器生成镜像
[root@server1 ~]# docker images ##v1是生成的镜像
REPOSITORY TAG IMAGE ID CREATED SIZE
demo v1 16b70d3f6375 13 seconds ago 1.15MB
busybox latest 59788edf1f3e 2 years ago 1.15MB
game2048 latest 19299002fdbe 4 years ago 55.5MB
mario latest 9a35a9e43e8c 5 years ago 198MB
直接使用commit提交生成镜像,没有审计,完全不知道里面干过什么。只有一个描述add file。
2.3 通过Dockerfile提交
## 创建一个Dockerfile
[root@server1 ~]# mkdir docker
[root@server1 ~]# cd docker
[root@server1 docker]# vim Dockerfile
[root@server1 docker]# cat Dockerfile
FROM busybox
RUN touch file1
RUN mkdir westos
##构建镜像
[root@server1 docker]# docker build -t demo:v1 .
dockerfile的创建原理—>相当于一个一个进行提交。
在新建一个镜像,使用的是是一个镜像v1的缓存。
3. Dockerfile详解(dockerfile常用指令)
ctel+q+p 可以将容器打入后台,而不直接瑞出。
没用的先删掉!
3.1 FROM
指定base镜像,如果本地不存在会从远程仓库下载。
3.3 MAINTAINER
设置镜像的作者,比如用户邮箱等。
3.3 COPY
- 把文件从build context复制到镜像
支持两种形式:COPY src dest 和 COPY ["src", "dest"]
src必须指定build context中的文件或目录
3.4 ADD
- 用法与COPY类似,不同的是src可以是归档压缩文件,文件会被自动解压到dest,也可以自动下载URL并拷贝到镜像:
ADD html.tar /var/www
ADD http://ip/html.tar /var/www
3.5 ENV
设置环境变量,变量可以被后续的指令使用:
ENV HOSTNAME sevrer1.example.com
3.6 EXPOSE
如果容器中运行应用服务,可以把服务端口暴露出去:
EXPOSE 80
下载一个 nginx做实验。
我这里是下载好的包。
3.7 VOLUME
申明数据卷,通常指定的是应用的数据挂在点:
VOLUME ["/var/www/html"]
进入到目录删除之后,文件消失
释放掉volume卷
3.8 WORKDIR
为RUN、CMD、ENTRYPOINT、ADD和COPY指令设置镜像中的当前工作目录,如果目录不存在会自动创建。
3.9 RUN
在容器中运行命令并创建新的镜像层,常用于安装软件包:
RUN yum install -y vim
4.0 CMD 与 ENTRYPOINT
这两个指令都是用于设置容器启动后执行的命令,但CMD会被docker run后面的命令行覆盖,而ENTRYPOINT不会被忽略,一定会被执行。
docker run后面的参数可以传递给ENTRYPOINT指令当作参数。
Dockerfile中只能指定一个ENTRYPOINT,如果指定了很多,只有最后一个有效。
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/echo", "hello, $name"]
- 需要改写成以下形式:
# cat Dockerfile
FROM busybox
ENV name world
ENTRYPOINT ["/bin/sh", "-c", "echo hello, $name"]
- 官方推荐使用exec格式书写
- Exec格式时,ENTRYPOINT可以通过CMD提供额外参数,CMD的额外参数可以在容器启动时动态替换。在shell格式时ENTRYPOINT会忽略任何CMD或docker run提供的参数。
# cat Dockerfile
FROM busybox
ENTRYPOINT ["/bin/echo", "hello"]
CMD ["world"]
4. 阿里云加速器的使用
首先注册帐号
登陆成功选择控制台
选择产品服务
查看镜像加速器码和操作步骤
设置加速器
测试拉取速度
拉取后版本新的替换掉版本旧的,然后删除掉没用的images
5. 镜像的优化—搭建最简nginx
- 选择最精简的基础镜像
减少镜像的层数
清理镜像构建的中间产物
注意优化网络请求
尽量去用构建缓存
使用多阶段构建镜像
删除镜像,保证实验环境纯净
我们使用rhel7.0作为最小系统
5.1 通过Dockerfile文件安装nginx容器
[root@server1 docker]# pwd
/root/docker
[root@server1 docker]# vim dvd.repo ##编写所用仓库
[root@server1 docker]# cat dvd.repo
[dvd]
name=rhel7.6
baseurl=http://172.25.13.250/rhel7.6
gpgcheck=0
[root@server1 docker]# vim Dockerfile
[root@server1 docker]# cat Dockerfile
FROM rhel7
COPY dvd.repo /etc/yum.repos.d/
ADD nginx-1.18.0.tar.gz /mnt
WORKDIR /mnt/nginx-1.18.0
RUN rpmdb --rebuilddb
RUN yum install -y gcc make pcre-devel zlib-devel
RUN ./configure
RUN make
RUN make install
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
[root@server1 docker]# docker build -t webserver:v1 .
[root@server1 docker]# docker images
##比较images大小
[root@server1 docker]# docker inspect webserver ##查看ip并测试是否访问成功
5.2 减少镜像层数,清理镜像构建的中间产物
5.3 使用多阶段构建镜像
[root@server1 docker]# vim Dockerfile
[root@server1 docker]# cat Dockerfile
FROM rhel7 as build
COPY dvd.repo /etc/yum.repos.d/
ADD nginx-1.18.0.tar.gz /mnt
WORKDIR /mnt/nginx-1.18.0
RUN rpmdb --rebuilddb && yum install -y gcc make pcre-devel zlib-devel &> /dev/null && ./configure &> /dev/null && make &> /dev/null && make install &> /dev/null && rm -fr /mnt/nginx-1.18.0 && yum remove -y gcc make && yum clean all
FROM rhel7
COPY --from=build /usr/local/nginx /usr/local/nginx
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
[root@server1 docker]# docker build -t webserver:v3 .
[root@server1 docker]# docker images webserver
REPOSITORY TAG IMAGE ID CREATED SIZE
webserver v3 9318bb8566e1 37 seconds ago 144MB ##缩减到了144M,但还是比nginx官方镜像133M大很多
webserver v2 ac33a92dfa33 8 minutes ago 233MB
webserver v1 3c76174a3370 33 minutes ago 303MB
5.4 选择最精简的基础镜像(google)
[root@server1 docker]# docker run -it --rm webserver:v3 bash
bash-4.2# ldd /usr/local/nginx/sbin/nginx ##执行nginx,base中下面的执行文件、库文件都必须有。这些都需要复制到base中
linux-vdso.so.1 => (0x00007ffeb0d8a000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f34521ff000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f3451fe3000)
libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f3451dac000)
libpcre.so.1 => /lib64/libpcre.so.1 (0x00007f3451b4b000)
libz.so.1 => /lib64/libz.so.1 (0x00007f3451935000)
libc.so.6 => /lib64/libc.so.6 (0x00007f3451574000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3452403000)
libfreebl3.so => /lib64/libfreebl3.so (0x00007f34512f5000)
## 更精简的镜像:(goole准备好了)
github上的查找方法(下载一般需要外网)
可以通过命令直接下载最简单的base(不需要外网)
我们使用下载好的包
[root@server1 ~]# cd nginx/
[root@server1 nginx]# pwd
/root/nginx
[root@server1 nginx]# vim Dockerfile
[root@server1 nginx]# cat Dockerfile
FROM nginx:1.18.0 as base ##下载一个nginx1.18.0
# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
ARG TIME_ZONE
RUN mkdir -p /opt/var/cache/nginx && \
cp -a --parents /usr/lib/nginx /opt && \
cp -a --parents /usr/share/nginx /opt && \
cp -a --parents /var/log/nginx /opt && \
cp -aL --parents /var/run /opt && \
cp -a --parents /etc/nginx /opt && \
cp -a --parents /etc/passwd /opt && \
cp -a --parents /etc/group /opt && \
cp -a --parents /usr/sbin/nginx /opt && \
cp -a --parents /usr/sbin/nginx-debug /opt && \
cp -a --parents /lib/x86_64-linux-gnu/ld-* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libpcre.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libz.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libc* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libdl* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libpthread* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libcrypt* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libssl.so.* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libcrypto.so.* /opt && \
cp /usr/share/zoneinfo/${TIME_ZONE:-ROC} /opt/etc/localtime
FROM gcr.io/distroless/base-debian10
COPY --from=base /opt /
EXPOSE 80 443
ENTRYPOINT ["nginx", "-g", "daemon off;"]
6. 总结补充
- 镜像常用子命令
images 显示镜像列表
history 显示镜像构建历史
commit 从容器创建镜像
build 从Dockerfile构建镜像
tag 给镜像打标签
search 搜索镜像
pull 从仓库拉取镜像
push 上传镜像到仓库
rmi 删除镜像