引言:为什么需要私有镜像仓库?
想象一下,如果每次做饭都要跑到超市去买食材,那对于我这种懒人来说,那该有多麻烦!在软件开发的世界里,Docker镜像就像是我们的"食材",而公共镜像仓库(如Docker Hub)就是那个"超市"。但有时候我们要当大老板,需要自己的"私人超市"——这就是私有镜像仓库的由来。
私有镜像仓库不仅能提高镜像拉取速度(告别漫长的下载等待,等着等着就打呼噜了),还能保护你的专有镜像(毕竟,妈妈的秘方不能公开给所有人),同时还能确保镜像的可用性(不怕"超市"突然关门)。现在就来一步步搭建属于自己的Docker "私人超市" !
Docker镜像:现代软件开发的"食材"
在深入私有镜像仓库之前,让先了解一下Docker镜像到底是什么?如果把软件开发比作烹饪,那么Docker镜像就是预先准备好的食材包——里面包含了应用程序及其所有依赖。你不需要担心"这个酱料和那个香料是否兼容"(依赖冲突),也不用操心"这种蔬菜在我这个季节能不能买到"(环境差异)。
Docker Hub 作为全球最大的公共镜像仓库,就像一个24小时营业的国际超市,里面有各种各样的"食材包"。但是,频繁地从这个"超市"购物会面临几个问题:
网络延迟:从远程服务器下载大型镜像可能需要很长时间,特别是在网络条件不佳的情况下。
带宽成本:反复下载相同的镜像会消耗大量带宽,尤其是在团队环境中。
可用性风险:如果Docker Hub暂时不可用,你的部署流程可能会中断。
隐私问题:你可能不希望将包含专有代码的镜像上传到公共仓库。
这就是为什么我们需要建立自己的"私人超市"——私有镜像仓库。
第一步:准备环境
在开始之前,请确保你的 CentOS 系统已安装 Docker。如果还没有,可以通过以下命令安装:
# 更新软件包索引
sudo yum update -y
# 安装必要的软件包
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# 添加Docker仓库
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 安装Docker CE
sudo yum install -y docker-ce docker-ce-cli containerd.io
# 启动Docker服务
sudo systemctl start docker
# 设置Docker开机自启
sudo systemctl enable docker
# 验证Docker是否安装成功
sudo docker run hello-world
如果看到"Hello from Docker!"的消息 ,Docker已成功安装!就像买到了建造超市的土地一样,我们已经准备好了基础设施。
安装Docker后,你可能会注意到系统添加了一个新的用户组 docker。这个用户组允许非 root 用户运行 Docker 命令,而不需要每次都使用sudo。如果你想避免总是输入sudo,可以将当前用户添加到 docker 组:
# 将当前用户添加到docker组
sudo usermod -aG docker $USER
# 应用新的组成员身份(需要重新登录或运行以下命令)
newgrp docker
# 测试无需sudo的Docker命令
docker run hello-world
第二步:启动私有镜像仓库
Docker官方提供了一个简单的Registry镜像,我们可以用它来快速搭建私有仓库。这个Registry是一个开源项目,专门用于存储和分发Docker镜像。
# 创建用于存储镜像的目录
sudo mkdir -p /opt/registry/data
# 启动Registry容器
sudo docker run -d \
--name registry \
-p 5000:5000 \
-v /opt/registry/data:/var/lib/registry \
--restart=always \
registry:2
这段命令做了什么?让我们逐一解析:
-d:在后台运行容器(守护模式)
--name registry:给容器起名为"registry",方便后续管理
-p 5000:5000:将容器内的5000端口映射到主机的5000端口
-v /opt/registry/data:/var/lib/registry:将主机上的/opt/registry/data目录挂载到容器内的/var/lib/registry目录,这样镜像数据就会持久化存储在主机上
--restart=always:设置容器自动重启策略,确保服务器重启后Registry也会自动启动
registry:2:使用的镜像名称和标签
这就像是用预制件快速搭建了一个超市的框架!现在,我们的私有镜像仓库已经在本地的5000端口上运行了。
你可以通过以下命令检查Registry容器是否正在运行:
# 查看运行中的容器
docker ps
# 应该能看到类似这样的输出
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# 3a2e3e4f5g6h registry:2 "/entrypoint.sh /etc…" 2 minutes ago Up 2 minutes 0.0.0.0:5000->5000/tcp registry
第三步:配置Docker客户端信任私有仓库
默认情况下,Docker客户端只信任HTTPS的仓库。但我们刚刚搭建的是HTTP仓库,需要告诉Docker:"嘿,老登,这是我的超市,Trust me!!"
# 创建或编辑Docker守护进程配置文件
sudo mkdir -p /etc/docker
sudo vi /etc/docker/daemon.json
# 添加以下内容(假设你的服务器IP是192.168.1.100)
{
"insecure-registries": ["192.168.1.100:5000"]
}
# 保存并关闭文件(按ESC,然后输入:wq回车)
# 重启Docker服务
sudo systemctl restart docker
记得将 192.168.1.100 替换为你自己的服务器IP地址。这就像是告诉你的好兄弟:"这个地址的超市是我开的,随便拿!"
为什么 Docker 默认只信任HTTPS仓库?这是出于安全考虑。HTTPS 提供了加密传输,防止中间人攻击,确保下载的镜像确实来自正确的源头,而不是被篡改过的版本。在生产环境中,强烈建议为你的私有仓库配置HTTPS。
如果你想在生产环境中使用HTTPS,需要获取SSL证书(可以使用Let's Encrypt等免费证书服务)并相应地配置Registry:
# 假设你已经有了证书文件
sudo mkdir -p /opt/registry/certs
# 将证书文件放在/opt/registry/certs目录下
# 重新启动Registry容器,启用HTTPS
sudo docker run -d \
--name registry \
-p 5000:5000 \
-v /opt/registry/data:/var/lib/registry \
-v /opt/registry/certs:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
--restart=always \
registry:2
第四步:测试私有镜像仓库
现在,让我们来测试一下我们的"私人超市"是否正常营业:
# 拉取一个测试镜像
sudo docker pull centos:7
# 给镜像打标签,准备推送到私有仓库
sudo docker tag centos:7 192.168.1.100:5000/my-centos
# 推送镜像到私有仓库
sudo docker push 192.168.1.100:5000/my-centos
# 删除本地镜像(为了测试拉取)
sudo docker rmi 192.168.1.100:5000/my-centos
# 从私有仓库拉取镜像
sudo docker pull 192.168.1.100:5000/my-centos
如果一切顺利,你应该能够成功推送和拉取镜像。这就像是在你的"私人超市"里存放和取用食材!
让我们理解一下这个过程:
首先,我们从Docker Hub拉取了官方的CentOS镜像。
然后,我们给这个镜像打上了一个新标签,指向我们的私有仓库。
接着,我们将带有新标签的镜像推送到私有仓库。
为了测试,我们删除了本地的镜像。
最后,我们从私有仓库拉取镜像,验证它是否正常工作。
这个过程展示了私有仓库的基本功能:存储和分发Docker镜像。
第五步:增强安全性(可选但推荐)
我们的"私人超市"现在还没有安装防盗系统!任何知道你仓库地址的人都可以推送和拉取镜像。让我们添加一些基本的安全措施:
# 停止并删除当前的Registry容器
sudo docker stop registry
sudo docker rm registry
# 创建存储认证信息的目录
sudo mkdir -p /opt/registry/auth
# 创建用户名和密码
sudo docker run --rm --entrypoint htpasswd registry:2 -Bbn myuser mypassword > /opt/registry/auth/htpasswd
# 重新启动Registry容器,启用认证
sudo docker run -d \
--name registry \
-p 5000:5000 \
-v /opt/registry/data:/var/lib/registry \
-v /opt/registry/auth:/auth \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
--restart=always \
registry:2
现在,你的"私人超市"有了门禁系统!在推送或拉取镜像时,需要提供用户名和密码:
# 登录到私有仓库
sudo docker login 192.168.1.100:5000 -u myuser -p mypassword
# 之后就可以正常推送和拉取镜像了
这种基于htpasswd的认证是最简单的方式,适合小型团队或个人使用。对于更大规模的部署,你可能需要考虑更复杂的认证方案,如OAuth或LDAP集成。
除了认证,你还可以实施以下安全措施:
网络隔离:将Registry部署在私有网络中,只允许特定的IP地址访问。
镜像扫描:使用工具如Clair或Trivy扫描镜像中的安全漏洞。
访问控制:实施细粒度的访问控制,限制谁可以推送或拉取特定的镜像。
第六步:管理你的私有镜像仓库
随着时间推移,你的"私人超市"可能会堆满各种"食材"。以下是一些管理技巧:
查看仓库中的镜像:
curl -X GET http://192.168.1.100:5000/v2/_catalog
如果启用了认证 ,需要提供凭据:
curl -X GET -u myuser:mypassword http://192.168.1.100:5000/v2/_catalog
查看特定镜像的标签:
curl -X GET http://192.168.1.100:5000/v2/my-centos/tags/list
定期清理不再使用的镜像(防止"超市"货架过满 ):
默认情况下,Registry不允许删除镜像。要启用删除功能,需要在启动Registry时设置环境变量:# 停止并删除当前的Registry容器 sudo docker stop registry sudo docker rm registry # 重新启动Registry,启用删除功能 sudo docker run -d \ --name registry \ -p 5000:5000 \ -v /opt/registry/data:/var/lib/registry \ -v /opt/registry/auth:/auth \ -e "REGISTRY_AUTH=htpasswd" \ -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \ -e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \ -e "REGISTRY_STORAGE_DELETE_ENABLED=true" \ --restart=always \ registry:2
然后,你可以使用Registry API删除镜像:
# 删除特定标签的镜像(需要先获取摘要) # 1. 获取镜像摘要 curl -v -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X GET http://192.168.1.100:5000/v2/my-centos/manifests/latest # 2. 使用摘要删除镜像(将<digest>替换为实际的摘要值 ) curl -X DELETE http://192.168.1.100:5000/v2/my-centos/manifests/<digest> # 3. 运行垃圾回收以释放磁盘空间 sudo docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml
备份你的Registry数据:
定期备份/opt/registry/data目录是个好习惯:# 创建备份 sudo tar -czf registry-backup-$(date +%Y%m%d ).tar.gz /opt/registry/data # 将备份移动到安全位置 sudo mv registry-backup-*.tar.gz /path/to/backup/location/
监控Registry的健康状态:
你可以使用简单的健康检查脚本:# 创建健康检查脚本 cat > registry-health-check.sh << 'EOF' #!/bin/bash REGISTRY_URL="http://192.168.1.100:5000" # 检查Registry是否响应 response=$(curl -s -o /dev/null -w "%{http_code}" $REGISTRY_URL/v2/ ) if [ $response -eq 200 ] || [ $response -eq 401 ]; then echo "Registry is healthy (HTTP $response)" exit 0 else echo "Registry is not healthy (HTTP $response)" exit 1 fi EOF # 添加执行权限 chmod +x registry-health-check.sh # 设置定时任务,每小时检查一次 (crontab -l 2>/dev/null; echo "0 * * * * /path/to/registry-health-check.sh >> /var/log/registry-health.log 2>&1") | crontab -
第七步:与CI/CD系统集成
私有镜像仓库的真正价值在于将其集成到你的持续集成/持续部署(CI/CD)流程中。以下是一个简单的示例,展示如何在Jenkins流水线中使用私有仓库:
pipeline {
agent any
environment {
REGISTRY = "192.168.1.100:5000"
IMAGE_NAME = "my-app"
IMAGE_TAG = "${env.BUILD_NUMBER}"
}
stages {
stage('Build') {
steps {
sh 'docker build -t $REGISTRY/$IMAGE_NAME:$IMAGE_TAG .'
}
}
stage('Push') {
steps {
withCredentials([usernamePassword(credentialsId: 'registry-credentials', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
sh 'docker login $REGISTRY -u $USERNAME -p $PASSWORD'
sh 'docker push $REGISTRY/$IMAGE_NAME:$IMAGE_TAG'
}
}
}
stage('Deploy') {
steps {
sh 'docker pull $REGISTRY/$IMAGE_NAME:$IMAGE_TAG'
sh 'docker stop my-app || true'
sh 'docker rm my-app || true'
sh 'docker run -d --name my-app -p 8080:8080 $REGISTRY/$IMAGE_NAME:$IMAGE_TAG'
}
}
}
}
这个流水线做了三件事:
构建Docker镜像并标记为私有仓库地址
登录到私有仓库并推送镜像
从私有仓库拉取镜像并部署
通过这种方式,你的CI/CD系统可以自动构建、存储和部署Docker镜像,而不需要依赖公共仓库。
结语:享受你的"私人超市"
恭喜!你现在拥有了自己的Docker"私人超市"。无需每次都跑到公共"超市"排队,你可以在自己的网络中高速获取所需的镜像"食材"。
私有镜像仓库带来的好处是显而易见的:
更快的部署速度:从本地网络拉取镜像比从互联网下载快得多。
更好的控制:你可以完全控制哪些镜像可以存储和使用。
更高的安全性:敏感的镜像不会暴露在公共网络中。
更可靠的可用性:即使互联网连接中断,你的部署流程仍然可以正常工作。
记住,就像真正的超市需要维护一样,定期备份你的/opt/registry/data目录是个好习惯。毕竟,谁也不想自己辛苦收集的"食材"突然消失,对吧?
随着你的团队和项目规模的增长,你可能需要考虑更高级的解决方案,如Harbor(一个企业级的Registry项目,提供更多功能如镜像扫描、复制和图形界面)或商业产品如JFrog Artifactory。但对于大多数小型团队和个人项目,Docker官方的Registry已经足够了。
参考文献
Docker官方文档:Registry部署指南
Docker官方文档:配置安全访问
Docker官方文档:存储配置
CentOS官方文档:在CentOS上安装Docker
CentOS Wiki:防火墙配置
GitHub: Docker Registry项目