文章摘要

这篇文章详细介绍了Docker镜像的基本概念、创建和管理方法。内容包括Docker镜像的定义、镜像与容器的关系、如何使用Dockerfile创建自定义镜像,以及常用的Docker镜像命令。文章还讲解了如何从Docker Hub拉取镜像、查看本地镜像列表、删除镜像等操作。通过实例和命令行示例,帮助读者深入理解和掌握Docker镜像的使用,适合初学者和有一定基础的用户参考学习。

介绍

Docker 镜像(Docker Image)是一个轻量级、独立、可执行的软件包,它包含了运行某个应用程序所需的所有内容,包括代码、运行时、库、环境变量和配置文件。Docker 镜像是 Docker 容器的基础,容器是镜像的运行实例。(类似面向对象里面的类和对象)

原理

Docker 镜像的原理基于几个关键技术,包括分层文件系统、联合文件系统(UnionFS)和存储驱动。

1.分层文件系统

Docker 镜像由多个只读层组成,每一层代表镜像的一个版本。每次对镜像进行修改时,都会创建一个新的层,而不是修改现有的层。这种分层结构带来了以下好处:

  • 共享和复用:多个镜像可以共享相同的基础层,从而节省存储空间。
  • 高效构建:构建镜像时,只需要构建发生变化的层,未变化的层可以直接复用。
  • 快速分发:镜像的分发可以按层进行,只需要传输新增或修改的层。

2. 联合文件系统(UnionFS)

联合文件系统(UnionFS)是一种文件系统服务,它可以将多个目录(称为分支)联合挂载到一个单一的目录结构中。Docker 使用 UnionFS 来实现镜像的分层结构。常见的 UnionFS 实现包括 AUFS、OverlayFS 和 Btrfs。

3. 存储驱动

Docker 使用存储驱动来管理镜像和容器的存储。不同的存储驱动实现了不同的 UnionFS,常见的存储驱动包括:

  • AUFS:Advanced Multi-Layered Unification Filesystem,是 Docker 最早使用的存储驱动之一。
  • OverlayFS:一个现代的联合文件系统,性能较好,支持多层叠加。
  • Btrfs:一个现代的文件系统,支持快照和子卷。
  • Device Mapper:基于块设备的存储驱动,支持精细的存储管理。
  • ZFS:一个高性能的文件系统,支持快照和压缩。

镜像的种类

操作系统镜像

这些镜像提供了一个基本的操作系统环境,适合需要从零开始构建应用的场景。

  • Ubuntu:FROM ubuntu:latest
  • Debian:FROM debian:latest
  • Alpine(一个非常小的 Linux 发行版,适合需要最小化镜像大小的场景):FROM alpine:latest
  • CentOS:FROM centos:latest

编程语言运行时镜像

这些镜像包含了特定编程语言的运行时环境,适合需要运行特定语言应用的场景。

  • Node.js:FROM node:14
  • Python:FROM python:3.9
  • Java:FROM openjdk:11
  • Go:FROM golang:1.16
  • Ruby:FROM ruby:2.7

应用服务器镜像

这些镜像包含了常见的应用服务器,适合需要运行特定类型应用的场景。

  • Nginx:FROM nginx:latest
  • Apache HTTP Server:FROM httpd:latest
  • Tomcat:FROM tomcat:9.0

数据库镜像

这些镜像包含了常见的数据库系统,适合需要运行数据库服务的场景。

  • MySQL:FROM mysql:8.0
  • PostgreSQL:FROM postgres:13
  • MongoDB:FROM mongo:4.4
  • Redis:FROM redis:6.2

特定应用镜像

这些镜像包含了特定应用的预配置环境,适合需要快速部署特定应用的场景。

  • WordPress:FROM wordpress:latest
  • Jenkins:FROM jenkins/jenkins:lts
  • Elasticsearch:FROM elasticsearch:7.10.1

工具和实用程序镜像

这些镜像包含了常见的开发工具和实用程序,适合需要在容器中运行特定工具的场景。

  • BusyBox(一个小型的 Unix 工具集):FROM busybox:latest
  • Curl:FROM curlimages/curl:latest
  • Git:FROM alpine:latestRUN apk add –no-cache git

多阶段构建镜像

多阶段构建允许你在一个 Dockerfile 中使用多个 FROM 指令,以减少最终镜像的大小。

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

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

查找和选择镜像

你可以在 Docker Hub 上查找各种官方和社区提供的镜像。Docker Hub 是一个公共的镜像仓库,包含了大量的预构建镜像。

构建过程

镜像的构建过程通常通过 Dockerfile 来定义。Dockerfile 是一个包含一系列指令的文本文件,这些指令定义了如何构建镜像。以下是一个简单的 Dockerfile 示例:

# 使用官方的 Node.js 镜像作为基础镜像
FROM node:14

# 创建应用目录
WORKDIR /usr/src/app

# 复制 package.json 和 package-lock.json
COPY package*.json ./

# 安装应用依赖
RUN npm install

# 复制应用代码
COPY . .

