docker鏡像與dockerfile

一、docker鏡像

1.什么是鏡像

????????容器解決應用開發、測試和部署的問題,而鏡像解決應用部署環境問題。鏡像是一個只讀的容器模板, 打包了應用程序和應用程序所依賴的文件系統以及啟動容器的配置文件,是啟動容器的基礎。鏡像所打 包的文件內容就是容器的系統運行環境——rootfs(根文件系統或根目錄)。容器與鏡像類似對象與類的關系。

2.docker鏡像原理

1. 分層: Docker鏡像采用分層的方式構建,每一個鏡像都由一組鏡像組合而成。每一個鏡像層都可 以被需要的鏡像所引用,實現了鏡像之間共享鏡像層的效果。這樣的分層設計在鏡像的上傳與下載 過程當中有效的減少了鏡像傳輸的大小,在傳輸過程當中本地或注冊中心只需要存在一份底層的基 礎鏡像層即可,真正被保存和下載的內容是用戶構建的鏡像層。而在構建過程中鏡像層通常會被緩 存以縮短構建過程。

2. 寫時復制:底層鏡像層在多個容器間共享,每個容器啟動時不需要復制一份鏡像文件,而是將所有 需要的鏡像層以只讀的方式掛載到一個掛載點,在只讀層上再覆蓋一層讀寫層。在容器運行過程中 產生的新文件將會寫入到讀寫層,被修改過的底層文件會被復制到讀寫層并且進行修改,而老文件 則被隱藏。

3. 聯合掛載:docker采用聯合掛載技術,在同一個掛載點同時掛載多個文件系統,從而使得容器的根 目錄看上去包含了各個鏡像層的所有文件。如下圖:

?4. 內容尋址:根據鏡像層內容計算校驗和,生成一個內容哈希值,并使用該值來充當鏡像層ID、索引 鏡像層。內容尋址提高了鏡像的安全性,在pull、push和load、save操作后檢測數據的完整性。另 外基于內容哈希來索引鏡像層,對于來自不同構建的鏡像層,只要擁有相同的內容哈希值,就能被 不同的鏡像所引用。

? ? ? ? docker的鏡像和容器的關系不是類和對象的關系而是相同的引用,以下是詳細講解:

一、“類與對象” 類比的局限性

1.?類與對象的本質特征
  • 類(Class):是抽象模板,定義屬性和方法,不占用實際資源;
  • 對象(Object):是類的實例化結果,每個對象獨立擁有數據空間,修改對象不會影響類或其他對象。
  • 核心邏輯:對象是類的 “復制”,彼此隔離。
2.?Docker 鏡像與容器的實際機制
  • 鏡像(Image):是只讀的文件系統快照,由多層只讀層疊加而成(基于 UnionFS);
  • 容器(Container):是鏡像的運行實例,在鏡像頂層添加一個可寫層(container layer)。
  • 核心邏輯:容器并非鏡像的 “復制”,而是共享鏡像的底層只讀層,僅添加獨立的可寫層。

二、“相同引用” 的本質:分層存儲與共享機制

1.?UnionFS 分層架構

Docker 使用 UnionFS(如 Overlay2)實現鏡像和容器的分層存儲:

?
  • 鏡像層(只讀):多個鏡像可共享底層基礎層(如ubuntu:latest的文件系統),類似 Linux 的硬鏈接,多個引用指向同一物理存儲;
  • 容器層(可寫):每個容器在鏡像頂層添加一個專屬的可寫層,用于存儲運行時修改(如寫入文件、環境變量變更)。
2.?“相同引用” 的具體體現
  • 底層共享:當多個容器基于同一鏡像啟動時,它們共享鏡像的所有只讀層(即底層文件系統的引用相同),而非各自復制一份鏡像數據。例如:

    bash

    # 啟動兩個容器基于同一鏡像
    docker run -d ubuntu:22.04 sleep 3600
    docker run -d ubuntu:22.04 sleep 3600
    

    這兩個容器的底層文件系統(如/bin/bash/etc)實際指向同一份物理存儲,僅各自的可寫層獨立。
  • 空間效率:這種共享機制大幅節省磁盤空間,避免鏡像復制的冗余(類似 Linux 系統中多個進程共享同一可執行文件的內存映射)。
3.?與 “類與對象” 的關鍵差異
對比維度類與對象關系鏡像與容器關系
數據隔離性對象完全獨立,無共享數據容器共享鏡像的只讀層數據
修改影響修改對象不影響類或其他對象容器修改僅作用于自身可寫層
資源占用每個對象獨立占用內存多個容器共享底層鏡像資源
創建邏輯對象是類的 “實例化復制”容器是鏡像的 “引用 + 擴展”

?3. docker鏡像關鍵概念

????????1. registry:注冊中心,用來保存docker鏡像,其中包括鏡像的層次結構和關于鏡像的元數據。

????????2. repository:倉庫,即由具有某個功能的Docker鏡像的所有迭代版本構成的鏡像組。

????????3. manifest:Docker鏡像元數據文件,在pull、push、save和load中作為鏡像結構和基礎信息的描 述文件。在鏡像被pull或者load到Docker宿主機時,manifest被轉化為本地的鏡像配置文件config

????????4. image:鏡像,用來存儲一組相關的元數據信息,主要包括鏡像的架構(如amd64)、鏡像默認配 置信息、構建鏡像的容器配置信息、包含所有鏡像層的rootfs。

????????5. layer:鏡像層,是docker用來管理鏡像的中間概念,鏡像是由鏡像層組成的,單個鏡像層可以被 多個鏡像和容器共享。

????????6. dockerfile:是一個鏡像制作過程的定義,文檔包含了鏡像制作的所有命令和完整操作流程

1. Registry(注冊中心)

定義與作用

Registry 是 Docker 生態中的鏡像存儲服務,負責集中保存 Docker 鏡像的完整數據(包括鏡像層、元數據、清單等)。它是鏡像的「云端倉庫」,支持鏡像的上傳(push)、下載(pull)、刪除等操作。

核心特性
  • 存儲結構:以分層方式存儲鏡像數據,支持內容尋址(通過鏡像層的哈希值索引),避免重復存儲;
  • 元數據管理:保存鏡像的?manifest(清單)、標簽(tag)、版本信息等;
  • 多租戶支持:可部署公共 Registry(如 Docker Hub)或私有 Registry(如 Harbor、AWS ECR)。
如何查看與使用?
  • 公共 Registry(Docker Hub)
    訪問?hub.docker.com?可瀏覽官方倉庫(如?nginxubuntu)和用戶倉庫。例如,搜索?nginx?會顯示其所有標簽(latestalpine?等)。

  • 私有 Registry 操作
    若部署了私有 Registry(如 Harbor),需先登錄:

    docker login my-private-registry.com:5000  # 輸入賬號密碼
    

    上傳鏡像到私有 Registry:

    docker tag nginx:alpine my-private-registry.com/my-team/nginx:alpine  # 重命名鏡像為私有倉庫路徑
    docker push my-private-registry.com/my-team/nginx:alpine  # 上傳
    

2. Repository(倉庫)

定義與作用

Repository(倉庫)是 Registry 中的鏡像邏輯分組單元,由同一功能鏡像的所有迭代版本(不同標簽)組成。例如,nginx?倉庫包含?nginx:latestnginx:alpinenginx:1.25?等不同標簽的鏡像。

核心特性
  • 標簽(Tag):倉庫中的每個鏡像版本通過標簽區分(如?latest?是默認標簽);
  • 命名規則:倉庫名通常為?[用戶/組織名]/[鏡像名](如?docker/library/nginx?是官方倉庫,myuser/myapp?是個人倉庫)。
