# Docker ###### tags: `ncnu`, `lsa`, `docker`, `container` [TOC] ## Container vs VM 快速比較 ### 架構差異  ### 關鍵差異表 | 特性 | 虛擬機 (VM) | Docker 容器 | |------|------------|------------| | 啟動時間 | 數分鐘 | 數秒 | | 資源占用 | 高 (完整 OS) | 低 (共享核心) | | 映像檔大小 | GB 級 | MB 級 | | 隔離程度 | 完全隔離 | 程式級隔離 | | 適用場景 | 需要不同 OS、強隔離需求 | 微服務、CI/CD、快速部署 | --- ## Docker 核心概念 ### 三大元件 1. **Dockerfile** - 定義如何建構 image 的「食譜」 - 包含作業系統、套件、程式碼、環境設定 2. **Image (映像檔)** - 唯讀模板,由多層 (layers) 組成 - 可版本化、分享、重複使用 - 使用 UnionFS / OverlayFS 技術疊加層級 3. **Container (容器)** - Image 的執行實例 - 相互隔離但共享 OS 核心 - 在 image 唯讀層之上加一個可寫層 --- ## Container 隔離技術 ### 1. **Namespaces** (隔離可見範圍) 限制 container 能「看到」什麼: | Namespace | 功能 | |-----------|------| | **PID** | 獨立行程 ID 空間 | | **Network** | 獨立網路設備、IP、Port | | **Mount** | 獨立檔案系統掛載 | | **UTS** | 獨立 hostname | | **IPC** | 獨立行程間通訊 | | **User** | 獨立 UID/GID 映射 | ### 2. **cgroups** (限制資源使用量) 控制 container 能「用多少」資源: - CPU 時間分配 - 記憶體上限 - 磁碟 I/O 限制 - 網路頻寬控制 **範例**: ```bash # 限制記憶體 512MB docker run --memory 512MB nginx # 限制 CPU 使用率 50% docker run --cpu-quota=50000 --cpu-period=100000 ubuntu ``` --- ## Docker 架構 ``` [ 使用者 ] ↓ [ Docker Client (CLI) ] ← 你下指令的地方 ↓ (透過 UNIX Socket / REST API) [ Docker Daemon (dockerd) ] ← 核心管理者 ↓ [ Container Runtime ] ↓ [ Linux Kernel ] ↓ [ 硬體 ] ``` ### 關鍵元件 - **Docker Client**:使用者介面 (CLI / Desktop) - **Docker Daemon**:背景服務,管理 image/container/network/volume - **Docker Registry**:儲存 image 的倉庫 (如 Docker Hub) --- ## 容器化的五大優勢 1. ✅ **不破壞主機**:隔離環境,系統風險低 2. ✅ **一鍵部署**:一行指令架起完整服務 3. ✅ **輕量高速**:秒級啟動,資源消耗少 4. ✅ **高度可攜**:開發、測試、正式環境一致 5. ✅ **易於擴展**:搭配 Docker Compose/Kubernetes 自動化管理 --- ## 實際應用場景 ### ✅ 適合用 Container - 快速開發和測試環境 - CI/CD 流程 - 雲端原生應用 - 需要快速擴展的應用 - 範例:網頁程式設計、軟體工程中快速架設 PostgreSQL 和 Apache,方便測試軟體 ### ❌ 適合用 VM - 需要不同作業系統(如 macOS、FreeBSD、Nintendo Switch、PS3) - 強隔離要求(如下載學習資料但擔心有毒) - 傳統單體應用(如 Word、PowerPoint、Excel) - 需要特定核心版本或模組 --- ## 快速上手指令 ```bash # 拉取映像檔 docker pull nginx # 執行容器 (背景模式 + Port 對應) docker run -d -p 8080:80 nginx # 查看運行中的容器 docker ps # 進入容器內部 docker exec -it <container_id> bash # 停止容器 docker stop <container_id> # 刪除容器 docker rm <container_id> ``` --- ## 總結 | 比較項目 | 虛擬機 | Docker 容器 | |----------|--------|------------| | 啟動速度 | 慢 (分鐘級) | 快 (秒級) | | 資源效率 | 低 | 高 | | 隔離強度 | 強 (硬體級) | 中 (程式級) | | 適用場景 | 需要完整 OS | 應用程式部署 | **核心概念**: - 容器 = 輕量化虛擬化 - 共享 kernel,但隔離執行環境 - 透過 Namespaces (限制視野) + cgroups (限制資源) 實現隔離 ## 虛擬化與容器技術 ### 虛擬化技術概述 虛擬化技術經歷了從傳統虛擬機到現代容器化的演進。 #### 容器化的優勢 - **不會實際修改到主機系統**:容器運行環境與主機隔離,所有變更只在容器中生效,降低系統風險 - **一行指令就可以架起完整的服務**:藉由預先打包好的映像檔,使用簡單指令即可快速部署服務,大幅簡化設定流程 - **輕量化**:容器只包含必要的程式庫與應用程式,佔用資源少、啟動速度快 - **不需要模擬整個作業系統**:容器共用主機核心,僅抽象應用運行環境,與虛擬機相比更有效率 - **高移植性**:在不同環境下執行容器不需額外調整,便於在開發、測試與正式部署間快速切換 - **易於管理與擴展**:可透過容器編排工具(如 Docker Compose、Kubernetes)自動化部署、擴展及維護多個服務 - **有助於持續整合/持續部署(CI/CD)流程**:方便自動化測試、打包、部署,提升開發與運維效率 #### 適用場景 **適合使用容器的場景**: - 微服務架構 - 快速開發和測試環境 - CI/CD 流程 - 雲端原生應用 - 需要快速擴展的應用 - 範例:網頁程式設計、軟體工程中快速架設 PostgreSQL 和 Apache,方便測試軟體 **適合使用虛擬機的場景**: - 需要不同作業系統(如 macOS、FreeBSD、Nintendo Switch、PS3) - 強隔離要求(如下載學習資料但擔心有毒) - 傳統單體應用(如 Word、PowerPoint、Excel) - 需要特定核心版本或模組 --- ## Docker 基礎實作 ### Docker 安裝 #### 在 Ubuntu 24.04 LTS 上安裝 Docker **快速安裝方式(推薦)**: ```bash # 下載並執行官方安裝腳本 curl -fsSL https://get.docker.com -o get-docker.sh sudo sh ./get-docker.sh ``` #### 設定使用者權限(選擇性) > 什麼時候會選擇這麼做 ```bash # 將目前使用者加入 docker 群組 sudo usermod -aG docker $USER # 重新登入或執行以下命令生效 newgrp docker # 測試安裝 docker --version ``` ### Docker 基本操作 #### Hello World 範例 ```bash # 執行第一個 Docker 容器 docker run hello-world ``` 這個命令會: 1. 檢查本地是否有 hello-world 映像檔 2. 如果沒有,則從 Docker Hub 下載 3. 建立並執行容器 4. 顯示歡迎訊息並退出 #### 常用 Docker 命令 ```bash # 查看映像檔 docker images # 查看執行中的容器 docker ps # 查看所有容器(包括已停止的) docker ps -a # 停止容器 docker stop <container_id> # 啟動已停止的容器 docker start <container_id> # 移除容器 docker rm <container_id> # 移除映像檔 docker rmi <image_id> # 查看容器日誌 docker logs <container_id> # 即時查看容器日誌 docker logs -f <container_id> # 進入執行中的容器 docker exec -it <container_id> bash # 查看容器資源使用情況 docker stats # 清理未使用的資源 docker system prune ``` #### 在 Ubuntu 虛擬機中跑 Docker 版本的 Ubuntu 容器 ```bash # 執行互動式 Ubuntu 容器 docker run -it ubuntu:24.04 bash # 在容器內執行命令 apt update apt install vim ``` ### 在 Docker 中架設 Nginx #### Docker Run ##### 基本運行 ```bash # 最簡單的方式 - 使用官方 image docker run -d \ --name my-nginx \ -p 8081:80 \ nginx:latest ``` ##### 完整版本(掛載自訂內容) ```bash docker run -d \ --name my-nginx \ -p 80:80 \ -p 443:443 \ -v ~/my-website/html:/usr/share/nginx/html:ro \ -v ~/my-website/nginx.conf:/etc/nginx/nginx.conf:ro \ nginx:latest ``` ##### 參數說明 - `-d`: 背景執行 - `--name`: 容器名稱 - `-p 80:80`: 對應 host 的 80 port 到容器的 80 port - `-v`: 掛載 volume(`:ro` 代表唯讀) - `nginx:latest`: 使用最新版官方 image --- nginx #### Docker Compose(官方範例) ##### 基礎版 `docker-compose.yml` ```yaml version: '3.8' services: nginx: image: nginx:latest container_name: my-nginx ports: - "80:80" - "443:443" volumes: - ./html:/usr/share/nginx/html:ro - ./nginx.conf:/etc/nginx/nginx.conf:ro restart: unless-stopped ``` --- #### 完整專案結構範例 ``` project/ ├── docker-compose.yml ├── html/ │ └── index.html ├── nginx/ │ ├── nginx.conf │ ├── conf.d/ │ │ └── default.conf │ ├── ssl/ │ │ ├── cert.pem │ │ └── key.pem │ └── logs/ │ ├── access.log │ └── error.log ``` ### Docker 持久化的幾種方式 #### Volume(推薦做法) ```bash # 建立 volume docker volume create nginx-data # 使用 volume 掛載 docker run -d \ -p 80:80 \ -v nginx-data:/usr/share/nginx/html \ nginx ``` **為什麼推薦?** - 資料獨立於容器生命週期 - 多個容器可以共享 - 方便備份和遷移 - Docker 會幫你管理 --- #### Dockerfile(最佳實踐) ```dockerfile FROM ubuntu:22.04 # 安裝 nginx RUN apt update && \ apt install -y nginx && \ apt clean && \ rm -rf /var/lib/apt/lists/* # 複製設定檔 COPY nginx.conf /etc/nginx/nginx.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] ``` **優點:** - ✅ 可追蹤(Git 版本控制) - ✅ 可重現(任何人都能 build) - ✅ 透明(所有步驟都寫明) - ✅ 容易維護和更新 --- #### Docker Commit(不推薦) ```bash # 在容器內做修改後 docker commit container-id reg-nginx:v1 ``` **為什麼不推薦?** | 問題 | 說明 | 實際影響 | |------|------|----------| | **無法追蹤** | 不知道做了什麼修改 | 出問題時無法 debug | | **無法重現** | 別人拿到 image 也不知道怎麼做的 | 團隊協作困難 | | **Layer 疊加** | 每次修改都加一層,刪檔案也算 | 容器越來越肥大 | | **缺乏文件** | 沒有 Dockerfile 當文件 | 接手的人會很痛苦 | ##### Layer 疊加範例: ```bash # 原始 image: 100MB docker commit -> 加了 nginx (150MB) docker commit -> 改設定檔 (151MB) docker commit -> 刪了某個檔案 (151MB) # 注意!沒有變小! docker commit -> 又裝了東西 (180MB) ``` 刪除檔案為什麼 image 不會變小?因為 Docker 的 **Union File System** 是用「遮罩」的方式標記刪除,舊的 layer 還在! --- #### Docker Save/Export(僅用於搬遷) ```bash # save: 保留 image metadata docker save nginx:latest > nginx.tar # export: 只保留檔案系統,丟失 metadata docker export container-id > container.tar ``` **什麼時候用?** - 需要在**沒網路**的環境部署 - 臨時備份 - ⚠️ 但不應該當作主要的版本管理方式 --- :::info ### 匯出與匯入 Docker Image #### 匯出 Docker image ```bash # 先確認容器 ID docker ps -a # 將容器提交(commit)為新的映像檔 # 格式: docker commit <容器ID或名稱> <新映像檔名稱>:<標籤> docker commit my-nginx-container my-nginx-image:v1.0 # 確認映像檔已建立 docker images # 將映像檔匯出為 tar 檔案 docker save -o my-nginx-image.tar my-nginx-image:v1.0 # 確認檔案已建立 ls -lh my-nginx-image.tar ``` #### 匯入 Docker image ```bash # 匯入映像檔 docker load -i my-nginx-image.tar # 執行匯入的映像檔 docker run -it -p 8080:80 --name restored-nginx my-nginx-image:v1.0 bash # 進入容器後啟動 Nginx service nginx start ``` ::: --- ## 本週作業 將 Nginx 中的 Load balance 放進 Docker 中,截圖連線結果及 Docker status
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up