文章詳情

AWS帳號認證開通 容器化應用遷移指南:從虛擬機器到 Docker 容器

亞馬遜雲AWS2026-10-21 15:42:07阿里雲

# 容器化應用遷移指南:從虛擬機器到 Docker 容器

很多團隊在虛擬機器上運行應用多年後,會遇到幾個很實際的問題:環境不一致、部署靠手工、升級容易出錯、回滾成本高。搜尋這個主題的使用者,通常不是想了解容器是什麼,而是已經有一台或多台 VM 正在跑業務,現在要把應用搬到 Docker,並且希望遷移過程可控、可回滾、不中斷或少中斷。

這篇文章不講概念,直接從工程落地角度出發,帶你完成一次從虛擬機器到 Docker 容器的遷移,重點放在:**怎麼盤點、怎麼打包、怎麼啟動、怎麼驗證、怎麼切換、出問題怎麼查**。

AWS帳號認證開通 ---

## 一、先判斷你的遷移目標是什麼

在動手前,先把目標說清楚,否則很容易出現「容器跑起來了,但不能用」的情況。

你通常在遷移的是以下其中一種:

1. **單體 Web 應用**
- 例如 Java、Node.js、Python、PHP 應用
- 對外提供 HTTP/HTTPS 服務

2. **後台服務**
- 例如定時任務、API 服務、消費者程序

3. **帶本地依賴的老系統**
- 依賴特定版本 OpenJDK、Nginx、Python、glibc、系統工具包

4. **資料與應用混跑的 VM**
- 同一台虛擬機器裡同時有應用、MySQL、Redis、上傳檔案目錄、日誌檔
- 這類遷移最容易出問題,因為容器化時需要先拆分

### 遷移前先回答 4 個問題

1. 應用程式入口命令是什麼?
- 例如 `java -jar app.jar`
- 例如 `python app.py`
- 例如 `gunicorn -c gunicorn.conf.py wsgi:app`

2. 應用依賴哪些檔案或服務?
- 配置檔
- 上傳目錄
- 本地快取
- MySQL / Redis / MQ

3. 現在 VM 上開了哪些埠?
- 80、443、8080、3306、6379 等

4. 哪些資料不能丟?
- 使用者上傳資料
- 應用配置
- SSL 憑證
- 資料庫資料

如果這 4 點沒盤清楚,後面做 Dockerfile 與容器啟動參數時大機率會遺漏。

---

## 二、遷移前盤點:先把 VM 裡的東西摸清楚

這一步是整個遷移中最容易被省略,但最關鍵的部分。

建議登入原 VM 後執行以下檢查。

## 1. 確認作業系統與軟體版本

```bash
cat /etc/os-release
uname -a
```

查看應用執行時版本:

```bash
java -version
python3 --version
node -v
nginx -v
mysql --version
redis-server --version
```

### 為什麼要做這一步?
因為很多應用在 VM 能跑,是建立在特定執行版本上。你如果在 Docker 裡換了基礎映像版本,可能直接報錯,例如:

- Java 8 程式拿去 Java 17 跑
- Python 3.7 依賴在 Python 3.11 失效
- 舊版二進位依賴新系統庫失敗

---

## 2. 找出應用啟動方式

查看目前怎麼啟動的:

```bash
ps -ef | grep -E 'java|python|node|gunicorn|nginx'
systemctl list-units --type=service
systemctl status your-service-name
```

如果是 systemd 管理,查看服務檔:

```bash
systemctl cat your-service-name
```

重點記下:

- 啟動命令
- 工作目錄
- 使用者帳號
- 環境變數
- 配置檔路徑
- 日誌路徑

AWS帳號認證開通 這些後面都要映射到容器裡。

---

## 3. 找出埠與網路依賴

```bash
ss -lntp
netstat -lntp
```

檢查應用是否依賴內網服務:

AWS帳號認證開通 ```bash
grep -R "mysql\|redis\|mq\|kafka\|postgres" /etc /opt /app 2>/dev/null
```

### 常見遺漏

- 配置檔裡連的是 `127.0.0.1:3306`
- Redis 寫的是 `localhost`
- Nginx upstream 指向 VM 本機埠

搬進容器後,如果資料庫不在同一容器,`localhost` 幾乎一定會出問題,這是遷移時最常見錯誤之一。

---

## 4. 找出需要持久化的目錄

常見目錄包括:

