JFrog Container Registry Subdomain mode

JFrog Container Registry 支持 Subdomain 模式,主要用于优化多仓库场景下的镜像拉取和推送操作。

在 Subdomain 模式下,每个仓库(repository)都通过不同的子域名来访问,而不是通过传统路径访问。例如:

Repositpry Path 模式(传统路径):

1
docker pull artifactory-jcr.warnerchen.com/docker-service-broker-tmp-local/library/nginx:mainline

Subdomain 模式:

1
docker pull docker-service-broker-tmp-local.artifactory-jcr.warnerchen.com/library/nginx:mainline

也就是说,仓库名变成了主机名的一部分。

Subdomain 支持 Apache、Nginx、Tomcat,此处测试 Apache 和 Nginx。

部署 JFrog Container Registry

1
2
3
helm repo add jfrog https://charts.jfrog.io
helm repo update
helm upgrade --install jfrog-container-registry --set artifactory.postgresql.postgresqlPassword=<postgres_password> jfrog/artifactory-jcr --namespace artifactory-jcr --create-namespace

获取 Service 信息,后续会用到:

1
2
3
4
5
6
7
root@rke2-cilium-01:~# kubectl -n artifactory-jcr get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
artifactory-jcr ClusterIP 10.43.83.174 <none> 8082/TCP,8085/TCP,8081/TCP 21d
artifactory-jcr-artifactory-nginx NodePort 10.43.252.158 <none> 80:31152/TCP,443:31837/TCP 21d
artifactory-jcr-nodeport NodePort 10.43.229.183 <none> 8082:32636/TCP,8085:32222/TCP,8081:32098/TCP 21d
artifactory-jcr-postgresql ClusterIP 10.43.222.157 <none> 5432/TCP 21d
artifactory-jcr-postgresql-headless ClusterIP None <none> 5432/TCP 21d

准备自签证书

准备一个 VM 作为 Proxy,安装 Docker/Podman。

然后参考链接创建证书:https://docs.rancher.cn/docs/rancher2/installation/resources/advanced/self-signed-ssl/_index/#4-%E5%A6%82%E4%BD%95%E7%94%9F%E6%88%90%E8%87%AA%E7%AD%BE%E5%90%8D%E8%AF%81%E4%B9%A6

将证书存放到指定目录下:

1
mkdir -pv ~/artifactory-jcr/tls
1
2
root@test-0:~# ls ~/artifactory-jcr/tls/
tls.crt tls.key

Apache

默认情况下模式为 Repositpry Path,部署完成后,先通过 Ingress/NodePort 访问 JFrog Container Registry,将模式设置为 Subdomain:

在安装了 Proxy VM 中,创建目录:

1
mkdir -pv ~/artifactory-jcr/apache_subdomain/conf.d

在生成的配置文件中,将 x.x.x.x:8081x.x.x.x:8082 修改成对应的 NodePort,然后保存到上面的目录中:

1
2
3
4
5
6
7
8
9
root@test-0:~/artifactory-jcr/apache_subdomain/conf.d# grep 172.16.16.120 default.conf
ProxyPass "/artifactory/" http://172.16.16.120:32098/artifactory/
ProxyPassReverse "/artifactory/" http://172.16.16.120:32098/artifactory/
ProxyPass "/" http://172.16.16.120:32636/ nocanon
ProxyPassReverse "/" http://172.16.16.120:32636/
ProxyPass "/artifactory/" http://172.16.16.120:32098/artifactory/
ProxyPassReverse "/artifactory/" http://172.16.16.120:32098/artifactory/
ProxyPass "/" http://172.16.16.120:32636/ nocanon
ProxyPassReverse "/" http://172.16.16.120:32636/

