Docker入门与常用命令笔记

O泡李华 6

Docker 入门笔记:核心概念、常用命令与 Spring Boot 部署

开发项目时,经常会遇到环境差异:本地使用 Java 17,服务器却使用其他版本;同事安装的数据库版本不同;新机器需要重新配置一遍依赖。

Docker 可以将应用和所需的运行环境打包成镜像,通过容器运行,方便分发和部署。本文介绍 Docker 的基本概念,并通过 Nginx 和 Spring Boot 示例说明常见操作。

一、Docker 是什么

Docker 是用于打包、运行和部署应用的工具。它把应用及其所需的运行环境装进镜像,再通过容器运行起来。

例如,一个 Spring Boot 项目需要 Java 17。使用 Docker,可以将应用和 Java 运行环境一起打包,让其他人或服务器使用相同的环境运行,减少环境差异带来的问题。Docker 官方介绍

假设项目需要:

Spring Boot 应用
Java 17
MySQL
Redis

传统方式需要分别安装和配置这些软件。使用 Docker 后,可以让应用、MySQL 和 Redis 分别在容器中运行,方便统一版本、启动和管理。

常见用途包括:

  • 搭建开发环境:快速运行数据库、缓存等服务。
  • 部署应用:通过镜像分发应用及其运行环境。
  • 自动化测试:为测试创建一致的环境。

配置、网络、数据和硬件架构仍需要匹配,Docker 不会自动解决所有环境问题。

二、镜像、容器与镜像仓库

概念 含义 类比
镜像 Image 创建容器的只读模板,包含应用和运行所需文件 安装包
容器 Container 根据镜像创建的运行实例 安装后正在运行的程序
镜像仓库 Registry 存储和分发镜像的地方 安装包下载站

它们的关系是:

镜像仓库 ──下载──→ 镜像 ──创建并启动──→ 容器

**一个镜像可以创建多个容器。**例如,用同一个 Nginx 镜像创建两个容器,分别运行两个网站服务。

Docker Hub 是常见的公共镜像仓库,也可以使用团队自己的镜像仓库。官方概念说明

镜像标签是什么

镜像名称可以带标签,例如:

nginx:stable
my-app:1.0

冒号后面是标签,用来区分版本或变体。stable 等标签可能随着发布更新,标签并不保证内容永远不变。需要严格复现时,应进一步固定镜像摘要。

三、Docker 与虚拟机的区别

虚拟机运行一套独立的操作系统,包括自己的内核。容器主要隔离应用进程,并共享运行它的内核,因此通常启动更快、额外开销更小。

对比项 容器 虚拟机
隔离对象 应用进程及其运行环境 整套操作系统
内核 共享运行环境的内核 各虚拟机有自己的内核
启动与开销 通常更快、额外开销较小 通常开销较大

在 Windows 上运行 Linux 容器时,Docker Desktop 通常借助 Linux 虚拟化环境运行。因此,容器和虚拟机也可以配合使用。容器与虚拟机

四、运行第一个容器:Nginx

以下命令需要先安装并启动 Docker。桌面环境可以使用 Docker Desktop;具体安装要求以官方安装文档为准。

1. 检查 Docker 是否可用

docker version

正常情况下可以看到客户端和服务端的信息。如果只有客户端信息,并提示无法连接服务端,需要检查 Docker 引擎是否已经启动。

2. 启动 Nginx 容器

docker run -d --name demo-nginx -p 127.0.0.1:8080:80 nginx:stable

各参数含义:

参数 含义
run 创建并启动一个新容器
-d 在后台运行
--name demo-nginx 给容器命名
-p 127.0.0.1:8080:80 将本机的 8080 端口映射到容器的 80 端口
nginx:stable 使用 Nginx 镜像的 stable 标签

如果本地没有镜像,Docker 会尝试下载。首次运行需要能访问相应镜像仓库。

3. 在浏览器访问

启动成功后,在本机浏览器打开:

http://localhost:8080

