linRichielinRichie
前端
Python
Linux
ChatGPT
  • B 站
  • 500px
前端
Python
Linux
ChatGPT
  • B 站
  • 500px
  • Ansible

    • Ansible: 基本操作
    • Ansible: 安装
    • Ansible: 简介
    • YAML: 文件格式
    • Playbook

      • Playbook: 介绍
      • Playbook: 操作
    • 模块

      • Yum模块常用参数
    • 实战

      • Ansible 实战
  • Anaconda

    • Anaconda命令
  • Iptables

    • Iptable: 防火墙
    • iptables 用法
  • Systemd

    • 系统服务配置
    • 系统服务启动文件
    • 性能优化

      • Linux 系统监控
      • Linux 系统性能优化
      • Linux 系统故障诊断
      • Linux 系统日志管理
  • Network

    • 用一张图解释 8 种流行的网络协议
    • 反子网掩码
    • 交换机端口模式
    • eNSP 软件
    • 华为交换机配置命令
    • eNSP静态路由实验
  • Commands

    • 命令别名:alias
    • 多类型资源统计工具: dstat
    • history配置
    • unzip命令
    • Linux用户到期登录时间和随机密码
    • 常用 Command
    • ssh

      • ssh-keygen
      • linux ssh命令
  • CI/CD

    • Jenkins CI/CD 管道
  • Kubernetes

    • Docker系列学习

      • 01. 什么是Docker
      • 02. Docker安装
      • 03. 使用Docker镜像
      • 04. 利用commit理解镜像构成
      • 05. 操作Docker容器
      • 06. 使用Dockerfile定制镜像
      • 07. Dockerfile指令详解
      • 08. Dockerfile多阶段创建
      • 09. 访问仓库
      • 10. 修改docker的启动项
      • 11. Nexus3.x的私有仓库
      • 12. docker-hub加速器
      • 13. 数据管理
      • 14. 使用网络
  • Shell编程

    • Shell 编程基础
    • Shell 脚本执行消耗的时间
    • Shell 自动生成简介

08. Dockerfile多阶段创建

  • 简介
  • 1. 传统构建方式的问题
    • 1.1 单一 Dockerfile 方式
    • 1.2 多 Dockerfile 方式
  • 2. 多阶段构建
    • 2.1 基本用法
    • 2.2 构建镜像
    • 2.3 高级特性
  • 3. 最佳实践

简介

多阶段构建(Multi-stage builds)是 Docker 17.05 引入的新特性,它允许在一个 Dockerfile 中使用多个 FROM 语句。这种方式可以:

  • 大幅减少最终镜像的体积
  • 避免在构建过程中引入不必要的依赖
  • 简化构建流程

1. 传统构建方式的问题

在多阶段构建出现之前,通常采用两种方式构建镜像:

  • 全部放入一个 Dockerfile
  • 分散到多个 Dockerfile

1.1 单一 Dockerfile 方式

存在的问题:

  • 镜像层次多,镜像体积较大,部署时间变长
  • 源代码存在泄露的风险

示例:构建 Go 应用

  1. 创建 app.go 文件:

    package main
    import "fmt"
    func main(){
        fmt.Printf("Hello World!");
    }
    
  2. 编写 Dockerfile.one:

    FROM golang:1.9-alpine
    RUN apk --no-cache add git ca-certificates
    WORKDIR /go/src/github.com/go/helloworld
    COPY app.go .
    RUN go get -d -v github.com/go-sql-driver/mysql \
        && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . \
        && cp /go/src/github.com/go/helloworld/app /root
        
    WORKDIR /root/
    CMD ["./app"]
    
  3. 构建镜像:

    docker build -t go/helloword:1 -f Dockerfile.one .
    

1.2 多 Dockerfile 方式

基本思路:

  • 第一个 Dockerfile 用于编译构建
  • 第二个 Dockerfile 用于生成运行环境
  • 使用脚本将两个阶段连接起来

示例:

  1. 编写 Dockerfile.build(构建阶段):

    FROM golang:1.9-alpine
    RUN apk --no-cache add git
    WORKDIR /go/src/github.com/go/helloworld
    COPY app.go .
    RUN go get -d -v github.com/go-sql-driver/mysql \
        && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
    
  2. 编写 Dockerfile.copy(运行阶段):

    FROM alpine:latest
    RUN apk --no-cache add ca-certificates
    WORKDIR /root/
    COPY app .
    CMD ["./app"]
    
  3. 创建构建脚本 build.sh:

    #!/bin/sh
    echo Building go/helloworld:build
    
    docker build -t go/helloworld:build . -f Dockerfile.build
    
    docker create --name extract go/helloworld:build
    docker cp extract:/go/src/github.com/go/helloworld/app ./app
    docker rm -f extract
    
    echo Building go/helloworld:2
    
    docker build --no-cache -t go/helloworld:2 . -f Dockerfile.copy
    rm ./app
    
  4. 执行构建:

    chmod +x build.sh
    
    ./build.sh
    

镜像大小对比:

$ docker image ls

REPOSITORY      TAG    IMAGE ID        CREATED         SIZE
go/helloworld   2      f7cf3465432c    22 seconds ago  6.47MB
go/helloworld   1      f55d3e16affc    2 minutes ago   295MB

注意: 虽然第二种方式可以得到更小的镜像,但构建过程较为复杂。

2. 多阶段构建

2.1 基本用法

使用多阶段构建,只需要一个 Dockerfile 就可以实现上述功能:

FROM golang:1.9-alpine as builder

RUN apk --no-cache add git

WORKDIR /go/src/github.com/go/helloworld/

RUN go get -d -v github.com/go-sql-driver/mysql

COPY app.go .

RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

FROM alpine:latest as prod

RUN apk --no-cache add ca-certificates

WORKDIR /root/

COPY --from=0 /go/src/github.com/go/helloworld/app .

CMD ["./app"]

2.2 构建镜像

docker build -t go/helloworld:3 .

2.3 高级特性

构建特定阶段

使用 --target 参数可以指定构建到某个阶段:

# 只构建 builder 阶段
docker build --target builder -t username/imagename:tag .

从其他镜像复制文件

COPY 指令支持从其他阶段或外部镜像复制文件:

# 从上一阶段复制
COPY --from=builder /go/src/app .

# 从指定镜像复制
COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf

3. 最佳实践

  • 将构建阶段放在前面,运行阶段放在后面
  • 使用 as 为每个阶段命名,提高可读性
  • 只复制必要的文件,减少镜像体积
  • 合理使用缓存,提高构建效率
最近更新时间:
Prev
07. Dockerfile指令详解
Next
09. 访问仓库