admin 管理员组

文章数量: 1184232

一、Docker 是什么?​

Docker​ 是一个开源的容器化平台,它允许开发者将应用程序及其所有依赖项(库、系统工具、运行时等)打包成一个标准化的、轻量级的、可移植的单元,称为容器(Container)​

核心概念

概念说明类比
镜像 (Image)​一个只读的模板,包含了运行应用所需的文件系统结构和内容。相当于面向对象编程中的 ​​“类”​
容器 (Container)​镜像的一个运行实例。它是一个轻量级、可执行的软件包。相当于面向对象编程中的 ​​“对象”​
仓库 (Registry)​存放镜像的地方。最著名的是 ​Docker Hub​(公有),也可以搭建私有仓库(如 Harbor)。相当于代码仓库 ​GitHub
Dockerfile一个文本文件,包含了一系列指令,用于自动化构建镜像相当于软件项目的 ​构建脚本​(如 pom.xml)。

Docker 的优势

  1. 环境一致性​:解决了“在我这儿是好的”的问题。开发、测试、生产环境完全一致。
  2. 快速部署与扩展​:秒级启动,易于水平扩展和缩容。
  3. 隔离性​:容器之间相互隔离,互不影响,更安全。
  4. 轻量级​:共享主机内核,无需虚拟化整个操作系统,资源占用极小。
  5. ​ DevOps ​​:是实现 CI/CD(持续集成/持续部署)的关键技术。

二、Docker 常用命令

1. 生命周期管理

命令说明示例
docker run创建并启动一个新容器docker run -d -p 8080:80 --name mynginx nginx
docker start启动一个已停止的容器docker start mynginx
docker stop停止一个运行中的容器docker stop mynginx
docker restart重启容器docker restart mynginx
docker rm删除一个已停止的容器docker rm mynginx
docker exec在运行中的容器内执行命令docker exec -it mynginx /bin/bash

2. 信息查看

命令说明示例
docker ps查看正在运行的容器docker ps
docker ps -a查看所有容器(包括已停止的)docker ps -a
docker logs查看容器的日志输出docker logs mynginx
docker inspect获取容器/镜像的详细信息​(JSON格式)docker inspect mynginx
docker stats实时显示容器资源使用情况docker stats

3. 镜像管理

命令说明示例
docker images列出本地所有镜像docker images
docker pull从仓库拉取镜像docker pull nginx:latest
docker push将镜像推送到仓库docker push myrepo/myimage:tag
docker build构建镜像​(需要 Dockerfile)docker build -t myimage:tag .
docker rmi删除本地镜像docker rmi nginx

4. 常用参数详解

参数说明示例
-d后台运行​(Detached mode)docker run -d nginx
-it交互模式​(分配一个伪终端)docker run -it ubuntu /bin/bash
-p端口映射​(主机端口:容器端口)docker run -p 8080:80 nginx
-v数据卷挂载​(主机目录:容器目录)docker run -v /host/data:/container/data nginx
--name为容器指定一个名称docker run --name myapp nginx
-e设置环境变量docker run -e JAVA_OPTS="-Xmx512m" myapp

三、核心面试题与答案

基础概念题

1. Docker 和虚拟机的区别是什么?​
这是最经典的面试题,考察对容器本质的理解。

特性Docker 容器虚拟机 (VM)​
启动速度秒级分钟级
性能接近原生有损耗
硬盘占用MB 级GB 级
隔离性进程级别隔离操作系统级别隔离
安全性较弱(共享内核)更强(完全隔离)
Guest OS共享主机OS内核每个VM有自己的完整OS

2. 什么是 Docker 镜像?它的分层结构是什么意思?​

  • 镜像​:一个只读的模板,用于创建容器。
  • 分层存储​:镜像由一系列只读层(Layer)​​ 叠加而成。每一层是上一层的增量修改。这种设计使得镜像可以共享层,极大节省了存储空间和传输带宽。例如,多个基于 Ubuntu 的镜像可以共享同一个 Ubuntu 基础层。

