跳至主要内容

Docker 代理:让容器在企业防火墙后正常工作的完整指南

学习如何在各层设置代理配置,使您的 Docker 操作在企业防火墙后依然稳定可靠。
· 15分钟 阅读

使用 AI 探索

大多数企业网络都会使用代理服务器来监控和过滤互联网流量。这会在 Docker 尝试从镜像仓库拉取镜像时制造障碍。您会遇到连接超时、身份验证错误,以及在家中网络本可正常运行的构建失败。这些与代理相关的问题会让无法获取基础镜像的开发团队陷入停滞。

配置 Docker 代理可以在满足企业安全要求的同时,通过缓存提升性能,并解决连接问题。完成配置后,无论网络限制如何,容器都能顺利拉取镜像。

本教程将带您依次完成 Docker 守护进程代理设置、容器环境变量配置,以及在 Docker Compose 中处理代理配置。

刚接触 Docker,被各种网络概念弄得有些不知所措?请先从Docker 基础开始,循序渐进建立信心。

理解 Docker 代理架构

Docker 生态中的不同部分需要在不同层面进行代理配置。

代理充当 Docker 组件与外部网络之间的中间人。 当 Docker 需要拉取镜像、容器需要访问互联网,或构建需要外部资源时,代理服务器会控制并监控这些连接。它们位于容器化应用与外部世界之间,过滤请求与响应。

组织在 Docker 中使用代理是出于性能、安全与合规的考虑。

性能收益来自对常用资源(如基础镜像)的缓存,从而缩短团队整体的下载时间。安全收益包括流量过滤、恶意软件扫描,以及阻止访问未授权站点。合规要求则规定所有网络流量必须通过受监控的通道,并具备适当的访问控制与审计跟踪。

Docker 代理配置分为四个层面:

  • 客户端代理: 影响 docker pull、docker push 等 Docker CLI 命令

  • 守护进程代理: 控制 Docker 守护进程如何访问外部镜像仓库  

  • 容器运行时代理: 为容器内的应用设置代理变量

  • 构建时代理: 在 docker build 期间处理 Dockerfile 访问互联网时的代理设置

每一层都有其作用,并需要各自的配置方法。

理解 Docker 网络从掌握容器如何通信开始。 

将 Docker 配置为使用代理

要让 Docker 在企业代理下正常工作,您需要同时配置 Docker 守护进程和客户端。

原因在于它们处理的是不同类型的网络请求。 

守护进程负责镜像拉取、推送以及仓库认证,而客户端则负责 CLI 操作与 API 调用。缺少任意一侧的配置,都会留下空档,导致 Docker 操作因连接错误而失败。

如何配置 Docker 守护进程

Docker 守护进程从 /etc/docker/daemon.json 读取代理设置。若该文件不存在,请创建:

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

noProxy 字段用于列出应绕过代理的地址。请将您的内部镜像仓库域名与本地主机地址加入其中。

设置 systemd 服务覆盖

在基于 systemd 的 Linux 系统上,您还需要为 Docker 服务本身配置代理。创建覆盖目录与配置文件:

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

然后,将如下环境变量添加到 http-proxy.conf 文件:

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

这可确保 Docker 守护进程本身能够通过您的代理访问外部服务。

Docker 在您重启守护进程之前不会应用代理变更。运行以下命令以重新加载 systemd 并重启 Docker:

sudo systemctl daemon-reload
sudo systemctl restart docker

重新加载会让 systemd 读取新的服务配置,而重启 Docker 则会应用 daemon.json 的更改。

平台特定注意事项

Docker Desktop 的代理配置与服务器安装方式不同。在 Windows 与 macOS 上,请使用 Docker Desktop 的图形界面于 Resources - Proxies 中设置代理。这些设置会自动配置守护进程与客户端。

使用 Docker Engine 的 Linux 主机需要按上述方法进行手动配置。不同发行版对 Docker 的打包方式不一,请检查您的系统是直接使用 dockerd,还是通过其他服务管理器。

验证配置

使用一个简单的拉取命令测试 Docker 是否能访问外部仓库:

docker pull hello-world

您也可以检查守护进程的有效配置:

docker system info | grep -i proxy

这将显示 Docker 是否检测并应用了您的代理设置。

