大家好,我是大华!
在后端和运维领域,Docker 几乎已经成了绕不开的技术。 面试在问,同事在用,越来越多的开源项目也默认提供了 Docker 一键部署方案。
那 Docker 到底解决了什么问题? 为什么现在的部署项目,大家都会优先选择它?
这篇文章,我想从一个新手的视角,把 Docker 讲清楚。
一、Docker是什么?
简单比喻
假设你要搬家:
- 传统方式:家具要拆、线路要拔、到新家后再一件件装回去,装的时候还可能发现:少了某个零件、接口不对、怎么都摆不回原样。
- Docker方式:直接把整个房间拍个快照,家具、布置、电器、位置全都封装好。到新家一键还原,跟原来一模一样。
Docker 做的,就是这件事。它把一个应用运行所需要的所有东西,代码、运行环境、依赖、配置,一次性打包成一个标准化的箱子。
不管你把这个箱子搬到哪里,只要能打开,它的表现永远一致。
专业解释
Docker是一个容器化平台,让开发者可以:
- 把应用程序及其所有依赖项(库、环境变量、配置文件)打包在一起
- 在任何支持 Docker 的机器上运行,保证环境一致
- 从而实现一次构建,到处运行
二、Docker有什么用?
1. 开发人员的痛点
开发者小明说:“在我电脑上运行好好的!”
运维人员回复:“在服务器上就是跑不起来!”
原因排查:
- 操作系统不同(Windows vs Linux)
- Node.js版本不同(12.x vs 14.x)
- 依赖库版本冲突
- 环境变量配置不同
- 文件路径不一致
最后你会发现,问题不是代码,而是环境。
Docker 出现的意义,就是把环境这件事彻底消灭。
2. 快速部署
传统部署:装系统、装运行环境、配环境变量再到装依赖等等,顺利的话,也要一两个小时。
Docker部署:下载镜像、运行容器,几分钟就能完成。
3. 资源节省
很多人会拿 Docker 和虚拟机做对比。
虚拟机的方式:每个应用自带一整套操作系统,占用动不动就是几个 GB
Docker 的方式:容器之间共享宿主机系统,只保留应用真正需要的东西,通常是 MB 级别。
你可以理解为:
- 虚拟机:每个项目都自己买一套房
- Docker:很多项目住在同一栋楼里,各自一间房
三、Docker 的四个核心概念
Docker 的核心概念其实非常少。
如果只用一句话来概括:Docker 用镜像准备环境,用容器运行程序。
1、镜像(Image)
镜像就是运行环境的模板。
它里面已经准备好了系统、运行时以及应用需要的依赖,但镜像本身是不能直接运行的,更像一个安装包。比如 node:18、openjdk:17、mysql:8,都是现成可以用的镜像。
2、容器(Container)
容器是镜像运行之后的样子。
镜像是静态的,容器是正在运行的。你平时对应用做的启动、停止、删除、查看日志,操作的其实都是容器。一个镜像可以同时启动多个容器,这也是 Docker 能跑多个实例的原因。
3、Dockerfile
Dockerfile 用来告诉 Docker,这个镜像该怎么做。
它是一个普通文本文件,里面写清楚:用什么基础镜像、代码放在哪里、要不要安装依赖,以及程序最终如何启动。想定制自己的镜像,就必须有 Dockerfile。
4、仓库(Docker Hub)
Docker Hub 是镜像的来源。
它就像一个应用商店,存放着大量官方和社区维护的镜像。
Dockerfile 里写的 FROM node:18,意思就是:从 Docker Hub 拉取一个 Node 18 的镜像作为基础环境。
把这几个概念串起来就是一句话:Dockerfile 用来构建镜像,镜像用来创建容器,而镜像通常来自 Docker Hub。
四、安装Docker(以 Ubuntu 为例)
下面以 Ubuntu 20.04 / 22.04 为例,介绍最常见、也是最稳妥的安装方式。
步骤 1:更新系统并安装基础依赖
sudo apt update
sudo apt install -y ca-certificates curl gnupg lsb-release
这些工具主要用来安全地添加 Docker 官方仓库。
步骤 2:添加 Docker 官方 GPG Key
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
步骤 3:添加 Docker 官方软件源
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
步骤 4:安装 Docker 引擎
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
步骤 5:验证是否安装成功
docker --version
sudo docker run hello-world
如果看到:
Hello from Docker!
说明 Docker 已经在你的 Ubuntu 服务器上成功运行。
(可选)步骤 6:非 root 用户运行 Docker
默认情况下,Docker 需要 sudo 权限。如果你不想每次都加 sudo,可以执行:
sudo usermod -aG docker $USER
然后 退出当前终端重新登录,再测试:
docker ps
能正常执行,说明配置成功。
五、常用的Docker命令
基础命令
# 查看版本
docker --version
# 查看所有命令
docker --help
# 查看运行中的容器
docker ps
# 查看所有容器(包括停止的)
docker ps -a
# 查看本地镜像
docker images
# 下载镜像(从Docker Hub)
docker pull 镜像名:标签
# 示例:docker pull node:14
# 运行容器
docker run [选项] 镜像名
# 示例:docker run -it ubuntu bash
# 停止容器
docker stop 容器ID或名字
# 删除容器
docker rm 容器ID或名字
# 删除镜像
docker rmi 镜像ID或名字
常用选项
# -d:后台运行(守护进程模式)
docker run -d nginx
# -p:端口映射(主机端口:容器端口)
docker run -p 8080:80 nginx
# -v:挂载卷(主机目录:容器目录)
docker run -v /home/data:/app/data nginx
# --name:给容器起名字
docker run --name my_nginx nginx
# -it:交互模式运行
docker run -it ubuntu bash
六、部署Java项目(Spring Boot示例)
项目结构(Windows 本地)
my-java-app/
├── src/ # 源代码
├── pom.xml # Maven 配置文件
└── Dockerfile # Docker 构建文件
步骤1:编写 Dockerfile(Windows 本地)
在项目根目录下创建 Dockerfile:
# 使用官方 Java 运行环境作为基础镜像
FROM openjdk:11-jre-slim
# 设置容器内工作目录
WORKDIR /app
# 复制 Spring Boot 打包后的 jar 文件
COPY target/myapp.jar app.jar
# 暴露端口(Spring Boot 默认 8080)
EXPOSE 8080
# 启动应用
ENTRYPOINT ["java", "-jar", "app.jar"]
⚠️ 注意: Dockerfile 中的路径是 容器内路径,和 Windows / Linux 本机路径无关。
步骤2:Windows 本地打包项目
在 Windows 本地开发环境 执行:
# 进入项目目录
cd my-java-app
# 使用 Maven 打包(生成 target/myapp.jar)
mvn clean package
执行完成后,确认文件存在:
target/myapp.jar
步骤3:将项目传到 Linux 服务器
方式一:使用 scp(推荐)
在 Windows 终端(PowerShell / Git Bash)中执行:
scp -r my-java-app user@服务器IP:/home/user/
示例:
scp -r my-java-app root@123.456.78.90:/root/
步骤4:Linux 服务器上构建 Docker 镜像
登录 Linux 服务器后执行:
cd my-java-app
构建镜像:
docker build -t my-java-app:1.0 .
查看镜像是否构建成功:
docker images
步骤5:在 Linux 上运行容器
docker run -d \
-p 8080:8080 \
--name java-app \
my-java-app:1.0
查看容器状态:
docker ps
查看日志:
docker logs java-app
步骤6:访问应用
http://123.456.78.90:8080
七、部署Node.js项目(Express示例)
项目结构(Windows 本地)
my-node-app/
├── src/
├── package.json
├── server.js
└── Dockerfile
步骤1:编写 Dockerfile(Windows 本地)
在项目根目录创建 Dockerfile:
# 使用官方 Node.js 运行环境
FROM node:18-alpine
# 设置容器工作目录
WORKDIR /app
# 复制依赖配置文件
COPY package*.json ./
# 安装依赖
RUN npm install --production
# 复制项目代码
COPY . .
# 暴露端口
EXPOSE 3000
# 启动应用
CMD ["node", "server.js"]
步骤2:将项目上传到 Linux 服务器
方式一:scp 传输(推荐)
在 Windows 终端执行:
scp -r my-node-app user@服务器IP:/home/user/
例如:
scp -r my-node-app root@123.456.78.90:/root/
步骤3:Linux 服务器构建镜像
登录 Linux 服务器:
cd my-node-app
构建镜像:
docker build -t my-node-app:1.0 .
查看镜像:
docker images
步骤4:运行容器
docker run -d \
-p 3000:3000 \
--name node-app \
my-node-app:1.0
查看运行状态:
docker ps
查看日志:
docker logs node-app
步骤5:访问应用
http://服务器IP:3000
可选:多阶段构建优化版(推荐生产环境)
# 构建阶段
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# 运行阶段
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
八、同时部署 Java + Node + MySQL
这里使用的是 Docker Compose,Docker Compose 是用一个配置文件,统一管理多个 Docker 容器的工具。
场景说明
服务器部署结构:
Linux服务器
├── MySQL
├── Spring Boot 后端
└── Node 前端
步骤1:服务器准备目录结构
在 Linux 服务器创建:
project/
├── docker-compose.yml
├── java-backend/
└── node-frontend/
把两个项目代码分别上传进去。
步骤2:创建 docker-compose.yml
version: '3.8'
services:
mysql:
image: mysql:8.0
container_name: mysql
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: mydb
MYSQL_USER: user
MYSQL_PASSWORD: password
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
networks:
- app-network
java-backend:
build: ./java-backend
container_name: java-backend
ports:
- "8080:8080"
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/mydb
SPRING_DATASOURCE_USERNAME: user
SPRING_DATASOURCE_PASSWORD: password
depends_on:
- mysql
networks:
- app-network
node-frontend:
build: ./node-frontend
container_name: node-frontend
ports:
- "3000:3000"
environment:
API_URL: http://java-backend:8080
depends_on:
- java-backend
networks:
- app-network
networks:
app-network:
driver: bridge
volumes:
mysql-data:
步骤3:启动所有服务(Linux 服务器执行)
docker compose up -d
新版本 Docker 推荐 docker compose,老版本使用 docker-compose。
查看运行状态:
docker compose ps
查看日志:
docker compose logs -f
停止服务:
docker compose down
步骤4:访问系统
node访问
http://服务器IP:3000
java访问
http://服务器IP:8080
MySQL 连接地址
服务器IP:3306
九、实用的几个常用命令
1. 进入运行中的容器
# 进入容器内的bash
docker exec -it 容器名 bash
# 在容器内执行命令
docker exec 容器名 ls /app
2. 查看容器资源使用
docker stats
3. 清理无用资源
# 删除所有停止的容器
docker container prune
# 删除所有未被使用的镜像
docker image prune
# 删除所有未被使用的网络
docker network prune
# 一键清理所有
docker system prune -a
4. 查看镜像构建历史
docker history 镜像名
5. 备份和恢复
# 备份镜像到文件
docker save -o myapp.tar myapp:1.0
# 从文件恢复镜像
docker load -i myapp.tar
写在最后
如果你是第一次接触 Docker,看到这里可能还是有点懵,这很正常。
等你哪天真的把一个项目从本地跑到服务器上,用 Docker 一次性拉起来的时候,那种终于搞定了的感觉,会非常明显。
本文首发于公众号:程序员大华,专注前端、Java开发,AI应用和工具的分享。关注我,少走弯路,一起进步!