6.1 构建应用程序镜像

系列 - 应用程序容器化
摘要
本实验将带你探索Docker镜像的构建技巧,包括选择合适的基础镜像、减少层数以及使用多阶段构建。通过这些实践,你将了解如何创建既高效又轻量的Docker镜像,为容器化应用开发打下坚实基础。

在这个任务中,我们将创建两个基于不同父镜像(Ubuntu和Alpine)的Dockerfile,以比较它们在镜像大小上的差异。

1、创建目录

bash

mkdir /root/compare
cd /root/compare

2、创建两个 Dockerfile 文件

bash

touch Dockerfile-1 Dockerfile-2

3、编辑Dockerfile文件内容

Dockerfile-1 文件内容(基于Ubuntu):

Dockerfile-2 文件内容(基于Alpine):

TSfVr7

信息
golang 在 Ubuntu 系统中的软件包名为 golang,在 alpine 系统中直接叫 go。这是因为不同的Linux发行版可能对同一软件使用不同的包名。

4、构建两个镜像

使用 Dockerfile-1 构建 golang:ubuntu 镜像:

stmfyR

使用 Dockerfile-2 构建 golang:alpine 镜像:

WUn9E9

Docker build参数解释
  • -t:指定构建的镜像名称和标签,格式为name:tag
  • -f:指定使用的Dockerfile文件路径,当Dockerfile不是默认文件名或不在当前目录时使用
  • .:构建上下文路径,Docker会将这个路径下的所有文件发送给Docker守护进程

5、对比镜像大小

bash

docker images golang

xp1lm1

基础镜像选择技巧
从上面的结果可以看出,基于Alpine的镜像比基于Ubuntu的镜像小很多。Alpine是一个面向安全的轻量级Linux发行版,镜像大小通常只有几MB,非常适合作为Docker镜像的基础。当你的应用不需要特定发行版的功能时,优先考虑使用Alpine作为基础镜像。

在这个任务中,我们将创建两个Dockerfile来对比镜像层数对最终镜像大小的影响。

1、在 /root/compare 中创建文件 Dockerfile-3 和 Dockerfile-4,内容如下:

Dockerfile-3(多层构建):

4sKNqr

Dockerfile-4(减少层数):

jnlThL

信息
Dockerfile-3使用了多个COPY命令,每个命令会创建一个新的镜像层。而Dockerfile-4将多个COPY命令合并为一个COPY命令,这样只会创建一个镜像层。

2、构建两个镜像,名称分别为 l3 和 l4

构建l3镜像:

ebuJ8v

构建l4镜像:

1DWCtJ

3、对比两个镜像的层数

docker history 命令可以查看镜像的层数:

6gwIDJ

减少镜像层数的好处
每一层都会增加镜像的复杂度并可能增加最终镜像的大小。通过合并命令减少层数,不仅可以优化镜像大小,还能提高构建和部署的效率。

在这个任务中,我们将创建一个包含Firefox浏览器和VNC服务器的Docker镜像,让用户可以通过网页远程访问容器中运行的Firefox。

1、创建目录

bash

mkdir /root/firefox-vnc
cd /root/firefox-vnc

2、创建 Dockerfile 文件

bash

vim Dockerfile

文件内容

思考问题

为什么在一条 RUN 指令中执行两次 apt-get,而不是拆成两条 RUN 指令?

答:这是为了减少镜像层数。每一个RUN指令都会创建一个新的镜像层,而通过&&连接多个命令,可以在一个层中完成多个操作,从而减小最终镜像的大小。另外,将apt-get update和apt-get install放在同一个RUN命令中可以确保使用的是最新的软件包列表。

3、构建镜像

bash

docker build -t firefox-vnc .

4、查看镜像列表

5、启动容器

bash

docker run --rm -p 8080:8080 --name ff-vnc firefox-vnc
参数解释
  • --rm:容器停止运行后自动删除容器,避免占用磁盘空间
  • -p 8080:8080:将容器内部的8080端口映射到主机的8080端口,使外部能够访问容器内的VNC服务
  • --name ff-vnc:给容器指定一个易记的名称
  • firefox-vnc:使用的镜像名称

6、打开浏览器,输入 ip:8080/vnc.html

应用场景
这种镜像构建方式非常适合需要图形界面应用的场景,如自动化测试、远程桌面应用等。通过在容器中运行GUI应用并暴露VNC服务,用户可以在任何支持网页的设备上远程访问这些应用。

在这个任务中,我们将对比单阶段构建和多阶段构建的镜像大小差异,了解多阶段构建的优势。

1、创建项目目录

bash

mkdir /root/go
cd /root/go

2、创建一个名为 app.go 的文件,其内容如下:

go

package main
import "fmt"
func main() {
    fmt.Println("Hello World!")
}

3、创建 Dockerfile-1(多阶段构建)

bash

vim Dockerfile-1

文件内容如下:

2vqaUq

多阶段构建说明

上面的Dockerfile使用了多阶段构建:

  1. 第一阶段(builder):使用golang:alpine镜像编译Go应用程序
  2. 第二阶段:使用最小的alpine镜像,只复制第一阶段中编译好的可执行文件 这样可以大大减小最终镜像的大小,因为最终镜像中不包含编译工具和源代码。

4、构建镜像

i2km0e

5、查看镜像列表

XtnzUA

多阶段构建的镜像大小是 9.96 MB。

6、创建 Dockerfile-2 用来单阶段构建

uDsUCL

单阶段构建说明
这个Dockerfile使用单阶段构建,直接在golang:alpine镜像中编译和运行应用。最终的镜像将包含整个Go开发环境,包括编译器和工具链,这会大大增加镜像大小。

7、构建镜像,名为 go:v2

BuCPwo

8、查看镜像列表

txI370

分阶段构建的 go:v1 大小是 9.96MB,单阶段构建的 go:v2 大小是 406MB。

多阶段构建的优势
从结果可以清楚地看到,多阶段构建的镜像比单阶段构建的镜像小了40倍!多阶段构建特别适合编译型语言(如Go、Java、C++等),可以将构建环境与运行环境分离,最终只保留必要的运行文件,大大减小镜像体积,提高部署效率。

构建Docker镜像的三个核心原则:

  1. 选择满足需求的尽量小的父镜像:例如使用Alpine替代Ubuntu可以大幅减小镜像体积
  2. 尽量减少镜像层数:合并RUN命令,使用&&连接多个操作
  3. 使用多阶段构建:将构建环境与运行环境分离,只保留必要的产物
实践建议

遵循这些原则可以确保你的Docker镜像既高效又轻量,带来以下好处:

  • 更快的镜像拉取和部署速度
  • 更少的存储空间占用
  • 更小的攻击面,提高安全性
  • 更好的资源利用率

在实际项目中,应根据应用的具体需求,合理应用这些原则,构建出最适合你应用的Docker镜像。

相关内容