如果拉取仍然失败,请检查代理服务器日志,确认 Docker 是否正确路由了请求。

被网络问题卡住了?正确暴露 Docker 端口,避免连接性难题。

设置代理环境变量

Docker CLI 命令需要独立于守护进程设置之外的代理配置。使用环境变量可以灵活控制 Docker 客户端如何通过企业代理进行连接。

客户端代理会控制 docker pull、docker push、docker login 等 CLI 操作。当您运行这些命令时,Docker 客户端会向镜像仓库发出 HTTP 请求,并需要知道该使用哪台代理服务器。若没有客户端代理设置,即使守护进程已正确配置,这些操作仍会失败。

JSON 配置方法

最干净利落的方法是使用 ~/.docker/config.json 中的 Docker 配置文件:

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

该方法将代理设置限定在 Docker 配置中,不会影响系统上的其他应用。

环境变量替代方案

您也可以设置标准的代理环境变量,Docker 会自动检测:

export HTTP_PROXY=http://proxy.company.com:8080
export HTTPS_PROXY=http://proxy.company.com:8080
export NO_PROXY=localhost,127.0.0.1,.company.com

这些变量适用于任何遵循代理标准的应用,不仅仅是 Docker。

全局与按用户配置

若需系统范围的配置,可将环境变量添加到 /etc/environment,或在 /etc/profile.d/ 中创建脚本:

# /etc/profile.d/proxy.sh
export HTTP_PROXY=http://proxy.company.com:8080
export HTTPS_PROXY=http://proxy.company.com:8080
export NO_PROXY=localhost,127.0.0.1,.company.com

若需按用户配置,可将其添加到您的 Shell 配置文件(~/.bashrc、~/.zshrc),或使用 JSON 配置方法。按用户设置可让开发者灵活使用不同代理,或为测试目的完全绕过代理。

安全注意事项

切勿在配置文件或环境变量中硬编码用户名和密码。 

以明文形式存放代理凭据会带来安全风险,尤其是在共享环境或版本控制系统中。

相应地,请采用以下做法:

  • 在可能的情况下,将代理服务器配置为基于 IP 的认证
  • 使用凭据助手或安全存储系统进行认证
  • 为 Docker 操作设置权限最小化的服务账号

如确需包含凭据,请使用 http://username:[email protected]:8080 这种格式,但务必将其保存在权限受限的受保护文件中。

构建时代理配置

Docker 构建需要通过构建参数显式传入代理设置:

docker build \
  --build-arg HTTP_PROXY=http://proxy.company.com:8080 \
  --build-arg HTTPS_PROXY=http://proxy.company.com:8080 \
  --build-arg NO_PROXY=localhost,127.0.0.1 \
  -t myapp .

构建参数会在构建上下文中成为环境变量。

这使得 RUN 指令可以通过您的代理下载软件包和依赖项。若缺少这些参数,当 Dockerfile 试图从互联网安装软件或获取资源时,构建会失败。

构建时的代理设置不会在最终镜像中保留,除非您在 Dockerfile 中使用 ENV 显式设置。

通过环境变量,您可以在适合的层级灵活处理代理设置,从而契合您的工作流。

对构建参数仍感到困惑?通过实际可用的示例来掌握 Docker 构建参数。

容器与构建时的代理注入

仅配置 Docker 客户端还不够——您的容器与构建需要各自的代理设置。本节将演示如何在运行时与构建时注入代理配置。

运行时环境变量

容器不会继承宿主机的代理设置。

您需要在启动容器时显式传入代理变量。Docker 提供了多种方式,取决于您希望配置所有容器还是特定容器。

如前所述,JSON 配置是获得一致代理设置的最干净方法。回顾一下,将此添加到 ~/.docker/config.json:

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

Docker 会自动将这些变量注入到您启动的每个容器中,无需额外参数。

CLI 标志可让您对每个容器进行更细粒度的控制:

docker run \
  --env HTTP_PROXY=http://proxy.company.com:8080 \
  --env HTTPS_PROXY=http://proxy.company.com:8080 \
  --env NO_PROXY=localhost,127.0.0.1 \
  nginx

您也可以传入整份环境变量文件:

