[實作筆記] MongoDB 解決方案評估-- Mongo Atlas

前情提要

最近在 VM 部署了 MongoDB, 不知道為什麼同事在 QA 與正式環境採取了兩個不同的作法,
因此產生了一些版本不一致的問題。
為此需要更換 MongoDB 版本,進而有一些討論,  
決策的考量主要有兩個面向,一、維運的成本。二、實際應付的帳務成本。
可行的方案比較如下,

  • VM 部署 MongoDB
    • GCP
    • Azure
    • Other Cloud …
  • Mongo Atlas(Start from GCP Marketing)
    • GCP VM with MongoDB(Pay as You Go)
    • Azure VM with MongoDB
  • Azure CosmosDB

實作隨筆:Mongo Atlas(Start from GCP Marketing)

測試規劃

mongo atlas 連線的測試架構

如圖,為了不影響原有的環境,我打算建一組新的 VPC Network 進行實驗,
並在這個網路中建立一台實體的 VM 機器,待 Mongo Atlas 設定完成後,
進行連線的測試。

測試的方法,由於 MongoDB Atlas 採用一種安全性較高的連線政策,
必需使用以下連線集群的三種方式才可以連到資料庫:
第一種,IP Access List,使用 GUI 建立 Cluster 的當下會自動加入一組你所在網路對外的 IP,
如果不是固定 IP 可能會有問題
第二種,Peering ,要付錢的版本 M10 以上才可用,也是我們這次實作的重點目標
最後一種,Create a Private Endpoint,也是
M10 以上才可用,但是不是我們這次的主要實作項目,所以不過多的展開。

從 GCP Marketing 建立 Mongo Atlas

在 GCP 的 Marketing 搜尋並訂閱 Mongo Atlas 後點擊 MANAGE ON PROVIDER
在 Mongo Atlas 建立 Cluster,也可以建立 Project 與 User 作更細緻的管控。
這時候可以到 Network Access 查看 IP Access List 的清單,應該會有你網路上設定的對外 IP,
這個流程是自動化的,但是我個人認為不是固定 IP 的話可能會有問題,如果有人可以給我一些提點會十分感激。

IP Access List

建立 VM

GCP 建立 VM 是十分簡單的,就不多作說明。
同時記得安裝我們的測試工具 - mongosh

Mongo DB 相關

切換 db

1
use mydb

查詢目前 DB 狀態

1
db.status()

Create User

1
db.createUser({ user: "username", pwd: "password", roles: [{ role: "roleName", db: "databaseName" }] });

Drop User

1
db.dropUser("username");

查詢 User

1
db.getUsers()

User 加入角色

1
db.grantRolesToUser("username", [{ role: "readWriteAnyDatabase", db: "mydb" }])

User 移除角色

1
db.revokeRolesFromUser("usernmae", [{ role: "readWrite", db: "admin" }])

前置作業: GCP VPC 與 Firewall Rules 設定

為了避免影響原有的系統,
建立 GCP 一組新的 VPC Network : vpc-lab,一般來說 GCP 的專案會有自動建立一組 default VPC Network,
default VPC Network 會預設建立以下的防火牆規則

  • default-allow-icmp – 允許來自任何來源對所有網路 IP 進行存取。ICMP 協議主要用於對目標進行 ping 測試。
  • default-allow-internal – 允許在任何埠口上的實例之間建立連接。
  • default-allow-rdp – 允許從任何來源連接到 Windows 伺服器的 RDP 會話。
  • default-allow-ssh – 允許從任何來源連接到 UNIX 伺服器的 SSH 會話。

與此對應,我也建立相同的規則給vpc-lab,如下:

  • vpc-lab-allow-icmp
  • vpc-lab-allow-internal
  • vpc-lab-allow-rdp
  • vpc-lab-allow-ssh

可以用以下的語法測試一下網路是否能連,如果可以連線再進行 mongodb connection 的測試

1
ping {ip address}
1
telnet {ip address} {port}
1
nc -zv {ip address}

測試連線用的語法

如果網路測試沒有問題,再進行 mongodb 的連線,由於目前沒有設定 Peering 連線,
所以在開發機上可以(網路環境需要在 IP Access List 內),而使用 GCP VM 會無法連線,
開發機連線 GCP MongoDB 語法

1
mongosh mongodb://{user:pwd}@{mongodb_ip}:27017/my_db

開發機連線 MongoDB Atlas 語法

1
mongosh mongodb+srv://{user:pwd}@{atlas_cluster_name}.mongodb.net/my_db

Peering 實作

首先需要在 Mongo Atlas 進行設定,
Network Access > Peering > Add Peering Connection
在 Cloud Provider 中選擇 GCP,

Mongo Atlas Setting

設定 Project ID、VPC Name 與 Atlas CIDR,
比較特殊的是 Atlas CIDR 在 GUI 的說明是

An Atlas GCP CIDR block must be a /18 or larger.
You cannot modify the CIDR block if you have an existing cluster.

但我遇到的狀況是,無法修改預設值為 192.168.0.0/16
建立後會產生一組 Peering 的資料,請記住 Atlas GCP Project ID 與 Atlas VPC Name

Mongo Atlas Peering

接下來到 GCP > VPC Network > GCP Network Peering 選擇 Create peering connection
在 Peered VPC network 中選擇 Other Project,並填入上面的 Atlas GCP Project ID 與 Atlas VPC Name

