[實作筆記] 清理 CI/CD(Gitlab-runner)

寫在前面

NM;DR
沒有什麼意義,不需要讀這篇

緣由

  • CI/CD 執行失敗,檢查錯誤發現是 Gitlab-runner[*1] 主機空間不足。

處理歷程

  • 連線 Gitlab-runner 主機
  • 查詢空間使用狀況,找到佔磁區的資料

    marsen@gr00:~$ sudo du -h --max-depth=1 /
    24K /tmp
    0 /sys
    74M /boot
    … skip …
    24K /root
    94G /var
    97G /

  • 用指令作深層的搜尋 sudo du -h --max-depth=3 /var
  • 發現 docker 的問題最大

    252K /var/lib/docker/containers
    4.0K /var/lib/docker/trust
    4.0K /var/lib/docker/runtimes
    91G /var/lib/docker

  • 不選擇清理磁碟,而用 docker 指令檢查 docker images
  • 批次刪除指令 docker images -f "dangling=true" -q | xargs docker rmi
  • 再次檢查

    marsen@gr00:~$ sudo du -h --max-depth=1 /
    24K /tmp
    0 /sys
    74M /boot
    … skip …
    24K /root
    16G /var
    20G /

後續

  • 可能要建立一個排程定期去清理 CI/CD 無用的 image
    • 可以的話想整入 CI/CD 作業中,但在 DinD[*2] 的環境不確定怎麼實作
  • log 與 cache 也有看到較高的資料成長曲線,未來也要納入評估

註解

  1. Gitlab-Runner 是 Gitlab Solution 中執行工作的實體,可以是多台,此案只有單台
  2. Dind: Docker In Docker,如同字面意思,在 Docker 中跑 Docker,是 Gitlab-runner 的實作方法之一

(fin)

[實作筆記] Gitlab CI/CD 與 GCP - Cloud Run

前情提介

在我的實務經驗上,很常與新創團隊合作,而架構選擇常常是第一個問題,
最常見的解法是,由技術負責人選擇最熟悉的技術…
這樣真的好嗎?
比如說,T 社早期由某群工程人員開發,
選擇了 Go、Nodejs、C# 等多語言與雲端 GKE(K8S) 作為開發架構,
事後不負責任離職後,對持續的運作與維護都造成了困難
這件事對我的警鐘是 — 作為管理者,如果不具備識別專業的能力,就只能透過信賴某人或團隊;這是非常脆弱且危險的。

執行環境的選擇

作為 Web 開發者,最常用的執行環境由簡入繁如下:

地端到雲端到

  • 開發機就是正式機: 通常只是用來展示,開發者最常這樣作
  • 地端的主機: 沒有技術能力公司,很有可能都是這樣的架構,直接向開發商買主機放機房或是由開發商部署
  • 地端的虛擬機(VM): 會用較高規格的機器部署多台 VM,可以更有效使用資源
  • 雲端的虛擬機(VM): 使用上與上面差不多,但是由大廠來維持高可用性,學習門檻低
  • 雲端的 Server Less: 需要熟悉不同雲的相關產品,算是有點門檻,完成後可以精準控制預算、減少人力成本、透過雲維持高可用性
  • 雲端的 K8s: 門檻較上面更高,也有相同的優點,但是會有更高的可控性,適合有一定使用規模後,需要細部彈性調整資源的公司。
  • 再回地端: 如果規模再繼續成長,雲端的成本變得高不可攀時,或控制力下降,在有一定的技術水準情況下,有的公司會選擇回到地端。參考 37signals 的例子

GCP Cloud Run

回歸本文,我選擇了 GCP Cloud Run,這是一種雲端的 Server Less 的解決方案。
產品的規模沒有大到需要 K8s,團隊成員的具備足夠的能力,
類似的方案還有 Cloud Function,
作為一個 Web API Base 的輕量專案,我評估 Cloud Run 更適合
Cloud Function 較適合 Event Driven 的片段行為
Cloud Run 較適合有點複雜度,但是可以容器化的應用。

相關作業

首先準備好我的程式,這是一個透過 Azure 寄信程式,需要在 Azure Registered APP 設定,
基本的讀取組態、寫 Log 到雲端與錯誤處理(Error Handle)、相依注入與測試等…
其中一個功能需要將 token 存儲在 GCS(gcloud storage) 裡,
並透過 Cloud Scheduler 定期更新,所以需要為其提供必要的權限與帳號(GCP Service Account).