分层例子:好处一:​节省空间(共享食材)​

假设你的朋友小王也要做一个三明治。他的步骤是:

  1. 拿一片面包(和你同一袋里的)

  2. 涂一层番茄酱

  3. 放一片火腿

  4. 盖上一片面包

问题:​​ 硬盘上会存两个一模一样的面包片吗?
不会!​​ 你们的“第一片面包”是一模一样的,所以系统只会存储一份​“面包层”,你们两个的三明治共享这一层。

Docker就是这样,所有基于 ubuntu 的镜像,都共享同一份 ubuntu 基础层,大大节省硬盘空间。

好处二:​构建飞快(缓存)​

第二天,你觉得煎蛋凉了不好吃,想重新做一个三明治,但这次把煎蛋换成火腿。

你的新步骤:

  1. 拿一片面包 -> ​和昨天一样!直接从冰箱里拿昨天的出来用!​

  2. 涂一层黄油 -> ​和昨天一样!直接用!​

  3. 放一片生菜 -> ​和昨天一样!直接用!​

  4. 放一片火腿​ -> ​这步改了!需要重新做

  5. 盖上一片面包 -> ​和昨天一样!直接用!​

你会发现,你只重新做了“放火腿”这一步,其他步骤直接用了昨天的现成的,所以做得非常快。


1. 镜像分层(Image Layers)​​:联合文件系统和写时复制实现

Docker镜像不是一个大文件,而是由一堆只读的(read-only)层叠加起来的。每一条Dockerfile指令(如RUNCOPYADD)都会创建一个新的层。

2. 联合文件系统(Union File System)​

这是一个​“粘合剂”​,它允许你将多个目录(层)​透明地叠加(union)​​ 起来,形成一个统一的视图。从用户角度看,好像只有一个完整的文件系统,而实际上它由多层组成。

3. 写时复制(Copy-on-Write, CoW)​

这是一个​“省空间、提速的魔法”​。它保证了:

  • 读操作​:所有容器共享底层镜像的同一份数据,极度节省空间。

  • 写操作​:当容器需要修改文件时,才把文件从只读的镜像层复制到可写的容器层,然后修改。这个过程对用户是透明的。


二、工作流程详解

联合文件系统如何工作?

它的核心思想是分层(Layers)​​ 和写时复制(Copy-on-Write, CoW)​

1. 分层(Layers)

一个Docker镜像不是一个大文件,而是由一系列只读的层(Layer)组成的。

  • 基础层(Base Layer)​​:通常是一个最小化的操作系统(如Alpine Linux、Ubuntu)。

  • 增量层(Incremental Layers)​​:每一行Dockerfile指令都会创建一个新的层。

    • RUN apt-get install -y curl → 创建一个包含curl的新层。

    • COPY . /app → 创建一个包含你的代码的新层。

    • ENV KEY=VALUE → 创建一个包含环境变量元数据的层。

这些层像搭积木一样堆叠起来,下层的文件可以被上层覆盖。最终用户看到的是一个统一的文件系统。

2. 写时复制(Copy-on-Write, CoW)

这是联合文件系统的性能关键。​所有镜像层都是只读的。​

  • 当启动一个容器时​:Docker会在所有镜像层之上添加一个可写的容器层(Container Layer)​

  • 当容器要读取文件时​:直接从底下的某个镜像层读取,非常高效。

  • 当容器要修改文件时(即使是删除)​​:

    1. 联合文件系统会从上往下寻找这个文件。

    2. 如果文件在某个只读层中存在,系统会先将这个文件复制到最顶层的可写层中。

    3. 然后,所有的修改都只发生在可写层中。

    4. 从此以后,读取这个文件都会从可写层中读取,屏蔽了下层的老文件。


3. Dockerfile 中的 COPY 和 ADD 指令有什么区别?​

  • COPY:​将本地文件或目录复制到镜像中。
  • ADD:在 COPY 的基础上,增加了:
    • 解压缩功能(自动解压 tar.gz 等压缩包)
    • 支持从 URL 下载文件(但不推荐,下载后无法自动解压且无法清除缓存)
  • 最佳实践​:除非需要解压,否则一律使用 COPY,因为它更透明、可预测。

