You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让docker pull使用HTTPS访问仅支持HTTPS的私有镜像仓库

问题:如何让Docker客户端通过HTTPS拉取镜像

我使用一个未安装dockerd的普通Ubuntu镜像,仅包含Docker命令行客户端和curl,已配置TLS安全,通过第三方容器(dind)运行Docker守护进程。以下curl操作符合预期:

curl https://myregistry/v2/_catalog # 成功获取仓库目录信息
curl http://myregistry/v2/_catalog  # 按预期失败(仓库仅支持HTTPS)

但执行docker pull时,Docker客户端却只尝试用HTTP连接,导致失败:

docker pull myregistry/myimage
Using default tag: latest
Error response from daemon: Client sent an HTTP request to an HTTPS server.

我需要让docker pull默认使用HTTPS而非HTTP,目前找到的资料都是解决“让Docker通过HTTPS访问HTTP仓库”的反向问题,而我的证书配置应该是正确的——毕竟curl的HTTPS请求能正常工作。

更新说明

按照提示,myregistry/image里的myregistry会被识别为命名空间而非仓库主机名,因此我将仓库主机名改为my.hub(包含点的格式会被Docker识别为独立主机)。另外,我没有在任何操作系统、容器或gitlab-runner的config.toml中配置“不安全仓库”。

最小复现示例

我已在/etc/hosts中添加了以下主机映射:myregistry、dind、client1、client2。

以下是完整的复现脚本:

#!/bin/bash

# 清理现有容器和数据
docker stop my.hub dind client1 client2
docker rm my.hub dind client1 client2
sudo rm -rf volumes

CURRENT=${PWD}
HUB_DIR=${PWD}/volumes/my.hub
DIND_DIR=${PWD}/volumes/dind

# 创建目录结构
sudo rm -rf $CURRENT/volumes
mkdir -p $CURRENT/ca
mkdir -p $HUB_DIR/certs
mkdir -p $DIND_DIR/certs/ca
mkdir -p $DIND_DIR/certs/client
mkdir -p $DIND_DIR/certs/server
mkdir -p $DIND_DIR/etc/docker/certs.d/my.hub
mkdir -p $DIND_DIR/etc/docker/certs.d/my.hub:443
mkdir -p $DIND_DIR/usr/local/share/ca-certificates

# 生成CA密钥和证书
cd $CURRENT/ca

openssl genrsa -out key.pem 2048
openssl req -x509 -days 365 -new -nodes -key key.pem \
    -subj "/C=UK/ST=Sussex/L=London/O=Moiself/OU=Sofa/CN=myregistry" \
    -sha256 -out cert.pem

# 生成my.hub的密钥和证书
cd $HUB_DIR/certs

openssl genrsa -out key.pem 2048
openssl req -new -key key.pem -out csr.pem \
    -subj "/C=UK/ST=Sussex/L=London/O=Moiself/OU=Sofa/CN=myregistry" \
    -addext "subjectAltName=DNS:my.hub,DNS:localhost"
openssl x509 -req -days 365 -sha256 -in csr.pem  \
    -CA $CURRENT/ca/cert.pem -CAkey $CURRENT/ca/key.pem \
    -CAcreateserial -out cert.pem \
    -extfile <(printf "authorityKeyIdentifier=keyid,issuer\nbasicConstraints=CA:FALSE\nkeyUsage=critical,digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment\nsubjectAltName=DNS:my.hub,DNS:localhost")

cd $CURRENT

# 复制证书到对应目录
cp $CURRENT/ca/cert.pem    $DIND_DIR/certs/client/ca.pem
cp $CURRENT/ca/cert.pem    $DIND_DIR/certs/ca/cert.pem
cp $CURRENT/ca/key.pem     $DIND_DIR/certs/ca/key.pem
cp $CURRENT/ca/cert.pem    $DIND_DIR/usr/local/share/ca-certificates/ca.crt
cp $HUB_DIR/certs/cert.pem $DIND_DIR/etc/docker/certs.d/my.hub/ca.crt

sudo chown -R root volumes

# 启动私有镜像仓库(my.hub)
docker run -d -it --network some-network --ip 172.18.0.2 -e REGISTRY_HTTP_ADDR=0.0.0.0:443  \
    -e REGISTRY_HTTP_TLS_KEY=/certs/key.pem -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/cert.pem \
    -v $HUB_DIR/certs:/certs:ro --name my.hub --hostname my.hub registry:2

# 启动dind容器(Docker-in-Docker)
docker run -d -it --privileged --network some-network --ip 172.18.0.3 --network-alias docker \
    -e DOCKER_TLS_CERTDIR=/certs  \
    -v $DIND_DIR/etc/docker/certs.d:/etc/docker/certs.d:ro \
    -v $DIND_DIR/usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro  \
    -v $DIND_DIR/certs/client:/certs/client  \
    -v $DIND_DIR/certs/ca:/certs/ca  \
    -v $DIND_DIR/certs/server:/certs/server \
    --name dind --hostname dind docker:dind  \
    sh -c "dockerd-entrypoint.sh --iptables=false && tail -f /dev/null"