使用 Cloud Run 前,Docker 也是必要的前置知識,
你會需要撰寫 Dockerfile ,並且需要在 GCP 上建立一個 Artifacts Registry
如此一來,就可以透過 Cloud Build 建立並部署 Cloud Run
用 GCP Workload Identity Federation 管理 Service Account
管理的對像有 2 個,CI 的 Service Account 與執行程式的 Cloud Run 的 Service Account.

後續有考慮透過 Cloud Run 提供 Swagger 之類的 API 文檔,但現階段先共享 Postman 資訊處理。

參考關鍵字

參考

(fin)

[實作筆記] MacBook Terminal 美化與設計

前情提要

參考前文,受同事啟發,改用 zim 取代 oh-my-zsh,
用更高效與精煉的方式設定 terminal 環境,
看看下面的小故事與 Zim 的官網
這就我選擇更換的原因。

小故事

可以參考此文

當前流行的 Zsh 框架有三個主要選項:Oh My Zsh、Prezto 和 Zim。
Oh My Zsh 是最受歡迎的,但因其過於龐大、混亂和性能問題而受到批評。
Prezto 是對其的重大改進,但未被合併回 Oh My Zsh。
而 Zim 是一個從頭重寫的框架,非常快速、高效,並將許多最佳想法結合在一起。
Zim 還提供了各種主題和模塊,並且易於安裝和管理。
這些框架在定製 Zsh 提示符、增加功能和優化性能方面提供了不同的選擇。

Overview

  • 下載與設定 iTerm2
  • 安裝 zim
  • 安裝 powerlevel10k

第一步 下載並安裝 iTerm2

