一、写在前面

上节课我们学习了容器云的基础概念,这次我给自己定了个小目标:把一个本地的Node.js Web应用完整容器化,并部署到云服务器上

整个过程走下来,踩了不少坑,但也真正打通了“开发→构建→推送→部署”的全链路。这篇博文就是我的实操复盘,核心“一得”是:容器化不是装个Docker就完事,而是一种“应用即镜像”的交付思维,真正实现了开发与运维的一致性

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

先写一个最简单的Web服务,用来演示。

项目结构:

text

myapp/
├── package.json
├── app.js
└── Dockerfile

package.json:

json

{
  "name": "myapp",
  "version": "1.0.0",
  "main": "app.js",
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "^4.18.2"
  }
}

app.js:

javascript

const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

app.get('/', (req, res) => {
  res.send('<h1>🚀 Hello from Container Cloud!</h1>');
});

app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

本地运行 npm install && npm start,访问 http://localhost:3000 确认页面正常。

三、编写Dockerfile:容器化的灵魂

Dockerfile是容器化的核心,它定义了如何把应用打包成镜像。

dockerfile

# 使用官方Node.js轻量镜像作为基础
FROM node:18-alpine

# 设置工作目录
WORKDIR /app

# 先复制package文件,利用Docker缓存层加速构建
COPY package*.json ./
RUN npm install --production

# 复制应用源码
COPY . .

# 声明运行时端口
EXPOSE 3000

# 启动命令
CMD ["node", "app.js"]

⚡ 小技巧:COPY package*.json ./ 和 RUN npm install 放在一起,能让依赖安装层被缓存。代码改动时只要依赖不变,就不会重新下载,构建速度飞快。

构建镜像:

bash

docker build -t myapp:v1 .

本地运行测试:

bash

docker run -d -p 3000:3000 --name myapp-container myapp:v1

浏览器访问确认容器内应用正常运行。

✅ 一得:Dockerfile是“基础设施即代码”的起点,它把运行环境、依赖、启动流程全部固化为可复现的脚本,从此告别“环境不一致”的噩梦。

四、推送镜像到容器仓库

要在云服务器上部署,需要把镜像推送到一个可访问的仓库。我用的是阿里云容器镜像服务(ACR),免费个人版完全够用。

1. 登录阿里云Docker Registry:

bash

docker login --username=你的阿里云账号 registry.cn-hangzhou.aliyuncs.com

2. 打标签:

bash

docker tag myapp:v1 registry.cn-hangzhou.aliyuncs.com/你的命名空间/myapp:v1

3. 推送:

bash

docker push registry.cn-hangzhou.aliyuncs.com/你的命名空间/myapp:v1

推送成功后,在阿里云控制台就能看到镜像了。

✅ 一得:镜像仓库是容器化的“分发枢纽”,有了它,任何一台有Docker的机器都能拉取并运行完全相同的应用,实现真正的“一次构建,处处运行”。

五、在云服务器上部署

我用的是一台阿里云ECS(CentOS 7.9),同样安装Docker后执行:

bash

# 登录仓库(如果是私有镜像)
docker login --username=你的账号 registry.cn-hangzhou.aliyuncs.com

# 拉取镜像
docker pull registry.cn-hangzhou.aliyuncs.com/你的命名空间/myapp:v1

# 运行
docker run -d -p 80:3000 --name myapp-prod myapp:v1

此时访问云服务器的公网IP,就能看到之前的页面了。

配置开机自启:

bash

docker update --restart=always myapp-prod

这样服务器重启后容器也会自动恢复。

部署架构示意图(文字描述):

text

 用户浏览器
     ↓
 云服务器 (ECS)
  ↓  端口80 → 容器3000
 Docker Engine
  ↓ 运行
 容器实例 (myapp:v1)

六、升级应用:体验滚动更新

假设修改了代码,把问候语改为 "<h1>🎉 Version 2 is LIVE!</h1>"

1. 构建新版本镜像并推送:

bash

docker build -t myapp:v2 .
docker tag myapp:v2 registry.cn-hangzhou.aliyuncs.com/你的命名空间/myapp:v2
docker push registry.cn-hangzhou.aliyuncs.com/你的命名空间/myapp:v2

2. 在服务器上更新:

bash

docker pull registry.cn-hangzhou.aliyuncs.com/你的命名空间/myapp:v2
docker stop myapp-prod && docker rm myapp-prod
docker run -d -p 80:3000 --name myapp-prod --restart=always myapp:v2

✅ 一得:版本化镜像让应用升级变得可控、可回滚。如果v2有问题,停掉v2、重新运行v1镜像就能秒级回滚,这是传统部署方式难以做到的。

七、遇到的坑与解决方法

问题 原因 解决方法
构建时 npm install 报网络错误 容器内网络访问国外源慢 在Dockerfile中先设置国内镜像源:RUN npm config set registry https://registry.npmmirror.com
容器启动后立刻退出 app.js有语法错误但没看到日志 先用 docker logs myapp-container 查看运行日志,定位错误
云服务器访问不到 ECS安全组未开放80端口 去阿里云控制台安全组中添加入方向规则,放行TCP 80端口
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