Skip to content

Docker 镜像仓库

本章将详细介绍 Docker 镜像仓库的使用和管理,包括公共仓库、私有仓库的搭建、镜像分发策略以及仓库安全配置。

镜像仓库概述

什么是 Docker 镜像仓库?

Docker 镜像仓库是存储和分发 Docker 镜像的服务。它类似于代码仓库,但专门用于管理容器镜像的版本和分发。

仓库架构层次

Registry (仓库服务)
├── Repository (镜像仓库)
│   ├── Tag 1 (标签/版本)
│   ├── Tag 2
│   └── Tag 3
└── Repository
    ├── Tag 1
    └── Tag 2

仓库类型

类型描述使用场景示例
公共仓库开放访问的镜像仓库开源项目、基础镜像Docker Hub
私有仓库受限访问的镜像仓库企业内部应用Harbor、Nexus
云仓库云服务商提供的仓库云原生应用ECR、ACR、GCR
本地仓库本地部署的仓库服务开发测试环境Registry

Docker Hub

Docker Hub 基础使用

bash
# 注册和登录
docker login

# 搜索镜像
docker search nginx
docker search --limit 10 --filter stars=100 nginx

# 拉取镜像
docker pull nginx:latest
docker pull nginx:1.21.6-alpine

# 推送镜像
docker tag myapp:latest username/myapp:latest
docker push username/myapp:latest

# 登出
docker logout

镜像命名规范

bash
# Docker Hub 镜像命名格式
[registry_host[:port]/]username/repository[:tag]

# 官方镜像(省略用户名)
nginx:latest
ubuntu:20.04
postgres:13

# 用户镜像
myuser/myapp:v1.0
company/backend:latest

# 私有仓库镜像
registry.company.com:5000/team/app:v1.0

自动构建

yaml
# .github/workflows/docker-hub.yml
name: Build and Push to Docker Hub

on:
  push:
    branches: [ main ]
    tags: [ 'v*' ]

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout
      uses: actions/checkout@v2
    
    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v1
    
    - name: Login to Docker Hub
      uses: docker/login-action@v1
      with:
        username: ${{ secrets.DOCKER_USERNAME }}
        password: ${{ secrets.DOCKER_PASSWORD }}
    
    - name: Extract metadata
      id: meta
      uses: docker/metadata-action@v3
      with:
        images: username/myapp
        tags: |
          type=ref,event=branch
          type=ref,event=pr
          type=semver,pattern={{version}}
          type=semver,pattern={{major}}.{{minor}}
    
    - name: Build and push
      uses: docker/build-push-action@v2
      with:
        context: .
        push: true
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}

私有仓库搭建

使用官方 Registry

bash
# 运行简单的私有仓库
docker run -d \
  -p 5000:5000 \
  --name registry \
  registry:2

# 推送镜像到私有仓库
docker tag myapp:latest localhost:5000/myapp:latest
docker push localhost:5000/myapp:latest

# 从私有仓库拉取
docker pull localhost:5000/myapp:latest

持久化存储配置

bash
# 使用数据卷持久化
docker run -d \
  -p 5000:5000 \
  --name registry \
  -v registry-data:/var/lib/registry \
  registry:2

# 使用主机目录
docker run -d \
  -p 5000:5000 \
  --name registry \
  -v /opt/registry:/var/lib/registry \
  registry:2

Registry 配置文件

yaml
# config.yml
version: 0.1
log:
  fields:
    service: registry
storage:
  cache:
    blobdescriptor: inmemory
  filesystem:
    rootdirectory: /var/lib/registry
  delete:
    enabled: true
http:
  addr: :5000
  headers:
    X-Content-Type-Options: [nosniff]
health:
  storagedriver:
    enabled: true
    interval: 10s
    threshold: 3
bash
# 使用自定义配置
docker run -d \
  -p 5000:5000 \
  --name registry \
  -v $(pwd)/config.yml:/etc/docker/registry/config.yml \
  -v registry-data:/var/lib/registry \
  registry:2

Harbor 企业级仓库

Harbor 部署

yaml
# docker-compose.yml
version: '3.8'

