使用JFrog Artifactory管理构件
Artifactory是JFrog出品的全功能构件管理器。所谓构件,可以表示任何软件构建过程的产出,包括:Docker镜像、NPM包、RPM/Debian等操作系统安装包、Helm Chart、Maven构建,等等。
Artifactory包含一套产品,我们尝试的是它的开源版本Artifactory OSS。该版本提供的特性包括:
- 基本的构件管理功能:
- 代理、缓存远程构件
- 批量的构件上传
- 为存储的构件设置包含/排除规则
- 通过REST或者UI上传构件
- 通过UI增删改查构件
- 基于Checksum的存储,支持去重
- 和主流的CI服务器集成
- 强大的REST API
- 安全性:
- LDAP身份验证
- 基于角色的访问控制
- 根据名称、属性、归档、Checksum值来检索
- 构件查询语言AQL
- 增量备份服务
- 构件发生变化后邮件提醒
示例脚本:
1 2 3 4 5 6 7 8 9 10 11 12 |
#!/bin/bash docker stop artifactory && docker rm artifactory docker run --name artifactory -h artifactory --network local --ip 172.21.0.13 --dns 172.21.0.1 \ --user 0 --restart=always --restart=always -d \ # 挂载数字证书 -v /etc/letsencrypt/live/gmem.cc/fullchain.pem:/etc/ssl/tls.crt -v /etc/letsencrypt/live/gmem.cc/privkey.pem:/etc/ssl/tls.key \ # 使用宿主机目录作为存储 -v /home/alex/Docker/volumes/artifactory:/var/opt/jfrog/artifactory \ -e SERVER_XML_ARTIFACTORY_PORT=80 \ # 开启HTTPS支持 -e SERVER_XML_EXTRA_CONNECTOR='<Connector port="443" scheme="https" secure="true" SSLEnabled="true" SSLCertificateFile="/etc/ssl/tls.crt" SSLCertificateKeyFile="/etc/ssl/tls.key" SSLProtocol="TLSv1" />' \ docker.gmem.cc/jfrog/artifactory-oss:latest |
打开Artifactory的Web UI,可以看到左侧边栏提供以下功能链接:
- Home,显示一个仪表盘,以及常用功能的入口
- Artifacts,浏览构件仓库、检索构件。显示构件仓库的用法,例如Maven配置片段、上传构件的curl命令
- Search,根据名称、包类型、属性,以及一些列额外的方法来检索构件
- Builds,可以查看所有的CI服务器用于输出其构件到Artifactory的项目
- Admin,仅管理员角色能够使用,用于:
- 配置仓库、软件License、代理、邮件服务器等实体
- 管理用户、组、权限、LDAP集成等安全方面的内容
- 管理备份、仓库的索引
- 导入、导出仓库
- 管理系统信息
- 调度清理操作
在Home、Artifacts等模块有此功能的入口。这个特性能够提示给你部署、解析构件的命令。支持将你的访问凭证注入到命令中。
点击右上角的Welcome ...下拉菜单,可以看到创建仓库的按钮。仓库分为以下几种形式:
- 本地仓库(Local Repository):真实的物理仓库,构件存放在此Artifactory上
- 远程仓库(Remote Repository):真实的物理仓库,构件存放在远程服务器上。本地实际上是远程服务的缓存代理(注意不是镜像),你只能删除缓存中的构件,不能删除远程服务器上的构件
- 虚拟仓库(Virtual Repository):多个物理仓库的聚合(为单个URL),用于简化构件的搜索、解析,也叫仓库组(Repository group)。当像虚拟仓库请求构件时,搜索顺序如下:
- 本地仓库
- 远程仓库缓存
- 远程仓库
- 发布仓库(Distribution Repository)
创建仓库时,必须指定包类型,OSS版本支持以下包类型:
- Generic:没有特定类型,你可以上传任何构件,不维护包索引
- Gradle
- Ivy:Ivy构件仓库
- Maven:Maven构件仓库
这是一个命令行工具,可用来操控Artifactory。
1 |
jfrog target command-name global-options command-options arguments |
目标 | 说明 |
rt | JFrog Artifactory |
bt | JFrog Bintray |
mc | JFrog Mission Control |
xr | JFrog Xray |
1 2 |
jfrog rt u file.txt repo0/new/artifact/directory/ --user=user --password=pswd # --apiKey=xxx |
支持多种身份验证方式:
- HTTP基本验证:用户名 + 密码
- HTTP基本验证:用户名 + API Key
- HTTP基本验证:用户名 + 访问令牌
- 请求头X-JFrog-Art-Api,设置为API Key
- 不记名令牌:Authorization: Bearer API Key
上传一个构件到repo0仓库下的new/artifact/directory目录结构下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 使用用户名密码 curl -u user:pswd -X PUT \ "https://artifactory.gmem.cc/artifactory/repo0/new/artifact/directory/file.txt" \ -T file.txt # 使用API Key curl -H "X-JFrog-Art-Api:ABcdEF" -X PUT \ "https://artifactory.gmem.cc/artifactory/repo0/new/artifact/directory/file.txt" \ -T file.txt # 使用不记名令牌 curl -H "Authorization: Bearer <Token>" -X "https://artifactory.gmem.cc/artifactory/repo0/new/artifact/directory/file.txt" \ -T file.txt |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// GET /api/storage/{repoKey}/{folder-path} // GET /api/storage/libs-release-local/org/acme { "uri": "http://localhost:8081/artifactory/api/storage/libs-release-local/org/acme", "repo": "libs-release-local", "path": "/org/acme", "created": ISO8601 (yyyy-MM-dd'T'HH:mm:ss.SSSZ), "createdBy": "userY", "lastModified": ISO8601 (yyyy-MM-dd'T'HH:mm:ss.SSSZ), "modifiedBy": "userX", "lastUpdated": ISO8601 (yyyy-MM-dd'T'HH:mm:ss.SSSZ), "children": [ { "uri" : "/child1", "folder" : "true" },{ "uri" : "/child2", "folder" : "false" } ] } |
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 |
// GET /api/storage/{repoKey}/{filePath} // GET /api/storage/libs-release-local/org/acme/lib/ver/lib-ver.pom { "uri": "http://localhost:8081/artifactory/api/storage/libs-release-local/org/acme/lib/ver/lib-ver.pom", "downloadUri": "http://localhost:8081/artifactory/libs-release-local/org/acme/lib/ver/lib-ver.pom", "repo": "libs-release-local", "path": "/org/acme/lib/ver/lib-ver.pom", "remoteUrl": "http://some-remote-repo/mvn/org/acme/lib/ver/lib-ver.pom", "created": ISO8601 (yyyy-MM-dd'T'HH:mm:ss.SSSZ), "createdBy": "userY", "lastModified": ISO8601 (yyyy-MM-dd'T'HH:mm:ss.SSSZ), "modifiedBy": "userX", "lastUpdated": ISO8601 (yyyy-MM-dd'T'HH:mm:ss.SSSZ), "size": "1024", //bytes "mimeType": "application/pom+xml", "checksums": { "md5" : string, "sha1" : string, "sha256" : string }, "originalChecksums":{ "md5" : string, "sha1" : string, "sha256" : string } } |
1 2 3 4 5 6 |
// GET /api/storage/{repoKey}/{item-path}?lastModified // GET /api/storage/libs-release-local/org/acme?lastModified { "uri": "http://localhost:8081/artifactory/api/storage/libs-release-local/org/acme/foo/1.0-SNAPSHOT/foo-1.0-SNAPSHOT.pom", "lastModified": ISO8601 } |
1 2 3 4 5 6 7 8 9 |
// GET /api/storage/{repoKey}/{itemPath}?properties[=x[,y]] // GET /api/storage/libs-release-local/org/acme?properties\[=x[,y]\] { "uri": "http://localhost:8081/artifactory/api/storage/libs-release-local/org/acme" "properties":{ "p1": ["v1","v2","v3"], "p2": ["v4","v5","v6"] } } |
1 2 |
# PUT /api/storage/{repoKey}/{itemPath}?properties=p1=v1[,v2][|p2=v3][&recursiveProperties=1] PUT /api/storage/libs-release-local/ch/qos/logback/logback-classic/0.9.9?properties=os=win,linux|qa=done&recursiveProperties=1 |
1 2 3 4 5 6 7 8 9 |
# PATCH /api/metadata/{repoKey}/{itemPath}?[&recursiveProperties=1] # PATCH /api/metadata/libs-release-local/org/acme?[recursiveProperties=1] { "props":{ "newKey": "newValue", "existingKey": "modifiedValue", "toBeRemovedKey": null } } |
1 2 |
# DELETE /api/storage/{repoKey}{itemPath}?properties=p1[,p2][&recursiveProperties=1] DELETE /api/storage/libs-release-local/ch/qos/logback/logback-classic/0.9.9?properties=os,qa&recursiveProperties=1 |
1 2 |
# GET /repo-key/path/to/artifact.ext GET http://localhost:8081/artifactory/libs-release-local/ch/qos/logback/logback-classic/0.9.9/logback-classic-0.9.9.jar |
该接口允许获取最新的构件:
- 同一快照版本的Maven构件,允许存在多个副本,在存储方面,会使用时间戳后缀来区分文件名。该接口可以下载时间戳最新的版本:
1GET http://localhost:8081/artifactory/libs-release-local/ch/qos/logback/logback-classic/0.9.9-SNAPSHOT/logback-classic-0.9.9-SNAPSHOT.jar - 对于Release版本,直接下载:
1GET http://localhost:8081/artifactory/ivy-local/org/acme/[RELEASE]/acme-[RELEASE].jar
允许下载和某个Build相关的所有Artifact。
你可以下载压缩包中的一个文件:
1 |
GET http://localhost:8081/artifactory/repo1-cache/commons-lang/commons-lang/2.6/commons-lang-2.6.jar!/META-INF/LICENSE.txt |
1 2 3 4 5 6 7 8 9 10 |
# PUT /repo-key/path/to/directory/ # PUT /libs-release-local/path/to/directory/ { "uri": "http://localhost:8081/artifactory/libs-release-local/path/to/directory", "repo": "libs-release-local", "path": "/path/to/directory", "created": ISO8601 (yyyy-MM-dd'T'HH:mm:ss.SSSZ), "createdBy": "userY", "children" : [ ] } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// PUT /repo-key/path/to/artifact.ext // PUT /libs-release-local/my/jar/1.0/jar-1.0.jar { "uri": "http://localhost:8081/artifactory/libs-release-local/my/jar/1.0/jar-1.0.jar", "downloadUri": "http://localhost:8081/artifactory/libs-release-local/my/jar/1.0/jar-1.0.jar", "repo": "libs-release-local", "path": "/my/jar/1.0/jar-1.0.jar", "created": ISO8601 (yyyy-MM-dd'T'HH:mm:ss.SSSZ), "createdBy": "userY", "size": "1024", //bytes "mimeType": "application/java-archive", "checksums":{ "md5" : string, "sha1" : string }, "originalChecksums":{ "md5" : string, "sha1" : string } } |
可以把多个构件打成压缩包,一起上传。你必须在压缩包中保持目录结构。
1 2 |
# PUT path1/to/repo-key/ /path2/to/archive.zip PUT /libs-release-local/ /Users/user/Desktop/archive.zip |
此API可用于删除本地仓库、远程仓库缓存中的目录、文件:
1 2 |
# DELETE /repo-key/path/to/file-or-folder DELETE http://localhost:8081/artifactory/libs-release-local/ch/qos/logback/logback-classic/0.9.9 |
仅仅支持本地仓库,复制构件或目录:
1 2 3 4 5 6 7 8 9 10 |
// POST /api/copy/{srcRepoKey}/{srcFilePath}?to=/{targetRepoKey}/{targetFilePath}[&dry=1][&suppressLayouts=0/1(default)][&failFast=0/1] // POST /api/copy/libs-release-local/org/acme?to=/ext-releases-local/org/acme-new&dry=1 { "messages" : [ { "level": "error", "message": "The repository has denied...." },... ] } |
仅仅支持本地仓库,移动构件或目录:
1 2 3 4 5 6 7 8 9 10 |
// POST /api/move/{srcRepoKey}/{srcFilePath}?to=/{targetRepoKey}/{targetFilePath}[&dry=1][&suppressLayouts=0/1(default)][&failFast=0/1] // POST /api/move/libs-release-local/org/acme?to=/ext-releases-local/org/acme-new&dry=1 { "messages" : [ { "level": "error", "message": "The repository has denied...." },... ] } |
1 |
POST /api/trash/empty |
1 |
DELETE /api/trash/clean/npm-local |
1 2 |
# POST /api/trash/restore/{from path}?to={to path} POST /api/trash/restore/npm-local?to=npm-local2 |
1 |
POST /api/system/storage/gc |
1 2 3 4 5 6 7 8 9 10 11 |
// GET /api/search/artifact?name=name[&repos=x[,y]] // GET /api/search/artifact?name=lib&repos=libs-release-local { "results": [ { "uri": "http://localhost:8081/artifactory/api/storage/libs-release-local/org/acme/lib/ver/lib-ver.pom" },{ "uri": "http://localhost:8081/artifactory/api/storage/libs-release-local/org/acme/lib/ver2/lib-ver2.pom" } ] } |
可以用于搜索构件中包含的Java类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// GET /api/search/archive?name=[archiveEntryName][&repos=x[,y]] // GET /api/search/archive?name=*Logger.class&repos=third-party-releases-local,repo1-cache { "results" :[ { "entry": "org/apache/jackrabbit/core/query/lucene/AbstractIndex.LoggingPrintStream.class", "archiveUris": [ "http://localhost:8081/artifactory/api/storage/third-party-releases-local/org/apache/jackrabbit/ jackrabbit-core/1.2.3/jackrabbit-core-1.2.3.jar", "http://localhost:8081/artifactory/api/storage/third-party-releases-local/org/apache/jackrabbit/ jackrabbit-core/1.3.1/jackrabbit-core-1.3.1.jar" ] },{ "entry": "org/codehaus/plexus/logging/AbstractLogger.class", "archiveUris": [ "http://localhost:8081/artifactory/api/storage/repo1-cache/org/codehaus/plexus/plexus-container-default/ 1.0-alpha-9-stable-1/plexus-container-default-1.0-alpha-9-stable-1.jar" ] } ] } |
根据Maven坐标来搜索构件:
1 2 3 4 5 6 7 8 9 10 11 |
// GET /api/search/gavc?[g=groupId][&a=artifactId][&v=version][&c=classifier][&repos=x[,y]] // GET /api/search/gavc?g=org.acme&a=artifact&v=1.0&c=sources&repos=libs-release-local { "results": [ { "uri": "http://localhost:8081/artifactory/api/storage/libs-release-local/org/acme/artifact/1.0/artifact-1.0-sources.jar" },{ "uri": "http://localhost:8081/artifactory/api/storage/libs-release-local/org/acme/artifactB/1.0/artifactB-1.0-sources.jar" } ] } |
1 2 3 4 5 6 7 8 9 10 11 |
// GET /api/search/prop?[p1=v1,v2][&p2=v3][&repos=x[,y]] // GET /api/search/prop?p1=v1,v2&p2=v3&repos=libs-release-local { "results" : [ { "uri": "http://localhost:8081/artifactory/api/storage/libs-release-local/org/acme/lib/ver/lib-ver.pom" },{ "uri": "http://localhost:8081/artifactory/api/storage/libs-release-local/org/acme/lib/ver2/lib-ver2.pom" } ] } |
REST API提供创建、修改、删除、锁定、解锁用户的功能。
下面的API用于创建当前用户的API Key,如果Key已经存在,返回错误:
1 2 3 4 5 |
// POST /api/security/apiKey // POST /api/security/apiKey { "apiKey": "3OloposOtVFyCMrT+cXmCAScmVMPrSYXkWIjiyDCXsY=" } |
下面的API用于(重新)生成当前用户的API Key,不会返回错误:
1 2 3 4 |
// PUT /api/security/apiKey { "apiKey": "3OloposOtVFyCMrT+cXmCAScmVMPrSYXkWIjiyDCXsY=" } |
APIKey以及下面的令牌,都支持创建、撤销、取回等API。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// POST /api/security/token // curl -uadmin:password -XPOST "http://localhost:8081/artifactory/api/security/token" // -d "username=johnq" // -d "scope=member-of-groups:readers" // -d "refreshable=false" 是否可刷新 { // 令牌内容 "access_token": "adsdgbtybbeeyh...", // 有效期 "expires_in": 3600, // 可访问哪些API "scope": "api:* member-of-groups:readers", // 令牌类型 "token_type": "Bearer", "refresh_token": "fgsfgsdugh8dgu9s8gy9hsg..." } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// GET /api/repositories[?type=repositoryType (local|remote|virtual|distribution)][&packageType=maven|gradle|ivy|sbt|helm|cocoapods|opkg|rpm|nuget|cran|gems|npm|bower|debian|composer|pypi|docker|vagrant|gitlfs|go|yum|conan|chef|puppet|generic] // GET /api/repositories [ { "key" : "libs-releases-local", "type" : "LOCAL", "description" : "Local repository for in-house libraries", "url" : "http://localhost:8081/artifactory/libs-releases-local", "packageType": "Generic" }, { "key" : "libs-snapshots-local", "type" : "LOCAL", "description" : "Local repository for in-house snapshots", "url" : "http://localhost:8081/artifactory/libs-snapshots-local", "packageType": "Maven" } ] |
1 2 3 4 5 |
// PUT /api/repositories/{repoKey} // PUT /api/repositories/libs-release-local { repository-config.json } |
更新、删除、获取操作类似。
绿色记忆:使用JFrog Artifactory管理构件
awtfjqqirt
[url=http://www.gz32460ql6el4ilegl3375686adbm76ls.org/]uwtfjqqirt[/url]
wtfjqqirt http://www.gz32460ql6el4ilegl3375686adbm76ls.org/