如何查看與使用?
  • 查看倉庫中的標簽

    • 公共倉庫:在 Docker Hub 頁面直接查看標簽列表(如?nginx 標簽頁);
    • 私有倉庫:通過命令行或 Registry 管理界面(如 Harbor 的 Web 界面)查看。
  • 拉取倉庫中的特定標簽

    docker pull nginx:alpine  # 拉取 nginx 倉庫的 alpine 標簽鏡像
    

3. Manifest(清單)

定義與作用

Manifest 是鏡像的元數據描述文件,JSON 格式,記錄鏡像的核心信息,包括:

?
  • 鏡像的配置文件(config)的哈希值;
  • 所有鏡像層(layers)的哈希值列表(按堆疊順序);
  • 鏡像的架構(如?amd64)、操作系統(如?linux)等元數據。
核心作用
  • 鏡像傳輸的「地圖」:當執行?docker pull?或?docker push?時,首先傳輸 Manifest,通過其中的層哈希值確認需要下載 / 上傳的層;
  • 本地鏡像的「索引」:下載后,Manifest 會被轉換為本地鏡像的配置文件(config.json),記錄鏡像的運行時默認配置(如入口命令、環境變量)。
如何查看與使用?
  • 查看遠程鏡像的 Manifest(需鏡像未開啟內容信任):

    docker manifest inspect nginx:alpine
    

    輸出示例(簡化):

    {"schemaVersion": 2,"mediaType": "application/vnd.docker.distribution.manifest.v2+json","config": {"mediaType": "application/vnd.docker.container.image.v1+json","size": 7023,"digest": "sha256:abc123..."  # 鏡像配置文件的哈希},"layers": [{"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip","size": 2815,"digest": "sha256:def456..."  # 第一層的哈希},{"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip","size": 1234,"digest": "sha256:ghi789..."  # 第二層的哈希}]
    }
    
  • 查看本地鏡像的 Manifest(需通過?docker inspect?間接獲取):

    docker inspect nginx:alpine | jq '.[0].RootFS'  # 查看鏡像層的哈希列表
    

4. Image(鏡像)

定義與作用

Image(鏡像)是 Docker 容器的只讀模板,由以下部分組成:

  • 配置信息config.json):包括鏡像的架構、默認命令(CMD)、入口點(ENTRYPOINT)、環境變量(ENV)等;
  • 根文件系統(RootFS):由多個只讀鏡像層(layer)堆疊而成,定義容器的初始文件系統;
  • 元數據:如鏡像創建時間、作者、標簽等。
核心特性
  • 不可變性:鏡像一旦構建完成,內容不可修改(修改需生成新鏡像);
  • 分層結構:基于內容尋址的鏡像層共享機制,節省存儲(詳見下文?layer?部分)。
如何查看與使用?
  • 查看本地鏡像列表

    docker images  # 顯示所有本地鏡像(倉庫名、標簽、鏡像 ID、大小等)
    
  • 查看鏡像詳細信息

    docker inspect nginx:alpine  # 輸出鏡像的完整配置(JSON 格式)
    

    關鍵字段:

    • Config:鏡像的默認運行配置(如?CmdEnv);
    • RootFS.Layers:鏡像層的哈希列表(與 Manifest 中的?layers?一致);
    • Created:鏡像的創建時間。

5. Layer(鏡像層)

定義與作用

Layer(鏡像層)是鏡像的最小存儲單元,對應 Dockerfile 中一條指令(如?RUN,?COPY)的文件系統變更。每個層是一個只讀的?tar?壓縮包,包含該指令對文件系統的修改(新增、刪除、修改的文件 / 目錄)。

核心特性
  • 內容尋址:每個層的哈希值由其內容(文件數據 + 元數據)計算生成(SHA256),相同內容的層會被不同鏡像共享;
  • 堆疊順序:層按 Dockerfile 指令順序堆疊,上層覆蓋下層的同名文件;
  • 可寫層隔離:容器運行時,會在鏡像層頂部添加一個可寫層(container layer),所有運行時修改僅作用于該層。
如何查看與使用?
  • 查看鏡像的層歷史

    docker history nginx:alpine
    

    輸出示例:

    IMAGE          CREATED         CREATED BY                                      SIZE      COMMENT
    sha256:abc123  2 weeks ago     /bin/sh -c #(nop)  CMD ["nginx" "-g" "daemon…   0B        
    <missing>      2 weeks ago     /bin/sh -c #(nop)  EXPOSE 80/tcp                0B        
    <missing>      2 weeks ago     /bin/sh -c apt-get update && apt-get install…   123MB     
    ...
    
    ?

    每行對應一個鏡像層,CREATED BY?顯示該層對應的 Dockerfile 指令,SIZE?是層的大小。

  • 查看層的具體內容(需借助工具):
    可通過?docker image inspect?獲取層的哈希,然后到 Docker 存儲目錄(如?/var/lib/docker/overlay2)查看層的實際文件:

    # 獲取鏡像層的哈希列表
    docker inspect nginx:alpine | jq '.[0].RootFS.Layers'
    # 輸出類似:["sha256:def456...", "sha256:ghi789..."]# 查看層的內容(需 root 權限)
    ls /var/lib/docker/overlay2/def456.../diff  # 該目錄是層的解壓內容
    

6. Dockerfile

定義與作用

Dockerfile 是鏡像構建的腳本文件,包含一系列指令(如?FROM,?RUN,?COPY),定義了鏡像的構建步驟和配置。Docker 通過解析 Dockerfile 逐行執行指令,生成鏡像層,最終構建出完整鏡像。

核心指令與示例

常見 Dockerfile 指令:

  • FROM:指定基礎鏡像(如?FROM ubuntu:22.04);
  • RUN:執行命令(如?RUN apt-get update);
  • COPY:復制文件到鏡像(如?COPY app/ /app/);
  • CMD:定義容器默認啟動命令(如?CMD ["nginx", "-g", "daemon off;"]);
  • EXPOSE:聲明容器監聽的端口(如?EXPOSE 80)。
如何使用?
  • 編寫 Dockerfile(示例:構建一個簡單的 Nginx 鏡像):

    # 基礎鏡像
    FROM nginx:alpine# 復制自定義配置到鏡像
    COPY nginx.conf /etc/nginx/nginx.conf# 聲明端口(僅文檔作用)
    EXPOSE 80# 容器啟動時執行的命令(繼承自基礎鏡像的 CMD)
    
  • 構建鏡像

    docker build -t my-nginx:v1 .  # -t 指定鏡像標簽,. 表示 Dockerfile 在當前目錄
    
  • 驗證構建結果

    docker images | grep my-nginx  # 查看新構建的鏡像
    docker history my-nginx:v1     # 查看鏡像層是否包含 COPY 指令生成的層
    

總結:概念間的協同關系

  1. 構建階段:用戶編寫?Dockerfile,Docker 逐行執行指令生成?layer(鏡像層),最終構建為?image(鏡像);
  2. 存儲階段:鏡像的?manifest(清單)描述其層結構和元數據,鏡像與層被存儲在?registry(注冊中心)的?repository(倉庫)中;
  3. 分發與運行階段:用戶通過?docker pull?從 Registry 下載鏡像(基于 Manifest 拉取層),啟動容器時鏡像的只讀層與容器的可寫層合并,形成運行環境。

?4. 鏡像管理命令

????????Docker 鏡像的全生命周期管理(構建、查看、標記、導出 / 導入、刪除)依賴一系列核心命令。以下按功能分類,詳細講解每個命令的作用、常用選項、操作示例注意事項,幫助你高效管理鏡像。

一、鏡像構建:docker build

功能

通過解析?Dockerfile?腳本,逐層構建鏡像。支持分層緩存、參數傳遞、資源限制等高級特性,是鏡像創建的標準方式(推薦替代?docker commit)。

