Docker入门与常用命令笔记
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 项目的容器及相关网络 |