Docker 環境下的 Proxy 配置
關於 Docker 環境下的 Proxy 配置,需要先根據問題具體情況分辨配置方法,有兩種:一個是 docker daemon 的配置,這主要是為了能讓 docker host 通過 proxy server 使用 docker pull/docker run 存取遠端 registry;另一個是 docker client 為了建置 image 或運行 container 的時候所需要的網路配置。
首先快速回顧一下 Linux 作業系統中命令行環境的 proxy 配置方法,以 CentOS 系統環境為例,假設一台 HTTPS proxy server 位在 192.168.1.34 而且 port 是 3128:
# environment variables for https proxy
# export https_proxy="https://192.168.1.34:3128/"
如果 Proxy server 需要輸入帳號密碼,則用下面這樣的形式
# Https proxy with authentication
# export https_proxy="https://username:password@192.168.1.34:3128/"
之後 ping 8.8.8.8 看看Internet是否有連通,可以的話就可在 shell 環境下使用軟體包管理器像是 yum, apt-get 等等,安裝新的軟體,但是,同樣的作業系統環境變數設定對於 Docker 引擎不起作用。
Docker 環境下的 Proxy 配置,根據問題具體情況分為 docker daemon 以及 docker client 的配置,下面分別詳細說明。以下方法可適用在 Docker CE 或 Docker EE 17.06 以上的版本。
(一)Docker daemon 的 proxy 配置
如果 Docker host 處於 air-gapped 的環境下,需要先配置 proxy 才能連到 Internet,否則直接用 docker pull 或相關的命令從遠端 registry 來存取 docker images 會遭遇失敗。
以 CentOS,RedHat, Debian, Ubuntu 為主 使用 systemd 來管理系統服務的作業系統,可以用下列方式修改 proxy 配置,
建立目錄
# create a systemd drop-in directory for the docker service
$ sudo mkdir -p /etc/systemd/system/docker.service.d
增加一個檔案在 /etc/systemd/system/docker.service.d/http-proxy.conf 並且增加下面關於 HTTPS PROXY 配置,
[Service]
Environment="HTTPS_PROXY=https://192.168.1.34:3128/"
重啟 Docker 引擎
# Restart docker daemon
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker
# verify
$ sudo systemctl show --property=Environment docker
Environment=HTTPS_PROXY=https://192.168.1.34:3128/
如果檢查結果看到類似上述內容,就代表設定成功。接下來就可以用 docker pull 等等相關命令從遠端 registry 下載 docker images 使用。
(二)image container 建置及運行
在 Docker 引擎端配置的 https proxy, 無法直接套用於 image 建置以及 container 的運行上,需要根據所使用的 base image 另外配置環境變數於其中。
以容器化建置常用的 alpine 作業系統作為 base image 為例。在 docker host 主機下,建置一個以 alpine 為基礎的 image, 編寫如下 Dockerfile:
# Dockerfile for the images based on Alpine
FROM alpine:3.8
ENV HTTPS_PROXY https://192.168.1.34:3128/
RUN apk update && apk add curl
如果 Proxy 需要輸入帳號密碼,則用下面這樣的形式,
# Dockerfile for the images based on Alpine
FROM alpine:3.8
ENV HTTPS_PROXY https://192.168.1.34:3128/
ENV HTTPS_PROXY_AUTH basic:*:username:password
RUN apk update && apk add curl
如果以其它系統例如 UBUNTU (ubuntu:16.04), CentOS (centos:7) 作為 base image 在 Dockerfile 裡面使用 ENV 指令,後面接如上述一般作業系統中所下的環境變數設定即可:
# Dockerfile for the images based on CentOS 7
FROM centos:7
ENV HTTPS_PROXY https://192.168.1.34:3128/
RUN yum update && yum install curl
大部分的情況下,只要根據 base image 的作業系統類型有配置上述環境變數,就可以使用 proxy. 但仍有少數應用程式需要另外設定,例如像是 Node.js 預設的、以 JavaScript 編寫的軟體套件管理系統, npm ,就需要再加入:
# setup proxy for npm
RUN npm config set proxy https://192.168.1.34:3128/ && npm install
使用 Dockerfile 的 ENV 指令,在 image 建置時期(build-time)有效,而且在 container 運行時期(run-time)也是有效的。以上述的例子來說,image 建置時期會使用 Proxy https://192.168.1.34:3128 來更新作業系統內軟體清單及安裝 curl, 而且在 container 運行時期(run-time) 此 Proxy 設定依然存在且有效,在 container 存活期間,其內部的 process 依舊能夠使用此 Proxy 設定。如果不使用 Dockerfile 的 ENV 指令,命令行下
docker run --env 也有同樣的效果。在 Dockerfile 中,如果使用 ARG 指令,則設定的內容只有在 image 建置時期(build-time)是有效的。以上述的例子來說,image 建置時期會使用 Proxy https://192.168.1.34:3128 來更新作業系統內軟體清單及安裝 curl, 在建置完成後 Proxy 設定就無效,在 container 運行時期(run-time)無法使用這個參數。使用命令行
docker build --build-arg 也是同樣的結果。這篇文章綜合整理了 Docker 環境中不同情況下的 proxy 的配置方式,如日後Docker功能有所變動,將會隨時再更新本文內容。
Thanks for your reading.
常見問題(FAQ)
為什麼設定了作業系統的 proxy 環境變數,docker pull 還是連不到遠端 registry?
因為在 shell 中用 export https_proxy 設定的作業系統環境變數,對 Docker 引擎(daemon)不起作用。Docker daemon 有獨立的 proxy 設定機制。在使用 systemd 管理服務的作業系統(CentOS、RedHat、Debian、Ubuntu)上,正確作法是建立 systemd drop-in 目錄與設定檔:
$ sudo mkdir -p /etc/systemd/system/docker.service.d
再新增 /etc/systemd/system/docker.service.d/http-proxy.conf,內容為:
[Service]
Environment="HTTPS_PROXY=https://192.168.1.34:3128/"
存檔後重啟引擎並驗證:
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker
$ sudo systemctl show --property=Environment docker
設定成功後,docker pull 才能透過 proxy 從遠端 registry 下載 images。此方法適用於 Docker CE 或 Docker EE 17.06 以上版本。
Docker daemon 的 proxy 和 image 建置、container 運行的 proxy 為什麼要分開設定?
因為兩者是不同層次的網路需求。在 Docker 引擎端配置的 proxy,只負責讓 docker host 透過 proxy 存取遠端 registry(例如 docker pull),無法直接套用到 image 建置與 container 運行上。
當你在 build image 時需要透過 proxy 下載套件(例如 apk update、yum install、npm install),必須在 Dockerfile 中另外針對所使用的 base image 配置環境變數。以 Alpine 為 base image 為例:
FROM alpine:3.8
ENV HTTPS_PROXY https://192.168.1.34:3128/
RUN apk update && apk add curl
若 proxy 需帳號密碼,Alpine 需額外加 ENV HTTPS_PROXY_AUTH basic:*:username:password。若 base image 是 Ubuntu 或 CentOS,直接用 ENV 指令設定一般作業系統的環境變數即可。
在 Dockerfile 中用 ENV 和 ARG 設定 proxy 有什麼差別?
關鍵差別在於設定的生效期間。
ENV:在 image 建置時期(build-time)與 container 運行時期(run-time)都有效——建置時會用該 proxy 更新軟體清單與安裝套件,且在 container 存活期間,其內部的 process 依舊能使用這個 proxy 設定。命令行下的 docker run --env 有相同效果。
ARG:只在 image 建置時期有效,建置完成後設定就失效,container 運行時期無法使用這個參數。命令行下的 docker build --build-arg 也是同樣結果。
因此若希望 container 執行期間也能走 proxy,應使用 ENV 而非 ARG。
為什麼在 Dockerfile 設了 proxy 環境變數,container 內的 npm 還是連不上網?
大部分情況下,只要根據 base image 的作業系統類型設定好 HTTPS_PROXY 環境變數就能使用 proxy,但少數應用程式需要額外設定。Node.js 的套件管理器 npm 就是典型例子——它不會只依賴系統環境變數,必須明確設定自己的 proxy config:
RUN npm config set proxy https://192.168.1.34:3128/ && npm install
這會先把 npm 的 proxy 設定寫入 npm config,再執行安裝。遇到其他類似「已設環境變數卻仍連不上」的工具時,通常都是因為該工具有自己獨立的 proxy 設定需要另外指定。
留言
張貼留言