services:
  registry:
    image: goharbor/registry-photon:v2.5.0
    container_name: registry
    restart: always
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - SETGID
      - SETUID
    volumes:
      - /data/registry:/storage:z
      - ./common/config/registry/:/etc/registry/:z
    networks:
      - harbor
    depends_on:
      - log
    logging:
      driver: "syslog"
      options:
        syslog-address: "tcp://localhost:1514"
        tag: "registry"

  registryctl:
    image: goharbor/harbor-registryctl:v2.5.0
    container_name: registryctl
    env_file:
      - ./common/config/registryctl/env
    restart: always
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - SETGID
      - SETUID
    volumes:
      - /data/registry:/storage:z
      - ./common/config/registry/:/etc/registry/:z
      - ./common/config/registryctl/config.yml:/etc/registryctl/config.yml:z
    networks:
      - harbor
    depends_on:
      - log
    logging:
      driver: "syslog"
      options:
        syslog-address: "tcp://localhost:1514"
        tag: "registryctl"

  postgresql:
    image: goharbor/harbor-db:v2.5.0
    container_name: harbor-db
    restart: always
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - DAC_OVERRIDE
      - SETGID
      - SETUID
    volumes:
      - /data/database:/var/lib/postgresql/data:z
    networks:
      - harbor
    env_file:
      - ./common/config/db/env
    depends_on:
      - log
    logging:
      driver: "syslog"
      options:
        syslog-address: "tcp://localhost:1514"
        tag: "postgresql"

  core:
    image: goharbor/harbor-core:v2.5.0
    container_name: harbor-core
    env_file:
      - ./common/config/core/env
    restart: always
    cap_drop:
      - ALL
    cap_add:
      - SETGID
      - SETUID
    volumes:
      - /data/ca_download/:/etc/core/ca/:z
      - /data/:/data/:z
      - ./common/config/core/certificates/:/etc/core/certificates/:z
      - ./common/config/core/app.conf:/etc/core/app.conf:z
      - ./common/config/core/private_key.pem:/etc/core/private_key.pem:z
      - ./common/config/core/key:/etc/core/key:z
    networks:
      - harbor
    depends_on:
      - log
      - registry
      - redis
      - postgresql
    logging:
      driver: "syslog"
      options:
        syslog-address: "tcp://localhost:1514"
        tag: "core"

networks:
  harbor:
    external: false

Harbor 配置

yaml
# harbor.yml
hostname: harbor.company.com

http:
  port: 80

https:
  port: 443
  certificate: /your/certificate/path
  private_key: /your/private/key/path

harbor_admin_password: Harbor12345

database:
  password: root123
  max_idle_conns: 100
  max_open_conns: 900

data_volume: /data

trivy:
  ignore_unfixed: false
  skip_update: false
  offline_scan: false
  security_check: vuln
  insecure: false

jobservice:
  max_job_workers: 10

notification:
  webhook_job_max_retry: 10

chart:
  absolute_url: disabled

log:
  level: info
  local:
    rotate_count: 50
    rotate_size: 200M
    location: /var/log/harbor

_version: 2.5.0

proxy:
  http_proxy:
  https_proxy:
  no_proxy:
  components:
    - core
    - jobservice
    - trivy

云仓库服务

Amazon ECR

bash
# 安装 AWS CLI
pip install awscli

# 配置 AWS 凭证
aws configure

# 获取登录令牌
aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-west-2.amazonaws.com

# 创建仓库
aws ecr create-repository --repository-name myapp

# 推送镜像
docker tag myapp:latest 123456789012.dkr.ecr.us-west-2.amazonaws.com/myapp:latest
docker push 123456789012.dkr.ecr.us-west-2.amazonaws.com/myapp:latest

Azure Container Registry

bash
# 安装 Azure CLI
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

# 登录 Azure
az login

# 创建资源组
az group create --name myResourceGroup --location eastus

# 创建 ACR
az acr create --resource-group myResourceGroup --name myregistry --sku Basic

# 登录 ACR
az acr login --name myregistry

# 推送镜像
docker tag myapp:latest myregistry.azurecr.io/myapp:latest
docker push myregistry.azurecr.io/myapp:latest

Google Container Registry

bash
# 安装 Google Cloud SDK
curl https://sdk.cloud.google.com | bash

# 初始化 gcloud
gcloud init

# 配置 Docker 认证
gcloud auth configure-docker

# 推送镜像
docker tag myapp:latest gcr.io/project-id/myapp:latest
docker push gcr.io/project-id/myapp:latest

仓库安全配置

HTTPS 配置

