Docker - Arch Linux 中文维基

跳至內容

# Docker

出自 Arch Linux 中文维基
翻譯狀態：

- 本文（或部分內容）譯自 Docker，最近一次同步於 2025-02-14，若英文版本有所更改，則您可以幫助同步與翻譯更改的內容。
- 您可以在 ArchWiki 的對應頁面找到本文翻譯的原始修訂歷史。
- 本文可能與英文原文存在出入。

相關文章

- Linux Containers
- Podman
- systemd-nspawn
- Vagrant

Docker 是一種打包、傳輸和運行任何程序作為輕量級容器的實用工具。

## 安裝

要拉取Docker鏡像並運行Docker容器，你需要安裝Docker引擎，其包含包括一個守護進程來管理容器，以及一個`docker`命令行界面前端。安裝 docker包 包。下一步啟用/啟動 `docker.service` 或者 `docker.socket`。兩者的差距在於`docker.service`將會在開機時啟動，而`docker.socket`將會在第一次啟動Docker時啟動，使用後者可以減少開機啟動時間。然後驗證操作:

    # docker info

注意, 如果你有一個活動的 VPN 連接, 那麼 docker 服務的啟動可能失敗, 因為 VPN 和 Docker 的網橋 IP 衝突以及網絡覆蓋。如果發生了這種事, 嘗試在啟動 docker 服務之前斷開 VPN 連接. 你可以在之後立刻重連 VPN。你也可以嘗試手動解決網絡衝突(也可參見[1]或[2])。

你也可以嘗試驗證是否可以運行容器。以下命令行將會下載一個最新的Arch Linux image，並使用其在這個容器中運行一個Hello World程序:

    # docker run -it --rm archlinux bash -c "echo hello world"

要刪除下載的Arch Linux Docker鏡像，請參見#移除 Docker 和鏡像。

如果你想以普通用戶身份運行docker的話，添加你自己到 `docker` 用戶組，重新登錄並重啟`docker.service`

警告：任何加入到 `docker` 組的用戶都和root用戶等價，因為他們可以通過運行`# docker run --privileged`來以root權限啟動容器。 參見 此處 以及 此處。

如果你還要使用 Docker 構建容器鏡像，請安裝docker-buildx包以使用新版構建器(否則會使用已棄用的舊版構建器)。

### Docker Compose

Docker Compose是另一種Docker引擎的CLI前端,它使用`compose.yaml` YAML文件來指定容器的屬性,這樣就可以不使用附帶指令的`docker run`腳本了。如果你需要經常設置或者使用具有複雜選項的容器,可能使用docker-compose更為方便。你需要安裝 docker-compose包來使用。

### Docker Desktop

Docker Desktop是一個專有的桌面應用程式,它在一個Linux虛擬機中運行Docker。它還包括Kubernetes集群以及一個漏洞掃描器。這個應用程式對於在macOS或Windows上進行開發Docker容器的團隊非常友好。Docker Desktop適配的Linux版本相對較新，同時也保持了對Docker CLI的良好兼容[3]。

Docker直接為Arch Linux提供了一個實驗性的軟體包（參見其官方文檔手動安裝Docker一節）。需要注意其手動下載的軟體包會與docker-compose包以及docker-buildx包衝突，你需要在安裝前手動移除這兩個包。如果你想保留現有的軟體包，你也可以從AUR安裝docker-desktopAUR，它將不會與現有軟體包發生衝突。

此外，在運行Docker Desktop之前，你需要確保你已經安裝了所有的在Linux上運行的最小系統要求,包括使用KVM進行虛擬化技術支援。對於Gnome用戶，你還需要安裝gnome-shell-extension-appindicator包以顯示托盤圖標。

最後，請注意文件共享功能是通過`/etc/subuid`和`/etc/subgid`映射用戶和組ID完成的。詳細參見Docker Desktop的Linux文件共享說明。

注意：在Linux上的Docker Desktop會在一個虛擬機(VM)上啟動，這個虛擬機會單獨創建並使用一個自定義的Docker上下文，即`desktop-linux`。

這意味著在安裝前，部署在Linux Docker引擎上的所有鏡像與容器都無法在Docker Desktop中使用。[4]

更多信息請參見Docker Desktop for Linux和Docker Engine的區別。

此外，由於Docker Desktop是在VM上啟動的，相比直接使用Docker引擎，預期性能會下降並且 CPU 使用率會提高。

默認情況下，Docker Desktop會啟用一個用戶級別的systemd服務，該服務會在啟動時自動啟動應用程式。在Docker Desktop儀錶板中禁用「自動啟動」設置並不能阻止此服務啟動，您需要手動禁用 `docker-desktop.service`。

### 前端工具

- Ducker — 一個用於管理Docker容器的終端應用程式。

  https://github.com/robertpsoane/ducker || ducker包

