在乾淨環境建立k8s環境

在乾淨環境建立k8s環境 使用k8sadmin架設k8s環境 linux環境設定 在開始安裝之前,需要先把host給設定好,所以會先說明要做哪些動作。 關閉swap功能 關閉swap 1 swapoff -a 編輯 /etc/fstab 1 vim /etc/fstab 把檔案裡面 /swapfile 開頭的這行註解掉 編輯swap的畫面.png 安裝docker 安裝所需的工具 1 sudo apt-get update && sudo apt-get install ca-certificates curl gnupg lsb-release 下載docker並新增官方的GPG key 1 sudo mkdir -m 0755 -p /etc/apt/keyrings && curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg 設定放docker的repository 1 echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 安裝docker engine

Local Path Provisioner

Local Path Provisioner 是一個 Container Storage Interface (CSI),也就是用來提供k8s環境下建立Persistent Volume (PV)的插件 安裝 command 1 kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.24/deploy/local-path-storage.yaml 會建立local-path-storage這個namespace,要查看運行狀態,可以到裡面看log 1 kubectl -n local-path-storage logs pods/local-path-provisioner-7f8667b75c-hjrrb 使用configmap來給予設定 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 kind: ConfigMap apiVersion: v1 metadata: name: local-path-config namespace: local-path-storage data: config.

關於鎖

關於鎖(lock) 畢業後,太久沒有用到相關的東西,概念開始有點混淆了,所以拿出恐龍本讀回來。順便做一篇筆記 一些專有名詞 名稱 說明 cooperation process (協作行程) 會操作到共同資源的不同process critical section 在各種cooperation process 裡面會操作到共同資源的code區塊 鎖想解決的問題 在多核心多執行序問世之前的單核心的時代,是一個核心切換來切換去的做不同事,在時間區間上每個時間點都只有一個process正在被cpu執行,如下圖。 單核心運作示意圖 而在多核心問世以後開始會出現一些問題,如下圖。 多核心的運作示意圖 開始會發生圖上,兩個核心會同時執行不同的process ,這個時候可能會發生互相改到資料的問題。例如process B和D是要在印表機上面印出現在電腦的時間,就有可能會發生一下的輸出: 假設兩個核心在執行processB和D的時間點是15:38和15:40 1 15:153:840 這是因為兩個核心互相搶著輸出到印表機,但是順序亂掉的緣故。為了解決這個問題,鎖的概念被提了出來。 鎖的用途 用來保護注critical section(以上面的例子來看,是Process B和Process D裡面,執行輸出資料到印表機的code block)。強制這兩個critical section,在同一個時間裡面,頂多只能有一個執行,另一個想要執行,得要等到另一個結束後,才能開始動作。 鎖的種類 mutex lock(互斥鎖) 又稱自旋鎖,會讓這個process一直卡在loop裡面,直到能夠存取資料後,才跳出迴圈,開始執行這個critical section。 因為實際上是一直在執行loop的狀態下做等待資源釋放的,所以它不需要使用到context switch,在獲得資源後的切換速度很快。所以常常被使用在共用資源都只會被佔用短短時間的情境下使用。 mutex lock的概念是一個被相同mutex lock保護起來的多個critical section,一個時間裡只能有一個被執行,其他都得要等待它mutex lock釋放後,才能繼續搶,搶到的才能執行。 semaphore lock(號誌鎖) 和mutex lock不同,可以設定資源同一時間下,最多可以有S個process同時執行,當同時執行的critical section數目大於S時,會被停下來,等待到同時執行的critical section小於S時,才能繼續搶進去執行。 如果要用mutex lock的方式執行,會讓很多process一直在執行loop,對於資源的浪費太大了,所以在semaphore lock的時候,會採用將process 暫停,將address存到lock S 的list裡面。等到有process把S給釋放,此時CPU會將S裡面的list,取出一個process出來執行。 我混淆的概念釐清 鎖不是鎖住cpu,而是鎖住其他一樣需要這個鎖的process,讓同一個鎖保護的同一個(或者不同個)critical section ,一次最多只能有1(或者semaphore lock設定的數字)個process存取。 被鎖保護住的critical section,只要裡面有存取某個共用資源的code,就能讓這項資源被鎖給保護,不被濫用。 結論 鎖的概念就是為了要保護有限的資源,不要被無限的取用。例如可以利用鎖來保護對同一個檔案的更改,讓這個檔案一次只能被一個process更新,防止檔案內資料變得亂七八糟的。

資料庫的同步