bash
# 生成自签名证书
mkdir -p certs
openssl req \
  -newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key \
  -x509 -days 365 -out certs/domain.crt \
  -subj "/C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost"

# 运行带 HTTPS 的仓库
docker run -d \
  --name registry \
  -p 5000:5000 \
  -v $(pwd)/certs:/certs \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
  -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
  registry:2

基础认证

bash
# 创建密码文件
mkdir auth
docker run --entrypoint htpasswd registry:2 -Bbn testuser testpassword > auth/htpasswd

# 运行带认证的仓库
docker run -d \
  --name registry \
  -p 5000:5000 \
  -v $(pwd)/auth:/auth \
  -e "REGISTRY_AUTH=htpasswd" \
  -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
  -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
  registry:2

# 登录私有仓库
docker login localhost:5000

Token 认证

yaml
# config.yml
version: 0.1
log:
  level: debug
storage:
  filesystem:
    rootdirectory: /var/lib/registry
http:
  addr: :5000
auth:
  token:
    realm: https://auth.company.com/token
    service: registry.company.com
    issuer: auth.company.com
    rootcertbundle: /etc/docker/registry/auth.crt

镜像分发策略

镜像标签策略

bash
# 语义化版本标签
docker tag myapp:latest myapp:1.0.0
docker tag myapp:latest myapp:1.0
docker tag myapp:latest myapp:1

# 环境标签
docker tag myapp:latest myapp:dev
docker tag myapp:latest myapp:staging
docker tag myapp:latest myapp:prod

# Git 提交标签
docker tag myapp:latest myapp:$(git rev-parse --short HEAD)
docker tag myapp:latest myapp:$(git describe --tags)

# 时间戳标签
docker tag myapp:latest myapp:$(date +%Y%m%d-%H%M%S)

多架构镜像

bash
# 创建多架构构建器
docker buildx create --name multiarch --use

# 构建多架构镜像
docker buildx build \
  --platform linux/amd64,linux/arm64,linux/arm/v7 \
  --tag myregistry/myapp:latest \
  --push .

# 查看镜像清单
docker buildx imagetools inspect myregistry/myapp:latest

镜像同步

bash
#!/bin/bash
# sync-images.sh

SOURCE_REGISTRY="source.registry.com"
TARGET_REGISTRY="target.registry.com"
IMAGES=(
  "myapp:latest"
  "myapp:v1.0.0"
  "database:latest"
)

for image in "${IMAGES[@]}"; do
  echo "同步镜像: $image"
  
  # 拉取源镜像
  docker pull $SOURCE_REGISTRY/$image
  
  # 重新标记
  docker tag $SOURCE_REGISTRY/$image $TARGET_REGISTRY/$image
  
  # 推送到目标仓库
  docker push $TARGET_REGISTRY/$image
  
  # 清理本地镜像
  docker rmi $SOURCE_REGISTRY/$image $TARGET_REGISTRY/$image
done

仓库管理

镜像清理

bash
# Registry 垃圾回收
docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml

# 删除未标记的镜像
docker exec registry bin/registry garbage-collect --delete-untagged /etc/docker/registry/config.yml

# 自动清理脚本
#!/bin/bash
# cleanup-registry.sh

REGISTRY_CONTAINER="registry"
DAYS_TO_KEEP=30

# 停止仓库服务
docker stop $REGISTRY_CONTAINER

# 执行垃圾回收
docker run --rm \
  -v registry-data:/var/lib/registry \
  registry:2 \
  bin/registry garbage-collect --delete-untagged /etc/docker/registry/config.yml

# 重启仓库服务
docker start $REGISTRY_CONTAINER

echo "清理完成"

仓库备份

bash
#!/bin/bash
# backup-registry.sh

BACKUP_DIR="/backup/registry"
DATE=$(date +%Y%m%d-%H%M%S)
REGISTRY_DATA="/var/lib/docker/volumes/registry-data/_data"

# 创建备份目录
mkdir -p $BACKUP_DIR

# 停止仓库服务
docker stop registry

# 备份数据
tar czf $BACKUP_DIR/registry-backup-$DATE.tar.gz -C $REGISTRY_DATA .

# 重启仓库服务
docker start registry

# 保留最近 7 天的备份
find $BACKUP_DIR -name "registry-backup-*.tar.gz" -mtime +7 -delete

echo "备份完成: registry-backup-$DATE.tar.gz"

仓库监控