sleep 3
# 配置dind容器并测试
docker exec -it dind apk update
docker exec -it dind apk add curl
docker exec -it dind /usr/sbin/update-ca-certificates
docker exec -it dind docker pull alpine:latest
docker exec -it dind docker tag alpine:latest my.hub/alpine2
docker exec -it dind docker push my.hub/alpine2
docker exec -it dind curl https://my.hub/v2/_catalog
docker exec -it dind docker images

# 准备client2证书目录
sudo rm -rf $DIND_DIR/certs/client2
sudo cp -r  $DIND_DIR/certs/client $DIND_DIR/certs/client2
cp $DIND_DIR/certs/client/cert.pem $DIND_DIR/etc/docker/certs.d/dind/ca.crt

# 启动Alpine客户端容器(仅含Docker CLI)
docker run  -d -it --network some-network --ip 172.18.0.4 \
    -e DOCKER_HOST=tcp://dind:2376 \
    -e DOCKER_TLS_CERTDIR=/certs \
    -v $DIND_DIR/certs/client2:/certs:ro \
    -v $DIND_DIR/etc/docker/certs.d:/etc/docker/certs.d:ro \
    -v $DIND_DIR/usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro  \
    --name client1  --hostname client1 docker:24.0.0-beta.1-cli-alpine3.17

sleep 3
# 配置client1并测试(以下操作均会出现HTTP请求错误)
docker exec -it client1 apk update
docker exec -it client1 apk add curl
docker exec -it client1 /usr/sbin/update-ca-certificates
docker exec -it client1 docker pull alpine:latest;              # 发送HTTP请求,报错
docker exec -it client1 docker tag alpine:latest my.hub/alpine3 # 发送HTTP请求,报错
docker exec -it client1 docker push my.hub/alpine3              # 发送HTTP请求,报错
docker exec -it client1 curl https://my.hub/v2/_catalog
docker exec -it client1 docker images                           # 发送HTTP请求,报错

# 启动Ubuntu客户端容器(仅含Docker CLI)
docker run  -d -it --network some-network  --ip 172.18.0.5  \
    -e DOCKER_HOST=tcp://dind:2376  \
    -e DOCKER_TLS_CERTDIR=/certs \
    -v $DIND_DIR/etc/docker/certs.d:/etc/docker/certs.d:ro \
    -v $DIND_DIR/usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro  \
    --name client2  --hostname client2 localci-ubuntu-gcc

sleep 3
# 配置client2并测试(以下操作均会出现HTTP请求错误)
docker exec -it client2 apt update
docker exec -it client2 /usr/sbin/update-ca-certificates
docker exec -it client2 docker pull alpine:latest               # 发送HTTP请求,报错
docker exec -it client2 docker tag alpine:latest my.hub/alpine4 # 发送HTTP请求,报错
docker exec -it client2 docker push my.hub/alpine4              # 发送HTTP请求,报错
docker exec -it client2 curl https://my.hub/v2/_catalog
docker exec -it client2 docker images                           # 发送HTTP请求,报错

解决方案

1. 确认证书与主机名匹配

用以下命令验证证书的SAN字段是否包含my.hub:

openssl x509 -in $HUB_DIR/certs/cert.pem -text -noout | grep -A 3 "Subject Alternative Name"

确保输出中存在DNS:my.hub,否则Docker会拒绝信任证书。

2. 检查dind容器内的dockerd配置

问题核心是dind里的dockerd在转发请求时强制使用HTTP,需做以下检查:

  • 进入dind容器,确认/etc/docker/certs.d/my.hub/ca.crt存在,权限为root:root、644,内容与CA证书一致。
  • 检查dockerd启动参数,确认无--insecure-registry=my.hub配置:
    docker exec -it dind ps aux | grep dockerd
    

3. 强制Docker使用HTTPS

两种可选方式:

  • 临时方案:拉取时显式指定HTTPS协议和端口:
    docker pull https://my.hub:443/myimage
    
  • 永久方案:在客户端容器的~/.docker/config.json中添加配置:
    {
      "registry-configs": {
        "my.hub": {
          "Protocol": "https"
        }
      }
    }
    
    将该文件挂载到客户端容器对应路径(Alpine为/root/.docker/config.json,Ubuntu为/home/你的用户名/.docker/config.json)。

4. 排查dockerd日志

查看dind容器内dockerd的日志,定位协议错误根源:

docker logs dind | grep -i "http\|https\|registry"

若日志出现证书信任错误,需在dind容器内重新执行update-ca-certificates并重启dockerd。


内容的提问来源于stack exchange,提问作者Patrick Fromberg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 02:50:58