Categories
docker

用 Nexus 搭建内网 Docker 镜像中心(完整指南)

# 用 Nexus 搭建内网 Docker 镜像中心(完整指南)

本文面向希望在内网搭建 Docker 镜像中心的运维/开发人员,基于已有的 compose 配置(见 nexus/docker-compose.yml),讲清 Hosted / Proxy / Group 三类仓库差异、端口占用与典型部署方案,并提供从启动到导入镜像的实操步骤与常见问题排查。

---

## 目标

搭建一个稳定的内网 Docker 镜像中心,满足以下需求:
- 私有镜像的推送与存储(CI -> hosted)
- 对外镜像的本地缓存(proxy)以节省带宽并提升可用性
- 对客户端暴露统一拉取入口(group),降低客户端配置复杂度
- 提供可运维、可监控的部署方案,支持 TLS 与反向代理

---

## 关键概念(一眼看懂)

- hosted:私有仓库,支持 docker push。用于存放你/团队构建的镜像,数据保存在 Nexus 的 blob store。
- proxy:远程代理仓库,指向像 Docker Hub 这样的远端 registry。首次拉取会从远端拉取并缓存到本地,后续命中缓存返回。
- group:聚合仓库,把多个 hosted/proxy 合并为一个统一入口。客户端只需配置 group 地址即可访问所有成员仓库(通常用于 pull)。

典型流程:CI 将镜像 push 到 hosted,客户端 pull 时指向 group。group 内既有 hosted(私有镜像),也有 proxy(缓存公共镜像)。

---

## 端口与网络模型(重要)

Nexus 的每个 Docker 仓库(connector)都通过一个独立的监听端口暴露(HTTP 或 HTTPS)。因此:

- 每个 connector 会占用一个 TCP 监听端口(示例本仓库:8082/8083/8084)。
- 同一端口不能同时被多个 connector 绑定。
- 不建议为大量仓库直接在外网暴露大量端口(管理/运维复杂且易冲突)。

推荐做法:在边缘层使用反向代理(Nginx / Traefik),对外仅暴露标准端口(443),根据 Host/SNI 或路径将请求路由到 Nexus 的内部端口。优点:统一 TLS 管理、只需暴露 443、避免客户端配置 insecure-registries。

---

## 快速上手(实操步骤)

假设仓库内已有示例 compose:`nexus/docker-compose.yml`(已包含端口映射 8081/8082/8083/8084)。

1) 启动 Nexus

```bash
docker compose -f nexus/docker-compose.yml up -d
```

查看日志(首次启动较慢):

```bash
docker compose -f nexus/docker-compose.yml logs -f
```

获取初始管理员密码:

```bash
docker exec nexus cat /nexus-data/admin.password
```

打开管理界面: http://<你的机器IP>:8081 ,使用 admin + 初始密码登录。

2) 创建仓库
- Settings -> Repositories -> Create repository
- 新建 `docker (hosted)`:示例命名 `docker-hosted`,HTTP port 设置为 8082,配置 Blob store 与部署策略(Allow redeploy 或 Disable redeploy)。
- 新建 `docker (proxy)`:示例命名 `docker-proxy`,HTTP port 设置为 8083,Remote storage 填 `https://registry-1.docker.io`。
- 新建 `docker (group)`:示例命名 `docker-group`,HTTP port 设置为 8084,成员选择 `docker-hosted` 与 `docker-proxy`。

3) 启用 Docker 登录能力

Settings -> Security -> Realms,把 `Docker Bearer Token Realm` 放到 Active 列表并保存(否则 docker login / push 可能失败)。

4) 客户端配置(HTTP / TLS)

如果你暂时用 HTTP(非 TLS):需要将 Nexus 端口添加到 Docker 的 insecure-registries,如:

/etc/docker/daemon.json
```json
{
  "insecure-registries": ["<你的IP>:8082", "<你的IP>:8084"]
}
```
重启 Docker 服务: sudo systemctl restart docker

