-
Notifications
You must be signed in to change notification settings - Fork 0
/
searchIndex.json
1921 lines (1682 loc) · 593 KB
/
searchIndex.json
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
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
[
{
"title": "Steam deck安裝筆記",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/191. Steam deck安裝除錯記/",
"content": "前言\n好久沒買聖誕禮物了,\n前陣子又有人說steam deck oled很推,\n看了幾次都沒現貨,\n上週五,剛好喵到pchome有貨,下訂隔天到。\n禮拜六吃喜酒,又逛了一下lalaport,\n禮拜天中午跟朋友吃飯,才開始動工,\n然後就是一整個踩坑記。\n禮拜天開始安裝,第一次搞steam一堆問題。\n正文\n安裝時,一直卡在安裝剩餘1秒\n我試了幾種方法,\n\n重開機(沒用),重開了五六次,還是卡住\n\n看redit說 不要連2.4g的wifi,重開機安裝,一樣卡\n\n不斷關閉wifi後,重連我也試過,沒用(設定開關在右下方的那三個點)。\n\n最後改連手機的熱點分享,終於過了\n\n外掛推薦(不裝也可以)\n目前看到的都是一些比較個人化的東西,\n也可能我遊戲玩不多,\n之前主要都在玩p4\n第一步先安裝 Decky loader,可以參考 版上的 這篇\n(桌面模式,按左下的steam按鈕->電源->切換至桌面)\n(沒外接鍵盤的話,需按下 steam按鈕+X ,開啓螢幕小鍵盤)\n前面的設定先改好,後面安裝不需要輸入指令,在網站上點擊即可下載,\n然後對着下載下來的檔案,點兩下安裝,\n最後從桌面上的 圖示,回到掌機畫面。\n目前我裝的有\n\nBluetooth : 據說是能讓藍牙耳機自動連線\n\nAnimation Changer:關機(長按電源)、暫停(短按電源)的畫面修改\n\nProtonDB Badges:判斷遊戲在裝置上的可玩性\n\nSteamGridDB:修改掌機模式下遊戲的圖片,裝這個是掌機模式下的Chrome沒圖案真的太醜了。\n\nCSS-Loader:桌面佈景,可以到官網看有哪些\n\nAnimation Changer ,影片放大\n安裝CSS-Loader,然後搜尋 Full Suspend ,安裝完後即可。\n補丁安裝\n前面步驟,請看這一篇steam deck夏日狂想曲中文18+補丁,如果你bottle無法建立的話再回來。\n同事一直推坑我夏日狂想曲,然後bottle的bottles無法建立,一直卡在Arial font的字體安裝失敗,\n查原文有人推薦用Q4wine,就試試看了。\n但在flatsel需將Q4wine底下的Filesystem中的All system files打開,\n安裝時才能夠讀取到steam deck夏日狂想曲中文18+補丁 這邊說的\nZ:\\home\\deck\\Summer Memories\n\n額外補充\n\nprotonDB :查遊戲相容性的網站,不同獎牌代表的意思\n\n白金:完美執行。\n金:調整後完美執行。\n銀:有小問題,但可玩。\n銅:可玩,但經常遇到遊戲崩潰等問題。\n無法執行:如題。\nOled燈號閃爍意思\n\n狀態\n說明\n\n三閃紅燈\n電池電力不足無法開機\n\n啟動中(綠燈)\n主機在PSU連接狀態且電池已經充滿\n\n啟動中(白燈)\n主機在PSU連接狀態且充電功率與PD協定有成功辨識並在電量達到觸發閾值後進入旁路充電\n\n啟動中(橘燈)\n主機在PSU連接狀態且充電功率不足或PD協定無法辨識,簡單說就是以低功率充電\n\n啟動中(紅燈)\n偵測到主機溫度高於95度C,無法開機\n\n呼吸白燈\n主機開機中\n\n呼吸藍燈\n主機更新韌體或系統中\n\n無亮燈\n主機關機,且沒有偵測到PSU連接\n\nsteamdb:查遊戲特價歷史價格\n重置sudo 密碼\n如果你忘記密碼(因爲我就忘了),\n只剩下重刷這一條路了。\n將steam deck關機,按住右下方的『...』與開機按鈕開機,\n然後清除資料吧。\n組合鍵\n長按Steam按鈕,有快速鍵列表\nsteam + R1 : 截圖\nsteam +X : 開啓螢幕鍵盤\n『 ... 』+類比上下:調整螢幕亮度\n『 ... 』+電源: Recovery Manager\n音量『 - 』+電源 :Boot Manager\n音量『 + 』+電源 :BiOS\n配件\n未來應該再來下面幾個東西,再觀察看看需不需要了。\n\ntomtoc Steam Deck硬殼收納包 :看起來跟steam deck很合\nInnergie C6 Duo 63瓦 USB-C 雙孔:臺達的充電器,現在有一個單孔的,但有時要拔來拔去不方便。\ntype c hub:感覺還是頗需要,如果要用桌面模式接鍵盤、滑鼠或外接螢幕的話,這個要再找找看了。\n\n目前應該就這樣,\n剩下的等有碰到再研究。\nref.\n\nSteam Deck 大樓!\nSuspend animations are extremely small using Deck Loader\n[閒聊] SteamDeck兩周心得(配件、調校、套件)",
"tags": [ "note","🎮"]
},
{
"title": "Obsidian發佈到github.io個人網站",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/193. Obsidian發佈到github.io個人網站/",
"content": "前言\n前陣子弄好了Obsidian自動發佈到vercel,\n成果也還不錯,但就是偶爾有點問題,\n因為是免費用戶,所以會碰到無法更新。\n有天一怒之下,就自己改成用github了。\n正文\n首先前面還是一樣<a class=\"internal-link\" data-note-icon=\"\" href=\"/🆒 SideProject/160.Obsidian發佈網站/\">160.Obsidian發佈網站</a>,\n步驟要先設定好從Obsidiant傳到你的github。\n\n當你在Obsidian選擇publish時,會將內容傳到public_vercel 這個repository。\n\n所以,接下來的流程是,在public_vercel 使用github action,\n將obsidian的內容編譯成html,再轉到github的網站上面。\n\n到github建立個人網頁\n到github,建立一個自己使用者的子網域,\nrepository的名稱會是 user.github.io 這種名稱,\n只有user這個字可以改。\n建立完後,可以先弄個index.html到github裏面,\n然後訪問剛剛建立的網址,\n我建立的名稱為daimom.github.io\n\n所以網址就是 daimom.github.io\nref. github_page\n\n將npm轉成pnpm\n其實這一步也可以不做,\n那就是寫github action的時候,不能用pnpm只能用npm,\n程式應該也要小改一下,\n但pnpm會比較快,我就順便改一改了。\n\n到 public_vercel的資料夾底下,執行下面三行,參考從 npm 遷移到 pnpm,\n有些步驟我測試是不需要,\n重點是 pnpm import,要將package-lock.json 轉成 pnpm-lock.yaml。\n# 刪除npm package\nrm -rf node_modules\n# 安裝pnpm\nnpm install -g pnpm\n# 轉換相關檔案\npnpm import\n\n完成後,上傳到github。\n\n建立github action\n資料夾結構如下\n\n能改檔案名稱的只有build-site.yaml以及 install-pnpm,\n但後者要改的話,程式內容也需要改,不熟的話不建議更改。\n\nbuild-site.yaml的程式如下\nname: 'Build Sites'\n\non:\nworkflow_dispatch:\ninputs:\ndeployment-version:\ndescription: 指定版本\nrequired: false\nschedule:\n- cron: '0 10 * * *'\njobs:\nbuild-site-test:\nruns-on: ubuntu-latest\nsteps:\n# [Checkout]\n- name: Checkout code repository\nuses: actions/checkout@v4\nwith:\nfetch-depth: 0\n\n# [執行腳本] 構建 pnpm 及 Node 環境\n- name: '[Macro] Prepare environment'\nuses: ./.github/actions/install-pnpm\n\n# [執行腳本] 構建html\n- name: '[Macro] Build sites '\nshell: bash\nrun: pnpm build\n\n- name: Push to HTML Repository\nrun: |\ngit config --global user.email $\ngit config --global user.name "daimom"\ngit config --list\ngit clone https://$@github.com/daimom/daimom.github.io.git temp-html-repo\ncp -r dist/. temp-html-repo/\n\ncd temp-html-repo\ngit add .\ngit commit -m "Update from Build Repository"\ngit remote -v\ngit push origin main\n\ninstall-pnpm/action.yaml的程式如下\nname: 'prepare'\ndescription: 'Prepare environment'\n\nruns:\nusing: 'composite'\nsteps:\n- name: Setup pnpm\nuses: pnpm/action-setup@v2\nwith:\nversion: 8\n- name: Setup node.js\nuses: actions/setup-node@v4\nwith:\nnode-version: 20\ncache: 'pnpm'\n\n- name: Install dependencies\nshell: bash\nrun: pnpm install\n\n簡易說明\n這邊的設定是每天的UTC 10:00 執行一次,\n如果要自定時間的話,可以參考Crontab 中文線上 編輯器\n測試的時候可以先把\nschedule:\n- cron: '0 10 * * *'\n\n改成\npush:\nbranches:\n\t- 'main'\n\n這樣只要推上去main就會觸發動作了(注意排版)。\nref. 以 GitHub Action 來發推文\n或者是直接手動部署,\n在public_vercel的github action選擇你的Action ,再選 Run workflow\n\n程式裏面的 $ 是要到repository裏面設定。\n\n也可以直接輸入你的email,反正email這東西應該已經...。\n但重點是底下的 $ ,\n這個一定要用secret隱藏,而且不能外流。\n產生的方式,詳閱, <a class=\"internal-link\" data-note-icon=\"\" href=\"/🆒 SideProject/160.Obsidian發佈網站/#github-token\">160.Obsidian發佈網站#建立github token</a>\n再來將產生的token,新增到sercret裏面。\nref.\n\nGitHub Actions 文件\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/💻 Code/110.github action pipeline筆記/\">110.github action pipeline筆記</a>",
"tags": [ "note","🆒"]
},
{
"title": "200. Net core SDK安裝至container",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/200. Net core SDK安裝至container/",
"content": "前言\n後端之前發了一個版本上去後,\n記憶體就一路往上飆,\n他們也查不出個所以,\n後來幫他們查,有請他們加個程式碼試試,看來也成功了。\n但為了以後,還是知道一下要怎麼抓記憶體的用量比較好,\n就交給他去看了。\n<PropertyGroup>\n<ServerGarbageCollection>false</ServerGarbageCollection>\n</PropertyGroup>\n\nref. 【譯】Asp.net core應用在 Kubernetes上記憶體使用率過高問題分析\n正文\n以下為同事執行的指令,\n可能需要先安裝wget之類的東西。\n\n裝 dotnet SDK\n\nwget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh\nchmod +x ./dotnet-install.sh\n./dotnet-install.sh --version latest\n\n執行\n\n裝完後,最好先用 find / -iname dotnet ,\n查一下安裝後的dotnet在哪。\n執行的時候,記得用 ./dotnet --version ,的方式執行。\n不然,預設是用/usr/bin 裏面的dotnet執行的。\n\n除錯\n沒研究,但同事是參考下面這篇去實作。\n參考連結 Identifying Memory Leaks with dotnet-dump and dotnet-gcdump\n\nref.\n\n已編寫指令碼的安裝\nIdentifying Memory Leaks with dotnet-dump and dotnet-gcdump",
"tags": [ "note","🐳"]
},
{
"title": "201. kustomize patch",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/201. kustomize patch/",
"content": "前言\n懶癌發作,要部署新環境時,\n想到每個deployment要一個一個改,就好懶。\n該換擬出來了 kustomize,\nkubectl 現在預設就有支援,以前還要單獨裝指令。\n正文\n查看kustomize的結果\nkubectl kustomize ./\n\n執行方式\nkubectl apply -k <folder path>\n\n修改映像檔\n要注意得點是, deployment.yaml 的image裏面的映像檔名稱,\n要對應到kustomize.yaml 的 images.name。\n以下面的範例來說, my-image:1.2.3 其中my-image就是映像檔名稱,\n所以在kustomize.yaml裏面的image name要寫 my-image\ndeployment.yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\nname: my-app\nspec:\ntemplate:\nspec:\ncontainers:\n- name: my-container\nimage: my-image:1.2.3\n\nkustomize.yaml\nresources:\n- ../../../base\nimages:\n- name: my-image\nnewName: my.image.registry/nginx\nnewTag: 1.4.0\n\n修改其他欄位\n除了一般能修改的東西,能用 cross-cutting field 修改以外,\n其他要修改只能透過patch的方式。\n其中 patchesJson6902跟 patchesStrategicMerge,\n目前已經被patches取代,也將於後續版本deprecated.\n且 patches能夠在 name以及namespace上使用regex。\nref. What is the difference between patches vs patchesJson6902 in Kustomize\ncross-cutting 基本有這些\n\n如果上面有用到 cross-cutting 的參數,下面的原始檔,\n只要寫原始的就好,不用寫修改過的參數。\n例如 namespace 在原始的deployment.yaml是default,\n然後在 kustomize.yaml 裏面 修改成 game,\n那Patches還是寫原本的default。\nPatches底下的patch,只要有以下資訊即可,\n然後就是要修改的設定了。\napiVersion: apps/v1\nkind: Deployment\nmetadata:\nname: systemmanageservice\n\n下面範例是,修改container底下的env變數。\npatches:\n- target:\nkind: Deployment\nname: systemmanageservice\npatch: |-\napiVersion: apps/v1\nkind: Deployment\nmetadata:\nname: systemmanageservice\nspec:\ntemplate:\nspec:\ncontainers:\n- name: systemmanageservice\nenv:\n- name: ASPNETCORE_ENVIRONMENT\nvalue: QA\n\nref.\n\nKustomize 功能特性列表\npatches\n\npatchesJson6902\n上面有提到patches是 patchesJson6902 與\npatchesStrategicMerge的結合。\n於是 patches也支援下面這種用法。\n使用 op 來作新增或取代。\napiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\n\npatchesJson6902:\n- target:\nversion: v1\nkind: Deployment\nname: my-deployment\npatch: |-\n- op: add\npath: /some/new/path\nvalue: value\n- op: replace\npath: /some/existing/path\nvalue: "new value"",
"tags": [ "note","⎈"]
},
{
"title": "GCP多帳號切換",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/202. GCP多帳號切換/",
"content": "前言\n最近適逢專案搬家時期,帳號要切來切去,\n結果一切過去就不能用了。\n錯誤寫,你的B帳號無法在A專案使用。\n正文\nOS是 MacOS,window會不會有相同錯誤不清楚\n試了幾次,切換GCP帳號的指令都沒用,\n最後摸出一套可行的步驟\n\n先確定目前使用的gcp帳號是哪一個,* 代表使用中的帳號\n\ngcloud auth list\n\n然後確認config設定有沒有錯\ngcloud config list\n\n如果帳號或project有錯誤,就修改\n# 修改帳號\ngcloud config set account abc@abc.com\n# 修改project\ngcloud config set project project_id\n\n確認要使用專案的context設定\n指令\n\n# 取得所有cluster設定\nkubectl config get-contexts\n# 切換要使用的cluster\nkubectl config use-context [NAME]\n# 檢查目前使用中的cluster\nkubectl config current-context\n\nDocker 切換\n選擇環境後滑鼠點一下\n\n完成後,重開 Terminal\n一定要重開!!!!不然會像鬼打牆一樣,一直跳錯誤。\n\n差點都想直接用 gcloud auth revoke <account> 把帳號強制登出了。\n2024/04/11\n要切帳號時,terraform又掛了,一直提示我用另一個帳號。\n但用kubectl 指令時,都正常。\n後來執行這行,\ngcloud auth application-default login\n\n重新登入後正常。\nref.\n\n[GCP]gcloud切換帳號、專案\ngcloud auth",
"tags": [ "note","☁️"]
},
{
"title": "istio Authorization 拒絕指定檔案瀏覽",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/203. istio Authorization 拒絕指定檔案瀏覽/",
"content": "前言\n接到個需求,要限定網站的某個副檔名不能被瀏覽。\n正文\nAuthorization-policy的yaml\nRule規則分成三大塊\nFrom\n請求來源\nTo\n請求目的\nWhen\n指定的請求附加條件\nTo\nnginx查一下,是有類似的東西。\n但istio我看了官方文件,\n寫法是\n- to:\n- operation:\npaths: ["/user/profile/*"]\n\n目前只有支援單個 *\n\nExact match: abc will match on value abc.\n完全匹配: abc 將匹配值 abc 。\nPrefix match: abc* will match on value abc and abcd.\n前綴匹配: abc* 將匹配值 abc 和 abcd 。\nSuffix match: *abc will match on value abc and xabc.\n後綴匹配: *abc 將匹配值 abc 和 xabc 。\nPresence match: * will match when value is not empty.\n存在匹配:當值不為空時, * 將匹配。\n\n現在的目標是要阻擋 index-erscvs.js.map ,禁止任何人觀看。\n但 index-erscvs.js 不能被deny\n於是\nkind: AuthorizationPolicy\nmetadata:\nname: frontend-map-policy\nspec:\nselector:\nmatchLabels:\ngroup: frontend\naction: DENY\nrules:\n- to:\n- operation:\nhosts: ["abc.def.com"]\nports: ["80"]\npaths: ["*.js.map"]\n\n優先順序評估表 Custom > Deny > Allow\nref. Authorization Policy\nWhen\n注意,values不支援CIDR,需用* 代替私有網段\n這邊沿用 <a class=\"internal-link\" data-note-icon=\"\" href=\"/⛵️ istio/186. istio的Authorization policy(白名單)/\">186. istio的Authorization policy(白名單)</a> 的方式,\n設定白名單。\n於是,下面的設定方式,label 是 group=frontend的deploy,\n不允許訪問*.js.map的檔案,除了來源是 123.123.123.123\napiVersion: security.istio.io/v1\nkind: AuthorizationPolicy\nmetadata:\nname: frontend-map-policy\nspec:\nselector:\nmatchLabels:\ngroup: frontend\naction: DENY\nrules:\n- to:\n- operation:\nhosts: ["abc.def.com"]\nports: ["80"]\npaths: ["*.js.map"]\nwhen:\n- key: request.headers[X-Envoy-External-Address]\nnotValues:\n- "123.123.123.123"\n\n驗證時,可以用下面的指令協助查詢,\n要注意是不是被其他的policy影響了\n# 先開啟debug模式,資訊比較多,查完後將deploy重啟即可\nistioctl proxy-config log deploy/httpbin --level "rbac:debug" | grep rbac\n\nfor i in {1..20}; do curl -H 'Cache-Control: no-cache, no-store' https://abc.def.com/assets/index-d74bceac.js -s -o /dev/null -w "%{http_code}\\n"; done\n\nkubectl logs <pod name> -c istio-proxy\n\n注意\nwhen 跟 to 如果用 下面方式的話,表示是兩條規則\n...\n\t- to:\n\t\t...\n\t- when:\n\t\t...\n\n這樣才是同一條規則,\n我犯了這個蠢錯誤\n\t- to:\n\t\t...\n\t when:\n\t\t...\n\nref.\n\nAuthorization Policy\nAuthorization Policy Conditions\nauthorizationPolicy詳解",
"tags": [ "note","⛵️"]
},
{
"title": "205. Grafana 筆記",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/205. Grafana 筆記/",
"content": "前文\n正文\n單位換算\nbyte(IEC):以1024轉換計算。2MB = 2042 kb\nbyte(SI) : 以十進位計算。 2MB= 2000kb\n更換線條顏色\n\n先把Legend 打開\n點選Legend的顏色\n\n隱藏\nOverrides裡面的選項,有時會被打勾,導致線圖不會出現\n匯出\n\n點選標題的右邊分享按鈕\n\n選擇Export ,再來看要存檔或檢視Json",
"tags": [ "note","👁"]
},
{
"title": "steamDeck 的 Cheat Engine替代品",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/206. steamDeck 的 Cheat Engine替代品/",
"content": "前言\n春特入手了幾款 跟弟弟一起玩的遊戲,\n但有些時候重複刷的有點煩,\n就想說改一下省點時間,\n查了一些資訊,發現CheatEngine不是不能裝,\n但有夠麻煩!!!!!\n正文\n鎮重聲明,修改有一定風險。\n感謝巴友C.C告知另一套軟體『memory deck』\n直接在Decky loader 搜尋,安裝即可。\n搜尋方式也很簡單,直接按掌機右下的 ... 就能搜尋。\n缺點是每次要改就要重新搜尋一次。\n最後在reddit找到了 memory_hack\n這款的好處在於,steam deck(桌面模式)開啟遊戲後,\n用手機或電腦在同一個wifi底下,開啟網頁即可修改。\n安裝方式也很簡單,\n\n建立一個資料夾,要放安裝檔\n\npython3 <(wget -qO- https://github.com/primetime00/memory_hack/raw/master/app/patches/install.py)\n\n安裝完後,會問你要不要當成預設程式,我是選n ,當有需要時再到剛剛的資料夾啟動就好。\n\n啟動指令,到該資料夾底下執行 ./run.sh\n安裝說明連結\n然後就可以先在steam deck上面開網頁,http://localhost:5000 看有沒有資料。\n如果要用手機或電腦連的話,\n可以另外開啟konsole ,執行 ip -4 addr 就會看到你的ip,假設是192.168.0.125,\n在手機上開啟 http://192.168.0.125:5000 ,就會看到畫面了。\n簡易操作\n\n到 Search 的頁籤上,選擇 Process的 遊戲名稱\n\n輸入數值查詢,通常要兩次查詢,第一次有很多資料,當數值變動時,再搜尋一次,就會有了\n\n複製記憶體位置\n\n到 Code的頁籤,選擇 Process的遊戲名稱\n\n輸入數值,旁邊的方格,打勾表示鎖定數值。\n\np.s 改完後,數值可能不會馬上重現,讓遊戲的數值變動一下。\n完整操作說明,請參考 Memory Hack Beginner Tutorial\n之前有人介紹另一款,\nMemory Deck ,直接在掌機模式下的Decky loader 商店搜尋,\n裝起來就好了。",
"tags": [ "note","🎮"]
},
{
"title": "207. mapgenie整批unfound",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/207. mapgenie整批unfound/",
"content": "前言\n前陣子玩遊戲時發現一個網站,mapgenie.io\n裡面有很多遊戲的地圖,\n按下found以後,不想一個一個把勾拿掉。\n正文\n有餘力的話,應該是買VIP會員才對,\n但我覺得我用不到那麼多功能,\n可能這個功能也是VIP專用。\n畢竟花錢就是要省時間,不想花錢又想省時間的話,\n洗洗睡吧。\n\n打開網頁的開發者工具,\n找到 body > div#app\n底下的scripts,會長的像這樣\n\n最上面有一些數字,那些數字就是我們要的。\n\n選擇網路頁籤\n再來將一個found關掉,會看到底下的Fetch/XHR,新增一筆。\n點選後,注意看箭頭是不是寫DELETE\n\n複製成CURL\n對著剛剛的58673按右鍵,選擇複製成CURL\n\n然後找個記事本貼上,你會發現一長串的東西。\n我測試過,可以把 -H 'cookie:' 整段拿掉,\n其他東西應該就不好刪了。\n\n再來就是更換最上面的數字,就不用一個一個點標誌,然後把勾拿掉了。\n上面的圖片,我只節錄了三行,完整的不只這樣。\n然後將curl丟去 命令提是字元執行就好了。\n更懶一點,弄個for迴圈,把數字自動帶進去網址。\n可以參考 <a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/135. gsutil整批複製/\">135. gsutil整批複製</a>\n還有另一種就是去找newman去搞自動化帶入參數應該也能做到。",
"tags": [ "note","🆒"]
},
{
"title": "208. 架設sftp",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/208. 架設 sftp/",
"content": "事由\n需要一個地方放大量的資料,日後提供給客戶下載,\n本來想說用GCS就好,但如果要一次下載好幾個檔案就沒辦法了。\n只好乖乖弄FTP。\n正文\n一開始用vsftp,搞個docker 大概沒10分鐘就好了。\n有一半的時間在找image上面,\n但如果要達成『一個使用者,可以看到所有使用者的目錄,其他使用者需要獨立』就懵了。\n後續找資料時,看到鳥哥說了一句話,『所以,建議您,除非必要,否則的話,使用 SSH 提供的 sftp-server 功能即可』\nref. FTP 的安全性問題與替代方案\n所以我就轉往sftp了。\n先來釐清目標,\n\n一個最高權限的帳號,\n可以在所有使用者的目錄新增檔案,\n然後所有使用者間是不能互相看到彼此的檔案。\n\ndocker image 使用 corilus/sftp,\n下載量已達1M。\n如果只是簡單的ftp功能,直接架起來就好了。\n但要做成上面的目標,要用mount的方式,將資料夾掛載到主目錄底下。\n詳細作法參考下面。\ndocker-compose.yaml\nversion: '3'\nservices:\nsftp:\ncontainer_name: sftp\nimage: corilus/sftp\nprivileged: true\nvolumes:\n- ./mount.sh:/etc/sftp.d/bindmount.sh\n- ./userlist.conf:/etc/sftp/users.conf:ro\n- ./upload:/home\nports:\n- "2222:22"\nrestart: always\n\n指令說明,可參考 <a class=\"internal-link\" data-note-icon=\"\" href=\"/🐧 Linux/108. linux shell 進階指令/#bdeaee\">108. linux shell 進階指令#^bdeaee</a>\nmount.sh\n#!/bin/bash\n# File mounted as: /etc/sftp.d/bindmount.sh\n# Just an example (make your own)\n\nfunction bindmount() {\nif [[ ! -d "$1" ]]; then\nmkdir -p "$1"\nfi\n\nif [[ ! -d "$2" ]]; then\n\t mkdir -p "$2"\nfi\n\nchown -R :100 "$1" "$2"\nchmod 775 "$1" "$2"\nmount --bind "$1" "$2"\n}\n\n# Remember permissions, you may have to fix them:\n# chown -R :users /data/common\nbindmount "/home/mike/upload" "/home/ms/mike"\nbindmount "/home/aaron/upload" "/home/ms/aaron"\n\nuserlist.conf\nms:ms:1001:100\nmike:mike:1002:100\naaron:aaron:1003:100\n\n本來想用ln的方式去操作,\n從terminal 能夠進去資料夾,但用FTP登入就是說 no such file or dirctory\n問了老半天GPT也都是失敗,\n從一開始說要加個不存在的參數 FollowSymlinks ,\n到後面的一連串重複回答。\n最後看到 Symbolic link and filezilla over sftp\n看來是ln的先天限制,所以改用mount後,調個權限,好了。\nref.\n\nCorilus/sftp Github",
"tags": [ "note","🐧"]
},
{
"title": "209.k8s中srs的各個pod metrics取得",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/209. k8s中srs的各個pod metrics取得/",
"content": "事由\n同事正在弄SRS串流,照我以前的寫法,\n是透過service去取得單一個pod的metrics,\n這樣只會有一個pod的資料,\n所以要想辦法取得所有pod的資料。\n正文\n由於我有套用istio,\n於是有套istio-proxy的pod通通會預設塞\nprometheus.io/path: /stats/prometheus\nprometheus.io/port: '15020'\nprometheus.io/scrape: 'true'\n\n所以直接在deploy加參數進去時,也會被改寫。\n於是只好額外寫job 如下\n- job_name: 'srs'\nscrape_interval: 10s\nstatic_configs:\n- targets:\n- 'srs.default.svc.cluster.local:9972'\n\n呼叫 service 的 srs ,然後去取得metrics的metrics。\n但當有多個pod的時候,這就會出問題了。\n因為service到pod的流量平均分配,你不會知道他連去哪個pod。\n但今天我要抓全部metrics,這種寫法就會出問題。\n其中 static_configs 這個只適用於 固定字串,\n所以對於會變來變去的pod ip沒有用。\n於是要改成\n- job_name: 'srs'\nscrape_interval: 10s\nkubernetes_sd_configs:\n- role: pod\nrelabel_configs:\n- source_labels: [__meta_kubernetes_pod_name]\naction: keep\nregex: srs-.*\n- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]\naction: replace\ntarget_label: __metrics_path__\nreplacement: /metrics # 強制指定路徑為 /metrics\n- source_labels: [__meta_kubernetes_pod_container_port_name]\naction: replace\ntarget_label: portname\nreplacement: 9972\n\n規則由上往下依序執行,有符合才會往下。\nkubernetes_sd_configs 有這5種方式(GPT抄來的)\n\nrole: endpoints:\n\n這個組態項告訴 Prometheus 去發現 Kubernetes 中的端點對象。端點對象代表了服務的後端 Pod 的 IP 地址和連接埠。\n通過此組態項,Prometheus 可以直接與後端 Pod 進行通訊,收集指標資料。\n\nrole: service:\n\n這個組態項告訴 Prometheus 去發現 Kubernetes 中的服務對象。\nPrometheus 將會為每個服務發現服務的所有後端 Pod,並從每個 Pod 中抓取指標資料。\n\nrole: pod:\n\n這個組態項告訴 Prometheus 去發現 Kubernetes 中的 Pod 對象。\nPrometheus 將會為每個發現的 Pod 收集指標資料。\n\nrole: ingress:\n\n這個組態項告訴 Prometheus 去發現 Kubernetes 中的 Ingress 對象。\nPrometheus 將會監視 Ingress 對象,並收集與之相關的指標資料。\n\nrole: node:\n\n這個組態項告訴 Prometheus 去發現 Kubernetes 中的節點對象。\nPrometheus 將會為每個節點收集相關的指標資料。\n\n再來是重點 relabel_configs\n分別有\n\nsource_labels:來源標籤,可以參考prometheus的UI,上面有顯示很多label\n\naction:四種動作(keep,drop,replace,labelmap)。\n決定你要將值保留、終止、取代或標籤對應\ntarget_label:目的標籤,\n抓資料的url,由下面三種特殊標籤組成__scheme__ + __address__ + __metrics_path__。\n範例: https://192.168.103.224:9527/metrics\n主要是決定特殊標籤要用什麼,不然隨便取名都可以。\nregex,當作是條件判斷這裡面的值要符合規則能往下。\n下面regex意思是,pod name要符合srs-.*的才保留。\n\n- source_labels: [__meta_kubernetes_pod_name]\naction: keep\nregex: srs-.*\n\nreplacement:變更的值\n\nref.\n\nSRS-Prometheus Exporter\nRelabeling 重新標記\n[Prometheus] Service Discovery & Relabel",
"tags": [ "note","👁"]
},
{
"title": "210. Arc Browser筆記",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/210. Arc Browser筆記/",
"content": "前言\n最近看到一個頗神的瀏覽器,Arc from The Browser Company\n最近剛出了win11版本,mac則要12版本以上才能使用。\n我的mac是2015年的可以安裝。\n正文\n可以先看一下這個Arc 真香!腦洞大開的功能讓超多 Chrome 死忠粉決定把 Arc 當作預設瀏覽器了! 裡面有簡單的教學。\n\n要注意的是,現在的版本已經把內建Note砍掉了,\n如果要使用只能用線上的。\n打開 Preferences > Profiles > New documents\n選擇你要設定的線上服務\n\n瀏覽器設定檔\nARC 本身也是用chrome的核心去做的,\n所以除了Arc本身的設定以外,還有chromium的設定。\n進去的方式 Preferences > Profiles > Search Settings..\n\n目前會常用到的快速鍵\n⌘+S:開關左邊的SideBar\n⌘+T:開啟新分頁\n\n注意,開啟的分頁預設只會維持12hour,\n更改可到 圖1 的Archive tabs after修改\n\n⌘+⌥(options)+G:快速開啟chatGPT\n\nArchive的歷史紀錄\n在sidebar 往左滑即可。\n或直接點選",
"tags": [ "note","🆒"]
},
{
"title": "211. k8s service endpoint無法連結",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/211. k8s service與 endpoint無法連結/",
"content": "前言\n某天在建立新的叢集,\n服務都已經架好準備給RD了,\n最後才發現,平常用的連線方式連不到GCP的Memorystore.Redis。\n這個問題卡了整整一週,\n不斷的刪除重建、比對、找差異。\n故事展開\nGKE 版本: 1.28.7-gke.1026000\n先簡單說一下架構,\nistio增加6379 的port ,\n新增redis的svc以及endpoint,\n由於redis是GCP的服務,故本身沒有pod,\n讓istio能夠透過virtusalService連到這個service,\n然後RD透過這個ip以及port連到 GCP的Redis。\n先來看錯誤的使用方式,\n\n在port name上面設定redis的名稱,\n導致svc的endpoints上面無法綁定。\n不設定port name的話\n\n則可以正常綁定。\n目前猜測,可能跟 IANA的port name有關係。\n但為什麼會這樣,\n就不清楚了。\n# Service Name and Transport Protocol Port Number Registry\n目前測試出來,只要有設定Name就會綁不到endpoints。\n另外,EndpointSlice目前(2024/05/20)仍會無法綁定,\n請先改用Endpoint的api。\n\napiVersion: discovery.k8s.io/v1\nkind: EndpointSlice\nmetadata:\nname: redis # must be the same as service name\nnamespace: istio-system\nlabels:\n# You should set the "kubernetes.io/service-name" label.\n# Set its value to match the name of the Service\nkubernetes.io/service-name: redis\naddressType: IPv4\nports:\n- name: redis # should match with the name of the service port defined above\nappProtocol: redis\nprotocol: TCP\nport: 6379\nendpoints:\n- addresses:\n- "10.1.11.43"\n\n---\napiVersion: v1\nkind: Service\nmetadata:\nname: redis\nnamespace: istio-system\nspec:\nports:\n- protocol: TCP\nport: 6379\ntargetPort: 6379\nname: redis\n\n參照官方文件的作法也不會綁定。\nServices without selectors\n2024/05/8\n有另一個工程師告知,\nendpoint那邊的Port Name也加上去的話,\n就好了。\n結論\n頂多改改 Endpoints的address就好了,\nport name那些,別亂加。\n要加就要一起加,且名稱也要一樣。\n---\napiVersion: v1\nkind: Endpoints\nmetadata:\nname: redis # must be the same as service name\nnamespace: istio-system\nsubsets:\n- addresses:\n- ip: 10.122.11.43\nports:\n- port: 6379\n\t name: redis\n---\napiVersion: v1\nkind: Service\nmetadata:\nname: redis\nnamespace: istio-system\nspec:\nports:\n- protocol: TCP\nport: 6379\ntargetPort: 6379\nname: redis",
"tags": [ "note","⎈"]
},
{
"title": "212. k8s的親和性與反親和性",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/212. k8s的親和性與反親和性/",
"content": "緣由\n後端的服務,沒有HPA,所以目前都單Pod在執行。\n但很不巧的,都在同一個Node裡面。\n所以當一個Node出問題時,其他服務會一起陣亡。\n但只有一個NodePool,也沒辦法用nodeSelector。\n正文\nGKE版本:1.27\n先上範例,詳細說明在下面(格式有點跑掉,複製使用時要注意)。\napiVersion: apps/v1\nkind: Deployment\nmetadata:\nname: bms\nlabels:\ngroup: svc\napp: backend\nspec:\nreplicas: 1\nselector:\nmatchLabels:\ngroup: svc\napp: backend\ntemplate:\nmetadata:\nlabels:\ngroup: svc\napp: backend\nspec:\ncontainers:\n- name: service\nimage: my-image:v1.0.6\nports:\n- name: http\ncontainerPort: 80\nprotocol: TCP\naffinity:\npodAntiAffinity:\n\t\t\tpreferredDuringSchedulingIgnoredDuringExecution:\n\t - weight: 100\n\t\t podAffinityTerm:\n\t labelSelector:\n\t matchExpressions:\n\t - key: app\n\t operator: In\n\t values:\n\t - gcp\n\t topologyKey: kubernetes.io/hostname\n\n這個的用途,主要是讓pod決定要跟哪個服務在一起,或不在一起。\n其中比較重要的參數,\n反親和性與親和性\n\npodAntiAffinity\npodAffinity\n\n前者是反親和性,不要跟哪個服務在一起\n後者是親和性,要跟哪個服務在一起\n必要與最好可以\n\nrequiredDuringSchedulingIgnoredDuringExecution\npreferredDuringSchedulingIgnoredDuringExecution\n\n前者是一定要達成下面的條件,\n後者是最好是達成這樣的條件,並設成比重分數\n選擇條件\nrequiredDuringSchedulingIgnoredDuringExecution:\n- labelSelector:\nmatchExpressions:\n- key: app\noperator: In\nvalues:\n- gcp\ntopologyKey: kubernetes.io/hostname\n\npreferredDuringSchedulingIgnoredDuringExecution:\n- weight: 100\npodAffinityTerm:\nlabelSelector:\nmatchExpressions:\n- key: app\noperator: In\nvalues:\n- gcp\ntopologyKey: kubernetes.io/hostname\n\n大致上的邏輯一樣,\n但preferredDuringSchedulingIgnoredDuringExecution ,\n必須加上podAffinityTerm 。\n簡單說明規則,\n選擇這個服務要跟哪個label當比較值。\n然後,topologyKey 有點類似SQL group的概念,你要根據哪個來分群。\n上面的例子是根據 node name來區分,\n還有根據區域 kind.zone 來分。\n如果想知道有哪些的話,可以下指令看一下。\nkubectl get nodes --show-labels\n\n上面是簡單的寫法,\n詳細過程可以參考 矽谷牛大大的文章,連結在下方。\nref.\n\n矽谷牛-解密 Assigning Pod To Nodes(下)\nK8s文件-將 Pod 指派給節點\n[Kubernetes] Assigning Pods to Nodes",
"tags": [ "note","⎈"]
},
{
"title": "214. Elastic API建立 Index_template",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/214. Elastic API建立 Index_template/",
"content": "前言\n幫同事測試不同LOG的刪除時間,\n每次要去點一點又怕忘記,\n弄個API了,\n不知道之後能不能在部屬時直接掛上去,再研究看看。\n這次就先簡單建立個 index template跟life cycle了\n正文\n首先要先確定你的filebeat有將資料丟到elastic裡面,可參考<a class=\"internal-link\" data-note-icon=\"\" href=\"/🗒 EFK/57.filebeat 補充說明/\">57.filebeat 補充說明</a>。\n再來根據你建的是indices還是datastream,來決定你的index_template。\n下面的指令,都在dev tools中執行。\n\nAPI後面的最後一個路徑為名稱\n\nindices\n\nAPI建立 Index Lifecycle Policies\n\nPUT _ilm/policy/worker\n{\n"policy": {\n"_meta": {\n"description": "used for worker log",\n"author": "Ezio",\n"project": {\n"name": "srs",\n"department": "lerouge"\n}\n},\n"phases": {\n"hot": {\n"min_age": "0ms",\n"actions": {\n"set_priority": {\n"priority": 100\n},\n"rollover": {\n"max_age": "3d",\n"max_primary_shard_size": "50gb"\n}\n}\n},\n"delete": {\n"min_age": "3d",\n"actions": {\n"delete": {\n"delete_searchable_snapshot": true\n}\n}\n}\n}\n}\n}\n\n建立 index_template\n\nPUT _index_template/worker\n{\n"index_patterns" : ["worker-*"],\n"template": {\n"settings": {\n"index": {\n"lifecycle": {\n"name": "videoworker"\n}\n}\n}\n},\n"composed_of": ["ecs@mappings", "logs@mappings","logs@settings"],\n"priority" : 200,\n"version": 1,\n"_meta": {\n"description": "test by Ezio",\n"latest_modify_date": "2024-05-28"\n}\n}\n\n檢查 Index Lifecycle Policies 及 index template\n\nGET _ilm/policy/worker # Index Lifecycle Policies\nGET _index_template/worker # index template\n\nref.\n\nCreate or update lifecycle policy API\nIndex templates\n\ndata stream\n\n建立 index template\n與上面的差異點在於,有沒有增加data_stream與 template.lifecycle.data_retention\n\nPUT _index_template/videowork\n{\n"index_patterns" : ["videoworker-*"],\n"template": {\n"lifecycle": {\n"data_retention": "3d"\n}\n},\n"data_stream": { },\n"composed_of": ["ecs@mappings", "logs@mappings","logs@settings"],\n"priority" : 200,\n"version": 1,\n"_meta": {\n"description": "test by Ezio",\n"latest_modify_date": "2024-05-28"\n}\n}\n\nref. Create a data stream with a lifecycle\nindices vs data stream\n下面資料是用gpt-4o提供的\n\n特性\nIndices\nData Streams\n\n管理方式\n手動管理或使用 ILM\n自動管理滾動和索引\n\n數據存儲\n適合任意結構數據\n專為時間序列數據設計\n\n對應組態\n每個索引獨立組態\n透過索引範本自動組態\n\n滾動策略\n需手動或 ILM 組態\n自動滾動\n\n查詢性能\n基於標準索引\n優化時間序列數據查詢\n\n索引創建\n使用 PUT /index_name\n透過索引範本自動創建\n\n適用數據\n任意數據,包括非時間序列數據\n主要為日誌、指標等時間序列數據\n\n學習曲線\n需要學習和管理索引的細節\n簡化,特別適合大規模時間序列數據\n\n生命週期管理\n需要組態 ILM\n自動管理\n\n存儲效率\n依賴手動優化\n為時間序列數據設計,具備存儲效率\n\n優缺點\n\n項目\nIndices\nData Streams\n\n優點\n- 更靈活,可用於任意類型數據\n- 自動管理滾動和索引\n\n- 完全自定義對應和設置\n- 簡化組態和管理\n\n- 支援複雜的查詢和聚合\n- 優化時間序列數據查詢和存儲\n\n- 適合大規模日誌和指標數據\n\n缺點\n- 需手動管理索引和滾動策略\n- 主要針對時間序列數據\n\n- 組態和管理相對複雜\n- 不適合非時間序列數據\n\n- 需要組態和維護 ILM\n- 對應和設置相對不靈活\n\n推薦使用場景\n\n使用場景\nIndices\nData Streams\n\n日誌管理\n可以使用,但需要手動組態滾動和管理\n最佳選擇,自動管理,簡化運維\n\n應用監控\n可以使用,但需自定義索引和對應\n最佳選擇,專為時間序列數據設計\n\n定期報表\n適合任何類型報表\n適合時間序列報表\n\n歷史數據查詢\n最佳選擇,可針對具體需求優化查詢\n適合基於時間範圍的歷史數據查詢\n\n複雜數據分析\n最佳選擇,支援靈活的對應和查詢\n適合時間序列數據的快速查詢和聚合\n\n非時間序列數據存儲\n最佳選擇,適合所有類型數據\n不推薦,僅適合時間序列數據\n\n結論\n其實從API來看的話,直接用data stream比較快,也比較省事。\n加上目前用的是ECK,\n我根本沒去設計 warm phase 或 cold phase的硬碟。\nref. ES 的超前佈署 - Index Template",
"tags": [ "note","🗒"]
},
{
"title": "216. GKE掛載ReadWrite Many的PVC",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/216. GKE掛載ReadWrite Many的PVC/",
"content": "緣由\nGKE上面的pvc是不支援ReadWrite Many的。\n用途是全部的Log寫到同一個資料夾,\n然後再用filebeat擷取到EFK。\n主題\n這邊要做的是自建一個NFS server。\ndeploy裡面,也可以直接在GCE上面建立一個硬碟,\n然後在deploy上面指定。就是下面這段,\n這原本是前任的方式,我直接改掉了。\n直接在一個yaml裡面全部弄好。\ngcePersistentDisk:\npdName: gke-log-nfs-disk\nfsType: ext4\n\nNFS-server.yaml\n---\napiVersion: v1\nkind: Namespace\nmetadata:\nname: nfs\n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\nname: nfs-pvc\nnamespace: nfs\nspec:\nstorageClassName: "standard"\nresources:\nrequests:\nstorage: 100Gi\naccessModes:\n- ReadWriteOnce\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\nname: nfs-server\nnamespace: nfs\nspec:\nreplicas: 1\nselector:\nmatchLabels:\nrole: nfs-server\ntemplate:\nmetadata:\nlabels:\nrole: nfs-server\nspec:\ncontainers:\n- name: nfs-server\nimage: gcr.io/google_containers/volume-nfs:0.8\nports:\n- name: nfs\ncontainerPort: 2049\n- name: mountd\ncontainerPort: 20048\n- name: rpcbind\ncontainerPort: 111\nsecurityContext:\nprivileged: true\nvolumeMounts:\n- mountPath: /exports\nname: nfs-pvc\nvolumes:\n- name: nfs-pvc\npersistentVolumeClaim:\nclaimName: nfs-pvc\n# gcePersistentDisk:\n# pdName: gke-log-nfs-disk\n# fsType: ext4\n---\napiVersion: v1\nkind: Service\nmetadata:\nname: nfs-server\nnamespace: nfs\nspec:\nports:\n- name: nfs\nport: 2049\n- name: mountd\nport: 20048\n- name: rpcbind\nport: 111\nselector:\nrole: nfs-server\n\n再來是掛載一個provisioner\nnfs-provisioner.yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\nname: nfs-client-provisioner\nnamespace: nfs\nlabels:\napp: nfs-client-provisioner\nspec:\nreplicas: 1\nselector:\nmatchLabels:\napp: nfs-client-provisioner\nstrategy:\ntype: Recreate\ntemplate:\nmetadata:\nlabels:\napp: nfs-client-provisioner\nspec:\nserviceAccountName: nfs-client-provisioner\ncontainers:\n- name: nfs-client-provisioner\nimage: gcr.io/k8s-staging-sig-storage/nfs-subdir-external-provisioner:v4.0.2\n# image: registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2\nvolumeMounts:\n- name: nfs-client-root\nmountPath: /persistentvolumes\nenv:\n- name: PROVISIONER_NAME\nvalue: nfs-log\n- name: NFS_SERVER\nvalue: nfs-server.nfs.svc.cluster.local\n- name: NFS_PATH\nvalue: /\nvolumes:\n- name: nfs-client-root\nnfs:\nserver: nfs-server.nfs.svc.cluster.local\npath: /\n---\napiVersion: storage.k8s.io/v1\nkind: StorageClass\nmetadata:\nname: nfs-log\nprovisioner: nfs-log\nparameters:\narchiveOnDelete: "false"\n\n---\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\nname: nfs-client-provisioner-runner\nrules:\n- apiGroups: [""]\nresources: ["nodes"]\nverbs: ["get", "list", "watch"]\n- apiGroups: [""]\nresources: ["persistentvolumes"]\nverbs: ["get", "list", "watch", "create", "delete"]\n- apiGroups: [""]\nresources: ["persistentvolumeclaims"]\nverbs: ["get", "list", "watch", "update"]\n- apiGroups: ["storage.k8s.io"]\nresources: ["storageclasses"]\nverbs: ["get", "list", "watch"]\n- apiGroups: [""]\nresources: ["events"]\nverbs: ["create", "update", "patch"]\n---\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\nname: run-nfs-client-provisioner\nsubjects:\n- kind: ServiceAccount\nname: nfs-client-provisioner\nnamespace: nfs\nroleRef:\nkind: ClusterRole\nname: nfs-client-provisioner-runner\napiGroup: rbac.authorization.k8s.io\n---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\nname: nfs-client-provisioner\nnamespace: nfs\n---\nkind: Role\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\nname: leader-locking-nfs-client-provisioner\nnamespace: nfs\nrules:\n- apiGroups: [""]\nresources: ["endpoints"]\nverbs: ["get", "list", "watch", "create", "update", "patch"]\n---\nkind: RoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\nname: leader-locking-nfs-client-provisioner\nnamespace: nfs\nsubjects:\n- kind: ServiceAccount\nname: nfs-client-provisioner\nroleRef:\nkind: Role\nname: leader-locking-nfs-client-provisioner\napiGroup: rbac.authorization.k8s.io\n\n要使用的話,\n建立一個pvc, storageClassName改成上面建立的storageClass\n其他deploy掛載方式,跟掛pvc一樣。\n---\nkind: PersistentVolumeClaim\napiVersion: v1\nmetadata:\nname: logs-nfs-pvc\nnamespace: default\nspec:\naccessModes:\n- ReadWriteMany\nstorageClassName: nfs-log\nresources:\nrequests:\nstorage: 100Gi\n\nref.\n\n在GKE上使用ReadWrite Many的Disk\nnfs-subdir-external-provisioner",
"tags": [ "note","⎈"]
},
{
"title": "217. iptables 筆記",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/217. iptables 筆記/",
"content": "緣由\nistio重新複習概念的時候,\n又碰到了iptable,然後,我又忘了。\n沒有用自己理解過的作法,\n果然很容易忘記啊。\n主題\niptables簡單說是個管高速公路大門的。\n基本有三條路(chain),\n分別是\n\nfilter:這條路會直接到管高速公路大門的管理單位大樓裡面。\nnat:要去這條高速公路的其他地方,就往這邊。\nmangle:特權道路,有高官要過時,就走這條。\n\n鳥哥的說明:\n\nfilter (過濾器):主要跟進入 Linux 本機的封包有關,這個是預設的 table 喔!\n\nINPUT:主要與想要進入我們 Linux 本機的封包有關;\nOUTPUT:主要與我們 Linux 本機所要送出的封包有關;\nFORWARD:這個咚咚與 Linux 本機比較沒有關係, 他可以『轉遞封包』到後端的電腦中,與下列 nat table 相關性較高。\n\nnat (位址轉換):是 Network Address Translation 的縮寫, 這個表格主要在進行來源與目的之 IP 或 port 的轉換,與 Linux 本機較無關,主要與 Linux 主機後的區域網路內電腦較有相關。\n\nPREROUTING:在進行路由判斷之前所要進行的規則(DNAT/REDIRECT)\nPOSTROUTING:在進行路由判斷之後所要進行的規則(SNAT/MASQUERADE)\nOUTPUT:\n\nmangle (破壞者):這個表格主要是與特殊的封包的路由旗標有關, 早期僅有 PREROUTING 及 OUTPUT 鏈,不過從 kernel 2.4.18 之後加入了 INPUT 及 FORWARD 鏈。 由於這個表格與特殊旗標相關性較高,所以像咱們這種單純的環境當中,較少使用 mangle 這個表格。\n\nref. iptables 的表格 (table) 與鏈 (chain)\n\n每個chain裡面都有自己rule,\nrule 1 是去彰化,\nrule 2 是去員林,\nrule 3是去嘉義。\n從台中南下要去彰化的話,rule 1 符合就直接去彰化了。\n但如果是要去嘉義,前面不符合,就跳過,直到rule 3判斷符合才會執行。\nref. Istio 中的 Sidecar 注入、透明流量劫持及流量路由過程詳解",
"tags": [ "note","🐧"]
},
{
"title": "219. Google Cloud Managed Service for Prometheus 費用",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/219. Google Cloud Managed Service for Prometheus 費用/",
"content": "緣由\n由於GKE預設惠啟用 Google Cloud Managed Service for Prometheus,\n來比較一下,看之後是不是能夠一個網站看到全部的圖表。\n不過也要先看下價格,如果太貴,那也只能分開了。\n主題\n2024/06/07\n價格\n\n$0.06/百萬個樣本†:注入的前 0-50 億個樣本†\n$0.048/百萬樣本:接下來的 50-2500 億個樣本\n$0.036/百萬樣本:接下來注入的 250-5,000 億個樣本\n注入的每百萬個樣本 $0.024:超過 5000 億個樣本\n\n這數字以百萬計。\n一下子真的不知道該怎麼算,\n那就先算出 每10秒一個metric,那一個月會有多少資料。\nans: 259,200筆。所以一個月 $0.06USD\n加減算一下50億個樣本,要多少錢。\nans: $300 USD\n現在來算一下,一般建pvc要多少,\n建立一個PVC,預設使用 Balanced persistent disk。\npvc通常掛個100G,每個月約$10 USD。\n\nType\nPrice (monthly in USD)\n\nStandard provisioned space\n$0.04 per GiB\n\nSSD provisioned space\n$0.17 per GiB\n\nBalanced provisioned space\n$0.1 per GiB\n\n結論\n這價格看起來還頗有吸引力的,來試試看吧。\n日後如果要從帳單看有多少筆資料的話,\nService -> Cloud Monitoring\nSKUs -> Prometheus Samples Ingested & Monitoring API Requests\nref.\n\nCloud Monitoring 價格摘要\n費用控制和歸因\n硬碟價格",
"tags": [ "note","☁️"]
},
{
"title": "220. winSW將程式變成服務的好東西",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/220. windows將程式變成服務的好東西-winSW/",
"content": "緣由\n本來在Linux上面跑的docker環境,\n這次在客戶那邊突然要變成用windows,\n非常好,之前弄的架構完全不一樣。\n主題\n今天有一個程式,你想讓他開機時自己啟動,\n不是到msconfig設定開機啟動,就是弄成服務。\n但開機啟動,如果沒有開機就沒用了,\n所以弄成服務,一般是最穩定的方式。\n用nginx為範例說明,\n我也是找nginx啟動時,才發現這個好東西。\n\n首先,先下載winSW,\n下載回來的程式,改名成nginx-server.exe。\n\n同一層目錄下,建立nginx-server.xml\n\n<!-- nginx-service.xml -->\n<service>\n<id>nginx</id>\n<name>nginx</name>\n<description>nginx</description>\n<logpath>C:\\nginx-1.26.1\\server-logs\\</logpath>\n<logmode>roll</logmode>\n<depend></depend>\n<executable>C:\\nginx-1.26.1\\nginx.exe</executable>\n<stopexecutable>C:\\nginx-1.26.1\\nginx.exe -s stop</stopexecutable>\n</service>\n\n安裝\ncommand執行 nginx-server.exe install\n如果要刪除則是 nginx-server.exe uninstall\n\n除錯\nnginx.conf如果寫錯,導致服務無法啟動時,\n可到上面的<logpaht>位置查看錯誤訊息,\n照上面的範例,是C:\\nginx-1.26.1\\server-logs\\。\n以上是最簡單的用法。\nref.\n\ngithub文件\nWinSW",
"tags": [ "note","🖼"]
},
{
"title": "L7mp stunner監控",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/221. L7mp stunner監控/",
"content": "Why\n有人搞了一個webRTC for k8s用的即時媒體串流方案,\n然後我要來接監控了。\nL7mp\nSolution\n參考文件\n\n加 enableMetricsEndpoint 參數加到Dataplane裡面\n\n...\nspec:\nargs:\n- '-w'\n- '--udp-thread-num=16'\ncommand:\n- stunnerd\nenableMetricsEndpoint: true\nhostNetwork: false\nimage: docker.io/l7mp/stunnerd:0.18.0\nimagePullPolicy: Always\nreplicas: 1\nresources:\nlimits:\ncpu: 2\nmemory: 512Mi\nrequests:\ncpu: 500m\nmemory: 128Mi\nterminationGracePeriodSeconds: 3600\n\n弄個暫時的pod測試看看metrics有沒有資料\n\nkubectl run alpine-pod -n istio-system --image=alpine --restart=Never -- /bin/sleep 600\n\n先取得stunner的pod ip,再來就看有沒有資料了\ncurl http://192.168.1.25:8080/metrics\n\n有資料後再來下一步。\n這邊要注意一下,剛開後,stunner開頭的指標通通找不到,\n像是stunner_listener_connections_total、stunner_listener_bytes_total...等。\n我放了一陣子(一兩個小時?),就突然跑出來了,\n我不確定為什麼,等之後再測試看看。\n\nprometheus 設定 discover\n詳細說明,參考<a class=\"internal-link is-unresolved\" href=\"/404\">209. k8s中srs的各個pod metrics取得</a>\n\nscrape_configs:\n- job_name: 'ome'\nscrape_interval: 10s\nkubernetes_sd_configs:\n- role: pod\nrelabel_configs:\n- source_labels: [__meta_kubernetes_pod_name]\naction: keep\nregex: tcp-gateway.*\n- source_labels: [__meta_kubernetes_pod_container_port_name]\naction: replace\ntarget_label: portname\nreplacement: 8080\n\n建立Grafana\n\n{\n"annotations": {\n"list": [\n{\n"builtIn": 1,\n"datasource": {\n"type": "grafana",\n"uid": "-- Grafana --"\n},\n"enable": true,\n"hide": true,\n"iconColor": "rgba(0, 211, 255, 1)",\n"name": "Annotations & Alerts",\n"type": "dashboard"\n}\n]\n},\n"editable": true,\n"fiscalYearStartMonth": 0,\n"graphTooltip": 0,\n"id": 14,\n"links": [],\n"liveNow": false,\n"panels": [\n{\n"datasource": {\n"type": "prometheus",\n"uid": "PBFA97CFB590B2093"\n},\n"fieldConfig": {\n"defaults": {\n"color": {\n"mode": "palette-classic"\n},\n"custom": {\n"axisCenteredZero": false,\n"axisColorMode": "text",\n"axisLabel": "",\n"axisPlacement": "auto",\n"barAlignment": 0,\n"drawStyle": "line",\n"fillOpacity": 0,\n"gradientMode": "none",\n"hideFrom": {\n"legend": false,\n"tooltip": false,\n"viz": false\n},\n"lineInterpolation": "linear",\n"lineWidth": 1,\n"pointSize": 5,\n"scaleDistribution": {\n"type": "linear"\n},\n"showPoints": "auto",\n"spanNulls": false,\n"stacking": {\n"group": "A",\n"mode": "none"\n},\n"thresholdsStyle": {\n"mode": "off"\n}\n},\n"mappings": [],\n"thresholds": {\n"mode": "absolute",\n"steps": [\n{\n"color": "green",\n"value": null\n},\n{\n"color": "red",\n"value": 80\n}\n]\n}\n},\n"overrides": []\n},\n"gridPos": {\n"h": 8,\n"w": 12,\n"x": 0,\n"y": 0\n},\n"id": 3,\n"options": {\n"legend": {\n"calcs": [],\n"displayMode": "list",\n"placement": "bottom",\n"showLegend": true\n},\n"tooltip": {\n"mode": "single",\n"sort": "none"\n}\n},\n"targets": [\n{\n"datasource": {\n"type": "prometheus",\n"uid": "PBFA97CFB590B2093"\n},\n"editorMode": "code",\n"expr": "stunner_listener_connections",\n"legendFormat": "__auto",\n"range": true,\n"refId": "A"\n}\n],\n"title": "stunner_listener_connections",\n"type": "timeseries"\n},\n{\n"datasource": {\n"type": "prometheus",\n"uid": "PBFA97CFB590B2093"\n},\n"fieldConfig": {\n"defaults": {\n"color": {\n"mode": "palette-classic"\n},\n"custom": {\n"axisCenteredZero": false,\n"axisColorMode": "text",\n"axisLabel": "",\n"axisPlacement": "auto",\n"barAlignment": 0,\n"drawStyle": "line",\n"fillOpacity": 0,\n"gradientMode": "none",\n"hideFrom": {\n"legend": false,\n"tooltip": false,\n"viz": false\n},\n"lineInterpolation": "linear",\n"lineWidth": 1,\n"pointSize": 5,\n"scaleDistribution": {\n"type": "linear"\n},\n"showPoints": "auto",\n"spanNulls": false,\n"stacking": {\n"group": "A",\n"mode": "none"\n},\n"thresholdsStyle": {\n"mode": "off"\n}\n},\n"mappings": [],\n"thresholds": {\n"mode": "absolute",\n"steps": [\n{\n"color": "green",\n"value": null\n},\n{\n"color": "red",\n"value": 80\n}\n]\n}\n},\n"overrides": [\n{\n"matcher": {\n"id": "byName",\n"options": "{__name__=\\"stunner_listener_connections_total\\", instance=\\"192.168.58.102:8080\\", job=\\"ome\\", name=\\"stunner/tcp-gateway/tcp-listener\\", portname=\\"8080\\"}"\n},\n"properties": [\n{\n"id": "color",\n"value": {\n"fixedColor": "dark-yellow",\n"mode": "fixed"\n}\n}\n]\n}\n]\n},\n"gridPos": {\n"h": 8,\n"w": 12,\n"x": 12,\n"y": 0\n},\n"id": 1,\n"options": {\n"legend": {\n"calcs": [],\n"displayMode": "list",\n"placement": "bottom",\n"showLegend": true\n},\n"tooltip": {\n"mode": "single",\n"sort": "none"\n}\n},\n"targets": [\n{\n"datasource": {\n"type": "prometheus",\n"uid": "PBFA97CFB590B2093"\n},\n"editorMode": "code",\n"expr": "rate(stunner_listener_connections_total[1m])",\n"legendFormat": "__auto",\n"range": true,\n"refId": "A"\n}\n],\n"title": "listener_connections_total",\n"type": "timeseries"\n},\n{\n"datasource": {\n"type": "prometheus",\n"uid": "PBFA97CFB590B2093"\n},\n"description": "監聽器上發送或接收的字節總數。",\n"fieldConfig": {\n"defaults": {\n"color": {\n"mode": "palette-classic"\n},\n"custom": {\n"axisCenteredZero": false,\n"axisColorMode": "text",\n"axisLabel": "",\n"axisPlacement": "auto",\n"barAlignment": 0,\n"drawStyle": "line",\n"fillOpacity": 0,\n"gradientMode": "none",\n"hideFrom": {\n"legend": false,\n"tooltip": false,\n"viz": false\n},\n"lineInterpolation": "linear",\n"lineWidth": 1,\n"pointSize": 5,\n"scaleDistribution": {\n"type": "linear"\n},\n"showPoints": "auto",\n"spanNulls": false,\n"stacking": {\n"group": "A",\n"mode": "none"\n},\n"thresholdsStyle": {\n"mode": "off"\n}\n},\n"mappings": [],\n"thresholds": {\n"mode": "absolute",\n"steps": [\n{\n"color": "green",\n"value": null\n},\n{\n"color": "red",\n"value": 80\n}\n]\n},\n"unit": "bytes"\n},\n"overrides": [\n{\n"matcher": {\n"id": "byName",\n"options": "{__name__=\\"stunner_listener_bytes_total\\", direction=\\"rx\\", instance=\\"192.168.58.102:8080\\", job=\\"ome\\", name=\\"stunner/tcp-gateway/tcp-listener\\", portname=\\"8080\\"}"\n},\n"properties": [\n{\n"id": "color",\n"value": {\n"fixedColor": "purple",\n"mode": "fixed"\n}\n}\n]\n},\n{\n"matcher": {\n"id": "byName",\n"options": "rx"\n},\n"properties": [\n{\n"id": "color",\n"value": {\n"fixedColor": "dark-red",\n"mode": "fixed"\n}\n}\n]\n}\n]\n},\n"gridPos": {\n"h": 9,\n"w": 24,\n"x": 0,\n"y": 8\n},\n"id": 2,\n"options": {\n"legend": {\n"calcs": [],\n"displayMode": "list",\n"placement": "bottom",\n"showLegend": true\n},\n"tooltip": {\n"mode": "single",\n"sort": "none"\n}\n},\n"targets": [\n{\n"datasource": {\n"type": "prometheus",\n"uid": "PBFA97CFB590B2093"\n},\n"editorMode": "code",\n"expr": "sum(irate(stunner_listener_bytes_total[1m])) by (direction)",\n"hide": false,\n"legendFormat": "__auto",\n"range": true,\n"refId": "A"\n}\n],\n"title": "stunner_listener_bytes_total",\n"type": "timeseries"\n},\n{\n"datasource": {\n"type": "prometheus",\n"uid": "PBFA97CFB590B2093"\n},\n"description": "發送到後端或從後端接收的字節總數。",\n"fieldConfig": {\n"defaults": {\n"color": {\n"mode": "palette-classic"\n},\n"custom": {\n"axisCenteredZero": false,\n"axisColorMode": "text",\n"axisLabel": "",\n"axisPlacement": "auto",\n"barAlignment": 0,\n"drawStyle": "line",\n"fillOpacity": 0,\n"gradientMode": "none",\n"hideFrom": {\n"legend": false,\n"tooltip": false,\n"viz": false\n},\n"lineInterpolation": "linear",\n"lineWidth": 1,\n"pointSize": 5,\n"scaleDistribution": {\n"type": "linear"\n},\n"showPoints": "auto",\n"spanNulls": false,\n"stacking": {\n"group": "A",\n"mode": "none"\n},\n"thresholdsStyle": {\n"mode": "off"\n}\n},\n"mappings": [],\n"thresholds": {\n"mode": "absolute",\n"steps": [\n{\n"color": "green",\n"value": null\n},\n{\n"color": "red",\n"value": 80\n}\n]\n},\n"unit": "bytes"\n},\n"overrides": [\n{\n"matcher": {\n"id": "byName",\n"options": "rx"\n},\n"properties": [\n{\n"id": "color",\n"value": {\n"fixedColor": "dark-red",\n"mode": "fixed"\n}\n}\n]\n}\n]\n},\n"gridPos": {\n"h": 8,\n"w": 24,\n"x": 0,\n"y": 17\n},\n"id": 4,\n"options": {\n"legend": {\n"calcs": [],\n"displayMode": "list",\n"placement": "bottom",\n"showLegend": true\n},\n"tooltip": {\n"mode": "single",\n"sort": "none"\n}\n},\n"targets": [\n{\n"datasource": {\n"type": "prometheus",\n"uid": "PBFA97CFB590B2093"\n},\n"editorMode": "code",\n"expr": "sum(irate(stunner_cluster_bytes_total[1m])) by (direction)",\n"legendFormat": "__auto",\n"range": true,\n"refId": "A"\n}\n],\n"title": "stunner_cluster_bytes_total",\n"type": "timeseries"\n}\n],\n"refresh": false,\n"schemaVersion": 38,\n"style": "dark",\n"tags": [],\n"templating": {\n"list": []\n},\n"time": {\n"from": "2024-06-21T01:25:08.227Z",\n"to": "2024-06-21T04:12:21.776Z"\n},\n"timepicker": {},\n"timezone": "",\n"title": "stunner",\n"uid": "cbd52e5c-df69-45e6-b2ba-84433a4cd6ec",\n"version": 5,\n"weekStart": ""\n}\n\nref.\n\nPromQL聚合操作\nstunner Github\nstunner Document",
"tags": [ "note","👁"]
},
{
"title": "222. elastic 整批刪除indics",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/222. elastic 整批刪除indics/",
"content": "Why\n不知道為什麼,ILM沒有動作,沒將舊的indics刪除。\n導致elastic直接報錯。\nthis action would add [2] shards, but this cluster currently has [1000]/[1000] maximum normal shards open;\n\n緊急處理先將node的 shared開成1500\nPUT /_cluster/settings\n{\n"persistent": {\n"cluster.max_shards_per_node": 1500\n}\n}\n\nSolution\n再來是檢查為什麼有那麼多shared沒刪除,\n但一整批,一個一個刪除會瘋掉。\n用wildcard卻會發生錯誤。\nDELETE /qa-backend-2024.02.*\n\n錯誤\n{\n"error": {\n"root_cause": [\n{\n"type": "illegal_argument_exception",\n"reason": "Wildcard expressions or all indices are not allowed"\n}\n],\n"type": "illegal_argument_exception",\n"reason": "Wildcard expressions or all indices are not allowed"\n},\n"status": 400\n}\n\n不想寫shellscript,一個一個撈index去刪除,\n於是先開放wildcard吧。\nPUT _cluster/settings\n{\n"transient": {\n"action.destructive_requires_name": false // allow wildcards\n}\n}\n\n再來執行\nDELETE /qa-backend-2024.02.*\n\n結束。\nref. elasticsearch, how to delete multiple indexes with wildcard",
"tags": [ "note","🗒"]
},
{
"title": "223. 檢查TCP or UDP是否有通",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/223. 檢查TCP or UDP是否有通/",
"content": "Why\n搞SRS的時候,\n要測試webRTC的功能,\n開了UDP但不知道到底有沒有通。\nSolution\nUDP\nnc -u YOUR_PUBLIC_IP 30000\n\n通的話,應該是會發現你可以在底下打字,然後不會結束。\n\n如果有另一台伺服器可以玩的話,\n可以做server\nnc -ulvp 30000\n\nref.\n\nUDP連接埠連通性檢查\n\nNetcat\n安裝方式\nMac\nbrew install netcat\n\nLinux\napt install netcat\n\nCentOS\nyum install nc\n\nAlpine Linux\napk add netcat-openbsd\n\nDocker\napt install netcat-traditional\n\n檢查特定的port 是否開啟\n\nnc -v 192.168.0.175 5000\n\n掃描對方機器的port\n\nnc -vnz -w 1 192.168.233.208 1-1000 2000-3000\n\n再來還有送出http請求、寄信、簡易網頁伺服器...\nref. Netcat(Linux nc 指令)網路管理者工具實用範例",
"tags": [ "note","🐧"]
},
{
"title": "224. GKE的節點上限",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/224. GKE的節點上限採坑記/",
"content": "WHY\n最近同事在搞壓力測試,\n然後他就突然跟我說,欸,我的pod起不來。\n看了一下,發現ip 應該是還夠的啊,怎麼會噴 scale.up.error.ip.space.exhausted\nHow\n因為GKE會根據每個node上,所設定的最大pod數量,\n以及pod的CIDR範圍,來計算你這個cluster可以開到幾個node。\nref.組態每個節點的 Pod 數上限\n文章的最後有寫到,\n\n如果您將默認最大 Pod 數設定為 110 並將 Pod 的次要 IP 地址範圍設定為 /21,Kubernetes 會為叢集中的節點分配 /24 CIDR 範圍。這允許叢集中最多有2(24−21) = 23 = 8 個節點。\n\n我的最大pod數為110,次要IP範圍也是/21,\n所以node開到8個,就達到上限了。\n\n然後,為什麼kubernetes替叢集的節點分配的範圍是 /24。\n要往下看表格。\n\n每個節點的最大 Pod 數量\n每個節點的 CIDR 範圍\nIP 地址數量\n\n8\n/28\n16\n\n9 - 16\n/27\n32\n\n17 - 32\n/26\n64\n\n33 - 64\n/25\n128\n\n65 - 128\n/24\n256\n\n129 - 256\n/23\n512\n\n假設最大pod數是64,那最大節點數則是 2(25−21) = 24 = 16\nSolution\n後來才知道原因,當時有其他案子在手中,沒空查原因。\n但當下直接加大機器規格,減少node的數量。\n或者直接在vpc上面增加新的pod range,應該也是可以的。",
"tags": [ "note","⎈"]
},
{
"title": "225. Debian安裝後設定",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/225. Debian安裝後設定/",
"content": "WHY\n被要求寫個SOP安裝服務的手冊,\n從作業系統開始。\nNote\n\n*** is not in the sudoers file. This incident will be reported.”\n修改sudoers檔案\n\nsu root\nchmod 777 /etc/sudoers\nvi /etc/sudoers\n\n# 在 root ALL=(ALL:ALL) ALL 下面加上\n <user> ALL=(ALL)ALL\n\nchmod 440 /etc/sudoers\n\n關閉休眠模式\n\nsudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target\n\n執行完後,需重開機\n\n關閉安裝來源\n最快的方法是直接從桌面模式關掉。\n程式介面搜尋 update,找到software & update ,\n進去後切到Other software的頁籤,將選項拿掉。\n\n安裝deb\n\napt install ./anydesk_6.3.2-1_amd64.deb",
"tags": [ "note","🐧"]
},
{
"title": "228. Cloudsql PITR還原",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/228. Cloudsql PITR還原/",
"content": "Why\n為了之後的服務,要來驗證一下有哪些的還原方式。\nSolution\n目前看到的是PITR,看說明文件,可以還原到秒的時間。\n開啓方式可以參考官方文件。\n但有一點文件沒提到,\n你只能選取五分鐘前的時間。\n例如\n現在時間是 15:30 ,你還原的時間點,只能選擇15:25以前。\n當然還有秒數的問題,\n如果選擇的時間是 15:25~15:30的話,會出現這個錯誤。\n\n如果要確認可以退的時間點,\n可以執行下面指令。\ngcloud sql instances get-latest-recovery-time <instanceName>\n\n會顯示\nkind: sql#getLatestRecoveryTime\nlatestRecoveryTime: '2024-08-15T06:48:48Z'\n\n下面就是你能夠還原的最早時間。\nref. gcloud sql instances get-latest-recovery-time",
"tags": [ "note","🗄"]
},
{
"title": "231. GKE node cpu limit 計算",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/231. GKE node cpu limit 計算/",
"content": "WHY\n線上服務的pod,CPU飆高,\n導致所屬的node,CPU也跟著衝高,合理。\n但同仁問了一句那個limit是啥。\nNote\n\n那條紅色的線,\n原本以為那是某個node的cpu最大值,\n但我這個node的最大cpu只有4而已。\n所以排除了CPU的上限,檢視 Metrics Explorer\n指標上面寫Limit cores\n再根據 GKE system metrics,得知這個metrics是指 CPU cores limit of the container。\n但我又懶得一個一個查這個node有多少limit。\n於是\nkubectl get pods --all-namespaces -o wide --field-selector spec.nodeName=<node name> -o custom-columns=:metadata.name,:metadata.namespace --no-headers | while read -r name ns; do\necho "$name and $ns"\nkubectl get pod $name -n $ns -o jsonpath='{.spec.containers[*].resources.limits.cpu}' | xargs -n1 echo " CPU Limit: "\ndone\n\n本來是用for,但在切割name 與 namespace出了點問題。\n最後才改用while。\n這邊將值總和計算出來後是6.2,數值一樣,謎底解開了。\nref. Command line tool (kubectl)",
"tags": [ "note","⎈"]
},
{
"title": "232. GCE Observability 安裝agent失敗",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/232. GCE Observability 安裝agent失敗/",
"content": "WHY\n利用terraform裝好GCE後,\n要來裝一下監控,才能把資料丟去grafana裏面統一管。\n結果一直卡在pending。\nSolution\n\n以爲只是單純安裝失敗,先強制關閉更新後再看看。\n# 關閉安裝\nsudo bash add-monitoring-agent-repo.sh --remove-repo\n\n重新啓用後還會卡在pending,\n還是只能查 log ,到 /var/log/google-cloud-ops-agent 底下,\n查看health-checks.log 。發現原因出現permission denied\n後來才發現原因,\n我用terraform建立GCE時,沒有設定的service account。\n導致他要安裝時會卡在那邊。\n所以,只要把機器停機,\n再到 API and identity management 選擇 Service account即可。\n\nref. 排查 Ops Agent 安裝和啟動問題",
"tags": [ "note","☁️"]
},
{
"title": "233. 不同區域 GCE與GKE LB連線",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/233. 不同區域 GCE與GKE LB連線/",
"content": "Why\n突然來了個要求,要從美東的GCE 連到臺灣的GKE。\nGKE的機器,我建了內部 LB 。\n但只有同一個區域的GCE機器能夠連。\n連去GCE 直接ping各個區域的機器,都正常。\n但連GKE的LB 就不通。\nSolution\n諮詢了顧問公司,\n他們的回答是VPC內部的子網路都是互通的(沒錯,測試有通),\n但要連到GKE的internal LB,\nLB要開啓 Global access\n\nref. 客戶端訪問\nTroubleshoot\n這幾天發現個問題,\n手動更改Global access後,會自動變成Disable。\n通報給Google了,後續看狀況。\n但有建議說直接在server上面加 annotations\napiVersion: v1\nkind: Service\nmetadata:\nannotations:\n# add globle access\nnetworking.gke.io/internal-load-balancer-allow-global-access: "true"\nnetworking.gke.io/load-balancer-type: "Internal"\nname: srs-source-internal\nnamespace: srs-prod\nspec:\ntype: LoadBalancer\nselector:\napp: srs-source\nports:\n- protocol: TCP\nport: 1935\ntargetPort: 1935\nname: rtmp\n\nref. Global access",
"tags": [ "note","☁️"]
},
{
"title": "234. Debian新增軟體源",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/234. Debian新增軟體源/",
"content": "Cause\n客戶那邊要新增一臺機器,\n連過去裝時,才發現他沒有software repositories\nSolution\nOS: Debian 10\n編輯 /etc/apt/sources.list ,\n新增\ndeb http://ftp.debian.org/debian stable main contrib non-free\n\n然後開啓terminal,執行下面指令,收工\napt update\n\nref. DebianRepository",
"tags": [ "note","🐧"]
},
{
"title": "235. Grafana Alert Template",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/235. Grafana Alert Template/",
"content": "Why\n新服務要上線了,\n要趕緊把 Observability做一做,\n之前的版本都會有一長串資訊,\n看了就很煩,不能很直觀的知道是哪邊出問題。\n訊息又都要一個一個打,\n所以,我能不能弄成一個範本,減少我人工的作業?\nSolution\n\n注意,因有特殊符號,導致編譯出問題。\n故將裡面的所有{ } 改為全形,請自行改為半形\n故將裡面的所有{ } 改為全形,請自行改為半形\n故將裡面的所有{ } 改為全形,請自行改為半形\n\n很重要,說三次\n原始的範本,通常長成這樣。\n有很多資訊,但有些是用不到的。\n[FIRING:1] (cpu-dealer GKE Cluster normal backend)\n\nFiring\n\nValue: B=2.632\nLabels:\n- alertname = cpu-abc\n- grafana_folder = GKE Cluster\n- level = normal\n- service-type = backend\nAnnotations:\n- summary = 環境:Prod\n機器名稱:dealer\n告警訊息:CPU使用量1core\nSource: http://localhost:3000/alerting/grafana/uRU7sCEnz/view?orgId=1\nSilence: http://localhost:3000/alerting/silence/new?alertmanager=grafana&matcher=alertname%3Dcpu-dealer&matcher=grafana_folder%3DGKE+Cluster&matcher=level%3Dnormal&matcher=service-type%3Dbackend\nDashboard: http://localhost:3000/d/2-jy90-nk?orgId=1\nPanel: http://localhost:3000/d/2-jy90-nk?orgId=1&viewPanel=13\n\n最後的成果\n[FIRING:1] sftp-qa Disk Space alarm-GCE (normal sftp-qa value_percent_used_mean_aggregate)\n\nAnnotations:\n- summary: 環境:alarm-GCE\n機器名稱:sftp-qa\n告警項目:sftp-qa Disk Space\n告警訊息:硬碟空間目前 46.22% ,已達上限 70%\nDashboard URL:\n\n[View Dashboard](http://<ip>/grafana/d/f649857c-4763-442f-9919-b41c3832d5b8?orgId=1)\n\nStep 1. 確認版本\n首先確認Grafana的版本,目前我使用的是Grafana v11.2.0。\n版本不一樣,指令可能會不一樣,需要再去查文件。\nStep 2. 設定Notification Template\n\n開啟 Home > Alerting > Cotact points\n切換到分頁 Notification Templates ,選擇 Add Notification Template\n\n在左上的Template框框,輸入下面程式碼。\n如果指令沒錯,可以在右邊的preview看到結果。\n{{ define "alert_message" }}\n{{ range .Alerts }}\n{{ if gt (len .Annotations) 0 }}\nAnnotations:\n{{ range $key, $value := .Annotations }}\n- **{{ $key }}**:\n{{ $value }}\n{{ end }}\n{{ else }}\nNo Annotations found.\n{{ end }}\n\nDashboard URL:\n[View Dashboard]({{ .DashboardURL }})\n{{ end }}\n{{ end }}\n\n這程式我是叫GPT寫的,再稍微小改一下。\n如果想自己開發,請參考Configure notification messages\np.s. 注意版本,版本不一樣從網頁的版本號調整\nStep 3. 綁定notification policy\n\n回到Contact Points,\n選擇你的notification policy\n\n選擇剛剛新增的Template\n可以按一下Test驗證一下有沒有通。\nStep 4. 設定 Alert Rules\n基本的設定就參考Alert rules\n在Summary則是輸入\n環境:{{ index $labels "grafana_folder" }}\n機器名稱:{{ index $labels "metadata.label.system.name" }}\n告警項目:{{ index $labels "alertname" }}\n告警訊息:硬碟空間目前 {{ humanize (index $values "B").Value }}% ,已達閥值 70%\n\nindex是用來顯示標籤中的內容,\n可以更方便得到你想要的數值。\n可以在測試時用 {{ $labels }} 看有哪些標籤可用。\np.s 版本不一樣,取值的方式也不一樣。\n同樣可以使用的是 {{ $value }} ,這邊注意只有value沒有s。\n但在使用index時,需要加上 s。\nref. Notification.Templates\n\nhumanize 是比較人性化的format函數。\nhumanize 會將多餘的小數點位數移除或改為比較易讀的方式。\nhumanizePercentage 將小數點轉為百分比\nhumanizeDuration 將時間轉為可讀的時間\n更多可參考下面連結,裡面也有其他function的用法。\nref. humanize\n\nTroubleshooting\n當有一個變數寫錯時,發送告警時,全部的變數都不會顯示。\n會變成下面的情況。\n- summary:\n{{ $value }}\n環境:{{ index $labels "grafana_folder" }}\n機器名稱:{{ (index $values "B").persistentvolumeclaim }}\n告警項目:{{ index $labels "alertname" }}\n告警訊息:硬碟空間目前 {{ humanizePercentage (index $values "B").Value }} ,已達閥值 70%\n\n此時就看一下是不是那邊要加空格沒空格,\n或是指定的values的欄位有錯誤。\n像上面的錯誤,機器名稱的部分應該要改成這樣。\n機器名稱:{{ (index $values "B").Labels.persistentvolumeclaim }}",
"tags": [ "note","👁"]
},
{
"title": "236. Telegram傳送檔案",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/236. Telegram傳送檔案/",
"content": "Why\n突然想要懶一下,\n定時送個檔案到TG上面,\n怎麼傳文字我很清楚,但檔案還真的沒想法。\n只打算弄個sh,不想寫code。\nSolution\n問了GPT很簡單,\n就一行。\n987654321 是 chat_id\nbot123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11是TG的機器人token\nbackup.zip是檔案\nsamplefile是附註\ncurl -F chat_id=987654321 \\\n-F document=@/path/to/backup.zip \\\n-F caption=samplefile \\\nhttps://api.telegram.org/bot123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11/sendDocument\n\nref. sendDocument\n小補充,想在caption上面標注日期,方便尋找。\ntoday=$(date +%F)\ncurl -F chat_id=987654321 \\\n-F document=@/path/to/backup.zip \\\n-F caption=samplefile-${today} \\\nhttps://api.telegram.org/bot123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11/sendDocument",
"tags": [ "note","💻"]
},
{
"title": "237. GCP IAM綁GKE的RBAC",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/237. GCP IAM綁GKE的RBAC/",
"content": "WHY\n要弄個小程式定時撈secret的資料出來,\n但叢集是舊的沒有開啟workload Identity,\n也只能掛IAM的service account了。\n只給予Kubernetes Engine Viewer的權限,\n但要撈secret時,會通知缺乏container.secrets.get的權限。\nSolution\n\n檢查Kubernetes Engine Viewer有哪些權限\n\n網頁查詢\n另一種透過指令的方式,參考上圖中的role將值帶入到下面指令。\ngcloud iam roles describe roles/container.viewer\n\n(我很想吐槽,我怎麼知道這個名稱要用哪個role去查啊,還不是要去網頁看)\nref. 查看 IAM 角色授予的權限\n查完的結果是真的缺乏 container.secrets.get的權限。\n那現在的問題是,要怎麼加權限?\n\n釐清認證方式\nGoogle 文件說明\n您可以使用 IAM 和 Kubernetes RBAC 來控制對 GKE 叢集的存取權:\n\nIAM 並非特定於 Kubernetes;它為多種 Google Cloud 產品提供身份管理,並且主要在 Google Cloud 項目級層運行。\n\nKubernetes RBAC 是 Kubernetes 的核心組成部分,可讓您針對叢集內的任何對象或對象類型建立和授予角色(一組權限)。\n\n為了授權操作,GKE 首先會檢查是否存在 RBAC 政策。如果不存在 RBAC 政策,GKE 會檢查 IAM 權限。\n\n在 GKE 中,IAM 和 Kubernetes RBAC 整合在一起,您可以通過任一工具向使用者授權,使其有足夠的權限執行操作。這對於 GKE 叢集的引導過程至關重要,因為默認情況下,Google Cloud 使用者不具有任何 Kubernetes RBAC RoleBindings。\nref. 使用基於角色的存取權控制向叢集中的操作授權\n所以說預設的角色權限就是那些,要針對角色加權限的話只能自己新增了。\n\n新增RBAC權限\n\nClusterRoleBinding 使用 kind: user,綁定IAM的帳號。\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\nname: secret-reader\nrules:\n- apiGroups: [""]\nresources: ["secrets"]\nverbs: ["get", "list", "watch"]\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\nname: secret-reader-binding\nsubjects:\n- kind: User # 或者 ServiceAccount 根據具體的需求\nname: get-api@project.iam.gserviceaccount.com # 替換成具體的使用者或服務帳號名稱\napiGroup: rbac.authorization.k8s.io\nroleRef:\nkind: ClusterRole\nname: secret-reader\napiGroup: rbac.authorization.k8s.io\n\n驗證方式\n\n綁完後,可使用指令看看能不能正常讀取。\nkc auth can-i get secret iplc-test-com-tls \\\n-o=jsonpath='{.data.tls\\.crt}' \\\n--as get-api@project.iam.gserviceaccount.com\n\n可讀取會顯示 Yes,否則就是 No\nref. Checking API access",
"tags": [ "note","⎈"]
},
{
"title": "238. Steam Deck安裝Cheat Engine",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/238. Steam Deck安裝Cheat Engine/",
"content": "WHY\n有些遊戲用簡易版的搜尋軟體 <a class=\"internal-link\" data-note-icon=\"\" href=\"/206. steamDeck 的 Cheat Engine替代品/\">206. steamDeck 的 Cheat Engine替代品</a>,\n就是搜不到,\n想說是不是還是該用CE來試試看了。\nSolution\n主要是參考這個影片Cheat Tables (.CT) for Steam Deck SteamOS Cheat Engine Guide Setup Tutorial\n主要幾個步驟,備忘一下。\n\n下載軟體\n\n到桌面模式下,安裝 ProtonUP-Qt 以及 Protontricks\n如果沒有外接滑鼠的話,\n右邊的觸控版是滑鼠, RT(R2) 是滑鼠左鍵, LT(L2)是滑鼠右鍵\n\n新增SteamTinkerLaunch\n\n開啟ProtonUP-Qt\n\nAdd version\n\n在Compatibility tool選擇 SteamTinkerLaunch\n然後 install\n完成後重新啟動Steam\n\n新增CE到收藏庫\n\n桌面模式下,開啟Steam。\n到『收藏庫』,左下方有一個新增遊戲的按鈕,\n選擇 『新增非Steam遊戲』。\n找到你剛剛下載的CheatEngine.exe。\n\n安裝CE\n\n新增完成後,會出現下圖,\n\n選擇右邊的內容,\n開啟相容性。\n『強制使用特定Steam Play 相容性工具』打勾。\n選擇『Proton Experimental』\n設定完後,啟動。\n會看到安裝畫面,就安裝吧。\n注意,中途會問你要不要裝其他軟體,選擇Skip All\n\n複製資料夾\n找到CE的資料夾,記得先開啟『顯示隱藏檔』\n\n/home/.steam/steam/steamapps/compatdata\n這邊有兩種方式,\n一種是找到建立日期是剛剛的。\n另一種是打開Protontricks 看CheatEngine的編號是哪一個。\n像我的是3262966842 就再進去\n3262966842/pfx/drive_c/Program FIles\n完整路徑會像這樣\n/home/.steam/steam/steamapps/compatdata/3262966842/pfx/drive_c/Program files\n將Cheat Engine 7.5資料夾整個複製,\n貼到你想要修改的遊戲資料夾上面。\n假設我要修Brotato,編號是 1942280(開Protontricks查)。\n就參考上面的路徑\n/home/.steam/steam/steamapps/compatdata/1942280/pfx/drive_c/Program files\n到這邊將Cheat Engine 7.5資料夾 貼上。\n\n設定Brotato用SteamTinkerLaunch開啟\n\n桌面模式\n內容->相容性->強制使用特定Steam Play相容性工具->Steam Tinker Launch\n\n設定Game Menu\n\n桌面模式\n照上面的設定完後,執行遊戲,會跳出一個視窗,\n選擇下方的Main Menu-> Game Menu\nUse custom command 打勾\nCustom command 選擇剛剛複製過來資料夾裡面的CheatEngine.exe\nFork custom command 打勾\n\n啟用開發者模式\n\n可以回到遊戲模式,\n先按下Steam按鈕,系統-> 啟用開發者模式。\n\n開始修改\n\n執行你的遊戲,此時按下 Steam 按鈕,\n會看到同時有兩個檔案在執行,\n一個是你玩得遊戲,\n另一個則是CheatEngine。\n需要注意的是,如果你有選擇開啟其他視窗的話,\n需要從Steam按鈕去選擇你開啟的其他視窗。\nNote\n\n抓圖的話使用內建的Spectacle\n複製圖片的話,使用ssh\n\nSteamDeck\n如果沒設過密碼,需使用passwd先行設定\nsystemctl enable sshd # 啟用sshd\nsystemctl restart sshd # 重新啟動sshd\nsystemctl status sshd # 查詢狀態\n\nip -4 addr # 查詢ip位置\n\nPC\nscp -r deck@192.168.1.2:/home/deck/Pictures/ .\n\nref.\n\nCheat Tables (.CT) for Steam Deck SteamOS Cheat Engine Guide Setup Tutorial\nFearLess Cheat Engine 下載CT檔案的網站",
"tags": [ "note"]
},
{
"title": "239.Cloudflare白名單及擷取國別設定",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/239. Cloudflare白名單及擷取國別設定/",
"content": "WHY\n每當要再設定一次時,\n都要找一陣子,才會發現在哪裡,\n於是才發現,我沒筆記啊...\nNote\n白名單設定\n網路安全->WAF->自訂規則\n\n新增規則\n\n這邊可選擇要篩選哪個欄位。\n\n再來要允許還是阻擋。\n最後記得『佈署』。\n國別header\n網路-> IP 地理位置\n\n之後就能從header裡面取得這個使用者是哪個國家。\nref. Configuring IP geolocation",
"tags": [ "note","🌐"]
},
{
"title": "240. git log 除錯指令",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/240. git log 除錯指令/",
"content": "WHY\n前陣子,RD同仁找來,說為什麼這樣的CI不會過。\n查了一連串的LOG,發現是fast-forward的問題。\n過程中用了一堆git 指令...\n紀錄吧\nNote\n\n只顯示merge的log\n\ngit log --merges\n\n顯示全部Log\n\ngit log\n\n顯示單一提交的詳細訊息\n\ngit show <commit>\n\n查詢某個特定提交的tag\n\ngit tag --points-at <commit>\n\n列出所有tag及對應的commit值\n\ngit show-ref --tags\n\n以圖形化顯示log\n\ngit log --graph\n\n取得git的tag資料\n\n# 取開頭第一個\ngit tag --points-at <commit> | head -1\n# 取結尾第一個\ngit tag --points-at <commit> | tail -1\n\nLog Merge欄位的意思\n假設顯示的資訊如下\n\ncommit a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t\nMerge: 1a2b3c4 5d6e7f8\nAuthor: John Doe <john.doe@example.com>\nDate: Tue Sep 11 14:30:00 2024 +0800\n\nMerge branch 'feature-branch' into 'develop'\n\ndevelop的 commit值是 1a2b3c4\nfeature-branch的commit值是5d6e7f8\n這兩個是 non-fast-forward合併,因為看得到Parents commit。\n如果是Fast-Forward合併,只會顯示單個提交,不會有Merge標記。\n\npull時不使用rebase,而是使用merge\n\ngit pull --no-rebase",
"tags": [ "note","💻"]
},
{
"title": "241. MSSQL紀錄log,使用QUERY_STORE",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/241. MSSQL紀錄log,使用QUERY_STORE/",
"content": "WHY\n線上出了問題,\n但沒有作Tracer,所以就只能先追Slow Query看看了。\nNote\n本來以為只能寫Trigger,當觸發動作時,記錄當下的Query\n後來問了一下GPT,才發現原來現在的SQL server有一個查詢存放區,\n是專門拿來放SQL指令。\n\n查詢存放區會收集 DML 陳述式,例如 SELECT、INSERT、UPDATE、DELETE、MERGE 和 BULK INSERT。\n\n但這也不是很新的東西,從SQL 2016就有了。\n但從SQL 2022開始,這個設定就會預設打開。\n開啟方式\nALTER DATABASE <database_name>\nSET QUERY_STORE = ON (OPERATION_MODE = READ_WRITE);\n\n然後,就可以查看看所有執行過的SQL了。\nSELECT Txt.query_text_id, Txt.query_sql_text, Pln.plan_id, Qry.*, RtSt.*\nFROM sys.query_store_plan AS Pln\nINNER JOIN sys.query_store_query AS Qry\nON Pln.query_id = Qry.query_id\nINNER JOIN sys.query_store_query_text AS Txt\nON Qry.query_text_id = Txt.query_text_id\nINNER JOIN sys.query_store_runtime_stats RtSt\nON Pln.plan_id = RtSt.plan_id;\n\nsys.query_store_query欄位說明\nsys.query_store_runtime_stats欄位說明\n\n計劃存放區中可為查詢儲存的不重複計劃數目,受限於 max_plans_per_query 組態選項。\n\n查詢 max_plans_per_query的值及其他參數\nselect *\nfrom sys.database_query_store_options\n\nsys.database_query_store_options欄位說明\n\n雖然說他的最大值預設是200,\n但我實際看起來,我的plan_id已經超過200了還在存。\n\nref.\n\n使用查詢存放區監視效能\n管理查詢存放區的最佳做法",
"tags": [ "note","🗄"]
},
{
"title": "242. .Net core 8 使用apt install 權限不足",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/242. .Net core 8 使用apt install 權限不足/",
"content": "WHY\n今天早上又被人抓住說要開新服務,\n看這個架構要怎麼調。\n測試時來到Docker build,然後就掛了。\nSOLUTION\n在使用apt update的時候,出現了Permission denied\n在Dockerfile的上層加上\nUSER root\n\n就能執行了,\n但不知道為什麼,我沒辦法復現錯誤狀況,\n使用 docker system prune -a 全部清除了也是一樣。\n但當時確實有碰到這個問題。\n附上完整Dockerfile\nFROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base\n\nUSER root\nWORKDIR /app\n\nRUN apt update && apt install -y curl python3\nRUN curl -O https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-443.0.0-linux-x86_64.tar.gz \\\n&& tar -xf google-cloud-cli-443.0.0-linux-x86_64.tar.gz && ./google-cloud-sdk/install.sh --command-completion=true --path-update=true --quiet\nCOPY gcs-download.json .\nRUN /app/google-cloud-sdk/bin/gcloud auth activate-service-account abc@abc.com --key-file=gcs-download.json\nEXPOSE 8080\nEXPOSE 8081\n\n其實應該用workload Identity會比較好,但這程式預計要放的位置,\n要改的話變動太大。\nref. # New non-root 'app' user in Linux images",
"tags": [ "note","🐳"]
},
{
"title": "243. GCP 全域負載平衡器進階路由設定",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/243. GCP 全域負載平衡器進階路由設定/",
"content": "WHY\n新的服務,就順便改一下新的負載平衡器去掛載bucket吧。\n然後滿滿的坑,GCP的說明範例不知道在寫啥。\nSolution\n\n以前都是選擇傳統版,\n設定也頗簡單。\n\n不要看他新版上面寫建議,\n就真的用,至少先弄個傳統的把你要的東西設定好。\n\n上面的設定是將 domain/files/123.jpg,轉到 bucket底下的123.jpg\n這邊提供一個最快的解法。\n假設已經在傳統的負載平衡器上面已經建立好了規則,名稱為 abc-qa。\n使用指令查詢\ngcloud compute url-maps describe abc-qa\n\n將 pathMatchers底下的東西抄出來,改一下,\n\n貼到『進階型主機與路徑規則』上面就好了(不要太相信程式碼指南)。\n真的要參考,請看底下連結。\n\nservice的部分,利用指令查詢你的服務或bucket。\ngcloud compute backend-buckets list --uri\nor\ngcloud compute backend-services list --uri\n\n這指令會得到類似下面的網址。\nhttps://www.googleapis.com/compute/v1/projects/<project_name>/global/backendBuckets/<bucket_name>\n\nservice 可以為 projects/<project_name>/global/backendBuckets/<bucket_name>\n或是\nglobal/backendBuckets/<bucket_name>\nTroubleshooting\n\n出現錯誤 Operation type [update] failed with message "Invalid resource: URL_MAP/513614964978.game-result-video-qa"\n\n錯誤的設定\ndefaultService: global/backendBuckets/abc-qa\nname: matcher1\nrouteRules:\n- matchRules:\n- prefixMatch: /videos\npriority: 100\nrouteAction:\nweightedBackendServices:\n- backendService: global/backendBuckets/abc-qa\nweight: 100\n\n問顧問,說不要用 weightedBackendServices 直接指定service。\ndefaultService: global/backendBuckets/abc-qa\nname: matcher1\nrouteRules:\n- matchRules:\n- prefixMatch: /videos\npriority: 100\nservice: global/backendBuckets/abc-qa\n\nref. GCP - HTTP(S) Load Balancer L7 Backend Bucket Issue\n\n程式碼指南的 $[DEFAULT_SERVICE_URL]是什麼\n\n使用指令查詢\ngcloud compute backend-buckets list --uri\nor\ngcloud compute backend-services list --uri\n\nref. What does "$[DEFAULT_SERVICE_URL]" refer to when setting Google Load Balancer towards a GCP Storage Bucket?\nConclusion\n沒事不要用新版的應用程式負載平衡器。\n官方文件要看的話,請看下面兩個連結。\n\nAdvanced host, path, and route rule\nURL maps overview",
"tags": [ "note","🌐"]
},
{
"title": "244. 在GCE使用filebeat傳到GKE的ECK",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/244. 在GCE使用filebeat傳到GKE的ECK/",
"content": "WHY\nRD說他要搞一台自動錄影的服務,\n本來以為只有一個服務,那就掛在GKE上就好了。\n但是,他有兩個服務A跟B,兩邊的資料要互通。\n真要用GKE硬作也是可以,但如果這個服務本身效能就吃很大,\n那用k8s也是要多開一台機器,那不如就用GCE吧。\n然後,問題就來了,LOG咧!?\nLog出問題時要查,最好也是傳去共同的ECK上面,但ECK在GKE上面。\nSolution\n抓取log的流程也跟一般的filebeat差不多。\nfilebeat會從主機上的 /var/lib/docker/containers/*/*.log 抓取。\n這邊文字檔的log是docker logs的資料,也就是程式的stdout。\n官方簡單說明\nDocker-compose.yaml\n我是用docker compose ,比較好管理。\nservices:\nfilebeat:\nimage: docker.elastic.co/beats/filebeat:8.15.3\nbuild: filebeat\ncontainer_name: filebeat\nuser: root\nrestart: unless-stopped\nenvironment:\n- ELASTICSEARCH_HOSTS=https://10.60.7.192:9200\n- ELASTICSEARCH_USERNAME=elastic\n- ELASTICSEARCH_PASSWORD=PASSWORD\nlabels:\nco.elastic.logs/enabled: "false"\nvolumes:\n- ./filebeat.yml:/usr/share/filebeat/filebeat.yml\n- /var/lib/docker/containers:/var/lib/docker/containers:ro\n- /var/run/docker.sock:/var/run/docker.sock:ro\n- ./ca.crt:/etc/pki/client/ca.crt\n- ./tls.crt:/etc/pki/client/cert.pem\n- ./tls.key:/etc/pki/client/cert.key\nlogging:\ndriver: "json-file"\noptions:\nmax-size: "10m"\nmax-file: "2"\nnetworks:\n- zlm_network\nnetworks:\nzlm_network:\ndriver: bridge\nname: zlm_network\n\n主要會著重於volume的部分。\n其他地方可能有點差異會抓幾個講。\nGeneral\n\nuser: root\n\n不設定的話,在filebeat.yml 的logging 會出現權限不足的錯誤。\n\nnetwork 的設定,讓他跟要抓取log的服務放在一起,故同一個網路名稱。\n\nVolume\n\nfilebeat.yml的設定檔連結,這部份沒什麼問題。\n裡面內容會在下面說。\n抓取log的路徑 /var/lib/docker/containers\n掛載SSL憑證\n為什麼要掛載呢?因為ECK在安裝的時候,預設都走ssl,\n但ECK安裝時在GKE上面,而目前filebeat在GCE,\n所以要拿ECK在GKE上面的憑證來用。\n\n重點來了,你怎麼知道要抓哪個憑證來用,\n此時我們可以先去看一下GKE的ECK裡面的設定檔。\nvolumes:\n- name: elastic-internal-http-certificates\nsecret:\nsecretName: prod-es-http-certs-internal\ndefaultMode: 420\noptional: false\n\n此時,就能去decode secret了\nkubectl get secret prod-es-http-certs-internal -n elastic-system -o=jsonpath='{.data.ca\\.crt}' | base64 -d;echo\n\nkubectl get secret prod-es-http-certs-internal -n elastic-system -o=jsonpath='{.data.tls\\.crt}' | base64 -d;echo\n\nkubectl get secret prod-es-http-certs-internal -n elastic-system -o=jsonpath='{.data.tls\\.key}' | base64 -d;echo\n\n之後將key ,掛載讓filebeat能夠讀取即可。\nref. Run Filebeat on Docker\nFilebeat.yml\nfilebeat.inputs:\n- type: container\nenabled: true\npaths:\n- '/var/lib/docker/containers/*/*.log'\ntags: ["videosokoban-qa"]\n\nprocessors:\n- add_docker_metadata: ~\n- drop_event:\nwhen:\nnot:\nequals:\ncontainer.name: "zlm-server"\noutput.elasticsearch:\nhosts: https://prod-es-http:9200 #https://10.60.7.192:9200\nusername: "elastic"\npassword: "PASSWORD"\nssl:\ncertificate_authorities:\n- "/etc/pki/client/ca.crt"\ncertificate: "/etc/pki/client/cert.pem"\nkey: "/etc/pki/client/cert.key"\nindices:\n- index: "videosokoban-qa-%{+yyyy.MM}"\nwhen.contains:\ntags: "videosokoban-qa"\nlogging:\nmetrics.enabled: false\nlevel: debug\nto_stderr: true\nto_files: true\nfiles:\npath: /var/log/filebeat\nname: filebeat\nkeepfiles: 7\npermissions: 0644\n\nfilebeat.input\n要擷取的log來源,\n已將本機的路徑掛到docker上面的路徑的。\n/var/lib/docker/containers/*/*.log\n這個路徑擁有所有的docker logs\ntype 有分成 container與 docker。\n據說是docker只能用在docker上面,\n但container可以用在任何的容器服務上面。\ntype: docker的設定我沒搞出來,有興趣的可以自己試一試。\nprocessors\n這邊牽扯到的部分比較多\n\nadd_docker_metadata\n增加一些欄位到log裡面,詳細內容可參考 Add Docker metadata\ndrop_event ,判斷當container_name是 zlm-server的時候,\n就不要紀錄,這個值是先塞資料進去到ECK後,再篩選出來的。\n條件判斷可參考conditions。\n\n之前還有用過 drop_fileds ,add_cloud_metadata,\n其他更多請參考Define processors\noutput.elasticsearch\n\nhost & ssl\n要將log丟去的ECK伺服器位置。\n\nhosts這邊,本來是用GKE的內部負載平衡的ip位置,\n但是直接使用ip位置的話,會出現錯誤。\n\ncannot validate certificate for 10.60.7.192 because it doesn't contain any IP SANs\n\n這是因為伺服器的憑證沒有加過IP地址,\n看一下 tls.crt,裡面的這段。\n\n這裡並沒有ip位置,所以沒辦法通過驗證。\n但這個憑證是ECK自動產生的,\n所以換個想法,直接讓服務去呼叫 https://prod-es-http:9200\n此時,就是到主機設定一下/etc/hosts,\n新增\n10.60.7.192 prod-es-http\n\nref. Secure communication with Elasticsearch\n\nindices\n將特定的tag綁定到指定的indices上\n\nref.Configure the Elasticsearch output\nlogging\n除錯時,\n可以先將to_stderr: true 開啟。\n可直接用docker logs filebeat 看 log。\n注意,如果要用 to_files, docker-compose.yaml 記得加上 user: root,\n否則會發生權限不足的情況。\nref. Configure logging\n官方的filebeat.yaml ,請參考 filebeat.reference.yml",
"tags": ["https", "note","🗒"]
},
{
"title": "245. gcloud storage取代gsutil",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/245. gcloud storage取代gsutil/",
"content": "WHY\n剛好想要查一下gsutil的 rsync指令,\n結果官方文件一直跑不出來,\n細看才發現\n\n通常,您應該使用 gcloud storage 命令)而不是 gsutil 命令:\ngsutil 工具是一個舊版 Cloud Storage CLI,僅進行最低程度的維護。\ngsutil 工具不支援使用較新的 Cloud Storage 功能,例如軟刪除和託管式資料夾\ngcloud storage 命令需要較少的手動最佳化即可實現最快的上傳和下載速率。\n\n看來我該改程式了。\nNote\nGsutil\n\nrsync 同步\n\ngsutil -m rsync -r /home/user/docker-compose/VideoSokoban/MP4Final gs://abc\n\nchange\n\ngcloud storage rsync -r /home/user/docker-compose-yaml/VideoSokoban/MP4Final gs://abc\n\nref. gcloud storage rsync\n\nsignurl 下載權限\n\ngsutil signurl -d 30m gcs-download.json gs://backup/downloadbak/24-4-17.bak\n\nchange\n\ngcloud storage sign-url -d=30m --private-key-file=gcs-download.json gs://backup/downloadbak/24-4-17.bak\n\n但第一次執行時,可能會發生錯誤\n\nERROR: (gcloud.storage.sign-url) This command requires the pyOpenSSL library. Please install it and set the environment variable CLOUDSDK_PYTHON_SITEPACKAGES to 1 before re-running this command\n\n執行\nexport CLOUDSDK_PYTHON_SITEPACKAGES=1\n\nref. gcloud storage sign-url\n\ndu 查bucket大小\n\ngcloud storage du gs://abc --summarize --readable-sizes\n\nref. gcloud storage du\n或是在Metrics Explorer ,查詢 Total bytes (v2) 選擇 GCS Bucket。\n這邊也有 Total count (v2) 可以查詢加總。\nfilter可指定bucket name。\n完整 api storage.googleapis.com/storage/v2/total_bytes\n\ncors\n\ngsutil cors set example_cors_file.json gs://example_bucket\n改\ngcloud storage buckets update gs://example_bucket --cors-file=example_cors_file.json\n\nref.\n\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/142.gcs cors設定/\">142.gcs cors設定</a>\nSet up and view CORS configurations\n\ncp 複製\n\ngsutil cp -n gs://abc/57d51e14-6ea2-409a-9bee-07a832456cf6.jpg .\n\ngcloud storage cp -n gs://abc/57d51e14-6ea2-409a-9bee-07a832456cf6.jpg .\n\nref. gcloud storage cp",
"tags": [ "note","☁️"]
},
{
"title": "246. GCP網路費用粗估計算",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/246. GCP網路費用粗估計算/",
"content": "WHY\n昨天突然說要叫我算一下影音串流,如果每秒2MB的話,一個月多少。\nSolution\nQ: 現在的題目,每秒有 2Mb的串流,每月會有多少費用。\n先計算每月流量\n2*60*60*24*30=5184000(Mb)\n再轉成MB\n51840000/8=648000\n因Google的費用單位都是 GiB (1GB 約0.93GiB),\n所以 648 GB = 602GiB\np.s GB是十進制,GiB是二進制\n組成\n網路的費用分成兩塊,\nData transfer(資料傳輸) + data processes(資料處理)\n入站不收 data transfer的費用,但會收 data processes的費用。\n出站,兩邊的費用都會收。\nInbound\nprocesses data的服務 有 Load Balancer 、Cloud NAT 、 Protocol forward\n\n從LB 進入的data processes費用為 602*0.008=4.816\nLB的轉發規則前五條,每小時 0.025 ,於是 0.025*24*30=18\n於是,inbound的 LB 資料處理費用為 22.816 USD\nOutbound\n這邊計算時,務必搞清楚 哪一邊是client 哪一邊是 server。\nGKE Private Cluster 的網路入跟出的IP不一樣,\n所以計算方式也不一樣。\n第一種\n客戶直接連線到server抓取串流\n所以GKE是server,是從Load Balancer出。\nData processes 費用\n跟上面inbound的費用一樣,都是 每GiB 0.008 ,所以是 22.816\nData Transfer 費用\n> 602*0.23 = 138.46\n \n 0.23是台灣到中國的每GB費用,\n 到其他地方的價格不一樣。\n \n ref. 虛擬私人雲端 網際網路資料移轉速率-> 進階級計價模式\n所以總金額約為 138.46+22.816 = 161.276\n第二種\n服務直接將串流打到對方的伺服器上\n所以GKE是client,是吃Cloud NAT的流量。\nData processes 費用\n\n(0.044*720) + (0.005*1*720)+(5184*0.045)=43.056\n\n(0.044*720 ) : 超過32個VM ,NAT 閘道的每小時價格 0.044 ,一個月有720個小時\n(0.005*1*720):NAT閘道的IP,1個每小時0.005\n(172.8*0.045): 每處理 GiB 資料、傳入與傳出資料移轉的價格 0.045 ,172.8G\nData Transfer 費用\n> 602*0.23 = 138.46\n \n 0.23是台灣到中國的每GB費用,\n 到其他地方的價格不一樣。\n所以總金額約為 138.46+43.056 = 181.516\nref. Cloud NAT",
"tags": [ "note","☁️"]
},
{
"title": "247. MSSQL指令賦予權限",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/247. MSSQL指令賦予權限/",
"content": "WHY\n因為之前RD組長真的幹了從刪庫到跑路的過程,\n重點刪了還沒跑路。\n於是每個RD的資料庫權限直接縮減。\n但由於程式是使用ORM ,會自建資料庫。\n導致RD沒有權限可以連到新建的DB,\n我只能手動賦予權限,但每次新增好煩,\n我又沒window,只能用VM開SSMS出來用。\nSolution\n用指令直接解決\n\ncreate USER bmsrd for login bmsrd\nEXEC sp_addrolemember 'db_datareader','bmsrd'\nEXEC sp_addrolemember 'db_datawriter','bmsrd'\n\n以後直接到 Google的 Cloud SQL Studio 執行指令就好。\n或是使用 Azure Data Studio就好了。",
"tags": [ "note","🗄"]
},
{
"title": "README",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/",
"content": "度估記事本\n\n懶人,始終相信科技始終來自於人類的惰性。\n懶是一種方式,卻不是一種態度。\n你如果想要有更多的時間偷懶,就一定要有最高的效率。\n\n最新文章\n\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/245. gcloud storage取代gsutil/\">245. gcloud storage取代gsutil</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/246. GCP網路費用粗估計算/\">246. GCP網路費用粗估計算</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/247. MSSQL指令賦予權限/\">247. MSSQL指令賦予權限</a>\n<a class=\"internal-link is-unresolved\" href=\"/404\">248. EFK, index is empty or not defined</a>\n\n用Obsidian發佈到Github\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/193. Obsidian發佈到github.io個人網站/\">193. Obsidian發佈到github.io個人網站</a>\n電影評分表\n做好玩的 電影評分表\n\nTag列表\n💡:Map Of Content\n💻:<a class=\"internal-link\" data-note-icon=\"\" href=\"/💻 Code/0.Code MOC/\">0.Code MOC</a>\n🐳:<a class=\"internal-link\" data-note-icon=\"\" href=\"/🐳 Container/0.Container MOC/\">Container MOC</a>\n🗄:<a class=\"internal-link\" data-note-icon=\"\" href=\"/🗄 Database/0.Database MOC/\">0.Database MOC</a>\n⏱:<a class=\"internal-link\" data-note-icon=\"\" href=\"/⏱ Drone/0.Drone MOC/\">0.Drone MOC</a>\n🗒:<a class=\"internal-link\" data-note-icon=\"\" href=\"/🗒 EFK/0.EFK MOC/\">EFK MOC</a>\n☁︎:<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/0.GCP MOC/\">GCP MOC</a>\n📥:inbox\n⛵️:<a class=\"internal-link\" data-note-icon=\"\" href=\"/⛵️ istio/0.istio MOC/\">istio MOC</a>\n⎈:<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/0.K8s MOC/\">k8s MOC</a>\n🐧:<a class=\"internal-link\" data-note-icon=\"\" href=\"/🐧 Linux/0.Linux MOC/\">Linux MOC</a>\n🍎:Apple\n🌐:<a class=\"internal-link\" data-note-icon=\"\" href=\"/🌐 Network/0.Network MOC/\">Network MOC</a>\n👁:<a class=\"internal-link\" data-note-icon=\"\" href=\"/👁 Observability/0.Observability MOC/\">0.Observability MOC</a>\n🎮:Game\n🆒:Side Project\n\nWhat is MOC ?\n當單一筆記的數量越來越多時,就能夠構成一個MOC(Map of Contens)\n詳細請參考下面連結,\n數位筆記太多很凌亂怎麼辦?使用 MOC 架構有系統地管理數百則的數位筆記\n技術文章寫法要點\n文章採用單線結構\n一點接着一點,就是一張卡片接着一個卡片,\n把問題拆成多篇文章,\n讓文章一篇就只有一個要點。\nref. # 科技愛好者週刊(第 288 期):技術寫作的首要訣竅\n\n舊筆記\n2021年以前文章請至 度估記事本 查詢",
"tags": [ "note","gardenEntry"]
},
{
"title": " ⎈ K8s MOC",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/0.K8s MOC/",
"content": "基本概念\n\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/27.K8s的節點選擇與污染/\">27.K8s的節點選擇與污染</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/GKE/41.GKE節點無法自動縮小/\">41.GKE節點無法自動縮小</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/42.k8s PDB(pod中斷預算)/\">42.k8s PDB(pod中斷預算)</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/105. linux系統時間與k8s/\">105. linux系統時間與k8s</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/123.Helm 使用方式/\">123.Helm 使用方式</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/172. 自建k8s版本升級/\">172. 自建k8s版本升級</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/192. 自建的k8s拉取private registry/\">192. 自建的k8s拉取private registry</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/194. pod debug方式/\">194. pod debug方式</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/196. http健康度偵測/\">196. http健康度偵測</a>\n\nTerraform\n\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/Terraform/82. Terraform vs Ansible/\">82. Terraform vs Ansible</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/Terraform/147. 用chatGPT學Terraform/\">147. 用chatGPT學Terraform</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/Terraform/148. Terraform的基本概念/\">148. Terraform的基本概念</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/Terraform/149. terraform 部署VM,啓動docker安裝metadata_startup_script/\">149. terraform 部署VM,啓動docker安裝metadata_startup_script</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/Terraform/189. 導入Terraform/\">189. 導入Terraform</a>\n\nTools\n\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/118. kubernetes Dashboard/\">118. kubernetes Dashboard</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/137. kubecolor 直觀的kubectl/\">137. kubecolor 直觀的kubectl</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/139. openlens add pod shell or logs button/\">139. openlens add pod shell or logs button</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/162.查詢已棄用的API/\">162.查詢已棄用的API</a>\n\nyaml\n\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/Yaml/2. k8s yaml撰寫 volume 踩坑篇/\">2. k8s yaml撰寫 volume 踩坑篇</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/Yaml/12. k8s YAML 小細節/\">12. k8s YAML 小細節</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/Yaml/85. gke-cronjob筆記/\">85. gke-cronjob筆記</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/Yaml/87.kustomize 共用label(optional)/\">87.kustomize 共用label(optional)</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/Yaml/94. k8s 細節補充/\">94. k8s 細節補充</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/Yaml/98. k8s中的command與dockerfile的 CMD/\">98. k8s中的command與dockerfile的 CMD</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/Yaml/136. 一步步篩選k8s的deploy內容/\">136. 一步步篩選k8s的deploy內容</a>\n\nGKE\n\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/GKE/4. GKE使用GPU/\">4. GKE使用GPU</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/GKE/37.SolrCloud on GKE/\">37.SolrCloud on GKE</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/GKE/39.solrCloud的初體驗/\">39.solrCloud的初體驗</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/GKE/44.srs 影音串流 on GKE/\">44.srs 影音串流 on GKE</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/GKE/50.GKE workload Identity 實地演練/\">50.GKE workload Identity 實地演練</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/GKE/56. GKE記錄 nginx log/\">56. GKE記錄 nginx log</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/GKE/70. GKE pvc還原/\">70. GKE pvc還原</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/GKE/71.gitlab on GKE 災害還原筆記/\">71.gitlab on GKE 災害還原筆記</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/101. 批次修改hpa/\">101. 批次修改hpa</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/104. rabbitmq operator安裝/\">104. rabbitmq operator安裝</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/🗒 EFK/43.自建ECK on GKE/\">43.自建ECK on GKE</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/190. cert-manager安裝/\">190. cert-manager安裝</a>\n\nTroubleshooting\n\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/Yaml/74. kubernetes 批次檢查yaml特定字元/\">74. kubernetes 批次檢查yaml特定字元</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/76. k8s error,The node was low on resource../\">76. k8s error,The node was low on resource..</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/144. k8s 的sercret複製/\">144. k8s 的sercret複製</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/151. kubeadm重新產生驗證/\">151. kubeadm重新產生驗證</a>",
"tags": [ "note","⎈"]
},
{
"title": "批次修改hpa",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/101. 批次修改hpa/",
"content": "前言\n這又是因為懶惰而衍生出來的一篇,\n懶得一個一個點進去改HPA的數量,\n就寫sh搞定吧。\n正文\n參考 <a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/88.批次修改GCP的label/\">88.批次修改GCP的label</a>,建立一個文字檔 hpa.txt,\n先用指令,將hpa的name取出存到文字檔內,因為是針對特定幾個修改,所以並沒有全拉。\nkubectl get hpa;\n\n文字檔內容如下\nistio-yabo-api-prod-external\nistio-yabo-api-prod-internal\nistio-yabo-frontend-external-demo\nistio-yabo-frontend-internal-demo\nistio-yabo-frontend-prod-external\nistio-yabo-frontend-prod-internal\nistio-yabo-frontpage-external-prod\nistio-yabo-frontpage-internal-prod\nistio-yabo-huanggua-external-beta\nistio-yabo-huanggua-external-prod\nistio-yabo-huanggua-internal-beta\nistio-yabo-huanggua-internal-prod\nistio-yabo-landingpage-external-demo\nistio-yabo-landingpage-external-prod\nistio-yabo-landingpage-internal-demo\nistio-yabo-landingpage-internal-prod\nistio-yabo-pwa-external-prod\nistio-yabo-pwa-internal-prod\n\n主要是 kubectl patch hpa 做修改。\npatch這功能看來頗強大,第一次見到,\n改天可研究看看。\nwhile read p; do\necho "$p"; kubectl patch hpa -p '{"spec":{"minReplicas": 2}}' -n istio-system $p; echo "done";\ndone <hpa.txt\n\nref.\n- Kubenetes: change hpa min-replica\n- 使用 kubectl patch 更新 API 對象",
"tags": [ "note","⎈"]
},
{
"title": "rabbitmq operator安裝",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/104. rabbitmq operator安裝/",
"content": "前言\n接到同事說要裝rabbitmq,\n說之前在dev有裝過,但在k8s上面沒看到,\n用之前留下的yaml,會裝不起來,只好從頭來了。\n正文\n\n本來是想參考他的這篇,結果看到第一段說\nStop! There is a Better Way!\n才知道rabbitmq有出了operator可供安裝。\n安裝rabbitmq operator\n\nkubectl apply -f "https://github.com/rabbitmq/cluster-operator/releases/latest/download/cluster-operator.yml"\n\nref. Installing RabbitMQ Cluster Operator in a Kubernetes Cluster\n\n部署yaml\n\napiVersion: rabbitmq.com/v1beta1\nkind: RabbitmqCluster\nmetadata:\nname: dev-rabbitmq\nspec:\nreplicas: 3\nrabbitmq:\nadditionalConfig: |\ndefault_user=admin\ndefault_pass=abc123\nservice:\ntype: NodePort\n\n因為是自建的k8s,沒有lb,所以就用NodePort了。\n更詳細的參數請參考下面連結。\nref. Using RabbitMQ Cluster Kubernetes Operator\n問題排除\n中間有發生小插曲,k8s內沒有預設的storeageClass\n導致建立pvc時發生錯誤,\n雖然在上面的yaml上面能夠指定,\n但可能是格式沒寫好,導致沒有產生statefuleSet 的pvc。\n最後先指定目前的storageClass為預設的。\nkubectl patch storageclass <your_storageclass_name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'\n\nref.\n\ninstall RabbitMQ in kubernetes\nRabbitMQ】五分鐘輕鬆瞭解 RabbitMQ 運作",
"tags": [ "note","⎈"]
},
{
"title": "linux系統時間與k8s",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/105. linux系統時間與k8s/",
"content": "前言\n最近弄之前的人自建的k8s,\n才碰到一堆問題,\n我的linux果然需要加強orz\n正文\n一般的linux內的時間顯示\ntimedatectl\n\nLocal time :本機時間\nUniversal time : UTC時間\nRTC time: 硬體時間\nNTP service : 自動效時\nTime Zone: 時區\n當時間不對時,可以設定時間的自動效正\ntimedatectl set-ntp yes\n\n設定完後,等一下(多久不確定,但不會立即),\nUTC的時間應該就會自己效對。\nNTP伺服器(有需要再設定)\n\ntime.google.com\n\n查詢各時區\ntimedatectl list-timezones\n\n設定時區\ntimedatectl set-timezone Asia/Taipei\n\nref. Ubuntu Linux 使用 timedatectl 校正時間、時區教學與範例\nPod的時區設定\npod的時間會跟他所在的node時間一致,\n所以當你的node 主機時間錯時,\npod的時間也會跟着錯。\n但基本上都是UTC,\n如果要指定時區的話,\n可以用volume掛載成特定地區。\n或是直接在build image時,一併更改。\n\npvc 掛載\n時區檔案的位置\n\napiVersion: v1\nkind: Pod\nmetadata:\nname: busybox-sleep\nspec:\ncontainers:\n- name: busybox\nimage: busybox\nargs:\n- sleep\n- "1000000"\nvolumeMounts:\n- name: tz-config\nmountPath: /etc/localtime\nvolumes:\n- name: tz-config\nhostPath:\npath: /usr/share/zoneinfo/Europe/Prague\ntype: File\n\nDockerfile更改\n\nRUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \\\n\t\t && echo "Asia/Shanghai" > /etc/timezone\n\nref.\n\nk8s環境下處理容器時間問題的多種姿勢\ndate and time synchronization among the pods and host in kubernetes",
"tags": [ "note","⎈"]
},
{
"title": "kubenetes簡易介面",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/118. kubernetes Dashboard/",
"content": "碎碎念\n以前GKE用習慣了,現在變成自建的k8s,只能用lens管,\n雖然說不上有哪不足,但總是怪怪的。\n今天查資料看到有這個UI,就架來看看了。\n正文\n本機訪問\n官方文件,安裝下去就好了\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.6.1/aio/deploy/recommended.yaml\n\n執行轉發來連到dashboard\nkubectl proxy\n\nkubectl 會使得 Dashboard 可以通過 http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/ 訪問。\n登入畫面如下\n\n再來就需要產生一組token來做登入了。\n首先建立一組serviceAccount\ncat <<EOF | kubectl create -f -\napiVersion: v1\nkind: ServiceAccount\nmetadata:\nname: admin\nnamespace: kube-system\nEOF\n\n綁定serviceAccount 與 角色\ncat <<EOF | kubectl create -f -\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\nname: admin-user\nroleRef:\napiGroup: rbac.authorization.k8s.io\nkind: ClusterRole\nname: cluster-admin\nsubjects:\n- kind: ServiceAccount\nname: admin\nnamespace: kube-system\nEOF\n\nService Account建立完後,Kubernetes Token Controller 就會自動的為其產生一個 secret resource(名稱為 [SERVICE_ACCOUNT_NAME]-token-[RANDOM_STRING])\nkubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin | awk '{print $1}')\n\n這邊取得的token即可在 Dashboard 上登入。\nref. 佈署 & 存取 Kubernetes Dashboard\n外部訪問\n更改service 內的 kubernetes-dashboard.kubenetes-dashboards\n將cluster改成NodePort ,然後看對應的port多少就能登入了。\n記得用https\n\nref. accessing-dashboard",
"tags": [ "note","⎈"]
},
{
"title": "Helm 使用方式",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/123.Helm 使用方式/",
"content": "睡睡念\n最近要用coturn,看到有人用helm 架在k8s上面,就順便來試試了。\n之前剛開始接觸k8s,碰到helm一堆錯誤,無法執行。\n現在想應該是裏面有些設定要修改的關係,\n現在應該會比較好了吧!?\n正文\n架構\nhelm的架構,可先產生一個範例檔,\n看有哪些東西。\nhelm create ezio\n\n在Helm裏面,將kubernetes的應用程式稱為Chart\n\ntree ezio\n\nezio\n├── Chart.yaml\n├── charts\n├── templates\n│ ├── NOTES.txt\n│ ├── _helpers.tpl\n│ ├── deployment.yaml\n│ ├── hpa.yaml\n│ ├── ingress.yaml\n│ ├── service.yaml\n│ ├── serviceaccount.yaml\n│ └── tests\n│ └── test-connection.yaml\n└── values.yaml\n\nChart.yaml :包含了chart的內容描述\ncharts(folder) :此目錄可能包含了其他不同的 chart,也可稱為 subcharts\ntemplates(folder):此目錄為要部署的所有類型範本\nvalues.yaml : 參數設定檔,所有的變數都寫在這。\n\ntemplates內寫的參數,通常為\n.Values.replicas:表示values.yaml裏面的replicas參數\n其他非values的取得方式,參考 Built-in Objects\ntemplate有一些可能會用到的函數,\n主要有\n\npipeline ( linux 裏面常見到的 | )\nif/else\nwith(類似vb.net 的with)\nrange(for loop)\n\nCheatsheet\ndry-run\n先查看helm所產生的yaml\nhelm install --dry-run coturn ./coturn\n\n設定參數\nhelm install coturn ./conturn --set certificate.enabled=false\n\n指定values.yaml\nhelm install coturn ./conturn -f myval.yaml\n\n指定namespace\nhelm install coturn ./conturn -n tools\n\n看helm列表\nhelm ls\n\n更新chart\nhelm upgrade coturn ./coturn\n\n移除chart\nhelm uninstall coturn\n\nref.\n- [Helm] Helm v3 使用簡介\n- Helm介紹",
"tags": [ "note","⎈"]
},
{
"title": "kubecolor 直觀的kubectl",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/137. kubecolor 直觀的kubectl/",
"content": "睡睡念\n剛好看到有人的文章說 kubecolor美美的kubectl就來試用了XD\n正文\nmac or linux 安裝\nbrew install hidetatz/tap/kubecolor\n\n直接使用\nkubecolor get pod\n\n但我平常打kubectl打習慣了,突然要改用那個覺得好麻煩,\n改別名吧\n新增別名\nalias kubectl="kubecolor"\n\n移除別名\nunalias kubectl\n\n但這個只有暫時,要永久的話,需要到.bash_profile設定\nmac 是在 個人目錄底下\nvim ~/.bash_profile\n\n沒有的話,就新建檔案,然後輸入\nalias kubectl="kubecolor"\n\np.s mac 的環境變數載入順序為\n\n/etc/profile -> /etc/paths -> ~/.bash_profile -> ~/.bash_login -> ~/.profile -> ~/.bashrc\n\nref\n\nkubecolor\nmac 組態環境變數,講的太仔細了,非常棒",
"tags": [ "note","⎈"]
},
{
"title": "openlens增加shell和logs 按鈕",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/139. openlens add pod shell or logs button/",
"content": "睡睡念\nlen在6.X版本後,要登入才能用。\n那個時候也正好跳去openlens,在那之前都可以從pod右上角的按鈕,\n快速進入到pod裏面,或是查pod log,但在6.2.4之後就消失了。\n直到現在6.4.10(寫這篇時的版本),還是沒有。\n最後得知是因為Lens才把那段移掉。\n正文\n安裝方式\n到 Extensions 直接貼上下面的來源\n@alebcay/openlens-node-pod-menu\n\n來源\n主要是框起來的功能,\n對於比較不熟悉的kubectl指令的人來說,非常實用。\n\n所以當初沒有的時候,反而是我同事無法接受。\n至少我還能用指令的方式查我要的東西。\nkubectl exec -it pod_name bash\nkubectl logs pod_name\n...\n\n今天心血來潮查查看有沒有相關問題,是bug還是已移除。\n才知道了,原來是Lens把它從openLens移除,\n詳細可參考下面連結\nhttps://github.com/lensapp/lens/issues/6819\nOpenLens 6.3.0 - No Logs or Shell buttons\n之後再試試其他的 devtron 或 Monokle",
"tags": [ "note","⎈"]
},
{
"title": "k8s取得登入憑證",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/143. k8s取得登入憑證/",
"content": "睡睡念\n幫同事新建一組drone 自動部署的新專案,\n要發版到自建的k8s上面,\n終於碰到我不想面對的東西了。\nkube_ca ,kube_token ,我哪知道這兩個東西在哪裏阿\n正文\n從 Drone Kubernetes可以知道,一個是使用者,一個是ca認證的key,\n但我還不知道去哪生這兩個東西出來。\nKUBE_TOKEN This plugin has one authentication method and that is to use the token to authorize the user.\nKUBE_CA This should be the base64 encoding of your certificate authority. You can get this string by running the command:\n跑去問了一下chatGPT,得到答案。\n執行指令前,必須先連到你要取得的cluster上。\nkubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep cluster-admin | awk '{print $1}')\n\n我的列出有很多個,就拿第一個看起來也最像的來用了。\nadmin-user-token-tm7g4\n\n這邊就會看到token。\n再來是ca\nkubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.certificate-authority-data}'\n\n放到drone上面,驗證,收工。\n\nref. 使用者認證",
"tags": [ "note","⎈"]
},
{
"title": "k8s 的sercret複製",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/144. k8s 的sercret複製/",
"content": "睡睡念\n本地的k8s機器,要去google artifact registry pull image ,發現沒權限。\n以前的權限在namespace的 default上面,\ndefault太肥了,實在不想再往那邊塞,\n要麻自己創個SA再把json丟去驗證,\n不然看能不能把舊的拿來用。\n正文\n複製\n參考 Kubernetes: copying a secret from one namespace to another\nkubectl get secret my-tlssecret --namespace=default -o yaml | sed 's/namespace: .*/namespace: gameservice/' | kubectl apply -f -\n\n本來my-tlssecret 在 defaul上 ,要改到gamerservice\n這樣就不用再申請一個sa帳號搞認證了,\n如果要從頭開始的話,\n參考google官方文件\n為 Docker 設定身份驗證\n解密\nkubectl get secret test-grafana -n monitoring -o jsonpath='{.data.admin-user}' |base64 --decode; echo",
"tags": [ "note","⎈"]
},
{
"title": "kubeadm重新產生驗證",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/151. kubeadm重新產生驗證/",
"content": "睡睡念\n事情發生在某一天,\n突然有個人跑來跟我說,他該怎麼連樓上自建的k8s,\n那時在處理其他東西,就說我等等給你。\n再來,突然發現我自己連不上去,一直跳錯誤。\nunable to connect to server: x509: certificate has expired or is not yet valid\n正文\n使用openLen連線時,出現錯誤。當下認爲應該是金鑰有問題,\n但那臺機器應該很久沒動了,當初k8s也不是我架起來的,\n頭痛阿。\n\nproxy_server.go:147 Error while proxying request: x509: certificate has expired or is not yet valid\n\n從這篇K8S自建叢集更換證書知道了一件事情\n\n通過kubeadm自建的叢集,初始化後會生成一年的證書,簽發的CA證書有效期默認是10年,簽發的apiserver證書有效期默認是1年\n\n再問一下其他單位的同事,那個環境是不是已經架一年了?\n結果出來,差不多一年了,那可以判斷是金鑰過期,但還是必須到機器裏面檢查一下。\n用ssh或任意方式連到master主機上,\n視權限變更使用者,\n我在執行kubeadm的時候,全程使用root的帳號\n檢查憑證到期日\nkubeadm certs check-expiration\n\n發現真的過期了,重建吧。\n參考下面連結發現有點問題,可能是因為版本有更新。\nref. 解決kubernetes證書過期問題\nkubeadm certs renew # 這樣有問題,會發生錯誤\n\nkubeadm missing subcommand; "renew" is not meant to be run on its own\n\n查詢官方文件\nkubeadm certs renew all\n\n執行完成後,在檢查一次到期日,是否已經變更。\nkubeadm certs check-expiration\n\n但此時還是沒辦法連線,需更新kube config,\n這邊使用一般使用者帳號\nmv config config.old cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config sudo chmod 644 $HOME/.kube/config\n\np.s 上面的文章說要重啟kube-apiserver,kube-controller,kube-scheduler,etcd 這四個容器,但我沒重啓,因為我這台master主機根本沒找到docker,這部分我也很疑惑。\n但一切都正常了,就先這樣吧。\n\n結尾\n如果要從其他地方連到k8s master,檔案就在/etc/kubernetes/admin.conf裏面了。\n不過官方強烈建議,不要將admin.conf與其他人共享。\n最好是另外開一個使用者,\n這部分我研究下,改天在寫篇文章了吧\n相關資訊:\n\n使用 kubeadm 進行憑證管理\nPKI 證書和要求",
"tags": [ "note","⎈"]
},
{
"title": "查詢GKE已棄用的API",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/162.查詢已棄用的API/",
"content": "前言\n這件事說來突然,\n某一天我就發現在GKE上面出現了警告訊息,\n說我的GKE仍在使用已棄用的API,\n但我搬到1.25版本已經是一個多月前的事情了,\n也沒聽到有人在說服務掛掉,\n百思不得其解。\n正文\n\n再來使用了 kubent ,來尋找到底是哪一個服務卡住,\n但很遺憾的都沒有搜尋到。\n過了幾天後,發現之前拿來測試的QA環境,\n也跳出來了已棄用API警告通知。\n\n發現GKE就有提示是什麼呼叫的了,\n在QA環境很清楚的寫着kubent,\n但本來的那個呢?\n只有 v2.1.0 ,\n於是根據這個關鍵字去找哪個image有這個版本號。\n在kube-state-metric上面找到了這個關鍵字,\n這也符合為什麼出錯了沒人知道,\n因爲沒人看(?)\n但因爲metric來源有至少三套,所以不好發現。\n不過這個前任建置的也有點奇怪,\n我查了官方的kube-state-metrics,\n沒找到有用sts建立過的方式,\n有點神奇。\n\n先拿QA來驗證改改看了,\n看後續會不會再跳出來警告",
"tags": [ "note","☁️"]
},
{
"title": "自建k8s版本升級",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/172. 自建k8s版本升級/",
"content": "睡睡唸\n有人說他要測試OME(OverMediaEngine),串流直播軟體,說比SRS好一些,但自建的k8s版本不夠,不能上gateway API,所以升級吧。\n正文\n更新前請先確認版本更新後,你的服務不會掛掉。\n更新大版本時,會有API棄用的狀況, <a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/162.查詢已棄用的API/\">162.查詢已棄用的API</a>\n目標\n更新k8s的master一臺與node兩臺的版本\n步驟\n\n查詢目前的版本\n\nkuberctl version\n\n(這是目前版本,升級當時的版本為1.22.?)\nserver的版本為1.25.14\n\nServer Version: version.Info\n\n升級kubeadm\n\n# 查看所有可用的kubeadm的版本\nyum list --showduplicates kubeadm --disableexcludes=kubernetes\n# 然後升級kubeadm的版本到1.23.0\nyum install -y kubeadm-1.23.0-0 --disableexcludes=kubernetes\n# 查看kubeadm版本\nkubeadm version\n\n升級master控制\n\nkubeadm upgrade plan\n\n這邊碰到一個問題,我本來只想升級到1.23.0,\n但上面這張圖,他要求直接到1.23.17,\n不照做行不行,『不行』,升級會出錯。\n所以回到第二步,再度更新kubeadm到1.23.17\n再來一次kubeam upgrade plan\n這次沒出現警告了\n\n執行上面執行完upgrade plan提供升級指令\nkubeadm upgrade apply v1.23.17\n\n完成後會看到\n\nSUCCESS! Your cluster was upgraded to "v1.23.17". Enjoy!\n\n升級kubectl 與 kubelet\n\n查看目前節點版本\nkubectl get node -o wide\n\n驅逐當下節點的pod(這段與參考來源的指令不一樣,這個比較暴力)\n$master為節點的名稱\nkubectl drain --force --ignore-daemonsets --delete-local-data --grace-period=10 "$master"\n\n等驅逐完後,確認node為SchedulingDisabled狀態,就可已開始升級了。\nyum install -y kubelet-1.23.17-0 kubectl-1.23.17-0 --disableexcludes=kubernetes\n# 重啓服務\nsudo systemctl daemon-reload\nsudo systemctl restart kubelet\n\n查詢node版本是否已經更新,然後解除封鎖。\nkubectl uncordon $node\n\n升級node的版本\n重複第四步驟,只有更新那一段yum install....需要到目標的node機器上做。\n\n所以指令如下\n$node為要更新的node主機\n# master主機\nkubectl drain --force --ignore-daemonsets --delete-local-data --grace-period=10 "$node"\n# node主機\nyum install -y kubelet-1.23.17-0 kubectl-1.23.17-0 --disableexcludes=kubernetes\n# 重啓服務\nsudo systemctl daemon-reload\nsudo systemctl restart kubelet\n# master主機\nkubectl uncordon $node\n\nref.\n\nk8s系列12-kubeadm升級k8s叢集 \nUpgrading kubeadm clusters",
"tags": [ "note","⎈"]
},
{
"title": "cert-manager安裝",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/190. cert-manager安裝/",
"content": "前言\n上次開新專案的延伸,\n設定domain時,對於cloudflare不夠熟,\n還好有個前端同事,熟此門路,因爲他也踩過。\n正文\n安裝cert-manager\n參照官網說明。\n下面語法不一定是最新的\nkubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cert-manager.yaml\n\n再來就是建立 ClusterIssuer 跟 Certificate\n在此之前,要先到cloudflare產生一組token,\n才有權限對這個domain做驗證。\n我的domain是在cloud domain購買,然後再cloudflare託管。\n為什麼不直接在google cloud託管,我也不知道,之前就這樣了。\n\nUser Profile > API Tokens > API Tokens.\n\n參照官方文件,設定權限,取得token\n\n將token存到 secret\napiVersion: v1\nkind: Secret\nmetadata:\nname: cloudflare-api-token-ezio-com\nnamespace: cert-manager\ntype: Opaque\nstringData:\napi-token: <token>\n---\napiVersion: cert-manager.io/v1\nkind: ClusterIssuer\nmetadata:\nname: cloudflare-issuer-ezio-com\nspec:\nacme:\nserver: https://acme-v02.api.letsencrypt.org/directory\nprivateKeySecretRef:\nname: cloudflare-issuer-ezio-com\nsolvers:\n- dns01:\ncloudflare:\nemail: ezio@abc.com\napiTokenSecretRef:\nname: cloudflare-api-token-ezio-com\nkey: api-token\n---\napiVersion: cert-manager.io/v1\nkind: Certificate\nmetadata:\nname: ezio-com-tls\nnamespace: istio-system\nspec:\nsecretName: ezio-com-tls\nissuerRef:\nname: cloudflare-issuer-ezio-com\nkind: ClusterIssuer\ncommonName: "*.ezio.com"\ndnsNames:\n- "*.ezio.com"\n\n這邊注意一下,檔案之間的關聯性。\n上面寫的範例domain是 *.ezio.com ,請改爲自己實際使用的。\n部署上去後,檢查狀態,有沒有Ready,通常不會超過5分鐘。\nkubectl get certificate -A\n\n如果啓動失敗的話,使用下面指令檢查log\nkubectl describe certificate ezio-com-tls\n\n如果是下面這個失敗訊息,\n\nFound no Zones for domain _acme-challenge.aplusmanagex.com. (neither in the sub-domain nor in the SLD) please make sure your domain-entries in the config are correct and the API key is correctly setup with Zone.read rights.\n\n表示你的token沒有相關權限,這個坑我踩完了orz。\nref.\n\nCloudflare\nkubectl apply",
"tags": [ "note"]
},
{
"title": "192. 自建的k8s拉取private registry",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/192. 自建的k8s拉取private registry/",
"content": "前言\n開發環境上,之前拉得都是另一個專案的registry,\n現在有個全新的專案,理所當然image應該拉去另一個地方的GAR。\n正文\n\n首先到IAM裏面,申請一個ServiceAccount,\n然後給權限,可以只給 Artifact Registry讀取者就好。\n然後產生金鑰,名稱為gar-push-bms.json。\n\n建立screct,名稱取名爲gar-pull\nstackoverflow的說明指出,該email是沒在用的,所以可以隨便打。\n\nkubectl create secret docker-registry gar-pull \\\n--docker-server "https://asia-east1-docker.pkg.dev" \\\n--docker-username _json_key \\\n--docker-email gar-pull@.iam.gserviceaccount.com \\\n--docker-password="$(cat gar-push-bms.json)"\n\ndeployment的yaml設定\n\nimagePullSecrets:\n- name: gar-pull\n\n記得,如果在不同的namespace,需重新建立新的secret。\nref.\n\nCreating image pull secret for google container registry that doesn't expire?\n為 Docker 設定身份驗證",
"tags": [ "note","⎈"]
},
{
"title": "pod debug方式",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/194. pod debug方式/",
"content": "前言\n這陣子建了一個新環境,\n然後pod在第一次啓動時,都會重啓,\n但一旦重啓就看不到之前的log。\n正文\n看上一次的log記錄\nkubectl logs {PODNAME} --previous\n\n其他用法\n# Return snapshot logs from pod nginx with only one container\nkubectl logs nginx\n\n# Return snapshot of previous terminated ruby container logs from pod web-1\nkubectl logs -p -c ruby web-1\n\n# Begin streaming the logs of the ruby container in pod web-1\nkubectl logs -f -c ruby web-1\n\n# Display only the most recent 20 lines of output in pod nginx\nkubectl logs --tail=20 nginx\n\n# Show all logs from pod nginx written in the last hour\nkubectl logs --since=1h nginx\n\nref .\n\nK8s如何方便尋找事件發生或是取得已消逝的LOG紀錄\nkubectl logs\n\n連進去pod裏面監控\n有時會碰到這個pod沒有權限可以安裝htop或 top等等,\n這些看系統效能的東西,\n此時可以透過這種方式,直接外掛一個debug的image,\n就能隨便你亂搞了,還不怕會影響到正在執行的pod。\n下面指令的意思是,連去 filebeat的pod。\n如果要指定container的話,增加 --target=filebeat的指令。\nkubectl debug -it \\\n--container=debug-container \\\n--image=alpine \\\nfilebeat-beat-filebeat-bcb666b79-vm6dt\n\nref.\n- Debugging Running Pods on Kubernetes",
"tags": [ "note","⎈"]
},
{
"title": "http健康度偵測",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/196. http健康度偵測/",
"content": "前言\n最近碰到一個怪問題,pod活得好好的,但裏面的服務就掛了。\n因為我還能連進去pod裏面,裝一堆東西,但服務就真的沒辦法了。\n只好,跟開發溝通,不然就弄個健康度偵測吧,\n但要注意,一定要非常確定這個服務隨時重啓沒關係。\n正文\nlivenessProbe:\nhttpGet:\npath: /Info/LivenessCheck\nport: 80\nscheme: HTTP\ninitialDelaySeconds: 120\ntimeoutSeconds: 1\nperiodSeconds: 5\nsuccessThreshold: 1\nfailureThreshold: 2\n\n當http 回應的狀態碼是 200~400 的話,默認為正常。\n不是這個以外的,就認爲失敗。\n上面的參數\n\ninitialDelaySeconds: pod啓動後幾秒才開始執行\ntimeoutSeconds: timeout時間\nperiodSeconds: 間隔幾秒呼叫一次\nsuccessThreshold: 在檢查失敗後, 接下來要多少次連續判定成功才算成功\nfailureThreshold: 失敗次數\n\nref.\n\nKubernetes — 健康檢查\n組態存活、就緒和啟動探針",
"tags": [ "note","⎈"]
},
{
"title": "k8s的節點選擇與污染",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/27.K8s的節點選擇與污染/",
"content": "前言\n最近碰到的問題,起因是單台的對外連線數過大,導致程式發生問題,無法再連線到外部網路。\n正文\n在 GCP網路對外的方式裡面有提到,對外連線時,如果是私有叢集會使用Cloud NAT,\n本次的情形,是因為再該節點內,某一個deploy疑似將連線數吃滿,最近想通了,應該是節點數量的問題。\nnodeSelector\n所以要將某一個服務,獨立掛在單一的節點池上面。\n最簡單的用法是 nodeSelector,在 spec.template.spec 的下一層。\napp : websocket 這個是label 在建立nodepool時,一併建立的。\n也可在建立nodepool後,在手動新增label。當然也可以直接指定google賦予的label。\n\n查詢label\nkubectl get nodes --show-label\n新增label\nkubectl label node <node name> <label>=<value>\n\nref.\nKubernetes 分派 Pod 到指定節點\ndeploy的範例\napiVersion: apps/v1\nkind: Deployment\nmetadata:\nname: deployabc\nspec:\nreplicas: 10\ntemplate:\nspec:\n.......\nnodeSelector:\napp: websocket\n\nref.\n將 Pod 部署到特定節點池\n將 Pod 分配給節點\n節點污點\n剛上面有提到,deploy可以指定pod到特定的節點,但是當前面的節點滿了後,其他的deploy還是有可能會到特定的節點上。\nk8s可以設定節點為 污點(Taint),使此污染的節點,只能接受有容忍度的pod。\n污點的設定不能事後更新,所以要在一開始建立時就設定好。請注意(fig.2)的Taint。\n另外建議統一由GKE的節點污點,從控制台建立或使用指令建立。\n否則當node自動新增時,該節點並不會產生 Taits\n設定時,要指定 key 與 value 以及 效果。\n\n效果有以下三種:\n- NoSchedule:不能容忍此污點的 Pod 不會被調度到節點上;現有 Pod 不會從節點中逐出。\n- PreferNoSchedule:Kubernetes 會避免將不能容忍此污點的 Pod 安排到節點上。\n- NoExecute:如果 Pod 已在節點上運行,則會將該 Pod 從節點中逐出;如果尚未在節點上運行,則不會將其安排到節點上。\nref.用節點污點控制調度\n之後在deploy上面建立容忍(toleration)污點, 在 spec.template.spec 的下一層\n其中 key 與 value 為自訂,效果請參考上面選擇。\napiVersion: apps/v1\nkind: pod\nmetadata:\nname: deployabc\nspec:\nreplicas: 10\ntemplate:\nspec:\n\t\tcontainer:\n\t .......\n\t\ttolerations:\n\t\t- key: "visible"\n\t\t operator: "Equal"\n\t\t value: "private"\n\t\t effect: "NoExecute"\n\t\t tolerationSeconds: 3600\n\n補充,如果是舊的節點集區,在GKE上面,可以改使用這個label去選擇。\ncloud.google.com/gke-nodepool: <節點池的名稱>\n\nref.\n污點和容忍度\nk8s進階篇(四):Affinity and Anti-Affinity、Taints and Tolerations",
"tags": [ "note","⎈"]
},
{
"title": "k8s PDB(pod中斷預算)",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/42.k8s PDB(pod中斷預算)/",
"content": "前言\nK8S真是 TXD博大精深......,\n沒想到再追<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/GKE/41.GKE節點無法自動縮小/\">41.GKE節點無法自動縮小</a>的時候,會到這邊來。\n正文\n簡單來說,這個設定是用來避免pod被無預警的刪除。\n當發生自願中斷的時候,讓此pod不會因為pod的數量過少,\n而導致服務中斷。\n這個跟 HPA有點像,但HPA是根據設定,來決定pod要不要增加或減少。\n自願中斷通常是下面三種:\n\n排空(drain)節點進行修復或升級\n從集群中排空節點以縮小集群(瞭解集群自動擴縮)。\n從節點中移除一個 Pod,以允許其他 Pod 使用該節點。\n\n我們一般直接下指令看有哪些pdb在系統內\nkubectl get pdb -A\n\n(fig.1)\n建立pdb,主要有兩個參數 看是要設定 minAvailable (最小可用)或 maxUnavailable(最大不可用)。\n建完後,可以看一下ALLOWED DISRUPTIONS 這個欄位,\n這個欄位表示目前該pod可以被中斷的pod數量。\n所以如果為0的話,您的自願中斷那些操作,\n是不會動作的,會一直waiting,直到這個值不為0。\nref.\n\n干擾(Disruptions)\n為應用程序設置干擾預算(Disruption Budget)\nkubernetes之PDB\nkubernetes之PDB",
"tags": [ "note","⎈"]
},
{
"title": "k8s error,The node was low on resource..",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/76. k8s error,The node was low on resource../",
"content": "前言\n之前發生過的,\nprometheus會這樣、gitlab最近在弄新版的CI/CD也跑這個出來。\n本來想要之後有空再解決,但最近被DDOS攻擊時,\n發現監控的grafana會卡住,因為他的prometheus ram爆了~~\n正文\n\n從字面上看來,其實蠻好理解的,\n\nThe node was low on resource: memory. Container web was using 4236080Ki, which exceeds its request of 0.\n\nnode的資源不夠了,container 使用量達到上限。\n最直覺的方式就是,資源不夠,那就加開資源阿。\n但開資源前要先想一下,如果我開了,那未來資源就一定夠嗎?\n開的資源又不一定是完全給prometheus用,他供應的是全體的pod。\n所以要先做的是,把 resources request 的加進去 pod裡面。\n\u001f\ntemplate:\nmetadata:\ncreationTimestamp: null\nlabels:\napp: webhook\nversion: v1\nspec:\ncontainers:\n- image: prom/prometheus:v2.28.0\nimagePullPolicy: Always\nname: prometheus\nports:\n- containerPort: 80\nprotocol: TCP\nresources:\nrequests:\ncpu: 30m\nmemory: 30Mi\nlimits:\nmemory: "128Mi"\ncpu: "500m"\n\n這邊要特別注意 limit,當limit踩到上限時,這個pod就會被終止\n,並引發記憶體不足(OOM)的錯誤。\n所以 limit 要設嗎??\n這邊要從掛載的服務去決定,\n如果今天掛載的服務 ram的使用量通常不多,\n那突然達到上限,是不是可以判斷這個服務有問題了,必須要重啟。\n但如果是使用prometheus,記憶體的量本來就會隨着metric的量而增加,\n那就不適合加上去了,不然只會一直看到 記憶體不足的錯誤。\n後面的單位,可設定 Ki, Mi ,Gi...\n補充,\n當node資源不足時,刪除pod的先後順序為,\n\n沒有設定 request 跟 limit的 pod\n只要有pod設定 request 或 limit ,但使用的資源是比在資源上設置的請求還多。\n只要有pod設定 request 或 limit ,但使用的資源是比在資源上設置的請求還少。\n\n結論\n先設定 request ,因node機器的擴展,是根據 request的值,\n來判斷要不要增加node數量,如果沒設定request,\n系統會認爲,沒有擴展的必要。就會導致前面的問題。\nref.\n\nWhy my pods are evicted on Kubernetes?\n節點壓力驅逐\n為容器管理資源\nHow does scale-up work?",
"tags": [ "note","⎈"]
},
{
"title": "GKE上架設SolrCloud",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/GKE/37.SolrCloud on GKE/",
"content": "正文\nSolr的架構\nref. 淺談Solr叢集架構\n完整架構\n\nSolrCloud是基於 Solr 與 <a class=\"internal-link is-unresolved\" href=\"/404\">blog.36.分佈式系統-Zookeeper</a>搜尋方案。\n特色功能有\n\n集中式的配置資訊\n自動容錯\n近實時搜尋\n查詢時自動負載平衡\n自動分發\n日誌跟蹤\n\nsolrCloud的架構,可以看看以下幾篇。\nref.\n\nExploring the Apache Solr Operator v0.3.0 on GKE\nSolrCloud分佈式企業搜索引擎架構原理解析\nsolrCloud架構\nSolrCloud集群架構\n\n這邊直接開始安裝吧。\n首先確定你的電腦有helm ,我試著找有沒有單純可以用 kubectl apply的方式安裝,但沒找到。所以,用helm吧。\nref.solr-operator\n\n先增加solr的倉庫\n\n\thelm repo add apache-solr https://solr.apache.org/charts\n\n\thelm repo update\t\n\n安裝 solr-operator,指定安裝在 solr的 namespace,避免istio的istio-proxy安裝進去\n\n\tkubectl create -f https://solr.apache.org/operator/downloads/crds/v0.3.0/all-with-dependencies.yaml\n\n\thelm install solr-operator apache-solr/solr-operator \\\n--version 0.3.0 --namespace solr\n\noperator 安裝完成 (fig.1)\n\n(fig.1)\n3. solrCloud.yaml\napiVersion: solr.apache.org/v1beta1\nkind: SolrCloud\nmetadata:\nname: video\nnamespace: solr\nspec:\ncustomSolrKubeOptions:\npodOptions:\nresources:\nlimits:\nmemory: 3Gi\nrequests:\ncpu: 700m\nmemory: 3Gi\ndataStorage:\npersistent:\npvcTemplate:\nspec:\nresources:\nrequests:\nstorage: 2Gi\nreclaimPolicy: Delete\nreplicas: 3\nsolrImage:\nrepository: solr\ntag: 8.8.2\nsolrJavaMem: -Xms500M -Xmx500M\nupdateStrategy:\nmethod: StatefulSet\nzookeeperRef:\nprovided:\nchroot: /explore\nimage:\npullPolicy: IfNotPresent\nrepository: pravega/zookeeper\ntag: 0.2.9\npersistence:\nreclaimPolicy: Delete\nspec:\naccessModes:\n- ReadWriteOnce\nresources:\nrequests:\nstorage: 2Gi\nreplicas: 3\nzookeeperPodPolicy:\nresources:\nlimits:\nmemory: 500Mi\nrequests:\ncpu: 250m\nmemory: 500Mi\n\n佈署 solrCloud.yaml,這邊的系統資源要求頗高,資源不夠請多開一些cpu 或 memory。\n\n\tkubectl apply -f solrCloud.yaml\n\n由於我是直接佈署在istio上面,所以開啟網頁的話,我是直接新增 virtualService的設定。\n\nkind: VirtualService\nmetadata:\nname: istio-virtualservice-tools\nnamespace: tools\nspec:\nhosts:\n- "*"\ngateways:\n- istio-gateway-tools.istio-system.svc.cluster.local\nhttp:\n- match:\n- uri:\nexact: /\n- uri:\nprefix: /solr\nname: solr\nroute:\n- destination:\nhost: video-solrcloud-common.solr.svc.cluster.local\nport:\nnumber: 80\n\n也可以直接在本機上使用port-forward轉發開啟網頁。如以下指令,開啟 網頁 http://localhost:8080 (fig.2)\n\tkubectl port-forward service/video-solrcloud-common -n solr 8080:80\n\n監控 solrCloud\n本來的solrCloud舊有簡易的監控畫面了,\n這部分是看記憶體的使用量。\n\n但可有發現資料並不是非常得多。\n之前在GKE的叢集上已經有架設prometheus了,\n所以這次也要將資料丟進去prometheus裡面。\n這邊要先export solr的metric,\n官方 github上面有建議的方法 ,但需安裝 prometheus operator。如果沒有安裝,prometheus 在探索metrics時,是找不到這個exporter的。\nref.Deploy Prometheus Exporter for Solr Metrics,\napiVersion: solr.apache.org/v1beta1\nkind: SolrPrometheusExporter\nmetadata:\nlabels:\ncontroller-tools.k8s.io: "1.0"\nname: explore-prom-exporter\nnamespace: solr\nspec:\ncustomKubeOptions:\npodOptions:\nresources:\nrequests:\ncpu: 300m\nmemory: 800Mi\nsolrReference:\ncloud:\nname: "video"\nnumThreads: 6\nimage:\nrepository: solr\ntag: 8.8.2\n---\napiVersion: monitoring.coreos.com/v1\nkind: ServiceMonitor\nmetadata:\nname: solr-metrics\nlabels:\nrelease: prometheus-stack\nspec:\nselector:\nmatchLabels:\nsolr-prometheus-exporter: explore-prom-exporter\nnamespaceSelector:\nmatchNames:\n- solr\nendpoints:\n- port: solr-metrics\ninterval: 15s\n\n因為我不想裝 prometheus operator,所以複製上面安裝的deploy yaml,自己產生一個solr exporter 的deploy跟 service給 prometheus抓資料。\n或許有人會問,為什麼不利用上面的部屬完後去修改service.yaml把\nprometheus.io/port: "80"\n改成\nprometheus.io/port: "8080"\n就好了。\n因為,改了後他會一直還原成舊的狀態。\n這應該是 solrOperator的關係,會一直覆蓋手動修改的設定,因為我也找不到去修改增加solrOperator的設定,讓80改成8080,所以應該透過上面的 ServiceMonitor 來讓prometheus可以取得資料。\napiVersion: apps/v1\nkind: Deployment\nmetadata:\nnamespace: solr\nname: explore-prom-exporter\nannotations:\ndeployment.kubernetes.io/revision: "1"\n# generation: 1\nlabels:\ncontroller-tools.k8s.io: "1.0"\nsolr-prometheus-exporter: explore-prom-exporter\ntechnology: solr-prometheus-exporter\nspec:\nprogressDeadlineSeconds: 600\nreplicas: 1\nrevisionHistoryLimit: 10\nselector:\nmatchLabels:\nsolr-prometheus-exporter: explore-prom-exporter\ntechnology: solr-prometheus-exporter\nstrategy:\nrollingUpdate:\nmaxSurge: 25%\nmaxUnavailable: 25%\ntype: RollingUpdate\ntemplate:\nmetadata:\ncreationTimestamp: null\nlabels:\ncontroller-tools.k8s.io: "1.0"\nsolr-prometheus-exporter: explore-prom-exporter\ntechnology: solr-prometheus-exporter\nspec:\ncontainers:\n- args:\n- -p\n- "8080"\n- -n\n- "6"\n- -z\n- video-solrcloud-zookeeper-0.video-solrcloud-zookeeper-headless.solr.svc.cluster.local:2181,video-solrcloud-zookeeper-1.video-solrcloud-zookeeper-headless.solr.svc.cluster.local:2181,video-solrcloud-zookeeper-2.video-solrcloud-zookeeper-headless.solr.svc.cluster.local:2181/explore\n- -f\n- /opt/solr/contrib/prometheus-exporter/conf/solr-exporter-config.xml\ncommand:\n- /opt/solr/contrib/prometheus-exporter/bin/solr-exporter\nimage: solr:8.8.2\nimagePullPolicy: IfNotPresent\nlivenessProbe:\nfailureThreshold: 3\nhttpGet:\npath: /metrics\nport: 8080\nscheme: HTTP\ninitialDelaySeconds: 20\nperiodSeconds: 10\nsuccessThreshold: 1\ntimeoutSeconds: 1\nname: solr-prometheus-exporter\nports:\n- containerPort: 8080\nname: solr-metrics\nprotocol: TCP\nresources:\nrequests:\ncpu: 300m\nmemory: 800Mi\nterminationMessagePath: /dev/termination-log\nterminationMessagePolicy: File\ndnsPolicy: ClusterFirst\nrestartPolicy: Always\nschedulerName: default-scheduler\nsecurityContext:\nfsGroup: 8080\nterminationGracePeriodSeconds: 10\n\n---\n\napiVersion: v1\nkind: Service\nmetadata:\nnamespace: solr\nname: explore-prom-exporter\nannotations:\nprometheus.io/path: /metrics\nprometheus.io/port: "8080"\nprometheus.io/scheme: http\nprometheus.io/scrape: "true"\ncreationTimestamp: "2021-09-03T05:52:23Z"\nlabels:\ncontroller-tools.k8s.io: "1.0"\nservice-type: metrics\nsolr-prometheus-exporter: explore-prom-exporter\nspec:\nports:\n- name: solr-metrics\nport: 80\nprotocol: TCP\ntargetPort: 8080\nselector:\nsolr-prometheus-exporter: explore-prom-exporter\ntechnology: solr-prometheus-exporter\nsessionAffinity: None\ntype: ClusterIP\n\n最後到prometheus看一下有沒有關於solr的資料(fig.4)\n\n(fig.4)\n有資料了,但我們不知道要拿哪些metrics來作爲監控的資料,就先去grafana dashboard找找吧。\nSolr Dashboard\n下載,匯入grafana收工。\nref. Solr Prometheus Exporter\n結尾\n再來就是,實際操作 <a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/GKE/39.solrCloud的初體驗/\">39.solrCloud的初體驗</a>了\n額外參考,雖然此連結已經不適用,但基本的安裝方式是可以參考。\nRunning Solr on Kubernetes",
"tags": [ "note","⎈"]
},
{
"title": "solrCloud的初體驗",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/GKE/39.solrCloud的初體驗/",
"content": "正文\n傻瓜操作,都是在UI上面執行。\n但solr都是使用api的方式做動作。\n所以下面的操作改成api是也可行的。\n基本篇\n\n新增資料\n\n查詢資料\n\n基本的查詢方式,\n如果要查筆數的話,將rows 改成 0 ,就會列出所有筆數。\n但不會顯示任何資料。\n刪除所有資料\n如果要刪除單筆,只要修改條件即可\n將 : 改成要搜尋的條件,\n(e.g. videoId: 28748)\n\n\t<delete><query>*:*</query></delete>\n\t<commit/>\n\nref.\nsolr刪除資料的四種方法\nSolr官方文檔\n進階篇\n\n查詢指令\n\nref.\nSolr 查詢參數\nsolr搜尋詳解\nSolr查詢界面\n\n查看collection的架構\n\n\thttp http://<host>:<port>/solr/<collectionName>/schema/fields\n\nref. Schema API\n\n搜尋中文字,欄位結構 text_general vs string\n\n一般我們搜尋中文要額外安裝中文分詞,這樣搜尋關鍵字的時候,才會正確。\n沒裝的話,會有下面的情況。\n例如,搜尋 『中文』 ,但這樣會將欄位裡面除了有『中文』的資料撈出來以外,還會將資料中有『中』的字取出。\n但後來同事有發現另一種解法,建立結構的時候,不能選擇 text_general,必須要選 string。\n如果使用string的話,要注意的是只接受完整的文字搜尋。也就是一串文字中,搜尋的關鍵字要完全符合才會顯示。\n而text_general,可接受部分的文字搜尋,但缺點就是搜尋中文時,會有上面的狀況。\n結構使用string的話,如果改使用\n\t*中文*\n\n這種搜尋方式,就只會搜尋資料中有『中文』關鍵字的資料,字串不會被拆開查詢。\n本來是要使用中文分詞,但後來也不用了。\n\nsolr的外掛套件\n\n本來官方是提供blob store API安裝套件,\n但在 solrCloud 8.4 ,有多出了一個功能 package managr\n可使用簡單且快速的方式安裝plugin。\n但因為上面的第三點,所以也不用研究這塊了。\n留下一些參考網址,留着以後查詢。\n初步看都是在solr 啟動時要加一個指令\n-Denable.packages=true\n\n這個應該是在yaml佈署的時候,就要加上去了。\nyaml佈署時,為容器設置啟動時要執行的命令和參數\n也有在猜測,未來應該是可以直接使用 solr operator安裝的時候一並設定,但目前參數沒有看到,看未來會不會新增。Solr Operator\nref.\n\nPackage Management\nSolr 8.4.0 – Plugin Management\nWorking with Solr Plugins System\n在SolrCloud模式下添加自定義插件",
"tags": [ "note","⎈"]
},
{
"title": "GKE使用GPU",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/GKE/4. GKE使用GPU/",
"content": "前言\n接了一個工作,要幫人在GKE上面生一個能夠使用GPU的叢集,並且佈署。\n正文\n要使用Google上面的 GPU,GKE版本要到1.9以上,\n節點池要到1.11.3以上。\n另外,GPU只支援通用N1的機器支援,其他細項 請詳閱 Google 運行 GPU\n可用性建議先用\ngcloud compute accelerator-types list\n看一下你的區域支援哪些顯卡,\n像我這邊的是 asia-east1-a ,就只支援特定顯卡。\n\n到 安裝 NVIDIA GPU 設備驅動程序,這邊基本上都沒問題。\nkubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/master/nvidia-driver-installer/cos/daemonset-preloaded.yaml\n這主要會裝在每個節點上的Daemonset,當pod起來後,會自動在pod上面安裝驅動程式。\n所以必須檢查一下,看pod是否有起來。\n\n也可以執行\nkubectl describe node -l cloud.google.com/gke-accelerator | grep nvidia.com/gpu\n看顯卡的使用情況\n當執行下一步驟配置 Pod 以使用 GPU時,這邊就會有問題了。\n他的image(nvidia/cuda:10.0-runtime-ubuntu18.04)會無法啟動,一直在crashLoopbackoff。\n更新\n在12/24有開工單詢問,他們那邊給出了解法。後續應該會改他們的文件。\n\ngoogle的回覆如下\n按照文檔簡單使用“command: ["/bin/bash"]”測試。此時bash執行後立刻退出,故pod被重啟。\n你們可以嘗試使用以下死循環避免這個問題:\ncommand: [ "/bin/sh", "-c", "--" ]\nargs: [ "while true; do sleep 600; done;" ]\n\n所以,可以改成下面的YAML,就能正常執行了。\napiVersion: v1\nkind: Pod\nmetadata:\nname: gpu-pod\nspec:\ncontainers:\n\nname: digits-container\nimage: nvidia/cuda:10.0-runtime-ubuntu18.04\ncommand: [ "/bin/sh", "-c", "--" ]\nargs: [ "while true; do sleep 600; done;" ]\nresources:\nlimits:\nnvidia.com/gpu: 1\n\n以下也可以使用\n最後的解法是,不要用他的image。\n完整 YAML\napiVersion: v1\nkind: Pod\nmetadata:\nname: gpu-pod\nspec:\ncontainers:\n- name: digits-container\nimage: nvidia/digits:6.0\nresources:\nlimits:\nnvidia.com/gpu: 1\n佈署完後,執行\nkubectl exec gpu-pod -- nvidia-smi\n這段話的意思是,在gpu-pod裡面執行 nvidia-smi的指令\n正常的話,會顯示如下\n\n下面參考的文件,可以看看,但目前只需要做到上面那段『安裝 NVIDIA GPU 設備驅動程序』的指令即可\nref.\nCrashLoopBackOff message wen running GPU Jobs example and others\nGPU Sharing on GKE DaemonSet\nInstall GPU in GKE(Google Kubernetes Engine)(中)\n查詢各有哪些VM使用GPU的指令\ngcloud compute instances list --format="table(guestAccelerators.acceleratorCount, name)"",
"tags": [ "note","⎈"]
},
{
"title": "GKE節點無法自動縮小,查錯之旅",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/GKE/41.GKE節點無法自動縮小/",
"content": "前言\n果然東西穩定之後,上面的都會想要costDown,\n不過這也算是當初建立的人沒設定好,\n會發生這個情況,後續也查明了,當初在每個節點上只允許放64個pod,\n所以就算放滿,也吃不到那麼多。\n但沒有自動縮小,這其實也是個問題,但要自動縮小,\n還要看這個服務是否合適...。\n反正我之後反而沒在糾結這個狀況了。\n正文\n最近發現一個東西,在GKE上面的節點,cpu分配很奇怪。\n\n(fig.1)\n每個node的節點都只佔了一半的CPU就去開新的節點了。\n本來懷疑是自動擴展有問題,\n後來發現應該是自動縮小有問題。\n這個狀況在新建一個叢集,然後設定節點自動伸縮就會發生了。\n一般來說,節點只要沒有pod在裡面,大約只要十分鐘就會把多餘的節點移除了。\nref. 集群自動擴縮程序的工作原理\n但新建了一個節點池,裡面都空的。他並沒有縮小到最小節點。\n詢問後得知,須先看一下log才能知道為什麼沒有自動縮小。\n首先開啟 GCP的日誌查看器,\na. 資源選擇 Kubernetes Cluster\nb. 日誌類型列表選擇\ncontainer.googleapis.com/cluster-autoscaler-visibility\n\nc. 再選擇要查看的cluster name\n\n(fig.2)\nd. 展開 noDecisionStatus\n\n(fig.3)\n看到錯誤了,就是這個害得pod無法自動縮減。\n這邊的錯誤訊息是\nnode.pod.has.local.storage,\n新建節點無法縮減會出現的錯誤訊息通常是\nnode.kube.system.unmovable\n\n(fig.4)\n碰到 node.pod.has.local.storage的解法是在deploy的yaml上面加上註釋,位置位於 metadata底下\nannotations:\n\tcluster-autoscaler.kubernetes.io/safe-to-evict: "true"\n\n(fig.5)\nref.\n\n集群未縱向縮容\nHow to make sure Kubernetes autoscaler not deleting the nodes which runs specific pod\n\n至於碰到 node.kube.system.unmovable 的解法,\n需建立 PDB ,讓在 namespace 的 kube-system可以被驅逐。PDB是什麼可參考 <a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/42.k8s PDB(pod中斷預算)/\">42.k8s PDB(pod中斷預算)</a>。\nkubectl create poddisruptionbudget <pdb name> --namespace=kube-system --selector app=<app name> --max-unavailable 1\n\n要注意,selector的label不一定是app開頭,\n要看各deploy裡面的設定。\n最近碰到在GKE的kube-system裡面pod label,\n反而是叫 k8s-app:kube-dns,selector可以隨意選擇,只要有辦法對到deploy即可\n\n(fig.6)\nHow to set PDBs to enable CA to move kube-system pods?\n但後來有發現一個問題,當解了一個 node.kube.system.unmovable ,後續可能會出現 node.pod.has.local.storage的問題,\n這樣會變成必須針對每個deploy都額外做設定。\n所以最後我選擇了,直接手動驅逐節點內的pod,\n但pdb的設定要先看一下,\nistio在安裝時,ingressgateway會同時設定pdb,\n當pod只有1個的時候,是沒辦法驅逐的,\n所以最好是預設ingressgateway 為 2個pod,這樣才能避免pdb的干擾,而導致無法驅逐。\nkubectl drain [node-name] --force --ignore-daemonsets --delete-local-data\n\ndrain的參數\n--force\n當一些pod不是經 ReplicationController, ReplicaSet, Job, DaemonSet 或者 StatefulSet 管理時\n就需要用--force來強制執行 (例如:kube-proxy)\n--ignore-daemonsets\n無視DaemonSet管理下的Pod\n--delete-local-data\n如果有mount local volumn的pod,會強制殺掉該pod並把資料清除掉\n另外如果跟本身的配置訊息有衝突時,drain就不會執行\nref.\n\nKubernetes中清空一個node的所有pod\n文件-遷移工作負載",
"tags": [ "note","⎈"]
},
{
"title": "srs 影音串流 on GKE",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/GKE/44.srs 影音串流 on GKE/",
"content": "前言\n首先介紹一下srs,這個就是一個影音串流,\n本來是乖乖再用EFK on GKE,然後說網路有問題,\n就又被抓去協助了,想裝死還不行 T_T ,\n我的東西還不夠多嗎 (╯‵□′)╯︵┴─┴\n正文\n這次主要是協助除錯,\n所以下面就直接列出碰到的問題點。\n由於我沒玩過直撥,有些概念是後來才知道的。\n也會順便列在下面。\n\nwebrtc推流時,出現 getUserMedia error\n\n需要到chrome上面修改設定。\n\nref.解決 ‘GETUSERMEDIA’ OF UNDEFINED 問題\n\nrtmp 推拉\n\n走TCP的協定\n使用rtmp播放的話,所有的連線都會在伺服器上面留一份。\n\nwebrtc播放\n\n需要到srs 4.0.14以後的版本\n有TCP跟 UDP的協定,\n伺服器只負責對 直撥者跟觀看者做驗證,\nwebrtc,是直撥者跟觀看者直接連線,也就是點對點的連接方式。\nref. 何謂WebRTC\n\nwebrtc觀看方式\n\n也是這一部分的網路架構,導致我不得不跳下去協助處理。\n因為GKE的service 負載平衡目前還不支援混合的網路架構,\n也就是TCP跟 UDP 混合使用。只能使用單一個協定。\n所以沒辦法像傳統機器一樣,直接一個ip,同時開啟TCP跟UDP的網路協定。\n所以會變成 TCP 一個IP,UDP又是一個IP(fig.1),\n\n此時在SRS上面的 Candidate ,必須要設定 *\n然後再推流的時候,推流網址要更改成\nwebrtc://35.2.3.1/live/ray123?eip=35.3.3.50\n\n35.2.3.1 是 只開TCP的外網位置。\n35.3.3.50 是 只開UDP的外網位置。\nref.\nv4_CN_WebRTC\n[SRS+docker]實現直播服務器 3 基於webRTC協議的srs低延遲直播研究_wltsysterm的博客-程序員秘密\n\n其他參考文件\n\n當然最好的方式,是把裡面的文件大約掃過一下。\n但這資料有點多,我也只挑了幾個重點看。\nref.\n\nv4_CN_K8S\n當SRS遇到K8s:如何實現高可用、回滾與灰度發布?\n使用 Linux nc 測試UDP有沒有通\nSRS全文件\nSRS full.conf",
"tags": [ "note","⎈"]
},
{
"title": "GKE workload Identity 實地演練",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/GKE/50.GKE workload Identity 實地演練/",
"content": "前言\n某位大神說,GKE使用 IAM的角色認證安全性不太夠,\n所以希望未來都改用這種,workload Ideneity,\n就開始了採坑之旅,是說這個坑沒想像中的深。\n正文\n查詢cluster是否有 workload Identity\ngcloud container clusters describe yaboxxx-test -z asia-east1-b\n\n建議最好直接加上地區,不然看錯誤訊息也是可以。\n會說在某個地區找不到此cluster\n修改cluster ,啟用 Workload Identity\ngcloud container clusters update istio-test -z asia-east1-b \\ --workload-pool=rd7-project.svc.id.goog\n\n修改 node-pool\ngcloud container node-pools update defaultpool -z asia-east1-b \\ --cluster=istio-test \\ --workload-metadata=GKE_METADATA\n\n如果成功的話,會看到\nGKE 中繼資料伺服器 : 已啟用\n\n建立ns\nkubectl create ns token-proxy\n\n建立kubernetes 帳號\nkubectl create serviceaccount -n token-proxy proxy-user\n\n申請 Google service accout的 IAM 服務帳號,\n然後綁定 kubernetes service account 與 Google service account 。\ngcloud iam service-accounts add-iam-policy-binding \\ --role roles/iam.workloadIdentityUser \\ --member "serviceAccount: project.svc.id.goog[token-proxy/proxy-user]" \\ token-proxy@rd7-project.iam.gserviceaccount.com\n\n在 kubernet service account上面,增加註釋\nkubectl annotate serviceaccount \\ --namespace token-proxy proxy-user \\ iam.gke.io/gcp-service-account=token-proxy@rd7-project.iam.gserviceaccount.com\n\nref.\n使用 Workload Identity",
"tags": [ "note","⎈"]
},
{
"title": "GKE記錄 nginx log",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/GKE/56. GKE記錄 nginx log/",
"content": "前言\n因前陣子被人用DDOS攻擊,\n然後公司有一個單位就跑出來了,說他們要nginx的log,\n發生當下才能作為分析用途。\n正文\nnginx 版本 1.21.4\n更改nginx config ,\n將\naccess_log /dev/stdout main;\nerror_log /dev/stderr;\n\n放在 http 底下的 service內。\n這樣就會把log 訊息,使用標準輸出的方式列印到機器上。\nGKE就能抓到記錄了。\n然後使用 ECK的filebeat ,預設是會去抓各個log的資料。\n但前提是要有標準輸出,所以這邊就不用設定了。\n完整config 如下\n\n#user nobody;\nworker_processes 1;\n\nerror_log /var/log/nginx/error.log warn;\npid /var/run/nginx.pid;\n\nevents {\nworker_connections 1024;\n}\n\nhttp {\ninclude /etc/nginx/mime.types;\ndefault_type application/octet-stream;\n\nlog_format main '$remote_addr - $remote_user [$time_local] , '\n'http-host: "$http_host" , URL: "$request" , request-status : "$status" , '\n'body-byte: $body_bytes_sent ,http-referer: "$http_referer" ,'\n'user-agent: "$http_user_agent" , X-Forwarded-For : "$http_x_forwarded_for" , '\n' request-time: "$request_time" , response_time : "$upstream_response_time" ';\n\nsendfile on;\n#tcp_nopush on;\n\nkeepalive_timeout 65;\n\n#gzip on;\n\nserver {\nlisten 80;\nlisten [::]:80;\nroot /app;\nlisten 443 ssl;\nlisten [::]:443 ssl;\n\nserver_name _;\n\nssl off;\nssl_certificate /etc/nginx/nginxssl.crt;\nssl_certificate_key /etc/nginx/nginxssl.key;\n\nssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;\nssl_protocols TLSv1 TLSv1.1 TLSv1.2;\nssl_prefer_server_ciphers on;\n\naccess_log /dev/stdout main;\nerror_log /dev/stderr;\n\nlocation / {\ntry_files $uri /index.php$is_args$query_string;\n}\n\nlocation ~ \\.php$ {\nfastcgi_pass 127.0.0.1:9000;\nfastcgi_index index.php;\nfastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;\ninclude fastcgi_params;\n}\n}\n\n}\n\nref.\n\nNginx配置中的log_format\nLinux – Nginx log 格式\ndocker運行nginx為什麼要使用 daemon off\nHave nginx access_log and error_log log to STDOUT and STDERR of master process",
"tags": ["user", "tcp_nopush", "gzip", "note","⎈"]
},
{
"title": "GKE pvc還原",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/GKE/70. GKE pvc還原/",
"content": "前言\n之前的Gitlab建在GKE的公開叢集上,\n雖然有限定IP訪問,一直要改到私有叢集上,\n但一直沒時間動,現在終於有空弄了,首先要解決的是資料還原的問題。\n正文\n首先在GCE上面複製一個磁碟,\n可以先從GKE上面的pod找到當初建立的pvc名稱,\n再根據這個名稱去找。\n\n再來就建立pv 跟 pvc了。\napiVersion: v1\nkind: PersistentVolume\nmetadata:\nname: test-pv\nnamespace: default\nspec:\n# persistentVolumeReclaimPolicy: Delete\nstorageClassName: "standard"\ncapacity:\nstorage: 300G\naccessModes:\n- ReadWriteOnce\nclaimRef:\nnamespace: default\nname: test-upload\ngcePersistentDisk:\npdName: test-upload\nfsType: ext4\n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\nname: test-upload\nnamespace: default\nspec:\nstorageClassName: "standard"\naccessModes:\n- ReadWriteOnce\nresources:\nrequests:\nstorage: 300G\n\npv的 gcePersistentDisk ,是剛剛複製的硬碟名稱。\n將裡面的參數改一改,\n要建立的 name,namespace,storage, claimRef ,\n結束。\ndeployment使用正常方式直接掛載即可。\ntemplate:\nmetadata:\ncreationTimestamp: null\nlabels:\napp: video-admin\nversion: v1\nspec:\ncontainers:\n- name: video\n...\nvolumeMounts:\n- mountPath: /upload\nname: source\ndnsPolicy: ClusterFirst\nrestartPolicy: Always\nterminationGracePeriodSeconds: 30\nvolumes:\n- name: source\npersistentVolumeClaim:\nclaimName: test-upload\n\n如果是statefuleSet的話,\npv的名稱需要改成 statefulSet的命名規則。\nstatefulSet不會用到pvc。\nVC_TEMPLATE_NAME-STATEFULSET_NAME-REPLICA_INDEX\n\nVC_TEMPLATE_NAME:新 PersistentVolumeClaim 模板的名稱。\nSTATEFULSET_NAME:新 StatefulSet 的名稱。\nREPLICA_INDEX:StatefulSet 副本的索引。此示例使用的是 0 和 1。\n\n注意,刪除pvc時,最好將pv也刪除,避免發生未知情況。\n如碰到下圖情況,表示pv有問題,請刪除重建。\n\nref.\n\n將原有永久性磁盤用作 PersistentVolume\n永久性卷和動態預配",
"tags": [ "note","⎈"]
},
{
"title": "gitlab on GKE 災害還原筆記",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/GKE/71.gitlab on GKE 災害還原筆記/",
"content": "前言\n之前一直沒寫的gitlab yaml,再文章的最下方。\n本片文章都是使用這個yaml做建立及佈署。\n正文\nStep 0.\n之前一直沒寫的gitlab yaml,再文章的最下方。\n本片文章都是使用這個yaml做建立及佈署。\nStep 1.\n先參考上篇 <a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/GKE/70. GKE pvc還原/\">70. GKE pvc還原</a>,建立好PVC。\n主要複製Gitlab的位置為\n- name: config\nmountPath: /etc/gitlab\n- name: gitlab-data\nmountPath: /var/opt/gitlab/git-data\n- name: postgres-data\nmountPath: /var/opt/gitlab/postgresql\n\n由於我之前建立的image為 last版本(應該是快一年前的事),\n這次我用last版本的話,版本超前太多,導致一直重開機。\n後來查我的gitlab版本為 14.0.1,\n但裝上去後一直碰到這個錯誤\n\nrelation "services" does not exist after upgrade to 14.2.0\n\n解決方式:\n後來將版本升級到 14.1.1 後就好了。\nref.\n\nERROR: relation "services" does not exist after upgrade to 14.2.0\n\nStep 2.\n用本來的帳號密碼能登入,沒問題。\n增加新的git remote 位置,\n然後試著推一個版本上去時,又出現錯誤了。這次比較好理解。\n\nremote: HTTP Basic: Access denied\n\n解決方式:\n跑去另一個空目錄,git clone ,會要輸入帳號密碼,輸入後就好了。\nStep 3.\n如果看過之前的文章,可能知道我有在用istio,\n會碰到要用一個ip暴露不同的服務。\n解決方式:\nexternal_url "http://{ip}/gitlab"\nvirtualservice直接改\nspec:\nhosts: []\nhttp:\n- match:\n- uri:\nprefix: /gitlab\nname: gitlab\nroute:\n- destination:\nhost: gitlab-svc.default.svc.cluster.local\nport:\nnumber: 80\n\nref.\n\nConfigure a relative URL for GitLab\n\nGitlab yaml\n現在也有gitlab operator跟 helm 可以做,有興趣的可以參考一下官方文件。\napiVersion: v1\nkind: Service\nmetadata:\nname: gitlab-svc\nspec:\nports:\n- name: "web"\nport: 80\ntargetPort: 80\n- name: "ssh"\nport: 22\ntargetPort: 22\n- name: "ssl"\nport: 443\ntargetPort: 443\nselector:\nio.kompose.service: web\ndrone: gitlab\ntype: LoadBalancer\nloadBalancerIP: 123.123.123.123\nloadBalancerSourceRanges:\n- 192.168.0.0/16\n- 172.16.0.0/12\n- 10.0.0.0/8\n\n---\n\napiVersion: apps/v1\nkind: Deployment\nmetadata:\nname: gitlab\nlabels:\nio.kompose.service: web\nspec:\nreplicas: 1\nselector:\nmatchLabels:\nio.kompose.service: web\ntemplate:\nmetadata:\nlabels:\nio.kompose.service: web\nspec:\ncontainers:\n- env:\n- name: GITLAB_TIMEZONE\nvalue: Taipei\n- name: GITLAB_OMNIBUS_CONFIG\nvalue: |\nexternal_url "http://123.123.123.123/gitlab"\ngitlab_rails['gitlab_default_projects_features_builds'] = false\nimage: gitlab/gitlab-ce:14.1.1-ce.0\nname: web\nports:\n- containerPort: 80\nresources: {}\nvolumeMounts:\n- name: config\nmountPath: /etc/gitlab\n- name: gitlab-data\nmountPath: /var/opt/gitlab/git-data\n- name: postgres-data\nmountPath: /var/opt/gitlab/postgresql\nrestartPolicy: Always\nserviceAccountName: ""\nvolumes:\n- name: config\npersistentVolumeClaim:\nclaimName: gke-drone-web-claim0\n- name: gitlab-data\npersistentVolumeClaim:\nclaimName: gke-drone-repository-data\n- name: postgres-data\npersistentVolumeClaim:\nclaimName: gke-drone-gitlab-postgresql\n\nPVC的建立,請參考<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/GKE/70. GKE pvc還原/\">70. GKE pvc還原</a>,如要建立空的,\n參考下方yaml\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\ncreationTimestamp: null\nlabels:\nio.kompose.service: web-claim0\nname: gke-drone-web-claim0\nspec:\naccessModes:\n- ReadWriteOnce\nresources:\nrequests:\nstorage: 20Gi\nstatus: {}\n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\nlabels:\ngitlab-data: gitlab\nname: gke-drone-repository-data\nspec:\naccessModes:\n- ReadWriteOnce\nresources:\nrequests:\nstorage: 100Gi\n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\nlabels:\ngitlab-data: postgresql\nname: gke-drone-gitlab-postgresql\nspec:\naccessModes:\n- ReadWriteOnce\nresources:\nrequests:\nstorage: 100Gi",
"tags": [ "note","⎈"]
},
{
"title": "用chatGPT學Terraform",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/Terraform/147. 用chatGPT學Terraform/",
"content": "睡睡念\n終於要來試試看terraorm了,\n現在公司好像很少全部k8s,\n大部分還是用虛擬機,這樣變成還是要把terraform學一下。\n正文\nTerraform跟ansible的差異\n\n差異點\nTerraform\nAnsible\n\n組態檔案管理 vs 組態\nTerraform使用組態檔案管理基礎設施,描述其狀態,而不是配置。\nAnsible基於主機的管理,直接配置基礎設施。\n\n可變基礎設施 vs 不可變基礎設施\nTerraform以可變的方式管理基礎設施,可以對基礎設施進行更改。\nAnsible通常將基礎設施視為不可變的,一旦配置,它們就不再更改。\n\n過程式的 vs 聲明式的\nTerraform是過程式的,會循序漸進地執行創建、修改和刪除操作。\nAnsible是聲明式的,描述了期望的最終狀態,而不是執行一系列步驟來實現它。\n\nMaster vs Masterless\nTerraform通常使用單一主節點管理基礎設施狀態。\nAnsible可以在主節點和無主節點(即agentless)模式下運行。\n\nAgent vs Agentless\nTerraform不需要在目標基礎設施上安裝任何代理。\nAnsible需要在目標基礎設施上安裝一個代理。\n\n成熟 vs 前沿\nTerraform是成熟的基礎設施自動化工具,已被廣泛使用。\nAnsible是一個新興的基礎設施自動化工具,並且正在積極發展。\n\n綜合使用多種工具\nTerraform與其他工具集成,如Packer、Docker和AWS CloudFormation等。\nAnsible與其他工具集成,如Jenkins、Docker和Kubernetes等。\n\n安裝\n官網安裝最快了,上面有各個平臺的安裝方式。\n詠唱\n我先問了一下chatGPT怎麼學Terraform,然後給了我很標準的答案。\n\n閱讀Terraform官方文檔,熟悉其基礎結構、功能和概念。\n安裝Terraform,並學習如何使用它來創建基礎設施。\n開始使用Terraform的示例項目,並嘗試使用它們創建簡單的基礎設施。\n學習如何使用Terraform管理不同的基礎設施提供者,如AWS、Azure、Google Cloud等。\n閱讀Terraform的模塊化文檔,並學習如何使用模塊化設計來管理複雜的基礎設施。\n學習如何使用Terraform命令列工具來測試和調試基礎設施代碼。\n研究Terraform的最佳實踐,包括如何管理機密、編寫可重用的代碼和設計可擴展的基礎設施。\n\n我還是直接從實際案例來看好了,\nQ: 幫我建立一個部署deployment的terrform程式碼\nA:\n# 定義Kubernetes provider\nprovider "kubernetes" {\nconfig_context_cluster = "my-cluster"\n}\n\n# 定義deployment\nresource "kubernetes_deployment" "my_deployment" {\nmetadata {\nname = "my-deployment"\nlabels = {\napp = "my-app"\n}\n}\n\nspec {\nreplicas = 3\n\nselector {\nmatch_labels = {\napp = "my-app"\n}\n}\n\ntemplate {\nmetadata {\nlabels = {\napp = "my-app"\n}\n}\n\nspec {\ncontainer {\nimage = "my-image:latest"\nname = "my-container"\n}\n}\n}\n}\n}\n\n看了一下他提供的程式碼,有點問題,然後接着問\nQ:resouce 宣告 kubernetes_deployment my_deployment 是要跟deployment的name一樣嗎\nA:\n\n是的,kubernetes_deployment的metadata區塊中的name屬性會定義Kubernetes deployment的名稱,您需要將其設定為與實際的deployment名稱相同。\n\n然後在後續的對談過程中,發現另一個指令。\nterraform import\n\n再緊接着問,這個的功用是什麼。\nA:\nterraform import是Terraform提供的一個命令,用於將現有的資源引入Terraform管理的狀態中。使用terraform import可以讓Terraform瞭解現有資源的狀態,並允許你使用Terraform管理這些資源,並在需要時進行更改。\n通常情況下,Terraform會從頭開始創建和管理所有資源。然而,在實際環境中,有時候會存在一些已經存在的資源,這些資源可能是手動創建的,或者是由其他工具創建的。這些資源可能包括Kubernetes deployment、AWS EC2實例、GCP虛擬機等等。在這種情況下,使用terraform import命令可以將這些現有資源引入到Terraform管理的狀態中,以便Terraform能夠管理它們。\n使用terraform import命令時,需要指定要引入的資源的類型和ID,以及要對應到Terraform的哪個資源。Terraform將使用提供的資源類型和ID尋找現有資源的狀態,並將其對應到Terraform組態檔案中的相應資源。一旦資源成功被引入,Terraform就可以開始管理它們,並將它們的狀態保存到狀態檔案中,這樣就可以使用terraform plan、terraform apply等命令進行更改。\n如果不知道怎麼用沒關係,\n再問一下,\nQ:該怎麼使用terraform import\nA:\n使用terraform import命令引入現有資源到Terraform管理的狀態中,通常需要以下步驟:\n\n在Terraform組態檔案中定義資源的組態,例如使用kubernetes_deployment定義Kubernetes deployment的組態。\n執行terraform init初始化Terraform,以設置Terraform的工作目錄和相關外掛。\n執行terraform import命令引入現有資源。例如,要引入Kubernetes deployment,可以使用以下命令:\n\nterraform import kubernetes_deployment.systemservice deployment2k7\n\n這裡的kubernetes_deployment.systemservice指的是在Terraform組態檔案中定義的Kubernetes deployment資源,deployment2k7則是現有Kubernetes deployment的名稱或ID。通過這樣的方式,Terraform就會將現有的Kubernetes deployment引入到Terraform管理的狀態中。\n\n檢查Terraform的狀態,使用terraform state list命令可以列出Terraform目前管理的所有資源,可以確認引入的資源是否已經被成功管理。\n更新Terraform組態檔案,通過terraform plan和terraform apply命令對資源進行更改。當Terraform管理現有資源時,它會比較Terraform組態檔案和現有資源的狀態,並生成一個計劃,顯示要將資源帶到Terraform所需的更改。通過執行terraform apply命令,Terraform就可以將這些更改應用到現有的資源中。\n\n結論\n光看沒有用,最重要的還是實作,\n一開始沒碰terraform是不知道寫壞了,會不會影響線上的服務,\n現在我能夠先import,看目前服務建設的程式後,再來修改。\n感想\n實作後完全崩掉,有很多東西還是要從頭開始看一下。\n像是, terraform 的backend ,跟tfstate 這些觀念。\n上面也有提到引入資源,但實際上可能跟你想得不太一樣,\n引入後是變成一個tfstate,而不是tf,\n那tf 跟 tfstate又有什麼不同呢?\n我們還是看下一篇,從頭來過吧。\nref.\n\n為什麼我們使用Terraform 而不使用Puppet, Ansible",
"tags": [ "note","⎈"]
},
{
"title": "Terraform的基本概念",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/Terraform/148. Terraform的基本概念/",
"content": "睡睡念\n經歷上一篇的失敗,\n還是先從基本觀念開始吧。\n正文\ntf基本組成\n下面指令輸入時,會用tf取代terraform\n宣告\n\nterraform\n宣告terraform以及環境的版本\n\nterraform {\nrequired_version = "~>0.13.5"\nrequired_providers {\nucloud = {\nsource = "ucloud/ucloud"\nversion = "~>1.22.0"\n}\n}\n}\n\nprovider\n呼叫該環境api時需要的參數\nk8s\n\nprovider "kubernetes" {\nconfig_path = "~/.kube/config"\n}\n\nucloud\nprovider "ucloud" {\npublic_key = "JInqRnkSY8eAmxKFRxW9kVANYThg1pcvjD2Aw5f5p"\nprivate_key = "IlJn6GlmanYI1iDVEtrPyt5R9noAGz41B8q5TML7abqD8e4YjVdylwaKWdY61J5TcA"\nproject_id = "org-tgqbvi"\nregion = "cn-bj2"\n}\n\n定義\n\ndata\n取得terraform以外的資訊,不同的proivder提供不同的data sources。\nprovider 列表\n\ndata "ucloud_security_groups" "default" {\ntype = "recommend_web"\n}\n\nresource\n要建立的資源\n\n\tresource "ucloud_eip" "web-eip" {\n\t internet_type = "bgp"\n\t charge_mode = "bandwidth"\n\t charge_type = "dynamic"\n\t name = "web-eip"\n\t}\n\noutput\n輸出\n\n\t\toutput "eip" {\n\t\t value = ucloud_eip.web-eip.public_ip\n\t\t}\n\n狀態檔案(tfstate)\n當terrform要執行變更時,會產生tfstate的檔案,\n上面記載了目前雲上的資源狀態,此檔案不建議編輯,\n當有任何資源變更時,會同步判斷目前雲上的資源狀態是否一致。\n可使用以下指令,匯入目前雲端上的資源狀態\nterraform import kubernetes_deployment.websocketclient default/websocketclient\n\nkubernetes_deployment.websocketclient 為tf的資源名稱\ndefault/websocketclient 是雲上的資源\n此tfstate的檔案是明碼,且多人使用會造成簽入時發生衝突,\n所以要透過backend來解決這個問題\n檔案裏面會看到一些狀態,代表的意思如下\n\n+ 代表新增的資源 (Resource added)\n- 代表刪除的資源 (Resource deleted)\n~ 代表修改的資源 (Resource modified)\n= 代表資源參數的值沒有改變,只是調整了排序 (Resource parameter unchanged, only ordering changed)\n-/+ 同時出現,表示毀壞性變更,先刪除後建立\n\nref. 使用基礎架構即程式碼工具 Terraform\n\n遠端狀態儲存機制(Backend)\nTerraform Remote Backend分為兩種:\n\n標準:支援遠端狀態儲存與狀態鎖\n\n狀態鎖是指,當針對一個tfstate進行變更操作時,可以針對該狀態檔案新增一把全域鎖,確保同一時間只能有一個變更被執行。\n\n增強:在標準的基礎上支援遠端操作(在遠端伺服器上執行plan、apply等操作)\n\n只存在於Terraform Cloud\n\n目前支援的backend list\n\n要共用 backend的話,\n先建立一個 backend.hcl\n裏面輸入\nbucket = "98c2c8-terraform-backend"\nprefix = "terraform/state"\n\n上面的prefix代表的意思為\n\nGCS prefix inside the bucket. Named states for workspaces are stored in an object called <prefix>/<name>.tfstate\n\n在main.tf的required_providers後面填上 backend "gcs" { },\n格式如下\nterraform {\nrequired_providers {\ngoogle = {\nsource = "hashicorp/google"\nversion = "4.63.1"\n}\n}\nbackend "gcs" {\n\n}\n}\n\n然後在初始化的時候,輸入\nterraform init -backend-config=backend.hcl\n\nref.\n\nBackend組態的動態賦值\ntf-gcs\n\n建立workspace\n相比起多資料夾隔離的方式來說,基於Workspace的隔離更加簡單,只需要保存一份程式碼,在程式碼中不需要為Workspace編寫額外程式碼,用命令列就可以在不同工作區之間來回切換。\n下列指令分別爲,建立、列表、選擇及顯示目前的workspace\nterraform workspace new qa\nterraform workspace list\nterraform workspace select qa\nterraform worspace show\n\nref. 狀態管理\n\n檢查terraform 的計劃\nterraform plan -out=out.tfplan\n\n-out的指定計畫的輸出檔,確保您所檢閱的方案就是所套用的方案。\n之後使用apply執行\nterraform apply out.tfplan\n\n建立完成後,使用show看目前狀態\nterraform show\n\ncount\n\n舉例來說, 兩個VM是一隻狗一隻貓,那就是dog.tf cat.tf\n如果是兩隻狗 就可以寫一個 dog.tf\n裡面用\nresources ec2\nCount = 2\n這樣\n\nconsole\n執行 console ,看程式執行結果\nterraform console\n\ncidrsubnet 後面的第二個參數表示二進位要位移多少,第三個參數表示,要設定位移的數字為多少。\n例如 10 = 1010\n位移4bit,所以是 1010 0000 = 160\n6 = 0110\n位移4bit ,所以是 0110 0000 = 96\ntf console\n> cidrsubnet("10.1.0.0/24",4,0)\n"10.1.0.0/28"\n> cidrsubnet("10.1.0.0/24",4,10)\n"10.1.0.160/28"\n> cidrsubnet("10.1.0.0/24",4,6)\n"10.1.0.96/28"\n> cidrsubnet("10.1.0.0/24",4,12)\n"10.1.0.192/28"\n\nref. How cidrsubnet works in Terraform\n\nvariable變數宣告\n先知道變數的繼承順序,\n\n種類\n描述\n範例\n優先\n建議使用\n\n命令列參數\n輸入命令時,指定變數\ntf apply -var="gcp_region=asia-east"\n1\n特殊情況\n\n環境變數\n使用 TF_VAR_ 環境變數定義\nTF_VAR_gcp_region=asia_east2\n2\n\n變數文件\n使用tfvars變數文件定義\ngcp_region=asia_east2\n3\n開發者\n\n設定文件\n使用variables區塊定義\nvariable "gcp_region" {default = "asia-east1"}\n4\n程式碼\n\ntf的變數要先宣告,\nvariable "gcp_region" {\ndefault = "asia-east1"\n}\n\n如果後續要改值,可以改成\ngcp_region = "asia-east2"\n\n如果要測試,可以執行 terraform console\n再輸入變數名稱驗證。\n變數文件載入方式\n\n檔案名稱為 terraform.tfvars or terraform.tfvars.json\n副檔名為 .auto.tfvars or .auto.tfvars\n\n必須在同一個tf init的資料夾內。\n\n還有其他載入方式,在apply 時載入變數檔,或是環境變數載入。\n詳細參考\n\n[Terraform] Input Variables\nTerraform 變數\n(Youtube)Terraform 從零開始 基礎 | 9-Variables(變數)的種類與使用順序\n\n常用指令\n\ntf console 可以經由這邊去驗證變數\n\ntf fmt 格式化main.tf\n\ntf validate 驗證terraform",
"tags": [ "note","⎈"]
},
{
"title": "terraform 部署VM,啓動docker安裝metadata_startup_script",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/Terraform/149. terraform 部署VM,啓動docker安裝metadata_startup_script/",
"content": "睡睡念\n由於前人弄向Let's encrypt 申請的ssl憑證,偶爾會出問題,\n步驟繁瑣,常常改了這個,忘記要重啓那個,那就重新做一套吧。\n為了我想偷懶..(^__^)\n但在那之前,先生個機器來測試看看。\n正文\n第一次用terraform部署vm機器,\n這邊要注意的是 backend "gcs",\n我直接將tfstate傳到gcs上面了,可以參考上一篇<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/Terraform/148. Terraform的基本概念/\">148. Terraform的基本概念</a>。\n底下的metadata_startup_script,\n指令很長,導致我不想放在同一行,\n跑去問了下chatGPT,能使用\n<<-EOT\nEOT\n\n這種方式將程式碼包在一起,就比較方便閱讀了\nterraform {\nrequired_providers {\ngoogle = {\nsource = "hashicorp/google"\nversion = "4.63.1"\n}\n}\nbackend "gcs" {\n\n}\n}\n\nprovider "google" {\nproject = "abc"\n}\n\nresource "google_compute_instance" "certificate-vm" {\nname = "ca-service"\nmachine_type = "f1-micro"\nzone = "asia-east1-b"\ntags = ["allow-admin-ip"]\n\nboot_disk {\ninitialize_params {\nimage = "debian-cloud/debian-11"\n}\n}\n\n# Install Docker\nmetadata_startup_script = <<-EOT\nsudo apt-get update; sudo apt-get install ca-certificates curl gnupg;\nsudo install -m 0755 -d /etc/apt/keyrings;\ncurl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg;\nsudo chmod a+r /etc/apt/keyrings/docker.gpg;\necho "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \\\n"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \\\nsudo tee /etc/apt/sources.list.d/docker.list > /dev/null ;\nsudo apt-get update;\nsudo apt-get -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin;\nEOT\n\nnetwork_interface {\n# subnetwork = google_compute_subnetwork.default.id\nsubnetwork = "default"\naccess_config {\n# Include this section to give the VM an external IP address\n}\n}\n}\n\ntroubleshooting\n如果執行了startup-script,但沒跑,該怎麼除錯?\n到vm裏面執行下面指令,就可以查log了\nsudo journalctl -u google-startup-scripts.service\n\nref. Install Docker Engine on Debian",
"tags": [ "note","⎈"]
},
{
"title": "Terrafrom 建立private cluster",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/Terraform/183. Terrafrom 建立private cluster/",
"content": "前言\n要重建一個新的project,然後把舊的服務搬過去。\n初步估計就一堆東西,正好拿來練一下terraform了\n正文\n\n服務列表\n\nCreate Project\n\nCreate Cluster\n\nCreate VPC\n\nCreate CLoudSQL\n\nCreate Memorystore\n\nCreate CloudStorage\n\nCopy file to CloudStorage\n\n後端修改config&publish\n\nCreaet RabbitMQ\n\nCreate Nginx ingress\n\n前端服務部署&測試\n\n後端服務部署&測試\n\nNetwork policy\n\nObserbility service\n\nEFK logs\n\n前後端 CI/CD 修改 & IAM權限\n\nProject沒辦法用terraform,因爲那不是我操作的。\n也不知道那個能不能用terraform 。\n這篇會建立一個bucket、vpc 、private cluster以及cloud NAT。\n下面會用tf 來稱呼terraform\n\n建立bucket\n因爲狀態關係,就乾脆用gcs統一狀態了,可參考<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/Terraform/148. Terraform的基本概念/\">148. Terraform的基本概念</a>\nnew\\gcs\\main.tf\n\nterraform {\nrequired_providers {\ngoogle = {\nsource = "hashicorp/google"\nversion = "4.63.1"\n}\n}\n}\n\nprovider "google" {\nproject = "ezio-sms-o"\n}\n\nresource "random_id" "bucket_prefix" {\nbyte_length = 3\n}\n\nresource "google_storage_bucket" "tfstate_bucket" {\nname = "${random_id.bucket_prefix.hex}-terraform-devops"\nforce_destroy = false\nlocation = "asia-east1"\nstorage_class = "Nearline"\n\n//物件版本管理\nversioning {\nenabled = false\n}\n}\n\noutput "bucket_name"{\ndescription = "get bucket name"\nvalue = google_storage_bucket.tfstate_bucket.name\n}\n\n記下bucket name與預計要用的前綴,然後寫在backend.hcl,\n等等下面會用到。\nnew\\backend.hcl\nbucket = "cb0392-terraform-devops"\nprefix = "terraform/state"\n\n建vpc 與cloudNAT\nnew\\gke\\main.tf\n\nterraform {\nrequired_providers {\ngoogle = {\nsource = "hashicorp/google"\nversion = "5.4.0"\n}\n}\nbackend "gcs" {\n\n}\n}\n\nprovider "google" {\nproject = "ezio-sms-o"\nzone = "asia-east1-b"\n}\n\n# VPC\nresource "google_compute_network" "basic" {\nname = "basic"\nauto_create_subnetworks = false\n# delete_default_routes_on_create = false\nrouting_mode = "REGIONAL"\n}\n\nresource "google_compute_subnetwork" "basic" {\nname = "basic-subnet"\nip_cidr_range = var.subnet_cidr\nregion = var.gcp_region\nnetwork = google_compute_network.basic.id\nprivate_ip_google_access = true\n\nsecondary_ip_range {\nrange_name = "gke-pod-range"\nip_cidr_range = var.pod_cidr\n}\nsecondary_ip_range {\nrange_name = "gke-service-range"\nip_cidr_range = var.service_cidr\n}\n}\n\n# Cloud NAT\nresource "google_compute_router" "default_cloudnat" {\nname = "default-nat"\nregion = var.gcp_region\nnetwork = google_compute_network.basic.id\n}\n\nresource "google_compute_router_nat" "default_cloudnat" {\nname = "nat"\nrouter = google_compute_router.default_cloudnat.name\nregion = var.gcp_region\n\nsource_subnetwork_ip_ranges_to_nat = "LIST_OF_SUBNETWORKS"\nnat_ip_allocate_option = "MANUAL_ONLY"\n\nsubnetwork {\nname = google_compute_subnetwork.basic.id\nsource_ip_ranges_to_nat = ["ALL_IP_RANGES"]\n}\n\nnat_ips = [google_compute_address.nat.self_link]\n}\n\nresource "google_compute_address" "nat" {\nname = "nat"\naddress_type = "EXTERNAL"\nnetwork_tier = "PREMIUM"\nregion = var.gcp_region\n\n}\n\n變數的設定,也請參考<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/Terraform/148. Terraform的基本概念/\">148. Terraform的基本概念</a>\nnew\\gke\\terraform.tf\nvariable "project_id" {\ndefault = "ezio-sms-o"\n}\nvariable "gcp_region" {\ndefault = "asia-east1"\n}\nvariable "gcp_zone" {\ntype = list(string)\ndefault = ["asia-east1-b"]\n}\nvariable "gke_name" {\ndefault = "fixed"\n}\n\nvariable "subnet_cidr" {\ndefault = "10.10.0.0/16"\n}\n\nvariable "pod_cidr" {\ndefault = "192.168.8.0/21"\n}\n\nvariable "service_cidr" {\ndefault = "192.168.16.0/21"\n}\n\nvariable "master_cidr" {\ndefault = "10.0.2.0/28"\n}\n\nref.\n\n透過 Terraform 建立私有 GKE Cluster\n# 使用基礎架構即程式碼工具 Terraform\ngoogle_compute_network\n\n建立GKE\n\n這部分算是查最久的,用到了terraform的module概念。\n可以先看這篇 [Terraform] 入門學習筆記,瞭解一下什麼是module。\n然後再來就是看官方文件了。\nnew\\gke\\main.tf\n沒錯跟上面vpc的檔案一樣,因爲是同一份文件。\n# GKE\nmodule "gke" {\nsource = "terraform-google-modules/kubernetes-engine/google//modules/private-cluster"\nversion = "29.0.0"\nproject_id = var.project_id\nname = var.gke_name\n# 區域性\nregional = false\nregion = var.gcp_region\nzones = var.gcp_zone\nnetwork = google_compute_network.basic.name\nsubnetwork = google_compute_subnetwork.basic.name\nip_range_pods = google_compute_subnetwork.basic.secondary_ip_range[0].range_name\nip_range_services = google_compute_subnetwork.basic.secondary_ip_range[1].range_name\nhttp_load_balancing = true\nnetwork_policy = false\nhorizontal_pod_autoscaling = true\nfilestore_csi_driver = false\n# private cluster\nenable_private_endpoint = false\nenable_private_nodes = true\nmaster_global_access_enabled = false\nmaster_ipv4_cidr_block = "10.0.0.0/28"\n# gke version\nrelease_channel = "UNSPECIFIED"\nremove_default_node_pool = true\n# log record\nlogging_enabled_components = ["SYSTEM_COMPONENTS"]\ncreate_service_account = false\n\nnode_pools = [\n{\nautoscaling = false\nnode_count = 2\nname = "default-node-pool"\nmachine_type = "e2-custom-4-12288"\nlocal_ssd_count = 0\nspot = false\ndisk_size_gb = 100\ndisk_type = "pd-standard"\nimage_type = "COS_CONTAINERD"\nenable_gcfs = false\nenable_gvnic = false\nlogging_variant = "DEFAULT"\nauto_repair = true\nauto_upgrade = false\npreemptible = false\ninitial_node_count = 80\n},\n]\n\nnode_pools_oauth_scopes = {\nall = [\n\t\t"https://www.googleapis.com/auth/logging.write",\n\t\t"https://www.googleapis.com/auth/monitoring",\n\t\t"https://www.googleapis.com/auth/devstorage.read_only",\n\t\t"https://www.googleapis.com/auth/service.management.readonly",\n\t\t"https://www.googleapis.com/auth/servicecontrol",\n\t\t"https://www.googleapis.com/auth/trace.append"\n]\n}\n\nnode_pools_labels = {\nall = {}\n\ndefault-node-pool = {\ndefault-node-pool = true\n}\n}\n\nnode_pools_metadata = {\nall = {}\n\ndefault-node-pool = {\nnode-pool-metadata-custom-value = "fixed-node-pool"\n}\n}\n\nnode_pools_taints = {\nall = []\n\ndefault-node-pool = [\n{\nkey = "default-node-pool"\nvalue = true\neffect = "PREFER_NO_SCHEDULE"\n},\n]\n}\n\nnode_pools_tags = {\nall = []\n\ndefault-node-pool = [\n"default-node-pool",\n]\n}\n}\n\n簡單說一下module的用法,\n當第一次用module時,需要初始化,加上指定gcs儲存tfstat\ntf init -backend-config=../backend.hcl\n\n之後要使用submodule的話,不用再初始化,只要get\ntf get\n\n要建立private cluster的話,需要使用submodule,\n可從kubernetes-engine 到 submodule的 private-cluster,\n有些參數不知道是建立GKE的哪個設定,\n可以多利用tf validate 驗證,\n但有時是部署時才會發生錯誤。\n我後來是直接手動把cluster砍掉,再tf apply比較快。\n本來也有想過不要用module,直接實作。\n但看了官方文件 Using GKE with Terraform,\n\nAdditionally, you may consider using Google's kubernetes-engine module, which implements many of these practices for you\n就試試看了。\n\n注意,submodule與主要module的source不一樣,有些參數在主module是沒有的。\nTroubleshooting\n部署GKE時,發現我沒辦法從Google Artifact Registry 下載image。\n最後發現是 沒有設定 存取權範圍,Access scopes in GKE。\n\n這個需要在 node_pools_oauth_scopes 裏面補上允許的api網址。",
"tags": [ "note","⎈"]
},
{
"title": "導入Terraform",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/Terraform/189. 導入Terraform/",
"content": "前言\n前面有稍微提到幾篇是terraform的使用方式,\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/Terraform/148. Terraform的基本概念/\">148. Terraform的基本概念</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/Terraform/149. terraform 部署VM,啓動docker安裝metadata_startup_script/\">149. terraform 部署VM,啓動docker安裝metadata_startup_script</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/Terraform/183. Terrafrom 建立private cluster/\">183. Terrafrom 建立private cluster</a>\n再來把剩下碰到的補一補了。\n正文\n\n建立完了private cluster,後續要建立SQL 跟 redis的話,該怎麼建?\n\n另外開一個資料夾,重新terraform init,但要注意,\n你的backend.hcl是怎麼寫的。\n舉例來說,\nprivate cluster的bucket.hcl是這樣\nbucket = "terraform-devops"\nprefix = "terraform/state"\n\n如果,另一個資料夾裏面的bucket.hcl也相同,\n那在產生計劃時,就會把你剛剛建好的private cluster給刪除,\n因爲他檢查的是tfstate跟你目前計劃有哪些差別。\n所以,需要更改prefix\nbucket = "terraform-devops"\nprefix = "terraform/other"\n\n這樣在bucket裏面,就會存成兩個不同的tfstate\n\nterrafrom使用迴圈,減少重複的程式碼\n\n建立兩個bucket,並開啓allUser read\nvariable "bucket_names" {\ntype = list(string)\ndefault = ["A-legacy", "B-legacy"]\n}\nresource "google_storage_bucket" "frontend_bucket" {\nuniform_bucket_level_access = true\nfor_each = { for name in toset(var.bucket_names) : name => name }\nname = each.value\nforce_destroy = false\nlocation = "asia-east1"\nstorage_class = "STANDARD"\n# public_access_prevention = "inherited"\n\n//物件版本管理\nversioning {\nenabled = false\n}\n}\nresource "google_storage_bucket_iam_binding" "binding" {\nfor_each = google_storage_bucket.frontend_bucket\n\nbucket = each.value.name\nrole = "roles/storage.legacyObjectReader"\nmembers = [\n"allUsers",\n]\n}\n\nref.\n\nThe for_each Meta-Argument\n禁止公開訪問\nIAM policy for Cloud Storage Bucket\n\n讀取之前的設定\n\n在建立private cluster的時候,就已經建好了vpc ,\n相同的網路,我想在建立mssql 時使用,\n使用data呼叫這個VPC。\n這個範例是拿來建立vpc裏面的私人服務連線的位置。\ndata "google_compute_network" "private-network" {\nname = "basic"\n}\n\nresource "google_compute_global_address" "private_ip_address" {\ndepends_on = [ google_project_service.project ]\nname = "private-ip-address"\npurpose = "VPC_PEERING"\naddress_type = "INTERNAL"\nprefix_length = 16\nnetwork = data.google_compute_network.private-network.id\n}\nresource "google_service_networking_connection" "private_vpc_connection" {\n\nnetwork = data.google_compute_network.private-network.id\nservice = "servicenetworking.googleapis.com"\nreserved_peering_ranges = [google_compute_global_address.private_ip_address.name]\n}\n\n設定.gitignore\n\n# Local .terraform directories\n**/.terraform/*\n\n# .tfstate files\n*.tfstate\n*.tfstate.*\n\n# Crash log files\ncrash.log\ncrash.*.log\n\n# Exclude all .tfvars files, which are likely to contain sensitive data, such as\n# password, private keys, and other secrets. These should not be part of version\n# control as they are data points which are potentially sensitive and subject\n# to change depending on the environment.\n# *.tfvars\n# *.tfvars.json\n\n# Ignore override files as they are usually used to override resources locally and so\n# are not checked in\noverride.tf\noverride.tf.json\n*_override.tf\n*_override.tf.json\n\n# Include override files you do wish to add to version control using negated pattern\n# !example_override.tf\n\n# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan\n# example: *tfplan*\n\n# Ignore CLI configuration files\n.terraformrc\nterraform.rc\n\nref. gitignore\n結尾\n基礎概念介紹\n\nTerraform基礎概念——Provider\nGCP-使用 Terraform 的最佳實踐\n大家都在用 Terraform 實作 IaC 為什麼不將程式寫得更簡潔易讀呢?\nLocals",
"tags": [ "note","⎈"]
},
{
"title": "Terraform vs Ansible",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/Terraform/82. Terraform vs Ansible/",
"content": "前言\n本來想直接用表格闡述兩邊不同的地方,\n但發現我不知道從何下手。\n只好先用條列代替了,\n這兩套我都沒用過,因為...我直接從GKE開始XD。\n正文\nTerraform\n\n聲明性代碼:程式碼的結果就是最終狀態\n協作(Orchestration):確保環境持續處於『理想狀態』,當服務不能用時,會砍掉重建。\n\nAnsible\n\n程式性代碼:每一次的狀態都是獨立的\n配置管理工具(Configuration Management): 是一套流程和程序,執行時不會重置系統,會在機器上修復問題或升級服務。\n\n結論\n目前看起來,\nAnsible主要偏向自動化管理工具但同時具備一定程度上的環境 建立。\nTerraform 就是單純的 環境建立工具\n如果走向k8s服務的話,學TerraForm就好了。\n用來建立cluster、loadbalancer...。\n由於 k8s的服務都已經容器化了,使用Ansible也沒什麼意義,\n重開服務又消失了。\nref.\n\nTerraform vs Ansible: What's the difference and which one you should use?\nAnsible vs Terraform vs Puppet差異比較:有什麼區別?選擇哪個?\n架構程式碼的實施工具\n[DevOps系列] 為什麼我們使用Terraform 而不使用Puppet, Ansible\nTerraform vs. Ansible : Key Differences and Comparison of Tools,感覺這篇寫的最好,但結論就...",
"tags": [ "note","⎈"]
},
{
"title": "k8s YAML 小細節",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/Yaml/12. k8s YAML 小細節/",
"content": "前言\n最近寫yaml,有時常會忘記這個的功能是什麼,就記一下吧\n正文\n\nService 的Port功能\nPort exposes the Kubernetes service on the specified port within the cluster. Other pods within the cluster can communicate with this server on the specified port.\n\nTargetPort is the port on which the service will send requests to, that your pod will be listening on. Your application in the container will need to be listening on this port also.\nNodePort exposes a service externally to the cluster by means of the target nodes IP address and the NodePort. NodePort is the default setting if the port field is not specified.\n\n探針檢查\n\nlivenessProbe:\ninitialDelaySeconds: 10\nperiodSeconds: 10\nsuccessThreshold: 1\nfailureThreshold: 3\ntcpSocket:\nport: 80\nreadinessProbe:\ninitialDelaySeconds: 30\nperiodSeconds: 10\nsuccessThreshold: 1\nfailureThreshold: 3\ntcpSocket:\nport: 80\n\npull image 認證\n如果要佈署的image是屬於 私密的,\n需要加上\n\nimagePullSecrets:\n- name: regcred\n\n要先注入Secred\nkubectl create secret generic regcred --from-file=./username.txt\n\nService 服務類型\n\nClusterIP\n\n一個集群內的服務,集群內的其它應用都可以訪問該服務。集群外部無法訪問它。 這也是默認的 ServiceType。\n可以使用proxy 的本機 port轉移,來訪問服務。像 (Fig.1)\n[[12.fig-1.jpg]]\n\nNodePort\n\n在所有節點(虛擬機)上開放一個特定端口,任何發送到該端口的流量都被轉發到對應服務。\n在 1 的service port,就是指這個部分。\n需使用K8s的叢集主機加上port,去訪問服務。 (Fig.2)\n[[12.fig-2.jpg]]\n\nLoadBalancer\n\nLoadBalancer 服務是暴露服務到 internet 的標準方式。在 GKE 上,這種方式會啟動一個 Network Load Balancer,它將給你一個單獨的 IP 地址,轉發所有流量到你的服務。\n一個外部ip,直接訪問即可,有時需注意防火牆有沒有擋住。\n\nref.\nKubernetes的三種外部訪問方式:NodePort、LoadBalancer 和 Ingress\nKubernetes 服務\n\nkube dns\n\nPod DNS record\n[[12.fig-3.jpg]]\n172-17-0-6.default.pod.cluster.local\n\n172-17-0-6: Pod IP\ndefault: Namespace Name\n\nService DNS record\n[[12.fig-4.jpg]]\nnginx.default.svc.cluster.local\n\nnginx: Service Name\ndefault: Namespace Name\n\nService Discovery\n[[12.fig-5.jpg]]\nweb-0.nginx.default.svc.cluster.local\n\nweb-0: Pod Name\nnginx: Service Name\ndefault: Namespace Name\n\nAuto Scaling(自動擴展)\n在Auto Scaling 裡面,有一個設定是根據cpu的使用量大小去增加Pod,\n假設\ntargetCPUUtilizationPercentage:10\n在deploy 裡的request CPU 設定 200m\n表示,當cpu的使用率在 20m(200m * 10% = 20m )時,會自動擴展\n\n如果要使用其他的指標,api 需改用 autoscaling/v2beta2\n這邊還沒測試過,有需要的可至相關網頁查詢\nref.\nKubernetes 那些事 — Auto Scaling\nKubernetes--k8s--進階--全面瞭解HPA--部署HPA實現高可用和成本控制\nKubernetes 1.8: Now with 100% Daily Value of Custom Metrics",
"tags": [ "note","⎈"]
},
{
"title": "一步步篩選k8s的deploy內容",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/Yaml/136. 一步步篩選k8s的deploy內容/",
"content": "睡睡念\n要抓一下,目前ingress裏面的所有白名單資訊,\n但一個一個開起來看又很麻煩,\n就寫code filter吧\n正文\n\n先取得json,先指定一個服務,不然會太亂\n\nkubectl get ingress websocketclient -o json\n\n然後開始看json 格式開始拆解,這次目的是要取得\nnginx.ingress.kubernetes.io/whitelist-source-range的值,\n這邊會碰到一個問題,因為有特殊符號 . 跟 / ,所以要用 \\ ,將它視爲一個整體。\n\nkubectl get ingress -n default -o=jsonpath='{range .items[*]}{"\\n"}{.metadata.name}{"\\t"}{.metadata.annotations.nginx\\.ingress\\.kubernetes\\.io\\/whitelist-source-range}{end}'\n\nref.\n\nJSONPath Support\nExtract information of kubernetes annotations with jsonpath",
"tags": [ "note","⎈"]
},
{
"title": "k8s yaml撰寫 volume 踩坑篇",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/Yaml/2. k8s yaml撰寫 volume 踩坑篇/",
"content": "前言\n昨天接到一個任務,要把一個純html,放到nginx上面。\n然後就開始踩坑之旅了\n正文\n這邊寫的都是GKE 的佈署方式,\n關於GKE 文章實在太多了,我也不知道何年何月何日才有那個技術存量可以把它寫成文章。\n目前使用的是 kustomize的方式佈署網站,\n目前也在架設drone,日後走的是自動佈署,\n但是第一次佈署還是要自己來的。\n基本的流程是,將網頁包成一個 docker image,\n(不論是php 或是 html, Go 則是本身有服務可以掛載,比較簡單點。)\n再將此image設定成 initContainers ,\n將此image的資料夾,掛載成volume,讓nginx可以直接掛載此資料夾。\n這次踩的坑有兩個,\n\n網站程式,是別人傳給我的,所以檔案權限,everyone都是 無法存取。\n所以要把裡面的所有檔案改成 755 rwxr-xr-x ,nginx圖片才能夠讀取。\n我懶的一個一個改,所以下指令一次把整個資料夾內容都改掉,當初安全點是設定777\n\nchmod -R 755 resource\n\n(ref. https://www.jianshu.com/p/6c52260b1ff3)\n\n在寫yaml的時候,沒有搞清楚 volume的用途\n導致一直出現rsync的錯誤。\n\ninitContainers:\n- command:\n- sh\n- -c\n- |\nrsync -avrh --delete /source/* /app\nimage: gcr.io/project/busybox-web:v2.7\nimagePullPolicy: Always\nname: source\nvolumeMounts:\n- mountPath: /app\nname: source\nvolumes:\n- emptyDir: {}\nname: source\n\nvolumeMounts: 這段的意思是 定義一個叫 soure的新磁區,掛載在 busybox-web容器裡的 /app 的path上面。\nvolumes: 的意思是定義磁碟區,emptyDir是伴隨著pod的生命,當pod消失資料也會跟著消失\n\nnginx.conf 改完後,要重啟pod ,因為nginx.conf 是寫在 k8s的 configMapGenerator,\n所以更改裡面的設定後,不會重啟pod ,裡面的服務就不會重新抓取conf。",
"tags": [ "note","⎈"]
},
{
"title": "kubernetes 批次檢查yaml特定字元",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/Yaml/74. kubernetes 批次檢查yaml特定字元/",
"content": "前言\n因為dockershim的問題,\n這次要搬cluster的node了。\n但我根本忘記有哪個yaml有寫到 nodeSelector了,\n一個一個看又好懶...怎麼辦?\n正文\n想起來之前在檢查 docker.sock的時候,有用指令檢查過這個yaml (1)裡面,\n有沒有 /docker.sock\nkubectl get pods --all-namespaces \\\n-o=jsonpath='{range .items[*]}{"\\n"}{.metadata.namespace}{":\\t"}{.metadata.name}{":\\t"}{range .spec.volumes[*]}{.hostPath.path}{", "}{end}{end}' \\\n| sort \\\n| grep '/var/run/docker.sock'\n\n這段最後面兩個就不用看了,sort 跟 grep 是 linux的指令。\n主要針對 -o jsonpath 來看,詳細指令 參考(2)\n當要取得複數資料時,用 range 來取資料。\n然後...參考 pod的yaml看要取得哪些欄位來用吧。\n下面範例為取得 全部的 nodeSelectord\nkubectl get pods -A \\\n-o=jsonpath='{range .items[*]}{"\\n"}{.metadata.namespace}{":\\t"}{.metadata.name}{":\\t"}{.spec.nodeSelector}{end}'\n\n再排序一下,就可以很快的知道有哪些yaml有用到 nodeSelector了。\nref.\n1. 從 dockershim 遷移遙測和安全代理\n2. JSONpath 幫助",
"tags": [ "note","⎈"]
},
{
"title": "gke-cronjob筆記",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/Yaml/85. gke-cronjob筆記/",
"content": "前言\n之前同事是直接自己土炮用golang寫timer,\n不過如果碰到執行時間過長,重複執行的話,\n就要判斷一堆狀態,決定要不要做,\n那就改用k8s的cronJob了吧。\n正文\n文件看一看(1) (2),好像就差不多了。\n下面是測試,每兩分鐘執行一次,\n但如果執行時間過長,是不是會在執行。\n這邊關掉的是併發以及 暫停後續執行,\n另外注意,gcp的cronjob是每10秒檢查一次狀態。\napiVersion: batch/v1beta1 # k8s after version 1.21 ,apiVersion: batch/v1\nkind: CronJob\nmetadata:\nname: hello\nspec:\nschedule: "*/2 * * * *" # min hour day Mon week\nconcurrencyPolicy: Forbid # 並發政策\nstartingDeadlineSeconds: 60 # 截止時限\nsuspend: true # 暫停後續執行\nsuccessfulJobsHistoryLimit: 3 # 歷史限制: 保存成功的數量\nfailedJobsHistoryLimit: 1 # 歷史限制: 保存失敗的數量\njobTemplate:\nspec:\ntemplate:\nspec:\ncontainers:\n- name: hello\nimage: busybox\nargs:\n- /bin/sh\n- -c\n- echo "start"; date; echo "Hello, World! Sleep 150s"; sleep 150s; date;\nrestartPolicy: OnFailure\n\nref.\n1. GCP-CronJob\n2. k8s-CronJob",
"tags": [ "note","⎈"]
},
{
"title": "kustomize 共用label(optional)",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/Yaml/87.kustomize 共用label(optional)/",
"content": "前言\n要把別人寫的yaml拆開,然後整併到自己的image,\n才發現service的 base 怎麼沒寫selector ,\n但佈署時卻有mapping到。\n正文\n原因在kustomize的 共用屬性\ncommonLabels:\napp: token-proxy\n\n這個會自動在各個resource上面增加label,\n如果這邊拔掉的話,\n需要在Deployment以及service上面增加label。\n但在一些文章也有人討論到這個問題,\n如果我不要讓他強制增加的話,\n該怎麼做?\nkustomize有新的參數可供設定(1)。\ncommonLabels:\n- path: metadata/labels\ncreate: true\n\n- path: spec/selector\ncreate: true\nversion: v1\nkind: Service\n\n- path: spec/selector/matchLabels\ncreate: true\nkind: Deployment\n\n另外,還有 下列新增的可供參考。\n\nannotations\nimages\nlabels\nname reference\nnamespace\nprefix/suffix\nvariable reference\n\nref.\n1 .transformerconfigs",
"tags": [ "note","⎈"]
},
{
"title": "k8s 細節補充",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/Yaml/94. k8s 細節補充/",
"content": "前言\n最近幫其他組的同事看問題時,\n發現有些東西是我沒看過的,\n就整合再一起,寫起來當備忘拉。\n正文\n\ndeployment 的 lifecycle\npostStart 在container創建後,立即發送postStart事件。\npreStop 在 container結束前,立即發送preStop事件。\n\napiVersion: v1\nkind: Pod\nmetadata:\nname: lifecycle-demo\nspec:\ncontainers:\n- name: lifecycle-demo-container\nimage: nginx\nlifecycle:\npostStart:\nexec:\ncommand: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]\npreStop:\nexec:\ncommand: ["/bin/sh","-c","nginx -s quit; while killall -0 nginx; do sleep 1; done"]\n\nref. 為容器的生命週期事件設置處理函數\n\npod的終止\n通常情況下,container會發送TERM信號到每個container中,\n當超出了正常終止期限,則會向其他的processor發送KILL信號\nref. Pod 的終止\n\n探針\nlivenessProbe :判斷container是否正常\nreadinessProbe:判斷服務是否正常\n\n查詢kubectl resouce 簡寫\n\nkubectl api-resources\n\n類似下列資源都可用縮寫\nconfigmap = cm\ndeployment=deploy\npod = po\npersistentvolumeclaims = pvc\nref .【從題目中學習k8s】-【Day8】K8s常用指令 (Cheat Sheet)&解題技巧\n\nk8s的 command ,bash -c 意思\n\ncommand: ["/bin/bash","-c"]\nargs: [ "service cron start; while true; do sleep 30; done;" ]\n\n很常看到 bash -c ,這個表示從後面的字串中 讀取命令來使用。\nps. bash 跟 sh 不一樣,sh通常是指dash。\n可用下列指令,查看目前使用的shell\necho $SHELL\nor\nls -l /bin/sh\n\nref.\n- The bash shell\n- 【Bash】什麼是 #!/bin/bash, #!/bin/sh,為什麼要加在 script 前面 (問題解決:sh, bash 的不同)\n\n使用指令建立基本的 yaml\n\nkubectl run nginx-kusc00101 --image=nginx --restart=Never --dry-run=client -o yaml> q1.pod\n\n有基本指令後再去裡面修修改改。\n如果要直接取得現有的yaml\nkubectl get deploy yiyuan-landingpage-qa -n istio-yiyuan -o yaml > yiyuan.yaml",
"tags": [ "note","⎈"]
},
{
"title": "k8s中的command與dockerfile的 CMD",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⎈ k8s/Yaml/98. k8s中的command與dockerfile的 CMD/",
"content": "前言\n忘記是什麼原因,\n讓我跑去查這兩個的差異\n正文\ndockerfile中的指令\nCMD 、 ENTRYPOINT\nk8s 中的yaml 中也有\ncommand 、args\n先來分辨 CMD 與 ENTRYPOINT的差別\nCMD\n先上個Dockerfile\nFROM golang:1.16-alpine AS build-env\n\nCMD ["/bin/sh","-c","echo $HOME"]\n\n這個build完後,直接執行會顯示 /root,如果用\ndocker run golang:1.16 /bin/sh -c "echo $SHELL"\n\n,會直接執行剛剛的指令。\n原因是,CMD 跟 外面接受的指令會互相覆蓋。\n\nENTRYPOINT\nDockerfile\nFROM golang:1.16-alpine AS build-env\n\nENTRYPOINT ["/bin/sh","-c","echo $HOME"]\n\n同樣也直接執行會顯示 /root ,\n如果用\ndocker run golang:1.17 /bin/sh -c "echo $SHELL"\n\n還是顯示 /root\n原因是,使用entrypoint的話,指令不會互相覆蓋。\n反而是被當成參數加在後面。\nref. Docker CMD 與 ENTRYPOINT 說明詳解\n兩者互動表\n\nNo ENTRYPOINT\nENTRYPOINT exec_entry p1_entry\nENTRYPOINT [“exec_entry”, “p1_entry”]\n\nNo CMD\nerror, not allowed\n/bin/sh -c exec_entry p1_entry\nexec_entry p1_entry\n\nCMD [“exec_cmd”, “p1_cmd”]\nexec_cmd p1_cmd\n/bin/sh -c exec_entry p1_entry\nexec_entry p1_entry exec_cmd p1_cmd\n\nCMD exec_cmd p1_cmd\n/bin/sh -c exec_cmd p1_cmd\n/bin/sh -c exec_entry p1_entry\nexec_entry p1_entry /bin/sh -c exec_cmd p1_cmd\n\nref.\n\nUnderstand how CMD and ENTRYPOINT interact\nDocker CMD 與 ENTRYPOINT 說明詳解\n\nK8S yaml command\n佈署個cronJob來測試\n這次掛載的映像檔是使用 dockerfile『command』的映像檔\n跟上面測試方法一樣,先不加command看結果是什麼\n加了後結果又會是什麼。\nspec:\ncontainers:\n- command:\n- /bin/sh\n- -c\n- echo $PATH\n\n11:57 那個沒有加command,所以會看到顯示root\n12:03 加了上面的command,指令覆蓋,所以顯示$PATH的內容\np.s 如果不用command改用args,指令覆蓋。\nK8S yaml args\n這次掛載的映像檔是使用 dockerfile『ENTRYPOINT』的映像檔\nspec:\ncontainers:\n- args:\n- /bin/sh\n- -c\n- echo $PATH\n\n13:44 不加任何參數,顯示 /root\n13:45 加了args,還是顯示/root,指令無覆蓋\nargs的主要用途是,當dockerfile 為 ENTRYPOINT時,\n使用args會將其視爲參數傳入到image內。\nps. 如果改使用 command ,則覆蓋\nref. k8s command, args, entrypoint, cmd 區別\n結論\nDocker\nENTRYPOINT 主要是將整個container當做可執行檔來用。\nCMD 則比較類似一台VM\nK8S\ncommand : 指令都是覆蓋\nargs : 外加的參數,可與command一起使用,\nspec:\ncontainers:\n- args:\n- -a\ncommand:\n- /bin/sh\n- -c\n- uname",
"tags": [ "note","⎈"]
},
{
"title": " ⏱ Drone MOC ",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⏱ Drone/0.Drone MOC/",
"content": "建置\n\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⏱ Drone/72. drone on GKE 建立/\">72. drone on GKE 建立</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⏱ Drone/10.drone 使用 騰訊雲 K8S及 容器鏡像服務/\">10.drone 使用 騰訊雲 K8S及 容器鏡像服務</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⏱ Drone/77. drone build Open Source Edition/\">77. drone build Open Source Edition</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⏱ Drone/78. drone k8s-runner 進階設定/\">78. drone k8s-runner 進階設定</a>\n\n編寫\n\n<a class=\"internal-link is-unresolved\" href=\"/404\">3. 撰寫drone.yml 筆記篇</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/⏱ Drone/109. drone jsonnet 各種怪招/\">109. drone jsonnet 各種怪招</a>\n<a class=\"internal-link is-unresolved\" href=\"/404\">119. Drone plugin-Drone-docker 修改原始檔</a>",
"tags": [ "note","⏱"]
},
{
"title": "drone 使用 騰訊雲 K8S及 容器鏡像服務",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⏱ Drone/10.drone 使用 騰訊雲 K8S及 容器鏡像服務/",
"content": "前言\n科技始終來自於人性,現在要讓自動佈署可以支援到騰訊雲\n正文\n1.發佈image到騰訊雲的容器鏡像服務\n直接先給 drone.yml\n- name: push2TCR\nimage: plugins/docker\nsettings:\nusername:\nfrom_secret: TCR_user\npassword:\nfrom_secret: TCR_PW\nbuild_args:\n- website=qa\n- location=tke\nrepo: tcr.tencentcloudcr.com/project/abc\nregistry: tcr.tencentcloudcr.com\ntags:\n- latest\n- ${DRONE_COMMIT}\n\n這邊使用的docker image 請參考 Docker\n要注意的地方在,如果直接把username跟 password 打在上面的話,\n會發生驗證失敗。\n需要將帳號密碼放到drone裡面的 Secrets,\n一開始也可以使用 command 直接看有沒有成功登入。\n- name: push2TCR\nimage: plugins/docker\ncommands:\n- docker login tcr.tencentcloudcr.com --username 123456789 --password token\n\n另外,當初在設定的時候,有限定ip才能連線,這部分記得要打開\n,如果沒有就不用在意了。\n\n2.佈署到騰訊雲\nkind: pipeline\nname: TKEPipeline(QA)\n\nplatform:\nos: linux\narch: amd64\n\nsteps:\n\n- name: deploy2TKE-QA\nimage: danielgormly/drone-plugin-kube:0.0.2\nsettings:\ntemplate: tke.yml\nserver: https://loud.com\nca:\nfrom_secret: TKE_CA\ntoken:\nfrom_secret: TKE_TOKEN\nnamespace: demo\n\nserver 跟 ca token,需看騰訊雲集群上的設定\n\n這個image不像GKE一樣有參數可以丟進去,只有固定的幾個參數\nref. danielgormly/drone-plugin-kube\n所幸這個有放在github上,還能夠根據自己的需求更改內容,增加參數。\n重新編譯後,如果不是上傳到公開的Container Registry ,而是傳到私有的CR就必須加上\nimage_pull_secrets:\n- TKE_LOGIN\n\n這個與image 同樣的層級,不然會導致pull image失敗\n\nref.How to pull private images with 1.0,\n至於TKE_LOGIN的內容(這個也必須加在drone的Secrets內),\n通常是在 $HOME/.docker/config.json 內,會長得像\n{\n\t"auths": {\n\t\t"https://index.docker.io/v1/": {\n\t\t\t"auth": "YW11cmRhY2E6c3VwZXJzZWNyZXRwYXNzd29yZA=="\n\t\t}\n\t}\n}\n\n但是,我的只有\n{\n\t"auths": {\n\t\t"https://index.docker.io/v1/": {}\n\t}\n}\n\n所以下面那個就必須自己產生了,\n產生的方式如下\necho -n 'username:password' | base64\n把username與 password 輸入,轉成base64,再貼上去至程式碼內,並儲存至drone的Secrets\nref.Docker login auth token\n至於修改這個image,要加入參數的話,\n目前看應該是 增加 main.go 跟 plugin 的 Kubeconfig 參數,然後重新編譯(build.sh)即可\np.s. 在騰訊雲的pod(Alpine Linux)內安裝軟體,需替換鏡像源\nsed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories\n\nref.\n支援k8s的各種指令Sh4d1/drone-kubernetes\n可直接在drone上下kubectl指令sinlead/drone-kubectl\nalpine源配置",
"tags": [ "note","⏱"]
},
{
"title": "drone jsonnet 各種怪招",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⏱ Drone/109. drone jsonnet 各種怪招/",
"content": "睡睡念\n本文章內容包含許多寫drone jsonnet會碰到的寫法。\n正文\n\n在pipeline下comand的時候,有時會碰到多行指令湊在一起的情況,\n在drone.yaml是直接這樣寫\n\n但如果要用jsonnet的話,要用\\n換行,\n\n轉換後就會變成下圖\n\n在執行command的時候,因為要先用" 將指令包起來,如果裏面還要有" 的話,必須在前面加上 \\\n\n執行drone jsonnet --stream --format後\n\n這是因爲 linux shell裏面,單引號跟雙引號的差別,詳細可看<a class=\"internal-link\" data-note-icon=\"\" href=\"/🐧 Linux/133. shell script字串處理/\">shell script 雙引號與單引號</a>\n\n如果碰到很長的一串指令,例如if else之類的,改使用 @'' 將程式包起來。\n\n@'\nif [ -z $${TAG_FROM} ]\n\nthen\n\necho "錯誤:無來源TAG。";\n\nexit 1\n\nfi'\n\n如果字串過長,想要換行的話, 可在雙引號內 使用 兩個\\\n\n用curl時,有些參數要用" ,所以在單引號使用 " " 固定參數,要先用 @ '' 包起來\n\n@'OAUTH2_TOKEN=$(curl -XGET $${TOTP_AUTH_URL} \\\\\n-H "accept: application/json" \\\\\n-H "TOTP-PIN-CODE: $${pin}" \\\\\n-H "TOTP-USER: $${user}")',\n\nref.\n\njsonnet教學\njsonnet 官方說明\nStandard Library",
"tags": [ "note","⏱"]
},
{
"title": "Drone plugin-Drone-docker 修改原始檔",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⏱ Drone/119. Drone plugin-Drone-docker 修改原始檔/",
"content": "碎碎念\n之前發現一個後端執行drone會發生的問題,\n偶爾發生,但一段時間總會發生一次。\n多個step同時build,會造成image錯亂。\n好麻煩阿....\n正文\n先來看幾張圖,應該就能瞭解我再說什麼了。\n\n首先看到第一張圖,他在執行docker build的時候,會用git commit的值,當作image的tag名稱。\n然後看第二張圖,直到build完image後,才會再根據你的tag去將image改成你要的tags\n所以我們來想一個情境,當A、B同時執行時,他們的git commit都一樣,\nA已經build完了,正要執行最後一個步驟,將git commit tag改成正常的image tag 。\n此時B也剛build完,所以他也產生了一個一模一樣的 commit tag的image,那A執行最後一個步驟時,他改得到底是誰的image?\n\n如果一個接一個step跑的話,時間大概需要 4分半,\n但同步的話,只要1分半,時間快了三倍。\n\n所以還是要想辦法解掉,本來有想幾個解法,\n\n一次把程式都build一遍,放在同一個image內,\n執行時,再根據參數看要執行哪個檔案。\n\n但是他們有一種情境是只要更新其中一個功能就好,那此時全部build就不太適合。\n\n在drone step時,塞tag進去,但他只會在最後一個步驟,才會改image的tag ,這招也不行\n\n改plugin/gcr 了,在第一步驟時就把image的tag改掉,不要使用git commit,那就解掉這個問題了。\n\n動手\n首先找到這個image的原始碼 drone-plugins/drone-docker,然後開始改吧。\n各環境main.go的package import docker 要先改掉,不改掉我不確定他會不會抓本機的package,我golang初學沒多久。\n修改前\nimport (\n\t"os"\n\t"runtime"\n\n\t"github.com/joho/godotenv"\n\t"github.com/sirupsen/logrus"\n\t"github.com/urfave/cli"\n\n\tdocker "github.com/drone-plugins/drone-docker"\n)\n\n修改後\nimport (\n\t"os"\n\t"runtime"\n\n\t"github.com/joho/godotenv"\n\t"github.com/sirupsen/logrus"\n\t"github.com/urfave/cli"\n\n\tdocker "drone-docker"\n)\n\n然後我在docker.go上面直接加了兩行,指定了tag,這不適合所有人,\n因為你們的使用情境可能跟我不太一樣,我這邊是只要push到git後,drone會自動產生tag,所以如果不指定的話,我還是有tag的值可以取得。\ntag := build.Repo + ":" + build.Tags[0]\n\nargs := []string{\n"build",\n"--rm=true",\n"-f", build.Dockerfile,\n"-t", build.Name,\n"-t", tag,\n}\n\n另外,如果要知道plugin/gcr裏面有什麼環境變數可以拿來用的話,\n可以在drone的step上面,執行export -p\n- name: publish-dev\nimage: plugins/gcr\npull: if-not-exists\nvolumes:\n- name: docker\npath: /var/run/docker.sock\ncommands:\n- export -p\n\n執行結果:\n\n改完後,執行下面的指令先產生go 的程式。\n這個go的指令,我是從.drone.yaml抄出來的。\n執行前記得先設定環境變數\nexport GOOS=linux\nexport GOARCH=amd64\nexport CGO_ENABLED=0\nexport GO111MODULE=on\n\nGo build\ngo build -v -ldflags "-X main.version=${DRONE_COMMIT_SHA:0:8}" -a -tags netgo -o release/linux/amd64/drone-docker ./cmd/drone-docker\n\ngo build -v -ldflags "-X main.version=${DRONE_COMMIT_SHA:0:8}" -a -tags netgo -o release/linux/amd64/drone-gcr ./cmd/drone-gcr\n\nDocker build\n將go的執行檔打包進去docker image內,\n先打包到本機的docker:linux-amd64,\n因為docker-gcr的dockerfile會去抓docker:linux-amd64 當作image的基底再產生檔案\ndocker build \\\n--label org.label-schema.build-date=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \\\n--label org.label-schema.vcs-ref=$(git rev-parse --short HEAD) \\\n--file docker/docker/Dockerfile.linux.amd64 --tag plugins/docker:linux-amd64 .\n\ndocker build \\\n--label org.label-schema.build-date=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \\\n--label org.label-schema.vcs-ref=$(git rev-parse --short HEAD) \\\n--file docker/gcr/Dockerfile.linux.amd64 --tag asia-east1-docker.pkg.dev/rouge-sms/docker-public/gcr:0.0.13 .\n\n完成\n\n上圖可以看到,在docker build時,會同時下兩個tag,\n一個還是維持git commit的值,但另一個就是拿repository加版本號當作tag。\nref.\n\nDRONE_STEP_NAME not available as substitution in environment\n\n查資料時剛好有碰到這個問題,drone_step_name一直抓不到,原因再文章內。\n\n修復在多模組java項目中,平行打包鏡像時,鏡像因為同名稱被覆蓋的問題\n\n昨天才看到有人發了個PR修復同名稱的問題,感覺跟我的頗像,但實際看了,覺得不太適合。",
"tags": [ "note","⏱"]
},
{
"title": "撰寫drone.yml 筆記篇",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⏱ Drone/3. 撰寫drone.yml 筆記篇(未)/",
"content": "前言\n換工作後,開始接觸k8s、GCP、GKE,再來是Drone。\nk8s中又延伸了kustomize ,ymal的寫法、佈署方式。\nGCP中的cloud armor、GCE ,然後GKE的架構\n真的是....滿滿的坑阿。以上講到的,還處於懞懂中,\n筆記不知道何年何月何日可寫\n正文\n簡單說一下環境,在GKE上面佈署 drone 跟 gitlab,\n當gitlab有條件觸發的話(例如在push 在master上),會同時送出一個webhook給drone,\n此時drone就會去gitlab pull程式碼下來,做你想要的動作(例如,打包成image,把image送到gcr上面,再佈署到GKE上)。\n先來份yaml,建議可以先看一下yaml是什麼東西,這樣寫起來比較不會撞牆。\n(ref. https://zh.wikipedia.org/wiki/YAML)\nkind: pipeline\nname: Pipeline(branch)\n\nsteps:\n- name: push2GCR(前哨)\nimage: plugins/gcr\nsettings:\nrepo: gcr.io/rd7-project/landingpage\ntags:\n- latest\n- ${DRONE_COMMIT}\n# dockerfile: configs/beta/Dockerfile\njson_key:\nfrom_secret: GOOGLE_CREDENTIALS\nbuild_args:\n- website=beta\n\n- name: deploy2GKE(前哨)\nimage: nytimes/drone-gke\nenvironment:\nTOKEN:\nfrom_secret: GOOGLE_CREDENTIALS\nsettings:\nproject: rd7-project\n# 改拉參數傳入kube.yml內\n# template: configs/beta/.kube.yml\nvars:\ndeployName: yaboxxx-landing-page-beta\nenv: beta\nzone: asia-east1-a\ncluster: xbb-common\ntrigger:\n# branch:\n# - master\nref:\ninclude:\n- refs/heads/master\nevent:\n- push\n\n分成三小塊來看,\n如果以 --- 區分的話,那\nkind: pipeline\nname: Pipeline(branch)\n是必須的。\n再來是 steps ,\n根據步驟游上往下執行,如果要并行的話,則使用depend_on ,\n這部分留到下次講。\n\ntrigger ,這是觸發條件,表示在gitlab上面做了哪些動作,會觸發這個step(步驟)\n這邊的觸發事件,常用到應該是 Branch、Reference 以及 Event\n(ref. https://docs.drone.io/pipeline/docker/syntax/trigger/)\nBranch 跟 Event 比較好理解(但碰到Tag的事件又是另一回事了) 。\nReference 這個其實只要在你的git裡面下指令\ntree .git/refs/\n大概就會知道他在講些什麼,git的底層都是靠refs去用出來的\n(\nref.\nhttp://iissnan.com/progit/html/zh-tw/ch9_3.html\nhttps://titangene.github.io/article/git-branch-ref.html\n)\n但要注意的是,drone 1.X,以後的版本不支援event的tag 與 branch 共存。\n可以參考這篇\n(\nref.\nhttps://github.com/drone/drone/issues/2536\nhttps://rabbit52.com/2019/11/drone-from-0-8-to-1-0/\n)\n\nsteps:\n這部分則開始由上往下開始執行,\n像上面的程式先做的是將程式打包後,上傳到GCR上面。\n(最上面還有一段clone,會先做(這是drone預設的),將gitlab的程式複製到機器內,這樣才能做後面的上傳,\n這一塊可以 參考 https://docs.drone.io/pipeline/docker/syntax/cloning/ )\n上傳到GCR使用的 plugins/gcr ,這個image,裡面的參數請參考說明頁面\n由於這邊需要上傳到GCR,故要先到Google 的 服務賬戶申請權限 ,除了需要push以外還必須要有 storage.buckets.get\n這邊會取得一個json檔案,將內容塞入drone內的Sercets。",
"tags": [ "note","⏱"]
},
{
"title": "drone on GKE 建立",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⏱ Drone/72. drone on GKE 建立/",
"content": "前言\n正文\ngitlab的安裝方式,參考 <a class=\"internal-link\" data-note-icon=\"\" href=\"/⎈ k8s/GKE/71.gitlab on GKE 災害還原筆記/\">71.gitlab on GKE 災害還原筆記</a>\n再來是安裝drone的方式,\n這邊之前沒寫文件,重試的時候搞了一陣子。\n要先知道 runner分成哪幾種,根據你的環境選擇你要的方式。\n在drone畫面,基本上都差不多。\n有差異的點是再建置時,就直接看圖吧\nDrone Runner分成五種,適用於不同的情境\n\nDocker runner :是drone最常見的用法,pineline中的每一個step都起一個獨立的container運行特定任務,本文即是採用docker runner。\n\n在建置時,會在該runner裡面執行docker,所以當下只會看到runner裡面的cpu跟ram使用量上升。\n\nKubernetes runner:跟docker runner 的功能相似,只是改成Kubernetes 版本,如果你的服務要搭建在k8s上,就用這個。\n\n選擇kubernetes的版本,再建置時會在當下的叢集建立一個pod,\n然後就會在裡面執行要跑得步驟。\n\nExec runner:用於你的專案不適合跑在容器內的狀況EX:MacOs專案。\n\nSSH runner:直接以ssh 連線到遠端以default shell 執行pipeline流程,需要使用openssh 7.9 以上版本。\n\nDigital Ocean runner :用於當你的pipeline需要權限可以操作整台虛擬機的情況,且不適合跑在容器內。\n\n角色\n功能\n\n用戶\nGitlab\n\nDrone Server\nDrone 主服務,提供Web界面\n\nDrone Runner\n我理解為實現各種操作的適配器,例如ssh、docker、k8s操作\n\nDrone Agent\n操作主機 Docker API 的代理程序\n\nDocker Server\n主機的 Doker 程序\n\n發佈到GKE,參數說明\n發佈到GCR,參數說明\n\n再來就是要佈署 drone server跟 runner了。\nStep 1.\n首先要到Gitlab,建立oAuth的id 跟token。\n切記是在user Setting的 Application,\n因為Gitlab是我建的,所以我有另一個Admin的區域,\n不是在Admin裡面。\n\n網頁不要關, Application ID 跟 Secret等等會用到。\n\nStep 2. drone Server\n\n將一些參數改成自己的。\n\nyaml欄位\n對應的欄位\n\nDRONE_GITLAB_CLIENT_ID\nApplication ID\n\nDRONE_GITLAB_CLIENT_SECRET\nSecret\n\nDRONE_SERVER_HOST\nCallback URL 的domain\n\nDRONE_RPC_SECRET\n自行建立,runner的secret需一致\n\napiVersion: apps/v1\nkind: Deployment\nmetadata:\nname: gke-drone-server\nlabels:\napp: drone\ndrone: drone-server\nio.kompose.service: drone-server\nspec:\nselector:\nmatchLabels:\napp: drone\ndrone: drone-server\nio.kompose.service: drone-server\ntemplate:\nmetadata:\nlabels:\napp: drone\ndrone: drone-server\nio.kompose.service: drone-server\nspec:\ncontainers:\n- env:\n- name: DRONE_GITLAB_CLIENT_ID # OAuth 的 Application ID\nvalue: 5b2f90188137bab7b1c6959721feb6e55f1137919e5b4b5ce005bd5e15af536a\n- name: DRONE_GITLAB_CLIENT_SECRET # OAuth 的 Secret\nvalue: 4cc261149603b3df864677f5af37b55613f6f4d20dd65fbb3e4f77f0cbca9e15\n- name: DRONE_GITLAB_SERVER # Gitlab Server\nvalue: http://35.234.26.234\n- name: DRONE_GIT_ALWAYS_AUTH # Drone clone 時,是否每次都驗證\nvalue: "false"\n- name: DRONE_LOGS_COLOR # Log 啟用顏色辨識\nvalue: "true"\n- name: DRONE_LOGS_DEBUG # 選擇是否開啟 debug 模式\nvalue: "false"\n- name: DRONE_LOGS_PRETY\nvalue: "false"\n# - name: DRONE_LOGS_TRACE #開啟log追蹤\n# value: "true"\n- name: DRONE_RUNNER_CAPACITY # 表示一次可執行 n 個 job\nvalue: "3"\n- name: DRONE_SERVER_HOST # Drone URL,不能加HTTP,解析會在加上HTTP\nvalue: 14.199.130.26\n- name: DRONE_SERVER_PROTO # http 或者 https 連線設定\nvalue: http\n- name: DRONE_TLS_AUTOCERT # 自動生成 ssl 證書,並接受 https 連線,末認為false\nvalue: "false"\n- name: DRONE_REGISTRATION_CLOSED # 啟用的話,管理員需在用戶登入前創建用戶\nvalue: "false"\n- name: DRONE_USER_CREATE # 建立admin權限的使用者 cli登入用\nvalue: username:ezio,admin:true\n- name: DRONE_USER_FILTER # 可操作 Drone 的用戶清單\nvalue: root,ezio\n- name: DRONE_RPC_SECRET\nvalue: 824de51510f08498fa770c7798e3cc9e\nimage: drone/drone:2\nimagePullPolicy: "Always"\nname: drone-server\nports:\n- containerPort: 80\nresources: {}\nvolumeMounts:\n- mountPath: /data\nname: drone-server-claim0\nrestartPolicy: Always\nserviceAccountName: ""\nvolumes:\n- name: drone-server-claim0\npersistentVolumeClaim:\nclaimName: gke-drone-server-claim0\n\n如果要其他git的安裝方式請參考 1. 的官方文件\nref.\n\nDrone Gitlab\n\nStep 3-a. drone Runner - Docker Runner\n\n注意 DRONE_RPC_SECRET需與server一致。\n這邊會用到 docker.sock,也是因為這個的關係,\n才導致這次重新測試。\nk8s即將廢棄 Dockershim,改用containerd,\n詳細內容就不多說了,有興趣的可參考 (1) 、 (2)\n雖然我實測出來的結果,\n在containerd的node是可以用的。\n有在想是不是因為核心還是 /var/run/docker.sock 個關係,\n但隨著後續研究 docker.sock (3),發覺應該是不能用的才對...\n但為什麼能用還是搞不懂。但(4)的官方論壇有說,他不擔心這個問題,\n實際上還真的沒問題...\n補充,\n最近把node的 containerd 版本升到 1.20 後,Docker Runner就真的不能用了。應該是早期還在用舊版的containerd,所以才能跑。\napiVersion: apps/v1\nkind: Deployment\nmetadata:\nname: agent\nspec:\nselector:\nmatchLabels:\ndrone: drone-agent\nreplicas: 1\ntemplate:\nspec:\ncontainers:\n- env:\n- name: DRONE_LOGS_DEBUG\nvalue: "false"\n# - name: DRONE_LOGS_TRACE #開啟log追蹤\n# value: "true"\n- name: DRONE_RPC_SECRET\nvalue: 824de51510f08498fa770c7798e3cc9e\n- name: DRONE_RPC_HOST\nvalue: 14.199.130.26\n- name: DRONE_RPC_PROTO\nvalue: "http"\n- name: DRONE_RUNNER_CAPACITY\nvalue: "3"\nimage: drone/drone-runner-docker:1\nimagePullPolicy: ""\nname: drone-agent\nresources: {}\nvolumeMounts:\n- mountPath: /var/run/docker.sock\nname: docker-socket\nrestartPolicy: Always\nserviceAccountName: ""\nvolumes:\n- name: docker-socket\nhostPath:\npath: /var/run/docker.sock\n\nref.\n1. 檢查棄用 Dockershim 對你的影響\n2. 棄用 Dockershim 的常見問題\n3. [Docker] 掛載 /var/run/docker.sock 的用意?\n4. Drone Disscus - Docker plugin & dockershim deprecation // Kubernetes 1.20+\nStep 3-b. drone Runner - kubernete Runner\n\n注意 DRONE_RPC_SECRET需與server一致。\n\nkind: Role\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\nnamespace: default\nname: drone\nrules:\n- apiGroups:\n- ""\nresources:\n- secrets\nverbs:\n- create\n- delete\n- apiGroups:\n- ""\nresources:\n- pods\n- pods/log\nverbs:\n- get\n- create\n- delete\n- list\n- watch\n- update\n\n---\n\nkind: RoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\nname: drone\nnamespace: default\nsubjects:\n- kind: ServiceAccount\nname: default\nnamespace: default\nroleRef:\nkind: Role\nname: drone\napiGroup: rbac.authorization.k8s.io\n\n---\n\napiVersion: apps/v1\nkind: Deployment\nmetadata:\nname: gke-drone-agent\n\nlabels:\napp: drone\ndrone: drone-agent\nio.kompose.service: drone-agent\nspec:\nreplicas: 1\nselector:\nmatchLabels:\napp: drone\ndrone: drone-agent\nio.kompose.service: drone-agent\ntemplate:\nmetadata:\nannotations:\nsidecar.istio.io/inject: "true"\nlabels:\napp: drone\ndrone: drone-agent\nio.kompose.service: drone-agent\nspec:\ncontainers:\n- name: runner\nimage: drone/drone-runner-kube:latest\nports:\n- containerPort: 3000\nenv:\n- name: DRONE_RPC_SECRET\nvalue: 824de51510f08498fa770c7798e3cc9e\n- name: DRONE_RPC_HOST\nvalue: 14.199.130.26\n- name: DRONE_RPC_PROTO\nvalue: "http"\n- name: DRONE_RUNNER_CAPACITY\nvalue: "3"\n\nref.\n- KUBERNETES Runner\n問題排除\n\n首先碰到的問題是,drone沒有反應,先檢查webhook\n到專案底下的webhook選項,查看錯誤的訊息\n\n因為GKE的防火牆沒開的關係,導致webhook資料丟不過去。\n\n2. drone無法連線到gitlab\n\n本來以為是防火牆的關係,但直接連進去pod裡面,呼叫這個網址是正常的。\n後來看到 (2) 的討論,我跟他們狀況一樣,應該也是istio造成的。\n原以為是 drone server或 runner,有安裝istio的關係,\n還特別寫了\ntemplate:\nmetadata:\nannotations:\nsidecar.istio.io/inject: "false"\n\n來阻止 istio的注入(3)。\n後來想了又想,才驚覺,我要取消的應該是整個namespace的istio注入,\n因為當新的 pipeline建立時,就已經注入了istio的sidecar,\n\n所以要先讓這個namespace通通不能自動注入,\n指定其他的deploy會自動注入。\n自動注入的規則,請參考 <a class=\"internal-link\" data-note-icon=\"\" href=\"/⛵️ istio/73. istio sidecar 注入規則/\">73. istio sidecar 注入規則</a>\n\n切換namespace,無法佈署\n\nref.\n1. Gitlab Webhooks\n2. Drone CI pipeline first step clone failed: Connection refused\n3. 安裝 Sidecar\n4. istio -Resource Annotations",
"tags": ["開啟log追蹤", "開啟log追蹤", "note","⏱"]
},
{
"title": "drone build Open Source Edition",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⏱ Drone/77. drone build Open Source Edition/",
"content": "前言\n在某一天,drone就跳出來了 『Your license limit is exceeded。』\n當下真是嚇死我了,當天又是維護日,\n一堆程式要上版,自動佈署掛掉就完了,要通通手動上。\n還好,沒事,只是跳個通知在那邊,查了一些文件,\n都沒說到期了會怎樣,就這樣過了兩個月,\n也都沒事發生,本來想繼續撐下去的,\n但有其他東西要用,就順便一起動了。\n正文\n\n官方文件有寫到關於權限的部分,\n\nYour license limit is exceeded ,這個是因為你build 超過了5000次,然後你又是直接抓官方版本的image才會出現這個通知。(OS:一開始測試當然直接抓官方的image來用阿...)\n基本上只要是年收入沒到 1 million(美金)的公司,都能免費使用,但要自己打包image。\n\n其他細項,可自行參考官方網站\nBuild image\n我們可以先從官方的github看看,他們是怎麼編譯的。\ndrone.yml\n\n先執行, scripts/build.sh\n再根據 docker/Dockerfile.server.linux.amd64 的dockerfile去打包程式。\n\n下面這段,直接存成dockerfile去編譯吧,\n版本號自行更改。\n\n補充說明,\ndocker 在編譯的時候,\n每一行指令 (前面有加 RUN 或COPY..的這種算一行),\n都算是一個新的image,可以看到sha256的數值都不一樣,\n所以用 cd drone 切 路徑的話,要再同一行把要執行的command,\n都執行完。\nFROM golang AS Builder\n\nENV DRONE_VERSION v2.9.1\nWORKDIR $GOPATH/src\nRUN git clone https://github.com/drone/drone --branch ${DRONE_VERSION} --single-branch\nRUN cd drone && pwd && go mod download && \\\ngo build -ldflags "-extldflags \\"-static\\"" -tags="nolimit" github.com/drone/drone/cmd/drone-server\n\nFROM alpine:3.13 AS Certs\n\nRUN apk add -U --no-cache ca-certificates\n\nFROM alpine:3.13\nEXPOSE 80 443\nVOLUME /data\n\nRUN [ ! -e /etc/nsswitch.conf ] && echo 'hosts: files dns' > /etc/nsswitch.conf\n\nENV GODEBUG netdns=go\nENV XDG_CACHE_HOME /data\nENV DRONE_DATABASE_DRIVER sqlite3\nENV DRONE_DATABASE_DATASOURCE /data/database.sqlite\nENV DRONE_RUNNER_OS=linux\nENV DRONE_RUNNER_ARCH=amd64\nENV DRONE_SERVER_PORT=:80\nENV DRONE_SERVER_HOST=localhost\nENV DRONE_DATADOG_ENABLED=true\nENV DRONE_DATADOG_ENDPOINT=https://stats.drone.ci/api/v1/series\n\nCOPY --from=Certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/\nCOPY --from=Builder go/src/drone/drone-server /bin/drone-server\n\nENTRYPOINT ["/bin/drone-server"]\n\n本來想用go get 的方式,直接把程式build出來,\n但一直卡在go 的版號限制,看了一些文章都說要改裡面的程式。\n但這東西寫完,基本上就不會再動了。\n只好用git clone把程式先抓下來,再build了。\nref.\n\n使用容器方式編譯無功能限制的 Drone CI\ngo get命令——一鍵獲取代碼、編譯並安裝\ngo 命令",
"tags": [ "note","⏱"]
},
{
"title": "drone k8s-runner 進階設定",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/⏱ Drone/78. drone k8s-runner 進階設定/",
"content": "前言\n再上篇 <a class=\"internal-link\" data-note-icon=\"\" href=\"/⏱ Drone/72. drone on GKE 建立/\">72. drone on GKE 建立</a>,有談到k8s runner,\n那時候都在default 的 namespace上面運作,\n所以沒什麼問題,\n但一到了正式環境,要切專門的namespace,\n就陣亡拉)))))\n正文\n這篇會講到兩個東西,\n\nRBAC(Role-based Access Control)\ndrone k8s-runner policy\n\nStep 1.\n先從Cloud RBAC開始說起,\n基本概念如下圖\n\nkind: Role\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\nnamespace: default\nname: drone\nrules:\n- apiGroups:\n- ""\nresources:\n- secrets\nverbs:\n- create\n- delete\n- apiGroups:\n- ""\nresources:\n- pods\n- pods/log\nverbs:\n- get\n- create\n- delete\n- list\n- watch\n- update\n\n---\n\nkind: RoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\nname: drone\nnamespace: default\nsubjects:\n- kind: ServiceAccount\nname: default\nnamespace: default\nroleRef:\nkind: Role\nname: drone\napiGroup: rbac.authorization.k8s.io\n\nrole : 設定權限能做什麼事\nroleBinding : 要將哪個角色綁定權限到sa帳號\n這邊簡單說明roleBinding (因rolebinding的roleRef 無法指定ns),\n\n將 role, namespace 在 default 的 drone 跟\nserviceAccount的 namespace在 default 的 default 綁在一起,\n\n更細項的說明,請參考 (1)~(4)\n當服務沒有指定是哪一個 『serviceAccountName』,就會使用預設的default 。\n所以,如果將namespace通通改成drone的話,會發生什麼事?\n會先在drone的畫面看到 skip\n\n然後查看 k8s-runner的 log,會看到沒有權限,被拒絕執行。\n\nStep 2.\n再來要解決權限問題,\n因為k8s-runner,預設都是使用 default(namespace)的default再建立pod。\n所以,現在有兩種做法(這邊會講第二種做法)。\n\nrole的權限,給他能夠在不同的ns也能佈署的權限(這部分應該是建立clusterRole,沒試過)。\nk8s-runner在pipeline時,要求在指定的namespace做動作。\n\n建立一個 policy(5) 的 yml,\n底下的關鍵欄位,有在碰k8s的應該都很熟,\nmatch這塊要再測試看看,這邊就先註解掉。\n(文件上是說 ,可以用來定義多個policy用,\n當有符合時,就執行下面的policy)\n這邊設定規則是,\n\n佈署時,佈署到drone的namespace ,\n資源請求是 512Mi,節點選擇的label 是 disktype: ssd\n\nkind: policy\nname: drone\n\n# match:\n# repo:\n# - "octocat/*"\n# - "octocat/hello-world"\n\nmetadata:\nnamespace: drone\n\nresources:\nrequest:\nmemory: 512MiB\n# limit:\n# cpu: 4000\n# memory: 1GiB\n\nnode_selector:\ndisktype: ssd\n\n再來要在runner裡面掛載這個檔案,直接用 configMap將檔案載入。\n建立configmap\nkubectl create configmap -n drone drone-policy --from-file=policy.yml --dry-run=client -o yaml | kubectl apply -f -\n\nk8s-runner內掛載configmap\n要特別注意env ,\nDRONE_POLICY_FILE(6),需要指定你的yml位置。\napiVersion: apps/v1\nkind: Deployment\nmetadata:\nname: drone-runner-k8s\nnamespace: drone\nlabels:\ndrone: runner-k8s\nspec:\nreplicas: 1\nselector:\nmatchLabels:\ndrone: runner-k8s\ntemplate:\nmetadata:\nlabels:\ndrone: runner-k8s\nspec:\ncontainers:\n- name: runner\nimage: drone/drone-runner-kube:latest\nports:\n- containerPort: 3000\nvolumeMounts:\n- mountPath: /policy.yml\nname: policy\nsubPath: policy.yml\nenv:\n- name: DRONE_POLICY_FILE\nvalue: /policy.yml\nvolumes:\n- configMap:\ndefaultMode: 420\nname: drone-policy\nname: policy\n\n附註,如果node_selector,選擇的節點是ssd的硬碟的話,\n時間會減少 35%。 但每個月會多13塊美金。\n再來下篇應該就是寫將drone完整導入istio的做法了\nref.\n\n使用 RBAC 鑑權\nKubernetes權限管理之RBAC\nDay-28 瞭解 Namespace 與 Rbac\n[Kubernetes] 如何取得合法可用的權限,讓 pod 與 API server 溝通\nPolicies\nDRONE_POLICY_FILE\n配置 Pod 的 Service Account",
"tags": [ "note","⏱"]
},
{
"title": "GCP MOC",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/0.GCP MOC/",
"content": "雲架構中心\nref. ### 雲架構中心\nPrice\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/Price/GCP費用/\">GCP費用</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/Price/GCP CPU用途/\">GCP CPU用途</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/Price/180. GCP 監控費用/\">180. GCP 監控費用</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/Price/126. GCP 硬碟費用比較/\">126. GCP 硬碟費用比較</a>\nGCP\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/88.批次修改GCP的label/\">88.批次修改GCP的label</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/5. Google Cloud Function限制/\">5. Google Cloud Function限制</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/95.cloud build的問題/\">95.cloud build的問題</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/97. Anthos 初體驗/\">97. Anthos 初體驗</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/120. 指令備份cloudSQL及下載/\">120. 指令備份cloudSQL及下載</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/121.cloudCDN設定/\">121.cloudCDN設定</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/128. 解決 the gcp auth plugin is deprecated in v1.22+/\">128. 解決 the gcp auth plugin is deprecated in v1.22+</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/161. GKE利用pubsub通知訊息到discord/\">161. GKE利用pubsub通知訊息到discord</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/164.gcloud install by bash/\">164.gcloud install by bash</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/181. cloudstorage無法使用cloudflare轉址/\">181. cloudstorage無法使用cloudflare轉址</a>\nGCE\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/19. GCE硬碟增加容量大小/\">GCE硬碟增加容量大小</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/46.列出GCE的所有VM/\">46.列出GCE的所有VM</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/46.GCE機器列表內的CPU個數/\">46.GCE機器列表內的CPU個數</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/79. gcloud compute instance 筆記/\">GCE指令</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/130. Google IAP ssh失敗/\">130. Google IAP ssh失敗</a>\nGCS\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/8.GCS使用方式/\">GCS使用方式</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/109.GCS臨時下載權限/\">109.GCS臨時下載權限</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/127. fuse device not found, try 'modprobe fuse' first/\">127. fuse device not found, try 'modprobe fuse' first</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/129. nginx 掛載gcs/\">129. nginx 掛載gcs</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/135. gsutil整批複製/\">135. gsutil整批複製</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/140. gcs 掛載domain/\">140. gcs 掛載domain</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/141. gcs自動刪除檔案/\">141. gcs自動刪除檔案</a>\nNetwrok\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/9.GCP網路對外的方式/\">GCP網路對外的方式</a>\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/13.騰訊雲連接GOOGLE雲/\">13.騰訊雲連接GOOGLE雲</a>\nTroubleshooting\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/17. Gcloud AttributeError module importlib has no attribute util/\">17. Gcloud AttributeError module importlib has no attribute util</a>",
"tags": [ "note","☁️"]
},
{
"title": "GCS臨時下載權限",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/109.GCS臨時下載權限/",
"content": "碎碎念\n今天維護,後端同仁要cloudSQL的備份檔,\n然後,因為他們都沒權限,只好丟去網路空間,給他們抓。\n我就在想,沒道理阿,應該有個方法能夠開特定的檔案臨時給人用。\n正文\n由於GCS的權限是 統一儲存分區級存取權,\n所以不能細分檔案權限給別人用。\n所以,開V4簽名,就能給別人訪問了。\ngsutil signurl -d 1m gcs-download.json gs://ai-assist-data/"Cloud_SQL_Export_warehouse_2022-10-12 (06:03:23)".bak\n\n1m 表示,只開放一分鐘的時間\ngcs-download.json是SA,從IAM那邊找到一個有權限下載的帳號產生的金鑰。\ngs 的網址,可以到詳細資料內取得 gsutil URI\n\n這個執行後,會得到一串\n\n把後面的https複製,就能拿來用了。\n錯誤處理\n如果在執行signurl的時候發生以下錯誤,\nCommandException: The signurl command requires the pyopenssl library (try pip install pyopenssl or easy_install pyopenssl)\n\n執行\npip3 install pyopenssl\n\n其他方式\n將底下的檔案跑遞迴(-R),通通設成public-read\ngsutil -m acl set -R -a public-read gs://bucket",
"tags": [ "note","☁︎"]
},
{
"title": "指令備份cloudSQL及下載",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/120. 指令備份cloudSQL及下載/",
"content": "前言\n有人不習慣ui操作,\n加上他們是兩三個月用一次,\n那就生個指令給他們用吧。\n做成自動化應該也可以,\n只是要看一下權限要用誰的。\n正文\n主要的兩行指令,請將視角往下移\n\ntest-db01: cloudSQL的instance名稱\ngs://data/desk-22-12-14.bak :要存放cloudStorage的位置\nDesk : 資料庫名稱\n\ngcloud storage cp\n\ngcloud beta sql export bak test-db01 gs://data/desk-22-12-14.bak \\\n--database=Desk\n\ngcloud storage cp gs://data/desk-22-12-14.bak /Users/daimom/Downloads\n\nTroubleshooting\n\n執行 gcloud storage cp ,出現error invalid choice storage\n\n更新 gcloud components\ngcloud components update\n\nref. gcloud beta functions command says "Invalid choice functions"\n\n權限問題\ncloudSQL 備份權限\nCloud SQL Editor 角色和 storage.objectAdmin IAM 角色\ncloudStorage下載權限\n這部分就需要到cloudStorage的bucket設定了\nref.\n使用 BAK 檔案匯出和匯入\n從儲存桶下載對象",
"tags": [ "note","☁︎"]
},
{
"title": "cloudCDN設定",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/121.cloudCDN設定/",
"content": "碎碎念\n之前測完後就忘了寫,\n但今天有人問我才想起來,\n我到底跑去哪設定的!?\n現在趕緊補一下\n正文\n如果已經在GCP上面建立好了負載平衡,\n那就到後端設定,看要針對哪個服務去開啓cdn就好了。\n上面有個逾時的設定,看要設定多少,\n當初同事是有說他測30秒就會斷線一次,\n所以我有把這邊拉長。\n\n這邊設定完後,在cloudCDN上面就會多一個設定出來。\n\n也能用指令去查,啓用cdn時的欄位\nkubectl get BackendConfig\n\nref. cloudCDN",
"tags": [ "note","☁︎"]
},
{
"title": "fuse device not found try modprobe fuse first",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/127. fuse device not found, try 'modprobe fuse' first/",
"content": "睡睡念\n以前用GKE掛載gcs的時候發生錯誤,fuse device not found, try 'modprobe fuse' first。解決方法。\n現在GKE有了新的掛載GCS方法了,Announcing Cloud Storage FUSE and GKE CSI driver for AI/ML workloads。\n目前我沒采用此方式,請他們改用api的方式上傳檔案了,\n要訪問的話,用Load balancing 指向GCS bucket。\n這文章用方法應該不太適用,\n而且此方法有缺點,當你檔案數量太多時,會掛載不起來。\n正文\n\napt install -y gnupg lsb-release\nexport GCSFUSE_REPO=gcsfuse-`lsb_release -c -s`\nexport GCSFUSE_REPO=gcsfuse-buster\necho "deb https://packages.cloud.google.com/apt $GCSFUSE_REPO main" | tee /etc/apt/sources.list.d/gcsfuse.list\ncurl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -\napt-get update\napt-get install -y gcsfuse\nexport GOOGLE_APPLICATION_CREDENTIALS=/home/gcs-download.json\ngcsfuse sms_backend_backup ./gcs-mount\n\n需要用特權模式\n在yaml檔裏面,加上\nsecurityContext:\nprivileged: true",
"tags": [ "note","☁️"]
},
{
"title": "解決 the gcp auth plugin is deprecated in v1.22+",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/128. 解決 the gcp auth plugin is deprecated in v1.22+/",
"content": "睡睡念\n每次下kubectl的指令總會跳這個錯誤出來,\n不處理也沒什麼事,但就是都會出現。\n今天...就解決吧\n正文\n警告訊息通常是這樣,\n但你deploy的服務都還是會跑。\n\nWARNING: the gcp auth plugin is deprecated in v1.22+, unavailable in v1.26+; use gcloud instead.\nTo learn more, consult https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke\n\n這是由於docker在安裝的時候,會順便將kubectl安裝進去,\nwhere kubectl\n\n可以得到 kubectl的執行檔位置\n\n/usr/local/bin/kubectl\n\n查詢kubectl的softlink 位置,會查到kubectl的命令是跟docker連結的。\n附註, ll 跟 ls -la 同意\nls -la /usr/local/bin\n\n先將本來的softlink刪除,\nrm /usr/local/bin/kubectl\n\n安裝gcloud版本的kubectl\ngcloud components install kubectl\n\n裝完後如果還不認識指令,\n需要額外處理。\n先檢查一下gcloud有沒有安裝好kubectl,\n如果path有路徑就代表正常,不然需要重新製作softlink\ngcloud info | grep -i kubectl\n\n製作softlink\nln /usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/bin/kubectl /usr/local/bin/kubectl\n\nref.\n- [實作筆記] 錯誤處理 the gcp auth plugin is deprecated\n- How to set path to kubectl when installed using gcloud components install?",
"tags": [ "note","☁︎"]
},
{
"title": "nginx 掛載gcs",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/129. nginx 掛載gcs/",
"content": "睡睡念\n今天要上QA測試了,然後我突然發現我之前測完沒留下筆記。\n現在都快忘光了,還好最後有找回記憶。\n來補一下了。\n正文\n今天要做的是把GCS變成一個圖片上傳空間,\n可以用nginx來訪問。\n\n前言\n某個案子,要整個翻掉重做,這次要讓VM的機器跟GKE的pod能夠同時存取一個儲存空間,\n預計使用Google Cloud Storage,踩了一個早上的坑。\n正文\n預計做兩個項目\n\n在VM上面掛載gcs的資料夾\n\n在GKE 上面的pod同時掛載 gcs的資料夾\n\n在VM上面掛載gcs的資料夾\n安裝方式,目前我的vm是 RedHat 所以用下面的方式,CentOS也是用同樣的方式\n\nConfigure the gcsfuse repo:\n\nsudo tee /etc/yum.repos.d/gcsfuse.repo > /dev/null <<EOF\n[gcsfuse]\nname=gcsfuse (packages.cloud.google.com)\nbaseurl=https://packages.cloud.google.com/yum/repos/gcsfuse-el7-x86_64\nenabled=1\ngpgcheck=1\nrepo_gpgcheck=1\ngpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg\nhttps://packages.cloud.google.com/yum/doc/rpm-package-key.gpg\nEOF\n\nInstall gcsfuse:\n\nsudo yum install gcsfuse\n\n完成,其他安裝方式,請參考GoogleCloudPlatform/gcsfuse/install.md\n登入使用,\n這邊先使用 gcloud auth login 做測試\n先建立資料夾 mkdir upload\n掛載 gcsfuse my-bucket upload\n卸除掛載 fusermount -u upload\nDebug用\ngcsfuse --foreground --debug_gcs --debug_http --debug_fuse --debug_invariants --key-file=/home/user/Downloads/my-key.json mybucket /upload\n\n永久加入GOOGLE_APPLICATION_CREDENTIALS變數\n開啟 /etc/profiles\n新增 export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/my-key.json"\n修改檔案後要想馬上生效還要執行#\nsource /etc/profile不然只能在下次重進此使用者時生效。\n\nref.Linux系統環境變數和別名設定(永久生效和臨時生效)\n附註,json檔案的取得在 IAM角色內的服務賬戶\nref.創建和管理服務帳號密鑰。\n新增完GCS,記得把權限給服務賬戶。記得選擇完整權限(Fig. 1)\n自動掛載\n有權限了已後,再來就是自動掛載了。\n到/etc/fstab上,輸入\nmy_bucket /home/ezio/upload gcsfuse key_file=key/key.json,rw,user,allow_other,uid=1008,gid=1009 0 0\n\n重開機測試看看,收工。\nref.\nHow to use mount command in fstab file\ngcsfuse automount on a non root user\n查詢目前登入使用者的uid 跟 gid\nid $(whoami)\n\n如果要看全部使用者的話,\ncat /etc/passwd\n\nref.Linux 的帳號與群組\n\n在GKE 上面的pod同時掛載 gcs的資料夾\n基本的方式,\n先自己產生一個 image\n\nFROM golang:1.14-alpine AS build-env\nENV GO111MODULE on\n\n# WORKDIR /工作名錄名稱 當前的工作目錄名稱,若是不存在則會新建該目錄,\n# 需要注意的是copy跟run的指令都是以WORKDIR為當前目錄下去跑的,\n# 運用的時候需要注意相對位置。\nWORKDIR $GOPATH/src\n\nRUN go get -u github.com/googlecloudplatform/gcsfuse\n\nCOPY key.json .\n\nFROM alpine:3.6\nRUN apk add --no-cache ca-certificates fuse && rm -rf /tmp/*\nCOPY --from=build-env /go/bin/gcsfuse /usr/local/bin\nCOPY --from=build-env /go/src/key.json /\nWORKDIR /\n\n佈署 Deployment\napiVersion: apps/v1\nkind: Deployment\nmetadata:\nlabels:\napp: gcs-fuse\nversion: v1\nnamespace: debug\nname: gcsfuse-test\nspec:\nreplicas: 1\nselector:\nmatchLabels:\napp: gcs-fuse\nversion: v1\ntemplate:\nmetadata:\nlabels:\napp: gcs-fuse\nversion: v1\nspec:\ncontainers:\n- name: gcsfuse-test\nimage: gcr.io/your-project/gcsfuse:v1.2\n# image: golang:1.14-alpine\n# command: [ "/bin/sh", "-c", "--" ]\n# args: [ "while true; do sleep 600; done;" ]\nsecurityContext:\nprivileged: true\ncommand:\n- "/bin/sh"\n- "-c"\n- "while true; do mkdir /upload ; gcsfuse --key-file=key.json your-bucket /folder; sleep 600; done; "\n\n如果跟現有的程式整合的話,\n由於要執行多行指令,需使用shellScript的方式執行指令。\n可能會遇到下列情況\n"exec: "/init.sh": permission denied\n在Dockerfile上修改權限\nRUN chmod +x /init.sh\n\nref.\ngetting permission denied in docker run\nexec user process caused "exec format error"\n有人說在sh的頂端加上\n#!/bin/bash\n但我試了沒用,在猜想可能是alpine linux沒有bash導致\n所以改用下面這個\nENTRYPOINT ["sh","/run.sh"]\n\nref. standard_init_linux.go:178: exec user process caused “exec format error”\n執行sh時卡住,debug方式\n用if else檢查\nif mkdir /upload; then\necho "mkdir directory! Success" 1>&2\ngcsfuse --key-file=key.json yellow-video /upload\nelse\necho "Could not mkdir directory!" 1>&2\nexit 1\nfi\n\n另外,最後找出來原因是因為先執行go的程式,導致後續卡住,所以先建立資料夾後,再執行go\nref.\nShell Script 遇到錯誤時自動退出離開\nref.\n身份驗證入門\nLinux系統環境變數和別名設定(永久生效和臨時生效)\n\n這篇有講到如何在deploy掛載GCS\n通常就是要安裝一些東西。\n會使用到gcsfuse這個指令,\n所以我選擇直接建一個image,\n然後掛載的時候直接用那個image就好。\ngcs-download.json 是 要掛載GCS用的權限json檔\nFROM nginx:latest\nWORKDIR /app\n\nCOPY gcs-download.json .\n#Start CloudStorage\nRUN apt update && apt install -y gnupg lsb-release\nRUN echo "deb https://packages.cloud.google.com/apt gcsfuse-$(lsb_release -c -s) main" | tee /etc/apt/sources.list.d/gcsfuse.list\nRUN curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -\nRUN apt-get update && apt-get install -y gcsfuse\nENV GOOGLE_APPLICATION_CREDENTIALS=/app/gcs-download.json\n\nWORKDIR /usr/share/nginx/html/files\n\n然後部署的yaml,\n這邊要注意的地方是\n1.\nnginx.conf 要加上 user root ,\n這是因爲gcs掛載資料夾是用root的角色,所以如果nginx不用root啓動,\n會出現403的權限問題。\nref. 四種解決Nginx出現403 forbidden 報錯的方法\n2.\ndaemon off; 這部分指的是要讓nginx能夠在前景執行,不然pod會一直重開。\nref. nginx -g "daemon off;" 你學廢了嗎?\napiVersion: v1\nkind: ConfigMap\nmetadata:\nname: systemfile-nginx-config\nnamespace: default\ndata:\nnginx.conf: |\nuser root;\nworker_processes auto;\n\nerror_log /var/log/nginx/error.log notice;\npid /var/run/nginx.pid;\n\nevents {\nworker_connections 1024;\n}\n\nhttp {\ninclude /etc/nginx/mime.types;\ndefault_type application/octet-stream;\n\nlog_format main '$remote_addr - $remote_user [$time_local] "$request" '\n'$status $body_bytes_sent "$http_referer" '\n'"$http_user_agent" "$http_x_forwarded_for"';\n\naccess_log /var/log/nginx/access.log main;\n\nsendfile on;\n#tcp_nopush on;\n\nkeepalive_timeout 65;\n\n#gzip on;\n\ninclude /etc/nginx/conf.d/*.conf;\n}\n\n---\napiVersion: v1\nkind: ConfigMap\nmetadata:\nname: sms-systemfile-config\nnamespace: default\ndata:\ndefault.conf: |\nserver {\nlisten 80 default_server;\nserver_name _;\nserver_tokens off;\n\nindex index.html;\n\nlocation /files {\nalias /usr/share/nginx/html/files;\nautoindex on;\n}\n\nlocation / {\nroot /usr/share/nginx/html;\nindex index.html;\n}\n\nerror_page 500 502 503 504 /50x.html;\nlocation = /50x.html {\nroot /usr/share/nginx/html;\n}\n}\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\nname: systemmanageservice-systemfile\nnamespace: default\nlabels:\ngroup: systemmanageservice\napp: systemfile\nspec:\nreplicas: 1\nrevisionHistoryLimit: 5\nprogressDeadlineSeconds: 15\nselector:\nmatchLabels:\ngroup: systemmanageservice\napp: systemfile\nstrategy:\nrollingUpdate:\nmaxSurge: 25%\nmaxUnavailable: 25%\ntype: RollingUpdate\ntemplate:\nmetadata:\nlabels:\ngroup: systemmanageservice\napp: systemfile\nspec:\ncontainers:\n- name: systemmanageservice-systemfile\nimage: gcs-nginx:0.0.2\ncommand:\n- /bin/bash\n- '-c'\n- >-\ngcsfuse systemfile-qa /usr/share/nginx/html/files && nginx -g\n"daemon off;";\nimagePullPolicy: Always # IfNotPresent, Always, Never\nsecurityContext:\nprivileged: true\nports:\n- name: http\ncontainerPort: 80\nprotocol: TCP\nresources: {}\nterminationMessagePath: /dev/termination-log\nterminationMessagePolicy: File\nvolumeMounts:\n- name: config-volume\nmountPath: /etc/nginx/conf.d/default.conf\nsubPath: default.conf\nreadOnly: true\n- name: nginx-config-volume\nmountPath: /etc/nginx/nginx.conf\nsubPath: nginx.conf\nreadOnly: true\nvolumes:\n- name: config-volume\nconfigMap:\nname: sms-systemfile-config\nitems:\n- key: default.conf\npath: default.conf\ndefaultMode: 420\n- name: nginx-config-volume\nconfigMap:\nname: systemfile-nginx-config\nitems:\n- key: nginx.conf\npath: nginx.conf\ndefaultMode: 420\ndnsPolicy: ClusterFirst\nrestartPolicy: Always\nterminationGracePeriodSeconds: 30\nschedulerName: default-scheduler\nsecurityContext: {}",
"tags": ["Start", "tcp_nopush", "gzip", "note","☁︎"]
},
{
"title": "騰訊雲連接GOOGLE雲",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/13.騰訊雲連接GOOGLE雲/",
"content": "前言\n又在搞新的東西了,這次要把騰訊雲(TKE)跟Google雲(GCP),做VPN對連,\n這次一樣又弄了幾天....最後還是找了GOOGLE工程師協助。\n正文\n下面的步驟,基本上都是TKE跟GCP,互相切換設定。\n\n騰訊雲設定網關IP\n私有網路-> VPN連接->VPN網關\n\n!<a class=\"internal-link is-unresolved\" href=\"/404\">13.fig-1.jpg</a>\n內容就照想輸入的打,輸入完成後會看到公網IP,為了方便溝通,就稱呼他為TKE的閘道IP。\n\nGCP設定VPN閘道\n這邊的選項比較繁瑣,因為騰訊雲不支援IKEv2,同時也不支援BGP的協定,\n所以Google要使用傳統VPN。\n高可用性的VPN有些要求才能使用,請參考轉為高可用性 VPN\n\n從Fig.3 有連結可以切到 傳統VPN設定,\n再來終於要開始設定GCP閘道IP了。\n建立IP,這邊建立的就是GCP的閘道ip,這組就是要與 TKE的閘道IP 對聯的IP。\n\n其他的選項,\n\n名稱: 自填\n網路: VPN 要連結的 Compute Engine 網路\n區域: 連結至 Compute Engine 網路的閘道所在地區\n\nGCP的通道設定\n\n名稱: 隨意\n遠端對等互連IP: TKE的閘道IP\nIKE版本:這邊選 IKEv1\nIKE預先共用金鑰: 可以自行輸入 或是 由系統產生,但要注意騰訊雲不支援 特殊符號(. / 之類的),\n所以要注意自行產生的金鑰\n導向選項: 這邊選擇 『依據政策』\n遠端網路ip範圍:輸入TKE的私有網路範圍,可以從『騰訊雲的私有網路->私有網路』 看到 IPv4 CIDR (Fig.6)。\n\nGCP的防火牆設定\n可能需要配置防火牆規則,不確定。\nref. 配置防火牆規則\n4. 騰訊雲的對端網關設定\n私有網路->VPN連接->對端網關\n\n名稱: 隨意\n公網IP: 這邊就是輸入 GCP的閘道ip\n標籤: 可以不打\n\n騰訊雲的VPN通道設定\n\n通道名稱:隨意\n地域: 連結至網路的區域\nVPN網關類型: 私有網路。 雲聯網指的是 騰訊雲內部各區域的私有網路互聯(ref.雲聯網產品概述)\n私有網路: 請看(Fig.6)\nVPN網關: 請看(Fig.1)\n對端網關: 請看(Fig.7)\n預共享金鑰: 請看(Fig.5) 的預先共享金鑰\n\nSPD策略\n\n本端網段: 請看(Fig.6)\n對端網段: 請看(Fig.4)的網段\n\nIKE、IPsec配置\n需與下圖一摸一樣。\n\nref. 支持的 IKE 加密方式,此文內(IKEv1 加密方式的第二階段,指的就是 IPsec配置)\nIKE 配置\n\n版本: IKEv1\n加密算法: AES-128\n認證算法: SHA1\n協商模式: main\nDH group: DH2\nIKE SA Lifetime: 36600\n\nIPsec 配置\n\n加密算法:AES-128\n認證算法:SHA1\nPFS: DH-GROUP2\nIPsec sa Lifetime:10800\n\n結尾(不,還有路由要設定)\n\n這邊會先看到VPN的通道狀態是 已聯通, 但如果實際去Ping機器,會發現還是不通。\n\n騰訊雲路由表設定\n私有網路->路由表->默認路由表\n\n新增路由策略(Fig.13)\n\n新增路由(Fig.14)\n\n新增路由:這邊是從騰訊雲要跳去GCP的網段,所以這邊要輸入的是(Fig.9)的對端網段\n下一跳類型:選擇VPN網關\n\n結論\n可能有人會想,為什麼騰訊雲要設定路由,\n而GCP不用設定路由。\n因為在設定(Fig.5)的時候,就已經幫你設定好了。\n但如果走的是 依據路徑,那這塊就必須要自行設定了。\n如果想要看路由表,可以到\nGCP->VPC網路->路徑\n\nref.\n使用靜態路由創建傳統 VPN\n網絡和隧道路由\n【VPN錦囊】 騰訊雲對接華為雲配置指南\n通過VPN連接到VPC\nMTR:Linux 網路診斷工具使用教學",
"tags": [ "note","☁︎"]
},
{
"title": "Google IAP ssh失敗",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/130. Google IAP ssh失敗/",
"content": "睡睡念\n為什麼會發生,俺不知道。\n但好像是好之前硬碟空間不夠,我砍了資料夾的關係...\n正文\n先看個錯誤訊息\n\n權限授權失敗,一般使用ssh連線的話,大部分都是server的ssh key出問題\n可以先參考 [GCP]遇到permission denied (publickey)怎麼辦?\n所以我才回想起,之前我好像去砍過資料夾。\n所以先弄ssh能夠直連GCE的機器,再來細看裏面的狀況。\nSSH解法\n\n建立ssh key\n\nssh-keygen -C "ezio"\n\n這邊使用ezio當作名稱\n\n複製 public key\n將 ~/.ssh/id_rsa.pub的內容複製\n有 .pub的是公鑰 ,沒有的是 私鑰\n\n貼上公鑰\n到GCE的VM執行個體內,將剛剛取得的公鑰貼到 『安全殼層金鑰』\n\n直接用ssh連線\n\n\tssh ezio@32.12.32.12\n\n一般到這邊就結束了,但今天的主題是用IAP無法登入。\n更詳細的ssh 用法,請參考下列網址\nref.\n- ### [Git] 多個SSH Key與帳號的設定(Mac)\n- [教學] 產生SSH Key並且透過KEY進行免密碼登入\nIAP解法\n能連進去了,終於確定裏面沒有我之前的資料夾。\n所以應該是這樣導致無法登入?\n然後查了一下目前的使用者帳號\ncat /etc/passwd | awk -F: '{print $1}'\n\n有我mail的使用者帳號,\n然後刪除!!!\nuserdel -r daimom\n\n再來試試,用IAP登入,看能不能在VM上面重建一個使用者\ngcloud compute ssh --tunnel-through-iap --project sms --zone asia-east1-b test-service01\n\n還是同樣的權限失敗。\n最後,在GCE的設定畫面,將本來的安全殼層金鑰刪掉,強迫重建,\n終於能連了",
"tags": [ "note","☁︎"]
},
{
"title": "gsutil整批複製",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/135. gsutil整批複製/",
"content": "睡睡念\n幫後端改圖片上傳的架構,直接把GCE(Google Compute Engine)的機器改成用GCS(GoogleCloudStorage),所以要把GCE的圖搬到GCS。\n正文\n\n首先要用到的是 <a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/135. gsutil整批複製/\">關閉ssh連線後,仍可執行程式</a> ,不然用gcloud 連線時間過久是會被切斷連線的。\n\n情境 1 整批資料夾\n將nfs資料夾裏面的所有檔案/資料夾複製到bucket裏面,\n-m 是多工,-r 是複製底下資料夾的檔案\ngsutil -m rsync -r nfs gs://systemfile-stage/\n\nref. gsutil rsync\n情境2 ,複製特定資料夾\n需要先建立一個文字檔,將資料夾名稱寫入\nrsync.txt\n\n20220201\n20220301\n20220310\n\nwhile read p;\ndo\nfolder=$(echo "$p");\ngsutil rsync -r nfs/$p gs://systemfile-stage/$p/\ndone < rsync.txt\n\n情境3,複製特定圖片\n這邊只能根據你的來源隨機應變了,\n我的文件格式為\nkeepfile.csv\n\n"files/20230217/104abc69-e612-4b6c-abe4-52b91b79562f.jpg","17/2/2023 19:27:46.79"\n"files/20230217/7a30d9eb-5e7c-4eb8-93c9-a72e5bd74f78.jpg","17/2/2023 19:28:47.56"\n"files/20230217/ea81d738-ff0c-416a-b6d9-3520fda8f0ed.jpg","17/2/2023 19:32:47.44"\n"files/20230217/7a7e1c75-4bec-4831-9a58-fa9650a82df1.jpg","17/2/2023 19:33:24.94"\n"files/20230217/cf495ecb-71a9-4d46-95f4-b051f260523a.jpg","17/2/2023 19:33:49.4"\n"files/20230217/eb05163b-bc0f-4e3b-96d5-82b0bb4f3a8d.jpg","17/2/2023 19:34:41.463"\n\n所以,要改讀csv的格式,然後將路徑與檔案名稱拆開,\n最後才複製圖片過去。但這個過成真的久,\n如果可以最好是用rsync複製資料夾吧。\n$file的變數,拆解出來有" ,所以又用了<a class=\"internal-link\" data-note-icon=\"\" href=\"/🐧 Linux/133. shell script字串處理/\">133. shell script字串處理</a>的方式,將"刪除。\nwhile IFS="," read -r path date\ndo\nfolder=$(echo "$path" | awk -F '/' '{print $2}');\nfile=$(echo "$path" | awk -F '/' '{print $3}');\ngsutil cp -n nfs/$folder/${file%*\\"} gs://systemfile-stage/$folder/\ndone < keepfile-sort.csv\n\nref.\n\nHow to Parse a CSV File in Bash\ngsutil cp",
"tags": [ "note","☁︎"]
},
{
"title": "gcs 掛載domain",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/140. gcs 掛載domain/",
"content": "睡睡念\n這篇文章要完成得部分有\n\n建立LB,連結到GCS\n設定cloud Armor白名單\nCertificate Manager 增加 ssl憑證\n\n正文\n建立負載平衡\n建立負載平衡 -> HTTP(S) 負載平衡\n\n不能用區域的,因為區域的不支援後端值區\n\n前端設定\n這邊建議最好就直接建立一個ip,不要用臨時的。\n如果通訊協定要用https,需要設定憑證,所以這邊先選擇http就好\n\n後端設定\n建立值區\n\n第一個箭頭,選擇你要建立的值區\n第二個箭頭,看要不要建CDN\n第三個箭頭,是設定白名單(cloud Armor)用的,這邊先不設定,等等第二部分會說\n\n主機與路徑規則\n預設會直接進入bucket,這邊要注意,記得要將bucket 設定為公開。\n\n設定cloud Armor\n上一部份有說到設定白名單(cloud Armor)\n網路安全性-> Cloud Armor\n這邊要增加的設定是 Edge 安全性政策,不是後端安全性政策,\n因為只有edge安全性政策支援後端儲存分區\nref. 安全政策的類型。\n\n新增的時候,選擇 Edge安全性政策,如果沒看到這個選項,\n你可能已經進到政策裏面的規則了。\n\n建立完成後,可以從目標去新增要新增的對象,或是到負載平衡那邊做修改。\ncloud armor 目標新增\n\n選擇『負載平衡器後端值區』,再選擇你的bucket\n\n負載平衡器修改\n後端設定 -> 修改\n\n箭頭處選擇剛剛新增的 cloud armor規則\n\nCertificate Manager 新增憑證\nssl憑證,在GCP上面是可以直接幫你管理的。\n雖然不支援 Wildcard SSL Certificate\n\n憑證分成自己管理與google代管,\n自己管理,時間到就要自己上傳新的憑證。\ngoogle管理,不用管,時間到會自己展延,前提是你必須要有該domain。\n選擇google代管的憑證,輸入要管理的domain\n\n儲存後,回到畫面應該會看到正在佈建中(PROVISIONING),\n這個需要一點時間,最久可能要到60 分\n\n然後到dns伺服器上面綁定domain跟ip了,\n我是使用cloudflare,就不截圖了。\nref. 使用 Google 管理的 SSL 證書\n設定好了以後,回到負載平衡的前端設定\n第一個箭頭,可以選擇跟上面一樣的ip(但你必須先幫他建立)\n第二個箭頭,選擇剛剛新增的ssl憑證,記得一定要新增,\n不然我卡了三個多小時還沒部署完。\n\nref. 部署概覽\n綜合設定\n假設有一個情境是希望domain後面一定要有files才能看圖的話,\n需要用到『進階型主機與路徑規則(第一個箭頭)』\n第二個箭頭設定domain\n第三個箭頭新增新的路徑規則\n\n路徑前置字串重新編寫,將/files轉成 / 訪問bucket\n\n另外要注意,由於每個規則都有一條預設的條件,\n『任何不相符合的項目』,這個可以選擇要不要導轉到其他網站。",
"tags": [ "note","☁︎"]
},
{
"title": "gcs自動刪除檔案",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/141. gcs自動刪除檔案/",
"content": "睡睡念\n本篇的目標,測試用的bucket,每隔一段時間就刪除檔案。\n或是轉到更便宜的bucket。\n先說個概念,一個bucket裏面,他的檔案類型可以是不一樣的。\n正文\n上面那句話不懂的話,直接看圖吧。\n\n由於每個儲存類型的價格不一樣,量大的話還是能省不少錢。\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/Price/126. GCP 硬碟費用比較/\">126. GCP 硬碟費用比較</a>\n到bucket裏面選擇 『生命週期』->新增規則\n\n動作看要選擇哪一種\n\n選擇條件\n\n要注意的地方是,設定完不是馬上生效,\n\n對儲存桶生命週期組態的更改可能需要長達 24 小時才能生效,在此期間,對象生命週期管理可能仍會根據舊組態執行操作。\n\n設定完後,再來就是等待他執行了。\n另外,如果有多個規則的話,\n目前GCP的優先順序為\n\n如果多個規則同時滿足單個對象的條件,則 Cloud Storage 將基於以下考慮,僅執行與其中一個規則關聯的操作:\n\nDelete 操作優先於任何 SetStorageClass 操作。\n將對象切換至靜態儲存價格最低的儲存類別的 SetStorageClass 操作優先。\n\np.s 如果你也跑去chtGPT提問的話,可能也會碰到我這個答案,但目前看起來GCS沒有標記這個東西了。\n\nref. 對象生命週期管理",
"tags": [ "note","☁︎"]
},
{
"title": "gcs cors設定",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/142.gcs cors設定/",
"content": "睡睡念\n架構從本來的 NFS全部轉到GCS上了,\n所以cors也要跟着設定\n正文\n將下面檔案,存成json\n[\n{\n"origin": ["https://tester.abc.com"],\n"method": ["GET","PUT","POST","HEAD","DELETE","PATCH"],\n"responseHeader": ["Content-Type", "DNT","X-CustomHeader","X-LANG,Keep-Alive","User-Agent","X-Requested-With","If-Modified-Since,Cache-Control","X-Api-Key,X-Device-Id","Access-Control-Allow-Origin"],\n"maxAgeSeconds": 3600\n}\n]\n\n執行,收工。\ngsutil cors set example_cors_file.json gs://example_bucket\n\n但要注意,這個不會馬上生效,感覺要等超過10分鐘以上。\n~~補充,origin不能用 * 的萬用符號,之前測了沒有效果 ,\n未來會不會改不清楚。 ~~\n測試時,可以用* ,直接用 origin:*\n查看bucket有沒有設定cors則用\ngsutil cors get gs://example_bucket\nor\ngcloud storage buckets describe gs://example_bucket --format="default(cors_config)"\n\n如果要用gcloud/api,請看下面連結\nref. 設定和查看 CORS 組態\nCors的工作原理\n當瀏覽器向 Cloud Storage 發出簡單請求時,會發生以下過程:\n\n瀏覽器將 Origin 標頭新增到請求中。Origin 標頭包含相應資源(該資源在尋求共享 Cloud Storage 儲存桶的資源)的來源,例如 Origin:https://www.example.appspot.com。\n\nCloud Storage 將請求的 HTTP 方法以及 Origin 標頭的值與目標儲存桶的 CORS 組態中的方法和來源資訊進行比較,以查看是否存在匹配項。如果存在匹配項,Cloud Storage 將在響應中包含 Access-Control-Allow-Origin 標頭。Access-Control-Allow-Origin 標頭包含初始請求的 Origin 標頭的值。\n\n瀏覽器接收響應並檢查 Access-Control-Allow-Origin 值是否與原始請求中指定的網域匹配。如果它們匹配,則請求成功。如果它們不匹配,或者響應中不存在 Access-Control-Allow-Origin 標頭,則請求失敗。",
"tags": [ "note","☁︎"]
},
{
"title": "GKE Pub/Sub通知訊息到DC",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/161. GKE利用pubsub通知訊息到discord/",
"content": "前言\n本來以爲不需要,但GKE有時就會幫你升級master的版本,\n神不知鬼不覺,就算用靜態版本也是。\n雖然是不會影響到線上服務,\n但還是最好知道一下是什麼時候升級的。\n正文\n\nPub/Sub建立一個主題\n\nGKE的叢集設定開啓通知,並選擇剛剛建立的主題\n\n建立Cloud Function\n\n環境選『第二代』,函式名稱自己命名。\n觸發條件,『允許未經驗證的叫用』,再選擇 ADD TRIGER裏面的『Pub/Sub trigger』\n\n選擇剛剛建立的Pub/Sub主題\n\n在連線的地方,可選擇僅允許內部流量即可。\n\n建立程式碼\n\n選擇Go 1.20 ,進入點改成 sendDiscord\n原始碼到pubsub notify複製 function.go的程式。\n\n測試\n\n觸發GKE的升級後,就會發送訊息到Discord上面。\n\n相關資訊\nPub/Sub價格\n在每個日曆月,結算帳號的 Message Delivery Basic SKU 的前 10 GiB 吞吐量免費\nref. Pub/Sub 價格\nPub/Sub架構\n\nref. 什麼是 Pub/Sub?\nThe request was not authenticated.\n\nThe request was not authenticated. Either allow unauthenticated invocations or set the proper Authorization header. Read more at https://cloud.google.com/run/docs/securing/authenticating Additional troubleshooting documentation can be found at: https://cloud.google.com/run/docs/troubleshooting#unauthorized-client\n\n如果沒在 第三步驟,選擇『允許未經驗證的叫用』,事後需改到cloud run修改安全性。\n\n從cloud function的連結到cloud run\n\n到安全性,將驗證改成『允許未經驗證的叫用』。\n如果你仍然想要用需要驗證,\n可能需要研究下,目前只允許內部流量調用。\nMessagePublishedData\npub/sub 事件的組成部分\n{\n"subscription": "projects/test-project/subscriptions/my-subscription",\n"message": {\n"attributes": {\n"attr1":"attr1-value"\n},\n"data": "dGVzdCBtZXNzYWdlIDM=",\n"messageId": "message-id",\n"publishTime":"2021-02-05T04:06:14.109Z",\n"orderingKey": "ordering-key"\n}\n}",
"tags": [ "note","☁️"]
},
{
"title": "使用bash安裝gcloud cli",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/164.gcloud install by bash/",
"content": "前言\n因爲『懶』,所以要來搞個一個sh就能安裝完所有東西。\n但在install gcloud就踩坑了。\n正文\n官方文件,這邊提到正常的安裝方式,\n./google-cloud-sdk/install.sh\n\n但這個是建立在人要在電腦前面輸入Y,於是改成\n./google-cloud-sdk/install.sh --command-completion=true --path-update=true --quiet\n\n這樣才會在.bashrc 增加執行的參數。\n一開始沒有想到是沒有增加 .bashrc的關係,\n只有一直出現找不到gcloud的錯誤,\n最後確認<a class=\"internal-link\" data-note-icon=\"\" href=\"/🐧 Linux/163.Shell的區別及查詢/\">163.Shell的區別及查詢</a>的關係後,\n才釐清是.bashrc沒加,\n於是利用\n./google-cloud-sdk/install.sh --help\n\n查詢有哪些參數可供使用。\n完整shell script\n完整install.sh如下,需使用root執行,不然在安裝gcloud會出錯,\nupdate-cert.sh是另一個shell script,是用gsutil拿來抓gcs的資料用。\ncurl -O https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-443.0.0-linux-x86_64.tar.gz\ntar -xf google-cloud-cli-443.0.0-linux-x86_64.tar.gz\n./google-cloud-sdk/install.sh --command-completion=true --path-update=true --quiet\nsource ~/.bashrc\n\ngcloud auth activate-service-account view-bucket@project.iam.gserviceaccount.com --key-file=view-bucket.json\n\nSCRIPTPATH=$(dirname "$(readlink -f $0)")\nchmod u+x update-cert.sh\n\necho "30 1 * * 1 root /bin/bash ${SCRIPTPATH}/update-cert.sh" >> /etc/crontab\n\nref.\n\ngcloud command not found - while installing Google Cloud SDK\ninstall Google Cloud CLI\n[Shell Script] 執行sh檔案提示Permission denied\n第十五章、例行性工作排程(crontab)",
"tags": [ "note","☁️"]
},
{
"title": "Gcloud AttributeError module importlib has no attribute util",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/17. Gcloud AttributeError module importlib has no attribute util/",
"content": "前言\n<a class=\"internal-link\" data-note-icon=\"\" href=\"/🐧 Linux/16.dustise sleep 測試工具簡介/\">16.dustise sleep 測試工具簡介</a> 上一篇,有講到httpie這個套件,簡單使用,我就直接在mac上裝了。\n然後,gcloud,kubectl就掛了...\n正文\n錯誤碼是這樣,\nAttributeError: module 'importlib' has no attribute 'util'\n\n後來一查,發現是kubectl 跟 python 3.9 的問題AttributeError: module 'importlib' has no attribute 'util' #970\n本來是想直接升級kubectl就好在 macOS 上使用 Homebrew 安裝,\nbrew upgrade kubectl\n\n雖然升級完成了,\n但查詢版本\nkubectl version --client\n出來的版本仍是舊的。\n後來才想到,我的kubectl 好像是跟gcloud 一起裝的,試了一下,連gcloud也是同樣的錯誤。\n那就來升級gcloud吧。但只要輸入 gcloud components update 也是出現同樣的錯誤,那要怎麼升級...\n所以,根據這篇 先在terminal上面輸入,\nexport CLOUDSDK_PYTHON=python2 # 先指定使用其他python版本\ngcloud components update # 更新gcloud\n\n完成。",
"tags": ["970", "note","☁︎"]
},
{
"title": "Debian install",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/181. cloudstorage無法使用cloudflare轉址/",
"content": "前言\n線上的圖片是使用GCP的Load balancer連到Google cloud storage,\n之前測試沒問題,但後來 <a class=\"internal-link\" data-note-icon=\"\" href=\"/⛵️ istio/186. istio的Authorization policy(白名單)/#cloudflare\">186. istio的Authorization policy(白名單)#cloudflare轉發</a> ,\nclient到origin server 都使用ssl連線後,就掛了,\n因為Load balancer當初沒有設定SSL的憑證,導致無法連線。\n正文\n到GCP的憑證管理器,新增憑證。\n一開始是沒有啓用的,必須先啓用\n\n建立新憑證,不支援萬用字元\n\n這邊注意,建立完後,\n可能需要等一陣子(幾小時)才會好,\n建立完後一定要到LB綁定,呈現有使用者的狀態。\n當好的時候,會看到狀態為『有效』。\n此時,再到Load Balancer那邊設定憑證,開啓https的入口即可。\n\n前面步驟,參考 <a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/140. gcs 掛載domain/\">140. gcs 掛載domain</a>",
"tags": [ "note","☁️"]
},
{
"title": "GCE硬碟增加容量大小",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/19. GCE硬碟增加容量大小/",
"content": "前言\n之前有加大過GCE的CPU跟ram,但怎麼加硬碟空間還真的不知道。\n正文\n\n先到GCE,開啟機器。選擇開機磁碟(可在開機的狀態下運作)\n\n按下編輯,修改硬碟大小,儲存。\n\n重新整理畫面,會看到硬碟空間容量變了。但還沒完成,需要到機器裡面重新調整大小。\n\nlsblk 列出可用設備\nlsblk\n\nNAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT\nsda 8:0 0 35G 0 disk\n└─sda1 8:1 0 30G 0 part /\n\nNAME:這是塊設備名。\nMAJ:MIN:本欄顯示主要和次要設備號。\nRM:本欄顯示設備是否可移動設備。注意,在設備sdb和sr0的RM值等於1,這說明他們是可移動設備。\nSIZE:本欄列出設備的容量大小信息。例如35G表明該設備大小為35GB,而1K表明該設備大小為1KB。\nRO:該項表明設備是否為只讀。在本案例中,所有設備的RO值為0,表明他們不是只讀的。\nTYPE:本欄顯示塊設備是否是磁盤或磁盤上的一個分區。在本例中,sda和sdb是磁盤,而sr0是只讀存儲(rom)。\nMOUNTPOINT:本欄指出設備掛載的掛載點。\nref. lsblk命令\n\ngrowpart 將全部多餘的空間給指定的分割區\nextend a partition\tin a partition table to\tfill available space\nubuntu 安裝方式:\napt -y install cloud-guest-growpart\n\n2024/08/15更新\napt -y install cloud-guest-utils\nCentOS 安裝方式:\nyum -y install cloud-utils-growpart\ngrowpart /dev/sda 1\n\n這邊的dev/sda 指的是disk,故sda與 1 中間有空格\nref. growpart\np.s 如果出現 錯誤\nFAILED: sfdisk not found\n\n請使用sudo growpart /dev/sda 1 的方式執行\n或 apt install -y fdisk\n\nresize2fs 調整系統大小 resize2fs /dev/sda1\n\n這邊的dev/sda1 指的是part ,故sda與 1 中間沒有空格\nref. Linux基礎命令---resize2fs\n\ndf 檢查分割區大小df -h\n\nref.\ngcp 增加硬碟容量\n不關機、不拔硬碟擴充VM root 磁碟區 - growpart\n調整磁碟區大小後擴展 Linux 檔案系統\nLinux 擴展ext2/3/4 xfs root分割區不用LVM\nTroubleshooting\n\n如果使用resize2fs 碰到錯誤訊息\n\nresize2fs 1.45.6 (20-Mar-2020)\nresize2fs: Bad magic number in super-block while trying to open /dev/sda2\nCouldn't find valid filesystem superblock.\n\n表示你使用的可能是xfs系統,來查一下\n\n\tmount \t\n\n所以必須改用下面指令\nxfs_growfs /dev/sda2\n\nref. # xfs檔案系統擴容報resize2fs: Bad magic number in super-block while trying to open /dev/centos/root Couldn’t find valid filesystem superblock",
"tags": [ "note","☁︎"]
},
{
"title": "GCE機器列表內的CPU個數",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/46.GCE機器列表內的CPU個數/",
"content": "前言\n要算一下各服務所佔的比例,\n大方向用VM的機器 cpu來算\n正文\n如果用gcloud compute list 能夠列出機器的類型,但裡面的cpu數量還是不知道。\n找了一下發現有人寫好一個shell script,拿來改一下能夠直接列出cpu數量\n跟連結的內容相比,我這邊多加了一個狀態。\n因為有些機器是不開機的,當有任務時,才會開機,故大部分時間都是關機狀態。\n# Get instance name,zone for `${PROJECT}\nfor PAIR in $(\\\ngcloud compute instances list \\\n--project=${PROJECT} \\\n--format="csv[no-heading](name,zone.scope(zones),status)")\ndo\n# Parse result from above into instance and zone vars\nIFS=, read INSTANCE ZONE STATUS <<< ${PAIR}\n# Get the machine type value only\nMACHINE_TYPE=$(\\\ngcloud compute instances describe ${INSTANCE} \\\n--project=${PROJECT} \\\n--zone=${ZONE} \\\n--format="value(machineType.scope(machineTypes))")\n# If it's custom-${vCPUs}-${RAM} we've sufficient info\nif [[ ${MACHINE_TYPE} == custom* ]]\nthen\nIFS=- read CUSTOM CPU MEM <<< ${MACHINE_TYPE}\nprintf "%s: vCPUs: %s; Mem: %s; Status: %s\\n" ${INSTANCE} ${CPU} ${MEM} ${STATUS}\nelse\n# Otherwise, we need to call `machine-types describe`\nCPU_MEMORY=$(\\\ngcloud compute machine-types describe ${MACHINE_TYPE} \\\n--project=${PROJECT} \\\n--zone=${ZONE} \\\n--format="csv[no-heading](guestCpus,memoryMb)")\nIFS=, read CPU MEM <<< ${CPU_MEMORY}\nprintf "%s: vCPUs: %s; Mem: %s; Status: %s\\n" ${INSTANCE} ${CPU} ${MEM} ${STATUS}\nfi\ndone\n\nref. gcloud command to display vCPU's and Memory assigned to Instances",
"tags": [ "note","☁︎"]
},
{
"title": "列出GCE的所有VM",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/46.列出GCE的所有VM/",
"content": "前言\n正文\n如果要查特定的欄位,可以先列出instances 的結構,\n看一下要什麼樣的資料。\ngcloud compute instances describe gke-xxxxxx-test-n2-8-819a6098-3b3r --zone=asia-east1-b\n\n然後就能湊出下面的語法了\ngcloud compute instances list --format="table(\nname,\nzone.basename(),\nnetworkInterfaces[].ipv6AccessConfigs[0].externalIpv6.notnull().list():label=EXTERNAL_IPV6,\nnetworkInterfaces[].subnetwork)" | sort -k 5 | grep -E 'gateway.*test'\n\n最前面的語法,是要取出子網路的名稱,以便計算該子網路內有幾台VM,\n然後排序、比對 名稱裡面有 gateway而且後面是 test的VM。\nref.\ngrep 指令使用 or 及 and 查兩個條件以上\ngcloud compute instances describe\ngcloud compute instances list",
"tags": [ "note","☁︎"]
},
{
"title": "Google Cloud Function限制",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/5. Google Cloud Function限制/",
"content": "前言\n這次要生一個ffmpeg的環境出來,然後找阿找阿,\n找到一篇文章,上面寫\nGoogle將Cloud Functions作業系統升級到了Ubuntu 18.04 LTS,擴大了可用函式庫的範圍,除了Imagemagick一直都有外,還多了Ffmpeg和Libcairo2系統函式庫,連無頭Chrome也有,使用者不只可以在Cloud Functions中處理影片,甚至還能進行網頁截圖。\n\nref Google事件驅動無伺服器平臺Cloud Functions正式上線了!\n然後不用架機器,就來看看這條路行不行的通吧\n正文\n找了一陣子,先注意到的是GCF的限制\n\ntimeout 預設1分鐘,最長9分鐘\n單一function可用memory為2G,超過會中斷\n這兩個是我認為比較重要的部分,其他細項,\n可參考\n配額和限制\n淺談Serverless Solution — 以GCP Cloud Function為例\n\n結論,拿來做影片轉檔的話...應該是沒辦法了。除非這影片夠小。\n不然只寫api看來是挺快的",
"tags": [ "note","☁︎"]
},
{
"title": "gcloud compute instance 筆記",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/79. gcloud compute instance 筆記/",
"content": "前言\n因為公司政策,\n要把label全部統一,之前有些已經命名過一次的但名稱不對,\n一個一個改又好麻煩,\n來寫command吧\n正文\n指令演化順序\nStep 1.\n先用指令撈出 GCE的全部列表\ngcloud compute instances --project=project list --format='table(name,status,labels.list())'\n\nStep 2.\n找出label只有特定字元的列表\ngcloud compute instances --project=project list --format='table(name,status,labels.list())' | grep product=abc\n\n問題來了,如果我只要取name出來,作爲變數的話,\n要怎麼做?\n我也一下子想不出來,就先跑去看一下gcloud文件了。\nStep 3.\ngcloud compute instances --project=project list --filter="labels.product:abc" --format="table(name)"\n\n改用 filter去篩選,這樣就能只顯示名稱了。\n\nStep 4.\n加上for迴圈,將label.product改成 zzz\nfor name in $(gcloud compute instances --project=project list --filter="labels.product:abc" --format="table(name)"); do\ngcloud compute instances update "$name" --update-labels product=zzz\ndone\n\n附註:\n刪除label的指令\nproduct 為 key值\ngcloud compute instances update beta-api01 --remove-labels product\n\nref.\n\n使用標籤整理資\ngcloud command",
"tags": [ "note","☁︎"]
},
{
"title": "GCS使用方式",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/8.GCS使用方式/",
"content": "前言\n某個案子,要整個翻掉重做,這次要讓VM的機器跟GKE的pod能夠同時存取一個儲存空間,\n預計使用Google Cloud Storage,踩了一個早上的坑。\n正文\n預計做兩個項目\n\n在VM上面掛載gcs的資料夾\n\n在GKE 上面的pod同時掛載 gcs的資料夾\n\n在VM上面掛載gcs的資料夾\n安裝方式,目前我的vm是 RedHat 所以用下面的方式,CentOS也是用同樣的方式\n\nConfigure the gcsfuse repo:\n\nsudo tee /etc/yum.repos.d/gcsfuse.repo > /dev/null <<EOF\n[gcsfuse]\nname=gcsfuse (packages.cloud.google.com)\nbaseurl=https://packages.cloud.google.com/yum/repos/gcsfuse-el7-x86_64\nenabled=1\ngpgcheck=1\nrepo_gpgcheck=1\ngpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg\nhttps://packages.cloud.google.com/yum/doc/rpm-package-key.gpg\nEOF\n\nInstall gcsfuse:\n\nsudo yum install gcsfuse\n\n完成,其他安裝方式,請參考GoogleCloudPlatform/gcsfuse/install.md\n登入使用,\n這邊先使用 gcloud auth login 做測試\n先建立資料夾 mkdir upload\n掛載 gcsfuse my-bucket upload\n卸除掛載 fusermount -u upload\nDebug用\ngcsfuse --foreground --debug_gcs --debug_http --debug_fuse --debug_invariants --key-file=/home/user/Downloads/my-key.json mybucket /upload\n\n永久加入GOOGLE_APPLICATION_CREDENTIALS變數\n開啟 /etc/profiles\n新增 export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/my-key.json"\n修改檔案後要想馬上生效還要執行#\nsource /etc/profile不然只能在下次重進此使用者時生效。\n\nref.Linux系統環境變數和別名設定(永久生效和臨時生效)\n附註,json檔案的取得在 IAM角色內的服務賬戶\nref.創建和管理服務帳號密鑰。\n新增完GCS,記得把權限給服務賬戶。記得選擇完整權限(Fig. 1)\n自動掛載\n有權限了已後,再來就是自動掛載了。\n到/etc/fstab上,輸入\nmy_bucket /home/ezio/upload gcsfuse key_file=key/key.json,rw,user,allow_other,uid=1008,gid=1009 0 0\n\n重開機測試看看,收工。\nref.\nHow to use mount command in fstab file\ngcsfuse automount on a non root user\n查詢目前登入使用者的uid 跟 gid\nid $(whoami)\n\n如果要看全部使用者的話,\ncat /etc/passwd\n\nref.Linux 的帳號與群組\n\n在GKE 上面的pod同時掛載 gcs的資料夾\n基本的方式,\n先自己產生一個 image\n\nFROM golang:1.14-alpine AS build-env\nENV GO111MODULE on\n\n# WORKDIR /工作名錄名稱 當前的工作目錄名稱,若是不存在則會新建該目錄,\n# 需要注意的是copy跟run的指令都是以WORKDIR為當前目錄下去跑的,\n# 運用的時候需要注意相對位置。\nWORKDIR $GOPATH/src\n\nRUN go get -u github.com/googlecloudplatform/gcsfuse\n\nCOPY key.json .\n\nFROM alpine:3.6\nRUN apk add --no-cache ca-certificates fuse && rm -rf /tmp/*\nCOPY --from=build-env /go/bin/gcsfuse /usr/local/bin\nCOPY --from=build-env /go/src/key.json /\nWORKDIR /\n\n佈署 Deployment\napiVersion: apps/v1\nkind: Deployment\nmetadata:\nlabels:\napp: gcs-fuse\nversion: v1\nnamespace: debug\nname: gcsfuse-test\nspec:\nreplicas: 1\nselector:\nmatchLabels:\napp: gcs-fuse\nversion: v1\ntemplate:\nmetadata:\nlabels:\napp: gcs-fuse\nversion: v1\nspec:\ncontainers:\n- name: gcsfuse-test\nimage: gcr.io/your-project/gcsfuse:v1.2\n# image: golang:1.14-alpine\n# command: [ "/bin/sh", "-c", "--" ]\n# args: [ "while true; do sleep 600; done;" ]\nsecurityContext:\nprivileged: true\ncommand:\n- "/bin/sh"\n- "-c"\n- "while true; do mkdir /upload ; gcsfuse --key-file=key.json your-bucket /folder; sleep 600; done; "\n\n如果跟現有的程式整合的話,\n由於要執行多行指令,需使用shellScript的方式執行指令。\n可能會遇到下列情況\n"exec: "/init.sh": permission denied\n在Dockerfile上修改權限\nRUN chmod +x /init.sh\n\nref.\ngetting permission denied in docker run\nexec user process caused "exec format error"\n有人說在sh的頂端加上\n#!/bin/bash\n但我試了沒用,在猜想可能是alpine linux沒有bash導致\n所以改用下面這個\nENTRYPOINT ["sh","/run.sh"]\n\nref. standard_init_linux.go:178: exec user process caused “exec format error”\n執行sh時卡住,debug方式\n用if else檢查\nif mkdir /upload; then\necho "mkdir directory! Success" 1>&2\ngcsfuse --key-file=key.json yellow-video /upload\nelse\necho "Could not mkdir directory!" 1>&2\nexit 1\nfi\n\n另外,最後找出來原因是因為先執行go的程式,導致後續卡住,所以先建立資料夾後,再執行go\nref.\nShell Script 遇到錯誤時自動退出離開\nref.\n身份驗證入門\nLinux系統環境變數和別名設定(永久生效和臨時生效)",
"tags": [ "note","☁︎"]
},
{
"title": "批次修改GCP的label",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/88.批次修改GCP的label/",
"content": "前言\n發現有一整批的資源沒有加過 label ,\nGCE的硬碟、負載平衡的前端轉導規則..\n有些條件不一樣,一個一個加會瘋掉。\n工程師就是懶...寫sh吧\n正文\n開始構思\n\n先把關鍵值拉出來 (1)\n\ngcloud compute forwarding-rules list\n\n只有ip,要跑去每個叢集查資料,看這該歸屬哪個label,\n太笨了,不行。\n先看一下forwarding-rules 有哪些資訊(2),再把欄位顯示出來。\ngcloud compute forwarding-rules describe a0589a367cdc1470e839b05803958e2b\n\n裡面的description似乎蠻有用處的,可以幫忙釐清是哪個cluster\n\n用 --format (3),顯示欄位\ngcloud compute forwarding-rules list --format='table(name,IPAddress,description)'\n\n開始寫bash\n\n將name丟進 文字檔,\n然後執行bash,bash的流程,迴圈讀檔案內容(4),執行更新label指令(5)。這邊要注意,如果是ingress或是區域型的要額外加上 --global,\n才能更新。\nwhile read p; do\necho "$p"; gcloud compute forwarding-rules update $p \\\n--update-labels=product=abc,env=prod,dept=rd; echo "done";\ndone <lbfr.txt\n\nref.\n\ngcloud compute forwarding-rules list\ngcloud compute forwarding-rules describe\ngcloud topic formats\nhttp://www.compciv.org/topics/bash/loops/\ngcloud compute forwarding-rules update",
"tags": [ "note","☁︎"]
},
{
"title": "GCP網路對外的方式",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/9.GCP網路對外的方式/",
"content": "前言\n這算是先前一直有問題,但不知道為什麼,也沒去查原因。\n正文\n為了要正確對應,讓其他機器開白名單,不得不弄清楚,到底怎麼一回事。\n之前同事都說是走cloudNat,但我直接連去 vm or pod裡面,\n用curl ifconfig.me 抓到的ip都不是我所知道的ip,\n(ifconfig.me 是一個網址,單純顯示目前連去網站的ip位置)\nCloudNAT 的基本概念,主要是可提供內部機器對外連線\nref. Cloud NAT 概覽\n基本的設定方式,\nref. 使用 Cloud NAT\nGCE沒有問題,基本上沒有外部ip而且又沒設定cloudNAT的話,就是無法連接外網。\n然而有外部ip位置的話,Google Cloud 會自動對來源與該接口的主內部 IP 地址匹配的數據包執行一對一 NAT。\n但GKE就有點問題了,就算沒有設定外部ip,還是能夠對外,\n而且抓到的ip位置,你不知道是從何而來,也不是CloudNAT的IP\n最後從問題排查這邊找到了答案,\n確保您的 Google Kubernetes Engine (GKE) 集群是一個專用集群。非專用集群中的每個節點虛擬機都具有外部 IP 地址,因此每個節點都可以使用 Virtual Private Cloud (VPC) 網絡中下一個躍點為默認互聯網網關而不依賴 Cloud NAT 的路由。\n\n簡單說,如果沒有設定專有集群(私有叢集),本身的node是具有對外的ip,所以還沒到CloudNAT之前,\n就直接從node節點出去了。這部分可以到pod裡面 抓取對外ip,然後去比對,這個pod所在的node的對外ip就知道了。\n建立私人叢集\n2021/04/19 更新\n今天來算一下數學,\n上面有提到,當設成私有叢集或是VM,需要對外連線時,\n需設定cloud nat ip,\n當對外連線數量不足時,會發生許多奇怪的問題,\n例如,佈署 deployment ,會發生image pull error ,pod無法啟動,一直重開...等等。\n[[9-fig.1.jpg]]\n每個 VM 執行個體的最低通訊埠數量 :64\n表示每台VM可以對外的連線數量。\n假設(fig.1)\n對外的ip有兩個,\n一個對外ip可以提供 64512的 port 給裡面的來源子網路與IP使用,\n而我們上面設定 每個 VM 執行個體的最低通訊埠數量 為 64 ,\n故 64512 * 2/64 = 2016 可提供的VM數量\n表示 來源子網路與 IP 範圍 的VPC網路 可以提供給2016 個VM (包含 GCE 跟 GKE的節點) 使用。\nref. Cloud NAT 地址和端口概覽",
"tags": [ "note","☁︎"]
},
{
"title": "cloud build的問題",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/95.cloud build的問題/",
"content": "前言\n正文\n在建置cloud build時遇到問題,\n經查詢後推測問題在於,\ncloud build的google service當他在運作過程,\n需要向私有專案內的gke cluster操作,\ncloud build是使用google的浮動ip,\n在此處應該是被block掉了所以無法完成cloud build建置\n錯誤訊息:Unable to connect to the server: dial tcp 124.111.27.75:443: i/o timeout\n(IP為cluster端點ip)\nref. google錯誤排解\n現階段有三種方式\n\n自架CICD系統\nGKE 直接開放 0.0.0.0/0 > 這有安全疑慮\n使用 private conn > 這複雜度很高且不彈性",
"tags": [ "note","☁︎"]
},
{
"title": "Anthos 初體驗",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/97. Anthos 初體驗/",
"content": "前言\n正文\n\n每個月增加 50 美\ncreate new cluster ,無法更改現有(Anthos)\n只能用workload identity\ncpu至少四個,total 要八個\nAnthos 跟 Anthos Service Mesh 不一樣\nref. Anthos 與 Anthos Service Mesh 界面差異\n\n如果在mac上,參照文件,執行的話會出現一些錯誤。\n\nmac不支援此指令,\n也不要使用cloudShell,會因為VPCSC 而出現錯誤\n最佳解法,使用linux系統\n\ndocker run -it --rm -v "$HOME"/.config:/root/.config -v /Users/ezio_liu/Documents/kill:/data google/cloud-sdk:latest\n\n因為有將 gcp驗證 掛載到image內,所以不用在驗證一次。\n可以使用下面指令,看人員有沒有驗證\ngcloud auth list\n\n最後,使用下面指令安裝\n./asmcli install \\\n--project_id rd7-project \\\n--cluster_name istio-test \\\n--cluster_location asia-east1-b \\\n--fleet_id rd7-project \\\n--output_dir asmcli_output \\\n--managed \\\n--ca mesh_ca\n\n--managed 是使用 代管式anthos",
"tags": [ "note","☁︎"]
},
{
"title": "GCP 硬碟費用比較",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/Price/126. GCP 硬碟費用比較/",
"content": "睡睡念\n正文\nGCE\n\nStandard : $0.04 per GiB\nSSD : $0.17 per GiB\n\nCloudStorage\n\nStandard :適合短期儲存和經常存取的資料\nNearline : 適用於備份項目和一個月存取不到一次的資料\nColdline:最適合用於災難復原,以及儲存「每季存取少於一次」的資料\nArchive :適合以數位方式長期保存一年存取不到一次的資料\n\n下面為每月每GB的空間費用\n| | Standard 儲存空間 | Nearline 儲存空間 | Coldline 儲存空間 | 封存儲存空間 | |\n|-----------------|---------------|---------------|---------------|------------|\n| 台灣 (asia-east1) | $0.020 美元 | $0.010 美元 | $0.005 美元 | $0.0015 美元 |\n如果有網路流量,額外在算\n| 每月用量 | 輸出至世界各地 (亞洲和澳洲除外) | 輸出至亞洲地區 (中國除外,但含香港) | 輸出至中國地區 (香港除外) | 輸出至澳洲地區,從位於澳洲的 Cloud Storage 區域輸出 | 輸入 | | | | |\n|-----------|-------------------|---------------------|----------------|-----------------------------------|----|\n| 0 至 1 TB | $0.12 美元 | $0.12 美元 | $0.23 美元 | $0.19 美元 | 免費 |\n| 1 至 10 TB | $0.11 美元 | $0.11 美元 | $0.22 美元 | $0.18 美元 | 免費 |\n| 10 TB 以上 | $0.08 美元 | $0.08 美元 | $0.20 美元 | $0.15 美元 | 免費 |\nref. 價目表",
"tags": [ "note","☁︎"]
},
{
"title": "GCP 監控費用",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/Price/180. GCP 監控費用/",
"content": "正文\n\n功能\n價格1\n每月免費配額\n\nLogging 儲存*\n$0.50/GiB; 將日誌流式傳輸到日誌儲存桶儲存空間,以便編入索引、查詢和分析的一次性費用;包括日誌儲存桶中長達 30 天的儲存費用。 查詢和分析日誌資料不會產生額外費用。\n每個項目每月的前 50 GiB\n\nLogging 保留†\n對於保留超過 30 天的日誌,每月每 GiB 為 $0.01;根據留存率按月結算。\n在默認保留期限內保留的日誌不會產生保留費用。\n\n日誌記錄入站流量‡\n無需額外費用\n不適用\n\n日誌路由器♦\n無需額外費用\n不適用\n\nLog Analytics♣\n無需額外費用\n不適用\n\nLogging保留\nLogging保留的費用,在默認保留的天數為以下\n\n日誌儲存桶\n默認保留期限\n自訂保留期限\n\n_Required\n400 天\n不可組態\n\n_Default\n30 天\n可組態\n\n使用者定義\n30 天\n可組態\n\n_Required 日誌儲存桶\nCloud Logging 會自動將以下類型的日誌路由到 _Required 儲存桶:\n\n管理員活動稽核日誌\n系統事件稽核日誌\nGoogle Workspace 管理員稽核日誌\n企業版群組稽核日誌\n登錄稽核日誌\nAccess Transparency 日誌。如需瞭解如何啟用 Access Transparency 日誌,請參閱 Access Transparency 日誌文件。\n\n_Default 日誌儲存桶\n除非您停用或以其他方式修改 _Default 接收器,否則未儲存在 _Required 儲存桶中的任何日誌條目都會被 _Default 接收器路由到 _Default 儲存桶。如需瞭解如何修改接收器,請參閱管理接收器。\nCloud Logging 會自動將以下類型的日誌路由到 _Default 儲存桶:\n\n資料訪問稽核日誌\n政策拒絕稽核日誌\n\n除非您為 _Default 儲存桶組態自訂保留,否則 Cloud Logging 會將日誌保留 30 天。\nref.\n\nGoogle Cloud 的維運套件價格\n日誌保留期限\n路由和儲存概覽",
"tags": [ "note","☁️"]
},
{
"title": "GCP CPU用途",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/Price/GCP CPU用途/",
"content": "<a class=\"internal-link\" data-note-icon=\"\" href=\"/☁︎ GCP/Price/GCP CPU用途/#2024-07-09\">#2024/07/09更新</a>\n官方建議\n下表是官方建議的機器型號及用途\nref.通用機器系列\nE2\n\nWeb 服務\n中小型資料庫\n應用提供服務\n後台應用\n微服務\n虛擬桌面\n開發環境\n\nN2、N2D、Tau T2D、N1\n\nWeb 服務\n大中型資料庫\n應用提供服務\n後台應用\n快取\n媒體/流式傳輸\n\nTau T2A\n\n應用服務、Web 服務和遊戲服務\n嵌入式系統開發\nArm 上的 CI/CD 開發\n視訊和圖片編碼、轉碼和處理\n數字廣告交易和投放\n快取伺服器\n計算型藥品研發\nAndroid 開發\n自動駕駛或傳統汽車軟體開發\n\n其他 N2D 跟 Tau T2D都是AMD的CPU,價格比N2的便宜\n以同樣的 4 cpu , 16GB memory 來比較價格的話,\n改天要開到N2的話,可以試試N2D的機器。\n\n類型\nCPU\n記憶體\n價格\n\nn2-standard-4\n4\n16GB\n$0.1942\n\nn2d-standard-4\n4\n16GB\n$0.1690\n\ne2-standard-4\n4\n16GB\n$0.13402\n\n更詳細的價格,參考 虛擬機器實例價格\n2024/07/09更新\n今天來算數學了,\n現在要來比較N2D與C2D的價格差距\n\n類型\nOn-demand price\n1-year\n3-year\nUnit\n\nN2D CPU\n$23.24612\n$14.64453\n$10.4609\nvCPU month\n\nC2D CPU\n$24.98863\n$15.74245\n$11.24492\nvCPU month\n\nC3D CPU\n$26.62383\n$16.77321\n$11.98076\nvCPU month\n\nN2D Memory\n$3.11564\n$1.96297\n$1.40233\nGB month\n\nC2D Memory\n$3.34632\n$2.10824\n$1.50599\nGB month\n\nC3D Memory\n$3.56532\n$2.24621\n$1.60454\nGB month\n\n但要特別注意 N2D,如果自定義CPU與Memory的話,\n價格又不一樣了。\nCPU 會來到 $24.408426 / vCPU month\nMemory 會來到 $3.271422 / GB month\n同樣以4顆CPU來算的話,\n當記憶體到13.82G時,價格將接近標準N2D。",
"tags": ["2024/07/09更新", "note","☁︎"]
},
{
"title": "GCP費用",
"date":"Wed Nov 13 2024 10:23:13 GMT+0000 (Coordinated Universal Time)",
"url":"/☁︎ GCP/Price/GCP費用/",
"content": "前言\n正文\nGCP的費用主要分三塊,\n\n機器規格的開機費用\n簡單說就是,機器開機的話產生的費用,但要注意的GCP他有續用折扣,當你用越多就能夠打折。而且他會主動合併未滿一個月機器,再一起算費用。\nref.\n\n聽說 GCP 費用最低?各種折扣方案完整說明\n持續使用折扣\n\n硬碟的費用\n恩...就開機器時,所需要的硬碟空間大小費用,就算你機器關機一樣照算。\nref. 磁碟和映像價格\n網路的費用\n以伺服器的角度來說,ingress(流量進來)不算錢,egress(流量出去)算錢。\n以使用者的角度來說,上傳不用錢,下載要錢。\nref. GCP 如何計費?就像水電費一樣\n\nRegistry\n\nArtifact Registry\nContainer Registry\n\n0.5GB以下免費,超過0.5GB,每GB 0.1 美元\n根據cloudStorage計價\n\n網路輸出另計\nref. Artifact Registry 定價",
"tags": [ "note","☁︎"]
},