# proxy.env
HTTP_PROXY=http://proxy.company.com:8080
HTTPS_PROXY=http://proxy.company.com:8080
NO_PROXY=localhost,127.0.0.1

docker run --env-file proxy.env nginx

对于已在运行的容器,可使用 docker exec 在启动后注入代理变量:

docker exec -e HTTP_PROXY=http://proxy.company.com:8080 container_name curl google.com

该方式适用于一次性命令,但在容器重启后不会保留。

构建时代理配置

在代理环境中,若未显式传入代理设置,镜像构建会失败。

构建参数是构建过程中注入代理变量的标准方法:

docker build \
  --build-arg HTTP_PROXY=http://proxy.company.com:8080 \
  --build-arg HTTPS_PROXY=http://proxy.company.com:8080 \
  --build-arg NO_PROXY=localhost,127.0.0.1 \
  --tag myapp .

您的 Dockerfile 需要声明这些参数以便使用:

ARG HTTP_PROXY
ARG HTTPS_PROXY
ARG NO_PROXY

# Use proxy for package installation
RUN apt-get update && apt-get install -y curl

# Don't persist proxy in final image

Dockerfile 声明允许您设置默认代理值:

ARG HTTP_PROXY=http://proxy.company.com:8080
ARG HTTPS_PROXY=http://proxy.company.com:8080

ENV HTTP_PROXY=$HTTP_PROXY
ENV HTTPS_PROXY=$HTTPS_PROXY

RUN pip install requests

ENV 指令会让代理变量在构建过程中对所有后续的 RUN 命令可用。

请注意,BuildKit 的某些限制可能会在较新的 Docker 版本中引发代理问题。BuildKit 会积极缓存构建上下文,有时会忽略代理变更。

您可以强制 BuildKit 识别代理更新:

DOCKER_BUILDKIT=1 docker build \
  --no-cache \
  --build-arg HTTP_PROXY=$HTTP_PROXY \
  --tag myapp .

或者,在对代理敏感的构建中完全禁用 BuildKit:

DOCKER_BUILDKIT=0 docker build --build-arg HTTP_PROXY=$HTTP_PROXY --tag myapp .

对于多阶段构建,需在所有阶段保持一致的代理配置:

ARG HTTP_PROXY
ARG HTTPS_PROXY
ARG NO_PROXY

# Build stage
FROM python:3.13 AS builder
ENV HTTP_PROXY=$HTTP_PROXY
ENV HTTPS_PROXY=$HTTPS_PROXY
ENV NO_PROXY=$NO_PROXY

COPY requirements.txt .
RUN pip install -r requirements.txt

# Runtime stage
FROM python:3.13-slim AS runtime
ENV HTTP_PROXY=$HTTP_PROXY
ENV HTTPS_PROXY=$HTTPS_PROXY
ENV NO_PROXY=$NO_PROXY

COPY --from=builder /usr/local/lib/python*/site-packages /usr/local/lib/python*/site-packages
RUN apt-get update && apt-get install -y curl

# Clear proxy variables for final image
ENV HTTP_PROXY=
ENV HTTPS_PROXY=
ENV NO_PROXY=

每个阶段都会继承构建参数,但不会从前一阶段继承环境变量。请在每个需要的阶段显式设置代理变量。

简而言之——一次配置,到处注入。

对启用代理的容器中 ENTRYPOINT 与 CMD 的区别感到困惑?查看包含实操示例的完整解析。

在容器中配置包管理器使用代理

Docker 的代理设置不会自动传递给容器内的包管理器。您需要分别配置每个包管理器,使其能够通过企业代理下载软件包。

apt-get、yum 和 apk 等包管理器会直接向软件源发起 HTTP 连接。在受限网络环境中,除非包管理器知晓您的代理服务器,否则这些连接会失败。

标准环境变量还不够。大多数包管理器都有自己的配置文件,会覆盖系统范围的代理设置。

Ubuntu/Debian:apt-get 配置

创建一个代理配置文件,供 apt-get 在安装软件包时读取。

将以下内容添加到您的 Dockerfile:

FROM python:3.13

# Configure apt proxy
RUN echo 'Acquire::http::Proxy "http://proxy.company.com:8080";' > /etc/apt/apt.conf.d/proxy.conf && \
    echo 'Acquire::https::Proxy "http://proxy.company.com:8080";' >> /etc/apt/apt.conf.d/proxy.conf