- goManageDocker — 一個用於管理Docker對象的TUI工具。

  https://github.com/ajayd-san/gomanagedocker || gomanagedockerAUR

- Lazydocker — 一個簡單的終端UI，用於管理docker和docker-compose，使用Go語言編寫，基於gocui庫。

  https://github.com/jesseduffield/lazydocker || lazydocker包

- oxker — 一個簡單的TUI，用於查看和控制Docker容器。

  https://github.com/mrjackwills/oxker || oxker-binAUR

- Podman Desktop — 從單一UI和托盤中管理Podman和其他容器引擎。

  https://github.com/containers/podman-desktop || podman-desktop包

- Portainer — 一個輕量級的Docker管理UI。

  https://github.com/portainer/portainer || portainer-binAUR

- Whaler — 為Pantheon設計的Docker容器管理工具。

  https://github.com/sdv43/whaler || whaler-gitAUR

## 使用

Docker由多個部分組成:

- Docker守護進程(也稱Docker引擎),這是一個以`docker.service`形式運行的進程。其提供了Docker API接口並管理Docker容器。

- `docker` CLI命令,其允許用戶使用命令行來與Docker API交互，並控制 Docker 守護進程。

- Docker容器，這是一種命名進程，由Docker守護進程通過Docker API的請求進行管理。

一般來說，用戶通過使用`docker`命令行來對Docker進行操作,命令行又通過Docker API對Docker守護進程發起請求以執行對容器的相關操作。掌握客戶端 (`docker`), 服務端(`docker.service`)和容器之間的關係是很必要的。

請注意，如果Docker守護進程停止/重啟，那麼當前運行的所有Docker容器也會停止/重啟。

你也可以不藉助`docker` CLI來對Docker API發起請求來控制容器，參見Docker API開發指南。

更多使用文檔請參見Docker入門指南。

## 配置

Docker守護進程可以通過修改配置文件`/etc/docker/daemon.json`或者直接在`docker.service`中添加命令行標誌來進行配置。根據Docker官方文檔, 推薦使用修改配置文件的方法進行配置。如果你想使用添加命令行標誌的方法進行配置，使用Systemd#附加配置片段覆蓋`docker.service`中的`ExecStart`部分。

對於`daemon.json`中的選項，參見守護進程配置文件參考。

### 存儲驅動程序

存儲驅動程序控制著Docker主機上的鏡像與容器的儲存與管理方式。默認的`overlay2`驅動在大部分情況下都具有良好的性能。

如果你的文件系統使用的是btrfs或者ZFS，你可以使用對應的`btrfs`或者`zfs`驅動,它們可以利用這些文件系統獨有的功能，要使用這些驅動請參見btrfs驅動或zfs驅動文檔。

### 啟用守護進程TCP套接字

本文或本節內容已經過時。

原因： Docker 26 棄用了未經身份驗證的TCP連接，並已經在Docker 28中移除。 (在Talk:Docker討論)

默認情況下,Docker守護進程使用位於`/var/run/docker.sock`的Unix套接字來提供Docker API。大部分情況下，這是一個合適的選擇。

你可以將設置守護進程設置為額外監聽TCP套接字,這樣就能使Docker API被遠程訪問了(參見允許遠程訪問Docker API)。如果你在Windows或macOS上使用Arch虛擬機，你可以在完成設置後使用宿主機上直接使用`docker`命令行訪問虛擬機中允許的Docker守護進程。

警告：Docker API默認情況下既沒有加密也沒有身份驗證。除非你在附加Docker配置中啟用了 使用SSH或TLS進行連接，否則對Docker守護進程的TCP訪問等同於不安全的遠程root訪問。

注意默認的`docker.service`設置了`-H`標誌，如果選項同時存在於標誌與`/etc/docker/daemon.json`文件中，Docker將不會啟動，因此最簡單的更改監聽TCP套接字設置的方法是使用一個附加文件。例如，如果你想在埠2376添加一個TCP套接字:

    /etc/systemd/system/docker.service.d/docker.conf

    [Service]
    ExecStart=
    ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2376

重載systemd守護進程並重啟 `docker.service`以應用更改。

### HTTP代理

要想在Docker中使用HTTP代理，你需要同時對Docker守護進程以及Docker容器進行配置。

#### Docker守護進程代理設置

參見Docker文檔：配置Docker守護進程使用HTTP代理。

#### Docker容器代理設置

參見Docker文檔：如何配置代理，使用`docker`CLI來自動為所有容器配置代理。

### 配置DNS

參見Docker中網絡配置了解Docker容器內部的DNS行為以及如何自定義Docker的DNS配置信息。一般來說，主機上的配置也會直接配置到容器中。