大概等待一下子就會生效了(網路上寫 10 分鐘,實測不到 3 分鐘)

參考

(fin)

[實作筆記] RWD 設計與 100vh 在行動裝置瀏覽器上的誤區

前情提要

參考圖片

RWD 設計與 100vh 在行動裝置瀏覽器上的誤區

我的網頁有作 RWD 的設計,需求大概是這樣,
綠色是在網頁底部懸浮的選單功能,
紅色區塊是一個控制面版,許多的功能、按鈕、連結都設定在上面。

我最一開始的設定方法如下,

1
height: 100vh;

在瀏覽器上使用模擬器顯示正常,但是在手機上就會出現異常
主要是手機上的 Chrome 和 Firefox 瀏覽器通常在頂部有一個 UI(例如導覽列及網址列等)  
而 Safari 更不同網址列在底部,這使得情況變得更加棘手。
不同的瀏覽器擁有不同大小的視窗,手機會計算瀏覽器視窗為(頂部工具列 + 文件 + 底部工具列)= 100vh。
使用 100vh 將整個文件填充到頁面上時可能導致顯示問題,因為內容可能超出視窗範圍或被遮擋。
因此,在移動設備上進行響應式設計時,應該避免使用 100vh 單位。

解決方法

解決的方法有好幾種,

JS 計算

使用 JavaScript 監聽事件,動態計算高度,缺點是效能較差,在主流的框架(EX:React)要小心觸發重新渲染的行為

1
2
3
4
5
6
const documentHeight = () => {
const doc = document.documentElement
doc.style.setProperty('--doc-height', `${window.innerHeight}px`)
}
window.addEventListener(‘resize’, documentHeight)
documentHeight()

CSS 變數

使用 CSS 變數

1
2
3
4
5
6
7
8
9
10
11
:root {
--doc-height: 100%;
}

html,
body {
padding: 0;
margin: 0;
height: 100vh; /* fallback for Js load */
height: var(--doc-height);
}

min-height 與 overflow-y

留言有人提到使用min-heightoverflow-y
但我的情境不適合,而且這個作法會產生捲軸

1
min-height: 100vh;
1
2
height: 100vh;
overflow-y: scroll;

進一步依照不同的使用情境也許我們需要 @supports

1
2
3
4
@supports (-moz-appearance: meterbar) {
/* We're on Mozilla! */
min-height: calc(100vh - 20px);
}

或是 Browser Hacks 的手法

1
2
3
4
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
/* We are on Internet Explorer! */
min-height: calc(100vh - 10px);
}

position:fixed 的作法

下面的方法可以將元素固定在畫面底部

1
2
3
4
position: fixed;
left: 0;
right: 0;
bottom: 0;

這是我最後選擇的方法,原文的討論相當精彩有趣,
但是我需要的其實是置底,而不是捲軸。
順帶一提我的專是基於 vue 與 tailwindcss,所以下面是 vue 與 tailwindcss 的寫法

1
2
3
<div class="fixed bottom-0 top-0">
<!--HERE THE FEATURES-->
</div>

參考

(fin)

[實作筆記] 管理 Linux 主機與 GCP VM 的磁碟

前情提要

在 GCP VM 上建立的 GitLab Runner 空間不足,導致執行失敗。
我們需要確保 GitLab Runner 有足夠的存儲空間來運行 CI 的 Jobs 。
有兩個解決方案可供選擇:
一、是清理磁碟空間
透過清理磁碟空間,可以移除不需要的文件和暫存資料,釋放寶貴的儲存空間。
二、是擴展磁碟空間
而擴展磁碟空間則是增加磁碟的容量,讓 GitLab Runner 可以持續運行而不受空間限制。
根據具體情況,可以選擇其中一種或兩種方案來解決空間不足的問題

第一部分:查詢與清理磁碟空間

要查詢 Linux 主機的磁碟空間,可以使用 df 命令。下面是使用 df 命令查詢磁碟空間的語法:

1
df -h

這將顯示磁碟空間的使用情況,包括每個檔案系統的大小、已使用的空間、可用的空間以及使用百分比。
要查詢特定目錄或資料夾的磁碟使用情況,可以使用 du 命令。以下是使用 du 命令查詢磁碟使用情況的語法:

1
du -h --max-depth=1 /path/to/directory

這將顯示指定目錄或資料夾的磁碟使用情況,並以人類可讀的格式顯示結果。
可以查詢到一些 cache 或是 log 如果沒有必要的話,可以將之刪除。

要清除 Docker 的磁碟空間,可以使用以下語法:

1
docker system prune -f

第二部分:擴展 GCP VM 的磁碟空間

要在 GCP VM 上垂直擴展 boot 磁碟空間,可以按照以下步驟進行操作:

在 GCP 控制台上,找到並選擇要擴展的 VM 實例。

  • 停止 VM:前往 VM instances 找到要停止的 VM,勾選後 STOP
  • 調整:前往 Disks,找到要 VM instances 所用的 Disk,點擊 Edit 後增加磁碟的大小。
  • 啟動 VM 實例。

小結

無論是清理磁碟空間還是擴展磁碟空間,都是為了讓我能確保足夠的空間供 GitLab Runner 使用,
確保順利運行 CI Jobs!

