編譯
bin / objcsproj Include版本錯誤案例解析當我們按下「Build」時…
編譯器先把 .cs 程式碼轉成中間結果放在 obj 資料夾,在 obj 裡面會產生有
暫存 DLL
編譯中間檔
自動產生的程式碼(例如 Razor)
當確認所有東西都沒問題後,才會輸出最終結果到 bin 而裡面會有
.dll(主要程式)
.exe(如果是應用程式)
相依套件 DLL(NuGet)
設定檔
也就是說真正執行網站時用的是 bin,而編譯過程中產生一堆暫存在 obj
有時候我們會看到刪掉 bin / obj 的建議來解決版本問題,例如我們若遇到錯誤 ReflectionTypeLoadException,是因為舊的編譯垃圾如果還被拿來用,很可能 bin 裡殘留舊版 DLL、新版 NuGet 已經下載,但舊 DLL 還在、執行時載到錯的版本,而我們刪掉它,就會強制全部重新編譯 + 重新產生正確 DLL
首先,以編譯器本人的角度來說,他不會自己去「找檔案」,它只會編譯「專案明確告訴它要編譯的清單」
當我們啟動 Build,其實是啟動 MSBuild,而 MSBuild ...
Container is environment
指令原本流程開發的問題改用 Docker 自建環境開發volume 掛載(bind mount)summary概念上是把 環境 抽離出你的電腦,讓專案去哪裡跑都長一樣,不再被本機設定搞壞,此時我們可以透過 Docker container 取代「本機安裝 Node.js」,來提供一致的開發環境
本機先裝 Node.js
進專案資料夾
跑 npm install
跑 npm start
雖然在自己的電腦開完了,但自己的電腦要裝 Node 18、同事可能裝 Node 16、CI/CD 用 Node 20
現在改成 Docker 做的事
1234567891011121314151617181920212223242526272829303132333435# 還沒有react#### 建一個測試資料夾mkdir docker-react-testcd docker-react-test#### 用 Docker 建立 React 專案docker container run -it --rm -w=/app -v "${PWD}:/app&quo ...
docker-compose
docker-compose網站Compose 的限制Docker Compose vs Dockerfile手動連通不同 container--linkdocker composesummary把「一堆需要一起啟動的容器」用一份設定檔講清楚,讓環境可以一鍵重現
本質就是把多容器的操作流程「腳本化 + 結構化」
步驟大致上是
先寫一個 docker-compose.yml : 定義有哪些服務(例如 web、db)、每個服務用哪個 image、要開哪些 port、環境變數是什麼
Compose 讀這個檔案 : 解析 services、networks、volumes 確認彼此的依賴關係
建立資源 : 它會自動幫你建立 network(讓容器可以互相用名稱溝通)、建立 volume(資料持久化)
啟動多個 container : 按照設定一次把所有服務跑起來,幫我們處理啟動順序(例如 db 先起)
維持這個「整組環境」
up:全部啟動
down:全部關掉並清理
logs:一起看所有服務的 log
今天有一個網站需要
前端(React)
後端(Node.js)
資料 ...
INCR / DECR
不就是 +1-1 嗎Basic情境summaryINCR = Increment,也就是增加,別看增加只是數學計算的 +1, +2 的事情,他牽扯的是 “流程” 問題,雖然 Redis 是單執行緒,但因為流程上或程式面,我們通常是把每一個看似簡單的事情,都會拆成一個個 UNIT
1231. GET count2. 程式 +13. SET count newValue
這三步是一個流程,但對 Redis 來說是三條分開的命令,只要是分開的命令,中間就可能插進別人的命令,它雖然一次只做一條,但順序可能變成
1234- A: GET count → 5- B: GET count → 5- A: SET count 6- B: SET count 6
結果就出事了,明明有兩次加一,最後卻只變成 6,不是 7,所以問題根本在「每個 UNIT 的順序是什麼」
sequenceDiagram
participant A as A
participant R as Red
is
participant B as B
Note over A, ...
WAF
WAF 動作模式 count blockCDN / WAF 流量管控策略檢查網路的方式檢查 ipWeb ACLproxy 的 WAFcount 跟 block 是兩種不同的 WAF 動作模式
count 模式意思是規則有命中,會記錄、會統計、會看到 log,但不會真的擋掉請求,用途通常是上線前先觀察規則準不準、看看會不會誤傷正常流量、蒐集資料後再決定要不要正式攔,可以把它理解成先裝監視器,不急著鎖門,因為規則只要看錯一點點,block 擋掉的就可能是自己人,所以很多團隊都會先 count,等確認沒誤殺再下手
block 模式意思是規則有命中,請求會被直接拒絕或攔下,流量進不到後面的服務,用途通常是已經確認這類流量就是不該進來,規則驗證過了,要正式啟用防護可以把它理解成監視器看夠了,現在直接鎖門
如果一開始就 block,風險是
合法來源也被擋掉
第三方串接突然失敗
測試人員以為系統掛了,其實是 WAF 擋掉
排查會變麻煩,因為問題不是程式本身,而是入口規則
所以常見流程會是先掛規則、設成 count、觀察命中來源、修正白名單或條件、再切成 block
情境QA 環境只給公司內部 ...
Case 1 - Build a REACT APP Image
事前準備Dockerfile建立 Docker image試跑 & 推送到 Docker Hub使用最簡單的方式建立一個 react template
12npm create vite@latest myweb -- --template reactnpm run dev
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253# build stage### FROM:選擇基底映像(base image),這裡用的是官方的 node:18-alpine### alpine:表示這是基於 Alpine Linux 的輕量版本,檔案體積小(數 MB 級別)### as builder:給這個階段取一個名字叫 builder,後面可以用 COPY --from=builder 來取這個階段的成果### 第一個階段專門負責「編譯(build)」程式碼,因為 Node.js 開發工具比較重(安裝很多套件),不需要帶到最終生產映像裡。多階段建置可以讓最終 i ...
docker-daemon、docker engine、runc、containerd
docker engine
daemonwebserver daemondockerdDocker EngineOCI 規範containerdsummarydaemon 這個詞在電腦世界裡,起源自早期 MIT 的作業系統研究圈,後來被 Unix 沿用,因為系統裡總有一堆沒人想手動一直顧的瑣事,所以工程師乾脆替這些工作取了一個像隱形幫手的名字,工程師會用 daemon 來稱呼背景工作的程式
sshd、httpd 這些名字後面的 d,就是這個文化留下來的痕跡
當我們開了一台多人共用的電腦,總不能每次有人要上網、登入、列印、記 log,才有人衝出來手動開一個程式幫忙,所以系統會先放一些常駐背景的程式在那邊
sshd:有人連 SSH 進來時接手
httpd / nginx:有人送 HTTP request 時接手
cron:時間到了就跑排程
dockerd:有人下 Docker 指令時接手
Nginx 和 Apache 都可以算是 web server daemon,它們是提供 HTTP 服務的背景常駐程式,也就是你常說的 Web Server
當開啟 https://e ...
Go
Why編譯交叉編譯體驗runtime效能優勢靜態連結 vs 動態連結靜態連結 vs 動態連結Docker 生態系的許多核心專案,例如
Docker Enginecontainerdrunc
主體實作也大多以 Go 為主,這是因為 Go 很適合拿來開發這種「系統工具、伺服器程式、基礎設施軟體」
Docker 這類軟體有幾個很重要的需求
能在不同平台運作
容易編譯與發佈
能處理大量並發工作
盡量降低部署與執行時的依賴
方便大型團隊長期維護
Go 在這幾件事情之間取得了平衡,所以非常適合 Docker 這種專案
編譯就是把人寫得懂的程式,整理成電腦能有效執行的結果,順便提早抓出一堆錯
平常寫的程式碼像這樣
1fmt.Println("Hello")
or
1Console.WriteLine("Hello");
這些文字是給人看的,不是 CPU 直接吃的,編譯器會做幾件事
檢查語法有沒有寫錯
檢查型別對不對
把程式整理成可執行的形式
幫你做一些優化
如果不經過編譯,很多錯要等到執行時才爆。先編譯的好處是很多問題在上線前就先攔下來
Go 可 ...
Network
Docker 網路docker0subnetLayer-2 區段network stackveth pairContainer 內查看網路介面在 Host 上查看整體網路結構summary1docker network ls
這個指令會請 Docker 把目前主機上的網路清單列出來
畫面上通常會看到幾個欄位
NETWORK ID:這個網路的識別碼NAME:網路名稱DRIVER:這個網路使用哪種驅動方式SCOPE:這個網路的作用範圍
假設有一個 web 容器和一個 mysql 容器,我們希望它們可以互相連線。這時可能先用 docker network ls,如果看到有一個自己建立的 app-network,那你就知道接下來應該把 web 和 mysql 都放進這個網路裡,這樣它們才可以透過容器名稱互相找到對方。如果你沒有先查清單,可能會發生兩個容器各自在不同網路裡,結果程式一直連不到資料庫,還以為是帳號密碼錯了,其實只是網路根本不通
12345docker network create app-networkdocker run -d --name mysql --network ...
VM vs Docker Container
概念VM 的思考方式Container 的思考方式為什麼這樣設計,結果就會差很多namespacecgroup抽象開一個測試環境跑舊系統快速部署一個 Web API啟動快不代表所有情境都適合用 ContainersummaryVM 是把「整台電腦」重做一份出來。它有自己的硬體模擬層、自己的作業系統、自己的開機流程,就像真的多養了一台機器。
Container 則不同,它直接借用同一個 Host OS 的核心,只把應用程式執行所需的空間隔開來,不需要額外的作業系統。
兩者解決的核心問題其實不一樣:
VM 解的是「我需要一台完整、隔離的電腦」
Container 解的是「我需要一個乾淨、一致的程式執行環境」
你要的是一個能安全執行程式的環境,但不是每次都值得為了跑一個程式,重新養一整套作業系統。理解這個出發點的差異,才能知道什麼時候該用哪個
VM 的核心概念是:模擬出一台完整的電腦,讓上面跑的作業系統完全感知不到自己是虛擬的。
它的啟動流程走的是完整的開機路徑:
Hypervisor 先虛擬出一組硬體資源
分配 vCPU、RAM、虛擬磁碟給這台 VM
VM 內部看到的這些資源,跟真實 ...