RUN apt-get update && apt-get install -y curl wget

/etc/apt/apt.conf.d/proxy.conf 文件会指示 apt-get 将所有软件包下载通过代理进行路由。该文件会在构建过程中的多个 RUN 命令之间保留。

您也可以为内部源设置代理排除:

RUN echo 'Acquire::http::Proxy::internal.company.com "DIRECT";' >> /etc/apt/apt.conf.d/proxy.conf

Alpine Linux:apk 配置

Alpine 使用 apk 包管理器,它会从 /etc/apk/repositories 与环境变量读取代理设置。

FROM python:3.13-alpine

# Configure apk proxy
ENV HTTP_PROXY=http://proxy.company.com:8080
ENV HTTPS_PROXY=http://proxy.company.com:8080

RUN apk add --no-cache curl wget

Alpine 的 apk 遵循标准 HTTP 代理环境变量,因此无需单独的配置文件。但若需更细致控制,也可创建:

RUN echo 'http_proxy=http://proxy.company.com:8080' > /etc/environment && \
    echo 'https_proxy=http://proxy.company.com:8080' >> /etc/environment

CentOS/RHEL:yum 配置

CentOS 与 RHEL 系统使用 yum 或 dnf,它们会从 /etc/yum.conf 读取代理设置。

FROM centos:8

# Configure yum proxy
RUN echo 'proxy=http://proxy.company.com:8080' >> /etc/yum.conf

RUN yum update -y && yum install -y curl wget

对于使用 dnf 的新版本 CentOS,请使用如下配置:

FROM centos:stream9

# Configure dnf proxy
RUN echo 'proxy=http://proxy.company.com:8080' >> /etc/dnf/dnf.conf

RUN dnf update -y && dnf install -y curl wget

您还可以通过添加以下命令来排除特定域名不经由代理:

RUN echo 'proxy_exclude=internal.company.com,localhost' >> /etc/yum.conf

测试代理功能

首先,您需要验证包管理器能否通过代理访问软件源。

将测试命令加入您的 Dockerfile:

FROM python:3.13

# Configure proxy
RUN echo 'Acquire::http::Proxy "http://proxy.company.com:8080";' > /etc/apt/apt.conf.d/proxy.conf

# Test package manager connectivity
RUN apt-get update && \
    apt-get install -y --dry-run curl && \
    echo "Package manager proxy test passed"

# Install actual packages
RUN apt-get install -y curl python3-pip

--dry-run 标志会在不实际安装的情况下测试软件包解析。若成功,则说明代理配置有效。

您也可以使用更详细的输出进行调试:

RUN apt-get -o Debug::Acquire::http=true update

这将准确显示 apt-get 试图访问的 URL,以及代理连接是否成功。

对于 Alpine 的测试,请使用:

RUN apk update --verbose && \
    apk add --simulate curl && \
    echo "Alpine proxy test passed"

总之,请分别配置每个包管理器,您的构建就能在任何代理后面正常工作。

需要清理代理相关的构建产物?Docker prune 命令 可释放空间并保持系统整洁。

高级代理实现

基础的 HTTP 代理足以入门,但生产环境需要对仓库访问与镜像缓存进行更细致的控制。以下是如何设置缓存代理与仓库镜像,以提升性能与可靠性。

缓存代理仓库

反复拉取相同的基础镜像会浪费带宽并拖慢构建。

缓存代理位于 Docker 客户端与 Docker Hub 等外部仓库之间。它们会将经常访问的镜像本地缓存,使后续拉取直接来自内部网络,而非互联网。

企业环境中最流行的选择是 Harbor:

# docker-compose.yml for Harbor
version: '3.8'
services:
  harbor-core:
    image: goharbor/harbor-core:v2.8.0
    environment:
      - CORE_SECRET=your-secret-key
      - JOBSERVICE_SECRET=your-job-secret
    ports:
      - "80:8080"
    volumes:
      - ./harbor.yml:/etc/core/app.conf

通过编辑 harbor.yml,您可以将 Harbor 配置为代理缓存:

# harbor.yml
hostname: harbor.company.com
http:
  port: 80

