Docker

出自 Arch Linux 中文维基

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

安裝[編輯 | 編輯原始碼]

要拉取Docker鏡像並運行Docker容器,你需要安裝Docker引擎,其包含包括一個守護進程來管理容器,以及一個docker命令行界面前端。安裝 docker 包 或者,對於開發版本,選擇docker-gitAUR 包. 下一步啟動 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"

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

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

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

Docker Compose[編輯 | 編輯原始碼]

Docker Compose是另一種Docker引擎的CLI前端,它使用compose.yamlYAML文件來指定容器的屬性,這樣就可以不使用附帶指令的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是在VM上啟動的,相比直接使用Docker引擎,預期性能會下降並且 CPU 使用率會提高。

GUI 工具[編輯 | 編輯原始碼]

  • ducker — 一個用於管理docker容器的終端應用程序。
  • oxker-binAUR — 一個簡單的 TUI程序,用於查看和控制 Docker 容器。
  • lazydockerAUR — 一個簡單的 docker 和 docker-compose 管理TUI程序,使用 Go 語言和 gocui 庫編寫。
  • dokoAUR — 一個簡單的docker TUI程序。
  • gomanagedockerAUR — 一款用於管理 Docker 對象的 TUI 程序。
  • whaler-gitAUR — 為 Pantheon 設計的 Docker 容器管理。
  • podman-desktopAUR — 從單一的用戶界面和托盤管理 Podman以及其他容器引擎。
  • portainer-binAUR — 一款輕量級的 Docker 管理用戶界面。
  • kitematicAUR — 可視化Docker 容器管理。

使用[編輯 | 編輯原始碼]

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守護進程使用位於/var/run/docker.sockUnix套接字來提供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文檔:如何配置代理,使用dockerCLI來自動為所有容器配置代理。

配置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)以避免網絡命名空間衝突。

鏡像位置[編輯 | 編輯原始碼]

默認,docker鏡像放置在 /var/lib/docker。他們可以被移動到其他分區,例如你想將鏡像移動到別的磁盤上,在這個例子中,假設我們要將鏡像移動到/mnt/docker

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

如果你正在運行docker鏡像,你必須確定鏡像被完全解除掛載。一旦這個完成後,你就可以把鏡像從 /var/lib/docker 移動到你的目標地點。在這個例子中使用指令cp -r /var/lib/docker /mnt/docker

/etc/docker/daemon.json中配置data-root:

/etc/docker/daemon.json
{
  "data-root": "/mnt/docker"
}

重啟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][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 image.

# 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

# 使用更快的镜像 
RUN echo 'Server = https://mirror.pkgbuild.com/$repo/os/$arch' > /etc/pacman.d/mirrorlist

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

# 配置 nvidia container runtime
# https://github.com/NVIDIA/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

初始化顯卡驅動錯誤: devmapper[編輯 | 編輯原始碼]

如果 systemctl 不能開啟docker並提供了以下信息:

Error starting daemon: error initializing graphdriver: devmapper: Device docker-8:2-915035-pool is not a thin pool

那麼嘗試以下步驟來解決錯誤。停止docker服務,備份 /var/lib/docker/ (如果需要的話), 移除/var/lib/docker/的內容, 嘗試重啟docker服務. 查閱 GitHub issue 獲取更多細節.

無法創建到某文件的路徑: 設備沒有多餘的空間了[編輯 | 編輯原始碼]

如果你獲取到的錯誤信息是像這樣的話:

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

當創建或者運行Docker鏡像時,儘管磁盤還有多餘的空間。所以請確保:

  • 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 RegistryQuay 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
    }
  }
} 

查閱更多[編輯 | 編輯原始碼]