Harbor的安装与配置

Harbor简介

Harbor 是由 VMware 公司中国团队为企业用户设计的 Registry server 开源项目,包括了权限管理(RBAC)、LDAP、审计、管理界面、自我注册、HA 等企业必需的功能,同时针对中国用户的特点,设计镜像复制和中文支持等功能。

作为一个企业级私有 Registry 服务器,Harbor 提供了更好的性能和安全。提升用户使用 Registry 构建和运行环境传输镜像的效率。Harbor 支持安装在多个 Registry 节点的镜像资源复制,镜像全部保存在私有 Registry 中, 确保数据和知识产权在公司内部网络中管控。另外,Harbor 也提供了高级的安全特性,诸如用户管理,访问控制和活动审计等。

Harbor的官网

1
https://goharbor.io/

Harbor的github地址

1
https://github.com/goharbor/harbor

(已经有15.2K的star了)

安装Harbor

前置条件

宿主机已安装好docker和docker-compose,具体安装方案这里不不展开。

下载&解压

Harbor有两个大版本,一是1.x,另外是2.x,据说2.x优化了很多,所以这里采用2.3.0这个版本,下载离线安装包。

1
2
3
wget https://github.com/goharbor/harbor/releases/download/v2.3.0/harbor-offline-installer-v2.3.0.tgz
tar zxvf harbor-offline-installer-v2.3.0.tgz
cd harbor

修改配置文件

将配置模板copy一份

1
cp harbor.yml.tmpl harbor.yml

编辑配置模板

1
vim harbor.yml

主要修改以下几个地方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# The IP address or hostname to access admin UI and registry service.
# DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients.
hostname: <你的harbor的域名或者IP(不加端口号)>

# http related config
http:
# port for http, default is 80. If https enabled, this port will redirect to https port
port: <http协议监听的端口>

# https related config
https:
# https port for harbor, default is 443
port: <https协议监听的端口>
# The path of cert and key files for nginx
certificate: <.crt证书文件的路径>
private_key: <.key证书文件的路径>

保存后执行配置脚本,使刚才的配置生效

执行配置脚本

1
./prepare

安装

1
./install.sh

如果之后修改配置再次启动,此步骤可以省略。

安装成功后,即可在 https://youip 上访问harbor了,初始帐号为 admin 初始密码为 Harbor12345 。

一些常用命令

启动Harbor

1
docker-compose up -d

关闭Harbor

1
docker-compose down -v

修改配制后需要重新关停和开启Harbor

1
2
3
./prepare #执行配置脚本
docker-compose down -v #关停Harbor
docker-compose up -d #启动Harbor

语雀javaSDK

支持语雀全部api接口,纯java编写,项目已上传至maven中央仓库,可直接maven引用。

源码地址

包引用

1
2
3
4
5
<dependency>
<groupId>com.bumao.models.yuquesdk</groupId>
<artifactId>yuquesdk</artifactId>
<version>0.0.1</version>
</dependency>

使用方式

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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
YuqueClient client = new YuqueClient("yuque-token");

System.out.println("--获取某个用户信息 by Id--");
UserDetailSerializer userDetailSerializer = client.getUserInfoById("1757692");
System.out.println(userDetailSerializer);

System.out.println("--获取某个用户信息 by Login--");
UserDetailSerializer user1 = client.getUserInfoByLogin("zhangxin_ux");
System.out.println(user1);
System.out.println(JSONObject.toJSONString(user1) );

System.out.println("--获取当前用户信息--");
UserDetailSerializer user2 = client.getCurrUserInfo();
System.out.println(user2);

System.out.println("--获取某个用户的加入的组织列表 by Id--");
List<GroupSerializer> groupList = client.listJoinedGroupById("1757692");
System.out.println(groupList);

System.out.println("--获取某个用户的加入的组织列表 by Login--");
List<GroupSerializer> groupList1 = client.listJoinedGroupByLogin("u1486894");
System.out.println(groupList1);

System.out.println("--获取公开组织列表--");
List<GroupSerializer> groupList3 = client.listPublicGroup();
System.out.println(groupList3);
System.out.println(groupList3.size());

List<GroupSerializer> groupList2 = client.listPublicGroup(99);
System.out.println(groupList2);
System.out.println(groupList2.size());

System.out.println("--获取单个组织的详细信息--");
GroupDetailVo groupDetailVo = client.getGroupInfoById("antv");
System.out.println(groupDetailVo.getData());
System.out.println(groupDetailVo.getAbilities());