大部分託管在`127.0.0.0/8`上的DNS解析器都是不被支持的(由於容器和主機網絡命名空間之間的衝突)。這些解析器會在容器中的/etc/resolv.conf中刪除。如果這導致了`/etc/resolv.conf`為空文件,容器將會使用Google DNS。

此外，如果`127.0.0.53`是唯一的名稱伺服器，在這種特定的情況下Docker會假設解析器是systemd-resolved並使用來自`/run/systemd/resolve/resolv.conf`的上游DNS解析器。

如果你使用dnsmasq來提供一個本地解析器，考慮為dnsmasq添加一個虛擬接口(使用`169.254.0.0/16`網段的鏈路本地IP位址來綁定，而不是`127.0.0.1`)以避免網絡命名空間衝突。

### 鏡像位置

注意，從 版本 29（2025 年 11 月）開始，新安裝的默認鏡像存儲後端已變更為 containerd。

當使用 containerd 鏡像存儲時，鏡像內容和容器快照默認存儲在 `/var/lib/containerd/` 目錄下。如果是從舊版本升級而來，Docker 鏡像仍位於 `/var/lib/docker/` 目錄中，直到您手動啟用 containerd 鏡像存儲。

您可以使用以下命令來確認當前使用的鏡像儲存後端：

    docker info -f '{{ .DriverStatus }}'

使用 containerd 鏡像存儲時，輸出將為：

    [[driver-type io.containerd.snapshotter.v1]]

您可以通過修改 配置文件 來將Docker鏡像放置在其他位置(如其他分區或磁碟中)。

首先, 停止`docker.service`,注意，這也會停止所有當前運行的容器並卸載任何正在運行的鏡像。

然後根據鏡像存儲後端編輯相應的配置文件：

- 對於 containerd 儲存後端：

    /etc/containerd/config.toml

    version = 2
    root = "/path/to/containerd-data"

- 對於傳統Docker(overlay)儲存後端：

    /etc/docker/daemon.json

    {
      "data-root": "/path/to/docker-data"
    }

隨後將 `/var/lib/containerd` 或 `/var/lib/docker` 中的內容移至目標位置。

注意：請注意，對於傳統Docker(overlay)儲存後端，無法僅移動鏡像，必須同時移動鏡像和卷。

重啟`docker.service`以應用更改。

### 不安全的自建倉庫

如果你使用自簽名證書的倉庫(registries)，或該自建倉庫未使用TLS加密（即通過http連接）, docker會拒絕連接。你需要將其添加到信任列表中。 例如，要信任託管於`myregistry.example.com:8443`上的鏡像,在文件`/etc/docker/daemon.json`中配置`insecure-registries`的值：

    /etc/docker/daemon.json

    {
      "insecure-registries": [
        "my.registry.example.com:8443"
      ]
    }

隨後重新加載 `docker.service`配置。

### IPv6

為了開啟Docker中的IPv6支持,參見[5][失效連結 2025-03-15 ⓘ]與[6]。

首先，將`/etc/docker/daemon.json`中的`ipv6`設置為啟用並設置一個特定的IPV6子網(即使用私有的`fd00::/80`子網)。請確保至少使用80位的子網，因為這樣可以使容器的IPv6地址以容器的MAC地址結尾，這有助於解決NDP鄰居緩存失效的問題。

    /etc/docker/daemon.json

    {
      "ipv6": true,
      "fixed-cidr-v6": "fd00::/80"
    }

重啟 `docker.service`以應用更改。

最後，為了讓容器能夠訪問主機網絡，你需要添加IPv6 NAT以解決使用私有IPv6子網時出現的路由問題:

    # ip6tables -t nat -A POSTROUTING -s fd00::/80 ! -o docker0 -j MASQUERADE

現在Docker應該已經開啟了IPv6支持，你可以使用以下指令來進行測試：

    # docker run curlimages/curl curl -v -6 archlinux.org

如果你使用firewalld,你還需要添加防火牆規則，例如：

    # firewall-cmd --zone=public --add-rich-rule='rule family="ipv6" destination not address="fd00::1/80" source address="fd00::/80" masquerade'

如果你使用ufw,你還需要根據Uncomplicated Firewall#轉發策略創建Ipv6轉發。

首先，你需要編輯`/etc/default/ufw`並取消以下幾行的注釋：

    /etc/ufw/sysctl.conf

    net/ipv6/conf/default/forwarding=1
    net/ipv6/conf/all/forwarding=1

現在你可以使用以下命令添加iptables規則:

    # ip6tables -t nat -A POSTROUTING -s fd00::/80 ! -o docker0 -j MASQUERADE

如果你使用docker-compose來創建的容器,你可能還需要在`networks`中對應的部分設置`enable_ipv6: true`。另外，你可能還需要手動指定IPv6子網，參見compose-file中的ipv6地址設置。

### 用戶命名空間隔離