database:
  password: harbor-db-password

data_volume: /data

proxy_cache:
  - endpoint: https://registry-1.docker.io
    username: your-dockerhub-username
    password: your-dockerhub-token

如果您需要更简单的基础缓存方案,可以使用 Docker Registry Proxy。具体如下:

docker run -d \
  --name registry-proxy \
  -p 5000:5000 \
  -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \
  -v registry-cache:/var/lib/registry \
  registry:2

然后,将 Docker 客户端指向该缓存代理:

{
  "registry-mirrors": ["http://harbor.company.com"]
}

使用缓存代理,您将获得以下收益:

  • 首次下载后镜像拉取更快
  • 减少互联网带宽消耗
  • 当外部仓库出现问题时,构建更具可靠性
  • 集中化的访问控制与镜像扫描

仓库镜像与 BuildKit

仓库镜像可将镜像拉取重定向至内部或地理位置更近的仓库。

单镜像配置会将所有 Docker Hub 请求路由到一个镜像站:

{
  "registry-mirrors": ["https://mirror.company.com"],
  "insecure-registries": ["harbor.company.com:5000"]
}

将其添加到 /etc/docker/daemon.json 并重启 Docker。所有 docker pull 命令将优先尝试镜像站,若镜像站不可用再回退至 Docker Hub。

多镜像提供冗余:

{
  "registry-mirrors": [
    "https://mirror1.company.com",
    "https://mirror2.company.com",
    "https://registry-1.docker.io"
  ]
}

Docker 将按顺序尝试镜像站,直到成功为止。

BuildKit 的镜像站设置需要单独配置,因为 BuildKit 会绕过部分守护进程设置:

# buildkitd.toml
debug = true

[registry."docker.io"]
  mirrors = ["mirror.company.com"]

[registry."mirror.company.com"]
  http = true
  insecure = true

您可以使用自定义配置启动 BuildKit:

buildkitd --config=/etc/buildkit/buildkitd.toml

或使用 BuildKit 的内联镜像站配置:

docker buildx create \
  --name mybuilder \
  --config /etc/buildkit/buildkitd.toml \
  --use

最后,通过构建一个会从 Docker Hub 拉取的镜像来测试镜像站设置:

FROM python:3.13-slim
RUN pip install requests
docker build --progress=plain .

--progress=plain 标志会显示 BuildKit 实际联系的是哪个仓库。您应当能在构建输出中看到镜像站的 URL。

就这些!

在管理复杂的多容器代理设置吗?Docker Compose 可简化网络与服务发现。

安全加固

代理配置会带来新的攻击面,需要仔细关注。以下是如何锁定 Docker 套接字访问,并保护代理凭据不被泄露。

Docker 套接字代理

直接暴露 Docker 套接字会带来巨大的安全风险。

Docker 套接字(/var/run/docker.sock)能为整个宿主系统提供 root 级别的访问。任何能写入该套接字的进程都可以启动具有宿主文件系统访问的容器、提升权限,甚至完全突破容器隔离。

直接挂载套接字是危险的:

# DON'T DO THIS
docker run -v /var/run/docker.sock:/var/run/docker.sock myapp

这种模式常见于 Docker-in-Docker 场景与 CI/CD 流水线,但安全隐患巨大。一旦容器被攻陷,整个 Docker 守护进程都可能被控制。

套接字代理服务能创建更安全的中间层。它们会过滤 Docker API 调用,并限制容器的实际操作范围。

使用 Tecnativa 的 docker-socket-proxy:

# docker-compose.yml
version: '3.8'
services:
  docker-proxy:
    image: tecnativa/docker-socket-proxy
    environment:
      - CONTAINERS=1
      - IMAGES=1
      - NETWORKS=1
      - VOLUMES=1
      - BUILD=0
      - COMMIT=0
      - CONFIGS=0
      - SECRETS=0
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    ports:
      - "2375:2375"

该代理仅暴露特定的 Docker API 端点。将环境变量设为 1 表示允许的操作,0 表示阻止。

您的应用应连接到代理,而不是原始套接字:

docker run --env DOCKER_HOST=tcp://docker-proxy:2375 myapp