System.out.println("--创建组织--");
GroupCreatePo createPo = new GroupCreatePo();
createPo.setName("firstGroup1");
createPo.setLogin("firstGroup2");
createPo.setDescription("firstGroup");
try {
GroupSerializer newGroup = client.createGroup(createPo);
System.out.println(newGroup);
}catch (YuqueException e){
System.out.println(e);
System.out.println("创建组织错误:httpCode="+e.getHttpCode()+",code="+e.getOrigCode()+",message="+e.getOrigMsg());
}

System.out.println("--更新组织--");
GroupCreatePo updatePo = new GroupCreatePo();
updatePo.setName("first被更新");
updatePo.setLogin("firstGroup2");
updatePo.setDescription("1234567890");
try {
GroupSerializer newGroup = client.updateGroupById("21807875",updatePo);
System.out.println(newGroup);
}catch (YuqueException e){
System.out.println(e);
if(e.getHttpCode().equals(400)) {
System.out.println("更新组织错误:httpCode=" + e.getHttpCode() + ",code=" + e.getOrigCode() + ",message=" + e.getOrigMsg());
}
}

System.out.println("--删除组织--");
try {
client.deleteGroupById("21807875");
}catch (YuqueException e){
System.out.println(e);
}

System.out.println("--获取组织成员信息--");
List<GroupUserSerializer> groupUserSerializerList = client.listGroupUserById("firstGroup");
System.out.println(groupUserSerializerList);

System.out.println("--增加或更新组织成员--");
GroupUserSerializer UpgroupUserSerializer = client.updateGroupUserbyId("firstGroup","zhangxin_ux",1);
System.out.println(UpgroupUserSerializer);

System.out.println("--删除组织成员--");
GroupUserSerializer DelgroupUserSerializer = client.deleteGroupUserbyId("firstGroup","zhangxin_ux");
System.out.println(DelgroupUserSerializer);

System.out.println("--获取某个用户的知识库列表 by Id--");
List<BookSerializer> bookSerializerList = client.listUserReposById("u1486894","all",0);
System.out.println(bookSerializerList);

System.out.println("--获取某个团队的知识库列表 by Id--");
List<BookSerializer> groupbookSerializerList = client.listGroupReposById("firstgroup","all",0);
System.out.println(groupbookSerializerList);

System.out.println("--往团队创建知识库 by Id--");
RepoCreatePo createPo = new RepoCreatePo();
createPo.setDescription("介绍");
createPo.setName("名称");
createPo.setPublic_id(1);
createPo.setSlug("abc");
createPo.setType("Book");
BookSerializer bookSerializer = client.createGroupRepoById("firstgroup",createPo);
System.out.println(bookSerializer);

System.out.println("--往自己下面创建知识库 by Id--");
RepoCreatePo cPo = new RepoCreatePo();
cPo.setDescription("介绍");
cPo.setName("名称");
cPo.setPublic_id(1);
cPo.setSlug("abc");
cPo.setType("Book");
BookSerializer bookSerializer = client.createUserRepoById("u1486894",cPo);
System.out.println(bookSerializer);

System.out.println("--获取知识库详情 by Id--");
BookDetailVo bookDetailVo = client.getRepoDetailById("20113349");
System.out.println(bookDetailVo.getData());//repo
System.out.println(bookDetailVo.getAbilities());//Abilities

System.out.println("--更新知识库信息 by repoId--");
RepoCreatePo upPo = new RepoCreatePo();
upPo.setDescription("介绍");
upPo.setName("名称");
upPo.setPublic_id(0);
upPo.setSlug("abc");
upPo.setType("Book");
BookSerializer bookSerializerUp = client.updateRepoById("20167466",upPo);
System.out.println(bookSerializerUp);

System.out.println("--删除知识库 by repoId--");
BookSerializer bookSerializerDel = client.deleteRepoById("u1486894/slug");
System.out.println(bookSerializerDel);

System.out.println("--获取某仓库的目录 by nameSpace--");
List<TocSerializer> tocSerializerList = client.listTocByNameSpace("u1486894/nn3k9e");
System.out.println(tocSerializerList);

System.out.println("--获取一个仓库的文档列表 by nameSpace--");
List<DocSerializer> docSerializerList = client.listDocByNameSpace("20113349");
System.out.println(docSerializerList);

System.out.println("--获取单篇文档的详细信息 by slug--");
DocDetailVo docDetailVo = client.getDocDetailBySlug("u1486894/nn3k9e","hgg9lg");
System.out.println(docDetailVo.getData());//文章
System.out.println(docDetailVo.getAbilities());//Abilities