常用選項(標?為高頻使用)
選項說明
-t, --tag??指定鏡像的標簽(格式:倉庫名:標簽,如?myapp:v1);可多次使用設置多個標簽。
-f, --file??顯式指定?Dockerfile?路徑(默認當前目錄的?Dockerfile)。
--no-cache??禁用構建緩存(強制重新構建所有層,用于解決緩存導致的鏡像內容不同步)。
--build-arg設置構建時變量(需在?Dockerfile?中用?ARG?聲明)。
--pull構建前嘗試拉取基礎鏡像的最新版本(避免使用本地舊版本)。
--rm構建成功后刪除中間容器(默認?true,節省磁盤空間)。
--force-rm無論構建是否成功,總是刪除中間容器(避免中間容器殘留)。
操作示例

假設當前目錄有?Dockerfile(內容如下):

# 基礎鏡像
FROM nginx:alpine# 復制自定義配置到鏡像
COPY nginx.conf /etc/nginx/nginx.conf# 聲明端口(僅文檔作用)
EXPOSE 80# 容器啟動命令(繼承自基礎鏡像)

構建命令

?
# 基本構建(標簽為 my-nginx:v1,使用當前目錄的 Dockerfile)
docker build -t my-nginx:v1 .# 顯式指定 Dockerfile 路徑(假設文件在 ./docker/ 目錄)
docker build -t my-nginx:v1 -f ./docker/Dockerfile .# 禁用緩存并設置構建變量(假設 Dockerfile 中有 ARG VERSION)
docker build -t my-nginx:v1 --no-cache --build-arg VERSION=1.25 .
注意事項
  • 構建上下文(PATH):命令中的?.?表示構建上下文路徑,Docker 會將該路徑下的所有文件打包傳給 Docker 守護進程(避免在上下文中放入大文件,否則會影響構建速度)。
  • 緩存機制:默認情況下,若某層的內容未變(哈希匹配),則直接復用緩存層,加速構建。若需強制更新某層(如?RUN apt-get update),需用?--no-cache
  • 中間容器:構建過程中會生成臨時容器(用于執行?RUN?指令),默認構建成功后刪除(--rm=true),失敗時保留(便于調試)。

二、鏡像查看:docker images

功能

列出本地已下載或構建的鏡像,支持過濾、格式化輸出,可查看鏡像的標簽、大小、創建時間等信息。

常用選項(標?為高頻使用)
選項說明
-a, --all??顯示所有鏡像(包括中間層鏡像,默認過濾中間層)。
--filter??過濾鏡像(如?dangling=true?查看懸空鏡像,label=key=value?按標簽過濾)。
--format自定義輸出格式(使用 Go 模板,如?{{.Repository}}:{{.Tag}})。
-q, --quiet僅顯示鏡像 ID(用于腳本自動化)。
--digests顯示鏡像的摘要(SHA256 哈希,用于驗證鏡像完整性)。
操作示例
# 查看所有本地鏡像(含標簽、大小等)
docker images# 查看所有鏡像(含中間層)
docker images -a# 過濾懸空鏡像(無標簽、未被引用的鏡像,通常是構建失敗的殘留)
docker images --filter dangling=true# 僅顯示鏡像 ID
docker images -q# 格式化輸出(顯示倉庫:標簽 及 大小)
docker images --format "{{.Repository}}:{{.Tag}} \t {{.Size}}"
注意事項
  • 懸空鏡像(Dangling Image):指無標簽(<none>:<none>)且未被其他鏡像引用的鏡像,通常由覆蓋標簽(如?docker tag old-image new-tag)或構建失敗導致,可通過?docker image prune?清理。
  • 中間層鏡像:構建過程中生成的臨時層(docker images -a?可見),默認被過濾,可通過?--no-cache?避免生成冗余中間層。

三、鏡像刪除:docker rmi

功能

刪除本地鏡像。若鏡像被容器引用(即使容器已停止),需先刪除容器或強制刪除鏡像。

常用選項
選項說明
-f, --force強制刪除鏡像(即使被容器引用,需先停止容器)。
--no-prune不刪除該鏡像的中間層(默認會刪除未被其他鏡像引用的中間層)。
操作示例
# 刪除指定標簽的鏡像
docker rmi my-nginx:v1# 強制刪除被容器引用的鏡像(需先停止容器)
docker stop my-container  # 停止容器
docker rmi -f my-nginx:v1  # 強制刪除鏡像# 刪除多個鏡像(通過鏡像 ID 或標簽)
docker rmi my-nginx:v1 nginx:alpine# 刪除所有無標簽的懸空鏡像(等價于 docker image prune)
docker rmi $(docker images -q --filter dangling=true)
注意事項
  • 依賴關系:若鏡像被其他鏡像引用(如作為基礎鏡像),需先刪除依賴它的鏡像,否則無法刪除。
  • 容器關聯:運行中的容器依賴的鏡像無法刪除(會報錯?conflict: unable to remove repository reference),需先停止并刪除容器(docker rm)。

四、鏡像標記:docker tag

功能

為本地鏡像添加或修改標簽,方便分類管理(如標記為測試版、生產版)或推送至不同倉庫(如私有 Registry)。

操作示例
# 為鏡像添加新標簽(原標簽保留)
docker tag my-nginx:v1 my-nginx:latest  # 同時存在 my-nginx:v1 和 my-nginx:latest# 標記鏡像到私有 Registry(以便推送)
docker tag my-nginx:v1 private-registry.com/my-team/my-nginx:v1# 覆蓋已有標簽(原標簽指向的鏡像變為懸空鏡像)
docker tag my-nginx:v1 my-nginx:old  # 原 my-nginx:old 若存在,會變為 <none>:<none>
注意事項
  • 標簽的意義:標簽是鏡像的「別名」,不影響鏡像本身(鏡像的唯一標識是?IMAGE ID)。
  • 推送準備:推送鏡像到私有 Registry 前,需通過?docker tag?將鏡像重命名為?私有倉庫路徑:標簽(如?private-registry.com/user/repo:tag)。

五、鏡像導出與導入:docker save?/?docker load

功能
  • docker save:將本地鏡像打包為?tar?文件,用于離線傳輸或備份。
  • docker load:從?tar?文件中導入鏡像到本地(恢復備份或傳輸后的鏡像)。
操作示例
# 導出單個鏡像為 tar 文件(包含鏡像層和元數據)
docker save -o my-nginx.tar my-nginx:v1# 導出多個鏡像(用空格分隔)
docker save -o all-images.tar my-nginx:v1 nginx:alpine# 導入 tar 文件到本地鏡像庫(會保留原標簽)
docker load -i my-nginx.tar
注意事項
  • 文件大小tar?文件包含鏡像的所有層,體積較大(與鏡像大小一致)。
  • 跨平臺兼容性:導出的鏡像僅適用于相同架構(如?amd64)的 Docker 環境,跨架構需重新構建。

六、歸檔文件創建鏡像:docker import

功能

從?tar?歸檔文件(如?docker export?導出的容器文件系統)創建鏡像。與?docker save?不同,docker import?會丟失鏡像的層信息,生成一個單層鏡像。

操作示例
# 從容器導出文件系統(得到容器的當前文件系統快照)
docker export my-container > container.tar# 從歸檔文件創建鏡像(無層信息,僅單層)
docker import -c "CMD [\"nginx\", \"-g\", \"daemon off;\"]" container.tar my-nginx:imported
注意事項
  • 適用場景:僅用于從容器文件系統快照恢復鏡像(如遷移容器狀態),不推薦替代?docker build(無法利用分層緩存)。
  • 元數據丟失:導入的鏡像會丟失原鏡像的構建歷史(docker history?僅顯示一層),且無法復用其他鏡像的層。

七、容器創建鏡像:docker commit