(fin)

[踩雷筆記] Hexo 網站跑版

前情提要

我的部落格是基於 Hexo 建立的靜態網站,
前幾天,我發佈了一篇新文章,但樣式出現了錯亂。
為了了解發生的問題與解決方案,必須先知道我們的架構,
相關的有三個儲存庫:

Gitlab Group

Github Page

這是部落格的主要內容,使用 Github Page 部署。
通常情況下,我們不會直接對它進行修改,因為大部分的更動都是透過串接的 Github Action 自動完成的。
這個儲存庫代表了整個流程的最終成果。

hexo action

這是我們的自動化工具,結合 Github Action 可以實現持續集成與部署(CI/CD)。
雖然平時不太需要特別注意,但它是相當重要的一環。

Source

這是我們撰寫文章的主要地方,也是整個部落格的功能和版面設計的編排處。

問題追蹤記錄

首先檢查了網頁載入的樣式,發現找不到 style.css 檔案,但有 style.styl
為了緊急處理,我先提供一個正確的 style.css

幸好我在本地端能夠生成正確的 style.css 檔案,所以我先緊急上傳了一個版本到 Github Page
重新執行本地端的測試,一切正常。再次進行部署,結果樣式又跑掉了。
於是我再次手動修正了 Github Page 的問題。

追查了一下 Github Action,發現在這個 commit 之後,異常情況開始發生:

1
2
-"hexo-renderer-stylus": "^2.1.0",
+"hexo-renderer-stylus": "^3.0.0",

從這個記錄中可以得知,問題出在 hexo-renderer-stylus 的更新,而且是一個較大的版本變動。
接下來我嘗試在本地端測試,但卻沒有發現問題。
我開始思考是不是我的部署環境(CI/CD)與本機環境的差異,
第一個是 Node 版本太舊了(12.x.x),所以我先更新了本機的 Node 版本到 20.x.x。
所以我修改了 hexo action,使用最新的 Node 20.x 版本的映像檔。
然而,重新執行部落格的持續部署作業仍然失敗,無法產生 style.css

盲點與解決方式

在這裡我卡住了很久,始終找不到原因。
再次梳理持續部署的流程,結果發現我使用的 hexo-action 版本為 v1.0.5。
原來我忽略了一個步驟,需要為 hexo action 添加新的標籤。
此外,在我們的 Source 的流程中(.github/workflows),
也需要修改為新的 action 標籤 uses: marsen/[email protected]

1
2
3
4
5
    # Deploy hexo blog website.
- name: Deploy
id: deploy
- uses: marsen/[email protected]
+ uses: marsen/[email protected]

(fin)

[實作筆記] 基於 Docker 的 CI Docker 映像檔加速構建流程

前情提要

在現代軟體開發的流程中,持續整合(Continuous Integration,簡稱 CI)是一個重要的概念,
它可以幫助開發團隊在頻繁的程式碼變更中保持項目的穩定性和品質。
而 Docker 作為一個輕量級的容器技術,在 CI 中也扮演著重要的角色。
本篇文章將介紹一個基於 Docker 的 CI Docker 映像檔(Dockerfile_project)的實作記錄(手動,未來將調整為自動化)。

實作

首先,這個 CI Docker 映像檔是基於 php:8.x 映像檔建立的,並且預先安裝了 composer 和 ext-mongodb 擴展。
這樣開發團隊在進行 PHP 項目的 CI 時,就可以直接使用這個映像檔,而不需要額外安裝這些依賴。

在開始使用之前,我們需要訪問 GitLab 的 Docker Registry,所以我們首先需要創建一個 Token。
在 GitLab 的項目設置中,可以找到「Settings > Repository > Deploy tokens」,
在這裡我們需要勾選「read_registry」和「write_registry」權限,以便於讀取和寫入映像檔。

接下來,我們需要使用以下指令來登錄到 GitLab 的 Docker Registry:

1
docker login $GITLAB_REGISTRY_URL -u $GITLAB_REGISTRY_USERNAME -p $GITLAB_REGISTRY_TOKEN

登錄成功後,我們就可以開始建立映像檔了。使用以下指令可以建立映像檔:

1
docker build -t registry.gitlab.com/my_group/subgroup/project .

如果你的電腦跟我一樣是 Mac M2 晶片,可以使用以下指令進行建立:

1
docker buildx build --platform linux/amd64 -t registry.gitlab.com/my_group/subgroup/project --load .

最後,我們需要將建立的映像檔推送到 GitLab 的 Docker Registry 中:

1
docker push registry.gitlab.com/my_group/subgroup/project

至此,我們已經完成了 CI Docker 映像檔的建立和推送的過程。
現在開發團隊可以在持續整合的過程中使用這個映像檔,從而確保項目的穩定性和品質。

小結

在本文中,我們介紹了一個基於 Docker 的 CI Docker 映像檔(Dockerfile_project)的實作步驟。
透過這個映像檔的建立和使用,開發團隊在持續整合(CI)過程中取得了顯著的效率提升。

使用這個新的 Docker 映像檔後,我們見證了從原本的 4 分鐘大幅改進至僅需 30 秒的驚人效果。
這意味著開發團隊現在能夠更快速地完成整個 CI 流程,並且在更短的時間內獲得即時的反饋。