默認情況下，Docker中的進程和`dockerd`主守護程序運行在同一用戶命名空間中，即容器不會通過用戶命名空間隔離(參見user_namespaces(7))。這將會允許進程根據用戶和用戶組#權限與屬主在主機上來訪問已配置的資源。這樣提升了容器運行的兼容性，但是一旦出現了一個允許容器中進程訪問非預期資源的漏洞，這會帶來很大的安全隱患。(一個這樣的漏洞在2019年2月發布並修補。)

啟用用戶命名空間隔離可以降低此類漏洞的影響。其將會在單獨的用戶命空間中運行每個容器，並將這個空間中的UIDs/GIDs映射到主機上不同的(通常情況下也是非特權的)UIDs/GIDs。

注意：

- 主`dockerd`守護程序依然是以`root`身份在主機上運行的，在非root身份下運行docker(rootless mode)是另一個功能。
- 容器中的進程將會以Dockerfile中定義的USER指令定義的用戶身份啟動。
- 所有容器都會映射到相同的UID/GID範圍，這是為了讓容器之間的共享卷功能生效。
- 在一些情況下無法啟用用戶命名空間。
- 由於 Docker 需要調整這些資源的所有權，因此啟用用戶命名空間隔離會有效屏蔽現有的映像層和容器層，以及 `/var/lib/docker/` 中的其他 Docker 對象。上游文檔建議僅在新安裝的Docker上啟用此功能，而不是在現有的Docker上啟用。

在`/etc/docker/daemon.json`中配置`userns-remap`的值。`default`是一個特殊值，其會自動創建名為`dockremap`的用戶與用戶組用於重映射。

    /etc/docker/daemon.json

    {
      "userns-remap": "default"
    }

在`/etc/subuid`和`/etc/subgid`中配置用戶名/組名，UID/GID的範圍。在這個例子中，`dockremap`用戶/用戶組分配為從165536開始的65536個UIDs/GIDs。

    /etc/subuid

    dockremap:165536:65536

    /etc/subgid

    dockremap:165536:65536

重啟`docker.service`以應用更改。

應用此更改後，默認情況下所有容器都將在隔離的用戶命名空間中運行。你也可以在`docker`命令中加上添加標誌`--userns=host`來在特定的容器中禁用用戶命名空間隔離，參見[7]。

### 非特權模式運行Docker守護程序(Docker rootless)

注意：非特權模式下運行Docker守護程序(Docker rootless)依賴於非特權用戶命名空間(`CONFIG_USER_NS_UNPRIVILEGED`)。在linux包, linux-lts包, 和linux-zen包內核中默認啟用這一功能。如果你使用其他版本的內核，你可能需要手動啟用這一功能。這可能帶來一些安全隱患，參見安全#沙盒程序。

要將Docker守護程序作為普通用戶運行，安裝 docker-rootless-extrasAUR軟體包。

隨後在`/etc/subuid`與`/etc/subgid`中配置用戶名/用戶組名，起始 UID/GID 和 UID/GID 範圍大小，以分配重新映射的用戶和組。以下是一個示例：

    /etc/subuid

    your_username:165536:65536

    /etc/subgid

    your_username:165536:65536

啟用 `docker.socket` systemd/用戶單元: 這將會使用systemd的套接字激活來啟動docker。

最後設置docker套接字的環境變量:

    $ export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock

### 啟用本地覆蓋差異引擎(native overlay diff engine)

默認情況下Docker無法在Arch Linux上使用本地覆蓋差異引擎(native overlay diff engine),這會導致構建Docker鏡像很慢。如果你經常構建鏡像，請按照以下步驟配置:

    /etc/modprobe.d/disable-overlay-redirect-dir.conf

    options overlay metacopy=off redirect_dir=off

隨後停止`docker.service`, 重新加載`overlay`內核模塊:

    # modprobe -r overlay
    # modprobe overlay

重載內核模塊後，啟動`docker.service`。

要驗證是否成功啟用，你可以運行`docker info`檢查`Native Overlay Diff`值是否為`true`。

## 鏡像

### Arch Linux

下面的命令會拉取 archlinux x86_64 image。這是一個arch內核的剝離版本，沒有網絡等功能。

    # docker pull archlinux

另請參閱 README.md。

對於完整的arch鏡像，可以從下面克隆鏡像並且建立你自己的基礎鏡像。

    $ git clone https://gitlab.archlinux.org/archlinux/archlinux-docker.git

請確保devtools包, fakechroot包以及fakeroot包軟體包已被安裝。

隨後編輯構建文件並運行：

    # make docker-image

### Alpine Linux

Alpine Linux是一個熱門的小型容器鏡像，其比較適合運行靜態二進制形式軟體。使用以下命令來拉取最新的Alpine Linux鏡像:

    # docker pull alpine