System.out.println("--创建文档 by nameSpace--");
DocCreatePo createPo = new DocCreatePo();
createPo.setTitle("helloword");
createPo.setSlug("helloword1");
createPo.setPublic_id(1);
createPo.setFormat("markdown");
createPo.setBody("#helloword");
DocSerializer docSerializerCreate = client.createDocByNameSpace("u1486894/nn3k9e",createPo);
System.out.println(docSerializerCreate);

System.out.println("--更新文档 by nameSpace--");
DocCreatePo upPo = new DocCreatePo();
upPo.setTitle("helloword");
upPo.setSlug("helloword1");
upPo.setPublic_id(1);
upPo.setFormat("markdown");
upPo.setBody("# helloword11111111");
DocSerializer docSerializerUp = client.updateDocByNameSpace("u1486894/nn3k9e","46939700",upPo);
System.out.println(docSerializerUp);

System.out.println("--删除文档 by repoId--");
DocSerializer docSerializerDel = client.deleteDocByRepoId("20113349","46939326");
System.out.println(docSerializerDel);

System.out.println("--搜索--");
SearchPo searchPo = new SearchPo();
searchPo.setType("doc");
searchPo.setQ("世界上最好的语言");
JSONObject obj = client.listSearch(searchPo);
System.out.println(obj);

Table2Entry将建表语句转义为实体

Table2Entry可以方便的将mysql建表语句转化为实体对象,进而帮助你快速映射实体。

Table2Entry源码地址

包引用

正常使用

1
2
3
4
5
<dependency>
<groupId>com.bumao.model</groupId>
<artifactId>table2entry</artifactId>
<version>0.0.1</version>
</dependency>

包冲突的处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<dependency>
<groupId>com.bumao.model</groupId>
<artifactId>table2entry</artifactId>
<version>0.0.1</version>
<exclusions>
<!--druid-->
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</exclusion>
<!--lombok-->
<exclusion>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclusion>
<!--slf4j-api-->
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>

Table2Entry的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
String sql = "CREATE TABLE `card` (\n" +
" `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'PK',\n" +
" `batch_id` int(11) NOT NULL COMMENT '所属批次ID',\n" +
" `denomination` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '面额',\n" +
" `card_no` varchar(20) NOT NULL COMMENT '实体卡号',\n" +
" `card_pass` varchar(20) NOT NULL COMMENT '实体密码',\n" +
" `status` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '状态,0=未核销 1=已核销',\n" +
" `active_time` datetime DEFAULT NULL COMMENT '核销核销时间',\n" +
" `active_userid` varchar(32) DEFAULT NULL COMMENT '核销用户ID',\n" +
" `active_mobile` varchar(20) DEFAULT NULL COMMENT '核销时用户的手机号码',\n" +
" `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n" +
" `stop_time` datetime NOT NULL COMMENT '结束核销时间',\n" +
" `active_openid` varchar(64) DEFAULT NULL COMMENT '用户openid',\n" +
" PRIMARY KEY (`id`) USING BTREE,\n" +
" KEY `batch_id` (`batch_id`) USING BTREE,\n" +
" KEY `status` (`status`) USING BTREE\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='卡券批次表';" +
"select * from card;";
ToEntry toEntry = new ToEntry();
List<TableEntryVo> tableEntryVos = toEntry.getEntry(sql);
log.info("tableEntryVos={}", JSONArray.toJSON(tableEntryVos));
  • 可同时转义多条建表语句,请用“;”隔开。
  • 会忽略建表语句以外的sql。

TODO

针对Mysql建表语句的转义

针对Oracle建表语句的转义

针对MsSQL建表语句的转义

当Mysql遇到SSL

SpringBoot 连接提示 Communications link failure

1
2
3
4
5
6
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:174) ~[mysql-connector-java-8.0.20.jar:8.0.20]
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64) ~[mysql-connector-java-8.0.20.jar:8.0.20]
at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:836) ~[mysql-connector-

具体的错误原因没找到,只从网上搜到了这个:

1
原因是MySQL在高版本需要指明是否进行SSL连接
1
2
Establishing SSL connection without server’s identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn’t set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to ‘false’. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
不建议在没有服务器身份验证的情况下建立SSL连接。根据MySQL 5.5.45+、5.6.26+和5.7.6+的要求,如果不设置显式选项,则必须建立默认的SSL连接。需要通过设置useSSL=false来显式禁用SSL,或者设置useSSL=true并为服务器证书验证提供信任存储。

用参数 useSSL=true 进行尝试,发现还是报一样的错误,当使用 useSSL=false 时,就可以进行连接了。也就是

1
jdbc:mysql://192.168.221.201:3306/jdbc?useSSL=false

不过为什么要这样连接,暂时没弄清楚,只知道时版本和兼容的原因。