Docker进阶(镜像优化与最佳实践)(一)

一,镜像原理

这里可以看之前的文章docker入门(镜像原理)(三)进行了解

二,镜像的优化
2.1 为什么要优化镜像

“docker镜像太大,导致用户服务器的磁盘空间很紧张,导致用户部署该产品时,花费的时间变长,如果客户的服务器规格不够,增大部署失败的概率”

小镜像制作原则
  • 选择最精简的基础镜像
  • 减少镜像的层数
  • 清理镜像构建的中间产物
  • 注意优化网络请求
  • 尽量去用构建缓存
  • 使用多阶段构建镜像

2.2 首先我们先编写示例Dockerfile
FROM openjdk:8-jdk-alpine
LABEL com.project.version="1.0"
LABEL com.project.release=“"017-9-9"
RUN wget http://muug.ca/mirror/apache-dist/maven/maven-3/3.5.0/binaries/apache-maven-3.5.0-bin. tar. gz
RUN tar xzvf apache maven-3.5.0-bin.tar.gz
RUN cp -R apache-maven-3.5.0 /usr/local/bin
RUN export PATH=apache-maven-3.5.0/bin:$PATH
RUN export PATH=/usr/local/bin/apache-maven-3.5. 0/bin:$PATH
RUN ln -s /usr/local/bin/apache-maven-3.5.0/bin/mvn /usr/local/bin/mvn
ADD /pom.xml pom.xml
ADD ./sre src/
RUN mvn clean package
RUN ep target/app-*.jar app. jar
CMD["java","-jar","app.jar"]

我们构建一个镜像的时候,Docker其实提供了一个标准化的构建指令集,当我们去用这些构建指令去写类似于脚本,这种脚本我们称之为DockerFile,Docker可以自动解析DockerFile,并将其构建成一个镜像,所以你就可以简单的认为这是一个标准化的脚本。DockerFile在做一些什么?首先第一行FROM指令表示要以哪一个镜像作为基础镜像进行构建,我们用了openJDK的官方镜像,以JAVA环境作为基础,我们在镜像上面准备跑一个JAVA应用,然后接下来两条LABLE是对镜像进行打标,标下镜像版本和构建日期,然后接下来的六个RUN是做了一个maven安装,maven是JAVA的一个生命周期管理工具,接下来将一些源代码从外面的环境添加到镜像里面,然后两条RUN命令做了打包工作,最后写了一个启动命令.

FROM openjdk:8-jdk-alpine
LABEL com.project.version="1.0" \
 com.project.release=“"017-9-9"
RUN wget http://muug.ca/mirror/apache-dist/maven/maven-3/3.5.0/binaries/apache-maven-3.5.0-bin.tar.gz \
 && tar xzvf apache maven-3.5.0-bin.tar.gz \
 && cp -R apache-maven-3.5.0 /usr/local/bin \
 && export PATH=apache-maven-3.5.0/bin:$PATH \
 && export PATH=/usr/local/bin/apache-maven-3.5. 0/bin:$PATH \
 && ln -s /usr/local/bin/apache-maven-3.5.0/bin/mvn /usr/local/bin/mvn
ADD /pom.xml pom.xml
ADD ./sre src/
RUN mvn clean package \ 
 && ep target/app-*.jar app. jar
CMD["java","-jar","app.jar"]

注:此时的Dockerfile文件从14层修改成7层

总的来说DockerFile写的还可以,至少思路是很清晰的,一步一步从基础镜像选择到编译环境,再把源代码加进去,然后再到最后的构建,启动命令写好,可读性、可维护性都可以,但是还是可以进行优化的。

我们可以减少镜像的层数, Docker对于Docker镜像的层数是有一定要求的,除掉最上面在容器运行时候的读写层以外,我们一个镜像最多只能有127层,如果超过可能会出现问题,所以第二行命令LABLE就可以把它合成一层,减少了层数,下面六个RUN命令做了maven的安装工作,我们也可以把它做成一层,把这些命令串起来,后面的构建我们也可以把它合成一层,这样我们一下就把镜像层数从14层减少到7层,减掉了一半。