這種效率的提升主要歸功於 Docker 的輕量級容器技術,以及映像檔中預先安裝的依賴(如 composer 和 ext-mongodb)。
透過這些優勢,開發團隊可以在相同的硬體資源下更有效地執行構建和測試操作,從而節省了寶貴的時間。

因此,使用這個新的 Docker 映像檔對於任何需要進行持續整合的專案來說都是一個明智的選擇。
它不僅能提升開發團隊的效率,同時也能確保項目的穩定性和品質。

(fin)

[實作筆記] Mac M2 建立 Docker Image

前情提要

在我的 Gitlab-CI 當中有個步驟 — 建立 Php Image — 十分的冗贅,
需要花3分鐘左右安裝 ext-mongo 與 composer,
如果可以找到已經安裝好的 Image 版本就可以省下這3分鐘。
但是找不到,所以我決定自已建一個 Image 吧

遇到的問題

在構建 GitLab CI 流程時,我遇到了一個問題。
我在開發機上建立了 PHP 的 Docker Image,但在 Gitlab-CI Runner 運行 Image 時,
出現了 “standard_init_linux.go:219: exec user process caused: exec format error” 的錯誤。
這個錯誤表示容器內部執行的可執行文件格式不正確或無效。

進一步分析後,我意識到問題可能是由於容器映像與主機操作系統的處理器架構不兼容引起的。
由於我的筆電是基於 Apple M2 晶片的 Mac,它使用的是 ARM 架構,而我的 CI 使用的容器映像可能是針對 x86 架構設計的。

解決方法

Docker for Mac 提供了一個功能稱為「多架構建置(Buildx)」,它允許我們在具有不同處理器架構的環境中建立 Docker Image。
以下是在 Mac 上建立 x86 架構的 Docker Image 的步驟:
確保您已安裝 Docker for Mac,並確保 Docker 客戶端已啟用 Buildx 功能。
可以使用以下命令來檢查是否啟用了 Buildx:

1
docker buildx version

如果 Buildx 功能已啟用,您應該能夠看到有關 Buildx 的相關訊息。

創建一個新的 Buildx builder,指定 x86 架構。使用以下命令:

1
2
docker buildx create --name mybuilder --use
docker buildx inspect --bootstrap

這將創建一個名為 “mybuilder” 的 Buildx builder,並將其設置為當前使用的 builder。

使用新建立的 builder 建立 Docker Image。
在 Dockerfile 所在的目錄中執行以下命令:

1
docker buildx build --platform linux/amd64 -t Image-name:tag .

在這個命令中,–platform linux/amd64 指定要建立的架構為 x86 架構。

為了將結果映像推送到容器倉庫,您可以加上 –push 選項,例如:

1
docker buildx build --platform linux/amd64 -t Image-name:tag --push .

這將在建置完成後將映像推送到指定的容器倉庫。

如果您只是想將映像載入到本地的 Docker 中,您可以使用 –load 選項,例如:

1
docker buildx build --platform linux/amd64 -t Image-name:tag --load .

實際上使用 --load 在本地端建立的 Image 因為架構不同也無法在本地端執行。

小結

使用了 Docker for Mac 的「多架構建置(Buildx)」功能,
讓我在 M2 Mac 上也可以成功建立 x86 架構的 Docker Image。
使用這個 Image 讓我可以省下 89% 的時間(3 分鐘 →20 秒)

(fin)

[實作筆記] Gitlab CI/CD 與 GCP - 機敏資料的處理

前言

請參考前篇 架構,
我們已經可以部署程式了.
更進一步討論一些實務上的狀況,這篇我們來討論如何處理一些特別的環境設定。

功能、組態與祕密

我們的程式有時會有一些設定,依照不同情境我的分類如下:
功能,是指提供給使用者的設定,簡單的有訂閱通知的開關,或是回呼的 callback url 等.
組態,不牽扯商業邏輯,純屬系統的設定,例如:站台第三方交互的網址,Stage 的名稱等.
祕密,相當於組態,但是不可以外留,否則有資安風險,例如:ClientId、Token、Secret 等.

今天討論的會是組態與祕密,然後我想參考一些資料,
一個是分散系統的建議作法 12 Factors - Config

The twelve-factor app stores config in environment variables (often shortened to env vars or env).
Env vars are easy to change between deploys without changing any code; unlike config files,
there is little chance of them being checked into the code repo accidentally; and unlike custom config files,
or other config mechanisms such as Java System Properties, they are a language- and OS-agnostic standard.

另一個是 Php Laravel 的官方作法

Laravel utilizes the DotEnv PHP library. In a fresh Laravel installation,
the root directory of your application will contain a .env.example file that defines many common environment variables.
During the Laravel installation process, this file will automatically be copied to .env.

想法

理想上、長遠上來我想要走到符合 12 Factory 的建議,
實務上考慮到現實情況和時間限制,加上我對 PHP 和 Laravel 不太熟悉:
現有系統的架構又不是分散式,我決定優先處理減少人為部署的工,而選擇以下的解決方案,

  1. 使用 Gitlab CI/CD 變數來保護敏感資料:
    Gitlab 提供了 CI/CD Variables 功能,可以將敏感資料儲存在 Group Variables 變數中
  2. 在 CI 過程中置換這些變數。
    這樣可以避免將敏感資料直接寫入到 .env 檔案中,提高了安全性(至少機敏資料不會在 Teams 或 Slack 中丟來丟去,或是寫入版控)。
    使用讀取 .env.example 檔案的方式,然後根據需要替換其中的參數值。
    這樣一來,我們可以根據不同的環境需求,動態生成 .env 檔案,而不需要手動修改原始 .env 檔案。

