docker簡介
docker是什么?
Docker 是一個開源的應用容器引擎,它可以讓開發者將應用與運行環境打包成一個標準的、可移植的容器(Container),在任何地方都可以快速部署和運行,無需關心底層環境是否一致。
核心優勢:
-
快速啟動與部署
-
高效利用資源
-
易于遷移與復制
-
開發環境一致性
一句話總結: Docker 是一個“構建-打包-交付-運行”一體化的容器平臺。
docker 的基本架構?
Docker 采用了 客戶端-服務器 架構,核心組件包括:
-
Docker 客戶端(Client):用戶通過命令行工具
docker
與 Docker 守護進程通信。 -
Docker 守護進程(Docker Daemon):負責構建、運行和管理容器。
-
Docker 鏡像(Image):容器的模板,是構建容器的基礎。
-
Docker 容器(Container):鏡像的運行實例,是應用的實際運行環境。
-
Docker 倉庫(Registry):存儲和分發鏡像,官方默認使用 Docker Hub。
+-------------------------+ +--------------------+
| Docker 客戶端 (CLI) |<-------> Docker 守護進程 |
+-------------------------+ | (dockerd) |+--------------------+|+-----------------------+------------------------+| | |+---------------+ +---------------+ +------------------+| 鏡像管理器 | | 容器運行時 (runc)| | 網絡/存儲管理器 |+---------------+ +---------------+ +------------------+|v+------------------+| Docker 鏡像倉庫 || (Docker Hub / 私有)|+------------------+
-
Client
發起命令 -> 守護進程執行操作。 -
守護進程拉取鏡像、創建容器、上傳/下載鏡像到 Registry。
docker 與虛擬機的區別?
架構組件 | 虛擬機(VM) | 容器(Docker) |
---|---|---|
中間層 | 虛擬機管理器(Hypervisor) | Docker 引擎 |
操作系統層 | 每個虛擬機一個完整的操作系統 | 所有容器共享宿主操作系統內核 |
資源分配 | 為每個 VM 分配固定 CPU、內存等,資源隔離明顯 | 容器之間共享資源,按需使用,隔離通過 namespace 和 cgroups 實現 |
啟動時間 | 分鐘級(需要啟動整個操作系統) | 秒級(只需啟動應用進程) |
系統開銷 | 高(需要管理多個操作系統) | 低(內核復用,運行開銷小) |
可移植性 | 跨平臺部署較復雜 | 鏡像一致,跨平臺移植方便 |
補充:Guest OS中文是客戶操作系統,是指運行在虛擬機中的操作系統,他與我們平時安裝在電腦上的操作系統(Host OS:主機操作系統)是并列概念。
傳統虛擬機:
+----------------------------+
| 硬件服務器 |
+----------------------------+
| 主機操作系統 |
+----------------------------+
| 虛擬機管理程序(Hypervisor)|
+----------------------------+
| VM1 | VM2 | VM3 |
| OS | OS | OS |
| App1 | App2 | App3 |
+----------------------------+
虛擬機的“重”在于完整操作系統
在 VM 架構中,每一個 VM 都包含一個完整的 Guest OS(比如 Ubuntu、CentOS),這意味著:
-
要為每個 VM 分配獨立的系統資源;
-
啟動慢,運行中資源占用高;
-
升級或維護成本大(多個系統要分別更新)。
這也是 Hypervisor 存在的原因:它在物理機與 Guest OS 之間提供虛擬化支持,但這層抽象帶來性能損耗。
Docker 容器結構:
+----------------------------+
| 硬件服務器 |
+----------------------------+
| 主機操作系統 |
+----------------------------+
| Docker 引擎 |
+----------------------------+
| 容器1 | 容器2 | 容器3 |
| App1 | App2 | App3 |
+----------------------------+
容器的“輕”源于共享宿主內核
Docker 容器運行在 Docker 引擎之上,所有容器共享宿主 OS 的內核,但通過內核提供的:
-
namespace
(名字空間)機制:隔離進程、網絡、文件系統等; -
cgroups
(控制組)機制:限制資源使用(如內存、CPU);
從而實現邏輯上的“隔離”,同時保留極高的運行效率。
docker應用場景?
開發環境快速搭建
通過 Dockerfile 或鏡像,一鍵構建完整開發環境,如 Node.js + Redis + MySQL 組合。
多版本/多實例服務運行
不同版本的同一服務可同時部署在不同容器中,避免端口/依賴沖突。
微服務架構部署
Docker 非常適合微服務架構的部署,每個微服務一個容器,統一管理和升級。
docker涉及的一些概念
鏡像(image)------docker的可執行模板
Docker 鏡像是一個只讀模板,它包含了運行某個應用所需要的所有內容,包括:
-
操作系統(如 Ubuntu、Alpine)
-
應用程序(如 nginx、redis)
-
應用所需依賴(如庫文件、環境變量)
-
初始化指令(如啟動服務)
鏡像就像一個“安裝包 + 配置說明書”,你可以從鏡像中創建出“運行中的實例” —— 容器。
鏡像怎么創建?
方式一:直接拉取別人構建好的鏡像
比如你拉取了 nginx
鏡像,它里面可能包含:
-
一個輕量操作系統(如 Alpine)
-
nginx 主程序
-
默認配置文件
-
啟動命令(如
CMD ["nginx", "-g", "daemon off;"]
)
方式二:自己通過編寫Dockerfile創建自己的鏡像
注意:我們也可以在拉取別人鏡像的基礎上創建屬于自己的鏡像。
容器(container)-----鏡像的運行實例
容器是基于鏡像創建的、可運行的獨立環境,它就像一個輕量級的虛擬機,但比傳統虛擬機:
-
啟動更快(秒級)
-
占用更少資源(共享宿主機內核)
-
更易移植(鏡像打包后“無差運行”)
容器 = 鏡像 + 運行時狀態(進程、網絡、掛載點、環境變量等)
數據卷(volume)
前提:容器是“臨時的”,容器被創建時,它是干凈的;容器被刪除時,它的數據也會一同消失
這就帶來一個問題:
-
如果我運行的是一個數據庫容器(如 MySQL),數據怎么保存下來?
-
如果我寫入了日志或用戶上傳了文件,容器一刪這些數據就沒了?
所以我們需要“數據持久化”機制 —— 數據卷
數據卷就是 Docker 提供的一塊專門用來保存數據的“獨立存儲空間”,它不屬于容器,但可以被容器掛載和訪問。
我們可以這樣理解:
-
容器就像一個快遞盒子
-
數據卷就像一個外接硬盤
-
你可以把快遞盒子丟了(刪除容器),但外接硬盤里的數據還在(數據卷不被刪除)
docker網絡(docker network)
Docker 網絡,是容器之間進行通信的橋梁,就像現實中的“網線”和“交換機”,讓容器能夠相互“看見”并訪問彼此。
Docker 網絡解決了幾個關鍵問題:
問題 | Docker 網絡怎么解決 |
---|---|
容器之間如何通信? | 容器加入同一個網絡,就像在一個局域網中 |
怎么訪問宿主機或互聯網? | Docker 默認提供 NAT 轉發 |
怎么隔離容器? | 網絡可以分組,防止不同容器互相干擾 |
多服務(如 Web + DB)怎么互聯? | 用網絡連接它們,像搭積木一樣組服務 |
Docker Compose
Docker 官方提供的一個多容器應用編排工具,通過一個 docker-compose.yml
文件,你可以用一行命令啟動、停止、構建多個服務容器,非常適合管理復雜應用。
-
你寫好一個
yml
配置文件, -
然后一句命令:
docker-compose up
-
就能自動搭好整個應用環境:Web、數據庫、緩存、后臺進程……全部一次性啟動
為什么需要docker compose?
在開發中,經常會遇到下面這種情況:
傳統方式 | 存在的問題 |
---|---|
用 docker run 啟多個容器 | 容器之間依賴配置麻煩 |
容器名字、端口、網絡、數據卷要手動指定 | 容易錯、不好維護 |
想重啟整個應用需要 N 條命令 | 運維效率低下 |
Docker Compose就是為了解決這些問題。
一個完整的 Compose 項目一般包括 3 部分:
組成 | 描述 |
---|---|
docker-compose.yml | 核心配置文件,定義了服務、網絡、卷等 |
.env | 可選的環境變量文件 |
項目目錄結構 | 一般包括源碼、Dockerfile 等 |
docker-compose.yml
文件示例
version: '3.8'services:web:build: .ports:- "8080:80"depends_on:- dbdb:image: mysql:8.0restart: alwaysenvironment:MYSQL_ROOT_PASSWORD: 123456volumes:- dbdata:/var/lib/mysqlvolumes:dbdata:
-
services
:定義所有容器服務,如 web、db -
build
:從當前目錄的 Dockerfile 構建鏡像 -
image
:使用已有鏡像 -
ports
:端口映射(宿主機:容器) -
volumes
:掛載卷(可復用數據) -
depends_on
:依賴關系(控制啟動順序) -
environment
:設置環境變量 -
networks
和volumes
:可選,全局定義網絡或數據卷
docker常用命令
鏡像相關命令
命令 | 說明 |
---|---|
docker images | 列出本地所有鏡像 |
docker image ls | 同上,官方推薦寫法 |
docker pull <image> | 從遠程倉庫拉取鏡像 |
docker pull <image>:<tag> | 拉取指定標簽的鏡像 |
docker build -t <name>:<tag> . | 從 Dockerfile 構建鏡像 |
docker rmi <image_id> | 刪除鏡像 |
docker image rm <image_id> | 同上,更推薦的寫法 |
docker image prune | 刪除未被使用的懸空鏡像 |
docker image inspect <image> | 查看鏡像詳細信息 |
docker tag <image> <new_name> | 給已有鏡像打新標簽 |
docker save -o <file>.tar <image> | 導出鏡像為 tar 包 |
docker load -i <file>.tar | 從 tar 包導入鏡像 |
docker history <image> | 查看鏡像構建歷史 |
容器管理命令
命令 | 說明 |
---|---|
docker ps | 查看正在運行的容器 |
docker ps -a | 查看所有容器(包括已停止) |
docker run <image> | 運行一個容器 |
docker run -it <image> bash | 以交互方式運行容器并進入 shell |
docker run -d <image> | 后臺運行容器 |
docker start <container_id> | 啟動已停止的容器 |
docker stop <container_id> | 停止運行中的容器 |
docker restart <container_id> | 重啟容器 |
docker rm <container_id> | 刪除容器 |
docker exec -it <container_id> <command> | 在運行中的容器中執行命令 |
docker attach <container_id> | 附著到容器控制臺 |
docker logs <container_id> | 查看容器輸出日志 |
docker inspect <container_id> | 查看容器詳細信息 |
docker cp <container_id>:<path> <local_path> | 從容器拷貝文件到本地 |
docker cp <local_path> <container_id>:<path> | 從本地拷貝文件到容器 |
docker top <container_id> | 查看容器中的進程 |
docker stats | 實時查看容器資源使用情況 |
docker rename <old_name> <new_name> | 重命名容器 |
?網絡管理命令
命令 | 說明 |
---|---|
docker network ls | 列出所有網絡 |
docker network inspect <network_name> | 查看指定網絡詳細信息 |
docker network create <network_name> | 創建自定義網絡(默認為 bridge) |
docker network create -d bridge <name> | 創建 bridge 網絡 |
docker network create -d overlay <name> | 創建 overlay 網絡(Swarm 模式用) |
docker network connect <network> <container> | 將容器連接到網絡 |
docker network disconnect <network> <container> | 將容器從網絡中移除 |
docker network rm <network_name> | 刪除網絡 |
?數據卷
命令 | 說明 |
---|---|
docker volume ls | 列出所有卷 |
docker volume create <volume_name> | 創建卷 |
docker volume inspect <volume_name> | 查看卷詳細信息 |
docker volume rm <volume_name> | 刪除卷 |
docker volume prune | 刪除所有未被使用的卷 |
docker run -v <volume_name>:<container_path> <image> | 使用卷運行容器 |
docker run -v $(pwd):<container_path> <image> | 使用當前目錄作為掛載點運行容器(bind mount) |
?Docker Compose 命令(需要安裝 docker-compose
)
命令 | 說明 |
---|---|
docker-compose up | 根據 docker-compose.yml 啟動所有服務 |
docker-compose up -d | 以后臺方式啟動服務 |
docker-compose down | 停止并移除服務容器、網絡等 |
docker-compose ps | 查看 compose 管理的容器狀態 |
docker-compose logs | 查看服務日志 |
docker-compose logs -f | 持續輸出日志 |
docker-compose build | 構建服務鏡像 |
docker-compose restart | 重啟服務 |
docker-compose exec <service> <cmd> | 在指定服務容器中執行命令 |
docker-compose config | 驗證和查看解析后的配置 |
docker-compose pull | 拉取 compose 文件中定義的鏡像 |
docker-compose stop | 停止服務但不移除容器 |
docker-compose start | 啟動已存在但停止的服務容器 |
?Swarm 管理命令(用于集群部署)
命令 | 說明 |
---|---|
docker swarm init | 初始化當前節點為 Swarm 管理節點 |
docker swarm join --token <token> <manager_ip>:2377 | 加入集群 |
docker node ls | 查看集群節點 |
docker service create --name <name> <image> | 創建服務 |
docker service ls | 查看服務列表 |
docker service ps <service_name> | 查看服務任務 |
docker service scale <name>=<count> | 擴縮容服務 |
docker service update --image <new_image> <service> | 更新服務 |
docker service rm <service> | 刪除服務 |
docker stack deploy -c docker-compose.yml <stack_name> | 使用 compose 文件部署 stack |
docker stack rm <stack_name> | 移除 stack |
docker stack services <stack_name> | 查看 stack 中的服務 |
?安全與身份驗證相關命令(Login、Registry)
命令 | 說明 |
---|---|
docker login | 登錄 Docker Hub 或私有倉庫 |
docker logout | 登出當前倉庫 |
docker login <registry_url> | 登錄指定私有倉庫 |
docker push <image> | 推送鏡像到遠程倉庫 |
docker pull <image> | 拉取鏡像 |
docker tag <image> <registry_url>/<name>:<tag> | 給鏡像打私有倉庫標簽 |
系統清理與信息查看命令(System)?
命令 | 說明 |
---|---|
docker system df | 查看 Docker 磁盤使用情況 |
docker system prune | 清理未使用的數據(容器、鏡像、網絡、卷) |
docker system prune -a | 更徹底地清理,包括所有未使用鏡像 |
docker info | 顯示 Docker 系統詳細信息 |
docker version | 查看 Docker 版本 |
docker events | 實時輸出 Docker 事件日志 |
docker stats | 實時顯示所有容器的資源使用情況 |
dockerfile的編寫?
制作一個docker鏡像需要編寫相應的dockerfile,dockerfile的內容是由一系列指令構成的,每個指令都會構建一個新的鏡像層,因為 Docker 的鏡像是通過多個只讀的文件系統層堆疊而成的。每個 Dockerfile 指令都會生成一個新的鏡像層,并在前一層的基礎上進行修改。這樣的設計使得 Docker 鏡像具有可重復構建和高度可定制的特性。
Dockerfile:FROM ubuntu|vRUN apt update|vRUN apt install -y python3|vCOPY . /app|vCMD ["python3", "/app/main.py"]每個指令生成一個鏡像層
[ 鏡像層 1: FROM ubuntu ]↓
-----------------------------↓
[ 鏡像層 2: RUN apt update ]↓
-----------------------------↓
[ 鏡像層 3: RUN apt install -y python3 ]↓
-----------------------------↓
[ 鏡像層 4: COPY . /app ]↓
-----------------------------↓
[ 鏡像層 5: CMD ["python3", "/app/main.py"] ]
dockerfile常用指令
FROM
指定構建鏡像所基于的基礎鏡像。
FROM <image>[:tag]<image>:鏡像的名稱
官方鏡像名(如:ubuntu、node、python 等)
用戶鏡像名(如:myrepo/myapp、username/image-name)
私有倉庫路徑(如:registry.example.com/myapp)
注意:鏡像默認從 Docker Hub 拉取,除非指定了私有倉庫地址。:tag 鏡像的版本標簽
用于標識鏡像的特定版本
如果省略則默認使用lastest標簽,即最新版本
python:3.11, node:18, ubuntu:20.04
注意:每個 Dockerfile必須以 FROM 開頭(除非使用 scratch:代表一個空白的基礎鏡像
)。
LABEL
為鏡像添加元數據信息(鍵值對形式),用于標注作者、版本、描述等信息。
LABEL key=value
-
添加作者信息:
LABEL maintainer="admin@example.com"
-
添加版本描述:
LABEL version="1.0"
-
添加鏡像簡要說明:
LABEL description="my image"
ENV
設置環境變量,在后續的 RUN、CMD、ENTRYPOINT 中可使用。環境變量可用于統一配置,如語言環境、應用路徑等。
ENV <key> <value>ENV CC=gcc \CXX=g++ \CFLAGS="-O2" \APP_HOME=/usr/src/app
RUN
執行命令并提交為新鏡像層。常用于安裝軟件包、修改系統配置等。
RUN <command>(shell 形式)或 RUN ["executable", "param1", "param2"](exec 形式)安裝依賴:RUN apt update && apt install -y curl
創建目錄:RUN mkdir -p /opt/myapp
執行程序并傳入參數:RUN ["./myapp", "--mode", "release"]
COPY
將構建上下文中的文件復制到鏡像中。適合復制本地靜態資源、源碼文件等。
構建上下文是什么?
當你執行docker build -t myapp .時
這個.就是構建上下文,表示當前目錄。Docker 會把這個目錄里的所有內容(除 .dockerignore
排除的)打包發送給 Docker 引擎,然后 Dockerfile 才能用 COPY
或 ADD
去訪問這些文件。
COPY <src> <dest>復制代碼文件:COPY . /app
復制配置文件:COPY config.json /etc/app/config.json
?ADD
與COPY 類似,但功能更強,支持解壓 tar 文件和 URL。簡單復制場景推薦使用COPY
ADD <src> <dest>自動解壓:ADD app.tar.gz /opt/
WORKDIR
設置工作目錄,影響后續命令的執行路徑。自動創建目錄,不存在會自動創建。
WORKDIR <path>設置應用目錄:WORKDIR /app
效果類似于cd到某個目錄下,然后接下來的操作默認都是在這個目錄下完成
# 在 /app 目錄下創建 main.cpp
COPY main.cpp . # 實際效果相當于 COPY main.cpp /app/main.cpp
# 在 /app 目錄下執行編譯
RUN g++ main.cpp -o myapp
EXPOSE
聲明鏡像運行時容器會監聽的端口(僅供文檔/說明用,不實際打開端口,容器內部端口的監聽,是由容器里運行的程序決定的。EXPOSE 本身不啟動程序,也不綁定端口)。
EXPOSE <port>Web 應用:EXPOSE 8080
數據庫服務:EXPOSE 3306
補充:端口監聽與端口映射
端口監聽 | 端口映射 |
---|---|
容器內的程序在某個端口(如 80)監聽網絡請求 | 把宿主機某個端口(如 8080)映射到容器內監聽的端口(如 80) |
是程序行為,程序決定監聽哪個端口 | 是 Docker 網絡配置,用戶決定如何暴露端口 |
CMD
指定容器啟動時默認執行的命令。只能有一個 CMD,若多個則只保留最后一個。
CMD ["executable","param1","param2"]啟動應用:CMD ["python3", "app.py"]
ENTRYPOINT
設置容器的主命令,不可被 docker run 參數覆蓋(可與 CMD 配合)。
ENTRYPOINT ["executable", "param1", "param2"]以某應用作為容器唯一入口:ENTRYPOINT ["nginx", "-g", "daemon off;"]
與cmd配合
ENTRYPOINT ["python3", "app.py"]
CMD ["--help"]
運行容器時如果不帶參數:docker run myimage 這時 Docker 會執行:python3 app.py --help
運行容器時如果帶參數:docker run myimage --version
這時 Docker 會執行:python3 app.py --versionENTRYPOINT 定義的是主命令,這個命令基本不會變。
CMD 定義的是默認參數,可以被運行容器時的參數替代。
運行容器時的額外參數,會替代 CMD 的參數,但不會替代 ENTRYPOINT。
補充:RUN CMD ENTRYPOINT區別
指令 | 執行時機 | 用途 | 是否可被覆蓋 | 舉例 |
---|---|---|---|---|
RUN | 鏡像構建時 | 安裝軟件、構建環境 | 不可覆蓋 | RUN apt-get install |
CMD | 容器啟動時 | 容器默認執行命令(可被覆蓋) | 可被覆蓋 | CMD ["nginx"] |
ENTRYPOINT | 容器啟動時 | 容器固定入口命令 | 不輕易覆蓋 | ENTRYPOINT ["python"] |
VOLUME
定義匿名卷,掛載目錄以便持久化數據,防止容器刪除后數據丟失。
VOLUME ["<path>"]持久化數據庫數據:VOLUME ["/var/lib/mysql"]
補充:VOLUME ["/var/lib/mysql"]
這條指令,是在容器里定義了一個掛載點目錄。那么,數據實際存儲在宿主機的哪里?我在本地電腦上怎么找到這些數據?
-
VOLUME 只是在容器中聲明了一個卷掛載點,數據不會直接存放在容器的普通文件系統層,而是存到 Docker 管理的宿主機卷存儲位置。
-
這個位置一般是 Docker 引擎管理的目錄,比如在 Linux 系統默認路徑通常是:/var/lib/docker/volumes/
-
具體數據會在這個目錄下的某個子目錄里,名稱是 Docker 自動生成的卷名或者你自己創建的卷名。
假設你啟動了一個帶卷的容器,可以用下面命令找到卷對應的宿主機目錄:
docker volume ls # 列出所有卷
docker volume inspect 卷名 # 查看某個卷的詳細信息
USER
設置運行鏡像時的用戶身份。
USER <user>[:<group>]如果不指定,默認情況下 Docker 容器是以 root 用戶身份運行的。
安全起見,不以 root 運行:USER nobody
ARG
定義構建時的參數,也就是在構建鏡像過程中可傳遞的變量,在鏡像構建時傳入(不能用于運行時)。常用于傳遞版本號、路徑、配置選項等,靈活定制鏡像。
ARG <name>[=<default>]構建時指定版本號:ARG APP_VERSION=1.0
然后用:RUN echo $APP_VERSION
RUN是構建時執行
構建時不傳入參數docker build -t myapp .
輸出:1.0
構建時傳入參數:docker build --build-arg APP_VERSION=2.3 -t myapp .
輸出:2.3
-
ARG
定義的變量只能用于 Dockerfile 中構建階段的命令,比如RUN
、ENV
等。 -
ARG
變量不會保存在鏡像中,鏡像運行時無法訪問。 -
如果想讓變量在鏡像運行時可用,需要使用
ENV
。
FROM ubuntu:20.04ARG APP_VERSION=1.0
RUN echo "Building version $APP_VERSION"ENV APP_VERSION=$APP_VERSION
CMD echo "Running version $APP_VERSION"
示例:
我們有一個簡單的 C++ 項目,目錄結構如下:
├── Dockerfile
├── main.cpp
├── config.json
├── resources.tar.gz
我們的目標是用 Docker 構建這個項目的鏡像,自動編譯 main.cpp,并運行編譯后的可執行程序。
# 1. 基礎鏡像
FROM ubuntu:20.04# 2. 添加標簽
LABEL maintainer="admin@example.com"
LABEL version="1.0"
LABEL description="C++項目的Docker示例,包含全部常用Dockerfile指令"# 3. 構建參數
ARG APP_VERSION=1.0# 4. 設置環境變量
ENV APP_HOME=/app
ENV LANG=C.UTF-8
ENV VERSION=$APP_VERSION# 5. 創建工作目錄
WORKDIR $APP_HOME# 6. 復制源代碼和配置文件
COPY main.cpp $APP_HOME/
COPY config.json /etc/app/config.json# 7. 添加壓縮資源(會自動解壓)
ADD resources.tar.gz /opt/# 8. 安裝依賴并構建應用
RUN apt-get update && \apt-get install -y g++ && \g++ main.cpp -o myapp && \rm main.cpp# 9. 暴露端口(假設該應用監聽 8080)
EXPOSE 8080# 10. 定義匿名卷用于持久化日志或數據
VOLUME ["/var/log/myapp"]# 11. 使用非 root 用戶運行
USER nobody# 12. 設置程序執行入口(執行二進制)
ENTRYPOINT ["./myapp"]# 13. 默認參數(可選傳參)
CMD ["--version"]