我们在做镜像优化的时候,我们希望能够尽量减少镜像的层数,但是和它相对应的是我们DockerFile的可读性,我们需要在这两者之间做折中,我们在保证可读性不受很大影响的情况下去尽量减少它,其实六条RUN命令在做一件事,就是做maven环境打结,做编译环境的准备工作。

构件过程中产生中间产物清理
FROM openjdk:8-jdk-alpine
LABEL com.project.version="1.0" \
 com.project.release=“"017-9-9"
RUN wget http://muug.ca/mirror/apache-dist/maven/maven-3/3.5.0/binaries/apache-maven-3.5.0-bin.tar.gz \
 && tar xzvf apache maven-3.5.0-bin.tar.gz \
 && cp -R apache-maven-3.5.0 /usr/local/bin \
 && export PATH=apache-maven-3.5.0/bin:$PATH \
 && export PATH=/usr/local/bin/apache-maven-3.5. 0/bin:$PATH \
 && ln -s /usr/local/bin/apache-maven-3.5.0/bin/mvn /usr/local/bin/mvn
 && rm -rf apache-maven-3.5.0-bin.tar.gz apache-maven-3.5.0                #清除构建中的中间产物
ADD /pom.xml pom.xml
ADD ./sre src/
RUN mvn clean package \ 
 && ep target/app-*.jar app. jar
CMD["java","-jar","app.jar"]

接下来我们继续对镜像进行优化,我们可以做一些什么工作呢?在安装maven构建工具的时候我们多加了一行,我们把安装包和展开目录删掉了,我们清理了构建的中间产物,我们要去注意每一个构建指令执行的时候,尽量把垃圾清理掉,我们通过apt-get去装一些软件的时候,我们也可以去做这样的清理工作,就是把这些软件包装完之后就可以把它删掉了,这样可以尽量减少空间,通过增加一行命令,我们可以把镜像的大小从137M削减到119M。

2.3多层构建
为何需要多阶段构建

多阶段构建的核心理念在于,构建过程中的每一阶段都可以产生一个独立的镜像层,这使得我们能够在最终镜像中只保留运行所需的组件,去除构建时的辅助工具和不必要的文件,从而大幅减小镜像体积。

Dockerfile中的多阶段构建

示例代码:Dockerfile多阶段构建

# 第一阶段:构建应用
FROM node:14 AS builder
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build

# 第二阶段:运行应用
FROM nginx:latest
COPY --from=builder /app/dist /usr/share/nginx/html

在这个例子中,第一阶段构建了应用,第二阶段从第一阶段复制构建好的结果到最终镜像中。

多阶段构建的优势和应用场景

(1) 优势

多阶段构建的主要优势包括减小镜像大小、提高构建速度、增强安全性等方面。通过示例和案例,我们将详细探讨这些优势。

(2) 应用场景

示例代码:Python应用的多阶段构建

# 第一阶段:构建应用
FROM python:3.9 AS builder
WORKDIR /app
COPY . .
RUN pip install --no-cache-dir -r requirements.txt

# 第二阶段:运行应用
FROM python:3.9-slim
WORKDIR /app
COPY --from=builder /app /app
CMD ["python", "app.py"]

(3)构建高效的java应用镜像

Java应用的构建通常涉及到编译、打包等步骤,将通过示例代码演示如何使用多阶段构建来优化Java应用的Docker镜像。

示例代码:构建高效的Java应用镜像

# 第一阶段:构建和打包应用
FROM maven:3.8.1 AS builder
WORKDIR /app
COPY . .
RUN mvn clean package