实战操作题

4. 如何进入一个正在运行的 Docker 容器?​
两种主要方式:

  1. docker exec -it <container_name> /bin/bash (最常用)
  2. docker attach <container_name> (不推荐,退出会导致容器停止)

5. 如何查看 Docker 容器的日志?​

  • docker logs <container_name>:查看历史日志
  • docker logs -f <container_name>:​实时跟踪(Follow)​​ 日志输出,类似 tail -f
  • docker logs --tail 100 <container_name>:查看最后100行日志

6. 如何清理 Docker 占用的磁盘空间?​

  • docker system prune:清理停止的容器、未被使用的网络、构建缓存和 dangling 镜像
  • docker system prune -a:​更彻底地清理,包括所有未被容器使用的镜像(慎用!)。

高级原理题

7. Docker 是如何实现资源隔离的?​
Docker 主要利用 Linux 内核的多种技术:

  • Namespaces​:实现进程、网络、文件系统、用户等隔离​(pid, net, mnt, user...)。
  • Cgroups (Control Groups)​​:实现资源限制​(CPU、内存、磁盘I/O等)。
  • Union File Systems​:实现镜像的分层结构​(如 Overlay2)。

8. 在 Docker 中,如何配置容器的资源限制?​
使用 docker run 时的参数:

  • -m 或 --memory:限制内存(如 -m 512m
  • --memory-swap:限制内存+交换分区
  • --cpus:限制CPU核心数(如 --cpus="1.5"
  • --cpu-shares:设置CPU份额(相对权重)

9. Docker 网络模式有哪几种?​

  • bridge:​默认模式,为每个容器分配IP,通过网桥与外部通信。
  • host:容器直接使用主机网络栈,性能最好,但隔离性最差。
  • none:禁用网络。
  • container:<name|id>:容器共享另一个容器的网络命名空间。

10. 什么是数据卷(Volume)?为什么推荐使用它?​

  • 数据卷​:是存在于一个或多个容器中的特殊目录,它绕过了联合文件系统,可以提供持久化存储数据共享
  • 为什么推荐​:
    • 数据持久化​:容器被删除后,数据卷不会被删除。
    • 性能​:绕过文件系统,读写性能接近原生。
    • 方便共享​:多个容器可以挂载同一个数据卷。

四、docker上传自己的jar包

1. 创建 Dockerfile

作用:创建 Dockerfile来定义如何构建你的应用镜像:

# 使用官方 OpenJDK 运行时作为父镜像
FROM openjdk:11-jre-slim

# 设置工作目录
WORKDIR /app

# 将 jar 文件复制到容器中
COPY target/myapp-1.0.0.jar app.jar

# 暴露端口(根据你的应用调整)
EXPOSE 8080

# 设置 JVM 参数(可选)
ENV JAVA_OPTS="-Xmx512m -Xms256m"

# 运行 jar 文件
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

2. docker-compose.yml

作用:定义镜像如何运行为容器,包括网络、端口、环境变量、依赖服务等运行时配置。

version: '3.8'
services:
  my-app:
    build: .
    ports:
      - "8080:8080"
    environment:
      - DB_URL=jdbc:mysql://db:3306/app
    depends_on:
      - mysql
    networks:
      - app-network

五、总结

掌握 Docker 的关键在于:

  1. 理解核心概念​:镜像、容器、仓库。
  2. 熟练常用命令​:run, ps, stop, exec, logs, build
  3. 理解其底层原理​:与虚拟机的区别、分层存储、资源隔离。
  4. 掌握实战技巧​: Dockerfile 编写、数据卷使用、网络配置、资源限制。

Docker 是现代软件开发和运维的基石,深入理解它对于任何技术岗位都至关重要。

用法:例如一个项目需要MySQL,nginx,zookeeper,先拉取这三者的镜像,然后启动三个容器。

本文标签: 命令 概念 docker