這樣的解決方案結合了 Gitlab CI/CD 的變數功能和動態生成 .env 檔案的方式,使得我們能夠更安全和靈活地管理參數。
雖然這不是 Laravel 官方的最佳實踐,但在缺乏 Laravel 經驗的情況下,這是一個可行且有效的解決方案。

重要的是,這個解決方案能夠讓我們在開發過程中保護敏感資料,同時又不需要深入理解 Laravel 的配置機制。
希望這個解決方案能對其他面臨相同問題的開發者有所幫助。
如果你對於 Laravel 的配置機制比較熟悉,當然也可以探索更適合的方法來保護參數。

實作

Gitlab Group
如圖,GitLab Group 是 GitLab 平台上的一個功能,它允許用戶在同一組織或專案的上下文中管理多個項目,方便協作、權限管理和組織層次的控制。

在 GitLab 中,Group 除了提供組織和專案的管理功能外,還可以使用 CI/CD Variables(持續整合/持續部署變數)來保護敏感資料。
CI/CD Variables 是在 GitLab CI/CD 過程中使用的環境變數,可以在項目層級或 Group 層級定義。

通過 Group 層級的 CI/CD Variables,你可以在整個 Group 內的多個專案中共享和管理變數。
這樣可以方便地保護和管理敏感資訊,例如 API 金鑰、密碼、配置設定等。
透過使用 Group 層級的 CI/CD Variables,你可以在所有專案中統一管理這些敏感資料。

而下面是一段 gitlab-ci 的範例,CI 過程中讀取 Gitlab 的 Group Variables 的並生成 .env 檔

1
2
3
4
- sed -e "s|#{APP_KEY}|$APP_KEY|"
-e "s|#{GOOGLE_CLIENT_ID}|$GOOGLE_CLIENT_ID|"
-e "s|#{GOOGLE_CLIENT_SECRET}|$GOOGLE_CLIENT_SECRET|"
.env.qa > .env

然後在 GCP 的 VM 加上 IAM 設定,Gitlab 對每個帳號設定適合的角色,
初步達成自動化與安全限制。

可能的(?)更好的作法

  • 環境變數與分散式系統 ???
  • 使用雲服務的 Secret Management ???
  • 實作 Laravel Best Practice ???

如果你更好的作法請推薦給我

20230607 補充

使用 CI 建置不同環境的 .env 檔是一件痛苦的事,再更好的方法出現前,我只能儘量減少重複,
下面是一個例子,我需要建立 QA 與 Production 的 .env 檔,
而我目前的作法會在 Gitlab 的 CI/CD Variables 建立不同的 Key,
像是 MY_QA_APP_KEYMY_PROD_APP_KEY
而基礎的設定值又來自不同的檔案 .env.qa 與 .env.production apl
這真是一個糟糕的實作,不過為了動態組出不同的 key,
可以參考以下的寫法,注意單雙引號有不同行為

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.config_temp: &config_script
script:
# Create Env
- echo "KEY:$(eval echo '${'${PREFIX}'APP_KEY}')"
- sed -e "s|#{APP_KEY}|$(eval echo '${'${PREFIX}'APP_KEY}')|"
-e "s|#{GOOGLE_CLIENT_ID}|$(eval echo '${'${PREFIX}'GOOGLE_CLIENT_ID}')|"
-e "s|#{GOOGLE_CLIENT_SECRET}|$(eval echo '${'${PREFIX}'GOOGLE_CLIENT_SECRET}')|"
.env.${suffix} > .env
# 中略
config-qa:
stage: build
variables:
PREFIX: "MY_QA_"
suffix: "qa"
needs: [build]
<<: *config_script

config-production:
stage: build
variables:
PREFIX: "MY_PROD_"
suffix: "production"
needs: [build]
<<: *config_script

參考

(fin)

[實作筆記] Gitlab CI/CD 與 GCP - Linux User 與資料夾權限

前言

請參考前篇,我們將建立兩台 VM,
一台作為 CI/CD 用的 Gitlab Runner,另一台作為 Web Server,
本篇將介紹 Gitlab Runner 的相關設定,
架構如下
GCP 與 Gitlab

參考我們的架構圖,

Linux 系統的使用者管理

使用 Linux 作業系統管理使用者帳號如新增、刪除或修改使用者帳號資訊等等。
以下是幾個常用的命令。

useradd

使用者帳號可以讓你進入系統,執行操作和管理文件等。
這是一個基本的命令,通常需要以系統管理員的權限執行。
範例如下:

1
useradd john

這個命令將會新增一個名為 john 的使用者帳號。

userdel

刪除一個使用者帳號,你可以使用 userdel。
刪除使用者帳號會刪除該使用者的所有文件,因此請確保你已經備份了重要的文件。
範例如下:

1
userdel john

這個命令將會刪除名為 john 的使用者帳號。

usermod

