搜尋

搜尋結果

steam deck 辦公用途工具資訊 2024/12更新
科技新知
MacauYeah・2024-12-17

購入steam deck 已經有一年多的時間,之前亦發過一些安裝教學。適逢筆者系統重裝,又有機會重新檢視工具的可用性。 Podman / Distrobox 一項很重要的更新,Steam OS已經有預安裝podman,不需要經home brew安裝。但預裝的podman 沒有內置DNS,可能會對K8S等進階應用有影響,不過筆者只作為單機測試用,普通的podman compose沒有問題。 另一項很重要的更新,就是 distrobox,它可以經 podman 讓大家方便地執行不同的 linux 版本,想在Steam OS上使用Ubuntu?沒問題,開箱即用;想用VScode官方維護版本,沒問題,安裝指定Linux再按裝VScode就好。 詳見上一期的介紹。Steam OS 3.5更新,內建 podman, distrobox 中文輸入法 我們不需要再安裝Fcitx5 + Rime,如果大家在遊戲模式下,已經設定好中文輸入法,那麼在輸到桌面模式下,照樣以Steam Button + X Button的方式,打開內鍵輸入法。你會見到有虛擬鍵盤彈出,它會覆寫桌面模式的。此時,即使你關掉虛擬鍵盤,並用實體鍵盤,中文輸入法都會保留。不過大家要確認,彈出當下必需要是【中文】。 若然你彈出的虛擬鍵盤是英文,請按【地球】轉換到【中文】後,關掉虛擬鍵盤,再重來一次(重按Steam Button + X Button),確保彈出的時候是經【中文】覆寫。 Discovery Discovery 是 Steam OS 預設用來安裝第三方程式的地方,它經 flathub / flatpak 存取程式。但筆者一定要先強調,它提供的第三方程式,並不一定會得到原開發者的支援,它屬於打包移植之類。 例如 flathub 中可以找到 Google Chrome (https://flathub.org/apps/com.google.Chrome) ,但它實際是經過一個github 專案移植過去的 (https://github.com/flathub/com.google.Chrome)。它有提供持續更新,但筆者不保證當中有沒有任何被植入過任何不正當軟件。 相反,flathub中有一些程式是經過原開發者支援的,例如 Firefox (https://support.mozilla.org/en-US/kb/install-firefox-linux), Gnome Boxes (https://gitlab.gnome.org/GNOME/gnome-boxes), Gimp (https://www.gimp.org/downloads/) ,這類可以比較放心使用。 筆者過去使用 Discovery ,的確有遇到一些權限問題,但最後估計應該是筆者安裝 Homebrew 所影響。筆者在重裝 Steam OS 後,直接使用 Discovery,就沒有問題。過去需要經 Homebrew 安裝的東西,現在經 podman , distrobox 或 Gnome boxes 就可以了,不再需要經Homebrew去折騰一輪。而且Homebrew也不是萬能的,因為Steam OS有限制一些套件的事用,即使安裝Homebrew也解決不了。若想要完全開放套件限制或解決依賴問題,還不如直接開啟Steam OS覆寫權限,轉用Arch Linux的安裝包。

概有雲供應商的K8S,為何要自己弄Docker Swarm / 本地K8S ?
科技新知
MacauYeah・2024-11-19

其實筆者寫了這麼多篇docker 的文章,可能有朋友會問,為何要自己從零建立Container環境,使用供應商直接提供的K8S服務不是很好嗎? 按照市場發展,各大雲供應商都越來多,競爭越嚟越激烈,作為用戶方,理應可以得到更合理的價格。不過作為使用VPS多年的筆者,真的沒有覺得雲服務的價格可以便宜到一個不用煩惱的水平,大家還是需要很㥀重地考量自己的業務是不是值得雲端化。 正常來講,在有足夠使用量的前提下,雲端化也是合適的,也真的有產到錢。但問題是大部份情況下公司內部自主開發的應用,都沒有去到這個程度。每個應用去租用一個VPS,即使使用最低配置,用起來的時候覺得不夠快,閒起來的時侯也是浪費錢。 這時,使用 Container 技術,就是讓多個不同的應用,共享同一個或多個VPS的好方法。因為 Container 可以簡易地做到應用之間的隔離,即使不同應用之間有依賴衝突,只要 Contianer 層面沒有衝突就可以共存。 Docker swarm 與 K8S 同為 container 技術,文章最前面,就提到了這個問題,為何不選現有的K8S,反而要自己弄Docker Swarm?其實關鍵亦是價錢的問題。使用K8S固然方便,但就每個節點都得使貴一級的雲端供應商服務,當我們的應用總是流量不足,就更易變得食之無味,棄之可惜。老實講,貴一級的雲端服務,有它存在的價值,很多東西可以做自動化擴展,例如概據流量自動擴容。另外,因為底層 Container 技術有供應商支援,也不用再另外購買支援服務。但這些都是業務有一定流量,才能展現出優勢。 反觀Docker Swarm,就是簡單可入手,初時一個VPS也可以。什至乎不上雲,找幾台舊電腦,實機做也可以。當然K8S也可以實機,不過就簡易程度來講,Docker Swarm 無得輸。待業務真正成長到一個有足夠流量的服務時,才進一步遷移到供應商的原生雲。在初期使用自建的Docker Swarm或小型K8S,可以先加入一些資源統計,以確定是否即裝滿負荷。

Git 歴史修正
科技新知
MacauYeah・2024-10-29

有時候,我們修正一系統檔案,例如某個commit中,多了一個不該放的檔案,又或者想修改該commit的作者,我們就要追搜到某個commit,然後用rebase隨個改。 例如本次repo,有一個githubAction.md,因為錯誤原因,被加到了main中,也藏了很久。如果我們想連根拔起,我們需要加出它第一次出現的commit。 $ git log githubAction.md commit 60ccd70f6b768138cbe23c93ffcfa32574ce895c 那我們就以它前一個commit作為rebase的根據,進行逐個commit修正。 $ git rebase -i 60ccd70f6b768138cbe23c93ffcfa32574ce895c^ pick 60ccd70 draft some content pick e2ee9a3 add some senario. pick b91afc1 refine submodule; pick 98cd366 add notes about submodule specific checkout; pick 064b06f test directly commit in submodule main pick 7b648d2 update git submodules notes pick 556f25e add notes about merge timing pick 5244804 Create git-continuous-integration-strategy.md pick 107e486 add more pratical nodes about ci; pick d93cbee add mono repo challenge pick 1c471b6 add worktree notes pick 9063ccb notes about different of git flow and github flow; pick b72e89e Update github-flow.md, add ref more link pick 0b8f2a9 draft github flow release problem pick 8b333fc finalize github flow release strategy 在rabase選項中,把需要改的commit由pick改為edit。(rebase會以舊到新顯示)。然後儲存。例如 edit 60ccd70 draft some content edit e2ee9a3 add some senario. edit b91afc1 refine submodule; pick 98cd366 add notes about submodule specific checkout; pick 064b06f test directly commit in submodule main pick 7b648d2 update git submodules notes pick 556f25e add notes about merge timing pick 5244804 Create git-continuous-integration-strategy.md pick 107e486 add more pratical nodes about ci; pick d93cbee add mono repo challenge pick 1c471b6 add worktree notes pick 9063ccb notes about different of git flow and github flow; pick b72e89e Update github-flow.md, add ref more link pick 0b8f2a9 draft github flow release problem pick 8b333fc finalize github flow release strategy 我們第一次會在60ccd70,我們作出想要的改動,然後經amend去改掉60ccd70 $ rm githubAction.md $ git add -u $ git commit --amend --author="newuser " 確定無誤的話,就可以去下一步,即是到了e2ee9a3 $ git rebase --continue 因為已經rebase過,你此時看到的不會再是hash不再是e2ee9a3,而是自動rebase完的e2ee9a3。若大家有東西要改,就使用commit --amend。如果沒有東西要改,也沒有conflict,可以繼續rebase --continue下去。

Docker Tag 命名
科技新知
MacauYeah・2024-10-24

一般來講,同一個docker image會提供多個不同的版本,每個版本會附予不同的tag,以作標識。但以docker image的維護者來講,它的tag通常代表的是自己程式的版本號。不過這個版本號卻存在很多變數,就讓筆者好好地逐一說明。 程式的版本號 在沒有Docker的年代,其實所有軟件在發佈時,都會標示版本號,方便使用方明確追蹤問題,自行選擇升級、降級以解決相容性問題。大家要重現問題,也能清清楚地重現。所以docker image的tag,在某程度,都是代表發佈自己的程式版本號。但以前的年代,軟件底層的依賴,例如OS層面的共享程式庫,則不在發佈的管控中,所以過去的程式,在跨電腦安裝時,都會出現缺少某些共享庫的問題。而使用了Docker後,image以內的共享庫的都會在打包的那一刻固定和發佈,就不會有漏的問題。 庫更新,怎麼辦 上面說到image可以打包共享庫,但問題是共享庫也會有安全性更新問題,那麼對docker image的維護者來講,它自己的tag又該如何命名? 因為庫的量可大可少,所以一般來說,都不可能完全把各個庫的版本號寫在自己的tag上。退而求其次,就是用"版本號+日期",庫的細版本號,就存在原始碼當中。Ubuntu 就是這樣的例子。 不過"版本號+日期"的命名方式真的方便嗎?每次下遊用戶想更新去最近版本,都要自己找一次最近的日期。這樣對很多用戶來講都不夠方便。所以docker又提供了一個重tag的功能。例如ubuntu:noble,在早些時候指著noble-20240904.1,然後過幾天,又指向更新的noble-20241009。更常見的是latest,每次image都預設會存在,docker也希望大家會定期更新這個tag,讓大家可以更易地找到最新版本。 註: 這跟git tag有所不同,git tag並不預期會變的。當協作者收到tag後,那怕上遊刻意更新tag指針,協作者沒有刪除原tag之前,都不會知道tag更新去了哪裏。 我們該如何選 在發佈方和引用方來講,引用時可以明確使用唯一的"版本號+日期",對穩定性來講是有意義的。不過多多少少,會產生額外的時間成本。發佈方來說,就是多用了一些儲存空間,方便引用方可以隨時找到舊(庫)版本。而引用方,就要手動修改引用號,作為驗收依據,自動更新的難度比較大。 但對於自動更新要求比較大的情況下,可能就是使用latest或者會隨時更新的share tag(共用tag)比較實際。但我們也依然要定一些方式去版本更新記錄,例如:同時使用 beta latest archive 每日自動更新beta,只有所有測試都通過時,才把archive指向現在的latest,再把latest指向現在的beta。這樣做的好處是,核心的docker stack檔案改變的機會較少,也可以免除docker swarm做太細緻的權限管理。

純文字圖案 | 懶人出圖工具
科技新知
MacauYeah・2024-09-20

早前,筆者就介紹過 Markdown / mdbook 等說明檔編寫工具,也分享過用於制於遊戲攻略時,如何加上插圖的情況。那怕是教學、說明、遊戲攻略,使用圖表的方式表達,的確有助於讀者理解。 在Markdown的技術上,圖文並茂是可以的,只是不太方便而已。以制作及修改的成本來講,出【圖】可能都不算最難,更麻煩的是管理。 怎樣教對?點開圖檔整個閱讀?。怎樣搜尋圖片,可以加附註嗎?更新後名字該怎樣取? 老實講,如果可以,有些【圖】,直接經文字轉譯成圖表就最好。 mermaid Markdown 轉成圖,其實坊間早就有一些免費的工具,筆者選擇了 Github 也預設支援的 mermaid 。廢話不多說,直接送出 web 版的編輯工具。 https://mermaid.live/ mermaid 官網 使用它的好處 Github markdown 直接支援,mdbook經插件也可以使用。 易於編寫,也易於閱讀 有支援IT其他範疇的圖表,例如ER,State。 有支援更多其他範疇的圖表,例如gantt,mindmap。 使用它的問題 不支援手動調整位置,全部靠自動調整 ascii chart 若想要更多的位置掌控,其實我們可以回到過去BBS的年代,用文字方塊來砌圖。這個方法很有局限,但也不是完全不能用。 廢話不多說,直接送出 web 版的編輯工具。 https://asciiflow.com/#/ https://kirilllive.github.io/ASCII_Art_Paint/ascii_paint.html 可以選擇中文字符 使用它的好處 任意手繪圖表 使用它的問題 使用中文等字元,還要考慮是否等寛字型問題。 修改文字長度,邊界要重畫。 筆者有試過用來制作遊戲簡略地圖說明,這是比不斷截圖來要得更直觀。但限制就是不要在圖中加入文字,加入英數等符號就算了,再於其他地方加以解釋。如果我們必需在圖中使文字,我們就要控制輸出字型為等寛字型,例如使用【細明體】,就無問題了。不然就要全部使用中文字元(全型符號),不要混合英數。 .-=. .:*%%+.:. :#%%%%%+#. :#%%%%%%%%%%*. .*%%%%%%%%%%%%%%%*+-.. .-%%%%%%%%%%%%%%%%%%%%%%*:. .-%%%%%%%%%%%%%%%%%%%%%%%%%%-. .=%%%%%%*=-::::::::::::::-=#%%#: :#%%*-:::::::::::::::::::::::-*%+. .*#=-:::::::::::--=========-::::-#+. .=#==-::::-=*%%%%%%%%%%%%%%%%%%=::-#-. .#*==--#%%%%%%%%%%%%%%%#..#%%%%%+::**. :#+==#%%%=.+%%%%%%%%%#-:**::+%%%#-:=--*= .-+#*=+%%#.=%+.+%%%%%%%#--====*%%%#-::::-*. :*====+%%%%#.-%%%%%%%%%%%%-:+%%%%%*::::-*: .*=====#%%%%%%%%%####%%%%%%%%%%%%*::-%+. .:##==#%%%%+-:::::::::::--===-::::##. .##====-::::::::::::=#-:::::::-##. .*%*====---==+**#*+=::::::::+%+. .-#%#+====-:-----::::::-+%%#:. :#%%%%#*+===---+*%%%%%*. ..:=#%%%%%%%%%%%%%+:. ..::---:...

Swarm Mode 上線番外篇:Ceph
科技新知
MacauYeah・2024-08-20

在預設Docker和K8s的容器主導世界裏面,其實一直都缺少了直觀的儲存空間。當你的程序需要讀寫故定的來源資料,該來源就必需是外部的穩定儲存空間,例如是資料庫、NFS。但資料庫、NFS等,要做到真的正穩定,其實就要走Cluster(叢集)模式,確保它們自己本身不是做成single point of failure (單點故障)的元兇。 坊間,只要付得起錢,其實找個穩定的資料庫或NFS,也是有的。但如果你像筆者一樣,只有一塊或多塊【鐵】,就要試試開源的儲存引擎Ceph Storage。 Ceph Storage,有自己特有的CephFS格式,但也支援NFS https://docs.ceph.com/en/quincy/cephadm/install/。也就是,只要我們有足夠多人力,道理上可以自己用實體機去模擬一個穩定的NFS。 因為只是試裝,筆者暫時只用VM來測試,完整的安裝script,可以在這裏找到。script使用Multipass VM,大家有條件的話,可以使用其他VM引擎來看重複。以下是一些官網上沒有提的重點: Ubuntu 24.04 還未能正式使用。在筆者做POC的當是,Ceph v18 在 Ubuntu 24.04上需要先解決,即使大家使用Curl base下載 binary,也未必能成功。 筆者成功測的版本是 Ubuntu 22.04 + Ceph v17,全使用Ubuntu 發佈的內置版本。但大家也要留意自己的Ubuntu apt 有沒有更新到最新版,過去的 cephadm,引用的container image url也變更。記得更新到v17 的最新版,cephadm 指令才能成功取得image。 在官方說明文件的【Deploying a new Ceph cluster】中的【Adding Hosts】https://docs.ceph.com/en/reef/cephadm/install/#adding-hosts 節章可能有些誤導,大家應該要看 【Host Management】中的【Adding Hosts】 https://docs.ceph.com/en/reef/cephadm/host-management/#cephadm-adding-hosts 在每個節點內,可以直觀地連接地Ceph Dashboard,但若大家需要Port Forword,要注意你的Network Interface,筆者就只能經過預設的IPv4的public ip 進行ssh port forward,不能經過0.0.0.0。 Script 位置 https://github.com/macauyeah/ubuntuPackerImage/blob/main/initCephCluster.sh

Docker Image打包建議
科技新知
MacauYeah・2024-07-10

之前筆者有分享過兩個不同的Docker Image打包方式 App直接打包成Image 只把底層程式打包在Image中(例如Tomcat),再用Docker Volume的方式讓Container可以起動App。 筆者就兩種方式做了一個條列式的對比。詳見連結 https://macauyeah.github.io/AProgrammerPrepares/VMDockerNotes/DeployDockerClusterCN.html 因為兩種方式筆者都有實作過,也算用了很段時間,所以也有一些實際經驗可以分享。 如果大家上正式的Docker課程,Docker導師通常會推薦為每個App打包成獨立Image,因為底層程式的Overhead通常不大,例如底層程式是Tomcat、Apache、Nignx這類網頁伺服器,重量級的開銷並不是因為多幾個Web Engine的分身造成,通常都是因為業務本身。但如果你講的底層程式是資料庫等的大型程式,才可能會有明顯的差異。 但實務上的建議,就是必需考慮自身的經驗,到底那個方案自己比較有把握。獨立打包App,在正式環境也需要考慮跟蹤問題的情況,多個不同App要溝通,也是了解Container網絡。如果打包底層程式,所有App都可以當成是本機下運行,更有信心追蹤問題,也是一個很好的出發點,到了有需要彈性改變不同App的需要,才轉向獨立打包的做法。 筆者最初也是走這個打包底層程式的方向,到了自己有信心試用Docker Swarm,才走向獨立打包的做法。筆者親身經驗,因為到了Docker Swarm,網段會變得暴增,這跟公司現有的內部網絡相衝的機會就會變多。在Swarm起立初時,筆者並沒有意識到這件事,所以當初排查問題,也花了一些時間才知道要向網段衝突上著手。 另一個出自Docker導師實務上的建議,就是正式環境中不要做用Docker compose,應該使用Docker Swarm。那怕Swarm只有一個節點,也應該用Swarm,導師的主要理據是Swarm有Rolling Update (滾動更新)的機制。同一個node也可以有多個分身,每個分身輪流更新,就不會出現大中斷的情況。筆者就自身經驗,Tomcat可以同時容納一個App的多個版本,Nginx也有Failover(故障轉移)等,如果你很熟這些功能,不一定要需要靠Swarm去提供。可以按自己步調去慢慢適應。

何謂 Infrastructure as code - IaC
科技新知
MacauYeah・2024-06-07

在雲端服務出現後,好多新的名字,或許大家都聽過,筆者也稍為再簡介一下。 Software as a Service (Saas)。就像我們的Web App,不用下載體件,可以直接經雲進行業務操作。 Platform as a service (Paas)。這個概念可能最含糊,筆者理解就是,雲端供應商提供一些底層的軟件,供IT人使用。像是資料庫,Web Engine。 Infrastructure as a Service (Iaas)。這個更底層,雲端供應商給出CPU, IP, Memory, Storage等,頂多就再多個預安裝OS的選項。IT人自己去配搭使用。 多得這些彈性服務,雲端應用才真的跟過去租用實體伺服器有所差異。 但對於IT人來講,要使用這麼多不同的服務,實在也不簡單。對於IT消費方,用錢換來實體硬件的靈活性,但因為硬件沒有邊界之後,軟件的量就暴增。管理也不能說是很方便。 在Docker, Kubernetes等Container(容器)出現後,又為這些管理問題帶來另一種希望,就是Infrastructure as code - IaC。它的目標是,管理基礎設施,要像管理原始碼一樣,checkout 就可以回覆到指定狀態。 初聽之下,大家可能覺得好玄,但其實這個概念,在之前筆者的Docker 教學中,已經有出現過。Docker compose 、Docker stack 指令,它們都是基於yaml檔的IaC。 當筆者更新了yaml 檔,執行一次stack deploy ,docker 就會對比之前狀態,如果replica(分身)不夠多,就自動增加所欠數量,如果image 也更新了,就排隊輪流重起換image 。最重要的是,當我們checkout 舊的yaml 檔,回到過去某個狀況,只要還是執行同一句stack deploy ,系統就自然減少所需的replica數量,下戴過去的image。這就代表,我們對於container 構建而成的環境,都可以放入Git等版本控制中,整個管理模式,就像管理程式碼一樣(GitOps)。 對於更進階的Kubernetes更是如些,除了container外,多種不同的network,storage配置,都通過yaml檔進行控制。這樣,架構即使複雜,但只少可以測試、重現和管理。還有一個,它比Docker stack要強的是,它某程度上支緩刪除的概念。雖然不完全,但總比完全沒有方便。 這個IoC的概念,可能還未達到一定廣泛地應用的階段,但它的核心在於,基建項目有檢測試差異的功能,自動去因為這個差異去加或減資源。用Programmer的講法,就是系統有Diff的功能,自動多除少補。

測試驅動開發 | 系統邊界Mock
科技新知
MacauYeah・2024-04-23

好一段日子之前,筆者就介紹了一些寫Test Case的大方向 。對於大部份情況來說,有分隔的開發環境,有整個配套,測試起來是順暢的,想做單元測試可以,做整合測試也可以。但如果沒有,我們其實也要想辦法寫Mock。 Mock這個概念,對於寫前端程式的朋友應該比較熟悉,因為前端開發者總不能等後端準備好之後,才開始慢慢設計。前端很早期就要模擬一些情況,做介面設計,做各種思考。而且這個Mock不是指在運行單元測試時,才使用的臨時修改隨機數據。而是針對開發時,自行模擬的後端或外部環境。不過因為前端介面涉及很多主觀設計,很多元素冇辦法做固定的自動測試,所以前端的測試通常要人幫測試。 而後端開發,邊界Mock這一概念也很有用。在外部環境不足的情況下,為自己系統的邊界部份自建一個Stub / Dummy 等的模疑數據,是很有幫助的。不論我們對外部環境的掌控度有多少,我們走測試驅動開發(Test Driven Development),好好地定義這個外部環境的期待行為是很重要的。 例如,你有個功能,需要存入數據,但資料庫未準備好,也沒有所謂的In Memory資料庫可以用。這時,自己架空寫一個什麼都不做或回傳固定結果的函數作為中轉接口,然後在你的Test Case可以規劃你的想要結果。 也許你會說,這個函數就是存下資料,我不會需要它的回傳結果,但我們其實還是可以在Test case 中定義一些錯誤檢測,確保這個函數沒有Throw Exception 。再進一步想,我們主程式是否真的不負任何儲存失敗的責任?要定義其他回傳變數,方便寫Log讓追蹤?或者我們至少要知道成功後的Primary Key ?若然業務上真的不在乎儲存結果的有效性,我們不存入數據也是可以的? 所以歸根究底,我們還是在乎儲存的成功與否。還是有必要去驗證驗寫入是否成功。 上述例子,因為資料庫不存在,開發途中可能Test Case 有好長一段時間也通過不了,但至少當資料庫完備後,可以直接驗證,不用人手手工測試。 舉另外一個例子,我們要從某個地方,例如API或資料庫,讀取數據。我們也可以先寫中轉接口,並為它寫Test Case定義應有的行為。雖然明明就只是讀取,我們沒法控制太多。但在接口做好異常狀態處理,是很重要的。例如Handle exception、檢查某些重要業務值會不會是空、確保後續部份可以正常使用,這是因為我們不能被外部系統的失誤而導致自身系統癱瘓。 其實測試驅動,本質上就是強逼大家想多一點,好好定義預期的行為,不論內部條件怎樣變化,都有一自動的檢收標準。

Git Worktree
科技新知
MacauYeah・2024-04-09

看了Git 大神的影片 part two,才知道原來切換git分支還是有不同的做法。傳統中,我們使用git checkout BRANCH_NAME_1 來切換到我們想要的分支。通常這樣做,代表我們放棄原來的工作環境,換到另一個工作環境中。 這樣做很好,對不對? 是的。但有些時候,我們只是被逼離開原本的工作環境,跳到一個過去的分支/節點去查一些東西,或者修正一些東西。更什的是我們原本的工作環境都還是混亂狀態下,我們不想做commit(提交),我們只好用git stash,暫時將工作環境存起,然後再git checkout BRANCH_NAME_1。在你想做的事做完後,再git checkout OLD_BRANCH。 看起來其實也沒有很麻煩,是不是? 但其實當你的專案有一定大小,你在不同版本跳來跳去,你的IDE就會不斷地重新編譯。更不幸的是,當你的不同版本中有模組數量的差異,弱一點的IDE,什至會攪死它的cache,之後就會發生鬼打牆。為解決IDE引發的問題,筆者有時會直接cp -r YOUR_PROJECT TEMP_PROJECT,在一個新資料夾下另起爐灶。那就是有兩個不同的資料夾裝載著你的專案。 這樣應該沒有問題了吧,是不是?這次是真的可以了,扣除了筆者個人健忘的問題,就沒什麼問題了。 不知大家有沒有經驗,連續commit了幾次,但最後一次commit卻忘了push(與伺服器同步),然後就跳到其他地方繼續工作。如果我們在同一個git repository下,我們commit了但忘了push,即使我們git checkout去了其他分支,用git GUI畫出commit graph時,也至少可以提醒筆者有一個未與伺服器同步的分支。但如果當初我們用的是cp,那就沒戲唱了,什至乎當初複制了去哪裏都忘了。(當你老闆同時要你跟多個專案,健忘真的很容易發生。) 這問題有解嗎?有的,git在2.5版本以後,就提供了一個git worktree的指令。它有點像cp 指令,更重要的是,它打通了兩個資料夾下的隱藏資料庫.git,當大家在那兩個資料夾底下,都可以看到另一方的存在。大家可以用git branch -a或git log --oneline --graph來看看。 詳細的指令介紹:git worktree git 大神的影片 Part 2

龐大的Docker Logs該如何處理? | 傳統的syslog幫到你
科技新知
MacauYeah・2024-02-02

平常大家在做單機app時,寫log有很多選擇,最簡單就是寫在檔案中。但在docker container裏面,寫檔案時要注意怎樣保留log檔,避免因為重建container時不見了。 docker 大部份官方預設image,都把log導向至stdout和stderr。這是方便docker做管理,也方便大家使用統一的docker logs指令來查看,即使到了Swarm mode底下,docker service logs也是同樣原理,使用差異不大,頂多就是不保證log的實時性。 如果網路延遲不計較的話,最大問題也是logs怎樣保存的做法。預設就是container刪走的時候,logs也會一借走。單機模式下,沿用最普遍的方法寫log的做法不是不可行,只是考慮到在極端情況下,同一個node(節點)中,有可能同時運作同一個service(服務)的多個分身(replica),這裏它們寫檔案時就有機會互相搶佔。 筆者認為,比較合理的是外部提供的服務,例如syslog,把寫檔的操作交給節點的Host OS處理。然後就保證好每筆log都會是一條完整的記錄。 以下就以linux Host裏面的syslog,為大家簡介一下設定的步驟。 設定docker 導向 syslog 把該主機的docker daemon (/etc/docker/daemon.json),設定使用syslog driver,並以特定的方式編寫syslog tag。 { "log-driver": "syslog", "log-opts": { "tag": "dockercontainer/{{.ImageName}}/{{.Name}}/{{.ID}}" } } 無腦設定已完成,重啟docker就可以了。 但為了日後管理方便,能把docker log放進獨立的一個檔案中,會更易找問題。所以我們可以進一步設定syslog。我們以Ubuntu 22.04為例,可以在/etc/rsyslog.d/下增加一個設定檔(/etc/rsyslog.d/*.conf),指定看到syslog tag以dockercontainer為首的記錄,都要獨立抽出來。 # file: /etc/rsyslog.d/51-docker.conf :syslogtag,startswith,"dockercontainer" -/var/log/dockercontainer.log 為免有檔案權限問題,手動指定檔案的所有權後,才正式重啟syslog。然後所有相關記錄都會寫在/var/log/dockercontainer.log 滾滾滾滾滾動的log檔 檔案一天一天地長大,如果可以,還是自動清掉太舊的記錄為妙。Linux Syslog,通常也會配著logrotate使用。 筆者亦以Ubuntu 22.04為例子,做了個最簡單的自動滾Log功能。目標就是當log檔案大於1M後,就要重開log檔。舊的log檔最多保留7份,多了就刪掉最舊的。 # file: /etc/logrotate.d/rsyslog-dockercontainer /var/log/dockercontainer.log { rotate 7 size 1M missingok notifempty compress delaycompress sharedscripts postrotate /usr/lib/rsyslog/rsyslog-rotate endscript } 加了設定後,什麼都不用重啟,因為它是Ubuntu 的排程動作,到執行時就會以最新的設定檔執行,詳見/etc/cron.daily/logrotate. 有需要手動測試的話,需要手動呼叫/usr/sbin/logrotate。加入-d參數後,會被視為debug mode,這是官方的說法,但因為debug mode沒有執行效果,更加像是linux中常見的dry run mode。

Steam Deck 也可以作為文字創作
科技新知
MacauYeah・2024-01-23

之前筆者就介紹了,如何使用Steam Deck作為程式開發機使用。這可能對於一般讀者來講不太常用,更常用的是做一些文書處理。筆者最近也拿著Steam Deck,也一步步地補充文書處理所缺少的軟件,正式踏入Steam Deck日常之路。 如果你沒有對系統做過任何更改,在桌面模式中,只要打開「Discover」,輸入後逐的軟件的唯一package name,就可以找到相關軟件。 但如果你像筆者之前一樣,加了homebrew等第三方系統,可能所有軟件都需要在terminal中,經過指令sudo flatpak install PACKAGE_NAME。 Chrome 唯一碼: com.google.Chrome 系統預設瀏覽器只有Firefox,不習慣的話可以另外下載Chrome。有了Chrome,至少所有的雲端文書軟件都可以用,想用Google Doc也沒有問題。 中文輸入法:Fcitx5 + Rime 唯一碼:org.fcitx.Fcitx5 唯一碼:org.fcitx.Fcitx5.Addon.Rime Steam Deck原本有自帶的輸入法,但只適用於螢幕虛擬鍵盤使用(即使用Steam key + X,打開虛擬鍵盤),而實體鍵盤就無法轉輸入法了。這時就需要Linux上的Fcitx5和Rime了。安裝很簡單,之後還要設定一下。 首次安裝後,在啟動器(桌面左下角)搜㝷及啟動 fcitx5,然後在右下角就會見到有個新的鍵盤圖示出現。 按鍵盤圖示,滑鼠右鍵,點選configure,把Rime 加入Fcitx裏面,然後Apply → Close 然後按鍵盤圖示,滑鼠左鍵,應該就會切會成中文輸入法了。這時原本的鍵盤圖示會變成中文輸入法的圖示(或者你經Ctrl-Space也可以) 最後對著中文輸入法圖示,再滑鼠右鍵,可以選擇不同的中文輸入法,例如拼音、注意、倉頡等。 有了輸入法,有了瀏覽器,世界已經都是你的了。 下載器 JDownloader 唯一碼:org.jdownloader.JDownloader 它可以用來下載大部份隱藏文件,例如YouTube video / audio 。但需要注要,首次下載JDownloader 後,還要經過軟件內部更新,否則不能使用。(就像很多手遊,下了主程式後還要下更新檔) 其他 如果你不是長期有網絡,還需要真離線版文書處理器,還可以看看LibreOffice,WPS Office。但這些都不能保證跟windows office 百分百轉換,可能還是使用雲版的Microsoft office 365還要實際。

Spring Boot - Maven Cheat sheet
科技新知
MacauYeah・2024-01-12

基礎 刪除所有結果,全部重新編譯 mvn clean compile 跑起用Spring boot寫的main class,運行Spring boot context。 mvn spring-boot:run # or mvn clean compile spring-boot:run 執行測試用例,預設只會測試test資料夾下以某些命名規則的class(例如class名以Tests或Test結尾的class,其他命名規則筆者未有能力一一驗證) mvn test # or mvn clean compile test 多Profile、多組件、多測試 使用-P指定編譯時的選用pom.xml中的project.profiles.profile參數。也可以用此來傳遞到spring profile,使得編譯後的spring war預設選擇特定profile。 mvn clean compile -PmvnProfile # or mvn clean compile spring-boot:run -PmvnProfile 使用-pl限定mvn指令只對某個子組件生效,但有時候子組件之間也有引用關係,所以需要再額外加上-am參數(--also-make) mvn clean compile spring-boot:run -pl SUBMODULE_NAME -am 使用-Dtest=限定只執行某個class的測試用例,或單個測試函數。(可以無視class名的命名規則) mvn test -Dtest=TEST_CLASS_NAME # or mvn test -Dtest=TEST_CLASS_NAME#TES_METHOD_NAME 若屬於多組件情況下,其他子模組找不到同樣名稱的測試,會測試失敗。需要再加上-Dsurefire.failIfNoSpecifiedTests=false mvn test -pl SUBMODULE_NAME -am -Dtest=TEST_CLASS_NAME -Dsurefire.failIfNoSpecifiedTests=false # or mvn test -pl SUBMODULE_NAME -am -Dtest=TEST_CLASS_NAME#TES_METHOD_NAME -Dsurefire.failIfNoSpecifiedTests=false 打包 在本機電腦中,把java變成jar或者war。通常用於自行發佈的環境中。 mvn package 有時特定Profile沒法成功執行測試用例,或者你認為有些測試問題不影響使用,需要跳過package中的test。 mvn package -Dmaven.test.skip=true # won't compile test folder mvn package -DskipTests=true # compile, but won't run 例外情況 強行把一個第三方jar,種到本機電腦中的.m2/repository # copy from https://maven.apache.org/guides/mini/guide-3rd-party-jars-local.html mvn install:install-file -Dfile= -DgroupId= -DartifactId= -Dversio

Git Submodule
科技新知
MacauYeah・2023-09-15

Git Submodule 初次實務上使用submodule來同時管理幾個project的更新。如果有任何理解上的錯誤,請在github中提issue或pull request。 Why Submodule 假設你的團隊中有三個人,A君做A Project,B君做B Project,C君做Main Project。如果可以,A,B各提供已編譯的Binary或Library,給C君直接使用就最好。 但要做到好好管理,A,B都要有自己的發佈系統,即是把Binary上傳到某個分享Repo中,這樣C君就能有條理地通過IDE或Compile工具下載對應的版本。如果是javascript,Repo可能就是npm repo,如果是java,可能就是maven repo。這亦代表A,B君對程式編譯、打包、版本命名等都要很熟悉,不能一輩子都命名為v1.0.0。 如果團隊對這些都不熟悉,C君還有什麼方法呢?其實靠著Submodule的功能,C君也可以硬把A,B的Source code取出,做最後打包。 這跟A、B君自己把source code壓縮然後Email寄給C君是有不同的。因為這樣C君並不清楚A,B的git脈絡:C君需要自己做好A、B的版本記錄。想要只回滾A,B的版本普不容易。但經過git Submodule後,C君可以清楚知道現在正使用的是A、B的那一個commit版本。假如有一天,A、B、C三個都更新了,但發現合起來時就跑不動。C君可以保持A、C的版本不變,單獨提取B的某個版本進行測試。當然,你可以說原本Email也可以這樣管理,但始終你不清楚B的版本記錄,Email的日期並不代表Source Code的進度。(因為有時候,Bug Fix是針對舊版本的做更新,新功能的Email日期反而比Bug Fix要早) 同理,如果大家要連結多個沒有發佈系統的文字資料,也可以利用Submodule。例如筆者正在編輯一本書,當中不同的主題,就是使用Submodule的功能串連起。 Command 馬上看來來Submodule可以怎樣做。 假設你已經知道git 怎樣用,也起了git repo。假設你是C君,進入你的本機repo資料夾內,使用submodule參數。 上面的效果,就是把C君當前repo的狀態,連結到B君submodule當時預設分枝(default branch)的最後一個commit 中。然後C君在自己的repo怎樣更新,它引用到B君的submodule版本都不會變。 直到某一刻,B君說他加了一個穩定的新功能,請C也連帶更新一下。C君也做好自己的準備後,使用submodule參數進行更新。 注意,如果C君有多於一個submodule,上述指令會全部一口氣更新。另外,如果你覺得B君的最新版本不能用,還是可以針對B君取得特定的版本。

排程執行任務 | Linux Schedule Job
科技新知
MacauYeah・2023-09-07

在Linux底下,crontab是一個最簡單建立Schedule Job的方法。大家用crontab -e 就可以進入設定。 # crontab -e */1 * * * * /opt/run.sh 其中每個星號,順序代表的是分、時、日、月、星期。上面的例子就是不論何月何日何時,只要每一分鐘就執行一次/opt/run.sh Singleton Job 問題是,實際情況下,你想執行程式的時間都不一定會少於1分鐘。所以你總是有機會上一個job未跑完,下一個job就開始了。為了保障自已,需要一些參考機制,去決定是否讓job開始跑。 有些情況,可能你會想用job server去做監管,但若只為單線執行的工作,起一個job server還是會增加管理上的複雜性。 最簡單的做法,就是根據不同的程式語言,使用file lock(鎖上)的機制,先上鎖,再做事。但要注意考慮有沒有出現異常情況,令你自己反鎖自己。即是你的process死了,但不懂自己解鎖,這樣以後你也不能再執行了。 在Linux Bash Shell下,就有一個很簡單的做法,就是使用flock指令。用它的最大好處,就是從OS層面下,去鎖上。只要process結束了,不論正常還是不正常結束,都會自動解鎖。 以下例子就是在執行/opt/run.sh前,先要取得/tmp/run.lockfile的鎖。如果沒法取鎖,就自動放棄執行後面的指令。 flock -n /tmp/run.lockfile /opt/run.sh # crontab -e */1 * * * * flock -n /tmp/run.lockfile /opt/run.sh Timeout 引入singleton的概念後,其實會引發另一個問題。因為異常的情況,還有機會是不生不死,process hang。所以我們還需要設定一個最大的執行時間,讓你的process在異常的情況下,被強行清走。 例如,ping指令在linux預設是永遠不會自動停止的,可以模擬process hang的情況。如果我們想定時從外部收走ping process,就可以使用timeout指令。以下指令就是2分鐘後殺指ping process。 # in file /opt/run.sh timeout 2m ping localhost # to check process id, you could use # > ps aux | grep ping # you will see two different id for ping and timeout 配合errorcode使用,你可能還會在想在timeout時送出一個email通知自已。 # in file /opt/run.sh timeout 2m ping localhost exitCode=$? if [[ $exitCode -eq 124 ]]; then echo "timeout" # enter email alert with timeout elif [[ $exitCode -gt 0 ]]; then echo "exit with error" # enter email alert with timeout else echo "exit normal" fi 配合docker使用,你可能需要考慮signal怎樣傳遞。 在筆者測試的環境中,似乎SIGTERM會被擋,也有可能是SIGTERM太強,它只把前景的docker container run收走,但其內的ping process還在docker daemon中行走。所以最後改用SIGINT,讓docker container run可以好好地把SIGINT傳入其內。 # It seems that docker captured the SIGTERM. Send SIGINT instead # in file /opt/run.sh timeout --signal=SIGINT 10s docker container run --rm pingtest -c 20 exitCode=$? if [[ $exitCode -eq 124 ]]; then echo "timeout" # enter email alert with timeout elif [[ $exitCode -gt 0 ]]; then echo "exit with error" # enter email alert with timeout else echo "exit normal" fi Full demo, github repo cronjobWithDocker