-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
953 lines (953 loc) · 280 KB
/
atom.xml
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
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<id>https://8loser.github.io</id>
<title>別在圍城時走散</title>
<subtitle></subtitle>
<icon>https://8loser.github.io/assets/favicon.ico</icon>
<link href="https://8loser.github.io" />
<author>
<name>八樓的人</name>
</author>
<updated>2024-06-16T16:38:53.000Z</updated>
<entry>
<id>https://8loser.github.io/2024/06/17/dev-container-bind-source-error/</id>
<title>bind source path does not exist</title>
<link rel="alternate" href="https://8loser.github.io/2024/06/17/dev-container-bind-source-error/"/>
<content type="html"><h1 id="問題描述"><a class="anchor" href="#問題描述">#</a> 問題描述</h1>
<p>DevContainer 啟動 container 錯誤,查看錯誤訊息如下<br />
<code>Error response from daemon: invalid mount config for type &quot;bind&quot;: bind source path does not exist: /run/user/1000/wayland-0</code></p>
<h1 id="環境"><a class="anchor" href="#環境">#</a> 環境</h1>
<ul>
<li>OS: EndeavourOS</li>
<li>在 VSCode 使用 Dev Container 套件啟動 container</li>
</ul>
<h1 id="修正方法"><a class="anchor" href="#修正方法">#</a> 修正方法</h1>
<p>刪除下面兩個檔案</p>
<ul>
<li>/run/user/1000/wayland-0</li>
<li>/run/user/1000/wayland-0.lock</li>
</ul>
</content>
<category term="Trouble" scheme="https://8loser.github.io/categories/Trouble/" />
<category term="VSCode" scheme="https://8loser.github.io/tags/VSCode/" />
<category term="Remote Container" scheme="https://8loser.github.io/tags/Remote-Container/" />
<updated>2024-06-16T16:38:53.000Z</updated>
</entry>
<entry>
<id>https://8loser.github.io/2024/06/16/shokaX-waline-comment/</id>
<title>Hexo ShokaX 主題使用 Waline 留言版</title>
<link rel="alternate" href="https://8loser.github.io/2024/06/16/shokaX-waline-comment/"/>
<content type="html"><h1 id="佈署-waline-server-端"><a class="anchor" href="#佈署-waline-server-端">#</a> 佈署 Waline server 端</h1>
<p>參考 Waline 佈署教學網站 <a href="https://waline.js.org/guide/deploy/vercel.html">https://waline.js.org/guide/deploy/vercel.html</a> ,點選 Deploy 按鈕,會跳轉 Vercel 頁面建立 Waline server。</p>
<p><img loading="lazy" data-src="vercel-deploy.png" alt="Vercel deploy" /></p>
<p>如果使用該方式,在 Vercel 出現下面錯誤訊息,改用這個 <a href="https://vercel.com/new/austin-lees-projects/clone?repository-url=https%3A%2F%2Fgithub.com%2Fwalinejs%2Fwaline%2Ftree%2Fmain%2Fexample">[Deploy]</a> 試試</p>
<div class="note danger">
<p>Error: No Output Directory named &quot;dist&quot; found after the Build completed. You can configure the Output Directory in your Project Settings.</p>
</div>
<div class="note info">
<p>除了 Vercel 作為 Waline 服務之外,也有其他選擇 <a href="https://waline.js.org/guide/get-started/server.html">https://waline.js.org/guide/get-started/server.html</a></p>
</div>
<h1 id="建立-waline-使用的資料庫"><a class="anchor" href="#建立-waline-使用的資料庫">#</a> 建立 Waline 使用的資料庫</h1>
<p>Waline 需要資料庫儲存留言資料,Waline 支援多種資料庫 <a href="https://waline.js.org/guide/database.html">https://waline.js.org/guide/database.html</a> 。<br />
Vercel 也有提供資料庫,所以這邊使用 Vercel 內建的資料庫服務,建立 PostgreSQL。</p>
<p><img loading="lazy" data-src="vercel-create-database.png" alt="Create Database Step1" /></p>
<p><img loading="lazy" data-src="vercel-create-postgres.png" alt="Create Database Step2" /></p>
<div class="note info">
<p>需要的資料表請參考<br />
<a href="https://github.com/walinejs/waline/blob/main/assets/waline.pgsql"> https://github.com/walinejs/waline/blob/main/assets/waline.pgsql</a></p>
</div>
<h1 id="將-waline-服務與資料庫連接"><a class="anchor" href="#將-waline-服務與資料庫連接">#</a> 將 Waline 服務與資料庫連接</h1>
<p>進入 App<br />
<img loading="lazy" data-src="enter-waline-app.png" alt="Enter Waline App" /><br />
連接剛剛建立的 PostgreSQL<br />
<img loading="lazy" data-src="database-connect.png" alt="Database connect" /></p>
<h1 id="設定-waline-環境變數"><a class="anchor" href="#設定-waline-環境變數">#</a> 設定 Waline 環境變數</h1>
<p><img loading="lazy" data-src="setting-environment-variable.png" alt="Setting environment variable" /></p>
<p>如果資料庫連接成功,會看到紅框內的環境變數。<br />
<img loading="lazy" data-src="waline-environment-variable.png" alt="Connected Success Variable" /></p>
<p>但這樣還無法讓 Waline server 成功連接資料庫,還需要設定下面的環境變數</p>
<ul>
<li>PG_SSL
<ul>
<li>設為 true</li>
</ul>
</li>
<li>PG_PORT
<ul>
<li>設為 5432</li>
</ul>
</li>
</ul>
<div class="note info">
<p>Waline 可設定的 PostgreSQL 環境變數<br />
<a href="https://waline.js.org/guide/database.html#postgresql"> https://waline.js.org/guide/database.html#postgresql</a></p>
</div>
<h1 id="測試-waline-功能"><a class="anchor" href="#測試-waline-功能">#</a> 測試 Waline 功能</h1>
<p>進入 Waline project 查看 Waline 留言頁面。</p>
<p><img loading="lazy" data-src="app-visit-test.png" alt="Visit Waline app" /></p>
<p>如果正常的話會看到如下畫面,可以留言測試看看是否成功。</p>
<p><img loading="lazy" data-src="waline-comment-page.png" alt="Waline comment page" /></p>
<h1 id="設定-shokax"><a class="anchor" href="#設定-shokax">#</a> 設定 ShokaX</h1>
<p>修改 Hexo ShokaX 設定檔;Hexo 資料夾 <code>/_config.shokax.yml</code> 或 <code>/_config.shokaX.yml</code></p>
<p>增加下面設定</p>
<figure class="highlight yml"><figcaption data-lang="YAML"><span>_config.shokax.yml</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token key atrule">waline</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token key atrule">enable</span><span class="token punctuation">:</span> <span class="token boolean important">true</span> <span class="token comment"># 啟用狀態</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token key atrule">serverURL</span><span class="token punctuation">:</span> <span class="token string">"https://waline-three-wine.vercel.app"</span> <span class="token comment"># Waline server 網址,從 Vercel Project 查看 domain</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token key atrule">lang</span><span class="token punctuation">:</span> <span class="token string">"zh-TW"</span> <span class="token comment"># comment 界面語言</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token key atrule">meta</span><span class="token punctuation">:</span> <span class="token comment"># comment 可填寫項目</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token punctuation">-</span> nick</pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token punctuation">-</span> mail</pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token key atrule">requiredMeta</span><span class="token punctuation">:</span> <span class="token comment"># comment 必填項目</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token punctuation">-</span> nick</pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token punctuation">-</span> mail</pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token key atrule">wordLimit</span><span class="token punctuation">:</span> <span class="token number">400</span> <span class="token comment"># comment 字數上限</span></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token key atrule">pageSize</span><span class="token punctuation">:</span> <span class="token number">10</span> <span class="token comment"># 每頁顯示筆數</span></pre></td></tr></table></figure><div class="note info">
<p>Hexo ShokaX 的 Waline 其他設定項目<br />
<a href="https://docs.kaitaku.xyz/guide/comment.html#valine-%E7%B3%BB%E8%AF%84%E8%AE%BA%E7%B3%BB%E7%BB%9F"> https://docs.kaitaku.xyz/guide/comment.html#valine - 系评论系统</a></p>
</div>
<h1 id="使用紀錄"><a class="anchor" href="#使用紀錄">#</a> 使用紀錄</h1>
<h2 id="202406"><a class="anchor" href="#202406">#</a> 2024/06</h2>
<ul>
<li>meta 設定無效,只設定 nick, mail 但是界面上還是會顯示網址欄位</li>
<li><code>最新評論</code> 顯示 emoji 無效,會變成 HTML</li>
</ul>
</content>
<category term="Step By Step" scheme="https://8loser.github.io/categories/Step-By-Step/" />
<category term="Hexo theme" scheme="https://8loser.github.io/tags/Hexo-theme/" />
<category term="Waline" scheme="https://8loser.github.io/tags/Waline/" />
<updated>2024-06-15T17:17:17.000Z</updated>
</entry>
<entry>
<id>https://8loser.github.io/2023/10/30/spawn-node-gyp-ENOENT/</id>
<title>spawn node-gyp ENOENT</title>
<link rel="alternate" href="https://8loser.github.io/2023/10/30/spawn-node-gyp-ENOENT/"/>
<content type="html"><h1 id="問題描述"><a class="anchor" href="#問題描述">#</a> 問題描述</h1>
<p>要把 theme 轉為 <a href="https://docs.kaitaku.xyz/">shokaX</a> 時,執行 <code>SXC install shokaX</code> 出現錯誤訊息</p>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre>error /workspaces/page/node_modules/deasync: Command failed.</pre></td></tr><tr><td data-num="2"></td><td><pre>Exit code: <span class="token number">1</span></pre></td></tr><tr><td data-num="3"></td><td><pre>Command: <span class="token function">node</span> ./build.js</pre></td></tr><tr><td data-num="4"></td><td><pre>Arguments: </pre></td></tr><tr><td data-num="5"></td><td><pre>Directory: /workspaces/page/node_modules/deasync</pre></td></tr><tr><td data-num="6"></td><td><pre>Output:</pre></td></tr><tr><td data-num="7"></td><td><pre>node:events:495</pre></td></tr><tr><td data-num="8"></td><td><pre> throw er<span class="token punctuation">;</span> // Unhandled <span class="token string">'error'</span> event</pre></td></tr><tr><td data-num="9"></td><td><pre> ^</pre></td></tr><tr><td data-num="10"></td><td><pre></pre></td></tr><tr><td data-num="11"></td><td><pre>Error: spawn node-gyp ENOENT</pre></td></tr><tr><td data-num="12"></td><td><pre> at ChildProcess._handle.onexit <span class="token punctuation">(</span>node:internal/child_process:284:19<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="13"></td><td><pre> at onErrorNT <span class="token punctuation">(</span>node:internal/child_process:477:16<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="14"></td><td><pre> at process.processTicksAndRejections <span class="token punctuation">(</span>node:internal/process/task_queues:82:21<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="15"></td><td><pre>Emitted <span class="token string">'error'</span> event on ChildProcess instance at:</pre></td></tr><tr><td data-num="16"></td><td><pre> at ChildProcess._handle.onexit <span class="token punctuation">(</span>node:internal/child_process:290:12<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="17"></td><td><pre> at onErrorNT <span class="token punctuation">(</span>node:internal/child_process:477:16<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="18"></td><td><pre> at process.processTicksAndRejections <span class="token punctuation">(</span>node:internal/process/task_queues:82:21<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span></pre></td></tr><tr><td data-num="19"></td><td><pre> errno: -2,</pre></td></tr><tr><td data-num="20"></td><td><pre> code: <span class="token string">'ENOENT'</span>,</pre></td></tr><tr><td data-num="21"></td><td><pre> syscall: <span class="token string">'spawn node-gyp'</span>,</pre></td></tr><tr><td data-num="22"></td><td><pre> path: <span class="token string">'node-gyp'</span>,</pre></td></tr><tr><td data-num="23"></td><td><pre> spawnargs: <span class="token punctuation">[</span> <span class="token string">'rebuild'</span> <span class="token punctuation">]</span></pre></td></tr><tr><td data-num="24"></td><td><pre><span class="token punctuation">&#125;</span></pre></td></tr><tr><td data-num="25"></td><td><pre></pre></td></tr><tr><td data-num="26"></td><td><pre>Node.js v18.18.2</pre></td></tr><tr><td data-num="27"></td><td><pre>info Visit https://yarnpkg.com/en/docs/cli/add <span class="token keyword">for</span> documentation about this command.</pre></td></tr></table></figure><h1 id="環境"><a class="anchor" href="#環境">#</a> 環境</h1>
<ul>
<li>Docker image: node:18-slim</li>
</ul>
<h1 id="修正方法"><a class="anchor" href="#修正方法">#</a> 修正方法</h1>
<p>安裝下面套件,不確定 <code>make</code> , <code>g++</code> 需不需要,因為之前遇過類似的問題都裝這三個,所以直接複製過來用。如果沒有安裝的話,在安裝 <code>node-gyp</code> 會出現其他錯誤。</p>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">apt-get</span> <span class="token function">install</span> <span class="token parameter variable">-y</span> python3 <span class="token function">make</span> g++</pre></td></tr></table></figure><p>安裝 <code>node-gyp</code></p>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">pnpm</span> <span class="token function">add</span> <span class="token parameter variable">-g</span> node-gyp</pre></td></tr></table></figure></content>
<category term="Trouble" scheme="https://8loser.github.io/categories/Trouble/" />
<category term="Docker" scheme="https://8loser.github.io/tags/Docker/" />
<category term="Hexo" scheme="https://8loser.github.io/tags/Hexo/" />
<category term="Shoka" scheme="https://8loser.github.io/tags/Shoka/" />
<category term="Node" scheme="https://8loser.github.io/tags/Node/" />
<updated>2023-10-29T17:04:26.000Z</updated>
</entry>
<entry>
<id>https://8loser.github.io/2023/08/27/static-web-page-refresh-404/</id>
<title>靜態網頁 refresh 出現 404</title>
<link rel="alternate" href="https://8loser.github.io/2023/08/27/static-web-page-refresh-404/"/>
<content type="html"><h1 id="trouble"><a class="anchor" href="#trouble">#</a> Trouble</h1>
<p>Vue 開發網頁打包成靜態網頁檔案,使用 docker compose 結合 nginx 佈署,網頁切換到有路徑的頁面後按 F5 重新整理頁面會出現 404 錯誤 。</p>
<p>靜態頁面打包後有再用 <a href="https://acme.com/software/thttpd/">thttpd</a> 作為 web 服務並打包成 container 方便佈署,實際錯誤情況如下圖,如果不同的 web 服務會有不同畫面。</p>
<p><img loading="lazy" data-src="404-not-found.png" alt="404 Not Found" /></p>
<h1 id="docker-composeyml"><a class="anchor" href="#docker-composeyml">#</a> Docker-compose.yml</h1>
<p>有修改過的內容,實際不只有兩個 container</p>
<figure class="highlight dockerfile"><figcaption data-lang="Docker"><span>docker-compose.yml</span></figcaption><table><tr><td data-num="1"></td><td><pre>services:</pre></td></tr><tr><td data-num="2"></td><td><pre> nginx:</pre></td></tr><tr><td data-num="3"></td><td><pre> image: nginx</pre></td></tr><tr><td data-num="4"></td><td><pre> restart: unless-stopped</pre></td></tr><tr><td data-num="5"></td><td><pre> volumes:</pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token comment"># nginx 設定檔</span></pre></td></tr><tr><td data-num="7"></td><td><pre> - ./nginx.conf:/etc/nginx/conf.d/default.conf</pre></td></tr><tr><td data-num="8"></td><td><pre> - ./robots.txt.test:/usr/share/nginx/html/robots.txt</pre></td></tr><tr><td data-num="9"></td><td><pre> environment:</pre></td></tr><tr><td data-num="10"></td><td><pre> TZ: Asia/Taipei</pre></td></tr><tr><td data-num="11"></td><td><pre> ports:</pre></td></tr><tr><td data-num="12"></td><td><pre> - target: 80</pre></td></tr><tr><td data-num="13"></td><td><pre> published: 80</pre></td></tr><tr><td data-num="14"></td><td><pre> protocol: tcp</pre></td></tr><tr><td data-num="15"></td><td><pre> mode: host</pre></td></tr><tr><td data-num="16"></td><td><pre></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token comment"># 前端 web service</span></pre></td></tr><tr><td data-num="18"></td><td><pre> branded:</pre></td></tr><tr><td data-num="19"></td><td><pre> image: ***馬賽克***</pre></td></tr><tr><td data-num="20"></td><td><pre> restart: unless-stopped</pre></td></tr></table></figure><h1 id="nginxconf"><a class="anchor" href="#nginxconf">#</a> Nginx.conf</h1>
<figure class="highlight nginx"><figcaption data-lang="nginx"><span>nginx.conf</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">&#123;</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token directive"><span class="token keyword">listen</span> <span class="token number">80</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token directive"><span class="token keyword">server_name</span> <span class="token string">""</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre> </pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token comment"># LB Public IP address</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token directive"><span class="token keyword">set_real_ip_from</span> ***馬賽克***</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token directive"><span class="token keyword">set_real_ip_from</span> 130.211.0.0/22</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token directive"><span class="token keyword">set_real_ip_from</span> 35.191.0.0/16</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token directive"><span class="token keyword">real_ip_header</span> X-Forwarded-For</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token directive"><span class="token keyword">real_ip_recursive</span> <span class="token boolean">on</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="11"></td><td><pre></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token comment"># 阻擋的 User Agent</span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token directive"><span class="token keyword">if</span> (<span class="token variable">$http_user_agent</span> ~* ***不要告訴泥*** )</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token punctuation">&#123;</span>return <span class="token directive"><span class="token keyword">101</span></span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span></pre></td></tr><tr><td data-num="15"></td><td><pre></pre></td></tr><tr><td data-num="16"></td><td><pre> <span class="token directive"><span class="token keyword">location</span> /robots.txt</span> <span class="token punctuation">&#123;</span></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token directive"><span class="token keyword">alias</span> /usr/share/nginx/html/robots.txt</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="18"></td><td><pre> <span class="token punctuation">&#125;</span></pre></td></tr><tr><td data-num="19"></td><td><pre></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token directive"><span class="token keyword">location</span> /healthcheck</span> <span class="token punctuation">&#123;</span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token directive"><span class="token keyword">access_log</span> <span class="token boolean">off</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="22"></td><td><pre> <span class="token directive"><span class="token keyword">return</span> <span class="token number">200</span> <span class="token string">'ok'</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="23"></td><td><pre> <span class="token punctuation">&#125;</span></pre></td></tr><tr><td data-num="24"></td><td><pre></pre></td></tr><tr><td data-num="25"></td><td><pre> <span class="token comment"># 前端</span></pre></td></tr><tr><td data-num="26"></td><td><pre> <span class="token directive"><span class="token keyword">location</span> /</span> <span class="token punctuation">&#123;</span></pre></td></tr><tr><td data-num="27"></td><td><pre> <span class="token directive"><span class="token keyword">proxy_pass</span> http://branded/</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="28"></td><td><pre> <span class="token directive"><span class="token keyword">proxy_set_header</span> Host <span class="token variable">$host</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="29"></td><td><pre> <span class="token directive"><span class="token keyword">proxy_set_header</span> X-Real-IP <span class="token variable">$remote_addr</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="30"></td><td><pre> <span class="token directive"><span class="token keyword">proxy_set_header</span> X-Forwarded-For <span class="token variable">$proxy_add_x_forwarded_for</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="31"></td><td><pre> <span class="token directive"><span class="token keyword">proxy_set_header</span> X-Custom-Referrer smc_identity_layer</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="32"></td><td><pre> <span class="token punctuation">&#125;</span></pre></td></tr><tr><td data-num="33"></td><td><pre><span class="token punctuation">&#125;</span></pre></td></tr></table></figure><h1 id="solution"><a class="anchor" href="#solution">#</a> Solution</h1>
<p>在 nginx.conf 加上</p>
<pre><code>proxy_intercept_errors on;
error_page 404 /index.html;
</code></pre>
<figure class="highlight nginx"><figcaption data-lang="nginx"><span>nginx.conf</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token comment"># 前端</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token directive"><span class="token keyword">location</span> /</span> <span class="token punctuation">&#123;</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token directive"><span class="token keyword">proxy_pass</span> http://branded/</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token directive"><span class="token keyword">proxy_set_header</span> Host <span class="token variable">$host</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token directive"><span class="token keyword">proxy_set_header</span> X-Real-IP <span class="token variable">$remote_addr</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token directive"><span class="token keyword">proxy_set_header</span> X-Forwarded-For <span class="token variable">$proxy_add_x_forwarded_for</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token directive"><span class="token keyword">proxy_set_header</span> X-Custom-Referrer smc_identity_layer</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token comment"># 高情商 (?) 加下面這兩行</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token directive"><span class="token keyword">proxy_intercept_errors</span> <span class="token boolean">on</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token directive"><span class="token keyword">error_page</span> <span class="token number">404</span> /index.html</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token punctuation">&#125;</span></pre></td></tr></table></figure></content>
<category term="Trouble" scheme="https://8loser.github.io/categories/Trouble/" />
<category term="Nginx" scheme="https://8loser.github.io/tags/Nginx/" />
<category term="static web page" scheme="https://8loser.github.io/tags/static-web-page/" />
<category term="Docker Compose" scheme="https://8loser.github.io/tags/Docker-Compose/" />
<updated>2023-08-26T16:40:55.000Z</updated>
</entry>
<entry>
<id>https://8loser.github.io/2023/07/14/fixing-mixed-content/</id>
<title>瀏覽器出現 Mixed Content 訊息</title>
<link rel="alternate" href="https://8loser.github.io/2023/07/14/fixing-mixed-content/"/>
<content type="html"><p>Chrome Console 出現 <code>Mixed Content</code> 訊息</p>
<pre><code>Mixed Content: The page at 'https://www.***.com/' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://192.168.10.200:3000/'.
This request has been blocked; the content must be served over HTTPS.
</code></pre>
<p>出現該訊息是因為在 https 頁面內,呼叫 http 協定的 API,基於安全問題,瀏覽器會封鎖該請求。解決方式是把 API 換成 https 即可,但這個 API 是我們放在客戶端存取客戶內部網路的 service,讓客戶在我們網站透過呼叫該 service 存取他們內網資料。</p>
<p>如果要為了這個 service 建立域名、申請 SSL 憑證有點麻煩(我就懶),所以請客戶調整瀏覽器設定,允許不安全內容。</p>
<p><img loading="lazy" data-src="allow-insecure-content.png" alt="Allow insecure conten" /></p>
<h1 id="相關參考"><a class="anchor" href="#相關參考">#</a> 相關參考</h1>
<ul>
<li>
<p><a href="https://support.google.com/chrome/answer/114662?hl=zh-Hant&amp;co=GENIE.Platform%3DDesktop#zippy=%2C%E7%9E%AD%E8%A7%A3%E5%8F%AF%E8%AE%8A%E6%9B%B4%E7%9A%84%E6%AC%8A%E9%99%90">變更網站設定權限</a></p>
</li>
<li>
<p><a href="https://developer.mozilla.org/zh-TW/docs/Web/Security/Mixed_content">混合內容</a></p>
</li>
</ul>
</content>
<category term="Trouble" scheme="https://8loser.github.io/categories/Trouble/" />
<category term="Mixed Content" scheme="https://8loser.github.io/tags/Mixed-Content/" />
<category term="Browser" scheme="https://8loser.github.io/tags/Browser/" />
<updated>2023-07-14T11:25:05.000Z</updated>
</entry>
<entry>
<id>https://8loser.github.io/2023/05/28/yay-is-corrupted/</id>
<title>yay 更新顯示檔案毀損</title>
<link rel="alternate" href="https://8loser.github.io/2023/05/28/yay-is-corrupted/"/>
<content type="html"><h1 id="問題描述"><a class="anchor" href="#問題描述">#</a> 問題描述</h1>
<p>EndeavourOS 更新時出現錯誤訊息,且每次更新時都出現。</p>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre>:: 進行安裝嗎? <span class="token punctuation">[</span>Y/n<span class="token punctuation">]</span> </pre></td></tr><tr><td data-num="2"></td><td><pre>:: 正在接收軟體包…</pre></td></tr><tr><td data-num="3"></td><td><pre> libusbmuxd-2.0.2-3-x86_64 <span class="token number">31.8</span> KiB <span class="token number">529</span> KiB/s 00:00 <span class="token punctuation">[</span>------------------------------------<span class="token punctuation">]</span> <span class="token number">100</span>%</pre></td></tr><tr><td data-num="4"></td><td><pre> libplist-2.3.0-2-x86_64 <span class="token number">140.7</span> KiB <span class="token number">1315</span> KiB/s 00:00 <span class="token punctuation">[</span>------------------------------------<span class="token punctuation">]</span> <span class="token number">100</span>%</pre></td></tr><tr><td data-num="5"></td><td><pre> libimobiledevice-1.3.0-9-x86_64 <span class="token number">481.5</span> KiB <span class="token number">2.35</span> MiB/s 00:00 <span class="token punctuation">[</span>------------------------------------<span class="token punctuation">]</span> <span class="token number">100</span>%</pre></td></tr><tr><td data-num="6"></td><td><pre> yay-12.0.5-1-x86_64 <span class="token number">3.0</span> MiB <span class="token number">2.69</span> MiB/s 00:01 <span class="token punctuation">[</span>------------------------------------<span class="token punctuation">]</span> <span class="token number">100</span>%</pre></td></tr><tr><td data-num="7"></td><td><pre> 總共 <span class="token punctuation">(</span><span class="token number">4</span>/4<span class="token punctuation">)</span> <span class="token number">3.7</span> MiB <span class="token number">3.23</span> MiB/s 00:01 <span class="token punctuation">[</span>------------------------------------<span class="token punctuation">]</span> <span class="token number">100</span>%</pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token punctuation">(</span><span class="token number">78</span>/78<span class="token punctuation">)</span> 正在檢查鑰匙圈中的鑰匙 <span class="token punctuation">[</span>------------------------------------<span class="token punctuation">]</span> <span class="token number">100</span>%</pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token punctuation">(</span><span class="token number">78</span>/78<span class="token punctuation">)</span> 正在檢查軟體包完整性 <span class="token punctuation">[</span>------------------------------------<span class="token punctuation">]</span> <span class="token number">100</span>%</pre></td></tr><tr><td data-num="10"></td><td><pre>錯誤:yay:來自 manuel <span class="token operator">&lt;</span>[email protected]<span class="token operator">></span> 的簽章信任等級不明:: /var/cache/pacman/pkg/yay-12.0.5-1-x86_64.pkg.tar.zst 檔案毀損<span class="token punctuation">(</span>套件不正確或損毀(PGP 簽章)<span class="token punctuation">)</span>。你要刪除它嗎? <span class="token punctuation">[</span>Y/n<span class="token punctuation">]</span> </pre></td></tr><tr><td data-num="11"></td><td><pre>錯誤:無法提交處理 <span class="token punctuation">(</span>套件不正確或損毀(PGP 簽章)<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="12"></td><td><pre>發生錯誤,沒有軟體包被更新。</pre></td></tr></table></figure><h1 id="修正"><a class="anchor" href="#修正">#</a> 修正</h1>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">sudo</span> pacman <span class="token parameter variable">-Sy</span> archlinux-keyring endeavouros-keyring</pre></td></tr></table></figure><p>修正後執行 <code>yay -Syu</code> 可正常更新了。</p>
</content>
<category term="Trouble" scheme="https://8loser.github.io/categories/Trouble/" />
<category term="EndeavourOS" scheme="https://8loser.github.io/tags/EndeavourOS/" />
<category term="Linux" scheme="https://8loser.github.io/tags/Linux/" />
<updated>2023-05-28T10:03:54.000Z</updated>
</entry>
<entry>
<id>https://8loser.github.io/2023/05/06/dbeaver-backup-start-unavailable/</id>
<title>DBeaver backup start 按鈕沒有作用</title>
<link rel="alternate" href="https://8loser.github.io/2023/05/06/dbeaver-backup-start-unavailable/"/>
<content type="html"><h1 id="問題描述"><a class="anchor" href="#問題描述">#</a> 問題描述</h1>
<p>在 Linux 內 DBeaver backup <code>Start</code> 按鈕無法點選,也無法 <code>Next</code></p>
<p><img loading="lazy" data-src="start-unavailable.png" alt="start unavailable" /></p>
<h1 id="環境"><a class="anchor" href="#環境">#</a> 環境</h1>
<ul>
<li>OS: EndeavourOS, BUILD_ID=2023.03.06</li>
<li>DBeaver Community 23.0.3</li>
<li>Database: 雲端 PostgreSQL</li>
</ul>
<h1 id="修正方法"><a class="anchor" href="#修正方法">#</a> 修正方法</h1>
<h2 id="安裝-postgresql"><a class="anchor" href="#安裝-postgresql">#</a> 安裝 PostgreSQL</h2>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">sudo</span> pacman <span class="token parameter variable">-S</span> postgresql</pre></td></tr></table></figure><h2 id="查看-pg_dump-位置"><a class="anchor" href="#查看-pg_dump-位置">#</a> 查看 pg_dump 位置</h2>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre>$ <span class="token function">whereis</span> pg_dump</pre></td></tr><tr><td data-num="2"></td><td><pre>pg_dump: /usr/bin/pg_dump /usr/share/man/man1/pg_dump.1.gz</pre></td></tr></table></figure><p>知道 <code>pg_dump</code> 程式位置在 <code>/usr/bin/</code></p>
<h2 id="dbeaver-設定-driver"><a class="anchor" href="#dbeaver-設定-driver">#</a> DBeaver 設定 Driver</h2>
<p>從 DBeaver 選單開啟 Database/Driver Manager,點選 PostgreSQL 按 <code>Edit</code> <br />
<img loading="lazy" data-src="driver-manager.png" alt="Driver Manager" /></p>
<p>選取 <code>Native Client</code> / <code>Add Home</code></p>
<p><img loading="lazy" data-src="native-client.png" alt="Native Client" /></p>
<p>設定 Home 為 <code>/usr/bin/</code></p>
<p><img loading="lazy" data-src="add-home.png" alt="Add Home" /></p>
<h1 id="測試"><a class="anchor" href="#測試">#</a> 測試</h1>
<p><code>Next</code> 可以點選了<br />
<img loading="lazy" data-src="backup-next.png" alt="Backup Next" /></p>
<p>點選 <code>Next</code> 後,選取備份路徑按 <code>Start</code> 就可以備份了<br />
<img loading="lazy" data-src="backup-start.png" alt="Backup Start" /></p>
</content>
<category term="Trouble" scheme="https://8loser.github.io/categories/Trouble/" />
<category term="Linux" scheme="https://8loser.github.io/tags/Linux/" />
<category term="DBeaver" scheme="https://8loser.github.io/tags/DBeaver/" />
<updated>2023-05-06T14:57:59.000Z</updated>
</entry>
<entry>
<id>https://8loser.github.io/2023/03/12/reduce-frontend-docker-image/</id>
<title>縮減靜態網頁 Docker image 大小</title>
<link rel="alternate" href="https://8loser.github.io/2023/03/12/reduce-frontend-docker-image/"/>
<content type="html"><h1 id="前言"><a class="anchor" href="#前言">#</a> 前言</h1>
<p>通常 Vue 部屬都是先打包成靜態網頁再部屬到 web 服務器上,但如此無法做到程式碼上傳版控後自動部屬,因為上傳的是原始碼,不是打包後的靜態網頁。</p>
<p>所以 Vue 搭配 Docker 時,有種作法是把原始碼直接直接 build 成執行 <code>npm run dev</code> 的 docker image 後放在 server 執行。</p>
<p><img loading="lazy" data-src="jsut-do-it.jpg" alt="" /></p>
<div class="note danger">
<p>這種作法產生的 docker image 很大,枉費還用 Vue</p>
</div>
<h1 id="縮減方式"><a class="anchor" href="#縮減方式">#</a> 縮減方式</h1>
<p>使用 <a href="https://docs.docker.com/build/building/multi-stage/">Multi-stage builds</a>,在第一個 stage build 出靜態網頁,複製到第二個 stage 跟 web service 打包成 image。</p>
<p>假設原本 Dockerfiler 如下</p>
<figure class="highlight dockerfile"><figcaption data-lang="Docker"><span>fat Dockerfile</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token instruction"><span class="token keyword">FROM</span> node:18-slim</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token instruction"><span class="token keyword">COPY</span> . .</span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token instruction"><span class="token keyword">RUN</span> npm install --production=false</span></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token instruction"><span class="token keyword">EXPOSE</span> 5173</span></pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token instruction"><span class="token keyword">CMD</span> [<span class="token string">"npm"</span>,<span class="token string">"run"</span>,<span class="token string">"dev"</span>]</span></pre></td></tr></table></figure><p>加上第二個 stage,並且使用 <a href="https://acme.com/software/thttpd/">thttpd</a> 作為靜態網頁的 web service</p>
<figure class="highlight dockerfile"><figcaption data-lang="Docker"><span>slim Dockerfile</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token comment"># 第一個 stage</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token instruction"><span class="token keyword">FROM</span> node:18-slim <span class="token keyword">AS</span> builder</span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token instruction"><span class="token keyword">COPY</span> . .</span></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token instruction"><span class="token keyword">RUN</span> npm install --production=false</span></pre></td></tr><tr><td data-num="5"></td><td><pre></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token comment"># build static html 檔案,檔案會產生在 /dist 內</span></pre></td></tr><tr><td data-num="7"></td><td><pre><span class="token instruction"><span class="token keyword">RUN</span> npm run build</span></pre></td></tr><tr><td data-num="8"></td><td><pre></pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token comment"># 第二個 stage</span></pre></td></tr><tr><td data-num="10"></td><td><pre><span class="token instruction"><span class="token keyword">FROM</span> alpine</span></pre></td></tr><tr><td data-num="11"></td><td><pre></pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token comment"># 安裝 thttpd</span></pre></td></tr><tr><td data-num="13"></td><td><pre><span class="token instruction"><span class="token keyword">RUN</span> apk update &amp;&amp; apk upgrade &amp;&amp; apk add --no-cache thttpd</span></pre></td></tr><tr><td data-num="14"></td><td><pre></pre></td></tr><tr><td data-num="15"></td><td><pre><span class="token comment"># 複製第一個 stage 產生的 static html 到 /front</span></pre></td></tr><tr><td data-num="16"></td><td><pre><span class="token instruction"><span class="token keyword">COPY</span> <span class="token options"><span class="token property">--from</span><span class="token punctuation">=</span><span class="token string">builder</span></span> /dist /front</span></pre></td></tr><tr><td data-num="17"></td><td><pre></pre></td></tr><tr><td data-num="18"></td><td><pre><span class="token instruction"><span class="token keyword">EXPOSE</span> 5173</span></pre></td></tr><tr><td data-num="19"></td><td><pre></pre></td></tr><tr><td data-num="20"></td><td><pre><span class="token comment"># container 啟動時執行 thttpd</span></pre></td></tr><tr><td data-num="21"></td><td><pre><span class="token instruction"><span class="token keyword">CMD</span> [<span class="token string">"thttpd"</span>, <span class="token string">"-D"</span>, <span class="token string">"-h"</span>, <span class="token string">"0.0.0.0"</span>, <span class="token string">"-p"</span>, <span class="token string">"5173"</span>, <span class="token string">"-d"</span>, <span class="token string">"/front"</span>, <span class="token string">"-l"</span>, <span class="token string">"-"</span>, <span class="token string">"-M"</span>, <span class="token string">"60"</span>]</span></pre></td></tr></table></figure><p><img loading="lazy" data-src="finish.gif" alt="" /></p>
<h1 id="比較"><a class="anchor" href="#比較">#</a> 比較</h1>
<table>
<thead>
<tr>
<th style="text-align:center"></th>
<th style="text-align:center">Docker image 大小</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">修改前</td>
<td style="text-align:center">504MB</td>
</tr>
<tr>
<td style="text-align:center">修改後</td>
<td style="text-align:center">11.1MB</td>
</tr>
</tbody>
</table>
<p><img loading="lazy" data-src="whoa.gif" alt="" /></p>
</content>
<category term="Docker" scheme="https://8loser.github.io/tags/Docker/" />
<updated>2023-03-12T13:59:19.000Z</updated>
</entry>
<entry>
<id>https://8loser.github.io/2023/03/11/EndeavourOS-init/</id>
<title>EndeavourOS 常用程式安裝</title>
<link rel="alternate" href="https://8loser.github.io/2023/03/11/EndeavourOS-init/"/>
<content type="html"><h1 id="參數說明"><a class="anchor" href="#參數說明">#</a> 參數說明</h1>
<ul>
<li><code>--noconfirm</code> 自動確認</li>
<li><code>--needed</code> 已安裝的套件不重複安裝</li>
</ul>
<h1 id="注音輸入法-新酷音"><a class="anchor" href="#注音輸入法-新酷音">#</a> 注音輸入法 (新酷音)</h1>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre>pacman <span class="token parameter variable">-S</span> <span class="token parameter variable">--noconfirm</span> <span class="token parameter variable">--needed</span> fcitx5 fcitx5-im fcitx5-chinese-addons fcitx5-configtool fcitx5-chewing</pre></td></tr></table></figure><p>修改 <code>/etc/environment</code> 檔案,增加下面設定</p>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token assign-left variable">GTK_IM_MODULE</span><span class="token operator">=</span>fcitx</pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token assign-left variable">QT_IM_MODULE</span><span class="token operator">=</span>fcitx</pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token assign-left variable"><span class="token environment constant">XMODIFIERS</span></span><span class="token operator">=</span>@im<span class="token operator">=</span>fcitx</pre></td></tr></table></figure><h1 id="藍芽"><a class="anchor" href="#藍芽">#</a> 藍芽</h1>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre>pacman <span class="token parameter variable">-S</span> <span class="token parameter variable">--noconfirm</span> <span class="token parameter variable">--needed</span> bluez bluez-utils blueberry</pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token comment"># 設定開機自動啟用</span></pre></td></tr><tr><td data-num="3"></td><td><pre>systemctl <span class="token builtin class-name">enable</span> bluetooth</pre></td></tr></table></figure><h1 id="visual-studio-code"><a class="anchor" href="#visual-studio-code">#</a> Visual Studio Code</h1>
<p>安裝 AUR 的 bin 版本才有 Remote Development 套件</p>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre>yay <span class="token parameter variable">-S</span> <span class="token parameter variable">--noconfirm</span> <span class="token parameter variable">--needed</span> visual-studio-code-bin</pre></td></tr></table></figure><h1 id="docker"><a class="anchor" href="#docker">#</a> Docker</h1>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre>pacman <span class="token parameter variable">-S</span> <span class="token parameter variable">--noconfirm</span> <span class="token parameter variable">--needed</span> <span class="token function">docker</span></pre></td></tr></table></figure><h1 id="docker-desktop"><a class="anchor" href="#docker-desktop">#</a> Docker Desktop</h1>
<p>要先下載安裝檔案</p>
<div class="note info">
<p>下載版本,可參考 <a href="https://docs.docker.com/desktop/release-notes/">https://docs.docker.com/desktop/release-notes/</a></p>
</div>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token comment"># 下載套件檔案</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token assign-left variable">dockerDesktopFile</span><span class="token operator">=</span>docker-desktop-4.17.0-x86_64.pkg.tar.zst</pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token function">wget</span> https://desktop.docker.com/linux/main/amd64/<span class="token variable">$dockerDesktopFile</span> <span class="token parameter variable">-P</span> /tmp</pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token comment"># 安裝套件</span></pre></td></tr><tr><td data-num="5"></td><td><pre>pacman <span class="token parameter variable">-U</span> <span class="token parameter variable">--noconfirm</span> /tmp/<span class="token variable">$dockerDesktopFile</span></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token comment"># 移除下載的檔案</span></pre></td></tr><tr><td data-num="7"></td><td><pre><span class="token function">rm</span> /tmp/<span class="token variable">$dockerDesktopFile</span></pre></td></tr></table></figure><div class="note info">
<p>手動安裝可參考 <a href="https://docs.docker.com/desktop/install/archlinux/">https://docs.docker.com/desktop/install/archlinux/</a></p>
</div>
<h1 id="google-chrome"><a class="anchor" href="#google-chrome">#</a> Google Chrome</h1>
<p>AUR 才有</p>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre>yay <span class="token parameter variable">-S</span> <span class="token parameter variable">--noconfirm</span> <span class="token parameter variable">--needed</span> google-chrome</pre></td></tr></table></figure><h1 id="設定-ram-disk"><a class="anchor" href="#設定-ram-disk">#</a> 設定 RAM disk</h1>
<p>建立檔案 <code>/etc/tmpfiles.d/shmFolder.conf</code> <br />
使用者名稱的位置記得修改</p>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token comment"># 下載資料夾</span></pre></td></tr><tr><td data-num="2"></td><td><pre>d /dev/shm/Downloads 0755 <span class="token operator">&lt;</span>使用者名稱<span class="token operator">></span> <span class="token operator">&lt;</span>使用者名稱<span class="token operator">></span> - -</pre></td></tr><tr><td data-num="3"></td><td><pre>L+ /home/<span class="token operator">&lt;</span>使用者名稱<span class="token operator">></span>/Downloads - - - - /dev/shm/Downloads</pre></td></tr><tr><td data-num="4"></td><td><pre></pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token comment"># Chrome 暫存資料夾</span></pre></td></tr><tr><td data-num="6"></td><td><pre>d /dev/shm/ChromeCache 0700 <span class="token operator">&lt;</span>使用者名稱<span class="token operator">></span> <span class="token operator">&lt;</span>使用者名稱<span class="token operator">></span> - -</pre></td></tr><tr><td data-num="7"></td><td><pre>L+ /home/<span class="token operator">&lt;</span>使用者名稱<span class="token operator">></span>/.cache/google-chrome - - - - /dev/shm/ChromeCache</pre></td></tr></table></figure><p>執行使設定檔生效,或者重新開機</p>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre>systemd-tmpfiles <span class="token parameter variable">--create</span></pre></td></tr></table></figure><h1 id="完整-shell-script"><a class="anchor" href="#完整-shell-script">#</a> 完整 Shell Script</h1>
<p>在這裡 <a href="https://gist.github.com/8loser/a99f0e946861db9a368693ab747c5506">EndeavourOS-init.sh</a></p>
</content>
<category term="EndeavourOS" scheme="https://8loser.github.io/tags/EndeavourOS/" />
<category term="Linux" scheme="https://8loser.github.io/tags/Linux/" />
<category term="Shell script" scheme="https://8loser.github.io/tags/Shell-script/" />
<updated>2023-03-11T13:23:40.000Z</updated>
</entry>
<entry>
<id>https://8loser.github.io/2023/02/23/linux-recovering-journal/</id>
<title>Linux 開機顯示 recovering journal</title>
<link rel="alternate" href="https://8loser.github.io/2023/02/23/linux-recovering-journal/"/>
<content type="html"><h1 id="描述"><a class="anchor" href="#描述">#</a> 描述</h1>
<p>Linux 作業系統開機顯示 recovering journal,無法正常進入桌面環境。<br />
完整訊息如下,出現 <code>recovering journal</code> 後,要等個幾分鐘才會再出現後續的訊息。</p>
<figure class="highlight bash"><figcaption data-lang="bash"><span>開機訊息</span></figcaption><table><tr><td data-num="1"></td><td><pre>/dev/nvme0n1p5: recovering journal</pre></td></tr><tr><td data-num="2"></td><td><pre>/dev/nvme0n1p5: clean, <span class="token number">1217915</span>/16416000 files, <span class="token number">17252131</span>/65536000 blocks</pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token punctuation">[</span> TIME <span class="token punctuation">]</span> Timed out waiting <span class="token keyword">for</span> device /dev/sda2.</pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token punctuation">[</span>DEPEND<span class="token punctuation">]</span> Dependency failed <span class="token keyword">for</span> /home/user/test.</pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token punctuation">[</span>DEPEND<span class="token punctuation">]</span> Dependency failed <span class="token keyword">for</span> Local File System.</pre></td></tr><tr><td data-num="6"></td><td><pre>You are <span class="token keyword">in</span> emergency mode. After logging in, <span class="token builtin class-name">type</span> <span class="token string">"journalctl -xb"</span> to view system logs, <span class="token string">"systemctl reboot"</span> to reboot, <span class="token string">"systemctl default"</span> or <span class="token string">"exit"</span> to boot into default mode.</pre></td></tr><tr><td data-num="7"></td><td><pre>Give root password <span class="token keyword">for</span> maintenance</pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token punctuation">(</span>or press Control-D to <span class="token builtin class-name">continue</span><span class="token punctuation">)</span>:</pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token punctuation">..</span>.</pre></td></tr></table></figure><h1 id="環境"><a class="anchor" href="#環境">#</a> 環境</h1>
<figure class="highlight bash"><figcaption data-lang="bash"><span>系統環境</span></figcaption><table><tr class="marked"><td data-num="1"></td><td><pre>$ lsb_release <span class="token parameter variable">-a</span></pre></td></tr><tr><td data-num="2"></td><td><pre>LSB Version: n/a</pre></td></tr><tr><td data-num="3"></td><td><pre>Distributor ID: ManjaroLinux</pre></td></tr><tr><td data-num="4"></td><td><pre>Description: Manjaro Linux</pre></td></tr><tr><td data-num="5"></td><td><pre>Release: <span class="token number">22.0</span>.4</pre></td></tr><tr><td data-num="6"></td><td><pre>Codename: Sikaris</pre></td></tr></table></figure><h1 id="修正"><a class="anchor" href="#修正">#</a> 修正</h1>
<p>使用 root 權限編輯 <code>/etc/fstab</code> ,把 <code>/dev/sda2</code> (錯誤訊息中顯示的) 那行刪除,儲存,reboot。</p>
<h1 id="原因"><a class="anchor" href="#原因">#</a> 原因</h1>
<p>應該是我前一次關機前,插外接硬碟又用 partition 管理工具 mount 外接硬碟 partition 導致。</p>
</content>
<category term="Trouble" scheme="https://8loser.github.io/categories/Trouble/" />
<category term="Linux" scheme="https://8loser.github.io/tags/Linux/" />
<updated>2023-02-23T08:51:28.000Z</updated>
</entry>
<entry>
<id>https://8loser.github.io/2023/02/20/terminals-pty-host-is-unresponsive/</id>
<title>Dev Containers 出現 terminal's pty host process is unresponsive</title>
<link rel="alternate" href="https://8loser.github.io/2023/02/20/terminals-pty-host-is-unresponsive/"/>
<content type="html"><h1 id="錯誤訊息"><a class="anchor" href="#錯誤訊息">#</a> 錯誤訊息</h1>
<div class="note success">
<p>Visual Studio Code 1.76.1 版本已不會有此問題</p>
</div>
<p>更新 Visual Studio Code 後,進入 Dev Containers 出現錯誤 <code>The connection to the terminal's pty host process is unresponsive</code> ,且 terminal 無法使用。<br />
<img loading="lazy" data-src="error-message.png" alt="Error message" /></p>
<p>點選 <code>Restart pty host</code> 後 terminal 仍無法正常顯示</p>
<h1 id="環境"><a class="anchor" href="#環境">#</a> 環境</h1>
<ul>
<li>作業系統</li>
</ul>
<figure class="highlight bash"><figcaption data-lang="bash"><span>系統資訊</span></figcaption><table><tr class="marked"><td data-num="1"></td><td><pre>$ lsb_release <span class="token parameter variable">-a</span></pre></td></tr><tr><td data-num="2"></td><td><pre>LSB Version: n/a</pre></td></tr><tr><td data-num="3"></td><td><pre>Distributor ID: ManjaroLinux</pre></td></tr><tr><td data-num="4"></td><td><pre>Description: Manjaro Linux</pre></td></tr><tr><td data-num="5"></td><td><pre>Release: <span class="token number">22.0</span>.4</pre></td></tr><tr><td data-num="6"></td><td><pre>Codename: Sikaris</pre></td></tr></table></figure><ul>
<li>Visual Studio Code 1.75.1 (會出現錯誤的版本)</li>
</ul>
<h1 id="嘗試修正"><a class="anchor" href="#嘗試修正">#</a> 嘗試修正</h1>
<p>Visual Studio Code 設定 terminal.integrated.windowsEnableConpty: false,重啟後異常狀況一樣。</p>
<h1 id="使用-downgrade-降版"><a class="anchor" href="#使用-downgrade-降版">#</a> 使用 downgrade 降版</h1>
<p>無法降版,可能因為我先把 VSCode 刪除再重新安裝,而重新安裝是最新版的,所以電腦內沒有保留舊版本。</p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr class="marked"><td data-num="1"></td><td><pre>$ <span class="token function">sudo</span> downgrade visual-studio-code-bin</pre></td></tr><tr><td data-num="2"></td><td><pre></pre></td></tr><tr><td data-num="3"></td><td><pre>Downgrading from A.L.A. is disabled on the stable branch. To override this behavior, <span class="token builtin class-name">set</span> DOWNGRADE_FROM_ALA to <span class="token number">1</span>.</pre></td></tr><tr><td data-num="4"></td><td><pre>See https://wiki.manjaro.org/index.php/Downgrading_packages <span class="token keyword">for</span> <span class="token function">more</span> details.</pre></td></tr><tr><td data-num="5"></td><td><pre></pre></td></tr><tr><td data-num="6"></td><td><pre>No results found</pre></td></tr><tr><td data-num="7"></td><td><pre>Unable to downgrade visual-studio-code-bin</pre></td></tr></table></figure><h1 id="直接安裝舊版本"><a class="anchor" href="#直接安裝舊版本">#</a> 直接安裝舊版本</h1>
<h2 id="取得舊版本"><a class="anchor" href="#取得舊版本">#</a> 取得舊版本</h2>
<p>從 <a href="https://aur.archlinux.org/packages/">AUR repository</a> 找到使用的套件<a href="https://aur.archlinux.org/packages/visual-studio-code-bin"> visual-studio-code-bin</a>,點選 <code>View Changes</code> 查看舊版本。</p>
<p><img loading="lazy" data-src="aur-package.png" alt="AUR package" /></p>
<p>選擇可以正常的版本;1.74.3,下載套件。</p>
<p><img loading="lazy" data-src="aur-package-changes.png" alt="AUR package changes" /><br />
<img loading="lazy" data-src="old-package-download.png" alt="old package download" /></p>
<h2 id="建立-package"><a class="anchor" href="#建立-package">#</a> 建立 package</h2>
<p>解壓縮後進入</p>
<figure class="highlight bash"><figcaption data-lang="bash"><span>解壓縮後的檔案清單</span></figcaption><table><tr class="marked"><td data-num="1"></td><td><pre>$ <span class="token function">ls</span> <span class="token parameter variable">-a1</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token builtin class-name">.</span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token punctuation">..</span></pre></td></tr><tr><td data-num="4"></td><td><pre>code.desktop</pre></td></tr><tr><td data-num="5"></td><td><pre>code-url-handler.desktop</pre></td></tr><tr><td data-num="6"></td><td><pre>PKGBUILD</pre></td></tr><tr><td data-num="7"></td><td><pre>.SRCINFO</pre></td></tr><tr><td data-num="8"></td><td><pre>visual-studio-code-bin.install</pre></td></tr><tr><td data-num="9"></td><td><pre>visual-studio-code-bin.sh</pre></td></tr><tr><td data-num="10"></td><td><pre>visual-studio-code-workspace.xml</pre></td></tr></table></figure><p>建立 package</p>
<figure class="highlight bash"><figcaption data-lang="bash"><span>建立 package</span></figcaption><table><tr class="marked"><td data-num="1"></td><td><pre>$ makepkg <span class="token parameter variable">-s</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token operator">==</span><span class="token operator">></span> Making package: visual-studio-code-bin <span class="token number">1.74</span>.3-1 <span class="token punctuation">(</span>廿廿三年二月廿日 <span class="token punctuation">(</span>週一<span class="token punctuation">)</span> 廿時47分十三秒<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token operator">==</span><span class="token operator">></span> Checking runtime dependencies<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token operator">==</span><span class="token operator">></span> Checking buildtime dependencies<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token operator">==</span><span class="token operator">></span> Retrieving sources<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="6"></td><td><pre> -<span class="token operator">></span> Found code.desktop</pre></td></tr><tr><td data-num="7"></td><td><pre> -<span class="token operator">></span> Found code-url-handler.desktop</pre></td></tr><tr><td data-num="8"></td><td><pre> -<span class="token operator">></span> Found visual-studio-code-workspace.xml</pre></td></tr><tr><td data-num="9"></td><td><pre> -<span class="token operator">></span> Found visual-studio-code-bin.sh</pre></td></tr><tr><td data-num="10"></td><td><pre> -<span class="token operator">></span> Downloading code_x64_1.74.3.tar.gz<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="11"></td><td><pre> % Total % Received % Xferd Average Speed Time Time Time Current</pre></td></tr><tr><td data-num="12"></td><td><pre> Dload Upload Total Spent Left Speed</pre></td></tr><tr><td data-num="13"></td><td><pre><span class="token number">100</span> <span class="token number">134</span> <span class="token number">100</span> <span class="token number">134</span> <span class="token number">0</span> <span class="token number">0</span> <span class="token number">159</span> <span class="token number">0</span> --:--:-- --:--:-- --:--:-- <span class="token number">159</span></pre></td></tr><tr><td data-num="14"></td><td><pre><span class="token number">100</span> 131M <span class="token number">100</span> 131M <span class="token number">0</span> <span class="token number">0</span> 3979k <span class="token number">0</span> <span class="token number">0</span>:00:33 <span class="token number">0</span>:00:33 --:--:-- 4091k</pre></td></tr><tr><td data-num="15"></td><td><pre><span class="token operator">==</span><span class="token operator">></span> Validating <span class="token builtin class-name">source</span> files with sha256sums<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="16"></td><td><pre> code.desktop <span class="token punctuation">..</span>. Passed</pre></td></tr><tr><td data-num="17"></td><td><pre> code-url-handler.desktop <span class="token punctuation">..</span>. Passed</pre></td></tr><tr><td data-num="18"></td><td><pre> visual-studio-code-workspace.xml <span class="token punctuation">..</span>. Passed</pre></td></tr><tr><td data-num="19"></td><td><pre> visual-studio-code-bin.sh <span class="token punctuation">..</span>. Passed</pre></td></tr><tr><td data-num="20"></td><td><pre><span class="token operator">==</span><span class="token operator">></span> Validating source_x86_64 files with sha256sums<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="21"></td><td><pre> code_x64_1.74.3.tar.gz <span class="token punctuation">..</span>. Passed</pre></td></tr><tr><td data-num="22"></td><td><pre><span class="token operator">==</span><span class="token operator">></span> Extracting sources<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="23"></td><td><pre> -<span class="token operator">></span> Extracting code_x64_1.74.3.tar.gz with bsdtar</pre></td></tr><tr><td data-num="24"></td><td><pre><span class="token operator">==</span><span class="token operator">></span> Entering fakeroot environment<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="25"></td><td><pre><span class="token operator">==</span><span class="token operator">></span> Starting package<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="26"></td><td><pre><span class="token operator">==</span><span class="token operator">></span> Tidying install<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="27"></td><td><pre> -<span class="token operator">></span> Removing libtool files<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="28"></td><td><pre> -<span class="token operator">></span> Purging unwanted files<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="29"></td><td><pre> -<span class="token operator">></span> Removing static library files<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="30"></td><td><pre> -<span class="token operator">></span> Stripping unneeded symbols from binaries and libraries<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="31"></td><td><pre> -<span class="token operator">></span> Compressing <span class="token function">man</span> and info pages<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="32"></td><td><pre><span class="token operator">==</span><span class="token operator">></span> Checking <span class="token keyword">for</span> packaging issues<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="33"></td><td><pre><span class="token operator">==</span><span class="token operator">></span> Creating package <span class="token string">"visual-studio-code-bin"</span><span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="34"></td><td><pre> -<span class="token operator">></span> Generating .PKGINFO file<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="35"></td><td><pre> -<span class="token operator">></span> Generating .BUILDINFO file<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="36"></td><td><pre> -<span class="token operator">></span> Adding <span class="token function">install</span> file<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="37"></td><td><pre> -<span class="token operator">></span> Generating .MTREE file<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="38"></td><td><pre> -<span class="token operator">></span> Compressing package<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="39"></td><td><pre><span class="token operator">==</span><span class="token operator">></span> Leaving fakeroot environment.</pre></td></tr><tr><td data-num="40"></td><td><pre><span class="token operator">==</span><span class="token operator">></span> Finished making: visual-studio-code-bin <span class="token number">1.74</span>.3-1 <span class="token punctuation">(</span>廿廿三年二月廿日 <span class="token punctuation">(</span>週一<span class="token punctuation">)</span> 廿時48分二秒<span class="token punctuation">)</span></pre></td></tr></table></figure><p>建立 package 後會產生需要的檔案,檢查有沒有產生 <code>visual-studio-code-bin-1.74.3-1-x86_64.pkg.tar.zst</code> 。</p>
<figure class="highlight bash"><figcaption data-lang="bash"><span>建立 package 後產生需要的檔案</span></figcaption><table><tr class="marked"><td data-num="1"></td><td><pre>$ <span class="token function">ls</span> <span class="token parameter variable">-a1</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token builtin class-name">.</span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token punctuation">..</span></pre></td></tr><tr><td data-num="4"></td><td><pre>code.desktop</pre></td></tr><tr><td data-num="5"></td><td><pre>code-url-handler.desktop</pre></td></tr><tr class="marked"><td data-num="6"></td><td><pre>code_x64_1.74.3.tar.gz</pre></td></tr><tr class="marked"><td data-num="7"></td><td><pre>pkg</pre></td></tr><tr><td data-num="8"></td><td><pre>PKGBUILD</pre></td></tr><tr class="marked"><td data-num="9"></td><td><pre>src</pre></td></tr><tr><td data-num="10"></td><td><pre>.SRCINFO</pre></td></tr><tr class="marked"><td data-num="11"></td><td><pre>visual-studio-code-bin-1.74.3-1-x86_64.pkg.tar.zst</pre></td></tr><tr><td data-num="12"></td><td><pre>visual-studio-code-bin.install</pre></td></tr><tr><td data-num="13"></td><td><pre>visual-studio-code-bin.sh</pre></td></tr><tr><td data-num="14"></td><td><pre>visual-studio-code-workspace.xml</pre></td></tr></table></figure><h2 id="安裝"><a class="anchor" href="#安裝">#</a> 安裝</h2>
<figure class="highlight bash"><figcaption data-lang="bash"><span>安裝 package</span></figcaption><table><tr class="marked"><td data-num="1"></td><td><pre>$ <span class="token function">sudo</span> pacman <span class="token parameter variable">-U</span> visual-studio-code-bin-1.74.3-1-x86_64.pkg.tar.zst</pre></td></tr><tr><td data-num="2"></td><td><pre>loading packages<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="3"></td><td><pre>resolving dependencies<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="4"></td><td><pre>looking <span class="token keyword">for</span> conflicting packages<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="5"></td><td><pre></pre></td></tr><tr><td data-num="6"></td><td><pre>Packages <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> visual-studio-code-bin-1.74.3-1</pre></td></tr><tr><td data-num="7"></td><td><pre></pre></td></tr><tr><td data-num="8"></td><td><pre>Total Installed Size: <span class="token number">331.05</span> MiB</pre></td></tr><tr><td data-num="9"></td><td><pre></pre></td></tr><tr><td data-num="10"></td><td><pre>:: Proceed with installation? <span class="token punctuation">[</span>Y/n<span class="token punctuation">]</span> y</pre></td></tr><tr><td data-num="11"></td><td><pre><span class="token punctuation">(</span><span class="token number">1</span>/1<span class="token punctuation">)</span> checking keys <span class="token keyword">in</span> keyring <span class="token punctuation">[</span><span class="token comment">####################################] 100%</span></pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token punctuation">(</span><span class="token number">1</span>/1<span class="token punctuation">)</span> checking package integrity <span class="token punctuation">[</span><span class="token comment">####################################] 100%</span></pre></td></tr><tr><td data-num="13"></td><td><pre><span class="token punctuation">(</span><span class="token number">1</span>/1<span class="token punctuation">)</span> loading package files <span class="token punctuation">[</span><span class="token comment">####################################] 100%</span></pre></td></tr><tr><td data-num="14"></td><td><pre><span class="token punctuation">(</span><span class="token number">1</span>/1<span class="token punctuation">)</span> checking <span class="token keyword">for</span> <span class="token function">file</span> conflicts <span class="token punctuation">[</span><span class="token comment">####################################] 100%</span></pre></td></tr><tr><td data-num="15"></td><td><pre><span class="token punctuation">(</span><span class="token number">1</span>/1<span class="token punctuation">)</span> checking available disk space <span class="token punctuation">[</span><span class="token comment">####################################] 100%</span></pre></td></tr><tr><td data-num="16"></td><td><pre>:: Processing package changes<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="17"></td><td><pre><span class="token punctuation">(</span><span class="token number">1</span>/1<span class="token punctuation">)</span> installing visual-studio-code-bin <span class="token punctuation">[</span><span class="token comment">####################################] 100%</span></pre></td></tr><tr><td data-num="18"></td><td><pre><span class="token operator">==</span><span class="token operator">></span> NOTE: Custom flags should be put directly in: ~/.config/code-flags.conf</pre></td></tr><tr><td data-num="19"></td><td><pre>Optional dependencies <span class="token keyword">for</span> visual-studio-code-bin</pre></td></tr><tr><td data-num="20"></td><td><pre> glib2: Needed <span class="token keyword">for</span> move to trash functionality <span class="token punctuation">[</span>installed<span class="token punctuation">]</span></pre></td></tr><tr><td data-num="21"></td><td><pre> libdbusmenu-glib: Needed <span class="token keyword">for</span> KDE global menu <span class="token punctuation">[</span>installed<span class="token punctuation">]</span></pre></td></tr><tr><td data-num="22"></td><td><pre> org.freedesktop.secrets: Needed <span class="token keyword">for</span> settings <span class="token function">sync</span> <span class="token punctuation">[</span>installed<span class="token punctuation">]</span></pre></td></tr><tr><td data-num="23"></td><td><pre> icu69: Needed <span class="token keyword">for</span> live share</pre></td></tr><tr><td data-num="24"></td><td><pre>:: Running post-transaction hooks<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="25"></td><td><pre><span class="token punctuation">(</span><span class="token number">1</span>/4<span class="token punctuation">)</span> Arming ConditionNeedsUpdate<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="26"></td><td><pre><span class="token punctuation">(</span><span class="token number">2</span>/4<span class="token punctuation">)</span> Updating the MIME <span class="token builtin class-name">type</span> database<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="27"></td><td><pre><span class="token punctuation">(</span><span class="token number">3</span>/4<span class="token punctuation">)</span> Refreshing PackageKit<span class="token punctuation">..</span>.</pre></td></tr><tr><td data-num="28"></td><td><pre><span class="token punctuation">(</span><span class="token number">4</span>/4<span class="token punctuation">)</span> Updating the desktop <span class="token function">file</span> MIME <span class="token builtin class-name">type</span> cache<span class="token punctuation">..</span>.</pre></td></tr></table></figure><h1 id="注意事項"><a class="anchor" href="#注意事項">#</a> 注意事項</h1>
<p>在 Linux 環境要安裝 <code>visual-studio-code-bin</code> 的版本,才有 <code>Remote Development</code> 套件可以安裝。</p>
<p><img loading="lazy" data-src="package-visual-studio-code-bin.png" alt="Visual Studio Code bin" /></p>
<h1 id="參考資料"><a class="anchor" href="#參考資料">#</a> 參考資料</h1>
<ul>
<li><a href="https://github.com/microsoft/vscode-remote-release/issues/7999">https://github.com/microsoft/vscode-remote-release/issues/7999</a></li>
<li><a href="https://github.com/microsoft/vscode/issues/130320">https://github.com/microsoft/vscode/issues/130320</a></li>
</ul>
</content>
<category term="Trouble" scheme="https://8loser.github.io/categories/Trouble/" />
<category term="VSCode" scheme="https://8loser.github.io/tags/VSCode/" />
<category term="Remote Development" scheme="https://8loser.github.io/tags/Remote-Development/" />
<updated>2023-02-20T06:10:40.000Z</updated>
</entry>
<entry>
<id>https://8loser.github.io/2023/02/19/newbie-guide/</id>
<title>新手指南</title>
<link rel="alternate" href="https://8loser.github.io/2023/02/19/newbie-guide/"/>
<content type="html"><h1 id="新手指南"><a class="anchor" href="#新手指南">#</a> 新手指南</h1>
<p>這是一篇新手進公司後整理內部開發流程的 <s>事故</s> 故事</p>
<h1 id="要有光"><a class="anchor" href="#要有光">#</a> 要有光</h1>
<p>上班第一天,要緊頭一件事就是 <span class="spoiler" title="你知道得太多了">認清自己在食物鏈中的位置</span> 熟悉開發環境,目前公司開發到佈署的流程是原始碼在每個人的環境都有一份,如果有修改再傳修改的檔案給知道怎麼佈署的人去佈署,這方式有時後會漏掉檔案,也很難搞清哪個才是最新版本的程式。而且每個人開發環境不同,剛拿到專案原始碼時啟動失敗,同學會教我一些奇計淫巧至今令我匪夷所思的方法(為什麼要修改 node_modules 內的檔案?)。</p>
<ul>
<li>改的檔案是最新版的嗎?</li>
<li>覆蓋別人給的檔案後,原本改好的程式不見了。</li>
<li>你給的檔案無法執行,說有缺少 function。</li>
<li>『可以只給提供修改的 function 嗎?』「我其實也不太確定耶,還是你整個貼上後試試看有沒有錯誤」</li>
</ul>
<h1 id="新手村"><a class="anchor" href="#新手村">#</a> 新手村</h1>
<p>村長跟我介紹村子內 NPC 的功能,還有 server 的佈署方式,程式碼上傳到 GCP linux VM 後使用 docker build 成 image,再使用 docker compose 啟動多個 container 運行服務。有兩個 VM 每個 VM 都有 5 個 container,除了前端、後端程式外還有串接其他服務,使用的程式語言有 Vue.js, Node.js, .NET Core 。</p>
<h1 id="程式一致"><a class="anchor" href="#程式一致">#</a> 程式一致</h1>
<p>為了解決程式碼同步問題,挑了可以免費 private 託管的版本控制服務,同學可以遠端上傳程式碼,其他人也可以同步。</p>
<ol>
<li class="quiz">使用的服務為 <span class="gap"></span> 。
<ul class="options">
<li class="correct">GitHub</li>
<li>PornHub</li>
</ul>
</li>
</ol>
<p>為什麼要選 GitHub 而不是 <s>PornHub</s> GitLab?忘記了,好像跟 CI/CD 的免費項目有關。難的不是選擇使用的版控服務,而是要上傳哪些程式碼?通常在 server 上運行的就是最新的程式碼,使用 <a href="https://winscp.net/">WinSCP</a> 抓下來後當作基準,因為其他同學還有改到一半未上傳的程式碼,所以也收集其他同學的程式碼進行整理合併。整理時發現不是每個人的開發環境設置都一樣,有的人用 Windows 有的人用 Mac。</p>
<p><div class="links"><div class="item" title="WinSCP" style="--block-color:#e9546b;"><a href="https://winscp.net/" class="image" data-background-image="https://winscp-static-746341.c.cdn77.org/assets/images/logos/logo.png?v=7008"></a>
<div class="info">
<a href="https://winscp.net/" class="title">WinSCP</a>
<p class="desc">https://winscp.net/</p>
</div></div></div></p>
<h1 id="環境一致"><a class="anchor" href="#環境一致">#</a> 環境一致</h1>
<p>雖然程式碼一致了,但相同的程式碼在不同開發環境卻會出現異常,<span class="spoiler" title="你知道得太多了">你就用 node 14 就好了阿,沒事幹麻升級自找麻煩 😒</span> 所以開發環境也要一致。最簡單的方法是大家都裝相同的 node 版本,凡是都有個 BUT,全部的專案使用的 node 並不是相同版本,而且不是每個人都會用 <a href="https://github.com/nvm-sh/nvmNVM">NVM</a>。<br />
雖然有的人用 Mac 有的人用 Windows,但是大家都是用 Visual Studio Code,所以把全部的專案都加上 <a href="https://code.visualstudio.com/docs/devcontainers/tutorial">Dev Containers</a>,之後所有人開發的時候,都使用 <a href="https://code.visualstudio.com/docs/devcontainers/tutorial">Dev Containers</a> 進入 container 進行開發。</p>
<p><div class="links"><div class="item" title="visual Studio Code" style="--block-color:#e9546b;"><a href="https://code.visualstudio.com/docs/devcontainers/containers" class="image" data-background-image="/assets/404.png"></a>
<div class="info">
<a href="https://code.visualstudio.com/docs/devcontainers/containers" class="title">Developing inside a Container</a>
<p class="desc">https://code.visualstudio.com/docs/devcontainers/containers</p>
</div></div><div class="item" title="八樓的人" style="--block-color:#e9546b;"><a href="/2022/05/13/Remote-Containers/" class="image" data-background-image="/assets/avatar.jpg"></a>
<div class="info">
<a href="/2022/05/13/Remote-Containers/" class="title">使用 VSCode 在 Docker container 內進行開發</a>
<p class="desc">/2022/05/13/Remote-Containers/</p>
</div></div></div></p>
<h1 id="docker-image-auto-build"><a class="anchor" href="#docker-image-auto-build">#</a> Docker image auto build</h1>
<p>上面提到程式最後都在 server 上 build image 後,使用 docker compose 建立 container 執行。 <ins>你終究要 image 的那為什麼不一開始就 image?</ins> 所以把每個專案都加上 <a href="https://docs.github.com/en/actions/quickstart">GitHub Action</a>,引用原本就有的 Dockerfile 修改,程式上傳後會自動打包成 docker image 且 push 到 <a href="https://docs.github.com/en/packages/learn-github-packages/introduction-to-github-packages">GitHub Package</a></p>
<p>在 GitHub Action 使用下面的 yml,程式碼上傳到 GitHub 後會自動打包成 docker image</p>
<p><a href="https://gist.github.com/8loser/4f78378d21358e8d4174bb9e8d872af3">Gist Auto build docker image yml</a></p>
<p>如果設定成功 push 程式碼後可以在 GitHub Action 看到執行動作<br />
<img loading="lazy" data-src="github-action.png" alt="GitHub Action" /></p>
<p><div class="links"><div class="item" title="Quickstart for GitHub Actions" style="--block-color:#e9546b;"><a href="https://docs.github.com/en/actions/quickstart" class="image" data-background-image="/assets/404.png"></a>
<div class="info">
<a href="https://docs.github.com/en/actions/quickstart" class="title">Quickstart for GitHub Actions</a>
<p class="desc">https://docs.github.com/en/actions/quickstart</p>
</div></div><div class="item" title="docker/build-push-action" style="--block-color:#e9546b;"><a href="https://github.com/docker/build-push-action" class="image" data-background-image="/assets/404.png"></a>
<div class="info">
<a href="https://github.com/docker/build-push-action" class="title">docker/build-push-action</a>
<p class="desc">https://github.com/docker/build-push-action</p>
</div></div></div></p>
<h1 id="docker-管理"><a class="anchor" href="#docker-管理">#</a> Docker 管理</h1>
<p>鑑於不是所有同學都習慣用 linux,所以在 server 裝上 <a href="https://www.portainer.io">portainer</a>,可以使用 Web 界面控制 server 上的 docker。一天又平安的過去了,感謝飛天小女警的努力。</p>
<p><div class="links"><div class="item" title="Install Portainer CE with Docker on Linux" style="--block-color:#e9546b;"><a href="https://docs.portainer.io/start/install-ce/server/docker/linux" class="image" data-background-image="/assets/404.png"></a>
<div class="info">
<a href="https://docs.portainer.io/start/install-ce/server/docker/linux" class="title">Install Portainer CE with Docker on Linux</a>
<p class="desc">https://docs.portainer.io/start/install-ce/server/docker/linux</p>
</div></div></div></p>
<h1 id="自動佈署"><a class="anchor" href="#自動佈署">#</a> 自動佈署</h1>
<p>出現 bug 急著修正的時候,可能一天要上傳程式到 server 八百次,但不是所有人都知道怎麼更新到 server,<span class="spoiler" title="你知道得太多了">所以維運的同學要多體諒工程師</span> 所以在 portainer 開啟 swarm 功能後,service 就可以啟用 webhook 接收更新通知,收到通知後自動 pull 新的 docker image 進行佈署,不知道怎麼佈署的人可以 <code>POST</code> 呼叫 webhook 進行 service 更新。</p>
<figure class="highlight shell"><figcaption data-lang="Bash"><span>開啟 docker swarm 方法</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">docker</span> swarm init</pre></td></tr></table></figure><p>設定完成後可以在 portainer 選單看到 service 項目<br />
<img loading="lazy" data-src="portainer-menu.png" alt="portainer menu" /></p>
<p>進入 service 可以開啟 <code>Service webhook</code> ,產生的網址就是用來接收通知拉取新 image 重新佈署的<br />
<img loading="lazy" data-src="portainer-service.png" alt="portainer service" /></p>
<p>更新 service 還要呼叫 webhook 有點麻煩,就交給 GitHub Action 吧!<br />
在 GitHub Action 加入下面設定後,每次 push/pull_request (根據 main.yml 設定) 就會自動更新。</p>
<figure class="highlight yml"><figcaption data-lang="YAML"><span>呼叫 webhook 進行更新</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> Call webhook update service</pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token key atrule">uses</span><span class="token punctuation">:</span> muinmomin/webhook<span class="token punctuation">-</span>[email protected]</pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token key atrule">with</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token key atrule">url</span><span class="token punctuation">:</span> <span class="token comment"># 要通知的 webhook URL</span></pre></td></tr></table></figure><p><div class="links"><div class="item" title="portainer.io" style="--block-color:#e9546b;"><a href="https://docs.portainer.io/user/docker/services/webhooks#enabling-a-service-webhook" class="image" data-background-image="/assets/404.png"></a>
<div class="info">
<a href="https://docs.portainer.io/user/docker/services/webhooks#enabling-a-service-webhook" class="title">Enabling a service webhook</a>
<p class="desc">https://docs.portainer.io/user/docker/services/webhooks#enabling-a-service-webhook</p>
</div></div><div class="item" title="muinmomin/webhook-action" style="--block-color:#e9546b;"><a href="https://github.com/muinmomin/webhook-action" class="image" data-background-image="/assets/404.png"></a>
<div class="info">
<a href="https://github.com/muinmomin/webhook-action" class="title">muinmomin/webhook-action</a>
<p class="desc">https://github.com/muinmomin/webhook-action</p>
</div></div></div></p>
<h1 id="正式站測試站"><a class="anchor" href="#正式站測試站">#</a> 正式站 / 測試站</h1>
<p>當業務外出跟客戶展示系統功能時,如果網站一直更新重啟服務中斷,在客戶端的同學會很尷尬,<span class="spoiler" title="你知道得太多了">所以有業務在外展示時工程師可以放假</span> 所以把線上系統分為正式站跟測試站。</p>
<ul class="task-list">
<li class="task-list-item"><input type="checkbox" id="cbx_0" checked="true" disabled="true" /><label for="cbx_0"> GCP VM 兩台變四台</label></li>
<li class="task-list-item"><input type="checkbox" id="cbx_1" checked="true" disabled="true" /><label for="cbx_1"> 設定測試站 subdomain</label></li>
<li class="task-list-item"><input type="checkbox" id="cbx_2" checked="true" disabled="true" /><label for="cbx_2"> GitHub 設定 main/test 兩個分支</label></li>
<li class="task-list-item"><input type="checkbox" id="cbx_3" checked="true" disabled="true" /><label for="cbx_3"> GitHub Action 設定只有 test 分支 push 時才自動更新到測試站</label></li>
<li class="task-list-item"><input type="checkbox" id="cbx_4" disabled="true" /><label for="cbx_4"> 你升職,我加薪,大家開香檳~YA</label></li>
</ul>
<p><img loading="lazy" data-src="Love-on-Delivery.gif" alt="破壞之王" /></p>
</content>
<category term="Need to Know" scheme="https://8loser.github.io/categories/Need-to-Know/" />
<category term="Story" scheme="https://8loser.github.io/tags/Story/" />
<updated>2023-02-19T07:04:11.000Z</updated>
</entry>
<entry>
<id>https://8loser.github.io/2023/02/11/redis-cluster/</id>
<title>GKE 佈署 Redis 叢集</title>
<link rel="alternate" href="https://8loser.github.io/2023/02/11/redis-cluster/"/>
<content type="html"><h1 id="環境"><a class="anchor" href="#環境">#</a> 環境</h1>
<p>在 <a href="https://cloud.google.com/kubernetes-engine?hl=zh-tw">Google Kubernetes Engine (GKE)</a> 內建置 Redis 叢集</p>
<ul>
<li>GKE node: g1-small * 2 (version 1.24.8-gke.2000)</li>
<li>Redis 7</li>
</ul>
<h1 id="建立-configmap"><a class="anchor" href="#建立-configmap">#</a> 建立 ConfigMap</h1>
<p>建立給 redis 節點使用的共用設定檔,名稱為 <code>redis-cluster</code> ,之後建立為 volume 讓每個容器使用</p>
<figure class="highlight yaml"><figcaption data-lang="YAML"><span>ConfigMap</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1</pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token key atrule">kind</span><span class="token punctuation">:</span> ConfigMap</pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token key atrule">metadata</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token key atrule">name</span><span class="token punctuation">:</span> redis<span class="token punctuation">-</span>cluster</pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token key atrule">data</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token key atrule">update-node.sh</span><span class="token punctuation">:</span> <span class="token punctuation">|</span><span class="token scalar string"></pre></td></tr><tr><td data-num="7"></td><td><pre> #!/bin/sh</pre></td></tr><tr><td data-num="8"></td><td><pre> REDIS_NODES="/data/nodes.conf"</pre></td></tr><tr><td data-num="9"></td><td><pre> sed -i -e "/myself/ s/[0-9]\&#123;1,3\&#125;\.[0-9]\&#123;1,3\&#125;\.[0-9]\&#123;1,3\&#125;\.[0-9]\&#123;1,3\&#125;/$&#123;POD_IP&#125;/" $&#123;REDIS_NODES&#125;</pre></td></tr><tr><td data-num="10"></td><td><pre> exec "$@"</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token key atrule">redis.conf</span><span class="token punctuation">:</span> <span class="token punctuation">|</span>+</pre></td></tr><tr><td data-num="12"></td><td><pre> cluster<span class="token punctuation">-</span>enabled yes</pre></td></tr><tr><td data-num="13"></td><td><pre> cluster<span class="token punctuation">-</span>require<span class="token punctuation">-</span>full<span class="token punctuation">-</span>coverage no</pre></td></tr><tr><td data-num="14"></td><td><pre> cluster<span class="token punctuation">-</span>node<span class="token punctuation">-</span>timeout 15000</pre></td></tr><tr><td data-num="15"></td><td><pre> cluster<span class="token punctuation">-</span>config<span class="token punctuation">-</span>file /data/nodes.conf</pre></td></tr><tr><td data-num="16"></td><td><pre> cluster<span class="token punctuation">-</span>migration<span class="token punctuation">-</span>barrier 1</pre></td></tr><tr><td data-num="17"></td><td><pre> appendonly yes</pre></td></tr><tr><td data-num="18"></td><td><pre> protected<span class="token punctuation">-</span>mode no</pre></td></tr></table></figure><p>建立成功後可以在 GKE 界面的 <code>Secret與ConfigMap</code> 內看到新增的 <code>redis-cluster</code></p>
<p><img loading="lazy" data-src="gke-configmap.png" alt="ConfigMap" /></p>
<h1 id="建立-statefulset"><a class="anchor" href="#建立-statefulset">#</a> 建立 StatefulSet</h1>
<ul>
<li>StatefulSet 需要使用 Kubernetes v1.9 或之後的版本才支援</li>
<li>.spec.selector.matchLabels 要跟 .spec.template.metadata.labels 相同</li>
<li>.spec.replicas 至少要 6 個,redis cluster 至少要 6 個節點;3 個 master, 3 個 slave, 不過還沒查到為什麼。</li>
</ul>
<p>參考文章在 .spec.selector.template.spec.containers.volumes.defaultMode 是寫 <code>0755</code> (八進位),但是我在 Lens 內執行時會出現下面錯誤,所以改成十進位的 <code>493</code></p>
<div class="note warning">
<p>create Pod redis-cluster-0 in StatefulSet redis-cluster failed error: Pod &quot;redis-cluster-0&quot; is invalid: [spec.volumes[1].configMap.defaultMode: Invalid value: 755: must be a number between 0 and 0777 (octal), both inclusive, spec.containers[0].volumeMounts[0].name: Not found: &quot;conf&quot;]</p>
</div>
<p>完整 yaml</p>
<figure class="highlight yaml"><figcaption data-lang="YAML"><span>StatefulSet</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> apps/v1</pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token key atrule">kind</span><span class="token punctuation">:</span> StatefulSet</pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token key atrule">metadata</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token key atrule">name</span><span class="token punctuation">:</span> redis<span class="token punctuation">-</span>cluster</pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token key atrule">spec</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token key atrule">serviceName</span><span class="token punctuation">:</span> redis<span class="token punctuation">-</span>cluster</pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token key atrule">replicas</span><span class="token punctuation">:</span> <span class="token number">6</span> <span class="token comment"># by default is 1</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token key atrule">selector</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token key atrule">matchLabels</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token key atrule">app</span><span class="token punctuation">:</span> redis<span class="token punctuation">-</span>cluster <span class="token comment"># has to match .spec.template.metadata.labels</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token key atrule">template</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token key atrule">metadata</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token key atrule">labels</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token key atrule">app</span><span class="token punctuation">:</span> redis<span class="token punctuation">-</span>cluster <span class="token comment"># has to match .spec.selector.matchLabels</span></pre></td></tr><tr><td data-num="15"></td><td><pre> <span class="token key atrule">spec</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="16"></td><td><pre> <span class="token key atrule">containers</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> redis</pre></td></tr><tr><td data-num="18"></td><td><pre> <span class="token key atrule">image</span><span class="token punctuation">:</span> redis<span class="token punctuation">:</span><span class="token number">7</span></pre></td></tr><tr><td data-num="19"></td><td><pre> <span class="token key atrule">ports</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token punctuation">-</span> <span class="token key atrule">containerPort</span><span class="token punctuation">:</span> <span class="token number">6379</span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token key atrule">name</span><span class="token punctuation">:</span> client</pre></td></tr><tr><td data-num="22"></td><td><pre> <span class="token punctuation">-</span> <span class="token key atrule">containerPort</span><span class="token punctuation">:</span> <span class="token number">16379</span></pre></td></tr><tr><td data-num="23"></td><td><pre> <span class="token key atrule">name</span><span class="token punctuation">:</span> gossip</pre></td></tr><tr><td data-num="24"></td><td><pre> <span class="token key atrule">command</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"/conf/update-node.sh"</span><span class="token punctuation">,</span> <span class="token string">"redis-server"</span><span class="token punctuation">,</span> <span class="token string">"/conf/redis.conf"</span><span class="token punctuation">]</span></pre></td></tr><tr><td data-num="25"></td><td><pre> <span class="token key atrule">env</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="26"></td><td><pre> <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> POD_IP</pre></td></tr><tr><td data-num="27"></td><td><pre> <span class="token key atrule">valueFrom</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="28"></td><td><pre> <span class="token key atrule">fieldRef</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="29"></td><td><pre> <span class="token key atrule">fieldPath</span><span class="token punctuation">:</span> status.podIP</pre></td></tr><tr><td data-num="30"></td><td><pre> <span class="token key atrule">volumeMounts</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="31"></td><td><pre> <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> conf</pre></td></tr><tr><td data-num="32"></td><td><pre> <span class="token key atrule">mountPath</span><span class="token punctuation">:</span> /conf</pre></td></tr><tr><td data-num="33"></td><td><pre> <span class="token key atrule">readOnly</span><span class="token punctuation">:</span> <span class="token boolean important">false</span></pre></td></tr><tr><td data-num="34"></td><td><pre> <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> data</pre></td></tr><tr><td data-num="35"></td><td><pre> <span class="token key atrule">mountPath</span><span class="token punctuation">:</span> /data</pre></td></tr><tr><td data-num="36"></td><td><pre> <span class="token key atrule">readOnly</span><span class="token punctuation">:</span> <span class="token boolean important">false</span></pre></td></tr><tr><td data-num="37"></td><td><pre> <span class="token key atrule">volumes</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="38"></td><td><pre> <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> conf</pre></td></tr><tr><td data-num="39"></td><td><pre> <span class="token key atrule">configMap</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="40"></td><td><pre> <span class="token key atrule">name</span><span class="token punctuation">:</span> redis<span class="token punctuation">-</span>cluster</pre></td></tr><tr><td data-num="41"></td><td><pre> <span class="token comment"># defaultMode: 0755</span></pre></td></tr><tr><td data-num="42"></td><td><pre> <span class="token key atrule">defaultMode</span><span class="token punctuation">:</span> <span class="token number">493</span></pre></td></tr><tr><td data-num="43"></td><td><pre> <span class="token key atrule">volumeClaimTemplates</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="44"></td><td><pre> <span class="token punctuation">-</span> <span class="token key atrule">metadata</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="45"></td><td><pre> <span class="token key atrule">name</span><span class="token punctuation">:</span> data</pre></td></tr><tr><td data-num="46"></td><td><pre> <span class="token key atrule">spec</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="47"></td><td><pre> <span class="token key atrule">accessModes</span><span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token string">"ReadWriteOnce"</span> <span class="token punctuation">]</span></pre></td></tr><tr><td data-num="48"></td><td><pre> <span class="token key atrule">resources</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="49"></td><td><pre> <span class="token key atrule">requests</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="50"></td><td><pre> <span class="token key atrule">storage</span><span class="token punctuation">:</span> 1Gi</pre></td></tr></table></figure><p>執行完等一下<br />
<img loading="lazy" data-src="Let_the_Bullets_Fly.png" alt="讓子彈飛一會兒" /></p>
<p>之後可以在 GKE 的 <code>工作負載</code> 內看到 6 個 Pod 建立完成<br />
<img loading="lazy" data-src="gke-stateful.png" alt="Pods" /></p>
<p><code>儲存空間</code> 也會產生 6 個 PVC (PersistentVolumeClaim)<br />
<img loading="lazy" data-src="gke-pvc.png" alt="PVC" /></p>
<p>或者使用指令查看</p>
<figure class="highlight shell"><figcaption data-lang="Bash"><span>kubectl get pods</span></figcaption><table><tr><td data-num="1"></td><td><pre>$ kubectl get pods</pre></td></tr><tr><td data-num="2"></td><td><pre>NAME READY STATUS RESTARTS AGE</pre></td></tr><tr><td data-num="3"></td><td><pre>redis-cluster-0 <span class="token number">1</span>/1 Running <span class="token number">0</span> 8m31s</pre></td></tr><tr><td data-num="4"></td><td><pre>redis-cluster-1 <span class="token number">1</span>/1 Running <span class="token number">0</span> 8m19s</pre></td></tr><tr><td data-num="5"></td><td><pre>redis-cluster-2 <span class="token number">1</span>/1 Running <span class="token number">0</span> 8m7s</pre></td></tr><tr><td data-num="6"></td><td><pre>redis-cluster-3 <span class="token number">1</span>/1 Running <span class="token number">0</span> 7m56s</pre></td></tr><tr><td data-num="7"></td><td><pre>redis-cluster-4 <span class="token number">1</span>/1 Running <span class="token number">0</span> 7m39s</pre></td></tr><tr><td data-num="8"></td><td><pre>redis-cluster-5 <span class="token number">1</span>/1 Running <span class="token number">0</span> 7m28s</pre></td></tr></table></figure><figure class="highlight shell"><figcaption data-lang="Bash"><span>kubectl get pv</span></figcaption><table><tr><td data-num="1"></td><td><pre>$ kubectl get <span class="token function">pv</span></pre></td></tr><tr><td data-num="2"></td><td><pre>NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE</pre></td></tr><tr><td data-num="3"></td><td><pre>pvc-01fc7eb6-e99a-4111-8923-53229eb112b4 1Gi RWO Delete Bound default/data-redis-cluster-1 standard-rwo 21m</pre></td></tr><tr><td data-num="4"></td><td><pre>pvc-4bc387e4-dd4c-4400-b99a-e75a720e509b 1Gi RWO Delete Bound default/data-redis-cluster-2 standard-rwo 21m</pre></td></tr><tr><td data-num="5"></td><td><pre>pvc-af768f00-7889-4fa5-9ef8-cb95337ef38a 1Gi RWO Delete Bound default/data-redis-cluster-5 standard-rwo 20m</pre></td></tr><tr><td data-num="6"></td><td><pre>pvc-b6dadea9-b10e-42cb-8ae4-729b186e8b7c 1Gi RWO Delete Bound default/data-redis-cluster-0 standard-rwo 21m</pre></td></tr><tr><td data-num="7"></td><td><pre>pvc-c42ebfa4-a726-42f5-b146-18c28de544a4 1Gi RWO Delete Bound default/data-redis-cluster-4 standard-rwo 20m</pre></td></tr><tr><td data-num="8"></td><td><pre>pvc-d1d4de96-2f91-4050-9707-8fd802bd7fb4 1Gi RWO Delete Bound default/data-redis-cluster-3 standard-rwo 21m</pre></td></tr></table></figure><h1 id="建立-service"><a class="anchor" href="#建立-service">#</a> 建立 Service</h1>
<figure class="highlight yaml"><figcaption data-lang="YAML"><span>Service</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1</pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token key atrule">kind</span><span class="token punctuation">:</span> Service</pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token key atrule">metadata</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token key atrule">name</span><span class="token punctuation">:</span> redis<span class="token punctuation">-</span>cluster</pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token key atrule">spec</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token key atrule">ports</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token punctuation">-</span> <span class="token key atrule">port</span><span class="token punctuation">:</span> <span class="token number">6379</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token key atrule">targetPort</span><span class="token punctuation">:</span> <span class="token number">6379</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token key atrule">name</span><span class="token punctuation">:</span> client</pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token punctuation">-</span> <span class="token key atrule">port</span><span class="token punctuation">:</span> <span class="token number">16379</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token key atrule">targetPort</span><span class="token punctuation">:</span> <span class="token number">16379</span></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token key atrule">name</span><span class="token punctuation">:</span> gossip</pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token key atrule">selector</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token key atrule">app</span><span class="token punctuation">:</span> redis<span class="token punctuation">-</span>cluster</pre></td></tr></table></figure><p>執行完檢查 Service <code>redis-cluster</code> 是否成功建立<br />
<img loading="lazy" data-src="gke-service.png" alt="service" /></p>
<figure class="highlight shell"><figcaption data-lang="Bash"><span>kubectl get service redis-cluster</span></figcaption><table><tr><td data-num="1"></td><td><pre>$ kubectl get <span class="token function">service</span> redis-cluster</pre></td></tr><tr><td data-num="2"></td><td><pre>NAME TYPE CLUSTER-IP EXTERNAL-IP PORT<span class="token punctuation">(</span>S<span class="token punctuation">)</span> AGE</pre></td></tr><tr><td data-num="3"></td><td><pre>redis-cluster ClusterIP <span class="token number">10.80</span>.5.184 <span class="token operator">&lt;</span>none<span class="token operator">></span> <span class="token number">6379</span>/TCP,16379/TCP 2m50s</pre></td></tr></table></figure><h1 id="建立-redis-叢集"><a class="anchor" href="#建立-redis-叢集">#</a> 建立 Redis 叢集</h1>
<p>參考的文章使用的指令如下</p>
<figure class="highlight shell"><figcaption data-lang="Bash"><span>create redis-cluster</span></figcaption><table><tr><td data-num="1"></td><td><pre>kubectl <span class="token builtin class-name">exec</span> <span class="token parameter variable">-it</span> redis-cluster-0 -- redis-cli <span class="token parameter variable">--cluster</span> create --cluster-replicas <span class="token number">1</span> <span class="token variable"><span class="token variable">$(</span>kubectl get pods <span class="token parameter variable">-l</span> <span class="token assign-left variable">app</span><span class="token operator">=</span>redis-cluster <span class="token parameter variable">-o</span> <span class="token assign-left variable">jsonpath</span><span class="token operator">=</span><span class="token string">'&#123;range.items[*]&#125;&#123;.status.podIP&#125;:6379 '</span><span class="token variable">)</span></span></pre></td></tr></table></figure><p>實際實行結果會出現如下錯誤</p>
<div class="note danger">
<p>kubectl exec -it redis-cluster-0 -- redis-cli --cluster create --cluster-replicas 1 $(kubectl get pods -l app=redis-cluster -o jsonpath='{range.items[*]}{.status.podIP}:6379 ')</p>
</div>
<p>查看原因是 <code>kubectl get pods -l app=redis-cluster -o jsonpath='&#123;range.items[*]&#125;&#123;.status.podIP&#125;</code> 會多一組空的 IP</p>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre>$ kubectl get pods <span class="token parameter variable">-l</span> <span class="token assign-left variable">app</span><span class="token operator">=</span>redis-cluster <span class="token parameter variable">-o</span> <span class="token assign-left variable">jsonpath</span><span class="token operator">=</span><span class="token string">'&#123;range.items[*]&#125;&#123;.status.podIP&#125;:6379 '</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token number">10.76</span>.2.30:6379 <span class="token number">10.76</span>.1.32:6379 <span class="token number">10.76</span>.2.31:6379 <span class="token number">10.76</span>.1.33:6379 <span class="token number">10.76</span>.2.32:6379 <span class="token number">10.76</span>.1.34:6379 :6379</pre></td></tr></table></figure><p>可以使用下面指令查看比較明顯</p>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre>$ kubectl get pods <span class="token parameter variable">-l</span> <span class="token assign-left variable">app</span><span class="token operator">=</span>redis-cluster <span class="token parameter variable">-o</span> <span class="token assign-left variable">jsonpath</span><span class="token operator">=</span><span class="token string">'&#123;range.items[*]&#125;&#123;.status.podIP&#125;:6379&#123;"\n"&#125;'</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token number">10.76</span>.2.30:6379</pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token number">10.76</span>.1.32:6379</pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token number">10.76</span>.2.31:6379</pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token number">10.76</span>.1.33:6379</pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token number">10.76</span>.2.32:6379</pre></td></tr><tr><td data-num="7"></td><td><pre><span class="token number">10.76</span>.1.34:6379</pre></td></tr><tr class="marked"><td data-num="8"></td><td><pre>:6379</pre></td></tr></table></figure><p>修改後指令如下</p>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre>kubectl <span class="token builtin class-name">exec</span> <span class="token parameter variable">-it</span> redis-cluster-0 -- redis-cli <span class="token parameter variable">--cluster</span> create --cluster-replicas <span class="token number">1</span> <span class="token variable"><span class="token variable">$(</span>kubectl get pods <span class="token parameter variable">-o</span><span class="token operator">=</span>jsonpath<span class="token operator">=</span><span class="token string">'&#123;range .items[*]&#125;&#123;.status.podIP&#125;:6379 &#123;end&#125;'</span><span class="token variable">)</span></span></pre></td></tr></table></figure><p><code>Can I set the above configuration?</code> 輸入 <code>yes</code> ,執行結果可以看到建立了 3 個 redis master 節點,3 個 slave 節點。</p>
<details class="info"><summary>執行結果</summary><div>
<p>$ kubectl exec -it redis-cluster-0 -- redis-cli --cluster create --cluster-replicas 1 $(kubectl get pods -o=jsonpath='{range .items[*]}{.status.podIP}:6379 {end}')<br />
&gt;&gt;&gt; Performing hash slots allocation on 6 nodes...<br />
Master[0] -&gt; Slots 0 - 5460<br />
Master[1] -&gt; Slots 5461 - 10922<br />
Master[2] -&gt; Slots 10923 - 16383<br />
Adding replica 10.76.2.32:6379 to 10.76.2.30:6379<br />
Adding replica 10.76.1.34:6379 to 10.76.1.32:6379<br />
Adding replica 10.76.1.33:6379 to 10.76.2.31:6379<br />
M: 05ecf3912ed0a5517ab74fd17f81d02a3314a833 10.76.2.30:6379<br />
slots:[0-5460] (5461 slots) master<br />
M: 9da23852cfd0a7489c2f53ec743363e48dea378b 10.76.1.32:6379<br />
slots:[5461-10922] (5462 slots) master<br />
M: 379127b6974b6acc59e5fb194361749e682bdc97 10.76.2.31:6379<br />
slots:[10923-16383] (5461 slots) master<br />
S: 5105cdd3a6637e3844316c557f81c68b231703e7 10.76.1.33:6379<br />
replicates 379127b6974b6acc59e5fb194361749e682bdc97<br />
S: dde0a9ef27e044cd124814529305732c9ab0d9dd 10.76.2.32:6379<br />
replicates 05ecf3912ed0a5517ab74fd17f81d02a3314a833<br />
S: 8a89a45f3161b606b13f1ede95fec240de2bcf9d 10.76.1.34:6379<br />
replicates 9da23852cfd0a7489c2f53ec743363e48dea378b<br />
Can I set the above configuration? (type 'yes' to accept): yes<br />
&gt;&gt;&gt; Nodes configuration updated<br />
&gt;&gt;&gt; Assign a different config epoch to each node<br />
&gt;&gt;&gt; Sending CLUSTER MEET messages to join the cluster<br />
Waiting for the cluster to join</p>
<p>&gt;&gt;&gt; Performing Cluster Check (using node 10.76.2.30:6379)<br />
M: 05ecf3912ed0a5517ab74fd17f81d02a3314a833 10.76.2.30:6379<br />
slots:[0-5460] (5461 slots) master<br />
1 additional replica(s)<br />
S: dde0a9ef27e044cd124814529305732c9ab0d9dd 10.76.2.32:6379<br />
slots: (0 slots) slave<br />
replicates 05ecf3912ed0a5517ab74fd17f81d02a3314a833<br />
S: 5105cdd3a6637e3844316c557f81c68b231703e7 10.76.1.33:6379<br />
slots: (0 slots) slave<br />
replicates 379127b6974b6acc59e5fb194361749e682bdc97<br />
M: 379127b6974b6acc59e5fb194361749e682bdc97 10.76.2.31:6379<br />
slots:[10923-16383] (5461 slots) master<br />
1 additional replica(s)<br />
M: 9da23852cfd0a7489c2f53ec743363e48dea378b 10.76.1.32:6379<br />
slots:[5461-10922] (5462 slots) master<br />
1 additional replica(s)<br />
S: 8a89a45f3161b606b13f1ede95fec240de2bcf9d 10.76.1.34:6379<br />
slots: (0 slots) slave<br />
replicates 9da23852cfd0a7489c2f53ec743363e48dea378b<br />
[OK] All nodes agree about slots configuration.<br />
&gt;&gt;&gt; Check for open slots...<br />
&gt;&gt;&gt; Check slots coverage...<br />
[OK] All 16384 slots covered.</p>
</div></details>
<h1 id="驗證-redis-叢集"><a class="anchor" href="#驗證-redis-叢集">#</a> 驗證 Redis 叢集</h1>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre>kubectl <span class="token builtin class-name">exec</span> <span class="token parameter variable">-it</span> redis-cluster-0 -- redis-cli cluster info</pre></td></tr></table></figure><details class="info"><summary>執行結果</summary><div>
<p>$ kubectl exec -it redis-cluster-0 -- redis-cli cluster info<br />
cluster_state:ok<br />
cluster_slots_assigned:16384<br />
cluster_slots_ok:16384<br />
cluster_slots_pfail:0<br />
cluster_slots_fail:0<br />
cluster_known_nodes:6<br />
cluster_size:3<br />
cluster_current_epoch:6<br />
cluster_my_epoch:1<br />
cluster_stats_messages_ping_sent:273<br />
cluster_stats_messages_pong_sent:278<br />
cluster_stats_messages_sent:551<br />
cluster_stats_messages_ping_received:273<br />
cluster_stats_messages_pong_received:273<br />
cluster_stats_messages_meet_received:5<br />
cluster_stats_messages_received:551<br />
total_cluster_links_buffer_limit_exceeded:0</p>
</div></details>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">for</span> <span class="token for-or-select variable">x</span> <span class="token keyword">in</span> <span class="token variable"><span class="token variable">$(</span><span class="token function">seq</span> <span class="token number">0</span> <span class="token number">5</span><span class="token variable">)</span></span><span class="token punctuation">;</span> <span class="token keyword">do</span> <span class="token builtin class-name">echo</span> <span class="token string">"redis-cluster-<span class="token variable">$x</span>"</span><span class="token punctuation">;</span> kubectl <span class="token builtin class-name">exec</span> redis-cluster-<span class="token variable">$x</span> -- redis-cli role<span class="token punctuation">;</span> <span class="token builtin class-name">echo</span><span class="token punctuation">;</span> <span class="token keyword">done</span></pre></td></tr></table></figure><details class="info"><summary>執行結果</summary><div>
<p>$ for x in <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>s</mi><mi>e</mi><mi>q</mi><mn>05</mn><mo stretchy="false">)</mo><mo separator="true">;</mo><mi>d</mi><mi>o</mi><mi>e</mi><mi>c</mi><mi>h</mi><mi>o</mi><mi mathvariant="normal">&quot;</mi><mi>r</mi><mi>e</mi><mi>d</mi><mi>i</mi><mi>s</mi><mo>−</mo><mi>c</mi><mi>l</mi><mi>u</mi><mi>s</mi><mi>t</mi><mi>e</mi><mi>r</mi><mo>−</mo></mrow><annotation encoding="application/x-tex">(seq 0 5); do echo &quot;redis-cluster-</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal">se</span><span class="mord mathnormal" style="margin-right:0.03588em;">q</span><span class="mord">05</span><span class="mclose">)</span><span class="mpunct">;</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">d</span><span class="mord mathnormal">oec</span><span class="mord mathnormal">h</span><span class="mord mathnormal">o</span><span class="mord">&quot;</span><span class="mord mathnormal">re</span><span class="mord mathnormal">d</span><span class="mord mathnormal">i</span><span class="mord mathnormal">s</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7778em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">c</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">u</span><span class="mord mathnormal">s</span><span class="mord mathnormal">t</span><span class="mord mathnormal" style="margin-right:0.02778em;">er</span><span class="mord">−</span></span></span></span>x&quot;; kubectl exec redis-cluster-$x -- redis-cli role; echo; done<br />
redis-cluster-0<br />
master<br />
504<br />
10.76.2.32<br />
6379<br />
504</p>
<p>redis-cluster-1<br />
master<br />
504<br />
10.76.1.34<br />
6379<br />
504</p>
<p>redis-cluster-2<br />
master<br />
490<br />
10.76.1.33<br />
6379<br />
490</p>
<p>redis-cluster-3<br />
slave<br />
10.76.2.31<br />
6379<br />
connected<br />
490</p>
<p>redis-cluster-4<br />
slave<br />
10.76.2.30<br />
6379<br />
connected<br />
504</p>
<p>redis-cluster-5<br />
slave<br />
10.76.1.32<br />
6379<br />
connected<br />
504</p>
</div></details>
<h1 id="yaml-檔案"><a class="anchor" href="#yaml-檔案">#</a> YAML 檔案</h1>
<p><a href="https://github.com/8loser/redis-sts">GitHub: 8loser/redis-sts</a></p>
<h1 id="參考"><a class="anchor" href="#參考">#</a> 參考</h1>
<p><a href="https://www.suse.com/c/rancher_blog/deploying-redis-cluster-on-top-of-kubernetes/">Deploying Redis Cluster on Top of Kubernetes February 22, 2019 | By: Rancher Admin</a></p>
</content>
<category term="Redis" scheme="https://8loser.github.io/tags/Redis/" />
<category term="GKE" scheme="https://8loser.github.io/tags/GKE/" />
<category term="Kubernetes" scheme="https://8loser.github.io/tags/Kubernetes/" />
<updated>2023-02-11T10:07:24.000Z</updated>
</entry>
<entry>
<id>https://8loser.github.io/2023/01/04/gcp-init/</id>
<title>GCP VM 初始化</title>
<link rel="alternate" href="https://8loser.github.io/2023/01/04/gcp-init/"/>
<content type="html"><h1 id="主旨"><a class="anchor" href="#主旨">#</a> 主旨</h1>
<p>把專案運行的 GCP VM 環境佈署動作整理,建立 shell script 進行快速佈署。使用作業系統為 Linux Ubuntu</p>
<h1 id="執行之前"><a class="anchor" href="#執行之前">#</a> 執行之前</h1>
<p>先執行下面指令,切換為 root 角色</p>
<figure class="highlight shell"><figcaption data-lang="Bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">sudo</span> <span class="token function">su</span> -</pre></td></tr></table></figure><h1 id="要新增的-linux-帳號"><a class="anchor" href="#要新增的-linux-帳號">#</a> 要新增的 Linux 帳號</h1>
<p>把要新增的帳號、密碼作為變數寫在 script 最上面,為了給共同維護的人登入用的。</p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token assign-left variable">ACCOUNT</span><span class="token operator">=</span><span class="token operator">&lt;</span>帳號<span class="token operator">></span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token assign-left variable">PASSWORD</span><span class="token operator">=</span><span class="token operator">&lt;</span>密碼<span class="token operator">></span></pre></td></tr></table></figure><h1 id="github-帳號"><a class="anchor" href="#github-帳號">#</a> GitHub 帳號</h1>
<p>執行環境會把 docker image 從 GitHub registry 抓下來執行,所以在 script 最上面把 GitHub 權限設定為變數,之後執行讀取變數即可。密碼為 PAT(personal access token),建立方法請參考 <a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token">建立 PAT</a>。</p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token assign-left variable">GITHUB_ACCOUNT</span><span class="token operator">=</span><span class="token operator">&lt;</span>github帳號<span class="token operator">></span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token assign-left variable">GITHUB_PAT</span><span class="token operator">=</span><span class="token operator">&lt;</span>github PAT<span class="token operator">></span></pre></td></tr></table></figure><h1 id="設定時區"><a class="anchor" href="#設定時區">#</a> 設定時區</h1>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre>timedatectl set-timezone Asia/Taipei</pre></td></tr></table></figure><h1 id="作業系統更新"><a class="anchor" href="#作業系統更新">#</a> 作業系統更新</h1>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">apt</span> update <span class="token operator">&amp;&amp;</span> <span class="token function">apt</span> upgrade <span class="token parameter variable">-y</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token function">apt-get</span> clean <span class="token parameter variable">-y</span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token function">apt-get</span> autoremove <span class="token parameter variable">-y</span></pre></td></tr></table></figure><h1 id="啟用-google-bbr"><a class="anchor" href="#啟用-google-bbr">#</a> 啟用 Google BBR</h1>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre>modprobe tcp_bbr</pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token builtin class-name">echo</span> <span class="token string">"tcp_bbr"</span> <span class="token operator">>></span> /etc/modules-load.d/modules.conf</pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token builtin class-name">echo</span> <span class="token string">"net.core.default_qdisc=fq"</span> <span class="token operator">>></span> /etc/sysctl.conf</pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token builtin class-name">echo</span> <span class="token string">"net.ipv4.tcp_congestion_control=bbr"</span> <span class="token operator">>></span> /etc/sysctl.conf</pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token function">sysctl</span> <span class="token parameter variable">-p</span></pre></td></tr></table></figure><h1 id="install-ops-agent"><a class="anchor" href="#install-ops-agent">#</a> Install Ops Agent</h1>
<p>安裝 <a href="https://cloud.google.com/stackdriver/docs/solutions/agents/ops-agent">GCP agent</a>,如果不是使用 GCP 可以不用執行</p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">curl</span> <span class="token parameter variable">-sSO</span> https://dl.google.com/cloudagents/add-google-cloud-ops-agent-repo.sh</pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token function">bash</span> add-google-cloud-ops-agent-repo.sh --also-install</pre></td></tr></table></figure><h1 id="安裝-docker"><a class="anchor" href="#安裝-docker">#</a> 安裝 Docker</h1>
<p>所有專案都以 container 形式使用 docker compose 運行。安裝 docker 沒毛病。</p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">apt-get</span> update</pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token function">apt-get</span> <span class="token function">install</span> ca-certificates <span class="token function">curl</span> gnupg lsb-release <span class="token parameter variable">-y</span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token function">mkdir</span> <span class="token parameter variable">-p</span> /etc/apt/keyrings</pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token function">curl</span> <span class="token parameter variable">-fsSL</span> https://download.docker.com/linux/ubuntu/gpg <span class="token operator">|</span> <span class="token function">sudo</span> gpg <span class="token parameter variable">--dearmor</span> <span class="token parameter variable">-o</span> /etc/apt/keyrings/docker.gpg</pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token builtin class-name">echo</span> <span class="token punctuation">\</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token string">"deb [arch=<span class="token variable"><span class="token variable">$(</span>dpkg --print-architecture<span class="token variable">)</span></span> signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \</pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token variable"><span class="token variable">$(</span>lsb_release <span class="token parameter variable">-cs</span><span class="token variable">)</span></span> stable"</span> <span class="token operator">|</span> <span class="token function">sudo</span> <span class="token function">tee</span> /etc/apt/sources.list.d/docker.list <span class="token operator">></span> /dev/null</pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token function">apt-get</span> update</pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token function">apt-get</span> <span class="token function">install</span> docker-ce docker-ce-cli containerd.io docker-compose-plugin <span class="token parameter variable">-y</span> <span class="token parameter variable">-q</span></pre></td></tr></table></figure><h1 id="安裝-portainer-with-docker-swarm"><a class="anchor" href="#安裝-portainer-with-docker-swarm">#</a> 安裝 Portainer with Docker Swarm</h1>
<p>使用 portainer 管理 container,portainer 很棒,是 web 界面。加上 docker swarm 是為了讓程式上傳後可以通知 server 去 pull 新的 image 自動佈署。 <code>一言不合就 CI/CD</code></p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">docker</span> volume create portainer_data</pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token function">docker</span> run <span class="token parameter variable">-d</span> <span class="token parameter variable">-p</span> <span class="token number">8000</span>:8000 <span class="token parameter variable">-p</span> <span class="token number">9443</span>:9443 <span class="token parameter variable">-p</span> <span class="token number">9000</span>:9000 <span class="token parameter variable">--name</span> portainer <span class="token parameter variable">--restart</span><span class="token operator">=</span>always <span class="token parameter variable">-v</span> /var/run/docker.sock:/var/run/docker.sock <span class="token parameter variable">-v</span> portainer_data:/data portainer/portainer-ce:latest</pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token function">docker</span> swarm init</pre></td></tr></table></figure><h1 id="建立-crond-docker-prune"><a class="anchor" href="#建立-crond-docker-prune">#</a> 建立 crond docker-prune</h1>
<p>每天自動清理 docker 垃圾,每次更新產生沒用的 image、cointainer 太多會造成主機容量不足掛掉。<br />
<s>不然每次掛掉老闆都罵我,我也不知道為什麼有人一天要 commit 600 次</s></p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">cat</span> <span class="token operator">>></span> /etc/cron.daily/docker-prune <span class="token operator">&lt;&lt;</span> <span class="token string">EOL</pre></td></tr><tr><td data-num="2"></td><td><pre>#!/bin/bash</pre></td></tr><tr><td data-num="3"></td><td><pre>docker system prune -af</pre></td></tr><tr><td data-num="4"></td><td><pre>EOL</span></pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token function">chmod</span> ugo+x /etc/cron.daily/docker-prune</pre></td></tr></table></figure><h1 id="建立-linux-帳號"><a class="anchor" href="#建立-linux-帳號">#</a> 建立 Linux 帳號</h1>
<p>使用最上面設定的變數建立帳號,讓其他維護的同學登入。</p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">useradd</span> <span class="token parameter variable">-c</span> <span class="token string">"update user"</span> <span class="token parameter variable">-s</span> /bin/bash <span class="token parameter variable">-G</span> <span class="token function">sudo</span> <span class="token parameter variable">-m</span> <span class="token variable">$ACCOUNT</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token builtin class-name">echo</span> <span class="token string">"<span class="token variable">$ACCOUNT</span>:<span class="token variable">$PASSWORD</span>"</span> <span class="token operator">|</span> chpasswd</pre></td></tr></table></figure><h1 id="登入-docker-registry"><a class="anchor" href="#登入-docker-registry">#</a> 登入 Docker registry</h1>
<p>登入 GitHub registry 之後 docker pull 就不用輸入密碼,讚!</p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token builtin class-name">echo</span> <span class="token variable">$GITHUB_PAT</span> <span class="token operator">|</span> <span class="token function">docker</span> login ghcr.io <span class="token parameter variable">--username</span> <span class="token variable">$GITHUB_ACCOUNT</span> --password-stdin</pre></td></tr></table></figure><h1 id="完整-shell-script"><a class="anchor" href="#完整-shell-script">#</a> 完整 shell script</h1>
<ul>
<li><a href="https://gist.github.com/8loser/f54b673b93a2df296887c2bd6edf96e8">https://gist.github.com/8loser/f54b673b93a2df296887c2bd6edf96e8</a></li>
</ul>
</content>
<category term="Linux" scheme="https://8loser.github.io/tags/Linux/" />
<category term="Shell script" scheme="https://8loser.github.io/tags/Shell-script/" />
<category term="GCP" scheme="https://8loser.github.io/tags/GCP/" />
<updated>2023-01-04T07:32:51.000Z</updated>
</entry>
<entry>
<id>https://8loser.github.io/2022/10/21/nginx-websocket/</id>
<title>Nginx websocket 無法連接</title>
<link rel="alternate" href="https://8loser.github.io/2022/10/21/nginx-websocket/"/>
<content type="html"><h1 id="環境"><a class="anchor" href="#環境">#</a> 環境</h1>
<p>在 docker compose 中,使用 nginx 導向 websocket 到 container 內</p>
<h1 id="錯誤訊息"><a class="anchor" href="#錯誤訊息">#</a> 錯誤訊息</h1>
<p>websocket 連接不上,查看 request headers 顯示 <code>Provisional headers are shown</code></p>
<p><img loading="lazy" data-src="provisional_headers_are_shown.png" alt="provisional headers are shown" /></p>
<h1 id="solution"><a class="anchor" href="#solution">#</a> Solution</h1>
<p>搜尋解決方法是在 nginx.conf 內加上</p>
<figure class="highlight editorconfig"><figcaption data-lang="editorconfig"></figcaption><table><tr><td data-num="1"></td><td><pre>proxy_set_header Upgrade $http_upgrade<span class="token comment">;</span></pre></td></tr><tr><td data-num="2"></td><td><pre>proxy_set_header Connection "upgrade"<span class="token comment">;</span></pre></td></tr></table></figure><h2 id="範例"><a class="anchor" href="#範例">#</a> 範例</h2>
<figure class="highlight editorconfig"><figcaption data-lang="editorconfig"><span>範例</span></figcaption><table><tr><td data-num="1"></td><td><pre>location /backend/ &#123;</pre></td></tr><tr><td data-num="2"></td><td><pre> proxy_pass http://backend/<span class="token comment">;</span></pre></td></tr><tr><td data-num="3"></td><td><pre> proxy_set_header Host $host<span class="token comment">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre> proxy_set_header X-Real-IP $remote_addr<span class="token comment">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre> proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for<span class="token comment">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre> proxy_set_header X-Custom-Referrer smc_identity_layer<span class="token comment">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token comment"># websocket 要加下面兩個</span></pre></td></tr><tr class="marked"><td data-num="8"></td><td><pre> proxy_set_header Upgrade $http_upgrade<span class="token comment">;</span></pre></td></tr><tr class="marked"><td data-num="9"></td><td><pre> proxy_set_header Connection "upgrade"<span class="token comment">;</span></pre></td></tr><tr><td data-num="10"></td><td><pre>&#125;</pre></td></tr></table></figure><h1 id="驗證"><a class="anchor" href="#驗證">#</a> 驗證</h1>
<p>比較有修正前跟修正後,後端實際收到的 request header</p>
<h2 id="修正前-request-headers"><a class="anchor" href="#修正前-request-headers">#</a> 修正前 request headers</h2>
<figure class="highlight js"><figcaption data-lang="JavaScript"><span>修正前</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">Headers</span><span class="token punctuation">(</span><span class="token punctuation">&#123;</span><span class="token string-property property">'host'</span><span class="token operator">:</span> <span class="token string">'localhost'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token string-property property">'x-real-ip'</span><span class="token operator">:</span> <span class="token string">'192.168.224.1'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token string-property property">'x-forwarded-for'</span><span class="token operator">:</span> <span class="token string">'192.168.224.1'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token string-property property">'x-custom-referrer'</span><span class="token operator">:</span> <span class="token string">'smc_identity_layer'</span><span class="token punctuation">,</span></pre></td></tr><tr class="marked"><td data-num="5"></td><td><pre> <span class="token string-property property">'connection'</span><span class="token operator">:</span> <span class="token string">'close'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token string-property property">'pragma'</span><span class="token operator">:</span> <span class="token string">'no-cache'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token string-property property">'cache-control'</span><span class="token operator">:</span> <span class="token string">'no-cache'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token string-property property">'user-agent'</span><span class="token operator">:</span> <span class="token string">'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token string-property property">'origin'</span><span class="token operator">:</span> <span class="token string">'chrome-extension://cbcbkhdmedgianpaifchdaddpnmgnknn'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token string-property property">'sec-websocket-version'</span><span class="token operator">:</span> <span class="token string">'13'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token string-property property">'accept-encoding'</span><span class="token operator">:</span> <span class="token string">'gzip, deflate, br'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token string-property property">'accept-language'</span><span class="token operator">:</span> <span class="token string">'zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token string-property property">'sec-websocket-key'</span><span class="token operator">:</span> <span class="token string">'iBVj1v1X8xkD324lsXZSUA=='</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token string-property property">'sec-websocket-extensions'</span><span class="token operator">:</span> <span class="token string">'permessage-deflate; client_max_window_bits'</span><span class="token punctuation">&#125;</span><span class="token punctuation">)</span></pre></td></tr></table></figure><h2 id="修正後-request-headers"><a class="anchor" href="#修正後-request-headers">#</a> 修正後 request headers</h2>
<figure class="highlight js"><figcaption data-lang="JavaScript"><span>修正後</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">Headers</span><span class="token punctuation">(</span><span class="token punctuation">&#123;</span><span class="token string-property property">'host'</span><span class="token operator">:</span> <span class="token string">'localhost'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token string-property property">'x-real-ip'</span><span class="token operator">:</span> <span class="token string">'192.168.208.1'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token string-property property">'x-forwarded-for'</span><span class="token operator">:</span> <span class="token string">'192.168.208.1'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token string-property property">'x-custom-referrer'</span><span class="token operator">:</span> <span class="token string">'smc_identity_layer'</span><span class="token punctuation">,</span></pre></td></tr><tr class="marked"><td data-num="5"></td><td><pre><span class="token string-property property">'upgrade'</span><span class="token operator">:</span> <span class="token string">'websocket'</span><span class="token punctuation">,</span></pre></td></tr><tr class="marked"><td data-num="6"></td><td><pre><span class="token string-property property">'connection'</span><span class="token operator">:</span> <span class="token string">'upgrade'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="7"></td><td><pre><span class="token string-property property">'pragma'</span><span class="token operator">:</span> <span class="token string">'no-cache'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token string-property property">'cache-control'</span><span class="token operator">:</span> <span class="token string">'no-cache'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token string-property property">'user-agent'</span><span class="token operator">:</span> <span class="token string">'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="10"></td><td><pre><span class="token string-property property">'origin'</span><span class="token operator">:</span> <span class="token string">'chrome-extension://cbcbkhdmedgianpaifchdaddpnmgnknn'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="11"></td><td><pre><span class="token string-property property">'sec-websocket-version'</span><span class="token operator">:</span> <span class="token string">'13'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token string-property property">'accept-encoding'</span><span class="token operator">:</span> <span class="token string">'gzip, deflate, br'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="13"></td><td><pre><span class="token string-property property">'accept-language'</span><span class="token operator">:</span> <span class="token string">'zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7'</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="14"></td><td><pre><span class="token string-property property">'sec-websocket-key'</span><span class="token operator">:</span> <span class="token string">'j2NwT86WmJt6rIyatTa5rw=='</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="15"></td><td><pre><span class="token string-property property">'sec-websocket-extensions'</span><span class="token operator">:</span> <span class="token string">'permessage-deflate; client_max_window_bits'</span><span class="token punctuation">&#125;</span><span class="token punctuation">)</span></pre></td></tr></table></figure></content>
<category term="Trouble" scheme="https://8loser.github.io/categories/Trouble/" />
<category term="Nginx" scheme="https://8loser.github.io/tags/Nginx/" />
<category term="WebSocket" scheme="https://8loser.github.io/tags/WebSocket/" />
<updated>2022-10-21T09:10:38.000Z</updated>
</entry>
<entry>
<id>https://8loser.github.io/2022/07/23/docker-access-host/</id>
<title>Docker Container 存取 host 服務</title>
<link rel="alternate" href="https://8loser.github.io/2022/07/23/docker-access-host/"/>
<content type="html"><h1 id="docker-container-存取-host-服務"><a class="anchor" href="#docker-container-存取-host-服務">#</a> Docker Container 存取 host 服務</h1>
<p>場景應用如 container 運行程式,host 安裝資料庫。container 內的程式需要存取安裝在 host 的資料庫。</p>
<p>只要在程式內呼叫資料庫的位址使用 <code>host.docker.internal</code> 即可,如在 host 安裝 PostgreSQL,程式內設定資料庫位置就是</p>
<blockquote>
<p><code>host.docker.internal:5432</code></p>
</blockquote>
<p>原本還有下面兩個,不過已經 deprecated 了。</p>
<blockquote>
<p><code>docker.for.mac.host.internal</code></p>
</blockquote>
<blockquote>
<p><code>docker.for.mac.localhost</code></p>
</blockquote>
<h1 id="參考資料"><a class="anchor" href="#參考資料">#</a> 參考資料</h1>
<p><div class="links"><div class="item" title="docker docs" style="--block-color:#9d5b8b;"><a href="https://docs.docker.com/desktop/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host" class="image" data-background-image="/assets/404.png"></a>
<div class="info">
<a href="https://docs.docker.com/desktop/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host" class="title">docker docs</a>
<p class="desc">I want to connect from a container to a service on the host</p>
</div></div></div></p>
</content>
<category term="Need to Know" scheme="https://8loser.github.io/categories/Need-to-Know/" />
<category term="Docker" scheme="https://8loser.github.io/tags/Docker/" />
<updated>2022-07-23T07:47:36.000Z</updated>
</entry>
<entry>
<id>https://8loser.github.io/2022/06/26/git_of_devcontainer/</id>
<title>VSCode devcontainer 使用 git</title>
<link rel="alternate" href="https://8loser.github.io/2022/06/26/git_of_devcontainer/"/>
<content type="html"><h1 id="remote-container-使用-git"><a class="anchor" href="#remote-container-使用-git">#</a> Remote container 使用 git</h1>
<p>在 Visual Studio Code (下面使用 VSCode 稱呼) 內使用 devcontainer 開發時,怎麼使用 git?</p>
<p>我的開發方式都是從 git hub 上 clone 程式後建立 devcontainer 環境進行開發</p>
<p>當建立完 devcontainer 環境進入 container 後,點選 VSCode 左邊的 Source Control 項目時,會出現</p>
<p><img loading="lazy" data-src="source_control_no_git_repo.png" alt="The folder currently open doesn't have a git repository" /></p>
<p>且右下角出現提示</p>
<p><img loading="lazy" data-src="git_not_found.png" alt="Git not found. Install it or configure it using the 'git.path' setting" /></p>
<p>出現這種情況表示 container 內沒有安裝 git</p>
<h1 id="安裝-git"><a class="anchor" href="#安裝-git">#</a> 安裝 git</h1>
<p>在 container 內安裝 git 的方法,可以在 Dockerfile 內加上</p>
<figure class="highlight dockerfile"><figcaption data-lang="Docker"><span>Dockerfile</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token instruction"><span class="token keyword">RUN</span> apk update &amp;&amp; apk upgrade &amp;&amp; apk add --no-cache <span class="token operator">\</span></pre></td></tr><tr><td data-num="2"></td><td><pre> git</span></pre></td></tr></table></figure><p>如果是使用 <code>apt-get</code> (不過我沒有用 apt-get 測試過)</p>
<figure class="highlight dockerfile"><figcaption data-lang="Docker"><span>Dockerfile</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token instruction"><span class="token keyword">RUN</span> apt-get update &amp;&amp; apt-get install -y --no-install-recommends <span class="token operator">\</span></pre></td></tr><tr><td data-num="2"></td><td><pre> git <span class="token operator">\</span></pre></td></tr><tr><td data-num="3"></td><td><pre> &amp;&amp; rm -rf /var/lib/apt/lists/*</span></pre></td></tr></table></figure><h1 id="cafile-none"><a class="anchor" href="#cafile-none">#</a> CAfile: none</h1>
<p>如果在 container 內 git pull 時出現 <code>CAfile: none</code> 的訊息</p>
<p><img loading="lazy" data-src="CAfileNone.png" alt="Git: fatal: server certificate verification failed. CAfile: none CRLfile: none" /></p>
<p>修改 Dockerfile,加上 ca-certificates 變成</p>
<figure class="highlight dockerfile"><figcaption data-lang="Docker"><span>Dockerfile</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token instruction"><span class="token keyword">RUN</span> apt-get update &amp;&amp; apt-get install -y --no-install-recommends <span class="token operator">\</span></pre></td></tr><tr><td data-num="2"></td><td><pre> git <span class="token operator">\</span></pre></td></tr><tr class="marked"><td data-num="3"></td><td><pre> ca-certificates <span class="token operator">\</span></pre></td></tr><tr class="marked"><td data-num="4"></td><td><pre> &amp;&amp; update-ca-certificates <span class="token operator">\</span></pre></td></tr><tr><td data-num="5"></td><td><pre> &amp;&amp; rm -rf /var/lib/apt/lists/*</span></pre></td></tr></table></figure><h1 id="so-many-pending-changes"><a class="anchor" href="#so-many-pending-changes">#</a> So many pending changes</h1>
<p>改完 Dockerfile 後執行 Rebuild container 再次進入 container 查看 Source Control</p>
<p>可能會出現很多 change 的檔案</p>
<p><img loading="lazy" data-src="source_control_pending_changes.png" alt="So Many Pending Changes" /></p>
<p>但實際上你並沒有修改這些檔案,查看 diff 也看沒看到有變更的地方</p>
<h1 id="git-autocrlf"><a class="anchor" href="#git-autocrlf">#</a> Git AutoCrLf</h1>
<p>如果你跟我一樣是使用 Windows 安裝 docker 的話,很有可能會遇到這個狀況</p>
<p>這是因為 Windows 跟 Linux 的跳行符號不一樣的關係</p>
<div class="note info">
<p>DOS/Windows 跳行使用 CR/LF (\r\n)<br />
UNIX/Linux 跳行使用 LF (\n)</p>
</div>
<p>可以執行</p>
<figure class="highlight bash"><figcaption data-lang="bash"><span>git config</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">git</span> config <span class="token parameter variable">--global</span> core.autocrlf <span class="token boolean">true</span></pre></td></tr></table></figure><p>然後在 Source Control refresh 就可以看到 change 的檔案變少了</p>
<p>如果不想每次建立 devcontainer 環境都要執行一次的話,可以修改 Windows 的 git config</p>
<p>使用 TortoiseGit 可以參考<br />
<a href="https://tortoisegit.org/docs/tortoisegit/tgit-dug-settings.html#tgit-dug-settings-config"> https://tortoisegit.org/docs/tortoisegit/tgit-dug-settings.html#tgit-dug-settings-config</a></p>
<p>不建議在 Dockerfile 內使用 RUN 或者在 devcontainer.json 內設定 autocrlf</p>
<p>因為原本 <code>user.name</code> , <code>user.email</code> ... 相關資訊會不見,導致無法執行 push/pull 等動作</p>
<p>如果要在 Dockerfile 內設定 autocrlf 可以用</p>
<figure class="highlight dockerfile"><figcaption data-lang="Docker"><span>Dockerfile</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token instruction"><span class="token keyword">RUN</span> git config --global core.autocrlf true</span></pre></td></tr></table></figure><p>可以自己測試看看加跟不加時,進入 container 後 config 的差異</p>
<figure class="highlight bash"><figcaption data-lang="bash"><span>list git config</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">git</span> config <span class="token parameter variable">--global</span> <span class="token parameter variable">-l</span></pre></td></tr></table></figure></content>
<category term="VSCode" scheme="https://8loser.github.io/tags/VSCode/" />
<category term="Remote Container" scheme="https://8loser.github.io/tags/Remote-Container/" />
<category term="Git" scheme="https://8loser.github.io/tags/Git/" />
<updated>2022-06-25T16:41:02.000Z</updated>
</entry>
<entry>
<id>https://8loser.github.io/2022/06/18/CodebaseShow/</id>
<title>專案建構</title>
<link rel="alternate" href="https://8loser.github.io/2022/06/18/CodebaseShow/"/>
<content type="html"><h1 id="專案建構"><a class="anchor" href="#專案建構">#</a> 專案建構</h1>
<p>以個人過往經歷,在專案開始寫程式前,會先進行技術選型,如要用什麼程式語言、要用什麼框架、部屬到哪裡等等,開發過程中可能還會需要決定要用什麼套件,不過在這邊沒有要介紹技術選型該怎麼決策,如果對技術選型有興趣的可以點 <a href="https://googlethatforyou.com?q=%E6%8A%80%E8%A1%93%E9%81%B8%E5%9E%8B">小幫手</a>。</p>
<h1 id="scaffolding"><a class="anchor" href="#scaffolding">#</a> Scaffolding</h1>
<p>在選型完之後,老大會建構出基礎框架,其他工程師在照個框架開始著手接收需求進行開發。</p>
<p>以前的作法都會把熟悉的架構整理成一個簡單的版本,複製過來改一下設定檔就可以開始開發。</p>
<p>也有些框架會提供腳手架的功能 (scaffolding) 的功能,選取一些需要的功能之後程式就會把專案的資料夾結構、設定建立出來。</p>
<p>如果上述方式都沒有的話,就蠻可憐的,要看著搭配的官方說明手動刻出來,弄了很久老闆可能還會問你怎麼還沒開始做功能。</p>
<h1 id="codebaseshow"><a class="anchor" href="#codebaseshow">#</a> CodebaseShow</h1>
<p>這邊要跟大家說有 <a href="https://codebase.show/projects/realworld">CodebaseShow</a> 這個網站,收集了前端、後端還有全端專案等不同程式語言的架構。</p>
<p>這個網站特別之處在於收集了不同框架與套件的結合,而且是基於實際專案開發使用的架構。</p>
<p><img loading="lazy" data-src="CodebaseShow.jpg" alt="CodebaseShow" /></p>
</content>
<category term="scaffolding" scheme="https://8loser.github.io/tags/scaffolding/" />
<updated>2022-06-18T02:30:00.000Z</updated>
</entry>
<entry>
<id>https://8loser.github.io/2022/05/27/Multiple-app-config/</id>
<title>Visual Studio C# 使用多個 App.config</title>
<link rel="alternate" href="https://8loser.github.io/2022/05/27/Multiple-app-config/"/>
<content type="html"><p>介紹如何在 Visual Studio 主控台應用程式專案中,設定多個應用程式組態檔 (App.config)。在 Debug/Release 不同組態間載入不同的變數資料。</p>
<p>分別介紹 <code>appSettings</code> 、 <code>applicationSettings</code> 兩種方式,這兩種方式可以共存,要注意在程式中讀取方式不同,範例中主要 <code>key</code> 都名稱設為 <code>keyName</code> , <code>value</code> 依不同組態設定:</p>
<ul>
<li>App.config 設定為 <code>default</code></li>
<li>App.Debug.config 設定為 <code>debug</code></li>
<li>App.Release.config 設定為 <code>release</code></li>
</ul>
<p><code>appSettings</code> 取值方式<br />
<code>string value = ConfigurationManager.AppSettings[&quot;keyName&quot;];</code></p>
<p><code>applicationSettings</code> 取值方式<br />
<code>string value = Properties.Settings.Default.keyName;</code></p>
<h1 id="新增應用程式組態檔-appconfig"><a class="anchor" href="#新增應用程式組態檔-appconfig">#</a> 新增應用程式組態檔 App.config</h1>
<div class="note warning">
<p>如果專案已經有 App.config 的可忽略該步驟</p>
</div>
<ol>
<li>方案總管</li>
<li>在專案上按右鍵,選取 <code>加入</code> / <code>新增項目</code><div class="note warning">
<p>是 <code>專案</code> 不是 <code>解決方案</code></p>
</div>
</li>
<li>選取一般 / 應用程式組態檔</li>
<li>檔名使用 App.config<br />
<img loading="lazy" data-src="add-app.config.png" alt="新增程式組態檔" /></li>
</ol>
<h1 id="編輯專案檔-csproj"><a class="anchor" href="#編輯專案檔-csproj">#</a> 編輯專案檔 .csproj</h1>
<ol>
<li>方案總管</li>
<li>在專案上按右鍵,選取 <code>卸載專案</code></li>
<li>在專案上按右鍵,選取 <code>編輯專案檔</code><div class="note info">
<p>就是編輯 <code>&lt;專案名稱&gt;.csproj</code> 這個檔案</p>
</div>
</li>
</ol>
<h2 id="新增-propertygroup"><a class="anchor" href="#新增-propertygroup">#</a> 新增 PropertyGroup</h2>
<p>專案檔內應該會有其他 <code>PropertyGroup</code> 區塊,可加在其他 <code>PropertyGroup</code> 下面</p>
<figure class="highlight xml"><figcaption data-lang="XML"><span><專案名稱>.csproj</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>PropertyGroup</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ProjectConfigFileName</span><span class="token punctuation">></span></span>App.config<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ProjectConfigFileName</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>PropertyGroup</span><span class="token punctuation">></span></span></pre></td></tr></table></figure><p><img loading="lazy" data-src="add-PropertyGroup.png" alt="新增 PropertyGroup" /></p>
<h2 id="修改-itemgroup"><a class="anchor" href="#修改-itemgroup">#</a> 修改 ItemGroup</h2>
<p>原先的專案檔應該有</p>
<figure class="highlight xml"><figcaption data-lang="XML"><span><專案名稱>.csproj</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ItemGroup</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>None</span> <span class="token attr-name">Include</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>App.config<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ItemGroup</span><span class="token punctuation">></span></span></pre></td></tr></table></figure><p>將他改為</p>
<figure class="highlight xml"><figcaption data-lang="XML"><span><專案名稱>.csproj</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ItemGroup</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>None</span> <span class="token attr-name">Include</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>App.config<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>None</span> <span class="token attr-name">Include</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>App.Debug.config<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>DependentUpon</span><span class="token punctuation">></span></span>App.config<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>DependentUpon</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>None</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>None</span> <span class="token attr-name">Include</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>App.Release.config<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>DependentUpon</span><span class="token punctuation">></span></span>App.config<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>DependentUpon</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>None</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ItemGroup</span><span class="token punctuation">></span></span></pre></td></tr></table></figure><h2 id="新增-import"><a class="anchor" href="#新增-import">#</a> 新增 Import</h2>
<p>專案檔下面會有一行<br />
<code>&lt;Import Project=&quot;$(MSBuildToolsPath)\Microsoft.CSharp.targets&quot; /&gt;</code> <br />
在他下面增加</p>
<figure class="highlight xml"><figcaption data-lang="XML"><span><專案名稱>.csproj</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Import</span> <span class="token attr-name">Project</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.targets<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>Target</span> <span class="token attr-name">Name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>AfterBuild<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>TransformXml</span> <span class="token attr-name">Source</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>@(AppConfigWithTargetPath)<span class="token punctuation">"</span></span> <span class="token attr-name">Transform</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>$(ProjectConfigTransformFileName)<span class="token punctuation">"</span></span> <span class="token attr-name">Destination</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>@(AppConfigWithTargetPath->'$(OutDir)%(TargetPath)')<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>Target</span><span class="token punctuation">></span></span></pre></td></tr></table></figure><h2 id="重新載入專案"><a class="anchor" href="#重新載入專案">#</a> 重新載入專案</h2>
<ol>
<li>方案總管</li>
<li>在專案上按右鍵,選取 <code>重新載入專案</code><div class="note info">
<p>如果載入成功表示上面的修改格式都正確</p>
</div>
</li>
</ol>
<h1 id="新增-debugrelease-組態設定檔"><a class="anchor" href="#新增-debugrelease-組態設定檔">#</a> 新增 Debug/Release 組態設定檔</h1>
<p>專案載入成功後在方案總管內應該會看到 <code>App.Debug.config</code> 與 <code>App.Release.config</code> 前面有紅色 x 的畫面,表示專案有設置但是檔案不存在。</p>
<p><img loading="lazy" data-src="config-missing.png" alt="沒有組態檔" /></p>
<p>要手動新增組態設定檔,參考 <a href="#%E6%96%B0%E5%A2%9E%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F%E7%B5%84%E6%85%8B%E6%AA%94-appconfig">新增應用程式組態檔 App.config</a> 分別新增兩個檔名為 <code>App.Debug.config</code> 與 <code>App.Release.config</code> 的組態設定檔 (注意大小寫)。</p>
<h1 id="新增-appsettings"><a class="anchor" href="#新增-appsettings">#</a> 新增 appSettings</h1>
<div class="note info">
<p>可在 <code>appSettings</code> 內設定多個 <code>key</code></p>
</div>
<div class="note info">
<p>如果 <code>App.Debug.config</code> 、 <code>App.Release.config</code> 內沒有設置的 <code>key</code> 預設會抓取 <code>App.config</code> 內的值</p>
</div>
<div class="note info">
<p>如果 <code>App.Debug.config</code> 、 <code>App.Release.config</code> 內有設置,但 <code>App.config</code> 內沒設置的 <code>key</code> 則會是空值,不會套用 Debug/Release 的設定</p>
</div>
<h2 id="appconfig"><a class="anchor" href="#appconfig">#</a> App.config</h2>
<p>設置的 <code>value</code> 為 default</p>
<figure class="highlight xml"><figcaption data-lang="XML"><span>App.config</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token prolog">&lt;?xml version="1.0" encoding="utf-8" ?></span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>configuration</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="3"></td><td><pre> ...</pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>appSettings</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>add</span> <span class="token attr-name">key</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>keyName<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>default<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>appSettings</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="7"></td><td><pre> ...</pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>configuration</span><span class="token punctuation">></span></span></pre></td></tr></table></figure><h2 id="appdebugconfig"><a class="anchor" href="#appdebugconfig">#</a> App.Debug.config</h2>
<div class="note warning">
<p>configuration 後要有 <code>xmlns:xdt</code> 屬性</p>
</div>
<div class="note warning">
<p>key 要有 <code>xdt:Transform</code> 、 <code>xdt:Locator</code> 屬性</p>
</div>
<figure class="highlight xml"><figcaption data-lang="XML"><span>App.Debug.config</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token prolog">&lt;?xml version="1.0" encoding="utf-8" ?></span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>configuration</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>xdt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://schemas.microsoft.com/XML-Document-Transform<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="3"></td><td><pre> ...</pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>appSettings</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token comment">&lt;!-- 設置的 `value` 為 debug --></span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>add</span> <span class="token attr-name">key</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>keyName<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>debug<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xdt:</span>Transform</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>SetAttributes<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xdt:</span>Locator</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Match(key)<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>appSettings</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="8"></td><td><pre> ...</pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>configuration</span><span class="token punctuation">></span></span></pre></td></tr></table></figure><h2 id="appreleaseconfig"><a class="anchor" href="#appreleaseconfig">#</a> App.Release.config</h2>
<div class="note warning">
<p>configuration 後要有 <code>xmlns:xdt</code> 屬性</p>
</div>
<div class="note warning">
<p>key 要有 <code>xdt:Transform</code> 、 <code>xdt:Locator</code> 屬性</p>
</div>
<figure class="highlight xml"><figcaption data-lang="XML"><span>App.Release.config</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token prolog">&lt;?xml version="1.0" encoding="utf-8" ?></span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>configuration</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>xdt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://schemas.microsoft.com/XML-Document-Transform<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="3"></td><td><pre> ...</pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>appSettings</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token comment">&lt;!-- 設置的 `value` 為 release --></span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>add</span> <span class="token attr-name">key</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>keyName<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>release<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xdt:</span>Transform</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>SetAttributes<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xdt:</span>Locator</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Match(key)<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>appSettings</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="8"></td><td><pre> ...</pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>configuration</span><span class="token punctuation">></span></span></pre></td></tr></table></figure><h1 id="取得-appsettings-值"><a class="anchor" href="#取得-appsettings-值">#</a> 取得 appSettings 值</h1>
<p>使用下面程式取抓取組態設定檔內設定的值,根據執行 Debug、Release 組態不同會顯示不同的值 (取決於設定檔 <code>value</code> )</p>
<figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token class-name"><span class="token keyword">string</span></span> <span class="token keyword">value</span> <span class="token operator">=</span> ConfigurationManager<span class="token punctuation">.</span>AppSettings<span class="token punctuation">[</span><span class="token string">"keyName"</span><span class="token punctuation">]</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="2"></td><td><pre>Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token keyword">value</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="3"></td><td><pre>Console<span class="token punctuation">.</span><span class="token function">ReadKey</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr></table></figure><p>編譯完成後,在 ./bin/Debug、./bin/Release 內都會有一個 <code>.config</code> 檔,分別就是 <code>App.Debug.config</code> 、 <code>App.Release.config</code> 的內容。</p>
<h1 id="使用-applicationsettings-方法"><a class="anchor" href="#使用-applicationsettings-方法">#</a> 使用 applicationSettings 方法</h1>
<p>這邊介紹使用 <code>applicationSettings</code> 的方法,該方法的優點就是在程式中會自動列出可使用的 <code>key</code> ,缺點就是比較繁瑣,需要修改 <code>Settings.Designer.cs</code></p>
<div class="note info">
<p><code>applicationSettings</code> 跟 <code>appSettings</code> 可同時存在</p>
</div>
<h2 id="專案屬性設定"><a class="anchor" href="#專案屬性設定">#</a> 專案屬性設定</h2>
<ol>
<li>方案總管</li>
<li>在專案上按右鍵,選取 <code>屬性</code></li>
<li>點選 <code>設定</code> , <code>名稱</code> 設定 <code>keyname</code> , <code>值</code> 設定 <code>default</code> , <code>範圍</code> 選取 <code>應用程式</code></li>
</ol>
<p>儲存後 <code>App.config</code> 會增加 <code>&lt;applicationSettings&gt;</code> , <code>Properties/Settings.Designer.cs</code> 也會變更</p>
<div class="note warning">
<p><code>Console.App</code> 會根據專案名稱不同</p>
</div>
<figure class="highlight xml"><figcaption data-lang="XML"><span>App.config</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token prolog">&lt;?xml version="1.0" encoding="utf-8" ?></span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>configuration</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="3"></td><td><pre> ...</pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>applicationSettings</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ConsoleApp.Properties.Settings</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>setting</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>keyName<span class="token punctuation">"</span></span> <span class="token attr-name">serializeAs</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>String<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>value</span><span class="token punctuation">></span></span>default<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>value</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>setting</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ConsoleApp.Properties.Settings</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>applicationSettings</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="11"></td><td><pre> ...</pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>configuration</span><span class="token punctuation">></span></span></pre></td></tr></table></figure><h2 id="修改-appdebugconfig"><a class="anchor" href="#修改-appdebugconfig">#</a> 修改 App.Debug.config</h2>
<div class="note warning">
<p><code>Console.App</code> 會根據專案名稱不同</p>
</div>
<div class="note warning">
<p><code>configuration</code> 要有 <code>xmlns:xdt</code> 屬性</p>
</div>
<div class="note warning">
<p><code>setting</code> 要有 <code>serializeAs</code> 、 <code>xdt:Transform</code> 屬性</p>
</div>
<figure class="highlight xml"><figcaption data-lang="XML"><span>App.Debug.config</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token prolog">&lt;?xml version="1.0" encoding="utf-8" ?></span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>configuration</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>xdt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://schemas.microsoft.com/XML-Document-Transform<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="3"></td><td><pre> ...</pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>applicationSettings</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ConsoleApp.Properties.Settings</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>setting</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>keyName<span class="token punctuation">"</span></span> <span class="token attr-name">serializeAs</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>String<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xdt:</span>Transform</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Replace<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token comment">&lt;!-- 將 value 內容設定為 debug --></span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>value</span><span class="token punctuation">></span></span>debug<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>value</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>setting</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ConsoleApp.Properties.Settings</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>applicationSettings</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="12"></td><td><pre> ...</pre></td></tr><tr><td data-num="13"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>configuration</span><span class="token punctuation">></span></span></pre></td></tr></table></figure><h2 id="修改-appreleaseconfig"><a class="anchor" href="#修改-appreleaseconfig">#</a> 修改 App.Release.config</h2>
<div class="note warning">
<p><code>Console.App</code> 會根據專案名稱不同</p>
</div>
<div class="note warning">
<p><code>configuration</code> 要有 <code>xmlns:xdt</code> 屬性</p>
</div>
<div class="note warning">
<p><code>setting</code> 要有 <code>serializeAs</code> 、 <code>xdt:Transform</code> 屬性</p>
</div>
<figure class="highlight xml"><figcaption data-lang="XML"><span>App.Release.config</span></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token prolog">&lt;?xml version="1.0" encoding="utf-8" ?></span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>configuration</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>xdt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://schemas.microsoft.com/XML-Document-Transform<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="3"></td><td><pre> ...</pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>applicationSettings</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ConsoleApp.Properties.Settings</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>setting</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>keyName<span class="token punctuation">"</span></span> <span class="token attr-name">serializeAs</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>String<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xdt:</span>Transform</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Replace<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token comment">&lt;!-- 將 value 內容設定為 release --></span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>value</span><span class="token punctuation">></span></span>release<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>value</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>setting</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ConsoleApp.Properties.Settings</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>applicationSettings</span><span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>configuration</span><span class="token punctuation">></span></span></pre></td></tr></table></figure><h2 id="取得-applicationsettings-properties"><a class="anchor" href="#取得-applicationsettings-properties">#</a> 取得 applicationSettings properties</h2>
<p>使用下面程式取抓取組態設定檔內設定的值,根據執行 Debug、Release 組態不同會顯示不同的值。</p>
<figure class="highlight csharp"><figcaption data-lang="C#"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token class-name"><span class="token keyword">string</span></span> <span class="token keyword">value</span> <span class="token operator">=</span> Properties<span class="token punctuation">.</span>Settings<span class="token punctuation">.</span>Default<span class="token punctuation">.</span>keyName<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="2"></td><td><pre>Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token keyword">value</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="3"></td><td><pre>Console<span class="token punctuation">.</span><span class="token function">ReadKey</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr></table></figure><p>Default 能不能帶出 keyName 要看 <code>Properties/Settings.Designer.cs</code> 有沒有修改,可以參考 <a href="#%E5%B0%88%E6%A1%88%E5%B1%AC%E6%80%A7%E8%A8%AD%E5%AE%9A">專案屬性設定</a> 新增 key。</p>
<h1 id="完整程式碼"><a class="anchor" href="#完整程式碼">#</a> 完整程式碼</h1>
<p><a href="https://github.com/8loser/Multiple-App.config">https://github.com/8loser/Multiple-App.config</a></p>
<h1 id="參考資料"><a class="anchor" href="#參考資料">#</a> 參考資料</h1>
<p><a href="https://iamsbc.blogspot.com/2019/09/visual-studio-consoleappreleaseconfigap.html">https://iamsbc.blogspot.com/2019/09/visual-studio-consoleappreleaseconfigap.html</a><br />
<a href="https://demo.tc/post/775">https://demo.tc/post/775</a><br />
<a href="https://amolpandey.com/2021/01/05/multiple-app-config-in-c-solution-based-on-build-selection/">https://amolpandey.com/2021/01/05/multiple-app-config-in-c-solution-based-on-build-selection/</a></p>
</content>
<category term="C#" scheme="https://8loser.github.io/tags/C/" />
<category term="App.config" scheme="https://8loser.github.io/tags/App-config/" />
<category term="Visual Studio" scheme="https://8loser.github.io/tags/Visual-Studio/" />
<updated>2022-05-27T08:46:50.000Z</updated>
</entry>
<entry>
<id>https://8loser.github.io/2022/05/14/init/</id>
<title>init</title>
<link rel="alternate" href="https://8loser.github.io/2022/05/14/init/"/>
<content type="html"><h2 id="起因"><a class="anchor" href="#起因">#</a> 起因</h2>
<p>偶然看到 <a href="https://zrn-code.github.io/">Zrn</a> 的網站,覺得好酷炫,我也想要一個,然後我就開始爬他的網站,找到這篇 <a href="https://zrn-code.github.io/2020/11/22/hexo/">Hexo + Github Pages 打造專屬於你的網站</a>,猜測網站是用 Hexo 框架作的。</p>
<h2 id="hexo"><a class="anchor" href="#hexo">#</a> Hexo</h2>
<p>於是我就自己用了一個</p>
<p><img loading="lazy" data-src="init_001.png" alt="init" /></p>
<p>看起來完全不像呢...</p>
<h3 id="hexo-特點"><a class="anchor" href="#hexo-特點">#</a> Hexo 特點</h3>
<ul>
<li>Node.js</li>
<li>文章可以用 Markdown 格式撰寫</li>
<li>快速佈署到 GitHub Page、Heroku</li>
</ul>
<h3 id="趕緊為此而來"><a class="anchor" href="#趕緊為此而來">#</a> 趕緊為此而來</h3>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">npm</span> <span class="token function">install</span> hexo-cli <span class="token parameter variable">-g</span></pre></td></tr><tr><td data-num="2"></td><td><pre>hexo init blog</pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token builtin class-name">cd</span> blog</pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token function">npm</span> <span class="token function">install</span></pre></td></tr><tr><td data-num="5"></td><td><pre>hexo server</pre></td></tr></table></figure><h2 id="shoka-theme"><a class="anchor" href="#shoka-theme">#</a> Shoka theme</h2>
<p>之後在 <a href="https://hexo.io/themes/">Hexo/themes</a> 上尋找喜歡的 theme,發現跟 <a href="https://zrn-code.github.io/">Zrn</a> 一樣風格的 theme 了。</p>
<p>這套 theme 叫 Shoka (書架)</p>
<p>作者網站 <a href="https://shoka.lostyu.me/">https://shoka.lostyu.me/</a></p>
<p>GitHub <a href="https://github.com/amehime/hexo-theme-shoka">https://github.com/amehime/hexo-theme-shoka</a></p>
<p>使用教學 <a href="https://shoka.lostyu.me/computer-science/note/theme-shoka-doc/">https://shoka.lostyu.me/computer-science/note/theme-shoka-doc/</a></p>
</content>
<category term="Need to Know" scheme="https://8loser.github.io/categories/Need-to-Know/" />
<category term="Hexo" scheme="https://8loser.github.io/tags/Hexo/" />
<updated>2022-05-14T09:49:48.000Z</updated>
</entry>
</feed>