以下是一些额外的套接字加固建议:

  • 将套接字代理运行在独立的网络分段上
  • 在客户端与代理之间使用 TLS 认证
  • 监控套接字代理日志,识别可疑的 API 调用
  • 定期轮换代理访问凭据

凭据管理

以明文形式出现在 URL 中的代理凭据会无处不在——日志、进程列表、环境转储。

切勿在代理 URL 中嵌入凭据:

# SECURITY RISK - credentials visible in process list
export HTTP_PROXY=http://admin:[email protected]:8080

任何能访问 ps aux 或环境变量转储的人都能看到您的代理密码。这包括应用日志、容器检查与系统监控工具。

相反,使用认证文件:

# Create credentials file with restricted permissions
echo "admin:password123" > ~/.proxy-creds
chmod 600 ~/.proxy-creds

# Configure proxy without embedded credentials
export HTTP_PROXY=http://proxy.company.com:8080

将您的代理服务器配置为从文件读取凭据,或使用外部认证系统。

TLS 代理会加密所有代理流量,包括认证握手:

# HTTPS proxy encrypts credentials in transit
export HTTPS_PROXY=https://proxy.company.com:8443

为您的代理服务器配置合适的 TLS 证书——可使用 CA 签发的证书,或将自签名证书分发到客户端机器。

基于证书的认证可完全消除密码:

# Client certificate authentication
export HTTPS_PROXY=https://proxy.company.com:8443
curl --cert client.crt --key client.key --cacert proxy-ca.crt https://example.com

代理会验证客户端证书,而非用户名/密码组合。若证书泄露,可单独吊销。

Kubernetes 的 Secret 管理可将代理凭据排除在容器镜像之外:

apiVersion: v1
kind: Secret
metadata:
  name: proxy-credentials
type: Opaque
data:
  username: YWRtaW4=  # base64 encoded
  password: cGFzc3dvcmQxMjM=  # base64 encoded
apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
      - name: myapp
        env:
        - name: PROXY_USER
          valueFrom:
            secretKeyRef:
              name: proxy-credentials
              key: username
        - name: PROXY_PASS
          valueFrom:
            secretKeyRef:
              name: proxy-credentials
              key: password

Secrets 会以加密形式静态存储,并在运行时注入,不会出现在镜像层中。

锁定套接字访问、加密您的凭据——未来的您会感谢现在的自己。

在为代理方案考虑 Docker 的替代品?请对比 Docker 与 Podman,选择合适的容器化工具。

常见问题排查

代理问题通常表现为超时、连接失败,以及在企业网络外运行良好的神秘构建错误。以下是系统化诊断并修复最常见 Docker 代理问题的方法。

结构化诊断步骤

从基础入手,逐层向上排查。

步骤 1:验证宿主机到代理的连通性

测试您的代理服务器是否可达:

curl -x http://proxy.company.com:8080 https://registry-1.docker.io/v2/

如果失败,说明您的代理配置或网络路由存在问题。在排查 Docker 之前,请联系网络团队。

步骤 2:检查 Docker 守护进程的代理设置

验证守护进程是否读取了您的代理配置:

docker info | grep -i proxy

您应当能看到代理 URL。如缺失,请检查 /etc/docker/daemon.json 并重启 Docker 服务。

步骤 3:测试 Docker 客户端操作

尝试拉取一个简单镜像:

docker pull hello-world

若成功,说明您的客户端代理设置有效。若失败,问题更可能出在守护进程层面的代理。

步骤 4:测试容器层的连通性

运行一个容器并测试外联:

docker run --rm \
  -e HTTP_PROXY=http://proxy.company.com:8080 \
  -e HTTPS_PROXY=http://proxy.company.com:8080 \
  python:3.13-slim \
  python -c "import urllib.request; print(urllib.request.urlopen('https://pypi.org').getcode())"

这能帮助您判断问题是在 Docker 操作层面还是容器网络层面。

常见问题与解决方案

问题:docker pull 超时

当 Docker 无法访问外部仓库时,会看到如下错误:

Error response from daemon: Get "https://registry-1.docker.io/v2/": dial tcp: lookup registry-1.docker.io: no such host

请从基础连通性测试开始,定位问题发生位置:

# Check if DNS resolution works through proxy
nslookup registry-1.docker.io