预期能看到 Nginx 的默认页面。

端口映射的顺序是:

主机地址:主机端口:容器端口

这里绑定 127.0.0.1,使这个演示服务通过本机访问。省略主机地址时,端口通常会发布到主机的所有网络接口,需要根据实际访问需求设置。官方端口说明

五、Docker 常用命令

以下容器名称沿用前面的 demo-nginx。

1. 镜像操作

# 下载镜像
docker pull nginx:stable

# 查看本地镜像
docker image ls

# 删除指定本地镜像,需先处理引用它的容器
docker image rm nginx:stable

下载镜像不会自动启动容器,删除容器也不会自动删除镜像。

2. 查看容器

# 查看正在运行的容器
docker ps

# 查看所有容器,包括已经停止的
docker ps -a

输出中可以看到容器 ID、镜像、状态、端口和名称。

3. 查看日志

# 查看已有日志
docker logs demo-nginx

# 持续查看日志
docker logs -f demo-nginx

按 Ctrl+C 可以退出日志跟随,不会因此停止容器。该命令主要查看容器进程输出到标准输出和标准错误的日志。

4. 在容器中执行命令

docker exec -it demo-nginx sh

这会在正在运行的容器中启动一个交互式 Shell。输入 exit 退出该 Shell,一般不会停止容器的主进程。

exec 要求容器处于运行状态,而且指定的程序必须存在于镜像中;部分精简镜像没有 Shell。

5. 启动、停止与删除

# 停止容器
docker stop demo-nginx

# 启动已经存在的容器
docker start demo-nginx

# 重启容器
docker restart demo-nginx

# 删除容器,通常先停止
docker rm demo-nginx

需要分清这些操作:

  • docker run:创建并启动新容器。
  • docker start:启动已有容器。
  • docker stop:停止容器,容器仍然存在。
  • docker rm:删除容器。

再次执行相同名称的 docker run 时,如果旧容器仍然存在,会出现名称冲突。应启动旧容器、使用新名称,或在确认不需要旧容器后删除它。

六、数据持久化:Volume

容器自己的可写文件层会随容器删除而消失。数据库数据、上传文件等需要长期保留的内容,应使用数据卷 Volume或目录挂载。

例如,假设你已经构建了 my-app:1.0 镜像,应用会将数据写入容器的 /data 目录:

docker run -d --name my-app -v app-data:/data my-app:1.0

这里:

app-data:Docker 管理的命名数据卷
/data:容器内挂载的位置

如果数据卷不存在,Docker 会创建它。应用写入 /data 的内容会保存在卷中。

删除容器后,只要数据卷没有被删除,新容器再次挂载同一个卷,就能继续使用其中的数据。停止或重启同一个容器,本身不会清空它的文件层。官方数据持久化说明

查看数据卷:

docker volume ls

数据卷不能替代备份,重要数据仍需要独立备份。

七、使用 Dockerfile 打包 Spring Boot 项目

Dockerfile 是一个文本文件,描述构建镜像的步骤,例如选择运行环境、复制程序文件和指定启动命令。

1. 准备可执行 JAR

假设项目使用 Java 17,并且已经通过 Maven 打包出可执行的:

target/app.jar

实际 JAR 名称可能带项目名和版本号,需要对应修改 Dockerfile。

2. 编写 Dockerfile

在项目根目录创建名为 Dockerfile、没有扩展名的文件:

FROM eclipse-temurin:17-jre

WORKDIR /app

COPY target/app.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]

指令含义:

指令 作用
FROM 选择 Java 运行环境作为基础镜像
WORKDIR 设置容器内工作目录
COPY 将打包后的 JAR 放入镜像
EXPOSE 声明应用预期使用的端口
ENTRYPOINT 设置容器启动时执行的命令

**EXPOSE 只是声明端口,不会自动将端口映射到电脑上。**这是一个最小演示配置,实际部署还需要按项目要求设置运行用户、资源和配置。Dockerfile 官方说明

