一、构建过程
1.清空之前的实验环境(rm删除容器、rmi删除镜像)
2.获取nginx软件包和rhel7的镜像文件
[root@server1 ~]# cd docker/
[root@server1 docker]# ls
Dockerfile nginx-1.18.0.tar.gz rhel7.tar testfile
[root@server1 docker]# docker load -i rhel7.tar 导入镜像
e1f5733f050b: Loading layer [============================>] 147.1MB/147.1MB
安装nginx要解决一些依赖性所以必须配置yum源
[root@server1 docker]# cp /etc/yum.repos.d/westos.repo .
[root@server1 docker]# ls
Dockerfile nginx-1.18.0.tar.gz rhel7.tar testfile westos.repo
编写dockerfile
解决
[root@server1 docker]# cat Dockerfile
FROM rhel7 指定镜像
EXPOSE 80 指定80端口
MAINTAINER wsp439@sina.com 说明联系人
COPY westos.repo /etc/yum.repos.d/ 将本地的yum源文件复制到容器中的/etc/yum.repo.d/目录下:此行书写错误导致上图报错现已更改
RUN rpmdb --rebuilddb 重新构建镜像 rpmdb命令用于初始化和重建rpm数据库
RUN yum install -y gcc make pcre-devel zlib-devel 指定安装所需的软件
ADD nginx-1.18.0.tar.gz /mnt/ 指定解压路径下
WORKDIR /mnt/nginx-1.18.0 指定解压后的目录名称
RUN ./configure --prefix=/usr/local/nginx 预编译
RUN make 编译
RUN make install 编译安装
ENTRYPOINT ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"] 启动运行nginx服务后台运行
[root@server1 docker]# docker build -t nginx:v1 . 再次构建成功注意命令后有一个点,表示当前目录下
[root@server1 docker]# docker images 可以看到nginx303M特大
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx v1 245f9de6f74e 4 minutes ago 303MB
对nginx进行优化:方便跨平台部署
一般解压后的目录,编译扮装的软件所产产生的垃圾文件一般存放于/var/cache/yum/
可以在构建镜像的时候直接清除缓存
第一次优化:更改dockerfile文件清理编译之后不需要的一些文件目录及yum缓存
[root@server1 docker]# vim Dockerfile
[root@server1 docker]# cat Dockerfile
FROM rhel7
EXPOSE 80
MAINTAINER wsp439@sina.com
COPY westos.repo /etc/yum.repos.d/
RUN rpmdb --rebuilddb
RUN yum install -y gcc make pcre-devel zlib-devel && yum clean all 清除yum缓存
ADD nginx-1.18.0.tar.gz /mnt/
WORKDIR /mnt/nginx-1.18.0
RUN ./configure --prefix=/usr/local/nginx
RUN make
RUN make install
RUN rm -rf /mnt/nginx-1.18.0 安装完成后删除解压文件
ENTRYPOINT ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
[root@server1 docker]# docker build -t nginx:v2 . 再次构建镜像
[root@server1 docker]# docker images 可以看到重新构建的v2只有277MB
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx v2 438bc20d33c5 44 seconds ago 277MB
nginx v1 245f9de6f74e 25 minutes ago 303MB
第二次优化:减少镜像构建层数
下图可以看到我们构建镜像的层数非常多(12层)
Dockerfile进行优化可以整合对个RUN运行的命令
整合顺序不能错乱
[root@server1 docker]# docker build -t nginx:v3 .
[root@server1 docker]# docker images 此时只有258MB
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx v3 0c469008341a 5 minutes ago 258MB
nginx v2 438bc20d33c5 19 minutes ago 277MB
nginx v1 245f9de6f74e 43 minutes ago 303MB
第三次优化:多阶段构建镜像,最大化缩减容器占比
多阶段构建介绍1 :在多阶段构建中,需要在 Dockerfile 中多次使用 FROM 声明。每次 FROM 指令可以使用不同的基础镜像,并且每次 FROM 指令都会开始新阶段的构建。可以选择将构件从一个阶段复制到另一个阶段,在最终镜像中,不会留下不需要的所有内容。
多阶段构建介绍2多阶段构建(Multi-stage builds),旨在解决Docker构建应用容器中的一些痛点。在日常构建容器的场景中,经常会遇到在同一个容器中进行源码的获取,编译和生成,最终才构建为镜像。这样做的劣势在于:
1.不得不在容器中安装构建程序所必须的运行时环境
2.不得不在同一个容器中,获取程序的源码和构建所需的一些生态工具
3.构建出的镜像甚至包含了程序源码和一些不必要的文件,导致容器镜像尺寸偏大
当然,还有一种稍微优雅的方式,就是我们事先在外部将项目及其依赖库编译测试打包好后,再将其拷贝到构建目录中,这种虽然可以很好地规避第一种方式存在的风险点,但是也需要考虑不同镜像运行时,对于程序运行兼容性所带来的差异。
其实,这些痛点,Docker也想到了,官方提供了简便的多阶段构建 (multi-stage build) 方案。所谓多阶段构建,也即将构建过程分为多个阶段,在同一个Dockerfile中,通过不同的阶段来构建和生成所需要的应用文件,最终将这些应用文件添加到一个release的镜像中。这样做能完全规避上面所遇到的一系列问题。实现多阶段构建,主要依赖于新提供的关键字:from 和 as 。
下面进行演示
[root@server1 docker]# cat Dockerfile
FROM rhel7 as build
EXPOSE 80
MAINTAINER wsp439@sina.com
COPY westos.repo /etc/yum.repos.d/
ADD nginx-1.18.0.tar.gz /mnt/
WORKDIR /mnt/nginx-1.18.0
RUN sed -i 's/CFLAGS="$CFLAGS-g"/#CFLAGS="$CFLAGS-g"/g' auto/cc/gcc && rpmdb --rebuilddb && yum install -y gcc make pcre-devel zlib-devel && yum clean all && ./configure --prefix=/usr/local/nginx && make && make install && rm -rf /mnt/nginx-1.18.0
上面的FROM主要是生成nginx的二进制文件
FROM rhel7
EXPOSE 80
MAINTAINER wsp439@sina.com
设置数据卷;添加数据卷挂载位置
VOLUME ["/usr/local/nginx/html"] 配置数据目录,与物理机上的默认发布页面同步,若要更改只需更改物理机的默认配置页面
COPY --from=build /usr/local/nginx /usr/local/nginx build表示上面的FROM
ENTRYPOINT ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
[root@server1 docker]# docker build -t nginx
nginx nginx:v1 nginx:v2 nginx:v3
[root@server1 docker]# docker build -t nginx:v4 .
[root@server1 docker]# docker images
可以看到这次减少了许多,我们是以rhel7为镜像的它本身就有140MB,所有我们的nginx实际只有不到1MB
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx v4 eacb07b8625e 7 seconds ago 141MB
nginx v3 0c469008341a About an hour ago 258MB
nginx v2 438bc20d33c5 About an hour ago 277MB
nginx v1 245f9de6f74e About an hour ago 303MB
busybox latest 59788edf1f3e 20 months ago 1.15MB
game2048 latest 19299002fdbe 3 years ago 55.5MB
ubuntu latest 07c86167cdc4 4 years ago 188MB
rhel7 latest 0a3eb3fde7fd 5 years ago 140MB
第四次优化:最后的优化
优化思路:从底层优化
导入一个distroless和nginx镜像
distroless”镜像只包含应用程序及其运行时依赖项,不包含程序包管理器、shell以及在标准Linux发行版中可以找到的任何其他程序;用distroless去除容器中所有不必要的东西
导入镜像
[root@server1 ~]# docker load -i distroless.tar
668afdbd4462: Loading layer [=============================>] 18.39MB/18.39MB
Loaded image: gcr.io/distroless/base:latest
[root@server1 ~]# docker load -i nginx.tar
014cf8bfcb2d: Loading layer [=============================>] 58.46MB/58.46MB
832a3ae4ac84: Loading layer [=============================>] 53.91MB/53.91MB
e89b70d28795: Loading layer [=============================>] 3.584kB/3.584kB
Loaded image: nginx:latest
编写Dockerfile
[root@server1 ~]# mkdir distroless
[root@server1 ~]# cd distroless/
[root@server1 distroless]# vim Dockerfile
FROM nginx as base
# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
ARG Asia/Shanghai
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 /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.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libdl.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libpthread.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libcrypt.so.* /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
COPY --from=base /opt /
EXPOSE 80
ENTRYPOINT ["nginx", "-g", "daemon off;"]
构建镜像
构建容器并测试
[root@server1 distroless]# docker run -d --name nginx nginx:v5 运行nginx服务名称为nginx
e5b99ef16d3f95c3a188bf5849d851f052a15349513181bc9094a8c5c5102702
[root@server1 distroless]# docker ps 查看已经运行
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e5b99ef16d3f nginx:v5 "nginx -g 'daemon of…" 11 seconds ago Up 10 seconds 80/tcp nginx
[root@server1 distroless]# docker inspect nginx 查看ip
测试访问
[root@server1 distroless]# yum whatprovides */brctl
[root@server1 distroless]# yum install -y bridge-utils-1.5-9.el7.x86_64
[root@server1 distroless]# brctl show 可以看到镜像的网卡桥接在docker0上,所以只有物理机可以访问
bridge name bridge id STP enabled interfaces
docker0 8000.024289ff8a42 no vethe02d183
两个不同的网段的访问本机可以访问容器:在安装容器后的时候会自动生成一个docker0的网卡,本机访问是通过docker0去访问镜像,但是目前只有本机可以访问,其他用户不可访问镜像,因为根本没有端口进入。
制作端口映射把容器镜像的80端口映射到主机的80端口;访问物理机的80端口就是访问容器80
[root@server1 distroless]# docker rm -f nginx
nginx
[root@server1 distroless]# docker run -d -p 80:80 --name nginx nginx:v5 确保本机80端口没有使用
d75e632503458555093180fcdcc04b28abc78dedcfefbe2caf70f90ee043f2b2