Docker通过读取Dockerfile中的指令主动构建镜像,Dockerfile是一个文本文件,其中顺次蕴含构建给定镜像所需的所有命令。
下面的解释摘自Docker的官网文档并总结了Dockerfile的用处。Dockerfile的应用十分重要,因为它是咱们的蓝图,是咱们增加到Docker镜像中的层的记录。
本文,咱们将学习如何利用BuildKit性能,这是Docker v18.09上引入的一组加强性能。集成BuildKit将为咱们提供更好的性能,存储管理和安全性。
先决条件
- Docker概念常识
- 已装置Docker(以后应用v19.03)
- 一个Java应用程序(在本文中,我应用了一个Jenkins Maven示例应用程序)
让咱们开始吧!
简略的Dockerfile示例
以下是一个蕴含Java应用程序的未优化Dockerfile的示例。咱们将逐渐进行一些优化。
FROM debianCOPY . /appRUN apt-get updateRUN apt-get -y install openjdk-11-jdk ssh emacsCMD [“java”, “-jar”, “/app/target/my-app-1.0-SNAPSHOT.jar”]
在这里,咱们可能会问本人:构建须要多长时间?为了答复这个问题,让咱们在本地开发环境上创立该Dockerfile,并让Docker构建镜像。
# enter your Java app foldercd simple-java-maven-app-master# create a Dockerfilevim Dockerfile# write content, save and exitdocker pull debian:latest # pull the source imagetime docker build --no-cache -t docker-class . # overwrite previous layers# notice the build time0,21s user 0,23s system 0% cpu 1:55,17 total
此时,咱们的构建须要1m55s。
如果咱们仅启用BuildKit而没有其余更改,会有什么不同吗?
启用BuildKit
BuildKit能够通过两种办法启用:
在调用Docker build命令时设置DOCKER_BUILDKIT = 1环境变量,例如:
time DOCKER_BUILDKIT=1 docker build --no-cache -t docker-class
将Docker BuildKit设置为默认开启,须要在/etc/docker/daemon.json进行如下设置,而后重启:
{ "features": { "buildkit": true } }
BuildKit最后的成果
DOCKER_BUILDKIT=1 docker build --no-cache -t docker-class .0,54s user 0,93s system 1% cpu 1:43,00 total
此时,咱们的构建须要1m43s。在雷同的硬件上,构建破费的工夫比以前少了约12秒。这意味着构建简直无需费劲即可节约10%左右的工夫。
当初让咱们看看是否能够采取一些额定的步骤来进一步改善。
从最小到最频繁变动的程序
因为程序对于缓存很重要,所以咱们将COPY命令移到更凑近Dockerfile开端的地位。
FROM debianRUN apt-get updateRUN apt-get -y install openjdk-11-jdk ssh emacsRUN COPY . /appCMD [“java”, “-jar”, “/app/target/my-app-1.0-SNAPSHOT.jar”]
防止应用“COPY .”
抉择更具体的COPY参数,以防止缓存中断。仅复制所需内容。
FROM debianRUN apt-get updateRUN apt-get -y install openjdk-11-jdk ssh vimCOPY target/my-app-1.0-SNAPSHOT.jar /appCMD [“java”, “-jar”, “/app/my-app-1.0-SNAPSHOT.jar”]
apt-get update 和install命令一起应用
这样能够避免应用过期的程序包缓存。
FROM debianRUN apt-get update && \ apt-get -y install openjdk-11-jdk ssh vimCOPY target/my-app-1.0-SNAPSHOT.jar /appCMD [“java”, “-jar”, “/app/my-app-1.0-SNAPSHOT.jar”]
删除不必要的依赖
在开始时,不要装置调试和编辑工具,当前能够在须要时装置它们。
FROM debianRUN apt-get update && \ apt-get -y install --no-install-recommends \ openjdk-11-jdkCOPY target/my-app-1.0-SNAPSHOT.jar /appCMD [“java”, “-jar”, “/app/my-app-1.0-SNAPSHOT.jar”]
删除程序包管理器缓存
你的镜像不须要此缓存数据。借此机会开释一些空间。
FROM debianRUN apt-get update && \ apt-get -y install --no-install-recommends \ openjdk-11-jdk && \ rm -rf /var/lib/apt/lists/*COPY target/my-app-1.0-SNAPSHOT.jar /appCMD [“java”, “-jar”, “/app/my-app-1.0-SNAPSHOT.jar”]
尽可能应用官网镜像
应用官网镜像有很多理由,例如缩小镜像保护工夫和减小镜像尺寸,以及事后配置镜像以供容器应用。
FROM openjdkCOPY target/my-app-1.0-SNAPSHOT.jar /appCMD [“java”, “-jar”, “/app/my-app-1.0-SNAPSHOT.jar”]
应用特定标签
请勿应用latest标签。
FROM openjdk:8COPY target/my-app-1.0-SNAPSHOT.jar /appCMD [“java”, “-jar”, “/app/my-app-1.0-SNAPSHOT.jar”]
寻找最小的镜像
以下是openjdk镜像列表。抉择最适宜本人的最轻的那个镜像。
REPOSITORY TAG标签 SIZE大小openjdk 8 634MBopenjdk 8-jre 443MBopenjdk 8-jre-slim 204MBopenjdk 8-jre-alpine 83MB
在统一的环境中从源构建
如果你不须要整个JDK,则能够应用Maven Docker镜像作为构建根底。
FROM maven:3.6-jdk-8-alpineWORKDIR /appCOPY pom.xml .COPY src ./srcRUN mvn -e -B packageCMD [“java”, “-jar”, “/app/my-app-1.0-SNAPSHOT.jar”]
在独自的步骤中获取依赖项
能够缓存–用于获取依赖项的Dockerfile命令。缓存此步骤将放慢构建速度。
FROM maven:3.6-jdk-8-alpineWORKDIR /appCOPY pom.xml .RUN mvn -e -B dependency:resolveCOPY src ./srcRUN mvn -e -B packageCMD [“java”, “-jar”, “/app/my-app-1.0-SNAPSHOT.jar”]
多阶段构建:删除构建依赖项
为什么要应用多阶段构建?
- 将构建与运行时环境离开
DRY形式
- 具备开发,测试等环境的不同详细信息
- 线性化依赖关系
具备特定于平台的阶段
FROM maven:3.6-jdk-8-alpine AS builderWORKDIR /appCOPY pom.xml .RUN mvn -e -B dependency:resolveCOPY src ./srcRUN mvn -e -B packageFROM openjdk:8-jre-alpineCOPY --from=builder /app/target/my-app-1.0-SNAPSHOT.jar /CMD [“java”, “-jar”, “/my-app-1.0-SNAPSHOT.jar”]
如果你此时构建咱们的应用程序,
time DOCKER_BUILDKIT=1 docker build --no-cache -t docker-class .0,41s user 0,54s system 2% cpu 35,656 total
你会留神到咱们的应用程序构建须要大概35.66秒的工夫。这是一个令人欢快的提高。
上面,咱们将介绍其余场景的性能。
多阶段构建:不同的镜像格调
上面的Dockerfile显示了基于Debian和基于Alpine的镜像的不同阶段。
FROM maven:3.6-jdk-8-alpine AS builder…FROM openjdk:8-jre-jessie AS release-jessieCOPY --from=builder /app/target/my-app-1.0-SNAPSHOT.jar /CMD [“java”, “-jar”, “/my-app-1.0-SNAPSHOT.jar”]FROM openjdk:8-jre-alpine AS release-alpineCOPY --from=builder /app/target/my-app-1.0-SNAPSHOT.jar /CMD [“java”, “-jar”, “/my-app-1.0-SNAPSHOT.jar”]
要构建特定的镜像,咱们能够应用–target参数:
time docker build --no-cache --target release-jessie .
不同的镜像格调(DRY /全局ARG)
ARG flavor=alpineFROM maven:3.6-jdk-8-alpine AS builder…FROM openjdk:8-jre-$flavor AS releaseCOPY --from=builder /app/target/my-app-1.0-SNAPSHOT.jar /CMD [“java”, “-jar”, “/my-app-1.0-SNAPSHOT.jar”]
ARG命令能够指定要构建的镜像。在下面的例子中,咱们指定alpine为默认的镜像,但咱们也能够在docker build命令中,通过–build-arg flavor=参数指定镜像。
time docker build --no-cache --target release --build-arg flavor=jessie .
并发
并发在构建Docker镜像时很重要,因为它会充分利用可用的CPU线程。在线性Dockerfile中,所有阶段均按程序执行。通过多阶段构建,咱们能够让较小的依赖阶段准备就绪,以供主阶段应用它们。
BuildKit甚至带来了另一个性能上的益处。如果在当前的构建中不应用该阶段,则在完结时将间接跳过这些阶段,而不是对其进行解决和抛弃。
上面是一个示例Dockerfile,其中网站的资产是在一个assets阶段中构建的:
FROM maven:3.6-jdk-8-alpine AS builder…FROM tiborvass/whalesay AS assetsRUN whalesay “Hello DockerCon!” > out/assets.htmlFROM openjdk:8-jre-alpine AS releaseCOPY --from=builder /app/my-app-1.0-SNAPSHOT.jar /COPY --from=assets /out /assetsCMD [“java”, “-jar”, “/my-app-1.0-SNAPSHOT.jar”]
这是另一个Dockerfile,其中别离编译了C和C ++库,并在builder当前应用该阶段。
FROM maven:3.6-jdk-8-alpine AS builder-base…FROM gcc:8-alpine AS builder-someClib…RUN git clone … ./configure --prefix=/out && make && make installFROM g++:8-alpine AS builder-some CPPlib…RUN git clone … && cmake …FROM builder-base AS builderCOPY --from=builder-someClib /out /COPY --from=builder-someCpplib /out /
BuildKit应用程序缓存
BuildKit具备程序包管理器缓存的非凡性能。以下是一些缓存文件夹地位的示例:
包管理器门路
apt /var/lib/apt/listsgo ~/.cache/go-buildgo-modules $GOPATH/pkg/modnpm ~/.npmpip ~/.cache/pip
咱们能够将此Dockerfile与下面介绍的在统一的环境中从源代码构建中介绍的Dockerfile进行比拟。这个较早的Dockerfile没有非凡的缓存解决。咱们能够应用–mount=type=cache来做到这一点。
FROM maven:3.6-jdk-8-alpine AS builderWORKDIR /appRUN --mount=target=. --mount=type=cache,target /root/.m2 \ && mvn package -DoutputDirectory=/FROM openjdk:8-jre-alpineCOPY --from=builder /app/target/my-app-1.0-SNAPSHOT.jar /CMD [“java”, “-jar”, “/my-app-1.0-SNAPSHOT.jar”]
BuildKit的平安性能
BuildKit具备平安性能,上面的示例中,咱们应用了–mount=type=secret暗藏了一些机密文件,例如~/.aws/credentials。
FROM <baseimage>RUN …RUN --mount=type=secret,id=aws,target=/root/.aws/credentials,required \./fetch-assets-from-s3.shRUN ./build-scripts.sh
要构建此Dockerfile,须要应用–secret参数:
docker build --secret id=aws,src=~/.aws/credentials
还有为了进步安全性,防止应用诸如COPY ./keys/private.pem /root .ssh/private.pem之类的命令,咱们能够应用BuildKit中的ssh解决此问题:
FROM alpineRUN apk add --no-cache openssh-clientRUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hostsARG REPO_REF=19ba7bcd9976ef8a9bd086187df19ba7bcd997f2RUN --mount=type=ssh,required git clone git@github.com:org/repo /work && cd /work && git checkout -b $REPO_REF
要构建此Dockerfile,你须要在ssh-agent中加载到你的SSH私钥。
eval $(ssh-agent)ssh-add ~/.ssh/id_rsa # this is the SSH key default locationdocker build --ssh=default .
论断
本文,咱们介绍了应用Docker BuildKit优化Dockerfile,并因而放慢了镜像构建工夫。这些速度的进步,能够帮忙咱们提高效率和节俭计算能力。
起源:https://os.51cto.com/art/2021...