修改使用者帳號的資訊,例如姓名或者家目錄,你可以使用 usermod 命令。
範例如下:

1
usermod -c "John Smith" john

這個命令將會修改名為 john 的使用者帳號的姓名為 John Smith。

2023/05/23 補充使用情境

  • 查詢 www 的 group 有包含哪些 user?
  • 用 usermod 將 user gitlab-runner 加入 group www
  • 再次查詢 www 的 group 有包含哪些 user?
1
2
3
4
5
$ grep '^www:' /etc/group
www:x:1008:
$ sudo usermod -aG www gitlab-runner
$ grep '^www:' /etc/group
www:x:1008:gitlab-runner

補充:g+w 和 755 的差別

g+w 和 755 是針對文件或目錄的權限設置。

g+w 表示給與用戶組寫入權限(write permission)。
這意味著屬於該文件或目錄所屬組的成員可以對其進行寫操作,例如創建、修改或刪除文件。
其他用戶和組仍可能具有其他權限,如讀取或執行權限。

755 是八進製表示法,用於設置文件或目錄的權限。具體而言,它代表以下權限:

所有者(Owner)具有讀、寫和執行權限(rwx = 4 + 2 + 1 = 7)。
屬組(Group)具有讀和執行權限(r-x = 4 + 0 + 1 = 5)。
其他人(Others)具有讀和執行權限(r-x = 4 + 0 + 1 = 5)。
因此,g+w 僅給予了用戶組寫入權限,而 755 給予了所有者讀寫執行權限,用戶組和其他人的讀執行權限。

要注意的是,g+w 是一種相對於當前權限的增量設置,而 755 是一種直接指定權限的絕對設置。
具體取決於文件或目錄的初始權限,兩者可能會有不同的效果。

資料夾權限

可以用以下語法列出資料夾內的檔案與資料夾權限

1
ls -al

在 Linux 系統中,檔案的類型和權限使用特殊的符號來表示。
第一個字元表示檔案的類型,例如目錄、檔案或連結檔等等。
d 是目錄,-是檔案,l 是 link file;
b 是可儲存的周邊設備、c 是鍵盤、滑鼠等設備。

接下來的三個字元代表三種權限,分別是讀取(r)、寫入(w)和執行(x)。
每三個一組,分別對應檔案的擁有者、群組帳號和其他帳號。如果沒有權限,則會用減號來表示。
這些權限可以用來控制不同使用者對於檔案的存取權限。

在 macOS 中最後一個字元,有可能是 @+. 或沒有字元
@:代表此檔案有擴展屬性(Extended Attributes)。
+:代表此檔案有 ACL(Access Control List)權限限制。
.:代表此檔案有 SELinux 安全屬性(SELinux Security Attributes)。
沒有字元:代表此檔案沒有以上特性

舉例來說

1
drwx------ 87 mark.lin  rd      2784  4 12 13:21 Library

這是一個名為 Library 的資料夾,擁有者是使用者 mark.lin,群組是 rd。
權限設定為只有擁有者有讀、寫、執行權限,而群組和其他使用者都沒有任何權限。

調整資料夾權限

1
chown -R mark:mark /www/api

chown:用於更改文件或目錄的擁有者和群組的命令。
-R:對目錄及其子目錄進行遞歸操作。
mark:mark:擁有者和群組名之間使用冒號分隔,這裡將 /www/api 目錄及其所有子目錄和文件的擁有者和群組都設置為 mark。
如果您的系統中不存在名為 mark 的使用者和群組,這條命令會失敗

20230707 補充說明

sudo chown -R www:www : 此命令用於更改指定目錄下的所有文件和子目錄的所有者(owner)和所屬群組(group)。chown 是 “change owner” 的縮寫。-R 選項表示要遞歸地更改所有子目錄和文件的所有者和所屬群組。www:www 是欲更改的目標所有者和所屬群組的用戶名和群組名,這裡是 www。

sudo chmod 775 -R : 此命令用於更改指定目錄下的所有文件和子目錄的權限設定。chmod 是 “change mode” 的縮寫。-R 選項表示要遞歸地更改所有子目錄和文件的權限。775 是許可權的數值表示法,其中第一個數字 7 表示所有者的權限設定,第二個數字 7 表示所屬群組的權限設定,最後一個數字 5 表示其他用戶的權限設定。每個數字由三個位元組組成,分別表示讀取(4)、寫入(2)和執行(1)權限。

建立 VM 的 Account

在 GCP 的實作上我們不需要直接建立帳戶與群組,記得架構圖中的 SSH Key 嗎?
當我們在 Compute Engine Metadata 建立 SSH KEYS 時,就會依照這把 KEY 的 Comments 建立一個 Linux VM 帳號
因此我們的 VM 就會有對應的帳號資料

參考

(fin)

[聲明] 關於支語警察

如果它看起來像支語警察、貼文像支語警察、留言像支語警察,那麼它可能就是支語警察。

聲明

  • 理解並尊重
  • 是否修改內容由我判斷
  • 文化交流本來就會相互影響
  • 只在增進理解上作文章的修改

緣由小記事

5566 與注音文的戰爭

記得 21世紀初有一段時間,在 PPT 當時的大學生/高中生分為兩派,
一派是喜歡 5566 寫注音文,較為年輕; 一派是不喜歡 5566 討厭注音文,較為年長,
長時間在網路論戰,PPT 大多是年長者的勝場,常見有禁注音文入版規,甚之 56 開版被閙到關版。