3. 构建镜像

在项目根目录执行:

docker build -t my-app:1.0 .
  • -t my-app:1.0:为镜像设置名称和标签。
  • 最后的 .:使用当前目录作为构建上下文。

这份 Dockerfile 只复制已有 JAR,不会自动编译项目。构建前必须确保 JAR 已生成。

4. 运行应用

docker run -d --name my-app -p 127.0.0.1:8080:8080 my-app:1.0

应用需要在容器内监听可供外部连接的地址和 8080 端口。

如果前面的 Nginx 容器仍占用主机 8080 端口,可将主机端口改成 8081:

docker run -d --name my-app -p 127.0.0.1:8081:8080 my-app:1.0

此时通过 http://localhost:8081 访问应用中实际存在的接口。如果项目接入了 Knife4j,可以访问:

http://localhost:8081/doc.html

如果应用配置了访问前缀,也需要将前缀加入地址。

上述命令展示预期操作流程,需要在实际项目中运行验证。代码修改后,要重新打包 JAR、构建镜像并更新容器,旧容器不会自动获得新代码。

八、多个服务一起管理:Docker Compose

当项目包含应用、数据库和缓存等多个服务时,可以使用 Docker Compose,通过 compose.yaml 描述各服务的镜像、端口、环境配置、网络和数据卷。

例如,将前面的 Nginx 演示配置写成:

services:
  web:
    image: nginx:stable
    ports:
      - "127.0.0.1:8080:80"

将文件保存为 compose.yaml,在该目录执行:

# 创建并在后台启动服务
docker compose up -d

# 查看服务状态
docker compose ps

# 查看日志
docker compose logs -f

# 停止并移除该项目的容器和相关网络
docker compose down

运行前应确认主机 8080 端口没有被其他服务占用。

docker compose down 默认不会删除命名数据卷;增加 -v 会删除 Compose 管理的命名卷及附加的匿名卷,应先确认数据不再需要。

Compose 适合将一组服务的运行配置保存在文件中,供团队共享。Docker Compose 官方文档

九、常见问题排查

1. 无法连接 Docker 服务

检查 Docker Desktop 或 Docker 引擎是否已经启动,再执行:

docker version

2. 容器启动后很快退出

检查容器状态和日志:

docker ps -a
docker logs 容器名

容器通常在主进程退出后停止。应根据日志检查启动命令、配置文件、依赖连接等原因。

3. 浏览器无法访问服务

依次检查:

  • 容器是否正在运行。
  • 应用实际监听的端口与映射目标是否一致。
  • 主机端口是否正确,是否被其他程序占用。
  • 应用是否只监听容器内的回环地址。
  • 请求路径和访问前缀是否正确。

4. 容器连接不到数据库

**容器内的 localhost 通常指向容器自己。**如果数据库在另一个容器中,应通过合适的容器网络连接;在 Compose 中,通常使用数据库服务名作为主机名。

如果数据库在主机上,访问方式取决于 Docker 运行环境,不能直接将主机上的 localhost 配置原样照搬进容器。

5. 删除容器后数据丢失

检查应用的数据目录是否正确挂载到卷或主机目录,以及数据卷是否被清理。

十、常用命令速查

命令 用途
docker version 查看客户端与服务端版本信息
docker pull 镜像:标签 下载镜像
docker image ls 查看本地镜像
docker build -t 名称:标签 . 构建镜像
docker run ... 镜像 创建并启动新容器
docker ps 查看运行中的容器
docker ps -a 查看所有容器
docker logs 容器名 查看容器日志
docker exec -it 容器名 sh 在运行中的容器内打开 Shell,需镜像包含 sh
docker stop 容器名 停止容器
docker start 容器名 启动已有容器
docker restart 容器名 重启容器
docker rm 容器名 删除容器
docker volume ls 查看数据卷
docker compose up -d 启动 Compose 服务
docker compose down 移除 Compose 项目的容器及相关网络