Alpine Linux使用musl libc實現，這有區別與大部分的Linux發行版使用的glibc libc實現。 由於Arch Linux使用的glibc,因此Arch Linux主機與Alpine Linux容器之間存在有功能差異，這可能會影響軟體性能或正確性。你可以在此處查看存在的差異。

注意，在Arch Linux(或其他沒有使用musl libc實現的發行版)上編譯的動態連結軟體在Alpine Linux (或其他使用musl libc的鏡像)上可能會出現錯誤或性能問題。參見[8], [9]和[10]。

### Debian

下面的命令以拉取Debian鏡像 debian x86_64。

    # docker pull debian

請參閱Docker Hub頁面查看可用標籤的完整列表，包括每個Debian版本的標準版與精簡版。

#### 手動

用 debootstrap包建立Debian鏡像:

    # mkdir jessie-chroot
    # debootstrap jessie ./jessie-chroot http://http.debian.net/debian/
    # cd jessie-chroot
    # tar cpf - . | docker import - debian
    # docker run -t -i --rm debian /bin/bash

### Distroless

Google 維護著distroless鏡像，這是沒有基本作業系統組件(例如shells和包管理器)的最小化鏡像。其最小鏡像`gcr.io/distroless/static-debian11`僅有2MiB左右，可以用於打包軟體並生成非常小的鏡像。

請參閱GitHub中的README以獲得鏡像列表以及在不同程式語言中的使用方法。

## 有用的建議

### 抓取運行容器的IP位址

抓取運行容器的IP位址:

    $ docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <container-name OR id>

    172.17.0.37

每個正在運行的容器，它們的名字和相關IP位址都能被列出來在 `/etc/hosts`裡用:

    #!/usr/bin/env sh
    for ID in $(docker ps -q | awk '{print $1}'); do
        IP=$(docker inspect --format="{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" "$ID")
        NAME=$(docker ps | grep "$ID" | awk '{print $NF}')
        printf "%s %s\n" "$IP" "$NAME"
    done

### 運行容器中的圖像程序

本節介紹了允許在主機的X伺服器上運行圖形程序（包括依賴於OpenGL或Vulkan的程序）所需的步驟。

首先，需要在容器內安裝與主機圖形硬體兼容的正確驅動程序。如果容器使用的Arch Linux鏡像，請參見OpenGL#安裝或 Vulkan#安裝來安裝對應的驅動。

接下來，你需要授予容器訪問主機上X服務的權限。在單用戶環境中，你可以通過在主機中運行Xhost來完成這一操作。該命令將非網絡本地連接添加到訪問控制列表：

    $ xhost +local:

最後，你需要在`docker run`中傳遞以下參數:

- `-e "DISPLAY=$DISPLAY"`將環境變量`DISPLAY`設置為主機顯示器;
- `--mount type=bind,src=/tmp/.X11-unix,dst=/tmp/.X11-unix`將主機X伺服器套接字掛載到相同路徑下的容器內;
- `--device=/dev/dri:/dev/dri`允許容器直接訪問主機上的直接渲染(DRI) 設備。

為了驗證設置是否生效，請在容器中運行mesa-utils包中的`glxgears`命令(或者vulkan-tools包中的`vkcube`命令)。

### 開機啟動 Docker Compose 項目

本文或本章節的事實準確性存在爭議。

原因： 沒有必要在`compose.yml`中啟用`restart: always`(討論請參見[11])。[12]（在 Talk:Docker#"開機啟動 Docker Compose 項目" 是否多餘? 中討論）

首先，創建一個用於Docker Compose的Systemed單元，並通過服務名稱進行參數化(參見systemd.service(5) § SERVICE TEMPLATES):

    /etc/systemd/system/docker-compose@.service

    [Unit]
    Description=%i service with docker compose
    Requires=docker.service
    After=docker.service

    [Service]
    WorkingDirectory=/opt/%i
    ExecStartPre=-/usr/bin/docker compose pull
    ExecStart=/usr/bin/docker compose up --remove-orphans
    ExecStop=/usr/bin/docker compose down
    ExecReload=/usr/bin/docker compose pull
    ExecReload=/usr/bin/docker compose up --remove-orphans

    [Install]
    WantedBy=multi-user.target

隨後，對於你想運行的每一個服務，在`/opt/project_name`目錄下新建一個包含Compose文件以及其他所需文件(例如`.env`文件)[13]。

最後, 啟用/啟動 `docker-compose@project_name.service`。

### 使用buildx進行交叉編譯

buildx CLI 插件使用了新的BuildKit構建工具包。安裝docker-buildx包，buildx接口支持構建多平台鏡像(包括與主機不同的框架)。

