1. 首页 > Docker教程 > 正文

Docker教程FG009-Docker Build优化与实战(多阶段构建)

本教程风哥教程参考Docker官方文档,详细介绍Docker Build的优化方法和多阶段构建的实战技巧。内容包括构建优化原理、多阶段构建语法、最佳实践以及常见问题解决方案,帮助读者掌握Docker镜像构建的高级技术。

本文档适合Docker容器开发人员、运维工程师以及DevOps工程师阅读,通过学习本教程,您将能够构建更高效、更轻量的Docker镜像。

目录大纲

Part01-基础概念与理论知识

1.1 Docker Build原理

Docker Build的核心原理是通过Dockerfile中的指令,逐步构建镜像层。它具有以下特点:

  • 每一条指令都会创建一个新的镜像层
  • 利用缓存加速构建过程
  • 构建上下文是构建过程中可以访问的文件和目录
  • 支持多阶段构建,分离构建环境和运行环境

理解Docker Build的原理,有助于我们优化构建过程,提高构建效率。

1.2 多阶段构建概述

多阶段构建是Docker 17.05引入的特性,它允许在一个Dockerfile中定义多个构建阶段,每个阶段可以使用不同的基础镜像,最终只保留需要的文件。多阶段构建的优势包括:

  • 减少最终镜像体积
  • 分离构建环境和运行环境
  • 避免在最终镜像中包含构建工具和依赖
  • 简化Dockerfile的编写
  • 提高构建效率

多阶段构建是构建优化的重要手段,特别适合需要编译的应用程序。

Part02-生产环境规划与建议

2.1 构建环境优化

在生产环境中,建议以下构建环境优化:

  • 使用BuildKit:启用Docker BuildKit,提高构建速度
  • 配置构建缓存:使用本地缓存或远程缓存
  • 优化构建上下文:使用.dockerignore文件排除不需要的文件
  • 使用并行构建:利用多核CPU提高构建速度
  • 选择合适的基础镜像:使用最小化的基础镜像

更多视频教程www.fgedu.net.cn

2.2 多阶段构建策略

在生产环境中,建议采取以下多阶段构建策略:

  • 构建阶段:使用包含构建工具的镜像
  • 测试阶段:运行测试用例
  • 运行阶段:使用最小化的基础镜像
  • 清理阶段:清理不需要的文件和依赖

2.3 构建缓存管理

构建缓存管理的建议:

  • 合理组织Dockerfile指令,利用缓存
  • 使用–cache-from参数使用远程缓存
  • 定期清理构建缓存,避免缓存膨胀
  • 在CI/CD环境中使用缓存,提高构建速度

学习交流加群风哥微信: itpux-com

Part03-生产环境项目实施方案

3.1 多阶段构建语法

多阶段构建的基本语法:

# 第一阶段:构建
FROM base_image AS build

# 构建指令
RUN commands

# 第二阶段:运行
FROM base_image

# 从构建阶段复制文件
COPY --from=build /path/to/file /path/to/destination

# 运行指令
CMD ["command"]

3.2 构建优化技巧

构建优化的技巧:

  • 使用多阶段构建减少最终镜像体积
  • 合理组织Dockerfile指令,利用缓存
  • 使用.dockerignore文件排除不需要的文件
  • 合并RUN指令,减少镜像层
  • 清理临时文件,减少镜像体积
  • 使用BuildKit提高构建速度

3.3 构建参数配置

常用的构建参数配置:

# 启用BuildKit
$ export DOCKER_BUILDKIT=1

# 构建镜像
$ docker build -t fgedu/myapp:latest .

# 使用远程缓存
$ docker build -t fgedu/myapp:latest --cache-from fgedu/myapp:latest .

# 禁用缓存
$ docker build -t fgedu/myapp:latest --no-cache .

# 指定构建参数
$ docker build -t fgedu/myapp:latest --build-arg VERSION=1.0 .

# 构建多平台镜像
$ docker buildx build -t fgedu/myapp:latest --platform linux/amd64,linux/arm64 .

Part04-生产案例与实战讲解

4.1 多阶段构建基础实战

案例:构建一个Java应用镜像

# 创建Dockerfile
$ cat > Dockerfile << 'EOF'
# 第一阶段:构建
FROM maven:3.8.5-openjdk-11 AS build

WORKDIR /app

COPY pom.xml .
RUN mvn dependency:go-offline

COPY src ./src
RUN mvn package -DskipTests