# 第二阶段:运行应用
FROM openjdk:11-jre-slim
WORKDIR /app
COPY --from=builder /app/target/app.jar /app/app.jar
CMD ["java", "-jar", "app.jar"]

在这个例子中,在第一阶段构建和打包应用,然后在第二阶段将构建好的Jar文件复制到最终镜像中。

(4)多阶段构建的最佳实践和技巧

(4.1)利用 .dockerignore文件

示例:.dockerignore的使用

node_modules
.git

通过合理使用.dockerignore​文件,可以避免将不必要的文件包含在构建上下文中,提高构建效率。

(4.2)避免使用latest标签

示例:指定明确的镜像标签

FROM node:14 AS builder

FROM nginx:1.21

避免使用latest​标签,明确指定所需的镜像版本,以确保构建的可重复性。

(5)安全性实践

多阶段构建也可以带来一些安全性方面的好处

示例代码:使用Docker Content Trust

expord DOCKER_CONTENT_TRUST=1

通过启用Docker Content Trust,可以确保只有经过签名的镜像才能被加载,提高了镜像的可信度。

(6)高级多阶段构建技巧

除了基本原理和常见实践外,深入探讨一些高级多阶段构建技巧,以更进一步提升构建过程的效率和灵活性。

(6.1) 多阶段构建的参数化

示例:参数化构建

ARG BASE_IMAGE=NODE:14
FROM ${BASE_IMAGE} AS builder

通过参数化构建,可以在构建时动态指定基础镜像,提高镜像的灵活性。

(6.2)构建时获取外部资源

示例代码:构建时获取外部资源

ROM alpine AS downloader
WORKDIR /app
RUN wget https://example.com/resource.tar.gz

FROM alpine
COPY --from=downloader /app/resource.tar.gz /app/resource.tar.gz

在这个例子中,通过构建时下载外部资源,然后在下一个阶段复制到最终镜像中,实现了构建时获取外部资源的需求。

(7)多阶段构建的适用范围和局限性

多阶段构建并非适用于所有场景,需要了解其适用范围和局限性,以便在实际应用中做出明智的选择。

(7.1) 适用范围

多阶段构建特别适用于大型应用、含有编译过程的应用以及需要优化镜像大小的场景。

(7.2) 局限性

多阶段构建可能增加构建过程的复杂性,并且不适用于所有应用。在一些简单应用或者构建过程较短的场景中,可能并不切实际。

(8)持续优化和反馈机制

多阶段构建是一个动态的过程,随着应用的演进,需要持续优化构建过程和镜像体积。建立反馈机制,及时调整构建策略,是一个不可忽视的环节。

(9)与容器编排工具的整合

多阶段构建与容器编排工具(如Kubernetes)的整合也是一个值得探讨的话题。可以通过适当的构建策略,使得镜像在不同环境中更为灵活地部署和调度。

示例代码:整合Kubernetes部署

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app
        image: my-username/my-app:latest

在这个例子中,使用Kubernetes的Deployment来部署多阶段构建后的镜像,并通过标签进行版本控制。

总结

在本文中,全面剖析了其基本原理、优势、应用场景以及高级技巧。透过更为丰富和实际的示例代码,获得了深入的了解,并掌握了如何通过多阶段构建优化Docker镜像大小和性能。深入研究了不同语言应用的构建优化,包括Python和Java,并探索了一些高级技巧,如参数化构建和构建时获取外部资源。同时,强调了多阶段构建的适用范围和局限性,以帮助大家在实际应用中做出明智选择。

除此之外,引入了持续优化和反馈机制的概念,提醒大家构建过程是一个动态的、需不断优化的过程。最后,探讨了多阶段构建与容器编排工具的整合,展示了如何通过巧妙的构建策略在Kubernetes等容器编排平台上更灵活地部署应用。

多阶段构建不仅是提升构建效率的工具,更是推动容器化技术未来发展的引擎,激发了更多创新和可能性。

  • 28
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安徽小刘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值