# Test direct registry access
curl -I https://registry-1.docker.io/v2/

# Verify daemon proxy configuration
sudo journalctl -u docker.service | grep -i proxy

通过以下方式修复 DNS 与代理配置问题:

  • 在 /etc/docker/daemon.json 中添加 DNS 服务器

  • 为内部 DNS 服务器配置 NO_PROXY

  • 检查代理是否支持 HTTPS CONNECT 方法

问题:构建期间软件包安装失败

容器内的包管理器无法访问软件源,会出现类似错误:

E: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/jammy/Release

在临时容器内直接测试包管理器连通性:

# Test package manager connectivity in a running container
docker run -it --rm python:3.13 bash
apt-get update -o Debug::Acquire::http=true

详细输出会准确显示连接失败的位置。

通过以下方法解决:为包管理器配置代理:

  • 在 Dockerfile 中配置包管理器代理设置
  • 在 Docker 构建时传入代理构建参数
  • 检查代理是否阻止了软件源域名

问题:BuildKit 忽略代理设置

BuildKit 的代理处理与旧版构建器不同,可能导致如下错误:

failed to solve: failed to fetch remote https://github.com/user/repo.git

检查构建器配置,判断是否为 BuildKit 特有问题:

# Check BuildKit configuration
docker buildx inspect

# Build with legacy builder
DOCKER_BUILDKIT=0 docker build .

如果旧版构建器可行,则说明您遇到的是 BuildKit 代理配置问题。

通过以下方法修复 BuildKit 代理问题:

  • 在 buildkitd.toml 中配置 BuildKit 专用代理设置
  • 使用 --build-arg 显式传入代理变量
  • 对于对代理敏感的构建,禁用 BuildKit

问题:容器无法访问外部服务

容器内的应用无法连接到外部 API:

requests.exceptions.ConnectionError: HTTPSConnectionPool(host='api.example.com', port=443)

通过在容器内测试连通性进行调试:

# Test from inside the container
docker exec container_name curl -v https://api.example.com

# Check container environment variables
docker exec container_name env | grep -i proxy

这将显示代理变量是否存在,以及连接尝试是否成功。

通过以下方式确保正确的代理配置,从而解决容器连通性问题:

  • 在运行时传入代理环境变量
  • 配置应用程序专用的代理设置
  • 将目标地址加入 NO_PROXY 列表

日志分析与连通性测试

Docker 守护进程日志 能完整呈现代理协商与失败的过程。

在基于 systemd 的系统上,使用 journalctl 实时查看 Docker 服务日志:

# SystemD systems
sudo journalctl -u docker.service -f

对于使用传统日志文件的系统,请直接查看 Docker 日志:

# Direct log file
sudo tail -f /var/log/docker.log

在日志中查找特定的代理相关信息。若出现“连接被拒绝”,说明代理服务器不可达。身份验证失败会以 "407 Proxy Authentication Required" 的信息出现。超时错误则可能暗示网络路由问题或代理服务器过载。

容器层测试 通过 curl 和 wget 可为您提供关于代理行为的详细洞察。

测试通过代理进行的 HTTP 连接,查看握手期间的实际情况:

# Test HTTP proxy
docker run --rm \
  -e HTTP_PROXY=http://proxy.company.com:8080 \
  python:3.13-slim \
  curl -v http://httpbin.org/ip

详细输出会显示 DNS 解析、代理连接建立以及实际的 HTTP 请求流程。若代理隧道正常,您会看到类似“Connected to proxy.company.com”,随后是“CONNECT httpbin.org:80”的信息。

HTTPS 连接要求代理支持 CONNECT 方法:

# Test HTTPS proxy
docker run --rm \
  -e HTTPS_PROXY=http://proxy.company.com:8080 \
  python:3.13-slim \
  curl -v https://httpbin.org/ip

请留意输出中的“CONNECT httpbin.org:443 HTTP/1.1”。如果看到“Method not allowed”等错误,说明您的代理不支持 HTTPS 隧道。

通过在代理 URL 中嵌入凭据来测试认证:

# Test with authentication
docker run --rm \
  -e HTTPS_PROXY=http://user:[email protected]:8080 \
  python:3.13-slim \
  wget -O- https://httpbin.org/ip