網路上查到簡單說明transaction的例子,常常都是用轉賬來說明,但其實還有很多東西需要注意 帳戶轉賬,因為race condition的緣故,導致操作欄位的值被改錯。 A有100,B有40。 A轉100元給B,B轉20元給A,由兩個不同的client來處理操作。 順序正確時:A會是減掉80 但是當順序不正確,則數字會錯掉,例如A很早取得現在的餘額(100),但是更新數字0慢了,導致A最終變成0元,因為在B轉完帳後才更新值。 以上的這個問題很明顯的是race condition。所謂的race condition是結果必須依賴與某種特定的順序,但是順序又並不是固定的,因此偶爾會出現錯誤。 解決race condition的方法 為了要解決race condition,必須得要讓操作依照我們期望的順序才操作,才能預防不對的順序導致的錯誤。為了要達到這個目標,資料庫本身有提供兩種方法: atomic update:資料庫提供的一個,對於單一欄位數值做相依於原本值的操作指令。這個操作過程會是atomic的,也就是不會操作到一半值被改掉而導致結果出錯。 1 update products set quantity = quantity -1 where id = 1; 優點:因為只是對於欄位做簡單的數字運算並馬上更新上去,所以對於欄位的佔用時間相較下面的select for update較短,且資料庫會將這類atomic操作做優化,所以效能會比較好。 缺點:只支援對於數值的簡單操作後更新,並不能做太複雜的運算。 select for update:這個操作被限制在transaction開起來的時候才能使用,使用時實際上就是將指定的欄位上一個更新的lock,此時直到commit之前,沒有其他client可以對這個欄位做任何更新。所以就能夠限制欄位更新的順序了。 1 2 3 4 Begin; select quantity into $q from products where id = 1 for update; update products set quantity = $q-1; Commit; 優點:因為有上鎖了,所以幾乎可以用各種邏輯運算來更新欄位的值。 缺點:因為會在欄位上面上鎖,並且持續到commit位置,所以對於效能會有很大的影響。 version scheme :在table上面多新增一個欄位叫做version,來確定現在更新時的version,是否從拿值的時候到現在還沒有被更新過。程式可以藉由資料庫回傳的訊息,是否有更改到任何row來判斷是否更新成功。 1 2 old_ver = `select money, version from bank where name = A` `update bank set money = 30, version = version + 1 where name = A and version = old_ver` 優點:能夠不使用任何鎖的時候實現。(或者還有其他我想不到的優點)

我用heptabase來實作卡片盒筆記的方式

卡片盒筆記寫作有兩種方式 卡片盒筆記的做法,現在網路上很多影片、文章都有教了,所以我就不贅述了,這篇文章主要是記錄我如何在heptabase上面實作卡片盒筆記的方式。目前理解到的用法大致上有兩種方式。 闡述延伸自己論點的做法 google搜尋卡片盒筆記最容易找到的是閱讀前哨戰站長瓦基的文章,張永錫老師有一次有和瓦基、朱騏有直播 ,我在這邊大概知道了瓦基使用heptabase的方式 ,大致上就是持續將相同大分類(同board)的卡片做多張卡片凝聚出共通點、複雜卡片切割成多張不需要上下文即可理解的論述、依照因果關係或層級架構為卡片作出連結。最後依照這個的架構輸出成文章。瓦基卡片盒筆記的文章 不同卡片蹦發出新的東西 在張永錫老師在hahow的卡片盒筆記術 中,教導的寫文章方式,則是直接將所有搜尋到有所關聯的卡片複製到whimsical 上面,再來整理排序,變成一張完整的文章。 對我來說 我使用卡片盒筆記的目的是學習知識、整理思路,對於卡片盒筆記術課程 中教導的用whimsical 配合notion放卡片,對於長期的專案來說,持續分裂、內聚的卡片很難同步。我的結論是,這套流程只比較適合一次結束的專案。 所以在理清我需要讓專案持續成長,又要能夠視覺化看到因果和層級架構 這件事後,我馬上就花錢訂閱了heptabase。 我實際的做法 整理卡片(收集、整理材料) white board為一項大項知識的庫,在裡面可以持續新增卡片,並且整理出順序。 持續做以下的流程 為簡單的卡片查詢資料 將資料整理成多項能夠獨立闡述內容的卡片(永久卡片) 看看多張卡片可不可以凝聚出共同性,將其抽出來寫成卡片 看看有沒有卡片寫了太多項內容,將內容封裝成多張卡片 如果卡片之間有因果關係、架構層級,為其加上connection。 在這邊要注意一點是,link和connection感覺很相似,我剛開始很混亂,不知道要怎麼使用。因為同時想要能闡述延伸自己論點的做法 、不同卡片蹦發出新的東西 ,所以會想要讓所有卡片之間的關聯都是用connection來連結。但是這個做法會讓畫面變得很混亂,反而會阻礙思考。後來在釐清了我使用卡片筆記的主要用法是闡述延伸自己論點的做法 後,就決定只讓有因係、層級架構關聯的卡片,使用connection,而其他的關聯則是在卡片內文使用link的方式來關聯。這個是在直播裡面學到的瓦基使用link和connect的時機 寫成文章時 把所有想到和這篇文章相關的卡片用bullet list 來link到entry card 這個方法是從瓦基學到的,文章/keyword card/entry卡片上面先用link把所有相關的卡片給連結進來。再來在這張卡片下面開始書寫文章。 entry card 這個方法的完全是利用了heptabase的功能。 首先heptabase的list可以隨意拖拉,來初步排列出書寫的順序。這個在各大筆記軟體(notion、evernote等)上的bullet list 其實都可以做得到。 Open in new tab → 再點選所有的link,heptabase會在右邊打開所有卡片,這樣可以快速的複製卡片內容過來變成初稿。 這篇文章大致上描述了我現在會在heptabase上面實作的卡片筆記流程,並且這篇文章也是我第一次在heptabase上面使用卡片筆記寫成的。總共花了一個下午和半個晚上研究、半個晚上整理成文章。