创建 Apache 全局配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
cat <<EOF > ~/artifactory-jcr/apache_subdomain/httpd.conf
ServerRoot "/usr/local/apache2"
Listen 80
Listen 443
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule reqtimeout_module modules/mod_reqtimeout.so
LoadModule filter_module modules/mod_filter.so
LoadModule mime_module modules/mod_mime.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule env_module modules/mod_env.so
LoadModule headers_module modules/mod_headers.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule status_module modules/mod_status.so
LoadModule autoindex_module modules/mod_autoindex.so
<IfModule !mpm_prefork_module>
</IfModule>
<IfModule mpm_prefork_module>
</IfModule>
LoadModule dir_module modules/mod_dir.so
LoadModule alias_module modules/mod_alias.so
LoadModule rewrite_module modules/mod_rewrite.so
<IfModule unixd_module>
User www-data
Group www-data
</IfModule>
ServerAdmin you@example.com
<Directory />
AllowOverride none
Require all denied
</Directory>
DocumentRoot "/usr/local/apache2/htdocs"
<Directory "/usr/local/apache2/htdocs">
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
<IfModule dir_module>
DirectoryIndex index.html
</IfModule>
<Files ".ht*">
Require all denied
</Files>
ErrorLog /proc/self/fd/2
LogLevel warn
<IfModule log_config_module>
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
<IfModule logio_module>
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
</IfModule>
CustomLog /proc/self/fd/1 common
</IfModule>
<IfModule alias_module>
ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/"
</IfModule>
<IfModule cgid_module>
</IfModule>
<Directory "/usr/local/apache2/cgi-bin">
AllowOverride None
Options None
Require all granted
</Directory>
<IfModule headers_module>
RequestHeader unset Proxy early
</IfModule>
<IfModule mime_module>
TypesConfig conf/mime.types
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
</IfModule>
<IfModule proxy_html_module>
Include conf/extra/proxy-html.conf
</IfModule>
<IfModule ssl_module>
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
</IfModule>
Include conf/conf.d/*.conf
EOF

获取 mime.type 文件:

1
podman run --rm harbor.warnerchen.com/library/httpd:2.4 cat /usr/local/apache2/conf/mime.types > ~/artifactory-jcr/apache_subdomain/mime.types

目录结构如下:

1
2
3
4
5
6
7
8
root@test-0:~# tree ~/artifactory-jcr/apache_subdomain
/root/artifactory-jcr/apache_subdomain
├── conf.d
│   └── default.conf
├── httpd.conf
└── mime.types

1 directory, 3 files

启动 Apache:

1
podman run -d --name apache-subdomain -p 80:80 -p 443:443 -v /root/artifactory-jcr/apache_subdomain:/usr/local/apache2/conf -v /root/artifactory-jcr/tls:/etc/ssl harbor.warnerchen.com/library/httpd:2.4

将 JFrog Container Registry 的域名映射调整为 Proxy 的 IP,检查是否能够正常访问:

尝试 Push 镜像:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
root@test-0:~# podman login docker-service-broker-tmp-local.artifactory-jcr.warnerchen.com --tls-verify=false -u xxx -p xxx
Login Succeeded!
root@test-0:~# podman push docker-service-broker-tmp-local.artifactory-jcr.warnerchen.com/devop/test/warner/nginx:mainline-podman --tls-verify=false
Getting image source signatures
Copying blob 7dca41ff1486 skipped: already exists
Copying blob a0c145a29c8d skipped: already exists
Copying blob ffe4285e2906 skipped: already exists
Copying blob 19b722697f76 skipped: already exists
Copying blob c3548211b826 skipped: already exists
Copying blob a1fe8b721bb1 skipped: already exists
Copying blob 61ef4e878aac skipped: already exists
Copying blob 88a3676c9d4f skipped: already exists
Copying config cefb6db338 done
Writing manifest to image destination
Storing signatures

Nginx

在 JFrog Container Registry 中,将 Apache 修改为 Nginx:

在安装了 Proxy VM 中,创建目录:

1
mkdir -pv ~/artifactory-jcr/nginx_subdomain

在生成的配置文件中,将 x.x.x.x:8081x.x.x.x:8082 修改成对应的 NodePort,然后保存到上面的目录中:

1
2
3
root@test-0:~/artifactory-jcr/nginx_subdomain# grep "172.16.16.120" default.conf
proxy_pass http://172.16.16.120:32636;
proxy_pass http://172.16.16.120:32098;

Nginx 相比 Apache 较为方便,准备好配置文件即可启动 Nginx:

1
podman run -d --name nginx-subdomain -p 80:80 -p 443:443 -v /root/artifactory-jcr/nginx-subdomain/default.conf:/etc/nginx/conf.d/default.conf -v /root/artifactory-jcr/tls:/etc/ssl harbor.warnerchen.com/library/nginx:mainline
Author

Warner Chen

Posted on

2025-08-05

Updated on

2025-08-06

Licensed under

You need to set install_url to use ShareThis. Please set it in _config.yml.
You forgot to set the business or currency_code for Paypal. Please set it in _config.yml.

Comments

You forgot to set the shortname for Disqus. Please set it in _config.yml.