如何優雅的給 Docker 配置網絡代理 如何配置docker通過代理服務器拉取鏡像

有時因爲網絡原因,比如公司 NAT,或其它啥的,需要使用代理。Docker 的代理配置,略顯複雜,因爲有三種場景。但基本原理都是一致的,都是利用 Linux 的 http_proxy 等環境變量。

Dockerd 代理

在執行docker pull時,是由守護進程dockerd來執行。因此,代理需要配在dockerd的環境中。而這個環境,則是受systemd所管控,因此實際是systemd的配置。

sudo mkdir -p /etc/systemd/system/docker.service.d
sudo touch /etc/systemd/system/docker.service.d/proxy.conf

在這個proxy.conf文件(可以是任意*.conf的形式)中,添加以下內容:

[Service]
Environment="HTTP_PROXY=http://proxy.example.com:8080/"
Environment="HTTPS_PROXY=http://proxy.example.com:8080/"
Environment="NO_PROXY=localhost,127.0.0.1,.example.com"

其中,proxy.example.com:8080 要換成可用的免密代理。通常使用 cntlm 在本機自建免密代理,去對接公司的代理。可參考《Linux下安裝配置Cntlm 代理》。

Container 代理

在容器運行階段,如果需要代理上網,則需要配置 ~/.docker/config.json。以下配置,只在Docker 17.07及以上版本生效。

{
 "proxies":
 {
   "default":
   {
     "httpProxy": "http://proxy.example.com:8080",
     "httpsProxy": "http://proxy.example.com:8080",
     "noProxy": "localhost,127.0.0.1,.example.com"
   }
 }
}

這個是用戶級的配置,除了 proxies,docker login 等相關信息也會在其中。而且還可以配置信息展示的格式、插件參數等。

此外,容器的網絡代理,也可以直接在其運行時通過 -e 注入 http_proxy 等環境變量。這兩種方法分別適合不同場景。config.json 非常方便,默認在所有配置修改後啓動的容器生效,適合個人開發環境。在CI/CD的自動構建環境、或者實際上線運行的環境中,這種方法就不太合適,用 -e 注入這種顯式配置會更好,減輕對構建、部署環境的依賴。當然,在這些環境中,最好用良好的設計避免配置代理上網。

Docker Build 代理

雖然 docker build 的本質,也是啓動一個容器,但是環境會略有不同,用戶級配置無效。在構建時,需要注入 http_proxy 等參數。

docker build . \
    --build-arg "HTTP_PROXY=http://proxy.example.com:8080/" \
    --build-arg "HTTPS_PROXY=http://proxy.example.com:8080/" \
    --build-arg "NO_PROXY=localhost,127.0.0.1,.example.com" \
    -t your/image:tag

注意:無論是 docker run 還是 docker build,默認是網絡隔絕的。如果代理使用的是 localhost:3128 這類,則會無效。這類僅限本地的代理,必須加上 --network host 才能正常使用。而一般則需要配置代理的外部IP,而且代理本身要開啓 Gateway 模式。

粉絲福利, 免費領取C/C++ 開發學習資料包、技術視頻/代碼,1000道大廠面試題,內容包括(C++基礎,網絡編程,數據庫,中間件,後端開發,音視頻開發,Qt開發,遊戲開發,Linux內核等進階學習資料和最佳學習路線)↓↓↓↓有需要的朋友可以進企鵝裙927239107領取哦~↓↓

重啓生效

代理配置完成後,reboot 重啓當然可以生效,但不重啓也行。

docker build 代理是在執行前設置的,所以修改後,下次執行立即生效。Container 代理的修改也是立即生效的,但是隻針對以後啓動的 Container,對已經啓動的 Container 無效。

dockerd 代理的修改比較特殊,它實際上是改 systemd 的配置,因此需要重載 systemd 並重啓 dockerd 才能生效。

sudo systemctl daemon-reload
sudo systemctl restart docker

如何配置docker通過代理服務器拉取鏡像 - 醉馬踏千秋 - 博客園