然後他們都老了,之所以說這段往事,是給自已的反省,
我還是不寫注音文,但是沒那麼討厭 56 了,
當時在版上的種種行為,被我認定為世代的集體霸凌,而我認為這種事不該再發生。

文化交流本來就會互相影響

不論是支語、晶晶體、古早的注音文,
我認為都有其歷史脈絡與背景故事,
注音文表示電腦打字的盛行、晶晶體是與國際交流、支語則代表的兩岸交流的頻繁程度。
而台灣科技發達、地理政治位置都處於世界各個文化的交匯地帶,本來就會有各式各樣的文化衝擊。

我理解你討厭中國

因為在國際上的各種打壓、飛彈、擾台,中國真的很雞掰。

我更討厭思想審查、蓋世太保

透過控制對方的言論的輸出、輸入來控制思想,
這很納粹、也很現在的中國。

正體中文的價值

理解各種母語面臨的危機,
但正體中文在中文語系也變少數了,
我覺得這很珍貴,也是台灣文化的一環,
不然看看滿族、內蒙、新彊、西藏被中國共產黨搞成什麼鬼。
不需特眨低正體中文,來強調自已母語多優秀。

專業從業人員應有標準

可以的話中文語系應該用同一套標準來說明相關的專業知識是最好的,
實務上應該有政治問題造成的困難。
不然就說原文吧,科技應該快要能解開巴別塔的詛咒了。

順帶一提,看過支語警察的對照表是互相衝突的,支語警察們請建立自已的標準吧。

AI 潤飾版

如果一個人的語言、貼文和留言都充滿著批評和指責他人使用支語,那麼這個人很可能就是所謂的支語警察。

聲明:本人尊重並理解不同的文化背景和價值觀,修改文章僅在於增進彼此理解,且修改內容應由原作者自行判斷。

文化交流是相互影響的,因此我們不應該排斥使用不同的語言和文字,例如注音文、晶晶體和支語。
這些語言和文字都有其歷史脈絡和背景故事,例如注音文表示電腦打字的盛行,晶晶體則表示了對英文的追崇,
而支語則反映了台灣與中國交流的頻繁程度。台灣處於世界各種文化的交匯地帶,因此各種的文化衝擊是不可避免的。

雖然我理解一些人對中國政府的態度很反感,但我更反對思想審查和控制言論的行為。
這種行為與納粹主義和現代中國的行為很相似。

正體中文是台灣文化的一環,也是中文語系的寶貴資源。
儘管我理解各種台灣本土多數母語面臨的危機,但我認為正體中文應該被尊重和保護。
與此同時,我們也不應該輕視其他語言和文字,以表達我們的優越性。

對於專業從業人員,使用同一套標準來說明相關的專業知識是最好的。
然而,由於政治問題的影響,實踐上可能會存在困難。
不過,我相信科技很快就可以幫助我們克服語言障礙,實現真正的文化交流。

最後,提醒一下支語警察們,他們的對照表往往互相矛盾,因此建立一套公正的標準將是有益的。

我猜有人反對使用 AI 寫的文章

我的建議啦: 不爽不要看

(fin)

[翻譯] 在 X 分鐘學會 YAML

本文

YAML 是一種用於數據序列化的語言,設計初衷是讓人類能夠直接讀寫。
它是 JSON 的一個嚴格超集,具有類似 Python 的有意義的換行和縮排。
不同的是,YAML 不允許使用文字 tab 字符進行縮排,而需要使用空格進行縮排。

範例檔

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
---  # 文件開始

# YAML中的註解看起來像這樣。
# YAML支援單行註解。

################
# 純量類型 #
################

# 我們的 root 物件是一個 map,
# 就像是其它語言的 dictionary, hash 或 object .
key: value
another_key: Another value goes here.
a_number_value: 100
scientific_notation: 1e+12
hex_notation: 0x123 # 0x開頭為 16 進制,所以值為 291
octal_notation: 0123 # 0開頭為 8 進制,所以值為 83

# 1 會被視作數字而非 boolean 值
# 如果要用 boolean 請使用 true

boolean: true
null_value: null
another_null_value: ~
key with spaces: value

# Yes No (不分大小寫) 也視作 boolean
# Yes→true 而 No→false
# 如果要用實際值,請用單引號或雙引號
no: no # 視作 false
yes: No # 視作 false
not_enclosed: yes # 視作 true
enclosed: "yes" # 視作字串 「yes」

# 請注意,字符串不需要引號。但是,它們可以使用引號。
however: 'A string, enclosed in quotes.'
'Keys can be quoted too.': "Useful if you want to put a ':' in your key."
single quotes: 'have ''one'' escape pattern'
double quotes: "have many: \", \0, \t, \u263A, \x0d\x0a == \r\n, and more."
# UTF-8/16/32字符需要編碼
Superscript two: \u00B2

# 特殊字符必須用單引號或雙引號括起來
special_characters: "[ John ] & { Jane } - <Doe>"

# 多行字符串可以使用“文字塊”(使用|)或“折疊塊”(使用'>')來寫入。
# 文字塊會將字符串中的每個換行符轉換為文字換行符(\n)。
# 折疊塊則刪除字符串中的換行符。
literal_block: |
This entire block of text will be the value of the 'literal_block' key,
with line breaks being preserved.

