这篇文章详细介绍了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 镜像可以存储在公共或私有的镜像仓库中,方便分发和部署。