功能

從運行中的容器創建新鏡像(將容器的可寫層保存為鏡像層)。適用于快速保存容器的臨時狀態,但不推薦用于正式鏡像構建(無法復現構建過程)。

常用選項
選項說明
-a, --author鏡像作者(如?--author "Nick <nick@example.com>")。
-m, --message提交說明(類似 Git 的?commit -m)。
-p, --pause提交時暫停容器(默認?true,避免提交過程中容器狀態變化)。
操作示例
# 啟動容器并修改內容(如修改 nginx 配置)
docker run -it --name my-container nginx:alpine /bin/bash
echo "server { listen 80; }" > /etc/nginx/nginx.conf  # 修改配置
exit# 從容器提交新鏡像
docker commit -a "Nick" -m "Custom nginx config" my-container my-nginx:committed
注意事項
  • 不可復現性commit?生成的鏡像無法通過?Dockerfile?復現,后續修改需再次?commit,難以維護。
  • 鏡像體積:每次?commit?會生成新層,可能導致鏡像體積膨脹(推薦用?docker build?分層構建)。

總結:命令使用場景建議

需求推薦命令原因
標準鏡像構建docker build可復現、支持分層緩存、易于維護。
臨時保存容器狀態docker commit快速保存,但不推薦長期使用。
鏡像離線傳輸 / 備份docker save?+?docker load保留鏡像層信息,支持恢復原鏡像。
從容器文件系統創建鏡像docker import僅用于遷移容器狀態,無法復用分層機制。
鏡像標簽管理docker tag靈活標記,便于分類和推送。
鏡像刪除docker rmi清理冗余鏡像,注意依賴關系。

5.? 鏡像倉庫命令

????????Docker 鏡像的全生命周期管理不僅包括本地構建與查看,還涉及遠程倉庫交互(登錄、拉取、推送)、鏡像分享(公共倉庫 / 本地導出 / 私有倉庫)等關鍵操作。以下結合命令詳解、操作示例與最佳實踐,完整梳理這一流程。

一、遠程倉庫認證:docker login?與?docker logout

核心作用
  • docker login:登錄到 Docker 鏡像倉庫(如 Docker Hub 或私有 Registry),獲取上傳 / 下載權限;
  • docker logout:退出當前登錄的倉庫,避免憑證泄露。
命令格式與選項
# 登錄(默認 Docker Hub)
docker login [OPTIONS] [SERVER]# 登出(默認 Docker Hub)
docker logout [OPTIONS] [SERVER]

常用選項

  • -u, --username:登錄用戶名;
  • -p, --password:登錄密碼(或 Token);
  • (注意:直接使用?-p?可能泄露密碼,推薦交互式輸入或使用?--password-stdin?從標準輸入讀取)
操作示例
# 登錄 Docker Hub(交互式輸入密碼)
docker login
# 輸入用戶名后,輸入密碼(隱藏輸入)# 非交互式登錄(僅用于腳本,需謹慎保管密碼)
docker login -u "myuser" -p "mypassword"# 登錄私有 Registry(如 localhost:5000)
docker login http://localhost:5000 -u "testuser" -p "testpwd"# 退出 Docker Hub
docker logout# 退出私有 Registry
docker logout http://localhost:5000
注意事項
  • 登錄憑證默認存儲在?~/.docker/config.json(Linux/macOS)或?%USERPROFILE%\.docker\config.json(Windows),包含倉庫地址和加密后的密碼;
  • 若私有 Registry 使用自簽名證書,需配置 Docker 信任該證書(或通過?--insecure-registry?跳過校驗,見后文私有倉庫部分)。

二、鏡像遠程操作:docker pull?與?docker push

核心作用
  • docker pull:從遠程倉庫下載鏡像到本地;
  • docker push:將本地鏡像上傳到遠程倉庫(需先登錄)。
命令格式與選項
# 拉取鏡像(默認 Docker Hub)
docker pull [OPTIONS] NAME[:TAG|@DIGEST]# 推送鏡像(默認 Docker Hub)
docker push [OPTIONS] NAME[:TAG]

常用選項

?
  • -a, --all-tags:拉取倉庫中所有標簽的鏡像(如?docker pull -a nginx?拉取?nginx:latestnginx:alpine?等);
  • --disable-content-trust:跳過鏡像內容校驗(默認開啟,確保鏡像未被篡改);
操作示例
# 拉取 Docker Hub 的 nginx:latest 鏡像(默認標簽為 latest)
docker pull nginx# 拉取指定標簽的鏡像(如 nginx:alpine)
docker pull nginx:alpine# 拉取指定摘要(Digest)的鏡像(確保內容絕對一致)
docker pull nginx@sha256:abc123...  # 從 manifest 中獲取摘要# 推送本地鏡像到 Docker Hub(需先登錄)
docker push myuser/myapp:v1# 推送鏡像到私有 Registry(需先打標簽為私有倉庫路徑)
docker tag myapp:v1 localhost:5000/myuser/myapp:v1
docker push localhost:5000/myuser/myapp:v1
注意事項
  • 拉取鏡像時,若本地已有相同哈希的鏡像層,會直接復用(基于內容尋址),節省下載時間;
  • 推送鏡像時,僅上傳本地不存在于遠程倉庫的鏡像層(增量上傳),提升效率;
  • 若鏡像被標記為多個標簽(如?myapp:v1?和?myapp:latest),推送時需分別推送每個標簽。

三、鏡像搜索:docker search

核心作用

在 Docker Hub 搜索公開鏡像,支持過濾(如官方鏡像、高星鏡像),快速定位所需鏡像。

命令格式與選項
docker search [OPTIONS] TERM

常用選項

  • --automated:僅顯示自動構建的鏡像(由 Dockerfile 自動構建,非手動?commit);
  • --no-trunc:顯示完整的鏡像描述(默認截斷);
  • -f, --filter:過濾條件(如?stars=10?表示收藏數≥10);
操作示例
# 搜索名稱包含 "nginx" 的鏡像
docker search nginx# 搜索收藏數≥10 的 nginx 鏡像
docker search -f stars=10 nginx# 僅顯示自動構建的 nginx 鏡像
docker search --automated nginx# 顯示完整描述(不截斷)
docker search --no-trunc nginx

輸出示例

NAME                      DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
nginx                     Official build of Nginx.                        20000     [OK]       
bitnami/nginx             Bitnami nginx Docker Image                      1500                  [OK]
...

四、鏡像分層與聯合掛載實踐(以 Nginx 為例)

Docker 鏡像的分層機制是其輕量化的核心,通過?docker save、解壓鏡像包和查看?manifest,可以直觀理解鏡像層的結構。