生产建议:使用 TLS + 反向代理(推荐)。

5) 登录并推送/拉取
- 推送到 hosted:
  docker login <你的IP>:8082
  docker tag myapp:1.0 <你的IP>:8082/myapp:1.0
  docker push <你的IP>:8082/myapp:1.0

- 客户端拉取使用 group:
  docker pull <你的IP>:8084/myapp:1.0

---

## 导入已有镜像(两种方式)

方式 A:本机已有镜像

```bash
docker images
docker tag myapp:1.0 <你的IP>:8082/myapp:1.0
docker push <你的IP>:8082/myapp:1.0
```

方式 B:镜像 tar 包

```bash
docker load -i myapp.tar
docker tag myapp:1.0 <你的IP>:8082/myapp:1.0
docker push <你的IP>:8082/myapp:1.0
```

---

## 常见问题与排查清单

- docker login 失败:确认已启用 `Docker Bearer Token Realm`,用户名/密码正确。
- http: server gave HTTP response to HTTPS client:客户端尝试 HTTPS,但服务为 HTTP → 配置 insecure-registries 或启用 TLS。
- push 返回 403/unauthorized:检查登录用户权限,确认推送目标为 hosted(不是 group 或 proxy)。
- 页面能打开但无法 push:确认仓库类型为 `docker (hosted)` 且 HTTP Connector 正确配置。

---

## 端口策略与反代建议(详析)

场景一:小型团队 / 测试环境
- 可以直接将 Nexus 的 8082/8083/8084 端口映射并在内部网络中使用,配合 `insecure-registries`。

场景二:生产 / 企业环境
- 在边缘使用 Nginx/Traefik 做 TLS 终结与路由:对外仅暴露 443,并用 Host/SNI 路由到 Nexus 的相应内部端口(或仅路由到 group)。
- 优势:统一证书管理、避免客户端修改 Docker 配置、便于接入 WAF/流量监控。

示例 Nginx 配置(简化):

```nginx
server {
    listen 443 ssl;
    server_name registry.example.com;

    ssl_certificate /path/to/fullchain.pem;
    ssl_certificate_key /path/to/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8084; # 转到 group
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
```

提示:如果需要同时对外提供多个 registry,可以用不同 subdomain(registry.team-a.example / registry.team-b.example),反向代理根据 Host 分流到不同 Nexus connectors 或不同 Nexus 实例。

---

## 监控、清理与权限管理

- 清理策略(Cleanup Policy):定期清理未使用或过期的 tag,避免磁盘被镜像占满。
- 磁盘告警:监控 /nexus-data 所在磁盘的使用率。
- 访问控制:把 Nexus 接入 LDAP/SSO,使用角色与仓库级权限限制 push/pull 能力。
- 审计:启用 Nexus 的日志与审计,便于追踪谁在什么时候 push 了什么镜像。

---

## 结论与下一步建议

- 模式:push->hosted,pull->group(group 包含 hosted+proxy)是最常见且易运维的模式。
- 端口:Connector 与端口是一一对应关系;生产用反向代理把外部流量归一到 443。
- 安全:生产环境请务必使用 HTTPS,并将权限/认证纳入统一认证系统(LDAP/SSO)。

以下为仓库内示例 `docker-compose.yml` 的完整内容(已嵌入):

```yaml
version: "3.8"

services:
  nexus:
    image: sonatype/nexus3:latest
    container_name: nexus
    restart: unless-stopped
    ports:
      - "8081:8081" # Nexus UI
      - "8082:8082" # Docker hosted (push)
      - "8083:8083" # Docker proxy (remote cache)
      - "8084:8084" # Docker group (pull/aggregate)
    volumes:
      - ./nexus-data:/nexus-data
    environment:
      # Optional: tune JVM memory if needed
      - INSTALL4J_ADD_VM_PARAMS=-Xms1200m -Xmx1200m
```