私有Docker仓库
大约 8 分钟
私有Docker仓库
- 由于众所周不知的原因,Docker国内镜像被禁用
- 个人电脑可以使用魔法上网解决,但在多服务器的情况下不方便,提供了如下解决方案
- 其中一台电脑设置代理(魔法上网),从Docker公共库拉取镜像(docker pull)
- 转换镜像标签(docker tag)
- 推送到内网私有仓库(docker push)
- 其他内网服务器都可以从私有仓库拉取镜像使用了(docker pull)
仓库方案
- 使用Registry搭建私有仓库(该仓库仅服务,搭配UI界面方便使用)
- Registry官网: https://distribution.github.io/distribution
- 可选UI界面
- docker-registry-browser(推荐): https://github.com/klausmeyer/docker-registry-browser
- docker-registry-ui(够用): https://joxit.dev/docker-registry-ui/
- docker-registry-web(勿用,巨丑,断更): https://github.com/mkuchin/docker-registry-web
- 该方案适合小微企业,或起步阶段
- 其他仓库方案
魔法环境
- 本文章使用的是"Clash",请求转发到7890端口就能魔法上网
- 这台可上魔法环境的电脑/服务器,当做"代理节点"
配置
# 编辑Docker配置
vim /etc/docker/daemon.json
# 如下配置后,重启服务
systemctl restart docker
- 代理配置如下
- "127.0.0.1:7890" 为VPN代理地址,要修改为自己的代理地址
{
"proxies": {
"http-proxy": "http://127.0.0.1:7890",
"https-proxy": "http://127.0.0.1:7890"
}
}
下载镜像
- 先从公共仓库先下载使用到的镜像
- 以下版本是当前最新的稳定版(当前时间:2024-11-03)
docker pull registry:2.8.3
docker pull klausmeyer/docker-registry-browser:1.7.4
- 镜像打包成文件
docker save registry:2.8.3 > registry_2.8.3.image
docker save klausmeyer/docker-registry-browser:1.7.4 > docker-registry-browser_1.7.4.image
- 文件上传到要部署仓库的服务器
- docker加载镜像
docker load < registry_2.8.3.image
docker load < docker-registry-browser_1.7.4.image
部署(无鉴权)
- 部署仓库的服务器在内网中,且不会开放外网访问,可以不需要鉴权
- 如果服务器在公网,或者会开放公网访问,看下面的有鉴权版本
- 服务组件:registry + docker-registry-browser
- 下面是博主的环境信息,大家根据自己的环境,替换为自己的
- 内网IP:192.168.1.3
- 仓库端口:8000
- 仓库UI端口:8001
使用Docker
- 部署仓库服务
- 验证
- 访问"http://IP:8000/v2/"
- 返回"{}",则成功
# 删除下面命令的注释才能运行
docker run --name registry-server \
--restart always \
-p 8000:5000 \
-v ./data:/var/lib/registry \ # 替换为自己的持久化地址,无持久化需求去掉这个参数
-e REGISTRY_STORAGE_DELETE_ENABLED=true \ # 是否允许删除镜像
-d registry:2.8.3
- 部署仓库UI
- 验证
- 浏览器访问"http://IP:8001"
# 删除下面命令的注释才能运行
docker run --name registry-ui \
--restart always \
-p 8001:8080 \
-e DOCKER_REGISTRY_URL=http://192.168.1.3:8000/v2 \ # 仓库地址,替换为自己仓库的IP及端口号
-e SECRET_KEY_BASE=$(openssl rand -hex 64) \ # 密钥使用"openssl rand -hex 64"生成
-e PUBLIC_REGISTRY_URL=192.168.1.3:8000 \ # 复制PULL命令的地址,将IP改为自己的IP/域名和宿主机端口号
-e ENABLE_DELETE_IMAGES=true \ # 是否显示删除镜像按钮
-d klausmeyer/docker-registry-browser:1.7.4
使用Docker Compose
- 生成密钥
# openssl生成随机密钥
openssl rand -hex 64
# 复制打印的密钥,手动替换yaml中的"SECRET_KEY_BASE"的值
- 创建"docker-compose.yaml"文件,内容如下
version: '1.0'
services:
registry-server:
container_name: registry-server
image: registry:2.8.3
restart: always
ports:
- 8000:5000
environment:
- REGISTRY_STORAGE_DELETE_ENABLED=true # 是否允许删除镜像
volumes:
- ./data:/var/lib/registry # 替换为自己的持久化地址,无持久化需求去掉这个参数
retistry-ui:
container_name: registry-ui
image: klausmeyer/docker-registry-browser:1.7.4
restart: always
ports:
- 8001:8080
environment:
- DOCKER_REGISTRY_URL=http://registry-server:5000/v2 # registry端口号,不是宿主机端口号,所以不要改
- PUBLIC_REGISTRY_URL=192.168.1.3:8000 # 复制PULL命令的地址,将IP改为自己的IP/域名和宿主机端口号
- SECRET_KEY_BASE=手动替换生成的密钥 # 修改密钥,使用"openssl rand -hex 64"命令生成一个
- ENABLE_DELETE_IMAGES=true # 是否显示删除镜像按钮
- 启动命令
# 启动服务
docker compose -f docker-compose.yaml up -d
# 关闭服务
docker compose -f docker-compose.yaml down
- 验证结果
- 浏览器访问"http://IP:8001"
部署(简单鉴权)
- 使用账号密码的简单鉴权
- pull/push命令前,先"docker login"登录
- 仓库UI访问需输入账号密码(配置了默认账号密码,不需要输入)
- 在上面无鉴权版本的基础上加几个配置就能实现鉴权
- 服务组件:registry + docker-registry-browser
- 下面是博主的环境信息,大家根据自己的环境,替换为自己的
- 内网IP:192.168.1.3
- 仓库端口:8000
- 仓库UI端口:8001
htpasswd密码文件
- 使用htpasswd生成密码文件
htpasswd -Bbn username password > /path/to/file
# 示例
# htpasswd -Bbn xxc 123456 > ./htpasswd
使用Docker
- 部署仓库服务
- 验证
- 访问"http://IP:8000/v2/"
- 返回"{}",则成功
# 删除下面命令的注释才能运行
docker run --name registry-server \
--restart always \
-p 8000:5000 \
-v ./data:/var/lib/registry \ # 替换为自己的持久化地址,无持久化需求去掉这个参数
-v ./htpasswd:/auth/htpasswd \ # 替换为自己的htpasswd文件(上个步骤生成)
-e REGISTRY_STORAGE_DELETE_ENABLED=true \ # 是否允许删除镜像
-e REGISTRY_AUTH=htpasswd \
-e REGISTRY_AUTH_HTPASSWD_REALM=basic-realm \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
-d registry:2.8.3
- 部署仓库UI
- 验证
- 浏览器访问"http://IP:8001"
- 如果设置了"BASIC_AUTH_USER"和"BASIC_AUTH_PASSWORD"参数,则与无鉴权感觉没有差别
- 如果未设置了,则需要输入账号密码才能查看仓库
# 删除下面命令的注释才能运行
docker run --name registry-ui \
--restart always \
-p 8001:8080 \
-e DOCKER_REGISTRY_URL=http://192.168.1.3:8000/v2 \ # 仓库地址,替换为自己仓库的IP及端口号
-e SECRET_KEY_BASE=$(openssl rand -hex 64) \ # 密钥使用"openssl rand -hex 64"生成
-e PUBLIC_REGISTRY_URL=192.168.1.3:8000 \ # 复制PULL命令的地址,将IP改为自己的IP/域名和宿主机端口号
-e ENABLE_DELETE_IMAGES=true \ # 是否显示删除镜像按钮
-e BASIC_AUTH_USER=xxc \ # 配置默认账号(htpasswd生成的),删除该参数则需要手动输入账号
-e BASIC_AUTH_PASSWORD=123456 \ # 配置默认密码(htpasswd生成的),删除该参数则需要手动输入密码
-d klausmeyer/docker-registry-browser:1.7.4
使用Docker Compose
- 生成密钥
# openssl生成随机密钥
openssl rand -hex 64
# 复制打印的密钥,手动替换yaml中的"SECRET_KEY_BASE"的值
- 创建"docker-compose.yaml",当前目录结构如下
registry
├─ htpasswd
└─ docker-compose.yml
- "docker-compose.yaml"内容如下
version: '2.0'
services:
registry-server:
container_name: registry-server
image: registry:2.8.3
restart: always
ports:
- 8000:5000
environment:
- REGISTRY_STORAGE_DELETE_ENABLED=true # 是否允许删除镜像
- REGISTRY_AUTH=htpasswd
- REGISTRY_AUTH_HTPASSWD_REALM=basic-realm
- REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd
volumes:
- ./data:/var/lib/registry # 替换为自己的持久化地址,无持久化需求去掉这个参数
- ./htpasswd:/auth/htpasswd # 挂载htpasswd命令生成的密码文件
retistry-ui:
container_name: registry-ui
image: klausmeyer/docker-registry-browser:1.7.4
restart: always
ports:
- 8001:8080
environment:
- DOCKER_REGISTRY_URL=http://registry-server:5000/v2 # registry端口号,不是宿主机端口号,所以不要改
- PUBLIC_REGISTRY_URL=192.168.1.3:8000 # 复制PULL命令的地址,将IP改为自己的IP/域名和宿主机端口号
- SECRET_KEY_BASE=手动替换生成的密钥 # 修改密钥,使用"openssl rand -hex 64"命令生成一个
- ENABLE_DELETE_IMAGES=true # 是否显示删除镜像按钮
- BASIC_AUTH_USER=xxc # 配置默认账号(htpasswd生成的),删除该参数则需要手动输入
- BASIC_AUTH_PASSWORD=123456 # 配置默认密码(htpasswd生成的),删除该参数则需要手动输入
- 启动命令
# 启动服务
docker compose -f docker-compose.yaml up -d
# 关闭服务
docker compose -f docker-compose.yaml down
- 验证结果
- 浏览器访问"http://IP:8001"
代理节点
配置
- 该节点使用了代理,私有仓库IP被代理导致无法访问,所以禁用部分IP的代理
- 修改配置
- 增加 "proxies.no-proxy" 禁止代理私有仓库的IP
- 增加 "insecure-registries" ,将私有仓库地址添加到信任列表
- 重启Docker
{
"proxies": {
"http-proxy": "http://127.0.0.1:7890",
"https-proxy": "http://127.0.0.1:7890",
"no-proxy": "localhost,127.0.0.1,192.168.1.3"
},
"insecure-registries": [
"192.168.1.3:8000"
]
}
# 编辑Docker配置
vim /etc/docker/daemon.json
# 如下配置后,重启服务
systemctl restart docker
使用
# 从公共库拉取镜像
docker pull alpine:latest
# 修改Tag
docker tag alpine:latest 192.168.1.3:8000/alpine:latest
# 登录(有鉴权的话)
docker login -u username -p password 192.168.1.3:8000
# 镜像推送到私有仓库
docker push 192.168.1.3:8000/alpine:latest
服务器节点
允许私有仓库
- 增加 "insecure-registries" ,将私有仓库地址添加到信任列表
{
"insecure-registries": [
"192.168.1.3:8000"
]
}
# 编辑Docker配置
vim /etc/docker/daemon.json
# 如下配置后,重启服务
systemctl restart docker
使用
- 运行直接带上私有仓库地址
- 镜像必须提前使用代理节点上传
# 登录(有鉴权的话)
docker login -u username -p password 192.168.1.3:8000
# 拉取镜像,命令可以从UI界面复制
docker pull 192.168.1.3:8000/alpine:latest
# 使用(和正常命令一样使用,只是前面加了私有可的地址和端口号)
docker run -d 192.168.1.3:8000/alpine:latest
- 如果是Dockerfile打包镜像
- tag名称加上私有仓库地址
# 在执行build命令
docker build -t 192.168.1.3:8000/xxx:latest .
# 登录(有鉴权的话)
docker login -u username -p password 192.168.1.3:8000
# 上传私有仓库
docker push 192.168.1.3:8000/xxx:latest
常见异常
EOF
- 原因:仓库地址错误
- 解决方法:确认仓库IP及端口号是否正确
# 推送私有仓库镜像
docker push 192.168.1.3:8000/alpine:latest
# The push refers to repository [192.168.1.5:8000/alpine]
# Get "https://192.168.1.5:8000/v2/": EOF
server gave HTTP response to HTTPS client
- 原因:未设置私有仓库
- 解决方法:修改/etc/docker/daemon.json,将仓库地址加入信任列表
docker push 192.168.1.3:8000/alpine:latest
# 报错如下
The push refers to repository [192.168.1.3:8000/alpine]
Get "https://192.168.1.3:8000/v2/": http: server gave HTTP response to HTTPS client
no basic auth credentials
- 原因:未登录
- 解决方法:使用"docker login"登录
docker push 192.168.1.3:8000/alpine:latest
# 报错如下
The push refers to repository [192.168.1.3:8000/alpine]
63ca1fbb43ae: Preparing
no basic auth credentials
参考文章
- https://baijiahao.baidu.com/s?id=1803388229356954283
- https://www.cnblogs.com/netcore3/p/16982828.html
- https://www.cnblogs.com/chen2ha/p/14787695.html
- https://developer.aliyun.com/article/1094892