操作步驟
  1. 運行 Nginx 容器

    docker run -d -p 81:80 --name mynginx1 nginx:latest
    
  2. 進入容器查看文件系統

    docker exec -it mynginx1 /bin/bash
    ls /etc/nginx  # 查看 Nginx 配置文件(來自鏡像層)
    exit
    
  3. 保存鏡像為 tar 歸檔

    docker save -o nginx.tar nginx:latest
    
  4. 解壓并查看鏡像層

    mkdir nginx-layers && tar -xvf nginx.tar -C nginx-layers
    

    解壓后會得到多個文件:

    • manifest.json:鏡像的清單文件(記錄層哈希、配置文件路徑);
    • config.json:鏡像的配置文件(記錄鏡像元數據);
    • 多個?sha256-xxx.tar?文件:每個文件對應一個鏡像層(壓縮的文件系統變更)。
  5. 分析?manifest.json(簡化示例):

    [{"Config": "config.json","RepoTags": ["nginx:latest"],"Layers": ["sha256:layer1.tar",  # 基礎層(如 Alpine Linux)"sha256:layer2.tar",  # Nginx 安裝層"sha256:layer3.tar"   # 其他配置層]}
    ]
    
  6. 對比?docker commit?生成的鏡像

    • 運行容器并修改文件(如添加?test.txt):
      docker exec mynginx1 touch /test.txt
      
    • 提交容器為新鏡像:
      docker commit -m "Add test.txt" mynginx1 mynginx:v1
      
    • 保存并解壓?mynginx:v1?的鏡像包,會發現?manifest.json?中新增了一個層(對應?test.txt?的變更),而底層的 Nginx 層與原鏡像完全一致(哈希相同,證明層復用)。
關鍵結論
  • 鏡像由多個只讀層堆疊而成,相同內容的層會被不同鏡像共享(節省存儲);
  • docker commit?會生成新層(記錄容器可寫層的變更),但無法復現構建過程(不推薦用于生產)。

五、鏡像分享的三種方式

方式 1:公共倉庫(Docker Hub)分享

適用于公開分享鏡像,需注冊 Docker Hub 賬號并創建倉庫。

?

操作步驟

?
  1. 創建 Docker Hub 倉庫
    登錄?hub.docker.com,點擊?Create Repository,輸入倉庫名(如?myuser/mynginx)。

  2. 本地鏡像打標簽

    docker tag mynginx:v1 myuser/mynginx:v1
    
  3. 推送鏡像到 Docker Hub

    docker login  # 登錄 Docker Hub
    docker push myuser/mynginx:v1
    
  4. 拉取驗證(任意設備):

    docker pull myuser/mynginx:v1
    
方式 2:本地導出 / 導入(docker save?+?docker load

適用于離線傳輸或備份鏡像(無需網絡)。

?

操作步驟

?
  1. 導出鏡像為 tar 文件

    docker save -o myimages.tar mynginx:v1 mysql:5.7  # 導出多個鏡像
    
  2. 傳輸文件(通過 U 盤、局域網等)。

  3. 導入鏡像到目標設備

    docker load -i myimages.tar  # 導入后鏡像標簽和層信息完整保留
    
方式 3:私有注冊中心分享

適用于企業內部私有鏡像管理,需搭建私有 Registry 并配置認證。

?

搭建步驟(以本地 Registry 為例)

?
  1. 啟動 Registry 容器(無認證版本):

    docker run -d -p 5000:5000 --name registry --restart=always registry:2
    
  2. 驗證 Registry 狀態

    curl http://localhost:5000/v2/_catalog  # 應返回 {"repositories":[]}(空倉庫)
    
  3. 配置認證(可選)
    使用?htpasswd?生成密碼文件(需安裝?apache2-utils):

    sudo apt install apache2-utils  # Linux
    htpasswd -Bbn testuser testpwd > /path/to/auth/htpasswd  # 生成密碼文件
    
  4. 啟動帶認證的 Registry

    docker run -d -p 5000:5000 --name registry --restart=always \-v /path/to/data:/var/lib/registry \  # 數據卷(持久化存儲)-v /path/to/auth:/auth \               # 密碼文件路徑-e "REGISTRY_AUTH=htpasswd" \          # 啟用 htpasswd 認證-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \registry:2
    
  5. 配置 Docker 信任私有 Registry(解決 HTTPS 校驗問題):

    • 編輯 Docker 服務配置(Linux):
      sudo vim /lib/systemd/system/docker.service
      
    • 在?ExecStart?行末尾添加?--insecure-registry localhost:5000(允許不安全連接):
      ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry localhost:5000
      
    • 重啟 Docker 服務:
      sudo systemctl daemon-reload
      sudo systemctl restart docker
      
  6. 推送與拉取鏡像

    # 登錄私有 Registry
    docker login http://localhost:5000 -u testuser -p testpwd# 打標簽
    docker tag mynginx:v1 localhost:5000/myuser/mynginx:v1# 推送
    docker push localhost:5000/myuser/mynginx:v1# 拉取(其他設備需配置相同的 --insecure-registry)
    docker pull localhost:5000/myuser/mynginx:v1

?二、 dockerfile

1.dockerfile是什么

????????Dockerfile是一個創建鏡像所有命令的文本文件, 包含了一條條指令和說明, 每條指令構建一層, 通過 docker build命令,根據Dockerfile的內容構建鏡像,因此每一條指令的內容, 就是描述該層如何構建.有了 Dockefile, 就可以制定自己的docker鏡像規則,只需要在Dockerfile上添加或者修改指令, 就可生成 docker 鏡像。

2.?dockerfile解決了什么問題

????????Dockerfile 包含了鏡像制作的完整操作流程,其他開發者可以通過 Dockerfile 了解并復現制作過程 Dockerfile 中的每一條指令都會創建新的鏡像層,這些鏡像可以被 Docker Daemon 緩存。再次制作鏡 像時,Docker 會盡量復用緩存的鏡像層(using cache),而不是重新逐層構建,這樣可以節省時間和 磁盤空間 Dockerfile 的操作流程可以通過docker image history [鏡像名稱]查詢,方便開發者查看變更記錄。

3.?docker build 構建流程

一、Docker build 核心流程
第一步:準備上下文(Context)并處理文件
  1. 打包上下文文件

    • docker build?會將指定的上下文目錄(context)中的文件打包,發送給 Docker 引擎(Docker daemon)。
    • 若上下文中存在?.dockerignore?文件,會按規則過濾掉不需要上傳的文件(如日志、臨時文件等)。
  2. 例外規則

    • 若?.dockerignore?文件中包含?.dockerignore?或?Dockerfile?本身,這兩個文件不會被過濾,仍會被上傳。
  3. 鏡像標簽驗證

    • 若指定了鏡像標簽(-t?參數),會先驗證倉庫名(repository)和標簽(tag)的格式是否合法。
第二步:發送構建請求至 Docker 引擎
  • 通過 HTTP 請求向 Docker server 發送構建指令,請求中包含上下文信息(打包后的文件)。
第三步:Docker 引擎執行鏡像構建
  1. 解壓上下文文件

    • 在臨時目錄中解壓上下文文件,作為構建的基礎環境。
  2. 解析 Dockerfile 指令

    • 讀取并解析?Dockerfile?中的每條指令,按指令類型(如?RUNCOPYADD?等)分發到對應模塊處理。
  3. 逐層構建鏡像層

    • 對每條指令,創建臨時容器并執行指令,然后將容器狀態提交(commit)為一個新的鏡像層。
    • 例如:RUN apt-get update?會生成一個包含更新操作的鏡像層。
  4. 合并鏡像層

    • 所有指令執行完畢后,合并所有鏡像層,最后一次 commit 生成的鏡像 ID 即為最終鏡像 ID。
二、構建緩存機制(提升效率的關鍵)
1. 緩存默認行為
  • Docker 會自動緩存已構建的鏡像層,下次構建時若發現指令未變,直接復用緩存,無需重新執行。
  • 可通過?--no-cache=true?參數禁用緩存(如?docker build --no-cache=true -t myimage .)。
2. 緩存匹配規則
  • 基礎檢查:遍歷緩存中的鏡像層,檢查構建指令是否與當前指令完全一致(如?RUN?命令的參數)。
  • 特殊指令處理
    • 對于?ADDCOPY?指令,除了指令本身,還會校驗文件的校驗和(checksum),若文件內容不同則緩存失效。
  • 忽略容器內文件檢查
    • 例如?RUN apt-get update?執行后,容器內文件更新,但緩存策略不會校驗這些文件,僅依賴指令本身和文件校驗和。
三、查看鏡像構建歷史
  • 命令:docker history <鏡像ID或標簽>
  • 作用:顯示鏡像各層的構建指令、大小、時間等信息,便于調試和優化構建流程。

4.?關鍵字

指令說明
FROM設置鏡像使用的基礎鏡像
MAINTAINER設置鏡像的作者
RUN編譯鏡像時運行的腳本
CMD設置容器的啟動命令
LABEL設置鏡像標簽
EXPOSE設置鏡像暴露的端口
ENV設置容器的環境變量
ADD編譯鏡像時復制上下文中的文件到鏡像中
COPY編譯鏡像時復制上下文中的文件到鏡像中
ENTRYPOINT設置容器的入口程序
VOLUME設置容器的掛載卷
USER設置運行 RUN、CMD、ENTRYPOINT 的用戶名
WORKDIR設置 RUN、CMD、ENTRYPOINT、COPY、ADD 指令的工作目錄
ARG設置編譯鏡像時加入的參數
ONBUILD設置鏡像的 ONBUILD 指令
STOPSIGNAL設置容器的退出信號量

5.?dockerfile 實踐(go)

一、基本語法實踐案例

案例目標:使用 Golang 構建一個可執行程序并打包為鏡像。

1. 案例準備
# 創建項目目錄
mkdir example1 && cd example1
2. Dockerfile 內容
FROM golang:1.18              # 指定基礎鏡像
ENV env1=env1value env2=env2value  # 設置環境變量
MAINTAINER nick                # 鏡像作者
LABEL hello=1.0.0              # 鏡像標簽
RUN git clone https://gitee.com/nickdemo/helloworld.git  # 克隆代碼
WORKDIR helloworld            # 設置工作目錄
RUN go env -w GOPROXY=https://proxy.golang.com.cn,https://goproxy.cn,direct  # 配置代理
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o app .  # 編譯程序
EXPOSE 80                     # 暴露端口
CMD ["./app", "--param1=p1", "--param2=p2"]  # 容器啟動命令
3. 構建與運行
# 構建鏡像
docker build -t hello:1.0.0 -f Dockerfile .
# 運行容器
docker run -p 80:80 -d --name hello hello:1.0.0
二、Docker Build 上下文實踐

案例目標:理解上下文(Context)對構建的影響。

1. 素材準備
mkdir example2 && cd example2
# 下載 Nginx 源碼和應用代碼
curl https://nginx.org/download/nginx-1.21.6.tar.gz > nginx-1.21.6.tar.gz
git clone https://gitee.com/nickdemo/helloworld
2. 無上下文優化的 Dockerfile(低效)
FROM golang:1.18
ENV env1=env1value env2=env2value
MAINTAINER nick
LABEL hello=1.0.0
RUN git clone https://gitee.com/nickdemo/helloworld.git  # 從網絡克隆,不使用本地上下文
WORKDIR helloworld
RUN go env -w GOPROXY=https://proxy.golang.com.cn,https://goproxy.cn,direct
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o app .
EXPOSE 80
CMD ["./app", "--param1=p1", "--param2=p2"]
3. 優化后的上下文 Dockerfile(高效)
FROM golang:1.18
ENV env1=env1value env2=env2value
MAINTAINER nick
LABEL hello=1.0.0
COPY ./helloworld /go/src/helloworld  # 從上下文復制本地代碼
WORKDIR /go/src/helloworld
RUN go env -w GOPROXY=https://proxy.golang.com.cn,https://goproxy.cn,direct
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o app .
EXPOSE 80
CMD ["./app", "--param1=p1", "--param2=p2"]
4. 實踐操作
  • 忽略文件測試:在?example2?中創建?.dockerignore,添加?helloworld,觀察構建時是否跳過該目錄。
  • 上下文路徑測試:修改?COPY?路徑為上下文外的路徑(如?../other),觀察構建錯誤。
三、多階段構建實踐

案例目標:分離編譯環境與運行環境,減小鏡像體積。

1. 素材準備
mkdir example3 && cd example3
curl https://nginx.org/download/nginx-1.21.6.tar.gz > nginx-1.21.6.tar.gz
git clone https://gitee.com/nickdemo/helloworld
2. 基礎多階段構建(無別名)
# 第一階段:編譯環境
FROM golang:1.18
ADD ./helloworld /go/src/helloworld/
WORKDIR /go/src/helloworld
RUN go env -w GOPROXY=https://proxy.golang.com.cn,https://goproxy.cn,direct
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o app .# 第二階段:運行環境(使用 Alpine 輕量級系統)
FROM alpine:latest
ENV env1=env1value env2=env2value
MAINTAINER nick
LABEL hello=1.0.0
WORKDIR /app/
COPY --from=0 /go/src/helloworld/app ./  # 從第一階段復制可執行文件
EXPOSE 80
CMD ["./app", "--param1=p1", "--param2=p2"]
3. 帶別名的多階段構建(更清晰)
# 第一階段:命名為 stage0
FROM golang:1.18 as stage0
ADD ./helloworld /go/src/helloworld/
WORKDIR /go/src/helloworld
RUN go env -w GOPROXY=https://proxy.golang.com.cn,https://goproxy.cn,direct
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o app .# 第二階段:運行環境
FROM alpine:latest
ENV env1=env1value env2=env2value
MAINTAINER nick
LABEL hello=1.0.0
WORKDIR /app/
COPY --from=stage0 /go/src/helloworld/app ./
EXPOSE 80
CMD ["./app", "--param1=p1", "--param2=p2"]
4. 構建命令
docker build -t hello:1.0.0 -f Dockerfile .
四、ADD 與 COPY 指令對比實踐

案例目標:理解?ADD?與?COPY?的功能差異。

1. 基礎功能對比
FROM alpine:latest
WORKDIR /soft/# COPY 僅復制文件(不支持解壓/URL)
COPY nginx-1.21.6.tar.gz ./copy/        # 復制本地文件
COPY srcDir/ ./destDir/                # 復制目錄內容(不含目錄本身)# ADD 支持解壓和 URL
ADD https://nginx.org/download/nginx-1.21.6.tar.gz ./add/  # 從 URL 下載(不解壓)
ADD nginx-1.21.6.tar.gz ./add/         # 解壓本地壓縮包
2. 多階段構建中的應用
# 編譯階段
FROM golang:1.18 as stage0
COPY ./helloworld /go/src/helloworld/  # 推薦用 COPY 復制本地文件
WORKDIR /go/src/helloworld
RUN go build -o app .# 運行階段
FROM alpine:latest
WORKDIR /app/
COPY --from=stage0 /go/src/helloworld/app ./
五、CMD 與 ENTRYPOINT 指令實踐

案例目標:理解容器啟動命令的不同配置方式。

1. CMD 指令案例
FROM alpine:latest
WORKDIR /app
COPY app ./
EXPOSE 80
CMD ["./app", "--param1=p1", "--param2=p2"]  # 默認啟動命令# 運行時覆蓋 CMD:
# docker run -d hello:1.0.0 ./app --param1=1 --param2=2
2. ENTRYPOINT 指令案例
FROM alpine:latest
WORKDIR /app
COPY app ./
EXPOSE 80
ENTRYPOINT ["./app"]  # 固定入口程序
CMD ["--param1=p1", "--param2=p2"]  # 為 ENTRYPOINT 提供默認參數# 運行時追加參數:
# docker run -d hello:1.0.0 --param1=1 --param2=2
# 替換入口程序:
# docker run --entrypoint sh hello:1.0.0
六、Build Arg 實踐

案例目標:動態傳遞構建參數。

?
FROM golang:1.18 as s0
WORKDIR /go/src/app
RUN go env -w GOPROXY=$http_proxy  # 使用預定義參數FROM alpine:latest as s1
ARG wd=./app          # 定義默認參數
ARG label=myapp       # 鏡像標簽參數
ARG tag=1.0.0         # 鏡像版本參數
RUN echo "工作目錄: $wd, 標簽: $label, 版本: $tag"
WORKDIR $wd
LABEL $label=$tag# 構建命令(傳遞參數):
# docker build --build-arg http_proxy=https://proxy... --build-arg wd=/home/app --tag hello:1.0.0 .
七、Target 與 Cache-From 實踐

案例目標:加速多階段構建,復用緩存

FROM golang:1.18 as s0
ADD ./helloworld /go/src/helloworld/
WORKDIR /go/src/helloworld
RUN go build -o app .FROM alpine:latest as s1
WORKDIR /app
COPY --from=s0 /go/src/helloworld/app ./# 分步構建:
# 1. 構建第一階段并保存
docker build -t prehello:1.0.0 --target s0 .
# 2. 從緩存構建第二階段
docker build -t hello:1.0.0 --cache-from prehello:1.0.0 --target s1 .
八、ONBUILD 指令實踐

案例目標:定義基礎鏡像的下游構建行為。

1. 定義基礎鏡像
FROM golang:1.18
ONBUILD ADD ./helloworld /go/src/helloworld/  # 下游構建時觸發
ONBUILD WORKDIR /go/src/helloworld
ONBUILD RUN go env -w GOPROXY=https://proxy.golang.com.cn,https://goproxy.cn,direct
ONBUILD RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o app .# 構建基礎鏡像
docker build -t mygolang:1.0.0 .
2. 使用基礎鏡像構建應用
FROM mygolang:1.0.0 as s0  # 自動觸發 ONBUILD 指令
FROM alpine:latest as s1
WORKDIR /app
COPY --from=s0 /go/src/helloworld/app ./
EXPOSE 80
ENTRYPOINT ["./app"]# 構建應用鏡像(無需重復編寫編譯步驟)
docker build -t hello:1.0.0 .

6. dockerfile實踐(c語言)

一、項目準備

1. 目錄結構

創建項目目錄?c-app-docker,包含:

  • src/:存放 C 源文件
  • Dockerfile:構建鏡像的核心文件
2. 編寫 C 程序

在?src/?目錄下創建?main.c,實現一個簡單的 HTTP 服務(使用?libmicrohttpd?庫)

// src/main.c
#include <stdio.h>
#include <microhttpd.h>#define PORT 8080static int handle_request(void *cls, struct MHD_Connection *connection,const char *url, const char *method,const char *version, const char *upload_data,size_t *upload_data_size, void **con_cls) {const char *response = "Hello, Docker C App!\n";struct MHD_Response *mhd_response;int ret;mhd_response = MHD_create_response_from_buffer(strlen(response), (void *)response, MHD_RESPMEM_PERSISTENT);ret = MHD_queue_response(connection, MHD_HTTP_OK, mhd_response);MHD_destroy_response(mhd_response);return ret;
}int main() {struct MHD_Daemon *daemon;daemon = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION, PORT, NULL, NULL,&handle_request, NULL, MHD_OPTION_END);if (NULL == daemon) {fprintf(stderr, "Failed to start MHD daemon\n");return 1;}printf("Server running on port %d...\n", PORT);getchar(); // 阻塞進程,避免退出MHD_stop_daemon(daemon);return 0;
}

二、Dockerfile 編寫(多階段構建優化)

使用?多階段構建?分離編譯環境與運行環境,最終鏡像僅保留運行所需的最小依賴,體積更小、更安全。

Dockerfile?內容:
# ================================================
# 階段1:編譯環境(使用 GCC 編譯 C 程序)
# ================================================
FROM gcc:13 as builder# 設置工作目錄
WORKDIR /app# 安裝依賴庫(libmicrohttpd 用于 HTTP 服務)
RUN apt-get update && \apt-get install -y libmicrohttpd-dev && \rm -rf /var/lib/apt/lists/*# 復制 C 源文件到容器
COPY src/main.c ./# 編譯 C 程序(生成可執行文件 app)
RUN gcc -o app main.c -lmicrohttpd# ================================================
# 階段2:運行環境(僅保留運行所需的最小依賴)
# ================================================
FROM alpine:3.19# 安裝運行時依賴(libmicrohttpd 庫)
RUN apk add --no-cache libmicrohttpd# 設置工作目錄
WORKDIR /app# 從編譯階段復制可執行文件(僅保留最終程序)
COPY --from=builder /app/app ./# 暴露服務端口(與 C 程序中定義的 PORT 一致)
EXPOSE 8080# 啟動命令:運行編譯后的可執行文件
CMD ["./app"]

三、鏡像構建與運行

1. 構建鏡像

在項目根目錄(c-app-docker)下執行構建命令:

docker build -t c-http-server:1.0 .

說明

  • -t c-http-server:1.0:指定鏡像名稱為?c-http-server,標簽為?1.0
  • 多階段構建會自動跳過中間階段(僅保留最后一個?FROM?后的內容),最終鏡像體積遠小于編譯環境。
2. 運行容器
docker run -p 8080:8080 --name c-server -d c-http-server:1.0

參數說明

?
  • -p 8080:8080:將容器的 8080 端口映射到宿主機的 8080 端口。
  • --name c-server:指定容器名稱為?c-server
  • -d:后臺運行容器。
3. 驗證服務

通過瀏覽器或命令行訪問宿主機的 8080 端口:

curl http://localhost:8080

預期輸出

Hello, Docker C App!

四、關鍵步驟說明

1. 多階段構建的優勢
  • 體積更小:編譯階段使用?gcc:13(約 1.2GB),運行階段使用?alpine:3.19(約 5MB),最終鏡像僅包含運行所需的?libmicrohttpd?庫和可執行文件(總大小約 20MB)。
  • 更安全:運行環境不包含編譯器、調試工具等冗余組件,減少攻擊面。
2. 依賴管理
  • 編譯階段:通過?apt-get?安裝?libmicrohttpd-dev(包含頭文件和編譯庫)。
  • 運行階段:通過?apk add?安裝?libmicrohttpd(僅運行時庫,無開發文件)。
3. 緩存優化
  • COPY src/main.c ./?放在?RUN gcc?前,避免源文件修改時重復安裝依賴(Docker 按指令順序緩存,若?COPY?后修改?main.c,僅?RUN gcc?會重新執行)。

五、擴展實踐建議

1. 靜態編譯(可選)

若需完全獨立的可執行文件(不依賴宿主機庫),可在編譯階段添加?-static?參數

# 階段1 編譯命令改為:
RUN gcc -o app main.c -lmicrohttpd -static

注意libmicrohttpd?可能不支持靜態編譯,需根據實際庫的特性調整。

2. 健康檢查

在?Dockerfile?中添加健康檢查,確保服務正常運行:

HEALTHCHECK --interval=5s --timeout=3s \CMD curl -f http://localhost:8080/ || exit 1
3. 環境變量配置

若需動態配置端口或參數,可使用?ENV?和?ARG?指令:

# 在階段2添加:
ARG PORT=8080
ENV APP_PORT=$PORT
EXPOSE $APP_PORT
CMD ["./app", "--port", "$APP_PORT"]

構建時指定參數

docker build -t c-http-server:1.0 --build-arg PORT=8090 .

?0voice · GitHub?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/907653.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/907653.shtml
英文地址,請注明出處:http://en.pswp.cn/news/907653.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

流媒體基礎解析:音視頻封裝格式與傳輸協議

在視頻處理與傳輸的完整流程中&#xff0c;音視頻封裝格式和傳輸協議扮演著至關重要的角色。它們不僅決定了視頻文件的存儲方式&#xff0c;還影響著視頻在網絡上的傳輸效率和播放體驗。今天&#xff0c;我們將深入探討音視頻封裝格式和傳輸協議的相關知識。 音視頻封裝格式 什…

普中STM32F103ZET6開發攻略(一)

各位看官老爺們&#xff0c;點擊關注不迷路喲。你的點贊、收藏&#xff0c;一鍵三連&#xff0c;是我持續更新的動力喲&#xff01;&#xff01;&#xff01; 目錄 普中STM32F103ZET6開發攻略 1. GPIO端口實驗——點亮LED燈 1.1 實驗目的 1.2 實驗原理 1.3 實驗環境和器材…

AWS API Gateway 配置WAF(中國區)

問題 需要給AWS API Gateway配置WAF。 AWS WAF設置 打開AWS WAF首頁&#xff0c;開始創建和配置WAF&#xff0c;如下圖&#xff1a; 設置web acl名稱&#xff0c;然后開始添加aws相關資源&#xff0c;如下圖&#xff1a; 選擇資源類型&#xff0c;但是&#xff0c;我這里出…

測試分類詳解

測試分類 一、按測試對象分類 1. 界面測試 1.1 測試內容介紹 界面測試驗證用戶界面(UI)的視覺呈現和交互邏輯&#xff0c;確保符合設計規范并提供良好的用戶體驗。測試內容包括&#xff1a; 頁面布局和元素對齊字體、顏色和圖標一致性交互反饋&#xff08;懸停、點擊狀態&a…

打開NRODIC SDK編譯不過怎么處理,keil與segger studio

打開NRODIC SDK編譯不過怎么處理,以下是keil處理. 1,如圖,不要安裝安裝也不會過 2. 不要安裝點擊否 3.點擊確定后進來這個樣子 4.這里選擇這個勾,OK后就不會再有后面的pack_license 5.去掉勾后這里要選擇自己SDK對應的pack版本,我的是8.27.0 6.OK后彈出個界面也要反復選擇…

HarmonyOS ArkUI-X開發中的常見問題及解決方案

一、跨平臺編譯與適配問題 1. 平臺特定API不兼容 ?問題現象?&#xff1a;使用Router模塊的replaceUrl或startAbility等鴻蒙專屬API時&#xff0c;編譯跨平臺工程報錯cant support crossplatform application。 ?解決方案?&#xff1a; 改用ohos.router的跨平臺封裝API&a…

CSS篇-2

4. position 的值分別是相對于哪個位置定位的&#xff1f; position 屬性是 CSS 布局中一個非常核心的概念&#xff0c;它允許我們精確控制元素在文檔中的定位方式&#xff0c;從而脫離或部分脫離正常的文檔流。理解 position 的不同值以及它們各自的定位基準&#xff0c;是實…

設計模式:觀察者模式 - 實戰

一、觀察者模式場景 1.1 什么是觀察者模式&#xff1f; 觀察者模式&#xff08;Observer Pattern&#xff09;觀察者模式是一種行為型設計模式&#xff0c;用于定義一種一對多的依賴關系&#xff0c;當對象的狀態發生變化時&#xff0c;所有依賴于它的對象都會自動收到通知并更…

Axure中繼器交互完全指南:核心函數解析×場景實戰×避坑策略(懂得才能應用)

親愛的小伙伴,在您瀏覽之前,煩請關注一下,在此深表感謝!如有幫助請訂閱專欄! Axure產品經理精品視頻課已登錄CSDN可點擊學習https://edu.csdn.net/course/detail/40420 主要內容:中繼器核心函數解析、場景方法詳解、注意事項、特殊函數區別 課程目標:提高中繼器的掌握…

【設計模式-4.5】行為型——迭代器模式

說明&#xff1a;本文介紹設計模式中&#xff0c;行為型設計模式之一的迭代器模式。 定義 迭代器模式&#xff08;Iterator Pattern&#xff09;&#xff0c;也叫作游標模式&#xff08;Cursor Pattern&#xff09;&#xff0c;它提供一種按順序訪問集合/容器對象元素的方法&…

鴻蒙OSUniApp自定義手勢識別與操作控制實踐#三方框架 #Uniapp

UniApp自定義手勢識別與操作控制實踐 引言 在移動應用開發中&#xff0c;手勢交互已經成為提升用戶體驗的重要組成部分。本文將深入探討如何在UniApp框架中實現自定義手勢識別與操作控制&#xff0c;通過實際案例幫助開發者掌握這一關鍵技術。我們將以一個圖片查看器為例&…

【數據結構】樹形結構--二叉樹

【數據結構】樹形結構--二叉樹 一.知識補充1.什么是樹2.樹的常見概念 二.二叉樹&#xff08;Binary Tree&#xff09;1.二叉樹的定義2.二叉樹的分類3.二叉樹的性質 三.二叉樹的實現1.二叉樹的存儲2.二叉樹的遍歷①.先序遍歷②.中序遍歷③.后序遍歷④.層序遍歷 一.知識補充 1.什…

從認識AI開始-----解密LSTM:RNN的進化之路

前言 我在上一篇文章中介紹了 RNN&#xff0c;它是一個隱變量模型&#xff0c;主要通過隱藏狀態連接時間序列&#xff0c;實現了序列信息的記憶與建模。然而&#xff0c;RNN在實踐中面臨嚴重的“梯度消失”與“長期依賴建模困難”問題&#xff1a; 難以捕捉相隔很遠的時間步之…

接地氣的方式認識JVM(一)

最近在學jvm&#xff0c;浮于表面的學了之后&#xff0c;發現jvm并沒有我想象中的那么神秘&#xff0c;這篇文章將會用接地氣的方式來說一說這些jvm的相關概念以及名詞解釋。 帶著下面兩個問題來閱讀 認識了解JVM大致有什么在代碼運行時的都在背后做了什么 JVM是個啥&#xf…

Next.js 15 與 Apollo Client 的現代集成及性能優化

Next.js 15 與 Apollo Client 的現代集成及性能優化 目錄 技術演進集成實踐性能優化應用案例未來趨勢 技術演進 Next.js 15 核心特性對開發模式的革新 Next.js 15 通過引入 App Router、服務器組件&#xff08;Server Components&#xff09;和客戶端組件&#xff08;Clie…

無人機橋梁3D建模、巡檢、檢測的航線規劃

無人機橋梁3D建模、巡檢、檢測的航線規劃 無人機在3D建模、巡檢和檢測任務中的航線規劃存在顯著差異&#xff0c;主要體現在飛行高度、航線模式、精度要求和傳感器配置等方面。以下是三者的詳細對比分析&#xff1a; 1. 核心目標差異 任務類型主要目標典型應用場景3D建模 生成…

Hive數據傾斜問題深度解析與實戰優化指南

一、數據傾斜現象的本質與危害 數據傾斜是Hive在MapReduce計算過程中,?部分Key對應的數據量遠超其他Key,導致少數Reducer任務處理時間遠高于其他任務的性能瓶頸問題。典型表現為: ?作業進度卡在99%??:99%的Reducer已完成,剩余1%持續數小時?資源利用率失衡?:部分節…

VRRP 原理與配置:讓你的網絡永不掉線!

VRRP 原理與配置&#xff1a;讓你的網絡永不掉線&#xff01; 一. VRRP 是什么&#xff0c;為什么需要它&#xff1f;二. VRRP 的核心概念三. VRRP 的工作原理四. 華為設備 VRRP 配置步驟 &#xff08;主備模式&#xff09;4.1 拓撲示例4.2 &#x1f6e0; 配置步驟 五. VRRP 配…

解決開發者技能差距:AI 在提升效率與技能培養中的作用

企業在開發者人才方面正面臨雙重挑戰。一方面&#xff0c;IDC 預測&#xff0c;到2025年&#xff0c;全球全職開發者將短缺400萬人&#xff1b;另一方面&#xff0c;一些行業巨頭已暫停開發者招聘&#xff0c;轉而倚重人工智能&#xff08;AI&#xff09;來滿足開發需求。這不禁…