- `/data/uploads`
- `/var/www/html/storage`
- `/opt/app/logs`
- `/etc/app/config`
- `/usr/local/nginx/conf`

如果容器刪掉後資料不能丟,就不要只放在容器內部,要改成 volume 掛載。

可用以下方式盤點最近變化較多的資料目錄:

```bash
du -sh /opt/* /data/* 2>/dev/null
find /opt/app -type f -mtime -7 | head
```

---

AWS帳號認證開通 ## 三、決定遷移策略:整機打包不可取,應用拆分才穩

很多人第一次遷移會想把整台 VM 直接「變成一個容器」。實務上這樣做後續維護很差,也不利於升級。

### 比較建議的拆分方式

**原 VM:**
- Nginx
- App
- MySQL
- Redis
- 上傳檔案

AWS帳號認證開通 **容器化後:**
- 一個 Nginx 容器
- 一個 App 容器
- MySQL 用獨立資料庫服務或獨立容器
- Redis 用獨立快取服務或獨立容器
- 上傳檔案掛載宿主機 volume 或物件儲存

### 遷移優先順序建議

1. 先容器化應用
2. 再處理 Nginx 或反向代理
3. 最後再處理資料庫與快取

如果你的目標只是先把應用從 VM 搬出來,**不要在第一天同時改應用、改資料庫、改網路拓撲**,否則排錯會非常痛苦。

---

AWS帳號認證開通 ## 四、準備 Docker 執行環境

以下以 Linux 伺服器為例。

AWS帳號認證開通 ## 1. 安裝 Docker

Ubuntu / Debian:

AWS帳號認證開通 ```bash
apt-get update
apt-get install -y docker.io
systemctl enable docker
systemctl start docker
```

CentOS / Rocky / AlmaLinux:

```bash
yum install -y docker
systemctl enable docker
systemctl start docker
```

確認版本:

```bash
docker version
docker info
```

如果你使用的是雲伺服器,還要同步檢查:

- 安全組是否放行對外服務埠
- 作業系統防火牆是否放行埠
- 公網 IP 是否正確綁定

例如開放 80 與 443:

```bash
firewall-cmd --permanent --add-port=80/tcp
firewall-cmd --permanent --add-port=443/tcp
firewall-cmd --reload
```

如果是 Ubuntu UFW:

```bash
ufw allow 80/tcp
ufw allow 443/tcp
ufw reload
```

---

## 五、開始製作 Docker 映像

下面用最常見的 Java、Python、Node.js 三類應用示範。你只需要選符合自己專案的方式。

## 1. Java 應用 Dockerfile 範例

假設原本 VM 啟動命令是:

```bash
java -jar /opt/app/app.jar --spring.profiles.active=prod
```

建立 `Dockerfile`:

```dockerfile
FROM eclipse-temurin:8-jre
WORKDIR /app
COPY app.jar /app/app.jar
EXPOSE 8080
ENV SPRING_PROFILES_ACTIVE=prod
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
```

AWS帳號認證開通 建置映像:

```bash
docker build -t myapp:1.0 .
```

啟動容器:

```bash
docker run -d \
--name myapp \
-p 8080:8080 \
-e SPRING_PROFILES_ACTIVE=prod \
myapp:1.0
```

### 常見問題

**問題:容器啟動後立刻退出**

排查:

```bash
docker ps -a
docker logs myapp
```

常見原因:
- JAR 檔沒有正確 COPY
- Java 版本不匹配
- 啟動參數漏掉
- 依賴的配置檔不存在

---

## 2. Python 應用 Dockerfile 範例

```dockerfile
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt /app/
RUN pip install --no-cache-dir -r requirements.txt
COPY . /app
EXPOSE 8000
CMD ["python", "app.py"]
```

如果是 Gunicorn:

```dockerfile
CMD ["gunicorn", "-b", "0.0.0.0:8000", "wsgi:app"]
```

啟動:

```bash
docker run -d \
--name pyapp \
-p 8000:8000 \
pyapp:1.0
```

### 常見問題

- `ModuleNotFoundError`
- requirements.txt 缺套件
- 入口檔案路徑不對
- 程式只監聽 `127.0.0.1`,沒監聽 `0.0.0.0`

這裡非常常見的一個錯誤是:程式在容器內只綁定 `127.0.0.1`,結果宿主機做了 `-p 8000:8000` 仍然無法從外部訪問。要改成監聽 `0.0.0.0`。

---

## 3. Node.js 應用 Dockerfile 範例

```dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json /app/
RUN npm install --production
COPY . /app
EXPOSE 3000
CMD ["npm", "start"]
```

啟動:

```bash
docker run -d \
--name nodeapp \
-p 3000:3000 \
nodeapp:1.0
```

### 常見問題

- package-lock.json 與 npm 版本衝突
- 原 VM 上有本地編譯依賴,alpine 缺庫
- 啟動命令其實不是 `npm start`

如果你的 Node 應用依賴原生模組,從 `alpine` 換成 `node:18-bullseye` 往往更省時間。

---

## 六、把配置檔與環境變數從容器鏡像中拆出來

遷移時另一個高頻錯誤是:把生產配置直接寫死進映像,導致每改一次配置就要重打包。

正確做法是把這些內容外置:

- 資料庫位址
- Redis 位址
- API 金鑰
- 域名
- 埠
- 日誌等級

### 用環境變數傳入

```bash
docker run -d \
--name myapp \
-p 8080:8080 \
-e DB_HOST=10.0.0.12 \
-e DB_PORT=3306 \
-e DB_NAME=appdb \
-e DB_USER=appuser \
-e DB_PASSWORD='yourpassword' \
myapp:1.0
```

### 用外部配置檔掛載

```bash
docker run -d \
--name myapp \
-p 8080:8080 \
-v /data/config/application-prod.yml:/app/application-prod.yml \
myapp:1.0
```

### 建議

- 機密資訊不要硬編碼進 Dockerfile
- 配置檔不要只放容器內部
- 上線前先用測試配置驗證,再切生產配置

---

## 七、處理資料持久化:不要把重要資料留在容器層

如果原 VM 裡有以下資料:

- 使用者上傳檔案
- 產出的報表
- SSL 憑證
- 應用日誌
- 本地快取

遷移到 Docker 時應該使用 volume 掛載。

### 例子:掛載上傳目錄

```bash
docker run -d \
--name myapp \
-p 8080:8080 \
-v /data/uploads:/app/uploads \
myapp:1.0
```

### 例子:掛載日誌目錄

```bash
docker run -d \
--name myapp \
-p 8080:8080 \
-v /data/logs:/app/logs \
myapp:1.0
```

### 遷移舊資料

從原 VM 拷貝資料:

```bash
rsync -avz /opt/app/uploads/ /data/uploads/
```

如果是跨主機遷移:

```bash
rsync -avz /opt/app/uploads/ root@new-server:/data/uploads/
```

### 常見問題

**問題:容器裡看不到掛載目錄內容**

排查:
- 宿主機目錄是否存在
- 權限是否正確
- 容器內程式執行使用者是否有讀寫權限

修正權限:

```bash
chown -R 1000:1000 /data/uploads
chmod -R 755 /data/uploads
```

具體 UID/GID 以容器內實際使用者為準。

---

## 八、處理資料庫與 Redis 連線

這一步是容器化遷移最常見的故障點。

## 1. 不要再用 localhost

原 VM 常見配置:

```ini
DB_HOST=127.0.0.1
REDIS_HOST=127.0.0.1
```

如果資料庫與 Redis 沒跟應用放在同一個容器,這樣配置會導致連線失敗。你應該改成:

- 雲資料庫內網位址
- Redis 實例內網位址
- 或 docker network 裡的服務名

例如:

```ini
DB_HOST=10.0.1.15
REDIS_HOST=10.0.1.20
```

---

AWS帳號認證開通 ## 2. 驗證網路連通性

進入容器測試:

```bash
docker exec -it myapp sh
```

測試資料庫埠:

```bash
nc -zv 10.0.1.15 3306
```

測試 Redis 埠:

```bash
nc -zv 10.0.1.20 6379
```

如果容器內沒安裝 `nc`,可臨時用工具容器測:

```bash
docker run --rm -it busybox sh
```

### 如果連不通,重點檢查

- 雲安全組是否放行來源 IP
- 資料庫白名單是否包含目前伺服器
- 作業系統防火牆是否阻擋
- 應用與資料庫是否在同一 VPC / 私網
- DNS 是否解析正確

---

## 九、使用 Docker Compose 管理多個服務

如果你的應用不只一個容器,建議直接用 Compose 管理,比一條一條 `docker run` 更穩定。

建立 `docker-compose.yml`:

```yaml
version: '3.8'
services:
app:
image: myapp:1.0
container_name: myapp
ports:
- "8080:8080"
environment:
DB_HOST: 10.0.1.15
DB_PORT: 3306
REDIS_HOST: 10.0.1.20
volumes:
- /data/uploads:/app/uploads
- /data/logs:/app/logs
restart: always

nginx:
image: nginx:stable
container_name: mynginx
ports:
- "80:80"
- "443:443"
volumes:
- /data/nginx/conf.d:/etc/nginx/conf.d
- /data/nginx/certs:/etc/nginx/certs
depends_on:
- app
restart: always
```

AWS帳號認證開通 啟動:

```bash
docker compose up -d
```

查看狀態:

```bash
docker compose ps
```

查看日誌:

```bash
docker compose logs -f app
```

### 適合用 Compose 的情況

- Nginx + App
- App + Worker
- App + 本地測試版 MySQL / Redis
- 多個環境變數與 volume 需要統一管理

---

AWS帳號認證開通 ## 十、Nginx 反向代理遷移實戰

AWS帳號認證開通 原 VM 很多時候是 Nginx 對外 80/443,再反代到本機 8080。容器化後,這個結構通常還會保留。

### Nginx 配置範例

`/data/nginx/conf.d/app.conf`

```nginx
server {
listen 80;
server_name example.com;

location / {
proxy_pass http://app:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```

這裡的 `app` 是 Compose 服務名,不再是 VM 上的 `127.0.0.1:8080`。

### 常見問題

**問題:Nginx 回 502**

排查順序:

1. `docker compose ps` 看 app 是否存活
2. `docker compose logs -f app` 看應用是否啟動成功
3. 進入 Nginx 容器測試:

```bash
docker exec -it mynginx sh
nc -zv app 8080
```

4. 檢查 `proxy_pass` 是否寫對
5. 檢查應用是否監聽 `0.0.0.0:8080`

---

## 十一、上線切換流程:不要直接停 VM 再啟容器

最穩妥的方式不是「停掉舊 VM 上服務,直接改用 Docker」,而是走灰度驗證或平滑切換。

### 建議切換步驟

## 1. 在新環境先完整啟動容器

確認:
- 容器正常啟動
- 配置已生效
- 資料庫可連
- Redis 可連
- API 可回應
- 日誌正常輸出

## 2. 用 hosts 或測試域名驗證

先不要切正式流量,使用:
- 本地 hosts 指向新伺服器 IP
- 二級測試域名
- 負載均衡測試後端

### 驗證項目

- 首頁存取
- 登入
- 上傳
- 下載
- 寫入資料庫
- 快取讀寫
- 定時任務
- 回呼接口

## 3. 降低 DNS TTL

在正式切換前,把 DNS TTL 調低,方便快速回切。

## 4. 保留原 VM 一段時間

即使新容器已上線,也建議保留舊 VM 運行窗口,至少觀察一段時間,避免一出故障就無法快速回滾。

---

## 十二、遷移後必做檢查清單

上線後不要只看「頁面能打開」,還要逐項核對。

### 應用層

- 進程是否穩定
- 健康檢查是否正常
- 是否有重啟循環
- 錯誤日誌是否增加

### 網路層

- 公網 IP 是否可達
- 80/443/業務埠是否放通
- 安全組與防火牆是否一致
- 內網依賴是否穩定

AWS帳號認證開通 ### 資料層

- 寫入資料是否正常
- 上傳檔案是否落到正確掛載目錄
- 備份策略是否延續
- 快照或資料備份是否已建立

### 資源層

- CPU 使用率
- 記憶體使用率
- 磁碟 IOPS
- 容器日誌膨脹速度

常用命令:

```bash
docker stats
df -h
free -m
top
```

---

## 十三、常見故障排查

下面列出遷移過程中最常遇到的幾類錯誤與處理方式。

## 1. 容器啟動即退出

排查:

```bash
docker ps -a
docker logs
```

常見原因:
- CMD / ENTRYPOINT 寫錯
- 啟動檔不存在
- 配置檔沒掛進去
- 程式報錯後主進程退出

---

## 2. 容器埠映射了但外部訪問不到

排查順序:

AWS帳號認證開通 1. 容器內是否監聽 `0.0.0.0`
2. `docker ps` 是否有埠映射
3. 宿主機防火牆是否開放
4. 雲安全組是否放行
5. 是否綁定正確公網 IP

檢查:

```bash
docker ps
ss -lntp
curl http://127.0.0.1:8080
curl http://:8080
```

---

## 3. 連不上 MySQL

排查:

- `DB_HOST` 是否還是 localhost
- MySQL 白名單是否開放
- 帳號是否允許遠端登入
- 安全組 3306 是否放通
- 目標資料庫是否啟用了內網位址

測試:

```bash
mysql -h 10.0.1.15 -P 3306 -u appuser -p
```

如果容器裡沒有 mysql client,可用臨時容器測。

---

## 4. 上傳檔案失敗

常見原因:
- volume 沒掛載
- 目錄不存在
- 權限不足
- 容器內路徑與應用配置不一致

排查:

```bash
docker exec -it myapp sh
ls -l /app/uploads
touch /app/uploads/test.txt
```

如果不能寫,優先看宿主機權限。

---

## 5. Nginx 502 / 504

502 常見是應用沒起來或 upstream 錯誤。
504 常見是應用能連上但回應超時。

排查:

```bash
docker logs mynginx
docker logs myapp
```

再檢查:
- upstream 位址
- 服務名解析
- 應用埠
- 應用啟動耗時
- 超時配置

---

## 十四、性能與穩定性優化建議

遷移完成後,建議順手把幾個容易踩坑的點處理掉。

## 1. 加上重啟策略

```bash
--restart always
```

或 Compose:

```yaml
restart: always
```

## 2. 限制容器資源

AWS帳號認證開通 避免單個容器把主機資源吃滿:

```bash
docker run -d \
--name myapp \
--memory=1g \
--cpus=1.0 \
-p 8080:8080 \
myapp:1.0
```

## 3. 控制日誌大小

避免磁碟被容器日誌打滿:

```bash
docker run -d \
--log-opt max-size=100m \
--log-opt max-file=3 \
--name myapp \
myapp:1.0
```

## 4. 做基本健康檢查

可以在 Dockerfile 或 Compose 中加健康檢查,便於快速發現異常。

---

## 十五、回滾方案一定要提前準備

真正的生產遷移,不是只想著怎麼成功,而是要想「失敗後 5 分鐘內怎麼恢復」。

### 建議回滾預案

1. 原 VM 服務暫時不要刪
2. DNS 切換前先降低 TTL
3. 保留舊版配置檔
4. 保留上一版映像
5. 建立資料備份或快照

### 需要備份的內容

- 應用配置
- 掛載目錄資料
- Nginx 配置
- SSL 憑證
- 資料庫備份

如果要重裝或更換伺服器,也建議先做系統快照與資料快照,這樣即使容器化遷移中斷,也能快速恢復原狀。

---

## 十六、一套可直接照做的最小遷移流程

如果你想要一個最精簡但能落地的流程,可以按下面執行:

### 第 1 步:盤點原 VM

AWS帳號認證開通 記錄:
- 啟動命令
- 埠
- 配置檔
- 依賴服務
- 資料目錄

### 第 2 步:製作 Dockerfile

根據目前執行環境選對基礎映像,不要先隨意升版本。

### 第 3 步:外置配置與資料

- 環境變數外置
- volume 掛載資料與日誌

### 第 4 步:本機或測試機驗證

確認容器可以獨立啟動,且基本功能正常。

### 第 5 步:部署到雲伺服器

檢查:
- 安全組
- 防火牆
- 公網 IP
- 私網連通性

### 第 6 步:接入 Nginx 或負載均衡

把對外流量導到容器服務。

### 第 7 步:灰度驗證

用測試域名或少量流量先跑。

### 第 8 步:正式切換

保留舊 VM 作為回滾節點。

---

## 結語

從虛擬機器遷移到 Docker,真正的難點不在 `docker build` 或 `docker run`,而在於把 VM 裡那些原本靠人工維持的細節整理清楚:啟動方式、配置來源、資料目錄、網路依賴、對外埠、權限與回滾方案。

只要你按本文的思路處理——**先盤點、再拆分、外置配置、持久化資料、先驗證後切換**——大多數從 VM 到 Docker 的遷移都能穩定落地。

如果你正在實作,優先關注這 5 個高頻故障點:

1. 應用是否監聽 `0.0.0.0`
2. 資料庫位址是否仍寫成 `localhost`
3. 重要資料是否用了 volume 掛載
4. 安全組與防火牆是否放通埠
5. 切換前是否保留回滾路徑

AWS帳號認證開通 把這 5 點做好,遷移成功率會高很多。

Telegram售前客服
客服ID
@cloudcup
联系
Telegram售后客服
客服ID
@yanhuacloud
联系