yaml
# docker-compose.monitoring.yml
version: '3.8'

services:
  registry:
    image: registry:2
    ports:
      - "5000:5000"
    volumes:
      - registry-data:/var/lib/registry
    environment:
      - REGISTRY_HTTP_DEBUG_ADDR=0.0.0.0:5001
      - REGISTRY_HTTP_DEBUG_PROMETHEUS_ENABLED=true
    networks:
      - registry-network

  prometheus:
    image: prom/prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    networks:
      - registry-network

  grafana:
    image: grafana/grafana
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana-data:/var/lib/grafana
    networks:
      - registry-network

volumes:
  registry-data:
  grafana-data:

networks:
  registry-network:
    driver: bridge

API 操作

Registry API v2

bash
# 列出仓库
curl -X GET http://localhost:5000/v2/_catalog

# 列出标签
curl -X GET http://localhost:5000/v2/myapp/tags/list

# 获取镜像清单
curl -X GET \
  -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
  http://localhost:5000/v2/myapp/manifests/latest

# 删除镜像
curl -X DELETE http://localhost:5000/v2/myapp/manifests/sha256:digest

自动化脚本

bash
#!/bin/bash
# registry-api.sh

REGISTRY_URL="http://localhost:5000"

list_repositories() {
    curl -s "$REGISTRY_URL/v2/_catalog" | jq -r '.repositories[]'
}

list_tags() {
    local repo=$1
    curl -s "$REGISTRY_URL/v2/$repo/tags/list" | jq -r '.tags[]'
}

get_manifest() {
    local repo=$1
    local tag=$2
    curl -s -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
        "$REGISTRY_URL/v2/$repo/manifests/$tag"
}

delete_image() {
    local repo=$1
    local digest=$2
    curl -X DELETE "$REGISTRY_URL/v2/$repo/manifests/$digest"
}

# 使用示例
case "$1" in
    "list-repos")
        list_repositories
        ;;
    "list-tags")
        list_tags "$2"
        ;;
    "get-manifest")
        get_manifest "$2" "$3"
        ;;
    "delete")
        delete_image "$2" "$3"
        ;;
    *)
        echo "Usage: $0 {list-repos|list-tags|get-manifest|delete} [args...]"
        exit 1
        ;;
esac

最佳实践

仓库设计原则

  1. 命名规范:使用一致的命名约定
  2. 版本管理:实施语义化版本控制
  3. 安全配置:启用 HTTPS 和认证
  4. 访问控制:实施细粒度权限管理
  5. 监控告警:监控仓库健康状态

镜像管理策略

bash
# 镜像生命周期管理
#!/bin/bash
# image-lifecycle.sh

# 开发阶段
docker build -t myapp:dev-$(git rev-parse --short HEAD) .
docker push myregistry/myapp:dev-$(git rev-parse --short HEAD)

# 测试阶段
docker tag myapp:dev-$(git rev-parse --short HEAD) myapp:test-$(date +%Y%m%d)
docker push myregistry/myapp:test-$(date +%Y%m%d)

# 生产发布
docker tag myapp:test-$(date +%Y%m%d) myapp:v1.0.0
docker tag myapp:v1.0.0 myapp:latest
docker push myregistry/myapp:v1.0.0
docker push myregistry/myapp:latest

安全检查清单

  • [ ] 启用 HTTPS 加密
  • [ ] 配置用户认证
  • [ ] 实施访问控制
  • [ ] 定期扫描漏洞
  • [ ] 监控访问日志
  • [ ] 备份重要数据
  • [ ] 更新仓库软件

本章小结

本章全面介绍了 Docker 镜像仓库的各个方面:

关键要点:

  • 仓库类型:公共、私有、云仓库的特点和使用
  • 私有仓库:Registry、Harbor 等解决方案
  • 安全配置:HTTPS、认证、访问控制
  • 镜像管理:标签策略、多架构、同步
  • 运维管理:监控、备份、清理

最佳实践:

  • 选择合适的仓库解决方案
  • 实施安全配置和访问控制
  • 建立镜像生命周期管理
  • 监控仓库健康状态
  • 定期备份和清理

应用场景:

  • 企业内部镜像管理
  • CI/CD 流水线集成
  • 多环境镜像分发
  • 大规模容器部署

掌握镜像仓库的管理技能对于容器化应用的开发和部署至关重要。

延伸阅读

本站内容仅供学习和研究使用。