設定 iTerm2 的外觀

  1. 從網站 iTerm2-Color-Schemes (https://github.com/mbadolato/iTerm2-Color-Schemes) 下載你喜歡的配色方案,
  2. 例如 “DimmedMonokai.itermcolors”。
  3. 開啟 iTerm2,點擊菜單欄的 “iTerm2”,選擇 “Preferences”。
  4. 在偏好設定視窗中,選擇 “Profiles” 選項卡,然後選擇你要更改配色方案的會話配置文件。
  5. 在 “Colors” 選項卡下,點擊 “Color Presets” 按鈕,選擇 “Import…”。
  6. 找到剛才下載的配色方案檔案,例如 “DimmedMonokai.itermcolors”,點擊 “Open”。
  7. 選擇 “DimmedMonokai” 作為你的 iTerm2 配色方案。

import .itemcolors

Profiles 裡有更多的設定, 字型、顏色
比如說, 調整啟始視窗大小與背景透明度, 可以前往 Windows 進行設定.
更多的細部設定可以自行摸索.  
記得重新載入才能看到效果

第二步, 安裝 zim

1
curl -fsSL https://raw.githubusercontent.com/zimfw/install/master/install.zsh | zsh

即可完成安裝,並預設定一些相當實用的模組,可以參考

設定

一般來說不需要這些額外的設定,我的情況是同時需要移除 oh-my-zsh 才會有額外的項目需要進行
進入 ~/.zshrc 修改

一、刪除 oh-my-zsh 的區塊
常用的一些工具,都被整合在 zim 之中了
例如 zsh-syntax-highlighting 原本在 zshrc 的設定如下
現在都可以全數刪除

1
2
3
4
5
6
7
8
9
10
11
12
13
# Install zsh-syntax-highlighting if it's not installed
if [ ! -d ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting ]; then
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
fi

# Load zsh-syntax-highlighting plugin
plugins+=(zsh-syntax-highlighting)

# Set name of the theme to load --- if set to "random", it will
# load a random theme each time oh-my-zsh is loaded, in which case,
# to know which specific one was loaded, run: echo $RANDOM_THEME
# See https://github.com/ohmyzsh/ohmyzsh/wiki/Themes
ZSH_THEME="powerlevel10k/powerlevel10k"

由於zim本身就有包含 zsh-syntax-highlighting,
所以其它相關的設定不會有問題。
例如:

1
2
3
4
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=177'
ZSH_HIGHLIGHT_HIGHLIGHTERS=(main brackets)
typeset -A ZSH_HIGHLIGHT_STYLES
ZSH_HIGHLIGHT_STYLES[comment]='fg=242'

Prompt 設定

Prompt 主要影響 terminal 的外觀,
一般來說社群主流會推薦的 Powerlevel10k 後面會提供實作步驟,
但是 zim 已經提供足夠的 theme作選擇,
下面選用 minimal (zim 提供的輕量版主題)作範例  
我們可以修改 ~/.zimrc 即可完成設定

1
2
# A heavily reduced, ASCII-only version of the Spaceship and Starship prompts.
zmodule minimal

安裝 Powerlevel10k

不過 zim 一樣可以使用 Powerlevel10k
前往 Powerlevel10k
我們使用 zim 的方式安裝

修改 ~/.zimrc

1
zmodule romkatv/powerlevel10k --use degit

後執行 zimfw install

之後重啟 iTerm2 將會有一連串設定問題, 依照喜歡的設定即可,
可以參考這個影片,
如果設定完後不喜歡, 可以執行 p10k configure 重新設定
比較一下,效果我覺得都不錯

爆
爆

參考

(fin)

[學習筆記] TypeScript 的 Using 與 Symbol.dispose

介紹

TypeScript 在 5.2 引入了一個新關鍵字 using - 可用於在離開作用域時使用 Symbol.dispose 函數處理任何內容。

看一下官方的說明

TypeScript 5.2 introduces support for the forthcoming Explicit Resource Management feature in ECMAScript,
which aims to address the need for “cleaning up” after creating an object.
This feature allows developers to perform necessary actions such as closing network connections,
deleting temporary files, or releasing memory.

usingawait 的目的在於釋放資源上會非常有用。

在舉例子之前先看一下新的全域 Symbol:Symbol.disposeSymbol.asyncDispose,
任何將函數分配給 Symbol.dispose 的物件都將被視為「資源」(“具有特定存留期的物件”),並且可以與 using 關鍵字一起使用。

舉例來說:

1
2
3
4
5
6
7
8
9
10
11
{
const getResource = () => {
return {
[Symbol.dispose]: () => {
console.log('Hooray!')
}
}
}

using resource = getResource();
} // 'Hooray!' logged to console

當程式離開 resource 所在的 scope 後,就會觸發 Symbol.dispose 的 function

應用

比較常見的場景在於存取 DB、File System 等…
我們現在的作法需要用 try...finally 進行處理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export function processFile(path: string) {
const file = fs.openSync(path, "w+");

try {
// use file...

if (someCondition()) {
// do some more work...
return;
}
}
finally {
// Close the file and delete it.
fs.closeSync(file);
fs.unlinkSync(path);
}
}

而改用 using 後可以變得如此簡單

1
2
3
4
5
6
7
8
9
10
export function processFile(path: string) {
using file = new TempFile(path);

// use file...

if (someCondition()) {
// do some more work...
return;
}
}

參考

(fin)

[實作筆記] Gitlab CI/CD 與 GCP - Workload Identity Federation

前情提介

現況用 Service Account 會有什麼問題?
當我們希望與第三方的服務與 GCP 作整合時,
傳統的(我之前的)作法是透過建立 Service Account Key 去提供給第三方資源存取的權限。
這會產生資安隱患,主要是這把 Key 的權粒度大難以稽核,有效期長風險,
而要定期更換 Key 會變成一個麻煩的管理問題。

需求介紹

我目前透過 GCS 並掛載 Load Balancing 部署靜態網站,
而 CI/CD 是透過 Service Account 的 Key 去執行工作,
這是一種有資安隱憂的作法,所以我試著使用 Workload Identity Federation 取代

概念

TLDR;

而 Workload Identity Federation 是基於 IAM 機制,允許第三方服務整合 GCP 資源,
背後的技術原理是基於 OIDC, 在這裡我們不過度展開,簡單描述如下:

  1. Gitlab CI/CD 首先取 Gitlab OIDC Token,取得 Token 的作法可以參考官方文件,下面是個簡單的範例:
1
2
3
4
5
6
7
8
9
10

job_with_id_tokens:
id_tokens:
FIRST_ID_TOKEN:
aud: https://first.service.com
SECOND_ID_TOKEN:
aud: https://second.service.com
script:
- first-service-authentication-script.sh $FIRST_ID_TOKEN
- second-service-authentication-script.sh $SECOND_ID_TOKEN

|OIDC 是基於 Oauth2 的標準,簡單可以想成 Oauth2 再加上身份驗証。
2. 有了 Gitlab OIDC Token,我們可以透過 GOOGLE STS(Security Token Service) API 取得 Federated Token
在這裡我們需要先建立好 Workload Identity Provider(IdP),而可以設定 Attribute Conditions 來作限制
3. 這個時候可以用 Federated Token 與 GCP IAM API 交換來一個短周期的 Access Token
4. 本質上還是用 Service Account 在作事,但是用短周期的 Access Token 取代 Key, 從而簡化了 Key 的管理工作

實作步驟

  1. 建立 Workload Identity Pool

    1
    2
    3
    4
    5
    6
    #Update $GCP_PROJECT_ID value
    gcloud iam workload-identity-pools create gitlab-test-wip \
    --location="global" \
    --description="Gitlab demo workload Identity pool" \
    --display-name="gitlab-test-wip" \
    --project=$GCP_PROJECT_ID
  2. 設定 workload identity pool provider 並建立 Attribute conditions,
    這步的關鍵是讓只符合你條件設定的 User 才能取得 Token

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #Update GITLAB_NAMESPACE_PATH value
    gcloud iam workload-identity-pools providers create-oidc gitlab-identity-provider --location="global" \
    --workload-identity-pool="gitlab-test-wip" \
    --issuer-uri="https://gitlab.com" \
    --allowed-audiences=https://gitlab.com \
    --attribute-mapping="google.subject=assertion.sub,attribute.aud=assertion.aud,attribute.project_path=assertion.project_path,attribute.project_id=assertion.project_id,attribute.namespace_id=assertion.namespace_id,attribute.namespace_path=assertion.namespace_path,attribute.user_email=assertion.user_email,attribute.ref=assertion.ref,attribute.ref_type=assertion.ref_type" \
    #--attribute-condition="assertion.namespace_path.startsWith(\"$GITLAB_NAMESPACE_PATH\")" \
    --attribute-condition="assertion.namespace_path.startsWith(\"marsen\")" \
    --project=$GCP_PROJECT_ID
  3. 建立 GCP Service Account
    在我的例子中

    1
    2
    3
    4
    5
    6
    7
    #Create a service account
    gcloud iam service-accounts create gitlab-runner-sa --project=$GCP_PROJECT_ID

    #Add sample permissions to the Service account
    gcloud projects add-iam-policy-binding $GCP_PROJECT_ID \
    --member=serviceAccount:gitlab-wif-demo@${GCP_PROJECT_ID}.iam.gserviceaccount.com \
    --role=roles/storage.admin
  4. 建立 Service Account 與 WIP 的角色關係綁定

    可以先取得專案的 GCP Project Id

    1
    PROJECT_NUMBER=$(gcloud projects describe $(gcloud config get-value core/project) --format=value\(projectNumber\) --project $GCP_PROJECT_ID)

    設定 Service Account 的角色為 workloadIdentityUser,並將其設定為 workloadIdentityPools 的服務帳戶

    1
    2
    3
    gcloud iam service-accounts add-iam-policy-binding gitlab-runner-sa@${GCP_PROJECT_ID}.iam.gserviceaccount.com \
    --role=roles/iam.workloadIdentityUser \
    --member="principalSet://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/gitlab-test-wip/*"
  5. 建立 Gitlab CI/CD 進行測試

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
image: node:20.9.0-alpine

.gcp_wif_auth: &gcp_wif_auth
#id_tokens to create JSON web tokens (JWT) to authenticate with third party services.This replaces the CI_JOB_JWT_V2
id_tokens:
GITLAB_OIDC_TOKEN:
aud: https://gitlab.com
before_script:
- apt-get update && apt-get install -yq jq
#Get temporary credentials using the ID token
- |
PAYLOAD=$(cat <<EOF
{
"audience": "//iam.googleapis.com/${GCP_WORKLOAD_IDENTITY_PROVIDER}",
"grantType": "urn:ietf:params:oauth:grant-type:token-exchange",
"requestedTokenType": "urn:ietf:params:oauth:token-type:access_token",
"scope": "https://www.googleapis.com/auth/cloud-platform",
"subjectTokenType": "urn:ietf:params:oauth:token-type:jwt",
"subjectToken": "${GITLAB_OIDC_TOKEN}"
}
EOF
)
- |
echo "Payload: ${PAYLOAD}"
- |
FEDERATED_TOKEN=$(curl -s -X POST "https://sts.googleapis.com/v1/token" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--data "${PAYLOAD}" \
| jq -r '.access_token'
)
#- |
# echo "Federated Token: ${FEDERATED_TOKEN}"
#Use the federated token to impersonate the service account linked to workload identity pool
#The resulting access token is stored in CLOUDSDK_AUTH_ACCESS_TOKEN environment variable and this will be passed to the gcloud CLI
- |
WHAT_IT_IS=$(curl -s -X POST "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/${SERVICE_ACCOUNT_EMAIL}:generateAccessToken" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer ${FEDERATED_TOKEN}" \
--data '{"scope": ["https://www.googleapis.com/auth/cloud-platform"]}' \
| jq -r '.'
)
- |
echo "WHAT_IT_IS: ${WHAT_IT_IS}"
- |
export CLOUDSDK_AUTH_ACCESS_TOKEN=$(curl -s -X POST "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/${SERVICE_ACCOUNT_EMAIL}:generateAccessToken" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer ${FEDERATED_TOKEN}" \
--data '{"scope": ["https://www.googleapis.com/auth/cloud-platform"]}' \
| jq -r '.accessToken'
)

stages:
- deploy-prod

deploy-prod:
variables:
GCP_PROJECT_NAME: my-project-9527
GCP_WORKLOAD_IDENTITY_PROVIDER: "projects/000009527/locations/global/workloadIdentityPools/gitlab-test-wip/providers/gitlab-identity-provider"
SERVICE_ACCOUNT_EMAIL: "[email protected]"
<<: *gcp_wif_auth
stage: deploy-prod
image: google/cloud-sdk:latest
script:
- echo "Deploying artifacts to PROD GCS🚀🚀🚀"
- echo $CLOUDSDK_AUTH_ACCESS_TOKEN
- gcloud config set project ${GCP_PROJECT_NAME}
- gcloud storage cp -r $CI_PROJECT_DIR/dist/* gs://my-static-website/

參考

(fin)

[學習筆記] 為前端框架 Component 建立 Props Typing 的幾種方式,以 React 為例

前言

在開發 React 應用程式時(其它框架其實也適用),
使用 TypeScript 來強制定義 props 是一個常見的做法。
然而,有許多不同的方法可以實現這一目標。這篇文章討論了三種主要的方法。

比較

Inline Object Literals

在這個方法中,我們直接在函式的參數位置定義了 props 的型別,如下所示:

1
2
3
4
5
const Wrapper = (props: {
children?: ReactNode;
}) => {
return <div>{props.children}</div>;
};

優點:快速簡潔。
缺點:不太適合長期維護。

另一種解構的寫法會有更少的字數,
它會有一個 {}:{}特殊寫法,前者表示傳入的參數,後者表示要被解構的物件與型別
這樣的寫法最主要在 component 當中要使用傳入參數時可以省略 prop. 的語法,
但是理解上會不會更困難(對於不熟悉的開發者而言)就見團隊見智了…

1
2
3
4
5
6
7
8
 
const Wrapper = ({
children,
}: {
children?: ReactNode;
}) => {
return <div>{children}</div>;
};

Type Aliases

在這個方法中,我們把 props 的型別定義抽取到一個類型別名中:

1
2
3
4
5
6
7
export type WrapperProps = {
children?: ReactNode;
};

const Wrapper = (props: WrapperProps) => {
return <div>{props.children}</div>;
};

優點:可以在其他文件中重用。
缺點:在大型代碼庫中可能會讓 TypeScript 變慢。

Interfaces

在這個方法中,我們使用介面來定義 props:

1
2
3
4
5
6
7
export interface WrapperProps {
children?: ReactNode;
}

const Wrapper = (props: WrapperProps) => {
return <div>{props.children}</div>;
};

優點:性能較好,在大型代碼庫中表現較好。
缺點:需要較多的代碼。

小結

儘量使用 interface 會有較好的效能,同時可以共用這些代碼並幫助理解。

參考

(fin)

[學習筆記] Vim 學習資源

介紹

Vim 是一款強大高效的文本編輯器,強調效率和快速操作。
學習 Vim 能顯著提升編輯速度和效率,無需滑鼠,節省操作時間。
這裡記錄著我的學習資源,提供給未來的我複習使用。

TLDR Tips

  1. gg:移動到檔案的第一行
  2. G:移動到檔案的最後一行
  3. gg=G:重新縮排整個檔案
  4. gv:重新選取上一次的視覺選取
  5. `` <`:跳到上一次視覺選取的開始
  6. `` >`:跳到上一次視覺選取的結尾
  7. ^:移動到行的第一個非空白字符
  8. g_:移動到行的最後一個非空白字符
  9. g_lD:刪除行上的所有尾部空白
  10. ea:在當前單字的末尾插入
  11. gf:跳到游標下的文件名
  12. xp:向前交換字符
  13. Xp:向後交換字符
  14. yyp:複製當前行
  15. yapP:複製當前段落
  16. dat:刪除包括標籤在內的 HTML 標籤
  17. dit:刪除 HTML 標籤內的內容,但不包括標籤本身
  18. w:向右移動一個單字
  19. b:向左移動一個單字
  20. dd:刪除當前行
  21. zc:關閉當前摺疊
  22. zo:打開當前摺疊
  23. za:切換當前摺疊
  24. zi:完全切換摺疊
  25. <<:向左移動當前行的縮排
  26. >>:向右移動當前行的縮排
  27. z=:顯示拼寫更正
  28. zg:添加到拼寫字典
  29. zw:從拼寫字典中刪除
  30. ~:切換當前字符的大小寫
  31. gUw:將大小寫轉換到單字的末尾(u 用於小寫,~ 用於切換)
  32. gUiw:將整個單字轉換為大寫(u 用於小寫,~ 用於切換)
  33. gUU:將整行轉換為大寫
  34. gu$:將直到行尾的文本轉換為小寫
  35. da":刪除下一個雙引號括起來的字符串
  36. +:移動到下一行的第一個非空白字符
  37. S:刪除當前行並進入插入模式
  38. I:在行的開頭插入
  39. ci":更改下一個雙引號括起來的字符串內容
  40. ca{:更改大括號內的內容(也可以試試 [, ( 等)
  41. vaw:視覺選取單字
  42. dap:刪除整個段落
  43. r:替換字符
  44. ``[`:跳轉到上次複製的文本的開始
  45. ``]`:跳轉到上次複製的文本的結尾
  46. g;:跳轉到上次更改的位置
  47. g,:向前跳轉到更改列表
  48. &:在當前行上重複上次的替換
  49. g&:在所有行上重複上次的替換
  50. ZZ:儲存當前檔案並關閉

學習資源

內建學習工具

1
> vimtutor

(fin)

[實作筆記] 一些關於 Azure Resource Group 的冷知識

前情提要

Resource Group 是 Azure 上比較特別的一個設計,
這裡拿來記錄一些知道就知道,不知道就不知道的小事務。

本文

NetworkWatcherRG

注意

當您使用 Azure 入口網站 建立網路監看員實例時:

網路監看員實例的名稱會自動設定為NetworkWatcher_region,其中region會對應至 網路監看員 實例的 Azure 區域。
例如,在美國東部區域中啟用的網路監看員名為NetworkWatcher_eastus。
網路監看員實例會建立在名為NetworkWatcherRG的資源群組中。 若尚無該資源群組,將會加以建立。

Azure DevOps

當我們將 Azure DevOps 的 Billing 綁定之時,
會建立一組 VisualStudioOnline-XXXX 的 Resource Group

(fin)

[實作筆記] Macbook 壓縮檔案

前情提要

假設分享機密文件給同事或者發送文件到郵件或雲端儲存時,就必須手動處理壓縮和加密,
可以參考一些文章,大致有三個作法

  • 購買付款壓縮軟體
  • 使用雲端服務
  • 手動執行 terminal 指令

手動執行就可以處理的問題,我不會特別想要付款買一個軟體,
而雲端服務會擔心資訊安全,特別是要加密的資料代表有一定程度的重要性。
Terminal 大概是網路文章的主流解。
當我需要經常這樣做時,就太麻煩了,還要記得操作指令,額外增加心智負擔。
理想上,我希望只要選擇文件或資料夾,右鍵點擊”Zip with Password”,就能創建加密的 zip 文件。

實作

  1. 打開 Automator app。

  2. 創建一個新 Automator 文件:File > New (或按 ⌘N),選擇 “Quick Action” 類型。

  3. 將輸入類型更改為 “files or folders”。

  4. 在左側的 Actions library 中,雙擊 “Run AppleScript”,或拖放到右側工作區。刪除示例代碼,替換為第 5 步的腳本。

  5. 複製並粘貼下面的 AppleScript 代碼。

    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

    set prompt_text to "請輸入壓縮密碼"

    repeat
    set zip_password to text returned of (display dialog prompt_text default answer "" with hidden answer)
    set verify_password to text returned of (display dialog "再次輸入壓縮密碼" buttons {"OK"} default button 1 default answer "" with hidden answer)
    considering case and diacriticals
    if (zip_password = verify_password) then
    exit repeat
    else
    set prompt_text to "密碼不一致,請重新設定"
    end if
    end considering
    end repeat

    tell application "Finder"
    set the_items to selection
    if ((class of the_items is list) and (count of the_items) > 0) then
    set items_to_zip to ""
    repeat with each_item in the_items
    set each_item_alias to each_item as alias
    set item_name to name of each_item_alias
    set item_name to quoted form of (item_name & "")
    set items_to_zip to items_to_zip & item_name & " "
    end repeat

    set first_item to (item 1 of the_items) as alias
    set containing_folder to POSIX path of (container of first_item as alias)
    set zip_name to text returned of (display dialog "輸入壓檔名" default answer "")
    set zip_file_name to quoted form of (zip_name & ".zip")

    if zip_password is not equal to "" then
    -- 如果存在密碼,執行加密壓縮
    do shell script "cd '" & containing_folder & "'; zip -x .DS_Store -r0 -P '" & zip_password & "' " & zip_file_name & " " & items_to_zip
    else
    -- 否則執行單純壓縮
    do shell script "cd '" & containing_folder & "'; zip -x .DS_Store -r0 " & zip_file_name & " " & items_to_zip
    end if
    else
    display dialog "你未選擇任何檔案。" buttons {"OK"} default button 1
    end if
    end tell

  6. 儲存工作流程:File > Save (或按 ⌘S),給它一個名字,如 “Zip with Password”

現在,選擇文件或文件夾,右擊,選擇 “Quick Actions” 中的 “Zip with Password”,
按照提示輸入密碼、驗證密碼和設置 zip 文件的名字。測試新創建的 zip 文件,確保一切運作正常。

參考

(fin)

[實作筆記] ClamAV 安裝

提要

因 ISO 需要在 GCP VM(Linux 系統)上安裝防毒。
ClamAV 是一款強大的開源防毒引擎,專為檢測和清除惡意程式而設計。
這篇用來記錄終端機中安裝和配置 ClamAV,包括系統更新、病毒庫更新、自動運行設定等步驟,
以確保系統有效抵禦各種威脅。

實作

首先,在終端機中輸入以下指令,展開系統更新的步驟:

1
sudo apt update && sudo apt upgrade

出現警示請按 Y

1
2
After this operation, 12.1 MB of additional disk space will be used.
Do you want to continue? [Y/n] Y

接著,透過以下指令安裝 ClamAV,一強大的防護工具,以確保系統免受惡意程式的侵害:

1
sudo apt install clamav clamav-daemon -y 

當安裝完成後

確保沒有其他 freshclam 進程在運行,您可以使用以下指令查看:

1
ps aux | grep freshclam

如果有其他 freshclam 進程在運行,請終止(kill)它們。

執行以下指令可更新 ClamAV 的病毒定義庫:

1
sudo freshclam

隨後,您可以進行系統掃描,以查找並清除潛在的威脅,請使用以下指令:

1
sudo clamscan -r /path/to/folder

若欲使 ClamAV 在系統啟動時自動運行,請執行以下指令:

1
sudo systemctl enable clamav-daemon

這將設定 ClamAV 在每次系統啟動時主動保護您的系統。

啟動 ClamAV 服務(如果它沒有在系統啟動時自動啟動):

1
sudo systemctl start clamav-daemon

檢查 ClamAV 服務的運行狀態:

1
sudo systemctl status clamav-daemon

這樣,您可以確保 ClamAV 已經更新、服務已經啟動,並檢查服務的當前運行狀態。

參考

(fin)

Please enable JavaScript to view the LikeCoin. :P