Docker镜像原理以及制作新镜像的方法

发布时间:2021-07-05 17:02:25 作者:chen
来源:亿速云 阅读:264
# Docker镜像原理以及制作新镜像的方法

## 一、Docker镜像基础概念

### 1.1 什么是Docker镜像

Docker镜像(Image)是一个轻量级、可执行的独立软件包,包含运行某个软件所需的所有内容:
- 代码
- 运行时环境
- 系统工具
- 系统库
- 设置

镜像采用分层存储结构,这种设计使得镜像构建和分发变得极其高效。当使用`docker pull`或`docker run`命令时,实际上是在操作这些分层的镜像文件。

### 1.2 镜像与容器的关系

镜像与容器的关系可以类比为:
- **镜像**:类(Class)
- **容器**:实例(Instance)

当镜像被`docker run`命令启动时,Docker会在镜像的最上层添加一个可写层(容器层),所有对运行中容器的修改都发生在这个可写层中。

## 二、Docker镜像核心原理

### 2.1 联合文件系统(UnionFS)

Docker镜像采用联合文件系统实现分层存储,主要特点包括:

1. **分层结构**:每个镜像由多个只读层组成
2. **写时复制(CoW)**:修改文件时不会直接改变底层镜像,而是复制到可写层
3. **资源共享**:不同镜像可以共享相同的底层

常见的UnionFS实现:
- AUFS(早期默认)
- OverlayFS(当前主流)
- Device Mapper
- Btrfs
- ZFS

### 2.2 镜像分层示例

以Nginx官方镜像为例:

IMAGE ID CREATED SIZE LAYERS f6d0b4767a6c 2 weeks ago 133MB 6 layers


通过`docker history nginx`查看分层构建历史:

IMAGE CREATED CREATED BY SIZE f6d0b4767a6c 2 weeks ago /bin/sh -c #(nop) CMD [“nginx” “-g” “daemon… 0B 2 weeks ago /bin/sh -c #(nop) STOPSIGNAL SIGQUIT 0B 2 weeks ago /bin/sh -c #(nop) EXPOSE 80 0B 2 weeks ago /bin/sh -c ln -sf /dev/stdout /var/log/nginx… 22B 2 weeks ago /bin/sh -c set -x && apt-get update && apt-… 53.6MB 2 weeks ago /bin/sh -c #(nop) ENV NJS_VERSION=0.7.12 0B 2 weeks ago /bin/sh -c #(nop) ENV NGINX_VERSION=1.23.4 0B 2 weeks ago /bin/sh -c #(nop) LABEL maintainer=NGINX Do… 0B 4 weeks ago /bin/sh -c #(nop) CMD [“bash”] 0B 4 weeks ago /bin/sh -c #(nop) ADD file:29c72d5be8c977acaeb… 77.8MB


### 2.3 镜像内容寻址存储

现代Docker使用内容寻址存储(CAS)模型:
- 每个层都有唯一的加密哈希值(SHA256)
- 基于内容而非名称进行存储和检索
- 确保数据完整性

## 三、制作Docker镜像的四种方法

### 3.1 使用Dockerfile构建

这是最推荐的标准方法,Dockerfile示例:

```dockerfile
# 基于官方Python镜像
FROM python:3.9-slim

# 设置工作目录
WORKDIR /app

# 复制依赖文件
COPY requirements.txt .

# 安装依赖
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用代码
COPY . .

# 暴露端口
EXPOSE 8000

# 定义环境变量
ENV NAME World

# 容器启动命令
CMD ["python", "app.py"]

构建命令:

docker build -t my-python-app .

3.2 使用commit命令创建

从运行中的容器创建新镜像(适合调试场景):

# 启动临时容器
docker run -it ubuntu bash

# 在容器内执行修改
apt-get update && apt-get install -y curl

# 退出容器后提交
docker commit [CONTNER_ID] my-ubuntu-curl

注意:这种方法不利于维护和版本控制,建议仅用于临时调试。

3.3 使用export/import

将容器导出为归档文件再导入为新镜像:

# 导出容器
docker export [CONTNER_ID] > mycontainer.tar

# 导入为镜像
docker import mycontainer.tar my-imported-image

与commit的区别: - export/import不保留历史记录和元数据 - 生成的是扁平化镜像(单层)

3.4 多阶段构建(高级技巧)

适用于需要构建环境但不想增大最终镜像的场景:

# 第一阶段:构建环境
FROM golang:1.19 AS builder
WORKDIR /go/src/app
COPY . .
RUN go build -o myapp

# 第二阶段:运行环境
FROM alpine:latest
WORKDIR /root/
COPY --from=builder /go/src/app/myapp .
CMD ["./myapp"]

优势: - 最终镜像只包含运行所需内容 - 显著减小镜像体积(上例中从~1GB减少到~10MB)

四、镜像优化最佳实践

4.1 减小镜像体积

  1. 选择合适的基础镜像

    • Alpine Linux(~5MB)
    • Distroless镜像(仅含运行时)
  2. 合并RUN指令: “`dockerfile

    不推荐

    RUN apt-get update RUN apt-get install -y package1 RUN apt-get install -y package2