交叉編譯鏡像也需要QEMU。如果你想在Docker中設置靜態版本的QEMU，請參見multiarch/qemu-user-static 鏡像。否則請在主機上設置QEMU與Docker共同使用(參見QEMU#從 x86_64 環境中 Chroot 至 arm/arm64 環境)。無論哪種情況，你的系統都將配置為對客戶端架構進行用戶模式模擬。

    $ docker buildx ls

    NAME/NODE DRIVER/ENDPOINT STATUS  PLATFORMS
    default * docker
      default default         running linux/amd64, linux/386, linux/arm64, linux/riscv64, linux/s390x, linux/arm/v7, linux/arm/v6

### 用NVIDIA GPU運行GPU加速的Docker容器

從19.03版本開始，Docker原生支持NVIDIA GPU作為Docker設備。 推薦使用NVIDIA Container Toolkit來運行需要操作NVIDIA顯卡的容器。 安裝 nvidia-container-toolkit包 包並重啟Docker。之後可以用`--gpus`選項來運行使用NVIDIA顯卡的容器

#### 使用 --gpus 選項（推薦）

    # docker run --gpus all nvidia/cuda:12.1.1-runtime-ubuntu22.04 nvidia-smi

指定容器內可使用多少GPU：

    # docker run --gpus 2 nvidia/cuda:12.1.1-runtime-ubuntu22.04 nvidia-smi

指定使用哪一個GPU：

    # docker run --gpus '"device=1,2"' nvidia/cuda:12.1.1-runtime-ubuntu22.04 nvidia-smi

或

    # docker run --gpus '"device=UUID-ABCDEF,1"' nvidia/cuda:12.1.1-runtime-ubuntu22.04 nvidia-smi

本文或本章節的事實準確性存在爭議。

原因： More information on when the following error happens is needed. It should work, see [14][失效連結 2023-04-23 ⓘ].（在 Talk:Docker#GPU accelerated Docker Nvidia 中討論）

如果在執行指令時收到錯誤`Failed to initialize NVML: Unknown Error`,你可以嘗試詳細指定GPU來解決這個問題:

    # docker run --gpus all --device /dev/nvidiactl:/dev/nvidiactl --device /dev/nvidia-uvm:/dev/nvidia-uvm --device /dev/nvidia0:/dev/nvidia0 nvidia/cuda:12.1.1-runtime-ubuntu22.04 nvidia-smi

指定需要的具體功能（圖像、計算等）

    # docker run --gpus all,capabilities=utility nvidia/cuda:12.1.1-runtime-ubuntu22.04 nvidia-smi

參閱 container-toolkit文檔與安裝指南。

#### 使用 NVIDIA Container Runtime

編輯`/etc/docker/daemon.json`以註冊NVIDIA運行時環境。

    /etc/docker/daemon.json

    {
      "runtimes": {
        "nvidia": {
          "path": "/usr/bin/nvidia-container-runtime",
          "runtimeArgs": []
        }
      }
    }

之後重啟 Docker。

運行時也可以通過dockerd的一個命令行選項來註冊。

    # /usr/bin/dockerd --add-runtime=nvidia=/usr/bin/nvidia-container-runtime

完成後可通過命令啟動GPU加速的容器:

    # docker run --runtime=nvidia nvidia/cuda:9.0-base nvidia-smi

或（要求 Docker 版本19.03或更高）

    # docker run --gpus all nvidia/cuda:9.0-base nvidia-smi

參閱 README.md。

#### 有CUDA的 Arch Linux 鏡像

可使用以下`Dockerfile` 構建自定義的有CUDA的 Arch Linux 鏡像。它使用 Dockerfile frontend syntax 1.2 在宿主機上緩存pacman包。請注意，你必須在構建鏡像之前設置環境變量`DOCKER_BUILDKIT=1`。

    Dockerfile

    # syntax=docker/dockerfile:1.2

    FROM archlinux:base-devel

    # 安装包
    RUN --mount=type=cache,sharing=locked,target=/var/cache/pacman \
        pacman -Syu --noconfirm --needed cuda

    # 配置 nvidia container runtime
    # https://github.com/NVIDIA/nvidia-container-toolkit/tree/main/cmd/nvidia-container-runtime#environment-variables-oci-spec
    ENV NVIDIA_VISIBLE_DEVICES=all
    ENV NVIDIA_DRIVER_CAPABILITIES=compute,utility

## 移除 Docker 和鏡像

如果你想完全移除 Docker，你可以通過下面的步驟完成：

注意：不要僅僅只是複製粘貼下面的命令而不知道你在幹什麼！

檢查正在運行的容器：

    # docker ps

列出在主機運行的所有容器，為刪除做準備：

    # docker ps -a

停止一個運行的容器：

    # docker stop <CONTAINER ID>

殺死還在運行的容器：

    # docker kill <CONTAINER ID>

通過 ID 刪除列出的所有容器：

    # docker rm <CONTAINER ID>

列出所有的 Docker 鏡像：

    # docker images

通過 ID 刪除所有鏡像：

    # docker rmi <IMAGE ID>

刪除所有與容器沒有關聯的鏡像、容器、卷與網絡（懸空）：

    # docker system prune

要刪除所有停止的容器和所有未使用的鏡像（而不只是懸空鏡像），添加 `-a` 標誌：

    # docker system prune -a

刪除所有 Docker 數據（清除目錄）：

    # rm -R /var/lib/docker

## 故障排除

### 使用systemd-networkd時,docker0 網橋無法獲取 IP / Internet 到容器

Docker會自己啟用IP轉發，但是默認 systemd-networkd 會覆蓋對應的sysctl設置，在網絡配置文件裡設置 `IPForward=yes`。查閱網絡分享#啟用包轉發獲取細節。

當systemd-networkd嘗試管理由Docker創建的網絡時，如果你在`Match`部分設置了`Name=*`或`Type=ether`，這可能會導致網絡連接出現問題。請更為具體地配置接口，即儘可能避免使用`Name=*`，`Type=ether`等通配符來匹配Docker管理的接口。你可以驗證 `networkctl list` 是否在 Docker 創建的所有網絡的 SETUP 欄中設置為 `unmanaged`。

注意：

- 你可能需要在每次 重啟 `systemd-networkd.service` 或者 `iptables.service` 之後，再手動重啟 `docker.service`。
- 注意nftables默認情況下可能會禁止Docker的連接，你可以使用命令 `nft list ruleset` 來檢查規則集。
- 你可以使用 `nft flush chain inet filter forward` 來臨時移除所有轉發規則，或者編輯 `/etc/nftables.conf` 文件使其永久生效。在更改了配置文件，請 重啟 `nftables.service` 以應用更改。詳細了解Docker的nftables支持請參見 [15]。

### 默認的允許的進程/線程數太少

如果你允許時得到下面的錯誤信息

    # e.g. Java
    java.lang.OutOfMemoryError: unable to create new native thread
    # e.g. C, bash, ...
    fork failed: Resource temporarily unavailable

那麼你可能需要調整被systemd允許的進程數, 編輯並添加下面片段 `docker.service` :

    # systemctl edit docker.service

    [Service]
    TasksMax=infinity

對於更多參數,例如 `DefaultLimitNPROC`，請參閱 systemd-system.conf(5) § OPTIONS。對於 `TasksMax` 請參閱 systemd.resource-control(5) § OPTIONS。

### 無法創建到某文件的路徑: 設備沒有多餘的空間了

如果你在創建或者運行Docker鏡像時獲取到類似的錯誤信息:

    ERROR: Failed to create some/path/to/file: No space left on device

如此時磁碟還有多餘的空間，請確保:

- Tmpfs 被禁用了並且有足夠的內存分配. Docker可能會嘗試寫入文件到 `/tmp` 但是失敗了因為內存使用的限制和磁碟空間不足.
- 如果你在使用 XFS, 你可能得從相關入口移除 `noquota` 掛載選項在 `/etc/fstab`裡 (通常是 `/tmp` 和/或 `/var/lib/docker` 在的地方). 查閱 Disk quota 獲取更多信息, 特別是你計劃使用和調整 `overlay2` Docker 存儲驅動.
- XFS 的配額掛載選項在文件系統重新掛載時 (`uquota`, `gquota`, `prjquota`, 等等.) 失敗了. 為了為root文件系統啟用配額掛載選項必須作為內核參數 `rootflags=`傳遞到initramfs. 之後, 它就不應該在 `/etc/fstab`中的掛載選項中列出root (`/`) 文件系統.

注意：XFS配額和標準LinuxDisk quota, [16] 是有區別的。這裡值得一讀。

### Docker-machine無法使用virtualbox驅動程序創建虛擬機

如果docker-machine 無法使用 virtualbox 驅動程序創建虛擬機並提供了以下信息:

    VBoxManage: error: VBoxNetAdpCtl: Error while adding new interface: failed to open /dev/vboxnetctl: No such file or directory

嘗試在CLI中使用`vboxreload`重啟virtualbox。

### 啟動Docker後會破壞KVM的橋接網絡

這是因為啟動Docker的腳本會添加一些iptables規則,其會阻止除自身外的其他接口進行轉發。這是一個已知問題。

您可以嘗試以下的解決方案(請將br0替換為您自己的橋接網絡名稱):

- 最快的解決方案(但是這會關閉所有Docker自動添加的iptables規則):

    /etc/docker/daemon.json

    {
      "iptables": false
    }

- 如果您已經配置好了用於KVM的橋接網絡，您也可以通過修改Docker的配置文件來解決這個問題，參見[17]將配置文件修改為：

    /etc/docker/daemon.json

    {
      "bridge": "br0"
    }

- 如果上述方法無效，或者您希望直接通過iptables或者類似於UFW的管理器來解決問題，請添加以下內容:

    iptables -I FORWARD -i br0 -o br0 -j ACCEPT

更詳細的解決方案可以參見此處。

### 從Docker Hub拉取的鏡像受到速率限制

從2020年11月1日開始，Docker Hub限制了匿名用戶以及免費帳戶用戶的下載速率，詳細請參見速率限制文檔。

匿名用戶的速率限制通過IP進行跟蹤，免費帳戶用戶的速率限制通過帳戶進行跟蹤。

如果你需要更高的下載速率，你可以註冊付費計劃或者將你需要的鏡像拉取到不同的鏡像倉庫。你可以自建鏡像倉庫或者使用雲託管的鏡像站點，例如 Amazon ECR, Google Container Registry, Azure Container Registry 或 Quay Container Registry。

使用Docker CLI 中的 `pull`, `tag` 以及 `push` 命令來鏡像一個鏡像。例如，將 Nginx 標籤(tag)為 `1.19.3` 的鏡像鏡像到託管於 `cr.example.com` 上的倉庫:

    $ docker pull nginx:1.19.3
    $ docker tag nginx:1.19.3 cr.example.com/nginx:1.19.3
    $ docker push cr.example.com/nginx:1.19.3

隨後你可以從鏡像倉庫中拉取並運行鏡像:

    $ docker pull cr.example.com/nginx:1.19.3
    $ docker run cr.example.com/nginx:1.19.3

### 錯誤提示：iptables (舊版): 未知選項 "--dport"

本文或本章節的事實準確性存在爭議。

原因： Nftables#與 Docker 一起工作 建議不要使用 iptables-nft包。（在 Talk:Docker 中討論）

如果你在運行容器時收到了這樣的錯誤： `iptables (legacy): unknown option "--dport"`

安裝 iptables-nft包 而不是 iptables包 (舊版) 然後重啟[18]。

注意：使用iptables-nft包可能會導致docker 混合 nftables 和 iptables 規則，詳細參見Nftables#與 Docker 一起工作。

### 運行docker login時提示"密碼以非加密形式儲存"

默認情況下 Docker 會嘗試使用 `pass` 或者 `secretservice` 的二進制形式文件來儲存你的註冊表密碼。如未能找到這些文件，註冊表秘密將以明文形式(base64編碼)儲存在 `$HOME/.docker/config.json` ，並在登錄成功後提示:

    $ WARNING! Your password will be stored unencrypted in /home/username/.docker/config.json.

如果你在使用支持 Secret Service Freedesktop DBUS API 的密碼管理器,例如KDE的 kwallet包 或著 GNOME的 gnome-keyring包，你可以安裝 docker-credential-secretserviceAUR 來讓你的註冊表密碼儲存在密碼管理器中。

### "無法在默認選項中找到可用的，不重疊的IPv4地址池進行分配"

如果你在使用大量的 Docker 項目 (例如使用 docker-compose)，可能會出現Docker容器的可用IP位址不足的情況：

    Could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network

參見這個 Docker issue, 默認選項是:

Type | Default Size | Default Pool
--- | --- | ---
local | /16 | 172.17.0.0/12
local* | /20 | 192.168.0.0/16

你可以在 `/etc/docker/daemon.json` 文件中修改 `default-address-pools` ，將其中第一個IP範圍的值從16改為24解決這個問題。為了避免本地網絡發生IP衝突，請不要修改第二個IP範圍的值。

    /etc/docker/daemon.json

    {
      ...
      "default-address-pools" : [
        {
          "base" : "172.17.0.0/12",
          "size" : 24
        },
        {
          "base" : "192.168.0.0/16",
          "size" : 24
        }
      ]
    }

重啟 `docker.service` 以應用更改。

更多詳細信息和技術解釋請參見文章: Docker默認地址池選項的權威指南。

### Golang編譯速度過慢

由於ulimit配置的原因，使用makepkg構建docker鏡像以及其依賴時會非常緩慢（會在"Entering fakeroot environment..."處卡住）。

這是因為[19] [20]，你可以嘗試將 `--ulimit "nofile=1024:524288"` 添加到你的docker構建選項中來解決問題：

    /etc/docker/daemon.json

    {
      "default-ulimits": {
        "nofile": {
          "Name": "nofile",
          "Soft": 1024,
          "Hard": 524288
        }
      }
    }

## 另請參閱

- 官方網站
- Arch Linux on docs.docker.com
- Docker 容器真的安全嗎？——opensource.com
- Awesome Docker
- 為什麼在 Docker 中運行特權容器是個壞主意

分類：​

- 沙箱
- 虛擬化
- 使用「模板:過時」標記的頁面或章節
- 包含失效連結的頁面

隱藏分類：​

- 使用「模板:準確性」標記的頁面或章節

Docker
新增話題