第 11 章:Docker 中使用
第 11 章:Docker 中使用
11.1 为什么在 Docker 中使用 BusyBox
11.1.1 容器镜像体积对比
| 基础镜像 | 大小 | 包含内容 |
|---|
busybox | ~1.2MB | BusyBox 静态二进制 + Applet |
alpine | ~5.6MB | BusyBox + apk 包管理器 + musl |
debian:slim | ~74MB | Debian 最小系统 |
ubuntu | ~77MB | Ubuntu 基础系统 |
centos | ~237MB | CentOS 基础系统 |
# 拉取并查看镜像大小
$ docker images
REPOSITORY TAG SIZE
busybox latest 1.24MB
alpine 3.19 5.61MB
debian slim 74.1MB
ubuntu 22.04 77.8MB
11.1.2 适用场景
| 场景 | 推荐镜像 | 原因 |
|---|
| 单一静态二进制 | busybox | 最小,只需 scratch |
| 需要包管理器 | alpine | 兼顾体积和灵活性 |
| Python/Node 应用 | alpine | 生态支持好 |
| 生产服务器 | debian:slim | 稳定性和兼容性 |
| 开发调试 | ubuntu | 工具齐全 |
11.2 使用 scratch 构建镜像
11.2.1 最小 BusyBox 镜像
# Dockerfile - 基于 scratch 的最小镜像
FROM scratch
# 复制静态编译的 BusyBox
COPY busybox /busybox
# 创建基本目录
RUN ["/busybox", "mkdir", "-p", "/bin", "/sbin", "/usr/bin", "/usr/sbin", \
"/tmp", "/proc", "/sys", "/dev", "/etc", "/var", "/root"]
# 创建符号链接
RUN ["/busybox", "--install", "-s"]
# 设置默认 Shell
CMD ["/bin/sh"]
# 编译静态 BusyBox
$ make defconfig
$ sed -i 's/# CONFIG_STATIC is not set/CONFIG_STATIC=y/' .config
$ make -j$(nproc)
# 构建镜像
$ docker build -t my-busybox .
# 查看大小
$ docker images my-busybox
REPOSITORY TAG SIZE
my-busybox latest 1.24MB
# 运行
$ docker run -it my-busybox
/ # ls
bin dev etc proc root sbin sys tmp usr var
/ # echo "Hello from BusyBox container!"
Hello from BusyBox container!
11.2.2 多阶段构建
# Dockerfile - 多阶段构建(从源码编译 BusyBox)
# 阶段一:编译
FROM ubuntu:22.04 AS builder
RUN apt-get update && \
apt-get install -y build-essential gcc make wget bzip2 && \
rm -rf /var/lib/apt/lists/*
ARG BUSYBOX_VERSION=1.36.1
RUN wget https://busybox.net/downloads/busybox-${BUSYBOX_VERSION}.tar.bz2 && \
tar xjf busybox-${BUSYBOX_VERSION}.tar.bz2 && \
cd busybox-${BUSYBOX_VERSION} && \
make defconfig && \
sed -i 's/# CONFIG_STATIC is not set/CONFIG_STATIC=y/' .config && \
make -j$(nproc) && \
make CONFIG_PREFIX=/output install
# 阶段二:运行时
FROM scratch
COPY --from=builder /output /
CMD ["/bin/sh"]
11.3 BusyBox 镜像进阶
11.3.1 包含应用的镜像
# Dockerfile - 运行 Go 应用的最小镜像
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /myapp .
# 运行时镜像
FROM busybox
COPY --from=builder /myapp /usr/local/bin/myapp
# 使用 mdev 设备管理
RUN mkdir -p /etc/init.d && \
echo '#!/bin/sh' > /etc/init.d/rcS && \
chmod +x /etc/init.d/rcS
EXPOSE 8080
USER nobody
CMD ["/usr/local/bin/myapp"]
11.3.2 包含 CA 证书的镜像
FROM scratch
# 从 builder 阶段复制 CA 证书
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY busybox /busybox
RUN ["/busybox", "--install", "-s"]
# 现在可以使用 HTTPS
RUN ["/bin/wget", "https://example.com"]
11.3.3 带配置文件的镜像
FROM busybox
# 复制应用和配置
COPY myapp /usr/local/bin/
COPY config.yml /etc/myapp/
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh /usr/local/bin/myapp
EXPOSE 8080
ENTRYPOINT ["/entrypoint.sh"]
CMD ["--config", "/etc/myapp/config.yml"]
11.4 Alpine Linux 对比
11.4.1 Alpine 简介
Alpine Linux 是一个基于 musl libc 和 BusyBox 的安全导向轻量级 Linux 发行版。
Alpine Linux = musl libc + BusyBox + apk 包管理器 + OpenRC init
11.4.2 详细对比
| 特性 | busybox | alpine |
|---|
| 大小 | ~1.2MB | ~5.6MB |
| 包管理器 | ✗ | apk |
| libc | 无(静态编译) | musl |
| Shell | ash | ash |
| 包数量 | 无 | 14000+ |
| init 系统 | BusyBox init | OpenRC |
| 适用场景 | 单一二进制 | 完整运行环境 |
| 安全更新 | ✗ | 定期更新 |
11.4.3 Alpine 使用
# Alpine 基础镜像
FROM alpine:3.19
# 安装软件包
RUN apk add --no-cache \
curl \
wget \
bash \
python3 \
nodejs
# 使用 apk 搜索包
# docker run -it alpine:3.19
/ # apk search python3
python3-3.11.6-r0
python3-dev-3.11.6-r0
...
11.4.4 选择建议
# 仅需要单一静态二进制 → busybox
FROM busybox
COPY myapp /myapp
CMD ["/myapp"]
# 需要运行时环境 → alpine
FROM alpine
RUN apk add --no-cache python3 py3-pip
COPY app.py /app.py
CMD ["python3", "/app.py"]
# 需要完整生态 → debian
FROM debian:slim
RUN apt-get update && apt-get install -y python3 python3-pip
11.5 Dockerfile 最佳实践
11.5.1 减小镜像体积
# 1. 使用多阶段构建
FROM golang:1.21 AS builder
RUN go build -ldflags="-s -w" -o /app .
FROM busybox
COPY --from=builder /app /app
# 2. 合并 RUN 指令
RUN mkdir -p /app && \
cp file1 /app/ && \
cp file2 /app/ && \
rm -rf /tmp/*
# 3. 使用 .dockerignore
# .dockerignore
.git
*.md
test/
vendor/
# 4. 清理包管理器缓存
RUN apk add --no-cache package # Alpine
RUN apt-get clean && rm -rf /var/lib/apt/lists/* # Debian
11.5.2 安全加固
FROM busybox
# 不以 root 运行
RUN adduser -D -u 1000 appuser
USER appuser
# 只读文件系统(运行时)
# docker run --read-only ...
# 限制资源
# docker run --memory=100m --cpus=0.5 ...
# 丢弃能力
# docker run --cap-drop=ALL ...
11.6 嵌入式容器方案
11.6.1 Docker on Embedded Linux
# 在 ARM 设备上运行 Docker
# 1. 安装 Docker
$ curl -fsSL https://get.docker.com | sh
# 2. 拉取 ARM 镜像
$ docker pull busybox:latest # 自动选择架构
# 3. 运行
$ docker run -it busybox
11.6.2 容器化嵌入式应用
# Dockerfile.arm32v7
FROM arm32v7/busybox:latest
COPY qemu-arm-static /usr/bin/
COPY myapp /usr/local/bin/
CMD ["/usr/local/bin/myapp"]
# 交叉构建镜像
$ docker buildx build --platform linux/arm/v7 -t myapp:arm32 .
11.6.3 Kubernetes 与 BusyBox
# debug-pod.yaml - 调试 Pod
apiVersion: v1
kind: Pod
metadata:
name: debug
spec:
containers:
- name: debug
image: busybox
command: ['sleep', '3600']
resources:
limits:
memory: "64Mi"
cpu: "100m"
restartPolicy: Never
# 创建调试 Pod
$ kubectl apply -f debug-pod.yaml
# 进入调试容器
$ kubectl exec -it debug -- /bin/sh
# 网络诊断
$ kubectl exec debug -- nslookup kubernetes.default
$ kubectl exec debug -- wget -qO- http://service:8080/health
11.7 实用 Docker 命令
# 交互式运行
$ docker run -it busybox /bin/sh
# 后台运行
$ docker run -d --name myapp busybox sleep 3600
# 进入运行中的容器
$ docker exec -it myapp /bin/sh
# 查看容器日志
$ docker logs myapp
# 复制文件
$ docker cp myapp:/etc/hosts ./hosts
# 容器导出为 tar
$ docker export myapp > myapp.tar
# 从 tar 导入镜像
$ docker import myapp.tar myapp:latest
# 查看容器资源使用
$ docker stats myapp
11.8 本章小结
| 概念 | 说明 |
|---|
| scratch | 空白基础镜像,适合静态二进制 |
| busybox | ~1.2MB,最小容器基础 |
| alpine | ~5.6MB,带包管理器 |
| 多阶段构建 | 编译和运行分离,减小镜像体积 |
| 安全 | 非 root 运行、只读文件系统、能力限制 |
扩展阅读
上一章: 第 10 章 — Buildroot 集成
下一章: 第 12 章 — 最佳实践