如何配置docker通過代理服務器拉取鏡像

 

如果 docker 所在的環境是通過代理服務器和互聯網連通的,那麼需要一番配置才能讓 docker 正常從外網正常拉取鏡像。然而僅僅通過配置環境變量的方法是不夠的。本文結合已有文檔,介紹如何配置代理服務器能使docker正常拉取鏡像。

本文使用的docker 版本是

docker --version
Docker version 24.0.2, build cb74dfc

問題現象

如果不配置代理服務器就直接拉鏡像,docker 會直接嘗試連接鏡像倉庫,並且連接超時報錯。如下所示:

$ docker pull busybox
Using default tag: latest
Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled 
while waiting for connection (Client.Timeout exceeded while awaiting headers)

容易誤導的官方文檔

有這麼一篇關於 docker 配置代理服務器的 官方文檔 ,如果病急亂投醫,直接按照這篇文章配置,是不能成功拉取鏡像的。

我們來理解一下這篇文檔,文檔關鍵的原文摘錄如下:

If your container needs to use an HTTP, HTTPS, or FTP proxy server, you can configure it in different ways: Configure the Docker client On the Docker client, create or edit the file ~/.docker/config.json in the home directory of the user that starts containers.

...

When you create or start new containers, the environment variables are set automatically within the container.

這篇文檔說:如果你的 容器 需要使用代理服務器,那麼可以以如下方式配置: 在運行容器的用戶 home 目錄下,配置 ~/.docker/config.json 文件。重新啓動容器後,這些環境變量將自動設置進容器,從而容器內的進程可以使用代理服務。

所以這篇文章是講如何配置運行 容器 的環境,與如何拉取鏡像無關。如果按照這篇文檔的指導,如同南轅北轍。

要解決問題,我們首先來看一般情況下命令行如何使用代理。

環境變量

常規的命令行程序如果要使用代理,需要設置兩個環境變量:HTTP_PROXY 和 HTTPS_PROXY 。但是僅僅這樣設置環境變量,也不能讓 docker 成功拉取鏡像。

我們仔細觀察 上面的報錯信息,有一句說明了報錯的來源:

Error response from daemon:

因爲鏡像的拉取和管理都是 docker daemon 的職責,所以我們要讓 docker daemon 知道代理服務器的存在。而 docker daemon 是由 systemd 管理的,所以我們要從 systemd 配置入手。

正確的官方文檔

關於 systemd 配置代理服務器的 官方文檔在這裏,原文說:

The Docker daemon uses the HTTP_PROXY, HTTPS_PROXY, and NO_PROXY environmental variables in its start-up environment to configure HTTP or HTTPS proxy behavior. You cannot configure these environment variables using the daemon.json file.

This example overrides the default docker.service file.

If you are behind an HTTP or HTTPS proxy server, for example in corporate settings, you need to add this configuration in the Docker systemd service file.

這段話的意思是,docker daemon 使用 HTTP_PROXYHTTPS_PROXY, 和 NO_PROXY 三個環境變量配置代理服務器,但是你需要在 systemd 的文件裏配置環境變量,而不能配置在 daemon.json 裏。

具體操作

下面是來自 官方文檔 的操作步驟和詳細解釋:

1、創建 dockerd 相關的 systemd 目錄,這個目錄下的配置將覆蓋 dockerd 的默認配置

$ sudo mkdir -p /etc/systemd/system/docker.service.d

新建配置文件 /etc/systemd/system/docker.service.d/http-proxy.conf,這個文件中將包含環境變量

[Service]
Environment="HTTP_PROXY=http://proxy.example.com:80"
Environment="HTTPS_PROXY=https://proxy.example.com:443"

如果你自己建了私有的鏡像倉庫,需要 dockerd 繞過代理服務器直連,那麼配置 NO_PROXY 變量:

[Service]
Environment="HTTP_PROXY=http://proxy.example.com:80"
Environment="HTTPS_PROXY=https://proxy.example.com:443"
Environment="NO_PROXY=your-registry.com,10.10.10.10,*.example.com"

多個 NO_PROXY 變量的值用逗號分隔,而且可以使用通配符(*),極端情況下,如果 NO_PROXY=*,那麼所有請求都將不通過代理服務器。

重新加載配置文件,重啓 dockerd

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

檢查確認環境變量已經正確配置:

$ sudo systemctl show --property=Environment docker

從 docker info 的結果中查看配置項。

這樣配置後,應該可以正常拉取 docker 鏡像。

結論

docker 鏡像由 docker daemon 管理,所以不能用修改 shell 環境變量的方法使用代理服務,而是從 systemd 角度設置環境變量。

參考資料
https://www.lfhacks.com/tech/pull-docker-images-behind-proxy/#correct
https://stackoverflow.com/questions/69047394/cant-pull-docker-image-behind-a-proxy
https://mikemylonakis.com/unix/docker-proxy/
https://docs.docker.com/config/daemon/systemd/

 

在一些特定環境下,需要在代理環境下使用Docker的某些功能,本文介紹一些場景下 如何配置網絡代理

1. 爲Docker Daemon配置代理

1.1 使用systemd配置代理

爲了使docker pull指令使用代理,需要在/lib/systemd/system/docker.service中的[Service]片段下添加HTTP_PROXYHTTPS_PROXY環境變量:

[Service]
# 新增環境變量提供代理服務器信息
Environment="HTTP_PROXY=http://<user>:<password>@<domain>:<port>"
Environment="HTTPS_PROXY=http://<user>:<password>@<domain>:<port>"
# 如果使用了國內鏡像源可以配置鏡像服務器不使用代理
Environmeng="NO_PROXY=<registry.domain>"
ExecStart=...
...
注意:尖括號<>中的內容需要替換爲自己的代理服務器信息

隨後刷新配置:

systemctl daemon-reload

此時可以通過以下指令檢查配置是否加載成功:

systemctl show --property Environment docker
# 輸出
Environment=HTTP_PROXY=http://<user>:<password>@<domain>:<port> HTTPS_PROXY=http://<user>:<password>@<domain>:<port> NO_PROXY=<registry.domain>

重啓Docker服務使配置生效

systemctl restart docker

重啓成功之後通過docker info指令查看docker服務中的代理配置

docker info | grep Proxy
# 輸出
 HTTP Proxy: http://<user>:<password>@<domain>:<port>
 HTTPS Proxy: http://<user>:<password>@<domain>:<port>
 No Proxy: <registry.domain>

此時再使用docker pull指令拉取鏡像時Docker服務會使用代理服務器拉取鏡像。

此外,systemd也會從/etc/systemd/system/docker.service.d/lib/systemd/system/docker.service.d文件夾下讀取配置,所以可以再其中一個文件夾中創建一個名爲http-proxy.conf的文件用來保存代理信息。內容如下:

[Service]
Environment="HTTP_PROXY=http://<user>:<password>@<domain>:<port>"
Environment="HTTPS_PROXY=http://<user>:<password>@<domain>:<port>"
Environmeng="NO_PROXY=<registry.domain>"

1.2 通過daemon.json配置代理

/etc/docker/daemon.json中增加代理配置:

{
  "registry-mirrors": ["..."],
  "proxies": {
    "http-proxy": "http://<user>:<password>@<domain>:<port>",
    "https-proxy": "http://<user>:<password>@<domain>:<port>",
    "no-proxy": "<registry.domain>"
  }
}

重啓Docker服務:

systemctl restart docker

檢查配置是否生效:

docker info| grep Proxy
# 輸出
 HTTP Proxy: http://<user>:<password>@<domain>:<port>
 HTTPS Proxy: http://<user>:<password>@<domain>:<port>
 No Proxy: <registry.domain>

注意:通過daemon.json方式配置的優先級會高於通過systemd配置。

2. 在容器中使用代理