The literal continues until de-dented, and the leading indentation is
stripped.

Any lines that are 'more-indented' keep the rest of their indentation -
these lines will be indented by 4 spaces.
folded_style: >
This entire block of text will be the value of 'folded_style', but this
time, all newlines will be replaced with a single space.

Blank lines, like above, are converted to a newline character.

'More-indented' lines keep their newlines, too -
this text will appear over two lines.

# |- 和 >- 可以刪除結尾的空行(也被稱為文字塊的 "strip")
literal_strip: |-
This entire block of text will be the value of the 'literal_block' key,
with trailing blank line being stripped.
block_strip: >-
This entire block of text will be the value of 'folded_style', but this
time, all newlines will be replaced with a single space and
trailing blank line being stripped.

# |+ 和 >+ 可以保留結尾的空行(也被稱為文字塊的 "keep")
literal_keep: |+
This entire block of text will be the value of the 'literal_block' key,
with trailing blank line being kept.

block_keep: >+
This entire block of text will be the value of 'folded_style', but this
time, all newlines will be replaced with a single space and
trailing blank line being kept.

####################
# 集合類型 #
####################

# 巢狀結構使用縮排. 建議值為 2 個空白 (非必要).
a_nested_map:
key: value
another_key: Another Value
another_nested_map:
hello: hello

# Maps 不一定要用 string 作key.
0.25: a float key

# Keys 也可以很複雜, 比如多行物件
# 我們用 ?| 開頭表示複雜的物件
? |
This is a key
that has multiple lines
: and this is its value

# YAML 也可以用複雜物件作 Key Value 的映射
# 但有解析器可能會不過
# 如下例
? - Manchester United
- Real Madrid
: [ 2001-01-01, 2002-02-02 ]

# 序列(Sequences 或 lists 或 arrays) 看起來像這樣
# (注意 '-' 有縮排):
a_sequence:
- Item 1
- Item 2
- 0.5 # sequences 可以包含不同類型
- Item 4
- key: value
another_key: another_value
- - This is a sequence
- inside another sequence
- - - Nested sequence indicators
- can be collapsed

# 因為 YAML 是 JSON 的超集, 你也可以寫出 JSON-風格的 maps 與 sequences:
json_map: { "key": "value" }
json_seq: [ 3, 2, 1, "takeoff" ]
and quotes are optional: { key: [ 3, 2, 1, takeoff ] }

#######################
# 額外 YAML 功能 #
#######################

# YAML 很方便的功能叫 'anchors', 讓你可以很輕易的複製文件內容
# 使用 & 來定義值
# 使用 * 來呼叫值
# 下面兩個 key 有相同的值
anchored_content: &anchor_name This string will appear as the value of two keys.
other_anchor: *anchor_name

# Anchors 可以用於複製與繼承的屬性
base: &base
name: Everyone has same name

# << 表示式代表 'Merge Key Language-Independent Type'.
# 用於合併已存在 map 成為新的 map 並保留 key value
# 注意: 如果合併時要合併的 key已經存在,則該鍵的別名(alias)不會被合併
# 也就是說,如果要合併的 key 已經存在於數據結構中,則合併操作只會更新該 key 的值
foo:
<<: *base # doesn't merge the anchor
age: 10
name: John
bar:
<<: *base # base anchor will be merged
age: 20

# foo 與 bar 將會有相同的名字

# YAML 也有 tags, 請參考以下 Syntax
# Syntax: !![typeName] [value]
explicit_boolean: !!bool true
explicit_integer: !!int 42
explicit_float: !!float -42.24
explicit_string: !!str 0.5
explicit_datetime: !!timestamp 2022-11-17 12:34:56.78 +9
explicit_null: !!null null

# 其中有一些解析器(parser)會實作語言特定的 tag,像是 Python 的複數類型(complex number)
# 可以使用 !!python/complex 這個 tag 來表示複數。
# 在這個範例中,python_complex_number 變數的值被指定為一個 Python 複數類型的物件,其實際值為 1+2j。
python_complex_number: !!python/complex 1+2j

# 我們可以使用 yaml 的 keys 轉換為語言的特定資料類型
? !!python/tuple [ 5, 7 ]
: Fifty Seven
# 以上將被 Python 解析為 {(5, 7): 'Fifty Seven'}

####################
# 額外的 YAML 類型 #
####################

# 除了基本型別外(string number)
# Yaml 也支援 ISO-formatted 的日期與時間
datetime_canonical: 2001-12-15T02:59:43.1Z
datetime_space_separated_with_time_zone: 2001-12-14 21:59:43.10 -5
date_implicit: 2002-12-14
date_explicit: !!timestamp 2002-12-14

# 你可以用 !!binary 這個 tag 表示其後的值是 base64-encoded 的二進位編碼
gif_file: !!binary |
R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5
OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+
+f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC
AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=

# YAML 也有集合(set)類型
set:
? item1
? item2
? item3
or: { item1, item2, item3 }

# Sets 將 maps 向 null 值; 上面的 yaml 範例將與下面相等
set2:
item1: null
item2: null
item3: null

... # document end

參考

(fin)

Please enable JavaScript to view the LikeCoin. :P