在自动化部署和测试过程中,通常需要在 CI/CD 流程中使用代理服务器。这可能与企业安全政策、地理位置功能的测试或在下载依赖项时绕过速率限制有关。在本指南中,我们将探讨如何为流行的 CI/CD 平台设置代理,并提供现成的配置示例。
为什么在 CI/CD 流程中需要代理
在自动化部署过程中使用代理服务器可以解决几个关键问题。首先,许多企业网络要求所有出站流量通过企业代理进行安全控制和日志记录。如果没有正确配置,CI/CD 管道将无法下载依赖项或连接到外部服务。
其次,在测试具有地理位置逻辑的应用程序时,需要从不同国家检查其工作情况。例如,如果您正在开发一个具有区域内容或定价的服务,自动化测试必须模拟来自不同位置的用户。在这里,住宅代理 提供来自所需地区的 IP 地址。
第三个原因是绕过速率限制和封锁。在频繁运行管道时,尤其是在大型团队中,CI/CD 服务器可能会受到外部服务 API 的限制。例如,GitHub API 或包注册表在超过请求限制时可能会暂时阻止 IP。代理轮换有助于分散负载。
重要: 对于 CI/CD 流程,连接的稳定性至关重要。使用正常运行时间不低于 99.5% 且响应时间快(少于 200 毫秒)的代理。不稳定的代理会导致构建意外失败,并浪费团队的时间进行调查。
在 GitHub Actions 中设置代理
GitHub Actions 是最流行的 CI/CD 平台之一。这里的代理设置通过环境变量完成,可以在工作流或整个组织的级别上设置。我们将探讨几种集成方法。
通过环境变量进行基本设置
最简单的方法是在作业开始时设置 HTTP_PROXY 和 HTTPS_PROXY 环境变量。大多数工具(curl、wget、npm、pip)会自动使用这些变量:
name: CI with Proxy
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
env:
HTTP_PROXY: http://proxy.example.com:8080
HTTPS_PROXY: http://proxy.example.com:8080
NO_PROXY: localhost,127.0.0.1,.internal.domain
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test
NO_PROXY 变量至关重要——它将本地地址和内部服务排除在代理之外。如果没有它,可能会出现连接到 localhost 或内部 Docker 容器的问题。
通过 GitHub Secrets 安全存储凭据
如果代理需要身份验证,请不要在工作流文件中以明文形式存储用户名和密码。请使用 GitHub Secrets:
name: CI with Authenticated Proxy
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Configure Proxy
run: |
echo "HTTP_PROXY=http://${{ secrets.PROXY_USER }}:${{ secrets.PROXY_PASS }}@${{ secrets.PROXY_HOST }}:${{ secrets.PROXY_PORT }}" >> $GITHUB_ENV
echo "HTTPS_PROXY=http://${{ secrets.PROXY_USER }}:${{ secrets.PROXY_PASS }}@${{ secrets.PROXY_HOST }}:${{ secrets.PROXY_PORT }}" >> $GITHUB_ENV
echo "NO_PROXY=localhost,127.0.0.1" >> $GITHUB_ENV
- name: Test proxy connection
run: curl -I https://api.github.com
- name: Install dependencies
run: npm ci
在存储库设置中创建 secrets:Settings → Secrets and variables → Actions → New repository secret。添加 PROXY_USER、PROXY_PASS、PROXY_HOST 和 PROXY_PORT。这些值将被加密,并且在日志中不可用。
为特定步骤设置代理
有时只需要在特定操作中使用代理,例如仅在下载依赖项时,而不是在部署时。在特定步骤的级别上设置变量:
steps:
- name: Download dependencies via proxy
env:
HTTP_PROXY: http://proxy.example.com:8080
HTTPS_PROXY: http://proxy.example.com:8080
run: npm install
- name: Deploy without proxy
run: ./deploy.sh
与 GitLab CI/CD 集成代理
GitLab CI/CD 提供了多个级别的代理设置:在 runner 级别、项目级别和特定作业级别。选择取决于代理是否需要用于所有项目或仅用于特定项目。
在 GitLab Runner 级别设置代理
如果使用自托管的 GitLab Runner 并且所有项目都必须通过代理工作,请在 runner 的配置中进行设置。编辑文件 /etc/gitlab-runner/config.toml:
[[runners]]
name = "docker-runner"
url = "https://gitlab.com/"
token = "YOUR_TOKEN"
executor = "docker"
[runners.docker]
image = "alpine:latest"
privileged = false
[runners.docker.services_environment]
HTTP_PROXY = "http://proxy.example.com:8080"
HTTPS_PROXY = "http://proxy.example.com:8080"
NO_PROXY = "localhost,127.0.0.1,.gitlab.com"
修改配置后,重启 runner:sudo gitlab-runner restart。现在该 runner 上的所有作业将自动使用代理。
通过 .gitlab-ci.yml 设置代理
要在特定项目级别设置代理,请在 .gitlab-ci.yml 文件中使用变量。这是一种更灵活的方法,允许不同项目使用不同的代理:
variables:
HTTP_PROXY: "http://proxy.example.com:8080"
HTTPS_PROXY: "http://proxy.example.com:8080"
NO_PROXY: "localhost,127.0.0.1,.internal"
stages:
- build
- test
- deploy
build:
stage: build
script:
- echo "Proxy configured: $HTTP_PROXY"
- npm install
- npm run build
artifacts:
paths:
- dist/
test:
stage: test
script:
- npm test
dependencies:
- build
使用 GitLab CI/CD Variables 存储凭据
为了存储敏感数据,请在项目设置中使用 CI/CD Variables:Settings → CI/CD → Variables。创建受保护和掩码变量:
- PROXY_URL — 包含凭据的完整 URL(掩码)
- PROXY_HOST — 代理服务器的主机
- PROXY_PORT — 端口
- PROXY_USER 和 PROXY_PASS — 用于单独存储
然后在 .gitlab-ci.yml 中使用它们:
build:
stage: build
before_script:
- export HTTP_PROXY="http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}"
- export HTTPS_PROXY="http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}"
script:
- npm install
- npm run build
在 Jenkins 中配置代理
Jenkins 提供了多种设置代理的方法,具体取决于架构:Jenkins master 的全局设置、特定代理的设置或单个管道的设置。
Jenkins 的全局代理设置
要设置 Jenkins 用于插件更新和其他内部操作的代理,请转到 Manage Jenkins → Manage Plugins → Advanced。在 HTTP Proxy Configuration 部分中指定:
- Server: proxy.example.com
- Port: 8080
- User name 和 Password(如果需要身份验证)
- No Proxy Host: localhost,127.0.0.1,.internal
此设置仅影响 Jenkins 本身,而不影响作业。作业需要单独配置。
为 Jenkins Pipeline 设置代理
在 Jenkinsfile 中,可以为整个管道或特定阶段设置环境变量:
pipeline {
agent any
environment {
HTTP_PROXY = 'http://proxy.example.com:8080'
HTTPS_PROXY = 'http://proxy.example.com:8080'
NO_PROXY = 'localhost,127.0.0.1,.internal'
}
stages {
stage('Build') {
steps {
sh 'npm install'
sh 'npm run build'
}
}
stage('Test') {
steps {
sh 'npm test'
}
}
}
}
使用 Jenkins Credentials 存储代理凭据
为了安全存储代理凭据,请使用 Jenkins Credentials Store。在 Manage Jenkins → Manage Credentials 中创建类型为“Username with password”的凭据,然后在管道中使用它们:
pipeline {
agent any
stages {
stage('Build with Authenticated Proxy') {
steps {
withCredentials([usernamePassword(
credentialsId: 'proxy-credentials',
usernameVariable: 'PROXY_USER',
passwordVariable: 'PROXY_PASS'
)]) {
sh '''
export HTTP_PROXY="http://${PROXY_USER}:${PROXY_PASS}@proxy.example.com:8080"
export HTTPS_PROXY="http://${PROXY_USER}:${PROXY_PASS}@proxy.example.com:8080"
npm install
'''
}
}
}
}
}
为 Jenkins 代理设置代理
如果使用单独的 Jenkins 代理(节点),请为每个代理单独设置代理。在代理的配置中(Manage Jenkins → Manage Nodes → Configure)添加环境变量:
HTTP_PROXY=http://proxy.example.com:8080
HTTPS_PROXY=http://proxy.example.com:8080
NO_PROXY=localhost,127.0.0.1
CI/CD 中的 Docker 代理
Docker 是现代 CI/CD 流程中不可或缺的一部分。为 Docker 设置代理有其特殊性,因为需要为 Docker daemon 和容器设置代理。
为 Docker daemon 设置代理
为了让 Docker daemon 能够通过代理下载镜像,请创建 systemd drop-in 文件。在 Linux 系统上创建目录和文件:
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo nano /etc/systemd/system/docker.service.d/http-proxy.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,.internal,docker.io"
重新加载配置并重启 Docker:
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl show --property=Environment docker
在构建期间为容器设置代理
如果容器在构建期间需要通过代理访问(例如,安装包),请通过 build args 在 Dockerfile 中传递变量:
FROM node:18-alpine
ARG HTTP_PROXY
ARG HTTPS_PROXY
ARG NO_PROXY
ENV HTTP_PROXY=${HTTP_PROXY}
ENV HTTPS_PROXY=${HTTPS_PROXY}
ENV NO_PROXY=${NO_PROXY}
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
# 在运行时删除代理变量
ENV HTTP_PROXY=
ENV HTTPS_PROXY=
CMD ["npm", "start"]
在 CI/CD 管道中传递 build args:
# GitHub Actions
- name: Build Docker image with proxy
run: |
docker build \
--build-arg HTTP_PROXY=${{ secrets.PROXY_URL }} \
--build-arg HTTPS_PROXY=${{ secrets.PROXY_URL }} \
--build-arg NO_PROXY=localhost,127.0.0.1 \
-t myapp:latest .
# GitLab CI
docker build:
script:
- docker build
--build-arg HTTP_PROXY="${PROXY_URL}"
--build-arg HTTPS_PROXY="${PROXY_URL}"
-t myapp:latest .
使用 Docker Compose 设置代理
在 CI/CD 中使用 Docker Compose 时,通过 docker-compose.yml 中的 environment 设置代理:
version: '3.8'
services:
app:
build:
context: .
args:
- HTTP_PROXY=${HTTP_PROXY}
- HTTPS_PROXY=${HTTPS_PROXY}
environment:
- HTTP_PROXY=${HTTP_PROXY}
- HTTPS_PROXY=${HTTPS_PROXY}
- NO_PROXY=localhost,127.0.0.1
ports:
- "3000:3000"
为包管理器设置代理
包管理器通常需要额外的代理设置,特别是如果使用自己的配置文件。我们将探讨流行包管理器的设置。
NPM 和 Yarn
NPM 可以使用 HTTP_PROXY/HTTPS_PROXY 环境变量,也可以使用自己的配置。要在 CI/CD 中明确设置:
# 在 GitHub Actions 或 GitLab CI 中
- name: Configure npm proxy
run: |
npm config set proxy http://proxy.example.com:8080
npm config set https-proxy http://proxy.example.com:8080
npm config set noproxy "localhost,127.0.0.1"
- name: Install dependencies
run: npm install
# 对于 Yarn
- name: Configure yarn proxy
run: |
yarn config set proxy http://proxy.example.com:8080
yarn config set https-proxy http://proxy.example.com:8080
另一种方法是在项目根目录创建 .npmrc 文件(但不要提交凭据!):
# .npmrc(在 CI 中生成)
proxy=http://proxy.example.com:8080
https-proxy=http://proxy.example.com:8080
noproxy=localhost,127.0.0.1
Python pip 和 Poetry
Pip 使用环境变量,但也可以通过配置进行设置:
# 通过环境变量(推荐用于 CI)
export HTTP_PROXY=http://proxy.example.com:8080
export HTTPS_PROXY=http://proxy.example.com:8080
pip install -r requirements.txt
# 或通过 pip 参数
pip install --proxy http://proxy.example.com:8080 -r requirements.txt
# 对于 Poetry
poetry config http-basic.proxy http://proxy.example.com:8080
poetry install
Maven 和 Gradle
对于 Java 项目,代理设置需要创建配置文件。对于 Maven,在 CI 管道中创建 settings.xml:
- name: Configure Maven proxy
run: |
mkdir -p ~/.m2
cat > ~/.m2/settings.xml << EOF
<settings>
<proxies>
<proxy>
<id>http-proxy</id>
<active>true</active>
<protocol>http</protocol>
<host>proxy.example.com</host>
<port>8080</port>
<nonProxyHosts>localhost|127.0.0.1</nonProxyHosts>
</proxy>
</proxies>
</settings>
EOF
- name: Build with Maven
run: mvn clean install
对于 Gradle,将设置添加到 gradle.properties:
systemProp.http.proxyHost=proxy.example.com
systemProp.http.proxyPort=8080
systemProp.https.proxyHost=proxy.example.com
systemProp.https.proxyPort=8080
systemProp.http.nonProxyHosts=localhost|127.0.0.1
安全存储代理凭据
存储代理凭据是 CI/CD 安全的关键方面。这些数据的泄露可能导致代理的未经授权使用和财务损失。我们将探讨不同平台的最佳实践。
GitHub Actions Secrets
GitHub Actions 提供了三种级别的秘密:repository、environment 和 organization。对于代理凭据,请使用:
- Repository secrets — 仅在一个存储库中需要代理的项目
- Organization secrets — 如果一个代理在组织的所有项目中使用
- Environment secrets — 用于 staging/production 环境中的不同代理
重要的安全规则:
- 永远不要在日志中输出秘密:GitHub 会自动掩盖它们,但最好避免 echo
- 为不同的环境使用不同的凭据
- 定期轮换代理密码(至少每 90 天一次)
- 通过分支保护规则限制对秘密的访问
GitLab CI/CD Variables
GitLab 提供了额外的变量保护选项:
- Protected — 变量仅在受保护的分支(main、production)中可用
- Masked — 值在日志中自动隐藏
- Environment scope — 限制在特定环境中使用
推荐的代理凭据配置:
# Settings → CI/CD → Variables
PROXY_USER: myuser (Protected: Yes, Masked: Yes)
PROXY_PASS: secret123 (Protected: Yes, Masked: Yes)
PROXY_HOST: proxy.example.com (Protected: No, Masked: No)
PROXY_PORT: 8080 (Protected: No, Masked: No)
Jenkins Credentials Store
Jenkins Credentials Store 支持多种凭据存储类型。对于代理,建议:
- 使用“Username with password”存储代理的用户名/密码
- 为不同团队/项目设置 Folder-level credentials
- 启用 Credentials Binding Plugin 以安全地在 Pipeline 中使用
- 设置审计日志以跟踪凭据的使用
外部秘密管理系统
对于企业环境,建议使用专门的秘密管理系统:HashiCorp Vault、AWS Secrets Manager、Azure Key Vault 或 Google Secret Manager。以下是与 HashiCorp Vault 在 GitHub Actions 中集成的示例:
- name: Import Secrets from Vault
uses: hashicorp/vault-action@v2
with:
url: https://vault.example.com
token: ${{ secrets.VAULT_TOKEN }}
secrets: |
secret/data/proxy proxy_user | PROXY_USER ;
secret/data/proxy proxy_pass | PROXY_PASS ;
secret/data/proxy proxy_host | PROXY_HOST
- name: Configure Proxy
run: |
export HTTP_PROXY="http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:8080"
npm install
解决常见问题
在 CI/CD 中集成代理时,常常会遇到相同的问题。我们将探讨最常见的问题及其解决方案。
问题:加载依赖项时连接超时
症状: npm install、pip install 或 docker pull 在 30-60 秒后以超时错误结束。
原因:
- 代理服务器不可用或过载
- 代理 URL 格式不正确(开头忘记加 http://)
- 代理需要身份验证,但未传递凭据
- 防火墙阻止了 CI/CD runner 与代理的连接
解决方案:
# 1. 检查代理的可用性
- name: Test proxy connectivity
run: |
curl -v -x http://proxy.example.com:8080 https://www.google.com
echo "Proxy test completed"
# 2. 增加 npm 的超时
- name: Install with increased timeout
run: |
npm config set fetch-timeout 300000
npm install
# 3. 检查 URL 格式
- name: Debug proxy configuration
run: |
echo "HTTP_PROXY: $HTTP_PROXY"
echo "HTTPS_PROXY: $HTTPS_PROXY"
# 应该是:http://user:pass@host:port
问题:SSL 证书验证失败
症状: 出现“SSL certificate problem: unable to get local issuer certificate”或“CERT_UNTRUSTED”之类的错误。
原因: 企业代理通常执行 SSL 检查,替换证书。CI/CD runner 不信任企业 CA。
解决方案:
# 选项 1:添加企业 CA 证书
- name: Install corporate CA certificate
run: |
sudo cp corporate-ca.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
# 选项 2:禁用 SSL 验证(不推荐用于生产!)
- name: Install with SSL verification disabled
run: |
npm config set strict-ssl false
npm install
env:
NODE_TLS_REJECT_UNAUTHORIZED: 0
# 选项 3:仅对 HTTP 使用代理,HTTPS 直接连接
- name: Selective proxy usage
run: npm install
env:
HTTP_PROXY: http://proxy.example.com:8080
# 不设置 HTTPS_PROXY
警告: 禁用 SSL 证书验证会带来严重的安全风险。仅在内部企业网络中使用此方法,并确保将企业 CA 添加到受信任的列表中。
问题:代理对某些命令有效,但对其他命令无效
症状: npm install 通过代理工作,但 git clone 或 docker pull 忽略代理设置。
原因: 不同工具使用不同的代理设置机制。Git 和 Docker 有自己的配置文件。
解决方案:
# 配置 Git 代理
- name: Configure Git proxy
run: |
git config --global http.proxy http://proxy.example.com:8080
git config --global https.proxy http://proxy.example.com:8080
# 配置 Docker 代理(参见上面的 Docker 部分)
# 对于 wget/curl
- name: Configure wget/curl
run: |
echo "use_proxy = on" >> ~/.wgetrc
echo "http_proxy = http://proxy.example.com:8080" >> ~/.wgetrc
echo "https_proxy = http://proxy.example.com:8080" >> ~/.wgetrc
问题:启用代理后内部服务不可用
症状: 在设置代理后,无法连接到 localhost、内部 Docker 容器或企业服务。
原因: NO_PROXY 变量设置不正确,所有请求都通过代理,包括本地请求。
解决方案:
# 正确设置 NO_PROXY
env:
HTTP_PROXY: http://proxy.example.com:8080
HTTPS_PROXY: http://proxy.example.com:8080
NO_PROXY: |
localhost,
127.0.0.1,
0.0.0.0,
.internal,
.local,
.corp.example.com,
docker.internal,
host.docker.internal
# 对于 Docker Compose 也添加
services:
app:
environment:
- NO_PROXY=localhost,127.0.0.1,db,redis
# db 和 redis 是 compose 中其他服务的名称
问题:代理凭据出现在日志中
症状: CI/CD 日志中明文显示代理密码。
原因: 通过 echo 或命令的详细模式输出环境变量。
解决方案:
# ❌ 不好 - 日志中的凭据
- name: Debug proxy
run: |
echo "Proxy: $HTTP_PROXY" # 会显示 http://user:pass@host:port
curl -v ... # 详细模式显示凭据
# ✅ 好 - 安全输出
- name: Debug proxy (safe)
run: |
echo "Proxy host configured: $(echo $HTTP_PROXY | cut -d'@' -f2)"
# 只会显示 host:port
# 使用 secrets 进行掩码
- name: Configure proxy
env:
PROXY_URL: ${{ secrets.PROXY_URL }} # GitHub 会自动掩码
run: |
export HTTP_PROXY="$PROXY_URL"
结论
在 CI/CD 管道中集成代理是自动化的重要方面,确保安全、符合企业政策并能够测试地理位置功能。在本指南中,我们探讨了如何为 GitHub Actions、GitLab CI、Jenkins、Docker 和流行的包管理器设置代理的实用方法。
设置代理时需要记住的关键点:始终通过平台内置的秘密机制安全存储凭据,正确设置 NO_PROXY 以排除本地和内部服务,在主要操作之前测试与代理的连接,并监控日志以防敏感数据泄露。对于关键的生产环境,建议使用外部秘密管理系统,如 HashiCorp Vault。
选择代理类型取决于您的需求:对于企业网络,通常使用现有的 HTTP/HTTPS 代理;对于地理位置功能的测试,适合使用 住宅代理,而对于高速下载依赖项,可以使用 数据中心代理。确保代理服务器的高正常运行时间,因为它们的不可用性将导致所有构建失败并阻碍开发团队的工作。
遇到问题时,从检查代理的基本可用性开始,使用 curl 或 wget,然后检查 URL 和凭据的格式,最后再进行特定工具的设置。大多数问题通过正确设置 HTTP_PROXY、HTTPS_PROXY 和 NO_PROXY 环境变量即可解决。