# demo-cache-docker-build **Repository Path**: consolelog/demo-cache-docker-build ## Basic Information - **Project Name**: demo-cache-docker-build - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-05-24 - **Last Updated**: 2024-05-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # rust加快docker构建速度 rust的编译速度本身就很慢,加上docker的沙盒模式,如果每次编译都在一个全新的沙盒中,不进行优化就直接编译,那么这个速度简直不忍直视。 所以我们要想办法优化编译流程,来降低编译复杂度,从而提高编译速度。 下面是我个人的经验,如果有更好的办法麻烦留言分享,非常感谢! ## 第一步,利用docker的layer建立缓存 下面是Dockerfile的示例,关键在这几行: ```dockerfile COPY Cargo.toml . RUN echo "fn main() {println!(\"Hello, world!\");}" > dummy.rs RUN sed -i 's/src\/main.rs/dummy.rs/' Cargo.toml RUN cargo build --release ``` - 将构建的步骤拆分开来,先将Cargo.toml复制进来,然后新建一个假的dummy.rs代替main.rs参与构建。 - 接下来再复制全部代码正常构建项目(例如: `COPY . . \n RUN cargo build --release`)。 这样做会将依赖提前下载下来,成为docker的一个layer并进入缓存,之后只要不修改Cargo.toml这些依赖就不需要重新下载。 这是利用docker的layer缓存机制实现的。 缺陷: - 这种方式的最后一步构建链接仍然很慢。因为仍然使用rust的默认构建,这个问题我还没想好怎么解决。 - 修改Cargo.toml之后需要重新执行第一步,这种方式就会失效,也就是说在第二次编译才会加快速度,第一次编译该慢还是慢。 ## 第二步,利用docker的mount机制对target目录建立缓存 关键代码: ```dockerfile # syntax=docker/dockerfile:1.2 # something xxxxxx COPY . . RUN --mount=type=cache,target=/usr/local/cargo/registry \ --mount=type=cache,sharing=private,target=target \ cargo build --release && mv target/release/demo-cache . ``` - `mount` 是docker新版本的语法,需要在Dockerfile内容的开头添加这一行 `# syntax=docker/dockerfile:1.2` 让语法生效 - `target` 后面的目录会被缓存,下次执行的时候会继承这个目录 - `sharing=private` 的意思是这个目录只在这一个镜像的构建过程生效,其它镜像不会使用相同的缓存 - *注意!注意!注意!* : mount挂载只在当前layer层生效,执行结束后实际镜像中不包含缓存的目录,所以如果你的产物本身就在缓存目录中,一定要在同一条RUN命令中将它移动出来,否则产物就丢失了!!! 这也是我这条命令的结尾,使用mv将二进制文件移动出去的原因 ## 完整Dockerfile ```dockerfile # syntax=docker/dockerfile:1.2 FROM rust:1.78.0-alpine as builder WORKDIR /app ENV RUSTFLAGS="-C target-feature=-crt-static" RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \ && apk add openssl-dev build-base \ && rm /var/cache/apk/* # 做一个假的main.rs参与构建,目的是建立依赖的缓存 COPY Cargo.toml . RUN echo "fn main() {println!(\"Hello, world!\");}" > dummy.rs RUN sed -i 's/src\/main.rs/dummy.rs/' Cargo.toml ARG CACHE_FLAG=1 RUN --mount=type=cache,target=/usr/local/cargo/registry \ --mount=type=cache,sharing=private,target=target \ cargo build --release COPY . . # 真实的构建,注意mount只在同一层layer生效,所以在同一层构建完成后就要马上mv出去 RUN --mount=type=cache,target=/usr/local/cargo/registry \ --mount=type=cache,sharing=private,target=target \ cargo build --release && mv target/release/demo-cache . FROM alpine:latest WORKDIR /app ENV TZ=Asia/Shanghai RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \ && apk add tzdata libgcc \ && ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \ && echo $TZ > /etc/timezone \ && rm /var/cache/apk/* COPY --from=builder /app/demo-cache /app/demo-cache CMD /app/demo-cache ``` ## docker-compose.yml ```yaml services: app: image: demo-cache:0.0.1 build: context: . dockerfile: Dockerfile ports: - "8080:8080" ```