前言:為什么你需要學習Docker?
想象一下,你開發了一個應用程序,在你的電腦上運行完美,但當你把它交給同事或部署到服務器時,卻出現了各種奇怪的問題。這就是著名的"在我機器上能運行"問題。
Docker就是解決這個問題的神器!它能確保你的應用在任何地方都能一致地運行,無論是在你的筆記本電腦、數據中心的服務器,還是在云平臺上。
學習路徑圖:
本手冊專為零基礎小白設計,通過簡單易懂的語言、實用示例和互動練習,帶你從Docker小白成長為能夠熟練使用Docker的開發者。
第一章:Docker基礎概念
1.1 什么是Docker?
Docker是一種容器化技術,它允許你將應用程序及其所有依賴(代碼、庫、環境變量等)打包到一個輕量級、可移植的"容器"中。
類比理解:
┌──────────────────────────────────────┐
│ 宿主機操作系統 │
├───────────┬───────────┬──────────────┤
│ 容器1 │ 容器2 │ 容器3 │
│ (應用A) │ (應用B) │ (應用C) │
│ ┌─────┐ │ ┌─────┐ │ ┌─────┐ │
│ │應用 │ │ │應用 │ │ │應用 │ │
│ │代碼 │ │ │代碼 │ │ │代碼 │ │
│ └─────┘ │ └─────┘ │ └─────┘ │
│ ┌─────┐ │ ┌─────┐ │ ┌─────┐ │
│ │依賴 │ │ │依賴 │ │ │依賴 │ │
│ │庫 │ │ │庫 │ │ │庫 │ │
│ └─────┘ │ └─────┘ │ └─────┘ │
└───────────┴───────────┴──────────────┘
- 每個容器就像一艘集裝箱船上的標準集裝箱
- 每個集裝箱(容器)都包含特定的貨物(應用程序)
- 無論船(服務器)是什么類型,集裝箱都能被正確裝卸和運輸
- 集裝箱之間相互隔離,互不影響
💡 小貼士:Docker容器共享宿主機的操作系統內核,而虛擬機需要運行完整的操作系統,因此容器更輕量、啟動更快。
1.2 Docker架構
Docker采用客戶端-服務端架構,主要組件包括:
┌───────────────────────────────────────────────────────────────┐
│ 宿主機 │
├───────────────────┬───────────────────────────┬───────────────┤
│ Client │ Docker Daemon │ Registry │
│ (docker命令行) │ (dockerd, containerd) │ (Docker Hub) │
└─────────┬─────────┴─────────────────┬───────┴───────┬───────┘│ │ │▼ ▼ ▼
┌─────────────────┐ ┌──────────────────┐ ┌──────────────┐
│ Docker CLI │ │ Container Runtime│ │ Image Store │
└─────────────────┘ └──────────────────┘ └──────────────┘
- Docker CLI:命令行界面,用于向Docker守護進程發送命令
- Docker Daemon:Docker守護進程,負責管理鏡像、容器、網絡和卷等
- Container Runtime:容器運行時(如containerd),負責運行容器
- Registry:鏡像倉庫,用于存儲和分發Docker鏡像
1.3 Docker vs 虛擬機
特性 | Docker容器 | 虛擬機 |
---|---|---|
架構 | 直接運行在宿主機操作系統上 | 運行在Hypervisor上 |
資源占用 | 輕量級(MB級別) | 重量級(GB級別) |
啟動速度 | 秒級 | 分鐘級 |
隔離性 | 進程級隔離 | 完整操作系統隔離 |
性能 | 幾乎無損耗 | 有性能損耗 |
關鍵區別:
┌───────────────────┐ ┌───────────────────┐
│ 虛擬機 │ │ Docker │
├─────────┬─────────┤ ├─────────┬─────────┤
│ Guest OS│ 應用 │ │ 應用 │ 依賴 │
├─────────┼─────────┤ ├─────────┼─────────┤
│ Hypervisor │ │ Docker │ │
├─────────┼─────────┤ ├─────────┼─────────┤
│ Host OS │ │ │ Host OS │ │
└─────────┴─────────┘ └─────────┴─────────┘
1.4 Docker核心概念
鏡像(Image)
- Docker的"藍圖"或"模板"
- 包含運行應用程序所需的一切
- 只讀層,不可修改
容器(Container)
- 鏡像的運行實例
- 鏡像 + 可寫層
- 應用程序實際運行的地方
倉庫(Repository)
- 存儲Docker鏡像的地方
- 最常用的公共倉庫:Docker Hub
Docker Hub上最受歡迎的鏡像:
- 數據庫:
- PostgreSQL(1B+ pulls,14502 stars)
- MySQL(1B+ pulls,15899 stars)
- MongoDB(1B+ pulls,10623 stars)
- 開發環境:
- Node.js(1B+ pulls,13983 stars)
- OpenJDK(1B+ pulls,4067 stars)
- Golang(1B+ pulls,5063 stars)
- PHP(1B+ pulls,7790 stars)
Dockerfile
- 創建Docker鏡像的"配方"
- 包含一系列指令
💡 避坑指南:鏡像是靜態的,容器是動態的。你可以從同一個鏡像啟動多個容器實例。
1.5 Docker Engine更新渠道
Docker Engine提供兩種更新渠道:
- Stable(穩定版):經過充分測試的正式發布版本
- Test(測試版):預發布版本,用于測試新功能
生產環境建議使用Stable渠道,開發環境可考慮使用Test渠道體驗新功能。
第二章:安裝Docker
2.1 Windows系統安裝
-
下載Docker Desktop:
- 訪問 Docker官網
- 點擊"Download for Windows"
-
安裝過程:
- 雙擊下載的安裝文件
- 按照向導提示進行安裝
- 建議勾選"Install required Windows components for WSL 2"
-
啟動Docker:
- 安裝完成后,Docker會自動啟動
- 檢查系統托盤,看到鯨魚圖標表示Docker正在運行
-
驗證安裝:
在命令提示符或PowerShell中輸入:
> docker --version Docker version 24.0.7, build afdd53b
💡 小貼士:Windows 10家庭版需要額外安裝WSL 2(Windows Subsystem for Linux 2)。安裝后可能需要重啟電腦。
許可說明:Docker Desktop 對于個人用戶、教育機構和中小型企業是免費的。大型企業(超過250名員工或年收入超過1000萬美元)需要購買商業許可。
2.2 macOS系統安裝
-
下載Docker Desktop:
- 訪問 Docker官網
- 點擊"Download for Mac"
-
安裝過程:
- 雙擊下載的
.dmg
文件 - 將Docker圖標拖到Applications文件夾
- 在Applications中雙擊Docker.app啟動
- 雙擊下載的
-
驗證安裝:
在終端中輸入:
> docker --version Docker version 24.0.7, build afdd53b
2.3 Linux系統安裝(Ubuntu 22.04示例)
# 1. 更新軟件包索引
> sudo apt update# 2. 安裝必要的軟件包
> sudo apt install apt-transport-https ca-certificates curl software-properties-common# 3. 添加Docker官方GPG密鑰
> curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg# 4. 設置Docker穩定版倉庫
> echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null# 5. 安裝Docker引擎
> sudo apt update
> sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin# 6. 驗證Docker是否正確安裝
> sudo docker run hello-world
💡 避坑指南:安裝后,普通用戶無法直接運行Docker命令。解決方法:
> sudo usermod -aG docker $USER
> newgrp docker # 或者重啟終端
注意:以上以Ubuntu為例,其他Linux發行版的安裝命令請參考Docker官方安裝文檔。
2.4 Docker Desktop功能詳解
Docker Desktop不僅包含Docker Engine,還提供了一系列增強功能:
- Docker Engine:強大的容器運行時,提供高性能和可靠的容器化應用支持
- Docker CLI:靈活的命令行界面,提供精確的容器控制
- Docker Compose:簡化多容器應用的管理
- Docker Build:簡化容器鏡像構建過程
- Docker Kubernetes:內置Kubernetes支持,無需外部集群即可本地開發
- Volume Management:有效的數據管理解決方案
- Synchronized File Shares:實時同步主機和容器間的文件
- Docker Debug:高級故障排除工具
- Hardened Docker Desktop:增強的容器隔離和安全性
- VDI Support:虛擬桌面基礎設施集成
- Docker Private Extensions Marketplace:定制化擴展功能
2.5 驗證安裝
無論哪個平臺,安裝完成后運行以下命令:
> docker run hello-world
如果看到類似以下輸出,說明Docker安裝成功:
Hello from Docker!
This message shows that your installation appears to be working correctly.
💡 小貼士:docker --version
只驗證了客戶端。docker run hello-world
驗證整個Docker引擎(客戶端+守護進程)都已正確安裝并運行。
第三章:Docker基礎操作
3.1 第一個Docker容器
讓我們運行一個簡單的Nginx Web服務器:
> docker run -d -p 8080:80 --name my-nginx nginx
參數解釋:
-d
:后臺運行容器(detached模式)-p 8080:80
:將宿主機的8080端口映射到容器的80端口--name my-nginx
:給容器命名nginx
:要使用的鏡像名稱(如果本地不存在,Docker會自動從Docker Hub拉取官方nginx鏡像)
💡 小貼士:docker run
命令實際上融合了 docker pull
(如果鏡像不存在)、docker create
、docker start
三個步驟。
驗證:
- 打開瀏覽器
- 訪問
http://localhost:8080
- 應該看到Nginx歡迎頁面
3.2 常用Docker命令
容器管理
# 列出正在運行的容器
> docker ps# 列出所有容器(包括停止的)
> docker ps -a# 停止一個容器
> docker stop my-nginx# 啟動一個已停止的容器
> docker start my-nginx# 重啟容器
> docker restart my-nginx# 刪除容器
> docker rm my-nginx# 查看容器日志
> docker logs my-nginx# 進入正在運行的容器
> docker exec -it my-nginx bash# 查看Docker磁盤使用情況
> docker system df
鏡像管理
# 列出本地鏡像
> docker images# 拉取鏡像(從Docker Hub)
> docker pull ubuntu:22.04# 刪除鏡像
> docker rmi nginx# 構建鏡像(基于Dockerfile)
> docker build -t my-app:1.0 .
💡 避坑指南:刪除正在運行的容器前,需要先停止它:docker stop container_id && docker rm container_id
,或者直接使用docker rm -f container_id
強制刪除。
3.3 實戰練習:運行Python應用
-
創建一個簡單的Python應用:
> mkdir python-app > cd python-app > echo "from http.server import HTTPServer, BaseHTTPRequestHandlerclass SimpleHandler(BaseHTTPRequestHandler):def do_GET(self):self.send_response(200)self.send_header('Content-type', 'text/html')self.end_headers()self.wfile.write(b'Hello from Docker!')if __name__ == '__main__':server = HTTPServer(('0.0.0.0', 8000), SimpleHandler)server.serve_forever()" > app.py
-
運行Python應用容器:
> docker run -d -p 8000:8000 -v $(pwd):/app -w /app python:3.11 python app.py
-
訪問
http://localhost:8000
查看結果
命令解釋:
-v $(pwd):/app
:將當前目錄掛載到容器的/app目錄-w /app
:設置工作目錄為/apppython:3.11
:使用Python 3.11官方鏡像
💡 小貼士:在Windows PowerShell中,$(pwd)
應替換為${PWD}
。
📝 本章練習
- 運行一個Ubuntu容器:
docker run -it ubuntu bash
- 在容器內執行
ls /
,查看文件系統 - 退出容器(輸入
exit
或按Ctrl+D) - 再次運行相同的命令,觀察結果有何不同
- (挑戰)運行一個MySQL容器,使用
-e MYSQL_ROOT_PASSWORD=my-secret-pw
設置root密碼,并使用docker exec
命令進入容器驗證MySQL是否正常運行
第四章:Dockerfile詳解
4.1 什么是Dockerfile?
Dockerfile是一個文本文件,包含了一系列指令,告訴Docker如何構建一個鏡像。
4.2 基本Dockerfile結構
讓我們創建一個簡單的Node.js應用Dockerfile:
# 1. 基礎鏡像
FROM node:18# 2. 設置工作目錄
WORKDIR /app# 3. 復制package.json(先單獨復制,利用Docker緩存)
COPY package.json .# 4. 安裝依賴
RUN npm install# 5. 復制應用代碼
COPY . .# 6. 暴露端口
EXPOSE 3000# 7. 定義啟動命令
CMD ["npm", "start"]
4.3 關鍵指令詳解
指令 | 用途 | 示例 |
---|---|---|
FROM | 指定基礎鏡像 | FROM ubuntu:22.04 |
ARG | 定義構建參數 | ARG NODE_VERSION=18 FROM node:${NODE_VERSION} |
RUN | 在鏡像中執行命令 | RUN apt-get update && apt-get install -y python3 |
COPY | 復制文件到鏡像 | COPY app.py /app/ |
ADD | 類似COPY,但支持URL和自動解壓 | ADD https://example.com/file.tar.gz /app/ |
WORKDIR | 設置工作目錄 | WORKDIR /app |
ENV | 設置環境變量 | ENV NODE_ENV=production |
EXPOSE | 聲明容器運行時監聽的端口 | EXPOSE 80 |
CMD | 容器啟動時執行的命令 | CMD ["python", "app.py"] |
ENTRYPOINT | 容器啟動時執行的命令(不可覆蓋) | ENTRYPOINT ["java", "-jar", "/app.jar"] |
4.4 構建和運行自定義鏡像
-
創建Node.js應用:
> mkdir node-app > cd node-app > npm init -y > echo 'const express = require("express"); const app = express(); app.get("/", (req, res) => res.send("Hello from Docker!")); app.listen(3000, () => console.log("Server running on port 3000"));' > index.js
-
創建Dockerfile(內容如上所述)
-
構建鏡像:
> docker build -t my-node-app:1.0 .
-
運行容器:
> docker run -d -p 3000:3000 --name node-app my-node-app:1.0
-
訪問
http://localhost:3000
💡 避坑指南:Docker構建時,默認使用當前目錄作為上下文。確保Dockerfile在項目根目錄,且不包含不必要的大文件(使用.dockerignore)。
4.5 Docker BuildKit詳解
Docker BuildKit是Docker 18.09+引入的下一代構建系統,提供了顯著的性能改進和新功能:
啟用BuildKit:
# 臨時啟用
> DOCKER_BUILDKIT=1 docker build .# 永久啟用(修改daemon.json)
{"features": {"buildkit": true}
}
BuildKit優勢:
- 更快的構建速度:并行構建和緩存優化
- 更好的安全性:隔離的構建環境
- 高級功能:
# 語法聲明(使用BuildKit特有功能) # syntax=docker/dockerfile:1.3# SSH轉發 FROM alpine RUN --mount=type=ssh ssh example.com ls# 構建時緩存 RUN --mount=type=cache,target=/root/.cache/go-build go build .# 秘密管理 RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret
💡 小貼士:Docker 23.0+默認啟用BuildKit,可以自動清理中間層,進一步減小鏡像大小。
4.6 優化Docker鏡像大小
1. 使用合適的基鏡像
- 優先使用
alpine
版本(更小) - 例如:
node:18-alpine
比node:18
小約200MB
2. 多階段構建
# 構建階段
FROM node:18 as builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production # 使用ci確保依賴版本確定性
COPY . .
RUN npm run build# 運行階段
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY package.json .
RUN npm ci --only=production
EXPOSE 3000
CMD ["node", "dist/index.js"]
3. 減少鏡像層數
# 不推薦
RUN apt-get update
RUN apt-get install -y package1 package2# 推薦(合并為一條命令)
RUN apt-get update && apt-get install -y \package1 \package2 \&& rm -rf /var/lib/apt/lists/*
4. 清理不必要的文件
RUN npm install && npm cache clean --force
5. 使用.dockerignore文件
創建.dockerignore
文件,排除不需要的文件:
node_modules
.git
*.log
.env
Dockerfile
.dockerignore
📝 本章練習
- 為你的Python應用創建Dockerfile
- 構建并運行鏡像
- 使用
docker image inspect
查看鏡像詳情 - (挑戰)嘗試使用多階段構建優化你的Docker鏡像
第五章:Docker Compose
5.1 什么是Docker Compose?
Docker Compose是用于定義和運行多容器Docker應用程序的工具。通過一個YAML文件配置應用程序服務,然后使用一個命令創建并啟動所有服務。
5.2 安裝Docker Compose
- Windows/macOS:Docker Desktop已包含Compose
- Linux:Docker 20.10+已內置Compose插件,無需單獨安裝
💡 小貼士:在Linux上,舊版Docker需要單獨安裝Compose:
> sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
> sudo chmod +x /usr/local/bin/docker-compose
5.3 Docker Compose Specification
Docker Compose已發展為Compose Specification,這是云原生計算基金會(CNCF)的項目,旨在標準化多容器應用的定義。最新版本已移除version
字段要求:
services:web:image: nginxports:- "8080:80"db:image: postgresenvironment:POSTGRES_PASSWORD: example
這種格式與Docker Compose、Podman Compose和Kubernetes的Kompose兼容,提供更廣泛的互操作性。
5.4 docker-compose.yml結構
version: '3.8' # 指定Compose文件格式版本services: # 定義所有服務web: # 服務名稱image: nginx:latest # 使用的鏡像ports:- "8080:80" # 端口映射volumes:- ./html:/usr/share/nginx/html # 卷掛載db:image: mysql:8.0environment:MYSQL_ROOT_PASSWORD: example # 設置環境變量MYSQL_DATABASE: mydbvolumes:- db_data:/var/lib/mysql # 命名卷volumes: # 定義卷db_data:
💡 小貼士:對于新項目,可以直接使用Compose Specification(即直接寫 services:
),這代表最新標準。工具會自動兼容。
5.5 實戰:部署WordPress應用
-
創建項目目錄:
> mkdir wordpress-app > cd wordpress-app
-
創建
docker-compose.yml
文件:version: '3.8'services:db:image: mysql:8.0volumes:- db_data:/var/lib/mysqlrestart: alwaysenvironment:MYSQL_ROOT_PASSWORD: somewordpressMYSQL_DATABASE: wordpressMYSQL_USER: wordpressMYSQL_PASSWORD: wordpresshealthcheck: # 添加健康檢查test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u$$MYSQL_USER", "-p$$MYSQL_PASSWORD"]interval: 10stimeout: 5sretries: 5wordpress:depends_on:db:condition: service_healthy # 確保數據庫真正就緒image: wordpress:latestports:- "8000:80"restart: alwaysenvironment:WORDPRESS_DB_HOST: db:3306WORDPRESS_DB_USER: wordpressWORDPRESS_DB_PASSWORD: wordpressWORDPRESS_DB_NAME: wordpress volumes:db_data:
-
啟動應用:
> docker-compose up -d
-
訪問
http://localhost:8000
開始WordPress安裝 -
常用Compose命令:
# 啟動所有服務 > docker-compose up -d# 停止所有服務 > docker-compose down# 查看服務日志 > docker-compose logs -f# 重啟服務 > docker-compose restart wordpress# 構建/重新構建服務 > docker-compose build
?? 重要提示:depends_on
只控制啟動順序,不等待服務真正就緒。對于需要等待數據庫初始化的應用,必須實現健康檢查并使用condition: service_healthy
,這是生產環境的最佳實踐。
📝 本章練習
- 創建一個包含Nginx和Alpine的Compose文件
- 配置Nginx服務監聽8080端口
- 使用
docker-compose up
啟動服務 - 訪問
http://localhost:8080
驗證 - (挑戰)為Nginx配置自定義HTML內容(使用卷掛載)
第六章:Docker網絡
6.1 Docker網絡模式
模式 | 描述 | 使用場景 |
---|---|---|
bridge | 默認模式,容器通過虛擬網橋連接 | 單機上多個容器通信 |
host | 容器直接使用宿主機網絡 | 需要高性能網絡的應用 |
none | 容器沒有網絡 | 完全隔離的容器 |
overlay | 跨多個Docker守護進程的網絡 | Docker Swarm集群 |
6.2 創建自定義網絡
# 創建自定義橋接網絡
> docker network create my-network# 在自定義網絡中運行容器
> docker run -d --name web --network my-network nginx
> docker run -it --name alpine --network my-network alpine sh# 在alpine容器中測試與web容器的連接
/ # ping web
6.3 容器間通信
場景:前端應用需要連接后端API
-
創建自定義網絡:
> docker network create app-network
-
啟動后端服務:
> docker run -d --name backend --network app-network -p 5000:5000 my-backend-image
-
啟動前端服務:
> docker run -d --name frontend --network app-network -p 3000:3000 \-e API_URL=http://backend:5000 my-frontend-image
-
前端容器可以通過
http://backend:5000
訪問后端服務
6.4 網絡排查
# 查看所有網絡
> docker network ls# 查看特定網絡的詳細信息
> docker network inspect app-network# 查看容器的網絡配置
> docker inspect frontend | grep IPAddress
💡 避坑指南:Docker容器使用服務名稱作為主機名進行通信。確保在代碼中使用服務名稱(如http://backend:5000
)而不是IP地址。
📝 本章練習
- 創建一個自定義網絡
test-net
- 在該網絡中運行兩個Nginx容器
- 從一個容器ping另一個容器
- 嘗試不使用自定義網絡,直接通過容器名通信(會失敗)
- (挑戰)創建一個包含前端、后端和數據庫的Compose文件,并配置正確的網絡
第七章:數據持久化
7.1 為什么需要數據持久化?
默認情況下,容器停止后,容器內的所有數據都會丟失。對于數據庫等需要持久存儲的應用,我們需要將數據存儲在容器外部。
7.2 三種數據管理方式
類型 | 描述 | 適用場景 |
---|---|---|
數據卷(Volumes) | 由Docker管理的存儲區域 | 生產環境,最佳實踐 |
綁定掛載(Bind Mounts) | 將宿主機目錄直接掛載到容器 | 開發環境,需要實時編輯文件 |
tmpfs掛載 | 僅存儲在內存中 | 臨時數據,敏感數據 |
7.3 使用數據卷
# 創建命名卷
> docker volume create my-volume# 查看所有卷
> docker volume ls# 使用卷運行容器
> docker run -d -v my-volume:/app/data --name my-container nginx# 查看卷詳情
> docker volume inspect my-volume# 清理未使用的卷
> docker volume prune
7.4 數據卷備份與恢復
數據卷備份:
# 創建備份容器
> docker run --rm -v my-volume:/volume -v $(pwd):/backup alpine \tar cvf /backup/backup.tar -C /volume .
數據卷恢復:
# 創建新卷
> docker volume create restore-volume# 恢復數據
> docker run --rm -v restore-volume:/volume -v $(pwd):/backup alpine \tar xvf /backup/backup.tar -C /volume
生產環境建議:
- 使用定時任務定期備份關鍵數據卷
- 將備份存儲到安全位置(如云存儲)
- 測試恢復流程,確保備份有效
- 考慮使用專業備份工具如Velero(Kubernetes環境)
7.5 實戰:MySQL數據持久化
# 創建數據卷
> docker volume create mysql-data# 運行MySQL容器
> docker run -d \-v mysql-data:/var/lib/mysql \-e MYSQL_ROOT_PASSWORD=my-secret-pw \--name mysql \mysql:8.0
即使容器被刪除,數據仍然保留在mysql-data
卷中。
💡 避坑指南:數據卷的路徑在宿主機上通常是/var/lib/docker/volumes/
,但不應直接操作這些文件,應通過Docker命令管理。
7.6 使用綁定掛載進行開發
# 將當前目錄掛載到容器的/app目錄
> docker run -d \-v $(pwd):/app \-w /app \node:18 \npm start
開發優勢:
- 代碼修改后無需重新構建鏡像
- 實時看到更改效果
- 適合前端開發和熱重載
📝 本章練習
- 創建一個數據卷
app-data
- 運行一個Nginx容器,將
/usr/share/nginx/html
掛載到該卷 - 在卷中創建一個
index.html
文件 - 訪問Nginx服務,驗證內容
- (挑戰)使用綁定掛載開發一個簡單的Node.js應用,實現代碼熱重載
第八章:實戰項目 - 部署一個完整的Web應用
8.1 項目結構
my-app/
├── frontend/ # 前端代碼(React)
├── backend/ # 吘端代碼(Node.js)
├── docker-compose.yml
└── README.md
8.2 前端Dockerfile
# frontend/Dockerfile
# 構建階段
FROM node:18 as build
WORKDIR /app
COPY package*.json ./
RUN npm ci # 使用ci確保依賴版本確定性
COPY . .
RUN npm run build# 生產階段
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
8.3 后端Dockerfile
# backend/Dockerfile
FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production # 生產環境只安裝生產依賴
COPY . .
EXPOSE 5000
CMD ["node", "server.js"]
8.4 docker-compose.yml
version: '3.8'services:frontend:build: context: ./frontendlabels:- "org.opencontainers.image.revision=${GIT_COMMIT:-latest}" # 注入git commit信息ports:- "3000:80"depends_on:backend:condition: service_healthynetworks:- app-networkbackend:build: context: ./backendlabels:- "org.opencontainers.image.revision=${GIT_COMMIT:-latest}"ports:- "5000:5000"environment:DB_HOST: dbDB_USER: userDB_PASS: passworddepends_on:db:condition: service_healthynetworks:- app-networkhealthcheck:test: ["CMD", "curl", "-f", "http://localhost:5000/health"]interval: 30stimeout: 10sretries: 3db:image: postgres:15environment:POSTGRES_USER: userPOSTGRES_PASSWORD: passwordPOSTGRES_DB: mydbvolumes:- pgdata:/var/lib/postgresql/datanetworks:- app-networkhealthcheck:test: ["CMD-SHELL", "pg_isready -U user"]interval: 10stimeout: 5sretries: 5networks:app-network:driver: bridgevolumes:pgdata:
💡 小貼士:condition: service_healthy
確保服務真正就緒后再啟動依賴服務,避免啟動順序問題。通過labels注入git commit信息便于鏡像追蹤。
8.5 部署步驟
-
克隆項目:
> git clone https://github.com/yourusername/my-app.git > cd my-app
-
啟動應用:
> docker-compose up -d --build
-
訪問應用:
- 前端:
http://localhost:3000
- 后端API:
http://localhost:5000/api
- 前端:
-
查看日志:
> docker-compose logs -f
-
停止應用:
> docker-compose down
📝 本章練習
- 創建一個簡單的前后端分離應用
- 為前后端分別編寫Dockerfile
- 創建docker-compose.yml文件,配置服務依賴和網絡
- 實現健康檢查,確保服務正確啟動
- (挑戰)添加Redis服務,并配置前后端使用Redis
第九章:常見問題與解決方案
9.1 容器無法啟動
問題:容器啟動后立即退出
原因:主進程執行完畢退出
解決方案:
- 確保
CMD
或ENTRYPOINT
指定的是長期運行的進程 - 使用
-it
參數運行容器進行調試:> docker run -it --rm my-image sh
💡 避坑指南:容器必須有一個前臺進程才能保持運行。如果運行的是后臺服務,需要使用-d
參數或確保命令保持前臺運行。
9.2 端口沖突
問題:
Error response from daemon: driver failed programming external connectivity on endpoint...:
bind: address already in use.
解決方案:
- 更換宿主機端口:
> docker run -p 8081:80 nginx
- 停止占用端口的進程:
# Linux/Mac > lsof -i :8080# Windows > netstat -ano | findstr :8080
9.3 鏡像拉取失敗
問題:
Error response from daemon: Get https://registry-1.docker.io/v2/:
net/http: request canceled while waiting for connection
解決方案:
- 檢查網絡連接
- 配置Docker鏡像加速器(針對中國用戶):
- 創建或修改
/etc/docker/daemon.json
- 添加:
{"registry-mirrors": ["https://docker.mirrors.ustc.edu.cn","https://hub-mirror.c.163.com"] }
- 重啟Docker:
sudo systemctl restart docker
- 創建或修改
💡 小貼士:Docker Desktop用戶可以在設置中直接配置鏡像加速器。常用的鏡像加速器包括:
- 阿里云容器鏡像服務(需登錄獲取個人加速地址)
- 網易云:
https://hub-mirror.c.163.com
- 中國科學技術大學:
https://docker.mirrors.ustc.edu.cn
9.4 容器內無法訪問網絡
問題:容器內無法ping通外部網絡
解決方案:
- 檢查DNS配置:
> docker run --dns=8.8.8.8 -it ubuntu ping google.com
- 檢查防火墻設置
- 重置Docker網絡:
> docker network prune
9.5 清理磁盤空間
問題:Docker占用大量磁盤空間
解決方案:
# 清理停止的容器
> docker container prune# 清理未使用的鏡像
> docker image prune# 清理未使用的網絡
> docker network prune# 清理所有未使用的資源(包括構建緩存)
> docker system prune -a# 查看磁盤使用情況
> docker system df
💡 避坑指南:定期清理可以避免磁盤空間不足問題。建議在CI/CD管道中添加清理步驟。
📝 本章練習
- 故意制造一個端口沖突,然后解決它
- 模擬鏡像拉取失敗,配置鏡像加速器
- 創建一個無法啟動的容器,使用
-it
調試 - (挑戰)編寫一個腳本,每天自動清理Docker資源
第十章:最佳實踐與安全建議
10.1 鏡像構建最佳實踐
-
使用.dockerignore文件:
node_modules .git *.log .env Dockerfile .dockerignore
-
合理排序Dockerfile指令:
- 將變化較少的指令放在前面
- 例如:先COPY package.json,再RUN npm install,最后COPY其他文件
-
使用多階段構建:
- 減小最終鏡像大小
- 避免將構建工具包含在生產鏡像中
-
指定軟件包版本:
RUN apt-get install -y python3=3.10.6-1ubuntu0.1
-
鏡像分層原理:
- Docker鏡像由多層只讀層組成
- 每條Dockerfile指令創建一個新層
- 利用緩存機制:當某一層發生變化時,其后的所有層都需要重新構建
- 合并相關操作到同一層可減少鏡像層數
10.2 安全最佳實踐
-
不要以root用戶運行容器:
FROM node:18 RUN groupadd -r appuser && useradd -r -g appuser appuser USER appuser
-
定期更新基礎鏡像:
> docker pull node:18 > docker build -t my-app:latest .
-
掃描鏡像漏洞:
# 需要先登錄Docker Hub > docker login > docker scan my-app:latest# 或者使用開源工具如Trivy > trivy image --severity CRITICAL,HIGH my-app:latest
-
限制容器資源:
> docker run -d \--memory=512m \--cpus=1.5 \my-app
-
不要在鏡像中存儲敏感信息:
- 使用環境變量或Docker secrets
- 通過
docker run -e
或docker-compose
的environment設置
-
使用非最新版本的具體標簽:
- 使用
node:18.18.0-alpine
而不是node:18-alpine
或node:latest
- 確保部署的確定性和安全性
- 使用
-
最小權限原則:
> docker run --cap-drop ALL --cap-add NET_BIND_SERVICE my-app
-
Docker內容信任(Docker Content Trust):
# 啟用內容信任 > export DOCKER_CONTENT_TRUST=1# 簽名并推送鏡像 > docker trust sign myimage:tag# 驗證簽名 > docker trust inspect myimage:tag
-
安全上下文配置:
services:app:# ...security_opt:- no-new-privileges:trueread_only: truecap_drop:- ALLcap_add:- NET_BIND_SERVICE
10.3 生產環境部署建議
-
使用編排工具:
- Docker Swarm(內置)
- Kubernetes(更強大,適合大型部署)
-
實現健康檢查:
HEALTHCHECK --interval=30s --timeout=3s \CMD curl -f http://localhost/ || exit 1
-
集中式日志管理:
- 使用ELK棧(Elasticsearch, Logstash, Kibana)
- 或Docker日志驅動:
docker run --log-driver=json-file ...
-
監控與告警:
- Prometheus + Grafana
- cAdvisor(容器資源監控)
-
Docker Desktop的Kubernetes集成:
Docker Desktop內置了Kubernetes支持,無需額外安裝即可在本地開發環境中使用Kubernetes:-
啟用Kubernetes:
- Windows/macOS:Docker Desktop設置 → Kubernetes → 勾選"Enable Kubernetes"
- Linux:需單獨安裝
-
驗證安裝:
> kubectl cluster-info Kubernetes control plane is running at https://kubernetes.docker.internal:6443
-
使用Kubernetes:
> kubectl create deployment nginx --image=nginx > kubectl expose deployment nginx --port=80 > kubectl get pods
Docker Desktop的Kubernetes支持包括:
- 單節點集群(開發使用)
- 與Docker Compose的集成
- 簡單的UI管理
- 本地開發的理想環境
-
💡 避坑指南:生產環境應避免使用latest
標簽,而應使用具體的版本號,確保可重復部署。
📝 本章練習
- 為你的應用Dockerfile添加非root用戶
- 添加健康檢查指令
- 限制容器的內存和CPU使用
- (挑戰)使用Docker掃描工具檢查你的鏡像漏洞
第十一章:進階主題
11.1 Docker Swarm簡介
Docker Swarm是Docker原生的集群管理和編排工具。
基本概念:
- Node:集群中的Docker主機
- Manager:管理集群的節點
- Worker:執行任務的節點
- Service:在集群中運行的應用
創建Swarm集群:
# 初始化Swarm(作為Manager)
> docker swarm init# 獲取加入令牌
> docker swarm join-token worker# 在其他節點上加入Swarm
> docker swarm join --token <token> <manager-ip>:2377
部署服務:
> docker service create --replicas 3 -p 80:80 --name my-web nginx
11.2 Kubernetes簡介
Kubernetes(簡稱K8s)是一個開源的容器編排系統,用于自動化部署、擴展和管理容器化應用。
核心概念:
- Pod:Kubernetes中最小的部署單元,可包含一個或多個容器
- Deployment:管理Pod的聲明式更新
- Service:定義Pod的訪問策略
- Namespace:資源的虛擬集群
簡單示例:
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-deployment
spec:replicas: 3selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginx:1.14.2ports:- containerPort: 80
應用配置:
> kubectl apply -f deployment.yaml
11.3 CI/CD集成
GitHub Actions示例:
name: Docker Image CIon:push:branches: [ main ]jobs:build:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4with:fetch-depth: 0 # 獲取所有歷史記錄,便于生成標簽- name: Set up Docker Buildxuses: docker/setup-buildx-action@v3- name: Login to DockerHubuses: docker/login-action@v2with:username: ${{ secrets.DOCKERHUB_USERNAME }}password: ${{ secrets.DOCKERHUB_TOKEN }}- name: Extract metadata for Dockerid: metauses: docker/metadata-action@v5with:images: user/apptags: |type=shatype=ref,event=branchtype=ref,event=prtype=semver,pattern={{version}}type=semver,pattern={{major}}.{{minor}}- name: Build and pushuses: docker/build-push-action@v5with:context: .push: truetags: ${{ steps.meta.outputs.tags }}labels: ${{ steps.meta.outputs.labels }}cache-from: type=ghacache-to: type=gha,mode=max
💡 小貼士:Docker 23.0+引入了Buildx Build Cache,可以顯著加速CI/CD中的鏡像構建過程。使用GitHub Actions的緩存功能可以進一步提升構建效率。
11.4 Docker Swarm和Kubernetes對比
特性 | Docker Swarm | Kubernetes |
---|---|---|
學習曲線 | 簡單,易于上手 | 陡峭,需要更多學習 |
安裝配置 | 簡單,Docker內置 | 復雜,需要單獨安裝 |
功能豐富度 | 基礎功能 | 非常豐富,功能全面 |
社區支持 | 中等 | 非常活躍 |
適用場景 | 中小型應用,簡單部署 | 大型應用,復雜部署 |
擴展性 | 有限 | 非常強大 |
自動伸縮 | 基礎支持 | 高級支持 |
滾動更新 | 支持 | 高級支持 |
健康檢查 | 基礎支持 | 高級支持 |
網絡策略 | 基礎支持 | 高級支持 |
選擇建議:
- 如果是小型團隊或簡單應用,Docker Swarm足夠使用
- 如果需要高級功能或大規模部署,Kubernetes是更好的選擇
- 對于本地開發,Docker Desktop內置的Kubernetes支持是理想選擇
📝 本章練習
- 初始化一個Docker Swarm集群
- 部署一個簡單的服務
- 擴展服務的副本數
- (挑戰)嘗試將你的應用部署到Kubernetes集群
附錄A:Docker命令速查表
基礎命令
命令 | 描述 |
---|---|
docker ps | 列出正在運行的容器 |
docker ps -a | 列出所有容器 |
docker images | 列出本地鏡像 |
docker run [OPTIONS] IMAGE [COMMAND] | 運行容器 |
docker stop CONTAINER | 停止容器 |
docker start CONTAINER | 啟動容器 |
docker rm CONTAINER | 刪除容器 |
docker rmi IMAGE | 刪除鏡像 |
docker logs CONTAINER | 查看容器日志 |
docker exec -it CONTAINER COMMAND | 在運行的容器中執行命令 |
高級命令
命令 | 描述 |
---|---|
docker build -t TAG . | 構建鏡像 |
docker-compose up | 啟動Compose服務 |
docker network ls | 列出網絡 |
docker volume ls | 列出數據卷 |
docker system df | 查看Docker磁盤使用 |
docker system prune | 清理未使用的資源 |
docker inspect CONTAINER | 查看容器詳細信息 |
docker stats | 實時資源使用情況 |
docker events | 監聽Docker事件 |
docker diff CONTAINER | 查看容器文件系統變化 |
附錄B:推薦學習資源
📚 官方文檔:
- Docker官方文檔
- Docker Hub
- Compose Specification
📺 視頻教程:
- Docker入門教程(B站)
- Docker & Kubernetes: The Practical Guide (Udemy)
💻 實踐平臺:
- Play with Docker
- Katacoda Docker場景
📖 書籍推薦:
- 《Docker技術入門與實戰》
- 《Kubernetes權威指南》
🔧 實用工具:
- Trivy - 容器漏洞掃描工具
- Dive - 鏡像層分析工具
- Lens - Kubernetes IDE
- Portainer - Docker管理UI
結語:繼續你的Docker之旅
恭喜你完成了Docker入門學習!現在你已經掌握了Docker的核心概念和實用技能,可以開始在自己的項目中應用Docker了。
下一步建議:
- 實踐項目:嘗試將你現有的一個應用容器化
- 深入學習:
- 閱讀Docker官方文檔
- 學習Kubernetes基礎知識
- 加入社區:
- Docker官方論壇
- Stack Overflow的docker標簽
- 本地Docker/Kubernetes用戶組
記住,最好的學習方式是動手實踐!從簡單開始,逐步增加復雜度,很快你就會成為Docker高手。
祝你在容器化旅程中一切順利! 🐳
📝 附:學習進度檢查表
? 已完成 | ? 未完成 | 📅 計劃完成日期 |
---|---|---|
安裝Docker | ||
運行第一個容器 | ||
理解Dockerfile | ||
使用Docker Compose | ||
配置Docker網絡 | ||
實現數據持久化 | ||
部署完整Web應用 | ||
解決常見問題 | ||
應用最佳實踐 | ||
探索進階主題 |
填寫你的學習計劃,跟蹤進度!