# 第二阶段:运行
FROM openjdk:11-jre-slim

WORKDIR /app

COPY --from=build /app/target/myapp-1.0.jar .

EXPOSE 8080

CMD ["java", "-jar", "myapp-1.0.jar"]
EOF

# 创建pom.xml
$ cat > pom.xml << 'EOF'

    4.0.0

    com.fgedu
    myapp
    1.0

    
        
            org.springframework.boot
            spring-boot-starter-web
            2.5.6
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
                2.5.6
            
        
    

EOF

# 创建src目录结构
$ mkdir -p src/main/java/com/fgedu

# 创建Application.java
$ cat > src/main/java/com/fgedu/Application.java << 'EOF'
package com.fgedu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @GetMapping("/")
    public String hello() {
        return "Hello World!";
    }
}
EOF

# 构建镜像
$ docker build -t fgedu/java-app:latest .

[+] Building 20.0s (12/12) FINISHED
 => [internal] load build definition from Dockerfile
 => => transferring dockerfile: 350B
 => [internal] load .dockerignore
 => => transferring context: 2B
 => [internal] load metadata for docker.io/library/maven:3.8.5-openjdk-11
 => [internal] load metadata for docker.io/library/openjdk:11-jre-slim
 => [build 1/5] FROM docker.io/library/maven:3.8.5-openjdk-11
 => [stage-1 1/4] FROM docker.io/library/openjdk:11-jre-slim
 => [build 2/5] WORKDIR /app
 => [build 3/5] COPY pom.xml .
 => [build 4/5] RUN mvn dependency:go-offline
 => [build 5/5] COPY src ./src
 => [build 6/5] RUN mvn package -DskipTests
 => [stage-1 2/4] WORKDIR /app
 => [stage-1 3/4] COPY --from=build /app/target/myapp-1.0.jar .
 => [stage-1 4/4] CMD ["java", "-jar", "myapp-1.0.jar"]
 => exporting to image
 => => exporting layers
 => => writing image sha256:1234567890abcdef...
 => => naming to docker.io/fgedu/java-app:latest

风哥提示:使用多阶段构建可以显著减少Java应用镜像的体积,只包含运行时所需的文件。

4.2 多阶段构建高级实战

案例:构建一个前端应用镜像

# 创建Dockerfile
$ cat > Dockerfile << 'EOF'
# 第一阶段:构建
FROM node:16-alpine AS build

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .
RUN npm run build

# 第二阶段:运行
FROM nginx:alpine

COPY --from=build /app/build /usr/share/nginx/html

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]
EOF

# 创建package.json
$ cat > package.json << 'EOF'
{
  "name": "myapp",
  "version": "1.0.0",
  "description": "React application",
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "dependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-scripts": "4.0.3"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}
EOF

# 创建src目录结构
$ mkdir -p src

# 创建index.js
$ cat > src/index.js << 'EOF'
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(
  
    
  ,
  document.getElementById('root')
);
EOF

# 创建App.js
$ cat > src/App.js << 'EOF'
import React from 'react';

function App() {
  return (
    

Hello World!

Welcome to React application

); } export default App; EOF # 创建index.html $ cat > public/index.html << 'EOF' EOF # 构建镜像 $ docker build -t fgedu/react-app:latest . [+] Building 15.0s (12/12) FINISHED => [internal] load build definition from Dockerfile => => transferring dockerfile: 320B => [internal] load .dockerignore => => transferring context: 2B => [internal] load metadata for docker.io/library/node:16-alpine => [internal] load metadata for docker.io/library/nginx:alpine => [build 1/5] FROM docker.io/library/node:16-alpine => [stage-1 1/4] FROM docker.io/library/nginx:alpine => [build 2/5] WORKDIR /app => [build 3/5] COPY package*.json ./ => [build 4/5] RUN npm install => [build 5/5] COPY . . => [build 6/5] RUN npm run build => [stage-1 2/4] COPY --from=build /app/build /usr/share/nginx/html => [stage-1 3/4] EXPOSE 80 => [stage-1 4/4] CMD ["nginx", "-g", "daemon off;"] => exporting to image => => exporting layers => => writing image sha256:1234567890abcdef... => => naming to docker.io/fgedu/react-app:latest

学习交流加群风哥QQ113257174

4.3 Docker数据库多阶段构建实战

案例:构建自定义PostgreSQL镜像

# 创建Dockerfile
$ cat > Dockerfile << 'EOF'
# 第一阶段:构建扩展
FROM postgres:14 AS build