# 暴露应用运行的端口
EXPOSE 8080

# 启动应用
CMD ["node", "app.js"]

使用 docker build 命令可以根据 Dockerfile 构建 Docker 镜像。以下是构建镜像的命令示例:

docker build -t my-node-app .

构建过程中的每一条指令都会创建一个新的镜像层。例如:

  • FROM node:14:下载并使用 Node.js 官方镜像作为基础层。
  • WORKDIR /usr/src/app:创建一个新的层,设置工作目录。
  • COPY package*.json ./:创建一个新的层,复制 package.json 和 package-lock.json 文件。
  • RUN npm install:创建一个新的层,安装应用依赖。
  • COPY . .:创建一个新的层,复制应用代码。
  • EXPOSE 8080:创建一个新的层,暴露端口。
  • CMD ["node", "app.js"]:设置容器启动时的默认命令。

镜像的运行

当你运行一个 Docker 容器时,Docker 会从镜像中创建一个新的可写层,称为容器层。容器层位于镜像层之上,所有对文件系统的修改(如写入、删除文件)都会发生在容器层,而不会影响底层的只读镜像层。

docker run -d -p 8080:8080 --name my-running-app my-node-app

这条命令会启动一个容器,并将主机的 8080 端口映射到容器的 8080 端口。

镜像的存储和分发

Docker 镜像可以存储在公共或私有的镜像仓库中。常见的镜像仓库包括:

  • Docker Hub:Docker 官方提供的公共镜像仓库,包含大量的官方和社区提供的镜像。
  • 私有镜像仓库:公司内部可以搭建私有镜像仓库,如 Docker Registry、Harbor、Nexus Repository、Artifactory 等。

使用 docker push 命令可以将镜像推送到镜像仓库:

docker push my-node-app

使用 docker pull 命令可以从镜像仓库拉取镜像:

docker pull my-node-app

搭建私有镜像仓库

为了安全和高效地管理公司内部的 Docker 镜像,建议使用私有镜像仓库。常见的私有镜像仓库解决方案包括:

  • Docker Hub 私有仓库:Docker Hub 提供私有仓库服务,但需要付费。
  • Harbor:一个开源的企业级 Docker 镜像仓库,支持镜像管理、访问控制和安全扫描。
  • Nexus Repository:一个支持多种格式(包括 Docker)的仓库管理工具。
  • Artifactory:一个通用的包管理工具,支持 Docker 镜像管理。

以下是使用 Docker Registry 搭建私有镜像仓库的示例:

安装 Docker Registry

首先,使用 Docker 官方的 registry 镜像启动一个私有镜像仓库:

docker run -d -p 5000:5000 --name registry registry:2

推送镜像到私有仓库

构建一个自定义镜像并推送到私有仓库:

# 构建镜像
docker build -t my-app:latest .

# 标记镜像
docker tag my-app:latest localhost:5000/my-app:latest

# 推送镜像到私有仓库
docker push localhost:5000/my-app:latest

从私有仓库拉取镜像

从私有仓库拉取镜像并运行容器:

# 拉取镜像
docker pull localhost:5000/my-app:latest

# 运行容器
docker run -d -p 8080:8080 localhost:5000/my-app:latest

配置安全性

为了确保私有镜像仓库的安全性,建议配置身份验证和 TLS 加密。

配置身份验证

可以使用 htpasswd 工具生成用户名和密码文件:

docker run --rm --entrypoint htpasswd registry:2 -Bbn myuser mypassword > auth/htpasswd

然后,修改 Docker Registry 的配置文件,启用身份验证:

# config.yml
version: 0.1
log:
  fields:
    service: registry
storage:
  filesystem:
    rootdirectory: /var/lib/registry
http:
  addr: :5000
  secret: asecretforlocaldevelopment
  headers:
    X-Content-Type-Options: [nosniff]
  auth:
    htpasswd:
      realm: basic-realm
      path: /auth/htpasswd

启动 Docker Registry 并挂载配置文件和认证文件:

docker run -d -p 5000:5000 --name registry \
  -v $(pwd)/auth:/auth \
  -v $(pwd)/config.yml:/etc/docker/registry/config.yml \
  registry:2

配置 TLS 加密

生成自签名证书或使用受信任的证书颁发机构(CA)生成证书,然后配置 Docker Registry 使用 TLS:

docker run -d -p 5000:5000 --name registry \
  -v $(pwd)/auth:/auth \
  -v $(pwd)/certs:/certs \
  -v $(pwd)/config.yml:/etc/docker/registry/config.yml \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
  -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
  registry:2

总结

Docker 镜像是一个轻量级、独立、可执行的软件包,包含了运行应用程序所需的所有内容。Docker 镜像基于分层文件系统和联合文件系统(UnionFS)构建,使用存储驱动来管理镜像和容器的存储。通过 Dockerfile 可以定义镜像的构建过程,使用 docker build 命令构建镜像,使用 docker run 命令运行容器。Docker 镜像可以存储在公共或私有的镜像仓库中,方便分发和部署。