认证失败会显示为 "407 Proxy Authentication Required"。若认证成功,将直接进入目标请求流程。

网络层调试 使用 tcpdump 可捕获 Docker 与代理服务器之间的实际数据包。

运行 tcpdump 以查看流向代理的所有流量:

# Capture proxy traffic
sudo tcpdump -i any host proxy.company.com and port 8080

原始数据包捕获会显示连接尝试、数据传输与连接终止。请查看 TCP 连接建立(SYN/ACK 包)以及后续的 HTTP 流量。连接超时常表现为重复的 SYN 包无响应。

DNS 解析测试 可消除一类常见的代理困惑。

许多代理问题其实伪装成 DNS 问题。在容器内测试 DNS 解析:

# Test DNS inside containers  
docker run --rm python:3.13-slim nslookup registry-1.docker.io

若失败,说明容器完全无法解析域名。可尝试使用公共 DNS 来定位问题:

# Test with custom DNS
docker run --dns 8.8.8.8 --rm python:3.13-slim nslookup registry-1.docker.io

企业环境通常配有仅在内网可用的 DNS 服务器。您的代理可能需要同时处理 DNS 请求与 HTTP 流量,或者您需要为容器配置能在代理下工作的特定 DNS 服务器。

逐层系统化排查,您就能找到根本原因。

想寻找对代理处理可能有所不同的选项吗?我们提供了一份Docker 替代方案指南,助您在 2025 年全面了解容器化工具版图。

结语

Docker 代理配置不仅是为了让镜像能够下载——更是为了在企业环境中构建可靠且安全的容器化应用。

本文展示了如何在四个不同层面配置代理:客户端操作、守护进程、容器运行时与构建时。每一层都有其特定目标,并需要对应的配置方法,涵盖从 JSON 文件、环境变量到包管理器设置与 BuildKit 配置。分层式的代理策略可以避免单点故障。

想更深入了解 Docker、容器化与安全?请查看我们精选的课程列表:

Dario Radečić

作者

Dario Radečić

常驻克罗地亚的高级数据科学家。顶级科技写作者,已发表 700 多篇文章,累计获得超过 1,000 万次阅读。著有《使用 TPOT 实现机器学习自动化》。

FAQs

为什么 Docker 需要配置代理?

企业网络会使用代理服务器监控与过滤互联网流量,这会阻断 Docker 与 Docker Hub 等仓库的直接连接。若未正确配置代理,您在拉取镜像时会遇到连接超时,安装软件包时构建失败,容器也可能无法访问外部服务。Docker 代理设置会将所有这些连接经由企业代理服务器进行路由,使其在防火墙后顺畅运行。

Docker 守护进程代理与客户端代理设置有什么区别?

Docker 守护进程负责如向仓库拉取与推送镜像等操作,而 Docker 客户端管理 CLI 命令与 API 调用。它们需要分别进行代理配置,因为发起的网络请求类型不同。缺失任一方的配置都会造成空缺,导致某些 Docker 操作正常、而另一些因连接错误而失败。

容器会自动继承宿主机的代理设置吗?

不会,容器默认不会继承宿主机的代理设置。您需要在启动容器时通过 --env 标志、环境文件或 JSON 配置显式传入代理环境变量。这种隔离意味您可以让不同容器使用不同的代理设置,或为特定应用完全绕过代理。

为什么镜像拉取没问题,但我的 Docker 构建仍然失败?

Docker 构建需要以构建参数的形式传入代理设置,因为构建流程与客户端配置相互隔离。请在运行 docker build 时使用 --build-arg HTTP_PROXY=...,并在 Dockerfile 中通过 ARG 指令声明这些参数。容器内的包管理器也需要各自的代理配置文件来下载依赖项。

如何排查只在 BuildKit 下出现、而旧版构建器没有的代理问题?

BuildKit 的代理处理方式不同,并且会积极缓存构建上下文,有时会忽略代理变更。可尝试使用 --no-cache 强制重新检测代理,或设置 DOCKER_BUILDKIT=0 完全禁用 BuildKit。若问题仍在,请在 /etc/buildkit/buildkitd.toml 中配置 BuildKit 专用的代理与仓库镜像设置。

主题