Docker 容器化应用实战:从环境搭建到部署上线
本文最后更新于235 天前,其中的信息可能已经过时,如有错误请发送邮件到109484028@qq.com

最近帮团队把一个老项目改成了 Docker 容器化部署,从一开始的 “怕配置复杂”,到后来发现 “容器化居然这么省心”,踩了些坑也总结了不少实用经验。今天就从实战角度,带大家一步步搞定 Docker 容器化 —— 不管你是想解决 “开发环境不一致” 的痛点,还是要搭一套简单的部署流程,这篇都能帮到你。

一、先搞懂:为什么要容器化?

在聊实战前,先说说容器化的核心价值 —— 毕竟搞技术得先知道 “为什么要做”。我之前遇到的最大问题就是 “开发环境和生产环境不兼容”:本地跑的好好的代码,到测试环境就报错,查了半天发现是 “本地用的 Node.js 14,测试环境是 Node.js 16”;还有 “部署时要装一堆依赖,少一个就崩”。

而 Docker 容器化能解决这些问题:

  • 环境一致性:把 “代码 + 依赖 + 配置” 打包成一个 “容器镜像”,不管在哪跑,环境都一样;

  • 轻量高效:容器比虚拟机省资源,启动快(秒级启动),一台服务器能跑多个容器;

  • 隔离性好:不同应用的依赖互不干扰,比如 A 应用用 Python 3.8,B 应用用 Python 3.10,不用再折腾多版本共存。

二、实战第一步:Docker 环境搭建(超简单)

首先得在本地装 Docker,不管是 Windows、Mac 还是 Linux,步骤都很简单,新手也能搞定。

1. 安装 Docker

  • Windows/Mac:直接下 Docker Desktop,双击安装,启动后在终端输 docker --version,能看到版本号就说明装好了;

  • Linux(以 Ubuntu 为例):几行命令搞定,不用手动找安装包:

\# 更新 apt 源

sudo apt update

\# 安装依赖

sudo apt install -y apt-transport-https ca-certificates curl software-properties-common

\# 添加 Docker 官方 GPG 密钥

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

\# 添加 Docker 源

sudo add-apt-repository "deb \[arch=amd64] https://download.docker.com/linux/ubuntu \$(lsb\_release -cs) stable"

\# 安装 Docker

sudo apt install -y docker-ce

\# 验证:启动 Docker 并查看状态

sudo systemctl start docker && sudo systemctl enable docker

sudo docker --version

2. 验证环境:跑一个 Hello World

装完后先跑个简单的容器,确认 Docker 能正常工作:

\# 拉取官方的 hello-world 镜像(很小,几秒就下完)

docker pull hello-world

\# 运行容器

docker run hello-world

如果终端输出 “Hello from Docker!”,说明环境没问题 —— 这一步主要是确认 Docker 能拉取镜像、启动容器,新手别跳过~

三、核心实战:把一个 Node.js 应用容器化

光跑 Hello World 没用,咱们拿一个真实的 Node.js 应用举例(其他语言思路类似),从 “写 Dockerfile” 到 “构建镜像” 再到 “启动容器”,一步一步来。

1. 准备一个简单的 Node.js 应用

先有个基础的 Node 项目,比如一个简单的 Express 服务:

  • 项目结构:
my-node-app/

├── app.js       # 入口文件

├── package.json # 依赖配置

└── Dockerfile   # 重点!Docker 构建配置文件(后面写)
  • app.js 代码(简单的接口服务):
const express = require('express');

const app = express();

const port = process.env.PORT || 3000; // 从环境变量拿端口,灵活配置

app.get('/', (req, res) => {

  res.send('Hello Docker! 这是容器化的 Node 应用~');

});