# 推荐 RUN apt-get update &&
apt-get install -y package1 package2 &&
rm -rf /var/lib/apt/lists/*


3. **使用.dockerignore文件**:
   避免复制不必要的文件到镜像中

### 4.2 提高构建速度

1. **利用构建缓存**:
   - 将变化频率低的指令放在前面
   - 避免`COPY . .`这样的全量复制

2. **使用构建工具包**:
   - BuildKit(Docker 18.09+默认启用)
   ```bash
   DOCKER_BUILDKIT=1 docker build .
  1. 多阶段构建: 避免在最终镜像中包含构建工具

4.3 安全实践

  1. 非root用户运行

    RUN groupadd -r appuser && \
       useradd -r -g appuser appuser
    USER appuser
    
  2. 定期更新基础镜像

    FROM alpine:3.18.2  # 使用具体版本号而非latest
    
  3. 扫描漏洞

    docker scan my-image
    

五、镜像分发与管理

5.1 标签管理

# 添加标签
docker tag my-image:1.0 my-registry.com/group/my-image:1.0

# 推送镜像
docker push my-registry.com/group/my-image:1.0

版本命名建议: - 语义化版本(SemVer) - 环境标签(dev/staging/prod) - Git commit SHA

5.2 私有Registry部署

  1. 使用Docker Registry官方镜像

    docker run -d -p 5000:5000 --name registry registry:2
    
  2. 带认证的Registry

    docker run -d \
     -p 5000:5000 \
     --name registry \
     -v /auth:/auth \
     -e "REGISTRY_AUTH=htpasswd" \
     -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
     -e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
     registry:2
    

5.3 镜像清理

# 查看磁盘使用
docker system df

# 删除悬空镜像
docker image prune

# 删除所有未使用镜像
docker image prune -a

六、高级镜像构建场景

6.1 构建参数(ARG)与环境变量(ENV)

ARG APP_VERSION=1.0
ENV APP_VERSION=${APP_VERSION}

# 构建时指定参数
# docker build --build-arg APP_VERSION=2.0 .

6.2 动态Dockerfile生成

使用heredoc语法:

docker build -t dynamic-image -<<EOF
FROM busybox
RUN echo "Built at $(date)" > /build-time.txt
EOF

6.3 跨平台构建

docker buildx create --use
docker buildx build --platform linux/amd64,linux/arm64 -t my-image .

七、常见问题排查

7.1 镜像构建失败

检查步骤: 1. 使用--no-cache排除缓存问题

   docker build --no-cache .
  1. 分阶段调试
    
    docker run -it [IMAGE_ID] bash
    

7.2 镜像体积异常

分析工具:

docker history [IMAGE]
docker inspect [IMAGE]
dive [IMAGE]  # 第三方镜像分析工具

7.3 镜像拉取问题

解决方法: 1. 检查网络和代理设置 2. 验证Registry认证

   docker login my-registry.com
  1. 尝试不同tag或digest
    
    docker pull my-image@sha256:45b23dee0...
    

结语

Docker镜像是容器化技术的核心组件,理解其分层原理和构建方法对于开发高效、安全的容器化应用至关重要。通过本文介绍的各种构建方法和优化技巧,开发者可以: - 创建更小的镜像(提高分发效率) - 构建更快的镜像(加速CI/CD流程) - 制作更安全的镜像(降低运行时风险)

随着容器技术的发展,建议持续关注: - 新一代构建工具(如Buildpacks) - 无root容器技术(如Rootless Docker) - 镜像签名与验证(Notary项目) “`

推荐阅读:
  1. Docker制作镜像
  2. docker镜像管理基础以及镜像的制作方法

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

docker

上一篇:Python中怎么利用多线程创建一个程序

下一篇:Python中怎么使用正则表达式匹配方法

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》