-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
900 lines (629 loc) · 82.1 KB
/
index.html
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 7.3.0">
<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
<link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
<link rel="mask-icon" href="/images/logo.svg" color="#222">
<link rel="stylesheet" href="/css/main.css">
<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">
<script id="hexo-configurations">
var NexT = window.NexT || {};
var CONFIG = {"hostname":"openqt.github.io","root":"/","scheme":"Pisces","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":true},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}}};
</script>
<meta name="description" content="伤心桥下春波绿,曾是惊鸿照影来。">
<meta property="og:type" content="website">
<meta property="og:title" content="在人间">
<meta property="og:url" content="https://openqt.github.io/index.html">
<meta property="og:site_name" content="在人间">
<meta property="og:description" content="伤心桥下春波绿,曾是惊鸿照影来。">
<meta property="og:locale" content="zh_CN">
<meta property="article:author" content="Jack Chu">
<meta name="twitter:card" content="summary">
<link rel="canonical" href="https://openqt.github.io/">
<script id="page-configurations">
// https://hexo.io/docs/variables.html
CONFIG.page = {
sidebar: "",
isHome : true,
isPost : false,
lang : 'zh-CN'
};
</script>
<title>在人间</title>
<noscript>
<style>
.use-motion .brand,
.use-motion .menu-item,
.sidebar-inner,
.use-motion .post-block,
.use-motion .pagination,
.use-motion .comments,
.use-motion .post-header,
.use-motion .post-body,
.use-motion .collection-header { opacity: initial; }
.use-motion .site-title,
.use-motion .site-subtitle {
opacity: initial;
top: initial;
}
.use-motion .logo-line-before i { left: initial; }
.use-motion .logo-line-after i { right: initial; }
</style>
</noscript>
</head>
<body itemscope itemtype="http://schema.org/WebPage">
<div class="container use-motion">
<div class="headband"></div>
<header class="header" itemscope itemtype="http://schema.org/WPHeader">
<div class="header-inner"><div class="site-brand-container">
<div class="site-nav-toggle">
<div class="toggle" aria-label="切换导航栏">
<span class="toggle-line toggle-line-first"></span>
<span class="toggle-line toggle-line-middle"></span>
<span class="toggle-line toggle-line-last"></span>
</div>
</div>
<div class="site-meta">
<a href="/" class="brand" rel="start">
<span class="logo-line-before"><i></i></span>
<h1 class="site-title">在人间</h1>
<span class="logo-line-after"><i></i></span>
</a>
</div>
<div class="site-nav-right">
<div class="toggle popup-trigger">
</div>
</div>
</div>
<nav class="site-nav">
<ul id="menu" class="main-menu menu">
<li class="menu-item menu-item-home">
<a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>
</li>
<li class="menu-item menu-item-tags">
<a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>
</li>
<li class="menu-item menu-item-categories">
<a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>
</li>
<li class="menu-item menu-item-archives">
<a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>
</li>
</ul>
</nav>
</div>
</header>
<div class="back-to-top">
<i class="fa fa-arrow-up"></i>
<span>0%</span>
</div>
<main class="main">
<div class="main-inner">
<div class="content-wrap">
<div class="content index posts-expand">
<article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
<link itemprop="mainEntityOfPage" href="https://openqt.github.io/2024/03/26/update-trivy-data-by-go-restful/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="Jack Chu">
<meta itemprop="description" content="伤心桥下春波绿,曾是惊鸿照影来。">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="在人间">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2024/03/26/update-trivy-data-by-go-restful/" class="post-title-link" itemprop="url">通过go-restful更新Harbor的Trivy数据库</a>
</h2>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2024-03-26 11:30:00" itemprop="dateCreated datePublished" datetime="2024-03-26T11:30:00+08:00">2024-03-26</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar-check"></i>
</span>
<span class="post-meta-item-text">更新于</span>
<time title="修改时间:2024-07-16 10:05:13" itemprop="dateModified" datetime="2024-07-16T10:05:13+08:00">2024-07-16</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-folder"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/golang/" itemprop="url" rel="index"><span itemprop="name">golang</span></a>
</span>
,
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/golang/programming/" itemprop="url" rel="index"><span itemprop="name">programming</span></a>
</span>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h2 id="trivy漏洞数据库下载"><a href="#trivy漏洞数据库下载" class="headerlink" title="trivy漏洞数据库下载"></a>trivy漏洞数据库下载</h2><ul>
<li>数据存储以oci方式存储,需要通过专用工具下载。</li>
</ul>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ oras pull ghcr.io/aquasecurity/trivy-db:2</span><br><span class="line">$ <span class="built_in">ls</span> -l</span><br><span class="line">.rw-rw-r-- 47M yang 28 3月 10:57 db.tar.gz</span><br></pre></td></tr></table></figure>
<h2 id="trivy漏洞数据库上传服务"><a href="#trivy漏洞数据库上传服务" class="headerlink" title="trivy漏洞数据库上传服务"></a>trivy漏洞数据库上传服务</h2><ul>
<li>上传数据命令</li>
</ul>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -XPUT http://localhost/api/trivy/v1/database -F <span class="string">"db=@bin/db.tar.gz"</span></span><br></pre></td></tr></table></figure>
<ul>
<li>以<code>github.com/emicklei/go-restful-openapi/v2 v2.9.1</code>为API框架注册上传接口</li>
</ul>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">webservice.Route(webservice.PUT(<span class="string">"/database"</span>).</span><br><span class="line"> Doc(<span class="string">"Update trivy vulnerability database."</span>).</span><br><span class="line"> Param(webservice.BodyParameter(<span class="string">"db"</span>, <span class="string">"trivy vulnerability database."</span>)).</span><br><span class="line"> To(h.updateVulnerabilityDatabase).</span><br><span class="line"> Consumes(<span class="string">"multipart/form-data"</span>).</span><br><span class="line"> Returns(http.StatusOK, api.StatusOK, <span class="literal">nil</span>).</span><br><span class="line"> Metadata(restfulspec.KeyOpenAPITags, []<span class="type">string</span>{constants.TrivyTag}))</span><br></pre></td></tr></table></figure>
<ul>
<li>读入form-data,直接解压并返回trivy metedata信息</li>
</ul>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(h *handler)</span></span> updateVulnerabilityDatabase(request *restful.Request, response *restful.Response) {</span><br><span class="line"> formfile, _, err := request.Request.FormFile(<span class="string">"db"</span>)</span><br><span class="line"> <span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line"> api.HandleBadRequest(response, request, err)</span><br><span class="line"> <span class="keyword">return</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">defer</span> formfile.Close()</span><br><span class="line"></span><br><span class="line"> err = utils.Extract(formfile, h.trivyOptions.Cache)</span><br><span class="line"> <span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line"> api.HandleBadRequest(response, request, err)</span><br><span class="line"> <span class="keyword">return</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 读数据的元信息并返回,确认一致性</span></span><br><span class="line"> metadata, err := os.ReadFile(filepath.Join(h.trivyOptions.Cache, <span class="string">"metadata.json"</span>))</span><br><span class="line"> <span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line"> api.HandleBadRequest(response, request, err)</span><br><span class="line"> <span class="keyword">return</span></span><br><span class="line"> }</span><br><span class="line"> response.Write(metadata)</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Implements Extractor.</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Extract</span><span class="params">(buffer io.Reader, targetDir <span class="type">string</span>)</span></span> <span class="type">error</span> {</span><br><span class="line"> uncompressedStream, err := gzip.NewReader(buffer)</span><br><span class="line"> <span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line"> <span class="keyword">return</span> err</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> err := os.MkdirAll(targetDir, <span class="number">0755</span>); err != <span class="literal">nil</span> {</span><br><span class="line"> <span class="keyword">return</span> err</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> tarReader := tar.NewReader(uncompressedStream)</span><br><span class="line"> <span class="keyword">for</span> {</span><br><span class="line"> header, err := tarReader.Next()</span><br><span class="line"> <span class="keyword">if</span> err == io.EOF {</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line"> <span class="keyword">return</span> err</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> path, err := cleanJoin(targetDir, header.Name)</span><br><span class="line"> <span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line"> <span class="keyword">return</span> err</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">switch</span> header.Typeflag {</span><br><span class="line"> <span class="keyword">case</span> tar.TypeDir:</span><br><span class="line"> <span class="keyword">if</span> err := os.Mkdir(path, <span class="number">0755</span>); err != <span class="literal">nil</span> {</span><br><span class="line"> <span class="keyword">return</span> err</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">case</span> tar.TypeReg:</span><br><span class="line"> outFile, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode))</span><br><span class="line"> <span class="keyword">if</span> err != <span class="literal">nil</span> {</span><br><span class="line"> <span class="keyword">return</span> err</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> _, err := io.Copy(outFile, tarReader); err != <span class="literal">nil</span> {</span><br><span class="line"> outFile.Close()</span><br><span class="line"> <span class="keyword">return</span> err</span><br><span class="line"> }</span><br><span class="line"> outFile.Close()</span><br><span class="line"> <span class="comment">// We don't want to process these extension header files.</span></span><br><span class="line"> <span class="keyword">case</span> tar.TypeXGlobalHeader, tar.TypeXHeader:</span><br><span class="line"> <span class="keyword">continue</span></span><br><span class="line"> <span class="keyword">default</span>:</span><br><span class="line"> <span class="keyword">return</span> errors.Errorf(<span class="string">"unknown type: %b in %s"</span>, header.Typeflag, header.Name)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<ul>
<li>服务镜像制作</li>
</ul>
<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> alpine:<span class="number">3.16</span>.<span class="number">2</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> bin/cmd/trivy-apiserver /</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> trivy-core.yaml /etc/trivy-core/</span></span><br><span class="line"><span class="keyword">WORKDIR</span><span class="language-bash"> /</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">EXPOSE</span> <span class="number">9090</span></span><br><span class="line"><span class="keyword">CMD</span><span class="language-bash"> [<span class="string">"/trivy-apiserver"</span>, <span class="string">"-v5"</span>]</span></span><br></pre></td></tr></table></figure>
<h2 id="API服务与Harbor集成-ingress-pod"><a href="#API服务与Harbor集成-ingress-pod" class="headerlink" title="API服务与Harbor集成(ingress, pod)"></a>API服务与Harbor集成(ingress, pod)</h2><ul>
<li>增加traefik middleware以处理URL路径前缀</li>
</ul>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Middleware</span></span><br><span class="line"><span class="comment"># Strip prefix /trivy</span></span><br><span class="line"><span class="attr">apiVersion:</span> <span class="string">traefik.containo.us/v1alpha1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Middleware</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">strip-trivy</span></span><br><span class="line"> <span class="attr">namespace:</span> <span class="string">"default"</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line"> <span class="attr">stripPrefix:</span></span><br><span class="line"> <span class="attr">forceSlash:</span> <span class="literal">false</span></span><br><span class="line"> <span class="attr">prefixes:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">/trivy</span></span><br></pre></td></tr></table></figure>
<ul>
<li>增加harbor-ingress配置(需要更新部分)</li>
</ul>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">networking.k8s.io/v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Ingress</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">harbor-ingress</span></span><br><span class="line"> <span class="attr">annotations:</span></span><br><span class="line"> <span class="attr">kubernetes.io/ingress.class:</span> <span class="string">traefik</span></span><br><span class="line"> <span class="attr">traefik.ingress.kubernetes.io/router.middlewares:</span> <span class="string">default-strip-trivy@kubernetescrd</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line"> <span class="attr">rules:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">host:</span> <span class="string">harbor.internal.io</span></span><br><span class="line"> <span class="attr">http:</span></span><br><span class="line"> <span class="attr">paths:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">path:</span> <span class="string">/trivy/</span></span><br><span class="line"> <span class="attr">pathType:</span> <span class="string">Prefix</span></span><br><span class="line"> <span class="attr">backend:</span></span><br><span class="line"> <span class="attr">service:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">harbor-trivy</span></span><br><span class="line"> <span class="attr">port:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">trivy-api</span></span><br></pre></td></tr></table></figure>
<ul>
<li>在已有harbor-trivy内加入trivy-apiserver容器</li>
</ul>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">apps/v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Deployment</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">harbor-trivy</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line"> <span class="attr">replicas:</span> <span class="number">1</span></span><br><span class="line"> <span class="attr">template:</span></span><br><span class="line"> <span class="attr">spec:</span></span><br><span class="line"> <span class="attr">containers:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">trivy</span></span><br><span class="line"> <span class="attr">image:</span> <span class="string">harbor-adapter-trivy:2.10.0-debian-12-r13</span></span><br><span class="line"> <span class="attr">imagePullPolicy:</span> <span class="string">"IfNotPresent"</span></span><br><span class="line"> <span class="attr">ports:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">api-server</span></span><br><span class="line"> <span class="attr">containerPort:</span> <span class="number">8080</span></span><br><span class="line"> <span class="attr">volumeMounts:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">data</span></span><br><span class="line"> <span class="attr">mountPath:</span> <span class="string">/bitnami/harbor-adapter-trivy/.cache</span></span><br><span class="line"> <span class="attr">readOnly:</span> <span class="literal">false</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">apiserver</span></span><br><span class="line"> <span class="attr">image:</span> <span class="string">trivy-apiserver:v1.0.2</span></span><br><span class="line"> <span class="attr">imagePullPolicy:</span> <span class="string">"IfNotPresent"</span></span><br><span class="line"> <span class="attr">ports:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">trivy-api</span></span><br><span class="line"> <span class="attr">containerPort:</span> <span class="number">9090</span></span><br><span class="line"> <span class="attr">volumeMounts:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">data</span></span><br><span class="line"> <span class="attr">mountPath:</span> <span class="string">/bitnami/harbor-adapter-trivy/.cache</span></span><br><span class="line"> <span class="attr">readOnly:</span> <span class="literal">false</span></span><br><span class="line"> <span class="attr">volumes:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">data</span></span><br><span class="line"> <span class="attr">persistentVolumeClaim:</span></span><br><span class="line"> <span class="attr">claimName:</span> <span class="string">trivy-data</span></span><br></pre></td></tr></table></figure>
<ul>
<li>测试外部接口上传数据</li>
</ul>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ curl -kXPUT https://harbor.internal.io:21000/trivy/api/v1/database -F <span class="string">"db=@bin/db.tar.gz"</span></span><br><span class="line">{<span class="string">"Version"</span>:2,<span class="string">"NextUpdate"</span>:<span class="string">"2024-03-28T06:15:32.76330602Z"</span>,<span class="string">"UpdatedAt"</span>:<span class="string">"2024-03-28T00:15:32.763306431Z"</span>,<span class="string">"DownloadedAt"</span>:<span class="string">"0001-01-01T00:00:00Z"</span>}</span><br></pre></td></tr></table></figure>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
<link itemprop="mainEntityOfPage" href="https://openqt.github.io/2024/03/25/deploy-acccessable-harbor-in-kind/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="Jack Chu">
<meta itemprop="description" content="伤心桥下春波绿,曾是惊鸿照影来。">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="在人间">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2024/03/25/deploy-acccessable-harbor-in-kind/" class="post-title-link" itemprop="url">kind集群内部署可访问的Harbor服务</a>
</h2>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2024-03-25 13:36:30" itemprop="dateCreated datePublished" datetime="2024-03-25T13:36:30+08:00">2024-03-25</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar-check"></i>
</span>
<span class="post-meta-item-text">更新于</span>
<time title="修改时间:2024-07-16 10:05:13" itemprop="dateModified" datetime="2024-07-16T10:05:13+08:00">2024-07-16</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-folder"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/devops/" itemprop="url" rel="index"><span itemprop="name">devops</span></a>
</span>
,
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/devops/kubernetes/" itemprop="url" rel="index"><span itemprop="name">kubernetes</span></a>
</span>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h2 id="部署Kubernetes及必要服务"><a href="#部署Kubernetes及必要服务" class="headerlink" title="部署Kubernetes及必要服务"></a>部署Kubernetes及必要服务</h2><ul>
<li><p>docker版本24.0.5</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">$ docker version</span><br><span class="line">Client:</span><br><span class="line"> Version: 24.0.5</span><br><span class="line"> API version: 1.43</span><br><span class="line"> Go version: go1.20.3</span><br><span class="line"> Git commit: 24.0.5-0ubuntu1~22.04.1</span><br><span class="line"> Built: Mon Aug 21 19:50:14 2023</span><br><span class="line"> OS/Arch: linux/amd64</span><br><span class="line"> Context: default</span><br><span class="line"></span><br><span class="line">Server:</span><br><span class="line"> Engine:</span><br><span class="line"> Version: 24.0.5</span><br><span class="line"> API version: 1.43 (minimum version 1.12)</span><br><span class="line"> Go version: go1.20.3</span><br><span class="line"> Git commit: 24.0.5-0ubuntu1~22.04.1</span><br><span class="line"> Built: Mon Aug 21 19:50:14 2023</span><br><span class="line"> OS/Arch: linux/amd64</span><br><span class="line"> Experimental: <span class="literal">true</span></span><br><span class="line"> containerd:</span><br><span class="line"> Version: 1.7.2</span><br><span class="line"> GitCommit: </span><br><span class="line"> runc:</span><br><span class="line"> Version: 1.1.0-0ubuntu1.1</span><br><span class="line"> GitCommit: </span><br><span class="line"> docker-init:</span><br><span class="line"> Version: 0.19.0</span><br><span class="line"> GitCommit: </span><br></pre></td></tr></table></figure>
</li>
<li><p>kind版本v0.22.0</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ kind version</span><br><span class="line">kind v0.22.0 go1.21.1 linux/amd64</span><br></pre></td></tr></table></figure>
</li>
<li><p>kind集群配置文件</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">kind:</span> <span class="string">Cluster</span></span><br><span class="line"><span class="attr">apiVersion:</span> <span class="string">kind.x-k8s.io/v1alpha4</span></span><br><span class="line"><span class="attr">containerdConfigPatches:</span></span><br><span class="line"><span class="bullet">-</span> <span class="string">|-</span></span><br><span class="line"><span class="string"> [plugins."io.containerd.grpc.v1.cri".registry]</span></span><br><span class="line"><span class="string"> [plugins."io.containerd.grpc.v1.cri".registry.mirrors]</span></span><br><span class="line"><span class="string"> [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]</span></span><br><span class="line"><span class="string"> endpoint = ["https://registry-1.docker.io"]</span></span><br><span class="line"><span class="string"> [plugins."io.containerd.grpc.v1.cri".registry.mirrors."gcr.io"]</span></span><br><span class="line"><span class="string"> endpoint = ["https://gcr.m.daocloud.io"]</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="attr">networking:</span></span><br><span class="line"> <span class="attr">apiServerAddress:</span> <span class="string">"0.0.0.0"</span></span><br><span class="line"> <span class="attr">apiServerPort:</span> <span class="number">6443</span></span><br><span class="line"></span><br><span class="line"><span class="attr">nodes:</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">role:</span> <span class="string">control-plane</span></span><br><span class="line"> <span class="attr">kubeadmConfigPatches:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">|</span></span><br><span class="line"><span class="string"> kind: InitConfiguration</span></span><br><span class="line"><span class="string"> nodeRegistration:</span></span><br><span class="line"><span class="string"> kubeletExtraArgs:</span></span><br><span class="line"><span class="string"> node-labels: "ingress-ready=true"</span></span><br><span class="line"><span class="string"></span> <span class="attr">extraPortMappings:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">containerPort:</span> <span class="number">31000</span></span><br><span class="line"> <span class="attr">hostPort:</span> <span class="number">21000</span></span><br><span class="line"> <span class="attr">protocol:</span> <span class="string">TCP</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>部署Kubernetes集群(单节点)</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">$ kind create cluster --name harbor --config demo.yaml</span><br><span class="line">Creating cluster <span class="string">"harbor"</span> ...</span><br><span class="line"> ✓ Ensuring node image (kindest/node:v1.29.2) 🖼</span><br><span class="line"> ✓ Preparing nodes 📦 </span><br><span class="line"> ✓ Writing configuration 📜 </span><br><span class="line"> ✓ Starting control-plane 🕹️ </span><br><span class="line"> ✓ Installing CNI 🔌 </span><br><span class="line"> ✓ Installing StorageClass 💾 </span><br><span class="line">Set kubectl context to <span class="string">"kind-harbor"</span></span><br><span class="line">You can now use your cluster with:</span><br><span class="line"></span><br><span class="line">kubectl cluster-info --context kind-harbor</span><br><span class="line"></span><br><span class="line">Not sure what to <span class="keyword">do</span> next? 😅 Check out https://kind.sigs.k8s.io/docs/user/quick-start/</span><br></pre></td></tr></table></figure>
</li>
<li><p>验证集群(默认context已经修改为最新部署的kind-harbor)</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">$ kubectl get no</span><br><span class="line">NAME STATUS ROLES AGE VERSION</span><br><span class="line">harbor-control-plane Ready control-plane 37s v1.29.2</span><br><span class="line"></span><br><span class="line">$ kubectl get po -A</span><br><span class="line">NAMESPACE NAME READY STATUS RESTARTS AGE</span><br><span class="line">kube-system coredns-76f75df574-6zqwf 1/1 Running 0 98s</span><br><span class="line">kube-system coredns-76f75df574-kwtm7 1/1 Running 0 98s</span><br><span class="line">kube-system etcd-harbor-control-plane 1/1 Running 0 112s</span><br><span class="line">kube-system kindnet-6xcrd 1/1 Running 0 98s</span><br><span class="line">kube-system kube-apiserver-harbor-control-plane 1/1 Running 0 113s</span><br><span class="line">kube-system kube-controller-manager-harbor-control-plane 1/1 Running 0 113s</span><br><span class="line">kube-system kube-proxy-sslv8 1/1 Running 0 98s</span><br><span class="line">kube-system kube-scheduler-harbor-control-plane 1/1 Running 0 113s</span><br><span class="line">local-path-storage local-path-provisioner-7577fdbbfb-9zgqc 1/1 Running 0 98s</span><br></pre></td></tr></table></figure>
</li>
<li><p>获取cert-manager的Chart版本v1.14.3</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cat</span> Chart.yaml</span><br><span class="line">name: cert-manager</span><br><span class="line">appVersion: v1.14.3</span><br><span class="line">version: v1.14.3</span><br></pre></td></tr></table></figure>
</li>
<li><p>部署cert-manager</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ helm install cert-manager --namespace cert-manager --create-namespace --kube-context kind-harbor .</span><br></pre></td></tr></table></figure>
</li>
<li><p>获取traefik的Chart版本26.1.0</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cat</span> Chart.yaml</span><br><span class="line">name: traefik</span><br><span class="line">appVersion: v2.11.0</span><br><span class="line">version: 26.1.0</span><br></pre></td></tr></table></figure>
</li>
<li><p>部署traefik</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ helm install traefik --namespace kube-system --create-namespace --kube-context kind-harbor .</span><br></pre></td></tr></table></figure>
</li>
<li><p>修改traefik的service配置</p>
</li>
</ul>
<ol>
<li>修改traefik的service类型,LoadBalancer => NodePort。</li>
<li>修改nodePort端口为31000,与之前部署集群的对外端口对应</li>
</ol>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spec:</span></span><br><span class="line"> <span class="attr">ports:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">websecure</span></span><br><span class="line"> <span class="attr">nodePort:</span> <span class="number">31000</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">443</span></span><br><span class="line"> <span class="attr">protocol:</span> <span class="string">TCP</span></span><br><span class="line"> <span class="attr">targetPort:</span> <span class="string">websecure</span></span><br><span class="line"> <span class="attr">type:</span> <span class="string">NodePort</span></span><br></pre></td></tr></table></figure>
<ul>
<li>修改local-path以支持ReadWriteMany模式<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ kubectl edit cm local-path-config -n local-path-storage</span><br></pre></td></tr></table></figure></li>
</ul>
<p>更新config.json如下:</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">data:</span></span><br><span class="line"> <span class="attr">config.json:</span> <span class="string">|-</span></span><br><span class="line"><span class="string"> {</span></span><br><span class="line"><span class="string"> "nodePathMap":[</span></span><br><span class="line"><span class="string"> {</span></span><br><span class="line"><span class="string"> "node":"DEFAULT_PATH_FOR_NON_LISTED_NODES",</span></span><br><span class="line"><span class="string"> "paths":["/var/local-path-provisioner"]</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string"> ]</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string"></span><span class="meta">---</span></span><br><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">data:</span></span><br><span class="line"> <span class="attr">config.json:</span> <span class="string">|-</span></span><br><span class="line"><span class="string"> {</span></span><br><span class="line"><span class="string"> "sharedFileSystemPath": "/opt/local-path-provisioner"</span></span><br><span class="line"><span class="string"> }</span></span><br></pre></td></tr></table></figure>
<p>重启local-path服务</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ kubectl -n local-path-storage get po -o jsonpath=<span class="string">"{.items[].metadata.name}"</span> | xargs kubectl -n local-path-storage delete po </span><br></pre></td></tr></table></figure>
<h2 id="部署Harbor服务"><a href="#部署Harbor服务" class="headerlink" title="部署Harbor服务"></a>部署Harbor服务</h2><ul>
<li>获取harbor的Chart版本19.9.0</li>
</ul>
<p><a target="_blank" rel="noopener" href="https://github.com/bitnami/charts/tree/main/bitnami/harbor">https://github.com/bitnami/charts/tree/main/bitnami/harbor</a></p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cat</span> Chart.yaml</span><br><span class="line">name: harbor</span><br><span class="line">apiVersion: v2</span><br><span class="line">version: 19.9.0</span><br></pre></td></tr></table></figure>
<ul>
<li>修改values.yaml</li>
</ul>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">externalURL:</span> <span class="string">https://harbor.internal.com</span></span><br><span class="line"><span class="attr">adminPassword:</span> <span class="string">"Passw0rd"</span></span><br><span class="line"></span><br><span class="line"><span class="attr">ingress:</span></span><br><span class="line"> <span class="attr">certProvider:</span> <span class="string">"cert-manager"</span></span><br><span class="line"> <span class="attr">core:</span></span><br><span class="line"> <span class="attr">hostname:</span> <span class="string">harbor.internal.com</span></span><br></pre></td></tr></table></figure>
<ul>
<li>部署harbor<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ helm upgrade harbor -i --namespace harbor --create-namespace --<span class="built_in">set</span> global.storageClass=standard --kube-context kind-harbor .</span><br></pre></td></tr></table></figure></li>
</ul>
<p>查看部署的POD情况</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">$ kubectl -n harbor get po</span><br><span class="line">NAME READY STATUS RESTARTS AGE</span><br><span class="line">harbor-core-75f79fb9f9-qpblp 1/1 Running 0 14m</span><br><span class="line">harbor-jobservice-5677b948b8-sw87s 1/1 Running 0 14m</span><br><span class="line">harbor-portal-67995b4946-mhvkn 1/1 Running 0 14m</span><br><span class="line">harbor-postgresql-0 1/1 Running 0 14m</span><br><span class="line">harbor-redis-master-0 1/1 Running 0 14m</span><br><span class="line">harbor-registry-5fb59b549-c86kj 2/2 Running 0 14m</span><br><span class="line">harbor-trivy-0 1/1 Running 0 14m</span><br></pre></td></tr></table></figure>
<ul>
<li><p>配置域名<br>在<code>/etc/hosts</code>内配置</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">192.168.2.110 harbor.internal.com</span><br></pre></td></tr></table></figure>
</li>
<li><p>访问harbor页面,输入之前配置的admin的密码</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://harbor.internal.com:21000</span><br></pre></td></tr></table></figure></li>
</ul>
<h2 id="修改Harbor服务类型"><a href="#修改Harbor服务类型" class="headerlink" title="修改Harbor服务类型"></a>修改Harbor服务类型</h2><p>从Statefulset修改为Deployment。</p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">kind:</span> <span class="string">StatefulSet</span> <span class="string">=></span> <span class="string">Deployment</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line"> <span class="comment"># serviceName # 需要注释掉</span></span><br><span class="line"> <span class="string">updateStrategy</span> <span class="string">=></span> <span class="string">strategy</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 需要将整个volumeClaimTemplates改为PersistentVolumeClaim形式</span></span><br><span class="line"> <span class="comment"># 同时要增加volumes声明域</span></span><br><span class="line"> <span class="string">volumeClaimTemplates</span> <span class="string">=></span> <span class="string">PersistentVolumeClaim</span> </span><br><span class="line"> <span class="attr">volumes:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">data</span></span><br><span class="line"> <span class="attr">persistentVolumeClaim:</span></span><br><span class="line"> <span class="attr">claimName:</span> <span class="string">data</span></span><br></pre></td></tr></table></figure>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
<link itemprop="mainEntityOfPage" href="https://openqt.github.io/2024/01/19/ml-basic/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="Jack Chu">
<meta itemprop="description" content="伤心桥下春波绿,曾是惊鸿照影来。">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="在人间">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2024/01/19/ml-basic/" class="post-title-link" itemprop="url">机器学习基础</a>
</h2>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2024-01-19 15:04:03" itemprop="dateCreated datePublished" datetime="2024-01-19T15:04:03+08:00">2024-01-19</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar-check"></i>
</span>
<span class="post-meta-item-text">更新于</span>
<time title="修改时间:2024-07-16 10:05:13" itemprop="dateModified" datetime="2024-07-16T10:05:13+08:00">2024-07-16</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-folder"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/machine-learning/" itemprop="url" rel="index"><span itemprop="name">machine-learning</span></a>
</span>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h2 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h2><p><a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/500366203">方差,标准差中要求差的平方的原因及其几何意义</a></p>
<h2 id="下采样和上采样"><a href="#下采样和上采样" class="headerlink" title="下采样和上采样"></a>下采样和上采样</h2><p><a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/579702765">上采样(UnSampling)和下采样(DownSampling)是啥</a></p>
<p>缩小图像(或称为下采样(subsampled)或降采样(downsampled))的主要目的有两个:</p>
<ol>
<li>使得图像符合显示区域的大小</li>
<li>生成对应图像的缩略图</li>
</ol>
<p>放大图像(或称为上采样(upsampling)或图像插值(interpolating))的主要目的是:</p>
<ol>
<li>放大原图像,从而可以显示在更高分辨率的显示设备上</li>
</ol>
<h2 id="Models"><a href="#Models" class="headerlink" title="Models"></a>Models</h2><p><a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/31852747">深度残差网络(Deep residual network, ResNet)</a></p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
<link itemprop="mainEntityOfPage" href="https://openqt.github.io/2024/01/03/learning-kubeflow/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="Jack Chu">
<meta itemprop="description" content="伤心桥下春波绿,曾是惊鸿照影来。">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="在人间">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2024/01/03/learning-kubeflow/" class="post-title-link" itemprop="url">学习Kubeflow</a>
</h2>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2024-01-03 14:24:15" itemprop="dateCreated datePublished" datetime="2024-01-03T14:24:15+08:00">2024-01-03</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar-check"></i>
</span>
<span class="post-meta-item-text">更新于</span>
<time title="修改时间:2024-07-16 10:05:13" itemprop="dateModified" datetime="2024-07-16T10:05:13+08:00">2024-07-16</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-folder"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/devops/" itemprop="url" rel="index"><span itemprop="name">devops</span></a>
</span>
,
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/devops/machine-learning/" itemprop="url" rel="index"><span itemprop="name">machine-learning</span></a>
</span>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="学习Kubeflow"><a href="#学习Kubeflow" class="headerlink" title="学习Kubeflow"></a>学习Kubeflow</h1><h2 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h2><p>Kubeflow的目标是在Kubernetes上能够简单的部署机器学习过程中涉及到的各种工具和服务,并提供迁移和扩展的方法。</p>
<p>Kubeflow牵扯到大量机器学习的概念和方式方法,需要对ML有基本的了解才能更好的运用和理解。</p>
<h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><ul>
<li>环境是两台虚拟机,16C32G100G<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># cat /etc/rocky-release</span></span><br><span class="line">Rocky Linux release 8.5 (Green Obsidian)</span><br></pre></td></tr></table></figure></li>
<li>更新系统<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># dnf update -y</span></span><br></pre></td></tr></table></figure></li>
<li>安装Kubernetes(1.28.6)<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># dnf install -y conntrack socat iptables ipvsadm wget git</span></span><br><span class="line"><span class="comment"># kk create cluster -f config.yml -y</span></span><br><span class="line">17:06:32 CST Pipeline[CreateClusterPipeline] execute successfully</span><br><span class="line">Installation is complete.</span><br></pre></td></tr></table></figure></li>
<li>安装基础工具<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> sysctl fs.inotify.max_user_instances=2280</span><br><span class="line"><span class="built_in">sudo</span> sysctl fs.inotify.max_user_watches=1255360</span><br><span class="line"></span><br><span class="line">wget https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv5.3.0/kustomize_v5.3.0_linux_amd64.tar.gz</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure></li>
</ul>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
<link itemprop="mainEntityOfPage" href="https://openqt.github.io/2023/11/29/learning-react/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="Jack Chu">
<meta itemprop="description" content="伤心桥下春波绿,曾是惊鸿照影来。">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="在人间">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2023/11/29/learning-react/" class="post-title-link" itemprop="url">如何学习React</a>
</h2>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2023-11-29 10:40:52" itemprop="dateCreated datePublished" datetime="2023-11-29T10:40:52+08:00">2023-11-29</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar-check"></i>
</span>
<span class="post-meta-item-text">更新于</span>
<time title="修改时间:2024-07-16 10:05:13" itemprop="dateModified" datetime="2024-07-16T10:05:13+08:00">2024-07-16</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-folder"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/javascript/" itemprop="url" rel="index"><span itemprop="name">javascript</span></a>
</span>
,
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/javascript/programming/" itemprop="url" rel="index"><span itemprop="name">programming</span></a>
</span>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<p><a target="_blank" rel="noopener" href="https://github.com/petehunt/react-howto/blob/master/README-zh.md">https://github.com/petehunt/react-howto/blob/master/README-zh.md</a></p>
<p>如果你是一个 React (或者前端) 新手, 出于以下的原因, 你可能会对这个生态圈感到困惑:</p>
<ul>
<li>React 的目标群体历来是喜欢尝试新事物的开发者和前端专家.</li>
<li>Facebook 开源的内容是应用在他们的实际应用中, 因此他们没有关注那些比 Facebook 小的工程需求.</li>
<li>现有的 React 指引水平参差不齐.</li>
</ul>
<p>在本文中, 我会假设你已有使用 HTML, CSS 和 JavaScript 开发网页的基础.</p>
<h2 id="为什么要听我的"><a href="#为什么要听我的" class="headerlink" title="为什么要听我的?"></a>为什么要听我的?</h2><p>关于 React, 现在已经有大量的相互冲突的建议了, 为什么要听我的?</p>
<p>因为我是在 Facebook 构建并开源 React 的最初成员之一. 现在我离开了 Facebook 并加入了一家初创公司, 所以我也不会站在 Facebook 的立场上来表态.</p>
<h2 id="如何踏入-React-生态圈"><a href="#如何踏入-React-生态圈" class="headerlink" title="如何踏入 React 生态圈"></a>如何踏入 React 生态圈</h2><p>所有的软件都是建立在某个技术栈之上的, 你需要对整个技术栈有足够深入的理解, 才能建造你的应用. 为什么 React 生态圈的工具似乎总让人感觉压力山大呢, 因为它总是以错误的顺序被解释:</p>
<p>你应该按照以下的顺序进行学习, <strong>而不是跳着学或者同时学习</strong>:</p>
<ul>
<li><a href="#user-content-%E5%AD%A6%E4%B9%A0-react-%E6%9C%AC%E8%BA%AB">React</a></li>
<li><a href="#user-content-%E5%AD%A6%E4%B9%A0-npm"><code>npm</code></a></li>
<li><a href="#user-content-%E5%AD%A6%E4%B9%A0-javascript-%E6%89%93%E5%8C%85%E5%B7%A5%E5%85%B7">JavaScript “打包工具”</a></li>
<li><a href="#user-content-%E5%AD%A6%E4%B9%A0-es6">ES6</a></li>
<li><a href="#user-content-%E5%AD%A6%E4%B9%A0%E8%B7%AF%E7%94%B1-routing">Routing</a></li>
<li><a href="#user-content-%E5%AD%A6%E4%B9%A0-flux">Flux</a></li>
</ul>
<p><strong>你不需要把这些都学完才去使用 React.</strong> 只需要在你遇到问题需要解决的时候, 才进入下一步的学习.</p>
<p>另外, 在 React 社区中, 有一些前沿主题是经常被提及到的, 以下的这些主题很有意思, 但也很难弄懂, 所以它们远没有上面的主题流行, <strong>大多数应用也不需要用到这些.</strong></p>
<ul>
<li><a href="#user-content-%E5%AD%A6%E4%B9%A0%E5%86%85%E8%81%94%E6%A0%B7%E5%BC%8F">内联样式</a></li>
<li><a href="#user-content-%E5%AD%A6%E4%B9%A0%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AB%AF%E6%B8%B2%E6%9F%93">服务器端渲染</a></li>
<li><a href="#user-content-%E5%AD%A6%E4%B9%A0-immutablejs">Immutable.js</a></li>
<li><a href="#user-content-%E5%AD%A6%E4%B9%A0-relay-falcor-%E7%AD%89">Relay, Falcor 等</a></li>
</ul>
<h2 id="学习-React-本身"><a href="#学习-React-本身" class="headerlink" title="学习 React 本身"></a>学习 React 本身</h2><p>有一种常见的误解是: 你需要花费大量时间在配置工具上, 然后才开始学习 React. 在官方文档里, 你可以找到 <a target="_blank" rel="noopener" href="https://facebook.github.io/react/docs/getting-started.html#quick-start-without-npm">copy-paste HTML template</a>. 只需要保存为 <code>.html</code> 文件, 你就可以马上开始学习了. <strong>这个步骤不需要任何工具, 你也无需额外学习工具使用, 直到你能熟练掌握 React 基础.</strong></p>
<p>我依然觉得, 学习 React 最简单的方法是通过官方教程 <a target="_blank" rel="noopener" href="https://facebook.github.io/react/docs/tutorial.html">the official tutorial</a>.</p>
<h2 id="学习-npm"><a href="#学习-npm" class="headerlink" title="学习 npm"></a>学习 <code>npm</code></h2><p><code>npm</code> 是 Node.js 包管理工具, 也是前端工程师和设计师分享 JavaScript 代码最流行的方式. 它包含了名为 <code>CommonJS</code> 的模块系统, 让你可以安装 JavaScript 写的命令行工具. 作为背景知识, 可以阅读 <a target="_blank" rel="noopener" href="http://0fps.net/2013/01/22/commonjs-why-and-how/">这篇文章</a> 了解 <code>CommonJS</code> 对于浏览器的重要性, 阅读 <a target="_blank" rel="noopener" href="http://wiki.commonjs.org/wiki/Introduction">CommonJS Spec Wiki</a> 了解关于 <code>CommonJS</code> API 的更多内容</p>
<p>在 React 生态圈中, 大部分可重用的组件、库和工具遵循 <code>CommonJS</code> 模块规范, 可通过 <code>npm</code> 来安装.</p>
<h2 id="学习-JavaScript-打包工具"><a href="#学习-JavaScript-打包工具" class="headerlink" title="学习 JavaScript 打包工具"></a>学习 JavaScript 打包工具</h2><p>出于若干技术原因, <code>CommonJS</code> 模块 (也就是 <code>npm</code> 里的所有内容) 不能直接用到浏览器. 你需要一个 JavaScript “打包工具(bundler)” 来把这些模块打包成 <code>.js</code> 文件, 使你可以在网页中通过 <code><script></code> 标签引入它们.</p>
<p>JavaScript 打包工具包括 <code>webpack</code> 和 <code>browserify</code>. 它们都是好的选择, 但我个人更喜欢 <code>webpack</code> , 因为它有许多功能简化大型应用开发. 鉴于 webpack 文档可能令人感到困惑, 我也写了两篇文章: <a target="_blank" rel="noopener" href="https://github.com/petehunt/react-webpack-template">plug-and-play template for getting started</a> 和针对更复杂用例的 <a target="_blank" rel="noopener" href="https://github.com/petehunt/webpack-howto">how-to guide for webpack</a>.</p>
<p>要记住的一点: <code>CommonJS</code> 使用了 <code>require()</code> 函数来引入模块, 因此许多人对此感到疑惑, 并认为需要导入 <code>require.js</code> 到工程里. 出于若干技术原因, 我建议你避免使用 <code>require.js</code>. 它在 React 生态圈并不流行.</p>
<h2 id="学习-ES6"><a href="#学习-ES6" class="headerlink" title="学习 ES6"></a>学习 ES6</h2><p>在 JSX (你会在 React tutorial 中学习到) 以外, 你可能会注意到 React 例子中一些有趣的语法. 这被称为 ECMAScript6, 是 JavaScript 的最新版本. 由于 ES6 很新, 你可能还没学习到, 浏览器也可能尚未兼容, 但别担心, 通过合适的配置, 你的打包工具会为你自动转换成兼容代码.</p>
<p>如果你只想要使用 React 来把事情做完, <strong>你可以跳过 ES6 的学习,</strong> 或者留到以后再学习.</p>
<p>你可能会看到一些讨论说更适合用 ES6 的 class 来创建 React 组件. 这并不是真的, 大多数人 (包括 Facebook) 用的还是 <code>React.createClass()</code>.</p>
<h2 id="学习路由-routing"><a href="#学习路由-routing" class="headerlink" title="学习路由 (routing)"></a>学习路由 (routing)</h2><p>“单页面应用” 是时下的技术热点. 当网页加载完成, 用户点击链接或者按钮的时候, JavaScript 会更新页面和改变地址栏, 但网页不会刷新. 地址栏的管理就是通过 <strong>路由(router)</strong> 来完成的.</p>
<p>目前 React 生态圈最受欢迎的路由解决方案是 <a target="_blank" rel="noopener" href="https://github.com/rackt/react-router">react-router</a>. 如果你正在创建一个单页面应用, 有什么理由不去使用它呢?</p>
<p><strong>如果你创建的并非单页面应用, 请不要使用路由.</strong> 无论如何, 大部分项目都是从大型应用中的小组件开始的.</p>
<h2 id="学习内联样式"><a href="#学习内联样式" class="headerlink" title="学习内联样式"></a>学习内联样式</h2><p>在 React 出现之前, 很多人通过像 SASS 这样的预处理器来重用复杂的 CSS 样式表. 鉴于 React 使开发可重用组件变得容易, 你的样式表可以变得没那么复杂了. 社区中许多人 (包括我) 正尝试完全抛弃样式表.</p>
<p>由于一些原因, 其实这是个相当疯狂的主意. 这让媒体查询 (media quries) 更加困难了, 而且这种技术可能有性能上的局限性. <strong>当你开始用 React 的时候, 只要用你平常使用的方法去写就好了.</strong></p>
<p>一旦你找到了用 React 开发的感觉, 你就可以关注那些可作为替代的技术了. 其中一种流行技术是 <a target="_blank" rel="noopener" href="https://en.bem.info/">BEM</a>. 我建议你逐渐停用 CSS 预处理器, 因为 React 给了你一种更强大的方式去重用样式 (通过重用组件), 并且 JavaScript 打包工具可以为你生成更高效的样式表 (我曾经<a target="_blank" rel="noopener" href="https://www.youtube.com/watch?v=VkTCL6Nqm6Y">在 OSCON 上发表过关于这个的演讲</a>). 说了这么多, 总之 React 就像其他 JavaScript 库一样, 可以和 CSS 预处理器很好地配合工作.</p>
<p>另一种可选项是 <a target="_blank" rel="noopener" href="http://glenmaddern.com/articles/css-modules">CSS 模块</a>, 更具体地说, 是 <a target="_blank" rel="noopener" href="https://github.com/gajus/react-css-modules">react-css-modules</a>. 虽然有了这些 CSS 模块, 你还是写 CSS (或者是 SASS/LESS/Stylus), 但你可以像处理 React 中的内联样式那样管理和组织 CSS 文件. 你也不需要担心用到 BEM 那样的方法学去管理类名, 因为模块系统在底层已经帮你处理好了.</p>
<h2 id="学习服务器端渲染"><a href="#学习服务器端渲染" class="headerlink" title="学习服务器端渲染"></a>学习服务器端渲染</h2><p>服务器端渲染经常被称为 “通用应用” 或 “同构应用”. 这意味着你可以用 React 组件在服务器端渲染出静态 HTML. 这样做可以提高初始化加载的性能, 因为用户不用等到 JS 下载完才看到初始界面, 并且 React 可以重用服务器端渲染出的 HTML, 无需客户端重新生成.</p>
<p>如果你发现首屏渲染速度过慢, 或者想提高网站在搜索引擎的排行, 你就需要服务器端渲染了. 尽管 Google 现在也会索引客户端渲染的内容, 但截至 2016 年 1 月, 这样做仍被证实会对排行有负面影响, 这可能是由于客户端渲染的性能问题所造成的.</p>
<p>服务器端渲染还需要许多工具的辅助, 因为显然 React 组件不是在考虑服务器端渲染的情况下写出来的, 你应该先构建你的应用, 之后再关心服务器端渲染的问题. 不用担心, 你不需要重写所有组件去支持它.</p>
<h2 id="学习-Flux"><a href="#学习-Flux" class="headerlink" title="学习 Flux"></a>学习 Flux</h2><p>你可能听过 Flux, 不过关于 Flux 有大量的错误资讯.</p>
<p>许多人一坐下来刚开始构建应用, 就认为需要用 Flux 来定义他们的数据模型. <strong>这样采用 Flux 是不对的, Flux 应该在大量组件被建立完成以后才被引入.</strong></p>
<p>React 组件之间存在层级关系. 在很多时候, 你的数据模型也跟随这种层级. 这种情况下, Flux 不会给你很大帮助. 但有些时候, 你的数据模型没有层次, 当你的 React 组件开始接受没有关联的 <code>props</code> 的时候, 或者当小部分组件开始变得复杂的时候, 你才可能需要看看 Flux.</p>
<p><strong>你会知道什么时候需要用 Flux. 如果你不确定是否需要用它, 你就不需要它.</strong></p>
<p>如果你决定使用 Flux, 现在最流行的、文档最全的 Flux 库是 <a target="_blank" rel="noopener" href="http://redux.js.org/">Redux</a>. 当然也有许多其他选择, 你或者会有兴趣尝试使用它们, 但我的建议是只需要用最流行的 Redux 就足够了.</p>
<h2 id="学习-Immutable-js"><a href="#学习-Immutable-js" class="headerlink" title="学习 Immutable.js"></a>学习 Immutable.js</h2><p><a target="_blank" rel="noopener" href="https://facebook.github.io/immutable-js/">Immutable.js</a> 提供了一系列的数据结构, 以帮助解决构造 React 应用时的某些性能问题. 这是一个很棒的库, 你可能会在应用发展的过程里大量用到它, 但直到你在意识到性能问题以前, 它是完全不必要的.</p>
<h2 id="学习-Relay-Falcor-等"><a href="#学习-Relay-Falcor-等" class="headerlink" title="学习 Relay, Falcor 等"></a>学习 Relay, Falcor 等</h2><p>这些技术可以帮你减少 AJAX 请求数, 它们仍然是非常前沿的, 所以如果你没有遇到过多 AJAX 请求的问题, 就不需要用到 Relay 或者 Falcor.</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<script>
window.addEventListener('tabs:register', () => {
let { activeClass } = CONFIG.comments;
if (CONFIG.comments.storage) {
activeClass = localStorage.getItem('comments_active') || activeClass;
}
if (activeClass) {
let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
if (activeTab) {
activeTab.click();
}
}
});
if (CONFIG.comments.storage) {
window.addEventListener('tabs:click', event => {
if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
let commentClass = event.target.classList[1];
localStorage.setItem('comments_active', commentClass);
});
}
</script>
</div>
<div class="toggle sidebar-toggle">
<span class="toggle-line toggle-line-first"></span>
<span class="toggle-line toggle-line-middle"></span>
<span class="toggle-line toggle-line-last"></span>
</div>
<aside class="sidebar">
<div class="sidebar-inner">
<ul class="sidebar-nav motion-element">
<li class="sidebar-nav-toc">
文章目录
</li>
<li class="sidebar-nav-overview">
站点概览
</li>
</ul>
<!--noindex-->
<div class="post-toc-wrap sidebar-panel">
</div>
<!--/noindex-->
<div class="site-overview-wrap sidebar-panel">
<div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
<p class="site-author-name" itemprop="name">Jack Chu</p>
<div class="site-description" itemprop="description">伤心桥下春波绿,曾是惊鸿照影来。</div>
</div>
<div class="site-state-wrap motion-element">
<nav class="site-state">
<div class="site-state-item site-state-posts">
<a href="/archives/">
<span class="site-state-item-count">5</span>
<span class="site-state-item-name">日志</span>
</a>
</div>
<div class="site-state-item site-state-categories">
<a href="/categories/">
<span class="site-state-item-count">8</span>
<span class="site-state-item-name">分类</span></a>
</div>
<div class="site-state-item site-state-tags">
<a href="/tags/">
<span class="site-state-item-count">7</span>
<span class="site-state-item-name">标签</span></a>
</div>
</nav>
</div>
</div>
</div>
</aside>
<div id="sidebar-dimmer"></div>
</div>
</main>
<footer class="footer">
<div class="footer-inner">
<div class="copyright">
©
<span itemprop="copyrightYear">2024</span>
<span class="with-love">
<i class="fa fa-at"></i>
</span>
<span class="author" itemprop="copyrightHolder">Jack Chu</span>
</div>
<div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://pisces.theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Pisces</a> 强力驱动
</div>
</div>
</footer>
</div>
<script src="/lib/anime.min.js"></script>
<script src="/lib/velocity/velocity.min.js"></script>
<script src="/lib/velocity/velocity.ui.min.js"></script>
<script src="/js/utils.js"></script>
<script src="/js/motion.js"></script>
<script src="/js/schemes/pisces.js"></script>
<script src="/js/next-boot.js"></script>
</body>
</html>