app.listen(port, () => {

  console.log(\`服务跑在 http://localhost:\${port}\`);

});
  • package.json 配置(依赖 express):
{

  "name": "my-node-app",

  "version": "1.0.0",

  "dependencies": {

    "express": "^4.18.2"

  },

  "scripts": {

    "start": "node app.js"

  }

}

2. 写 Dockerfile:告诉 Docker 怎么打包镜像

Dockerfile 是容器化的 “灵魂”,它定义了 “从基础镜像开始,装哪些依赖、复制哪些文件、怎么启动应用”。咱们逐行解释:

\# 1. 指定基础镜像:用官方的 Node 镜像,选择 16-alpine 版本(alpine 是轻量版,体积小)

FROM node:16-alpine

\# 2. 设置工作目录:在容器内创建一个目录,后续命令都在这个目录下执行(避免文件混乱)

WORKDIR /app

\# 3. 复制 package.json 和 package-lock.json 到工作目录(先复制依赖配置,利用 Docker 缓存)

\# 为什么先复制这两个文件?因为 Docker 构建是分层的,依赖不变时,这一层会缓存,不用每次都重新装依赖

COPY package\*.json ./

\# 4. 安装依赖:在容器内执行 npm install,装 express

RUN npm install --production # --production 只装生产依赖,减少镜像体积

\# 5. 复制项目其他文件(如 app.js)到工作目录

COPY . .

\# 6. 暴露端口:告诉 Docker 这个容器会用 3000 端口(只是声明,不是真正映射)

EXPOSE 3000

\# 7. 容器启动时执行的命令:启动 Node 服务

CMD \["npm", "start"]

3. 构建镜像:把应用打包成 “可运行的镜像”

在项目根目录(Dockerfile 所在目录)执行 docker build 命令,构建镜像:

\# -t 给镜像起个名字(my-node-app),后面跟版本号(v1.0),最后加个 . 表示“从当前目录的 Dockerfile 构建”

docker build -t my-node-app:v1.0 .

构建过程中,Docker 会一步步执行 Dockerfile 里的命令,最后看到 “Successfully built xxx” 就说明成功了。可以用 docker images 查看本地镜像,能看到 my-node-app:v1.0 就对了。

4. 启动容器:运行容器化的应用

镜像构建好后,用 docker run 启动容器:

\# -p 8080:3000:把本地的 8080 端口映射到容器的 3000 端口(本地访问 localhost:8080 就能到容器的 3000 端口)

\# --name my-node-container:给容器起个名字,方便后续管理

\# my-node-app:v1.0:用哪个镜像启动容器

docker run -p 8080:3000 --name my-node-container my-node-app:v1.0

启动后,打开浏览器访问 http://localhost:8080,能看到 “Hello Docker! 这是容器化的 Node 应用~”,说明容器跑起来了!

如果想让容器在后台运行(不占用终端),加个 -d 参数:

docker run -d -p 8080:3000 --name my-node-container my-node-app:v1.0

四、实战进阶:容器管理与部署小技巧

光启动容器还不够,实际开发中还要会 “停止容器”“查看日志”“部署到服务器”,这些小技巧能帮你少踩坑。

1. 常用容器管理命令

记几个高频命令,不用死记,用多了就熟了:

\# 查看正在运行的容器

docker ps

\# 查看所有容器(包括停止的)

docker ps -a

\# 停止容器(my-node-container 是容器名)

docker stop my-node-container

\# 启动已停止的容器

docker start my-node-container

\# 查看容器日志(实时日志加 -f)

docker logs -f my-node-container

\# 删除容器(先停止再删除,强制删除加 -f)

docker rm my-node-container

\# 删除镜像(my-node-app:v1.0 是镜像名)

docker rmi my-node-app:v1.0

2. 环境变量:让应用更灵活

实际应用中,很多配置(比如端口、数据库地址)不能写死在代码里,要用环境变量传递。比如咱们的 Node 应用用了 process.env.PORT,启动容器时可以用 -e 传环境变量:

\# 传 PORT=3001,让容器内的应用用 3001 端口,本地映射 8081 端口

docker run -d -p 8081:3001 -e PORT=3001 --name my-node-container-2 my-node-app:v1.0

这样不用改代码,就能灵活调整配置,比如生产环境用 80 端口,测试环境用 8080 端口。

3. 数据持久化:避免容器删除后数据丢失

容器删除后,里面的数据会跟着丢(比如数据库容器的表数据),这时候要用到 “数据卷(Volume)”,把容器内的数据挂载到本地,实现 “数据持久化”。

比如用 Docker 跑一个 MySQL 容器,挂载本地目录保存数据:

\# 创建一个数据卷(叫 mysql-data)

docker volume create mysql-data

\# 启动 MySQL 容器,把数据卷挂载到容器的 /var/lib/mysql(MySQL 数据存储目录)

docker run -d -p 3306:3306 \\

  -e MYSQL\_ROOT\_PASSWORD=123456 \ # 传 MySQL 根密码

  -v mysql-data:/var/lib/mysql \ # 挂载数据卷

  \--name mysql-container \\

  mysql:8.0 # 用官方 MySQL 8.0 镜像

这样即使删除 mysql-container,数据卷 mysql-data 里的数据还在,下次启动新的 MySQL 容器时,挂载同一个数据卷就能恢复数据。

4. 部署到服务器:简单的 “镜像推送 + 拉取” 流程

本地容器化好后,怎么部署到服务器?核心思路是 “把本地镜像推到镜像仓库,服务器从仓库拉取镜像并启动”。

(1)用 Docker Hub 当镜像仓库(免费版够用)

  • 先在 Docker Hub 注册账号,比如账号名是 yourusername

  • 本地给镜像打标签(格式:仓库地址/账号名/镜像名:版本):

docker tag my-node-app:v1.0 yourusername/my-node-app:v1.0
  • 登录 Docker Hub,推送镜像:
docker login # 输入账号密码登录

docker push yourusername/my-node-app:v1.0 # 推送到远程仓库

(2)服务器拉取镜像并启动

服务器上先装 Docker(步骤和本地一样),然后拉取镜像并启动:

\# 服务器拉取远程镜像

docker pull yourusername/my-node-app:v1.0

\# 启动容器(和本地一样,传环境变量、挂载数据卷)

docker run -d -p 80:3000 -e PORT=3000 --name my-node-prod yourusername/my-node-app:v1.0

这样服务器就能跑起容器化的应用了,后续更新时,只要本地构建新镜像、推送到仓库,服务器拉取新镜像、重启容器就行,比传统部署(上传代码、装依赖、重启服务)快多了。

五、新手避坑指南

  1. 镜像体积别太大:用 alpine 基础镜像(比完整版小很多),装依赖时用 npm install --production 只装生产依赖,避免把 node_modules 复制到容器(先复制 package.json 装依赖,再复制其他文件);

  2. 别用 root 用户跑容器:实际生产中,容器内用普通用户运行应用,减少安全风险(Dockerfile 里可以加 RUN adduser -D myuser && su myuser 切换用户);

  3. 端口别冲突:启动容器时,本地端口(比如 8080)别被其他应用占用,不然启动失败,用 netstat -tuln 查看本地占用的端口;

  4. 别把敏感信息写 Dockerfile:比如数据库密码、密钥,别在 Dockerfile 里用 ENV 写死,用 -e 传环境变量,或者用 Docker Secrets(进阶用法)。

总结:容器化没那么难,动手试就对了

刚开始接触 Docker 时,我总觉得 “配置复杂、怕搞崩环境”,但实际动手后发现,核心流程就 “写 Dockerfile → 构建镜像 → 启动容器”,常用命令也就那几个。

如果你是新手,建议从 “把自己的小项目容器化” 开始,比如一个简单的前端 Vue 项目、后端 Spring Boot 项目,一步步踩坑、总结经验;如果是团队用,后续可以学 Docker Compose(管理多个容器,比如 “前端 + 后端 + 数据库” 一起启动)、Kubernetes(大规模容器编排,中小项目暂时用不上)。

容器化的核心是 “让应用跑在一致的环境里,减少部署麻烦”,用过之后你会发现,再也不用跟 “我这能跑啊”“你那边少个依赖” 这种问题打交道了 —— 这才是 Docker 最爽的地方~

你们在容器化时遇到过什么坑?欢迎评论区分享,一起避坑~

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