Docker部署步骤
为什么需要 Docker?
想象这样一个场景:你在自己的电脑上辛辛苦苦开发了一个 Web 应用,所有功能都跑得完美无缺。当你满怀信心地把它部署到服务器上时,却惊讶地发现——应用无法启动!经过一番排查,你发现服务器上的 Python 版本不对、依赖包没装全、配置文件位置不对……这种“在我电脑上明明是好的”的窘境,相信很多开发者都经历过。
Docker 的出现,就是为了解决这个“环境一致性问题”。它就像是一个神奇的“集装箱”,可以把你的应用和它所需要的运行环境一起打包。无论在哪个服务器上,只要对方有 Docker 这个“起重机”,就能确保你的应用运行得和在你电脑上一模一样。
今天,我们就来学习如何使用 Docker 部署一个 Web 应用。即使你是一个对 Docker 完全陌生的初学者,看完这篇文章后,你也能够独立完成应用的容器化部署。
一、Docker 基本概念:三个核心元素
在开始动手之前,我们先来理解 Docker 的三个核心概念。把 Docker 想象成一个物流系统,这三个概念就很好理解了:
1. 镜像(Image)—— 装箱单
镜像就像是集装箱的“装箱单”或者“蓝图”。它里面包含了运行一个应用所需的一切:代码、运行时环境(比如 Node.js、Python)、系统工具、库文件、配置等。镜像是一个只读的模板,你可以基于它创建多个完全相同的容器。
打个比方:镜像就像是蛋糕的配方,只要按照这个配方,你就能做出味道一模一样的蛋糕。
2. 容器(Container)—— 正在运行的集装箱
容器是镜像的一个运行实例。当你把镜像“运行”起来,它就变成了一个容器。容器是轻量级的、相互隔离的运行环境,每个容器都拥有自己独立的文件系统、网络和进程空间。
延续上面的比喻:容器就是按照配方做出来的那块蛋糕。你可以用同一个配方(镜像)做出很多块蛋糕(容器),每一块蛋糕都是独立存在的。
3. 仓库(Repository)—— 集装箱码头
仓库是存放镜像的地方,类似于代码仓库。最常用的公共仓库是 Docker Hub,你可以把制作好的镜像推送到仓库中,也可以从仓库中拉取别人制作好的镜像。
这就好比是码头上的集装箱堆场,你可以把做好的集装箱(镜像)存放在那里,也可以从那里取用别人放好的集装箱。
这三个概念的关系可以用一句话总结:从仓库拉取镜像,用镜像创建容器,容器运行你的应用。
二、准备工作:环境搭建
2.1 安装 Docker
在使用 Docker 之前,需要先在你的电脑上安装它。Docker 支持 Windows、macOS 和 Linux 系统。
Windows 用户:
-
访问 Docker 官网(docs.docker.com)下载 Docker Desktop for Windows
-
双击安装程序,按照提示完成安装
-
安装完成后,你可能需要重启电脑
macOS 用户:
-
同样从官网下载 Docker Desktop for Mac
-
将应用拖入“应用程序”文件夹即可
Linux 用户:
-
使用包管理器安装,以 Ubuntu 为例:
bash
复制 下载sudo apt update sudo apt install docker.io sudo systemctl start docker sudo systemctl enable docker
2.2 验证安装
安装完成后,打开终端(命令行),输入以下命令验证 Docker 是否安装成功:
bash
复制
下载
docker --version
如果看到类似 Docker version 24.0.7 的输出,说明安装成功了。
三、编写 Dockerfile:为你的应用“装箱”
Dockerfile 是一个文本文件,里面包含了构建镜像所需要的“配方”。我们来一步步学习如何编写它。
3.1 准备一个示例 Web 应用
首先,让我们创建一个简单的 Node.js Web 应用作为示例。在你的电脑上新建一个文件夹,命名为 my-web-app,然后创建以下两个文件:
app.js —— Web 应用的主文件:
javascript
复制
下载
const express = require('express');
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.send(`
<html>
<head>
<title>我的 Docker 应用</title>
<style>
body { font-family: Arial; text-align: center; margin-top: 100px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; }
h1 { font-size: 48px; }
p { font-size: 20px; }
</style>
</head>
<body>
<h1>🎉 欢迎来到 Docker 世界!</h1>
<p>你的应用正在容器中运行</p>
<p>容器 ID:${process.env.HOSTNAME || 'unknown'}</p>
</body>
</html>
`);
});
app.listen(port, () => {
console.log(`应用运行在 http://localhost:${port}`);
});
package.json —— 项目依赖文件:
json
复制
下载
{
"name": "my-web-app",
"version": "1.0.0",
"description": "一个简单的 Docker 示例应用",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "^4.18.2"
}
}
3.2 编写 Dockerfile
在 my-web-app 文件夹中,创建一个名为 Dockerfile(注意没有文件后缀)的文件,内容如下:
dockerfile
复制
下载
# 第1步:选择基础镜像 # 就像一个蛋糕配方,我们选择别人已经做好的“底胚” FROM node:18-alpine # 第2步:设置工作目录 # 在容器内部创建并进入 /app 目录 WORKDIR /app # 第3步:复制依赖文件 # 先把 package.json 复制进去,利用 Docker 的缓存机制 COPY package*.json ./ # 第4步:安装依赖 # 运行 npm install,安装应用所需的所有依赖 RUN npm install # 第5步:复制应用代码 # 将当前目录下的所有文件复制到容器的工作目录 COPY . . # 第6步:暴露端口 # 告诉 Docker 这个容器会使用 3000 端口 EXPOSE 3000 # 第7步:启动命令 # 容器启动时要运行的命令 CMD ["npm", "start"]
3.3 逐行解析 Dockerfile
让我们逐行理解这个 Dockerfile:
-
FROM node:18-alpine:这就像是在说“我要基于 Node.js 18 版本的 Alpine Linux 镜像来构建”。Alpine 是一个非常轻量的 Linux 发行版,可以让镜像体积很小。
-
WORKDIR /app:在容器内创建
/app目录,并把它设为当前工作目录。后续的命令都会在这个目录下执行。 -
COPY package*.json ./:把本地的
package.json和package-lock.json复制到容器的当前目录。之所以先复制依赖文件再复制代码,是为了利用 Docker 的缓存机制——只要依赖文件没变,下次构建时就不会重复执行npm install,大大加快构建速度。 -
RUN npm install:在容器内执行
npm install命令,安装所有依赖。 -
COPY . .:将当前目录的所有文件复制到容器内。注意,我们可以在项目根目录创建
.dockerignore文件,像.gitignore一样忽略不需要的文件(比如node_modules)。 -
EXPOSE 3000:这只是文档性的声明,告诉使用这个镜像的人,容器会监听 3000 端口。
-
CMD ["npm", "start"]:容器启动时执行的命令。这里我们运行
npm start来启动应用。
四、构建与运行:让容器跑起来
4.1 构建镜像
打开终端,进入 my-web-app 目录,执行以下命令构建镜像:
bash
复制
下载
docker build -t my-web-app .
命令解析:
-
docker build:构建镜像的命令 -
-t my-web-app:给镜像起一个名字(tag),方便后续使用 -
.:指定构建上下文为当前目录
构建过程会逐行执行 Dockerfile 中的指令,你会在终端看到类似这样的输出:
text
复制
下载
[+] Building 15.2s (10/10) FINISHED => [1/5] FROM node:18-alpine => [2/5] WORKDIR /app => [3/5] COPY package*.json ./ => [4/5] RUN npm install => [5/5] COPY . . => exporting to image => => naming to docker.io/library/my-web-app
构建完成后,用以下命令查看已创建的镜像:
bash
复制
下载
docker images
你会看到 my-web-app 出现在列表中。
4.2 运行容器
镜像构建完成后,就可以运行容器了:
bash
复制
下载
docker run -d -p 8080:3000 --name my-app my-web-app
命令解析:
-
docker run:运行容器的命令 -
-d:让容器在后台运行(detached mode) -
-p 8080:3000:端口映射,将宿主机的 8080 端口映射到容器的 3000 端口。这样我们访问本机的 8080 端口,就能访问到容器内运行的 Web 应用 -
--name my-app:给容器起一个名字 -
my-web-app:指定使用哪个镜像
运行成功后,打开浏览器,访问 http://localhost:8080,你应该能看到刚才编写的 Web 页面!
4.3 常用容器管理命令
学习几个常用的容器管理命令:
bash
复制
下载
# 查看正在运行的容器 docker ps # 查看所有容器(包括已停止的) docker ps -a # 停止容器 docker stop my-app # 启动已停止的容器 docker start my-app # 删除容器(需要先停止) docker rm my-app # 查看容器日志 docker logs my-app # 进入容器的命令行 docker exec -it my-app sh
五、优化 Dockerfile:让镜像更“轻”
上面的 Dockerfile 已经能工作,但还有一些优化空间。让我们来改进一下:
dockerfile
复制
下载
# 使用更具体的基础镜像版本
FROM node:18-alpine
# 设置时区(可选)
RUN apk add --no-cache tzdata
ENV TZ=Asia/Shanghai
WORKDIR /app
# 只复制 package.json 和 package-lock.json
COPY package*.json ./
# 只安装生产环境依赖,减少镜像体积
RUN npm ci --only=production
# 复制应用代码
COPY . .
# 使用非 root 用户运行,提高安全性
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001 -G nodejs
USER nodejs
EXPOSE 3000
# 使用 exec 形式的 CMD
CMD ["node", "app.js"]
优化点说明:
-
使用
npm ci替代npm install,安装更快更可靠 -
--only=production只安装生产环境依赖,排除开发依赖 -
创建非 root 用户运行应用,提高安全性
-
使用
node app.js直接运行,而不是通过 npm 脚本
六、推送到仓库:让应用“上云”
构建好的镜像只存在于本地,如果想在其他服务器上使用,需要把它推送到镜像仓库。
6.1 注册 Docker Hub 账号
-
点击 Sign Up 注册一个账号
-
记住你的用户名
6.2 登录并推送镜像
bash
复制
下载
# 登录 Docker Hub docker login # 输入你的用户名和密码 # 给镜像打上标签(tag) # 格式:docker tag 本地镜像 用户名/仓库名:版本号 docker tag my-web-app your-username/my-web-app:v1.0 # 推送到仓库 docker push your-username/my-web-app:v1.0
推送成功后,任何人都可以通过 docker pull your-username/my-web-app:v1.0 来拉取你的镜像并运行了。
七、部署到云平台:从本地到云端
当你的应用运行稳定后,就可以把它部署到云平台上了。这里介绍几种常见的部署方式。
7.1 部署到云服务器
如果你有一台云服务器(比如阿里云 ECS、腾讯云 CVM、AWS EC2 等),部署非常简单:
第一步:连接到云服务器(使用 SSH)
bash
复制
下载
ssh root@你的服务器IP
第二步:在服务器上安装 Docker(参考前面的安装步骤)
第三步:拉取镜像并运行
bash
复制
下载
# 拉取镜像 docker pull your-username/my-web-app:v1.0 # 运行容器 docker run -d -p 80:3000 --name my-web-app your-username/my-web-app:v1.0
注意,这里我们映射到了 80 端口,这样用户直接访问你的服务器 IP 就能看到应用了。
第四步:配置防火墙
确保云服务器的防火墙开放了 80 端口。
7.2 使用 Docker Compose(进阶)
如果你的应用比较复杂,比如需要同时运行 Web 应用和数据库,可以使用 Docker Compose。
创建一个 docker-compose.yml 文件:
yaml
复制
下载
version: '3.8'
services:
web:
image: your-username/my-web-app:v1.0
ports:
- "80:3000"
environment:
- NODE_ENV=production
restart: always
# 如果需要数据库,可以这样配置
# database:
# image: mysql:8.0
# environment:
# MYSQL_ROOT_PASSWORD: your-password
# volumes:
# - db-data:/var/lib/mysql
# volumes:
# db-data:
然后在服务器上运行:
bash
复制
下载
docker-compose up -d
7.3 部署到云容器服务
各大云厂商都提供了容器托管服务,可以免去管理服务器的麻烦:
| 云厂商 | 服务名称 | 特点 |
|---|---|---|
| 阿里云 | 容器服务 ACK | 与阿里云生态集成好 |
| 腾讯云 | 容器服务 TKE | 腾讯云原生服务 |
| 华为云 | 云容器引擎 CCE | 企业级容器服务 |
| AWS | ECS / EKS | 全球领先的容器服务 |
这些服务的共同特点是:你只需要上传镜像,平台会自动帮你运行和管理容器,自动处理扩缩容、负载均衡等问题。
八、常见问题与解决方案
8.1 端口被占用
问题:运行容器时提示端口已被占用
解决:换个端口映射
bash
复制
下载
# 用 8081 替代 8080 docker run -d -p 8081:3000 my-web-app
8.2 容器启动后立即退出
问题:容器启动后就停止了
解决:查看日志找出原因
bash
复制
下载
# 查看容器日志 docker logs 容器ID # 交互式运行,方便调试 docker run -it my-web-app sh
常见原因:端口配置错误、依赖未安装、环境变量缺失等。
8.3 镜像体积过大
问题:构建的镜像有好几百 MB
解决:
-
使用 Alpine 版本的基础镜像(如
node:18-alpine) -
使用多阶段构建
-
清理不必要的文件
8.4 文件权限问题
问题:容器内无法写入文件
解决:创建非 root 用户并赋予权限,或者使用卷挂载
bash
复制
下载
# 挂载宿主机目录到容器 docker run -v /host/data:/app/data my-web-app
结语
通过这篇文章,我们学习了 Docker 的核心概念,亲手编写了 Dockerfile,构建并运行了容器,最后还将应用部署到了云平台。现在,你已经掌握了将 Web 应用容器化的完整流程。
Docker 的世界远比这篇文章介绍的更加广阔。当你熟悉了基础操作后,可以继续探索以下方向:
-
Docker Compose:管理多容器应用
-
Docker Swarm 或 Kubernetes:容器编排
-
CI/CD 集成:自动构建和部署
-
容器安全最佳实践
容器化已经成为现代软件交付的标准方式。掌握 Docker,不仅能让你的部署工作变得轻松,更能让你在技术道路上走得更远。
下一步建议:现在就动手试试吧!打开终端,创建一个 Node.js 应用,按照文章步骤完成你的第一次 Docker 部署。遇到问题不要怕,看看日志,查查资料,解决掉它,你就真正掌握这项技能了。
更多推荐
所有评论(0)