RUN apt-get update && apt-get install -y \
    build-essential \
    postgresql-server-dev-14 \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app

# 复制扩展源代码
COPY pg_cron /app/pg_cron

# 构建扩展
RUN cd pg_cron && make && make install

# 第二阶段:运行
FROM postgres:14

# 复制构建的扩展
COPY --from=build /usr/lib/postgresql/14/lib/pg_cron.so /usr/lib/postgresql/14/lib/
COPY --from=build /usr/share/postgresql/14/extension/pg_cron* /usr/share/postgresql/14/extension/

# 配置postgresql.conf
RUN echo "shared_preload_libraries = 'pg_cron'" >> /usr/share/postgresql/postgresql.conf.sample

# 初始化脚本
COPY init.sql /docker-entrypoint-initdb.d/

EXPOSE 5432
EOF

# 创建init.sql
$ cat > init.sql << 'EOF'
-- 启用pg_cron扩展
CREATE EXTENSION IF NOT EXISTS pg_cron;

-- 创建表
CREATE TABLE fgedu_users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(50),
    email VARCHAR(100)
);

-- 插入数据
INSERT INTO fgedu_users (name, email) VALUES
('张三', 'zhangsan@example.com'),
('李四', 'lisi@example.com'),
('王五', 'wangwu@example.com');

-- 创建定时任务
SELECT cron.schedule('0 0 * * *', 'DELETE FROM fgedu_users WHERE id > 1000');
EOF

# 构建镜像
$ docker build -t fgedu/postgres:latest .

[+] Building 15.0s (12/12) FINISHED
 => [internal] load build definition from Dockerfile
 => => transferring dockerfile: 450B
 => [internal] load .dockerignore
 => => transferring context: 2B
 => [internal] load metadata for docker.io/library/postgres:14
 => [build 1/5] FROM docker.io/library/postgres:14
 => [stage-1 1/4] FROM docker.io/library/postgres:14
 => [build 2/5] RUN apt-get update && apt-get install -y build-essential postgresql-server-dev-14 && rm -rf /var/lib/apt/lists/*
 => [build 3/5] WORKDIR /app
 => [build 4/5] COPY pg_cron /app/pg_cron
 => [build 5/5] RUN cd pg_cron && make && make install
 => [stage-1 2/4] COPY --from=build /usr/lib/postgresql/14/lib/pg_cron.so /usr/lib/postgresql/14/lib/
 => [stage-1 3/4] COPY --from=build /usr/share/postgresql/14/extension/pg_cron* /usr/share/postgresql/14/extension/
 => [stage-1 4/4] COPY init.sql /docker-entrypoint-initdb.d/
 => exporting to image
 => => exporting layers
 => => writing image sha256:1234567890abcdef...
 => => naming to docker.io/fgedu/postgres:latest

更多学习教程公众号风哥教程itpux_com

Part05-风哥经验总结与分享

5.1 最佳实践

  • 使用多阶段构建减少镜像体积
  • 启用BuildKit提高构建速度
  • 合理组织Dockerfile指令,利用缓存
  • 使用.dockerignore文件排除不需要的文件
  • 选择合适的基础镜像,减少镜像体积
  • 合并RUN指令,减少镜像层
  • 清理临时文件,减少镜像体积
  • 使用构建参数实现环境差异
  • 定期更新基础镜像,修复安全漏洞
  • 实施镜像扫描,检测安全漏洞

5.2 常见问题与解决方案

问题 解决方案
构建速度慢 启用BuildKit,利用缓存,优化构建上下文
镜像体积过大 使用多阶段构建,清理临时文件,使用最小化基础镜像
构建失败 检查Dockerfile语法,确保依赖正确,检查网络连接
缓存失效 合理组织Dockerfile指令,避免缓存失效
多平台构建问题 使用docker buildx,配置正确的平台参数

5.3 性能优化建议

  • 使用SSD存储提高构建速度
  • 配置足够的CPU和内存资源
  • 使用并行构建,提高构建效率
  • 优化网络连接,提高依赖下载速度
  • 使用本地缓存或远程缓存
  • 合理组织项目结构,减少构建上下文
  • 使用构建缓存,避免重复构建

from Docker视频:www.itpux.com

通过以上优化措施,可以显著提高Docker Build的效率和质量,为容器化应用提供更好的运行环境。

本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html

联系我们

在线咨询:点击这里给我发消息

微信号:itpux-com

工作日:9:30-18:30,节假日休息