2.1 通過命令行配置代理

docker run --env HTTP_PROXY="http://<user>:<password>@<domain>:<port>" <some-image>

驗證

docker run \
    --env HTTP_PROXY="http://<user>:<password>@<domain>:<port>" \
    --rm alpine sh -c 'env | grep -i  _PROXY'
# 輸出
HTTP_PROXY=http://<user>:<password>@<domain>:<port>

2.2 通過~/.docker/config.json配置

~/.docker/config.json中增加以下配置:

{
  "auths": {
    "..."
  },
  "proxies": {
    # 通用配置,會對當前客戶端連接的所有Docker服務生效
    "default": {
      "httpProxy": "http://proxy.example.com:3128",
      "httpsProxy": "https://proxy.example.com:3129",
      "noProxy": "*.test.example.com,.example.org,127.0.0.0/8"
    },
    # 如果只對某個Docker服務時配置代理,則需要通過 docker-host: proxy-settings的方式在下面配置 
    "tcp://docker-daemon1.example.com": {
      "noProxy": "*.internal.example.net"
    }
  }
}

驗證:

docker run --rm alpine sh -c 'env | grep -i  _PROXY'
# 輸出
HTTPS_PROXY=https://proxy.example.com:3129
no_proxy=*.test.example.com,.example.org,127.0.0.0/8
NO_PROXY=*.test.example.com,.example.org,127.0.0.0/8
https_proxy=https://proxy.example.com:3129
http_proxy=http://proxy.example.com:3128
HTTP_PROXY=http://proxy.example.com:3128

3. 在構建鏡像的過程中使用代理

通過~/.docker/config.json的方式配置代理在構建過程中依然有效。

驗證:

docker build \
  --no-cache \
  --progress=plain \
  - <<EOF
FROM alpine
RUN env | grep -i _PROXY
EOF
# 輸出
# ...
#5 [2/2] RUN env | grep -i _PROXY
#5 0.382 HTTPS_PROXY=https://proxy.example.com:3129
#5 0.382 no_proxy=*.test.example.com,.example.org,127.0.0.0/8
#5 0.382 NO_PROXY=*.test.example.com,.example.org,127.0.0.0/8
#5 0.382 https_proxy=https://proxy.example.com:3129
#5 0.382 http_proxy=http://proxy.example.com:3128
#5 0.382 HTTP_PROXY=http://proxy.example.com:3128
#5 DONE 0.6s
# ...

3.1 通過命令行配置代理

docker build --build-arg HTTP_PROXY="http://proxy.example.com:3128"

驗證

docker build --build-arg HTTP_PROXY="http://another-proxy.example.com:3128" \
  --no-cache \
  --progress=plain \
  - <<EOF
FROM alpine
RUN env | grep -i _PROXY
EOF
# 輸出
# ...
#5 [2/2] RUN env | grep -i _PROXY
#5 0.393 HTTPS_PROXY=https://proxy.example.com:3129
#5 0.393 no_proxy=*.test.example.com,.example.org,127.0.0.0/8
#5 0.393 NO_PROXY=*.test.example.com,.example.org,127.0.0.0/8
#5 0.393 https_proxy=https://proxy.example.com:3129
#5 0.393 http_proxy=http://another-proxy.example.com:3128
#5 0.393 HTTP_PROXY=http://another-proxy.example.com:3128
#5 DONE 0.6s
# ...

3.2 不要在Dockerfile中使用ENV指令配置構建過程中使用到的代理配置

使用環境變量配置構建過程中用到的代理配置會把代理服務器打包進鏡像中,如果代理服務器是私有化部署的服務器,通過此鏡像創建的容器可能訪問不到代理服務器,產生難以理解的錯誤。

同時,由於代理配置中可能包含敏感信息,把代理服務器信息嵌入到鏡像中也有可能造成一些安全隱患。

資料來源

Configure the daemon with systemd

Configure Docker to use a proxy

配置Docker代理 - 知乎

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章