Hugo LoveIt 不會顯示toc

問題描述 明明有開啟toc功能,但是在旁邊的toc卻完全沒有顯示任何的標題鏈接。 解法 這個問題的原因很簡單,是因為LoveIt預設會抓h2的標題,但我習慣從h1的標題開始寫,所以在toc上面沒有任何的標題存在。 解決的方法很簡單,只要到設定(config.toml)裡面,加上 1 2 3 [markup] [markup.tableOfContents] startLevel = 1 即可讓LoveIt從h1就開始抓到toc上面。 reference LoveIt Github Issue 410

Hugo Bundle問題

描述 原本在hugo上面放文章是把所有的文章和圖片都放在content/posts/裡面用文章來分類。 1 2 3 4 5 6 7 8 9 10 content/posts/ ├── post1 │ └── post1.md │ └── img1.jpg ├── post2 │ └── post2.md │ └── img2.jpg ├── post3 │ └── post3.md │ └── img3.jpg 因為覺得全部文章和圖片都放在一起是在是太過於雜亂,而且害怕未來文章多的時候,markdown和圖片的命名會很痛苦,雖然也是可以利用在前面加上日期前綴來區分,但感覺還是會很亂。所以開始研究page bundle怎麼處理,試著將結構改成這樣。 1 2 3 4 5 6 7 8 9 10 11 12 content/posts/ ├── 2022-08-02 │ └── post1 │ └── post1.md │ └── img1.jpg │ └── post2 │ └── post2.md │ └── img2.

Goland Markdown split editor消失的問題

最近開始使用Goland來用hugo寫部落格文章,之前markdown的preview分頁都還很正常,但到了今天,突然之間只剩下一般的編輯界面,而且Goland好像還把它識別為html,旁邊會出現在各種瀏覽器上面的按鈕。 偵測成html 而且使用hugo的shortcode還會出現網頁相關的錯誤訊息,在設定裡面查了一陣子才發現到。關於檔案的偵測少了.md的部分,只剩下markdown的部分 settings -> Editor -> File Type 將*.md加上去,一切的紅底線、還有markdown就都全部回來了。

CloudFlare SSL in redirect loop

內文 最近在godaddy上面購買網域,然後使用cloudflare來申請ssl並弄成https的連線。結果今天上來看blog卻發現進不去,錯誤訊息是太多的redirect了。 打開F12重整看看,還真的是持續進行著 重複redirect到首頁的情況 經過一段研究,發現只是這個問題很sssssssss多人有遇到,只是因為CloudFlare的SSL設定設到了Flexible 造成迴圈的ssl設定 正確的設定 參考資料 {< link “https://community.cloudflare.com/t/error-301-on-dns-and-http-proxy/77699" >}}

淺談在Golang上面的物件導向

從物件導向的語言轉到Golang常常會遇到,不知道該怎麼在Golang實作類似多型和繼承的功能。這是因為Golang根本不是物件導向的語言。 在網路上會看到一些文章,寫說可以使用可以embed來模擬繼承,但事實上embed的用途應該只是用來減少重複的程式碼,增加可讀性。像在io package裡面就很明顯,如interface ReadWriter就是用Reader和Writer 兩個interface組合起來的。 1 2 3 4 type ReadWriter interface { Reader Writer } 使用embed struct的方式來模擬繼承。為了要可以被抽換注入,還是得要同時implement一個interface。這樣還不如直接implement interface就好了。 在Golang,唯一類似物件導向的東西只有 interface。只要有implement interface,就可以在宣告使用這個interface的地方使用。 個人的理解,Golang把繼承的概念且分成兩個部分:embed和interface。embed struct (interface) 負責擴增fields (method); interface負責讓不同struct可以有相同的調用方式 embed struct 的功能只是單純消除struct的field的重用而已。embed interface 也是如此,單純想要減少 method 裡面重複宣告 method 的程式碼。 簡單來說,就是 想要可以抽換,用interface; 想要減少重複可以用embed的方式包裝組合