GX博客

分享个人 Full-Stack JavaScript 项目开发经验

使用Docker Stack部署私有镜像仓库和Docker Registry UI

本文并不打算详细地解释每部分内容背后的基础知识,而是要按步骤介绍如何使用 Docker Stack 在生产环境部署一个单节点的私有 Docker 镜像仓库服务,并使用 Nginx 作为 SSL 连接器部署 Docker Registry UI 作为一个简单的可视化镜像管理服务。


部署服务

1、在 Docker 主机恰当位置创建密码文件目录:

mkdir auth

2、拉取 registry:2 镜像:

docker pull registry:2

3、重写 registry:2 镜像入口点,并保存认证账号密码到 auth/htpasswd 文件:

docker run --entrypoint htpasswd registry:2 -Bbn <auth-username> <auth-password> > auth/htpasswd

4、切换 Docker 为 Swarm 模式:

docker swarm init

5、添加节点标签,用于节点约束,使其部署为单节点镜像仓库:

docker node ls
docker node update --label-add registry=yes <node-id>

6、创建域名证书 Docker secret:

docker secret create domain.pem <crt-path>
docker secret create domain.key <key-path>

7、准备 Stack 声明文件 docker-stack-registry.yml(具体的域名端口和卷挂载路径等按照自己实际情况编写):

version: "3.5"
networks:
  registry_network:
services:
  registry-ui:
    image: joxit/docker-registry-ui:static
    networks:
      - registry_network
    ports:
      - target: 80
        published: 5100
        mode: host
    environment:
      REGISTRY_URL: https://www.leeguangxing.cn:5000
      PULL_URL: https://www.leeguangxing.cn:5000
      REGISTRY_TITLE: leeguangxing.cn
      DELETE_IMAGES: 'true'
    deploy:
      replicas: 1
      update_config:
        parallelism: 1
        failure_action: rollback
      placement:
        constraints:
          - 'node.labels.registry == yes'
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
        window: 120s
  registry:
    image: registry:2
    networks:
      - registry_network
    ports:
      - target: 443
        published: 5000
        mode: host
    environment:
      REGISTRY_HTTP_ADDR: 0.0.0.0:443
      REGISTRY_HTTP_TLS_CERTIFICATE: /run/secrets/domain.pem
      REGISTRY_HTTP_TLS_KEY: /run/secrets/domain.key
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
      REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
      REGISTRY_STORAGE_DELETE_ENABLED: 'true'
    secrets:
      - domain.pem
      - domain.key
    volumes:
      - /var/docker-registry/registry:/var/lib/registry
      - /var/docker-registry/auth:/auth
      - /var/docker-registry/garbage:/garbage
    deploy:
      replicas: 1
      update_config:
        parallelism: 1
        failure_action: rollback
      placement:
        constraints:
          - 'node.labels.registry == yes'
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
        window: 120s
secrets:
  domain.pem:
    external: true
  domain.key:
    external: true

部署 Stack:

docker stack deploy -c docker-stack-registry.yml <stack-name> 

8、添加 Docker Registry UI 的 Nginx SSL 配置(具体的证书、端口等配置按照自己实际情况编写)registry_ui.conf:

upstream registry_ui_website {
  server 127.0.0.1:5100;
  keepalive 32;
}

server {
  listen 5200 ssl;

  server_name leeguangxing.cn www.leeguangxing.cn;

  ssl_certificate /crt/certificate.pem;

  ssl_certificate_key /crt/certificate.key;

  ssl_session_cache shared:WEB:10m;

  ssl_ciphers RC4:HIGH:!aNULL:!MD5:@STRENGTH;

  ssl_prefer_server_ciphers on;

  access_log off;

  location / {
    proxy_pass http://registry_ui_website;
  }

  error_page   500 502 503 504  /50x.html;
  location = /50x.html {
    root  /usr/share/nginx/html;
  }
}

Docker Registry UI 介绍展示。

镜像列表:

镜像列表

标签列表:


镜像构建历史:


Docker 客户端操作

下面是一个向私有镜像仓库推送镜像及标签的操作例子。

1、使用设定的账号密码登录私有镜像仓库:

docker login leeguangxing.cn:5000

2、为镜像添加新标签:

docker tag nginx leeguangxing.cn:5000/web-demo:latest

3、推送到新的镜像仓库:

docker push leeguangxing.cn:5000/web-demo:latest

已知问题

目前没有 HTTP API 可以删除整个镜像,当镜像下的所有标签都被删除后,镜像目录仍然存在。若要删除残留的镜像信息,需要手动删除对应镜像文件夹(具体路径取决与你挂载的卷位置)。但要注意,不要直接删除镜像目录,而是通过 HTTP API 删除所有镜像标签后,执行垃圾回收,最后再删除镜像残留目录。

执行镜像垃圾回收(添加 --dry-run 参数,则不删除任何数据,只打印扫描结果):

docker container exec -it <registry-container-id or name> /bin/registry garbage-collect /garbage/config.yml

其中 config.yml 指定镜像在容器中保存的目录:

version: 0.1
storage:
  filesystem:
    rootdirectory: /var/lib/registry

删除镜像目录:

rm -r docker/registry/v2/repositories/<image-name> 

扩展

可以根据项目需要,对私有镜像仓库进行集群部署,提高可用性。集群节点间共享高速存储,但程序要考虑读写冲突问题。

版权声明:

本文为博主原创文章,若需转载,须注明出处,添加原文链接。

https://leeguangxing.cn/blog_post_80.html