eeyellow's Blog

日常隨筆

HomeAssistant 01 - 安裝

今天的目標是在 Synology NAS 上使用 Docker 運行 HomeAssistant。

先列出配備與環境:

  1. NAS:Synology DS224+
  2. OS:DSM 7.2.2-72806 Update 3
  3. CPU:Intel Celeron J4125
  4. RAM:18GB (原廠2GB + 擴充16GB)

安裝步驟

  1. 套件中心 -> Container Manager

  2. Container Manager -> 倉庫伺服器 -> 搜尋 home-assistant -> 下載

  3. Container Manager -> 容器 -> 新增

    • 啟用自動重啟要打勾

    • 資源限制要依照自己的環境規格設置,我之後也是要依照使用狀況再調整。

  4. 儲存空間設定 -> 設定資料夾 /docker/home_assistant/config : /config

  5. 環境設定 -> 新增 -> TZ : Asia/Taipei

  6. 網路 -> 選擇 host

  7. 設定完成後,等待一段時間,HomeAssistant 就會啟動完成。輸入 http://NAS_IP:8123 進入 HomeAssistant。

  8. 第一次進入需要設定帳號、密碼、家庭所在位置,其他設定就用預設。登入後,就可以看到 HomeAssistant 的介面了。

安裝SpecFlow

SpecFlow官網已經有開新測試專案的教學,這邊不贅述。

這邊紀錄把SpecFlow整合進現有的測試專案之步驟。

1. 安裝VisualStudio擴充功能

SpecFlow for Visual Studio 2022

2. 安裝套件

在現有的 xUnit 測試專案中,安裝SpecFlow.xUnit

1
dotnet add package SpecFlow.xUnit

加入 LivingDoc 支援

1
dotnet add package SpecFlow.Plus.LivingDocPlugin

3. 加入Feature

建立資料夾結構:

1
2
3
BDD
├───Features
└───StepDefinitions

Features資料夾上按右鍵 > 加入 > 新增項目 > Feature File for SpecFlow,檔名先用預設 Feature1.feature,之後可以再改。

預設的內容是這樣:

1
2
3
4
5
6
7
8
9
Feature: Feature1

A short summary of the feature

@tag1
Scenario: [scenario name]
Given [context]
When [action]
Then [outcome]

把它簡單修改成如下:

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
@Home
@Login
Feature: 登入功能

使用者輸入帳密後送出
能夠得到登入的結果

#===========================================

Background:
Given 帳號列表如下:
| Account | Password |
| user1 | pwd1 |
| user2 | pwd2 |
| user3 | pwd3 |

#===========================================

Scenario: 輸入正確的帳密,可以成功登入
Given 輸入帳號為 "<account>"
And 輸入密碼為 "<password>"
When 按下登入按鈕
Then 得到登入結果應為 "<isValid>"

Examples:
| account | password | isValid |
| user1 | pwd1 | true |
| user2 | pwd2 | true |
| user3 | pwd3 | true |

#===========================================

建置專案,會發現自動產生出了 Feature1.feature.cs

4. 加入StepDefinition

上個步驟完成後,Feature 檔會出現顏色區別,其中 Given-When-Then 是紫色,這表示還沒有對應的 StepDefinition

按右鍵 > Define Steps > Create

把產生出的檔案,移到StepDefinitions資料夾中。

回到 Feature 檔,會發現 Given-When-Then 變成白色了,這表示已經有對應的 StepDefinition,並且可以按右鍵 > 移到定義,直接移到對應的程式碼。

5. 修改StepDefinition

產生出來的 StepDefinition 預設類似這樣:

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
[Binding]
public class 登入功能
{
[Given(@"帳號列表如下:")]
public void Given帳號列表如下(Table table)
{
throw new PendingStepException();
}

[Given(@"輸入帳號為 ""([^""]*)""")]
public void Given輸入帳號為(string p0)
{
throw new PendingStepException();
}

[Given(@"輸入密碼為 ""([^""]*)""")]
public void Given輸入密碼為(string p0)
{
throw new PendingStepException();
}

[When(@"按下登入按鈕")]
public void When按下登入按鈕()
{
throw new PendingStepException();
}

[Then(@"得到登入結果應為 ""([^""]*)""")]
public void Then得到登入結果應為(string @true)
{
throw new PendingStepException();
}
}

需要實作它,以下是一個很簡單的實現

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
[Binding]
public class 登入功能
{
private readonly ScenarioContext _scenarioContext;
private Dictionary<string, string> _mockUserTable = new Dictionary<string, string>();
private string _account;
private string _password;
private bool _isValid;
/// <summary>建構式</summary>
public 登入功能(ScenarioContext scenarioContext)
{
_scenarioContext = scenarioContext;
}

[Given(@"帳號列表如下:")]
public void Given帳號列表如下(Table table)
{
foreach(var row in table.Rows)
{
_mockUserTable.Add(row["Account"], row["Password"]);
}
}

[Given(@"輸入帳號為 ""([^""]*)""")]
public void Given輸入帳號為(string account)
{
_account = account;
}

[Given(@"輸入密碼為 ""([^""]*)""")]
public void Given輸入密碼為(string password)
{
_password = password;
}

[When(@"按下登入按鈕")]
public void When按下登入按鈕()
{
_isValid = _mockUserTable.Any(a => a.Key == _account
&& a.Value == _password);
}

[Then(@"得到登入結果應為 ""([^""]*)""")]
public void Then得到登入結果應為(bool expectedResult)
{
Assert.Equal(_isValid, expectedResult);
}
}

6. 加入更多 Scenario

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#===========================================

Scenario: 輸入的錯誤帳密,登入失敗
Given 輸入帳號為 "<account>"
And 輸入密碼為 "<password>"
When 按下登入按鈕
Then 得到登入結果應為 "<isValid>"

Examples:
| account | password | isValid |
| user1 | pwd123 | false |
| pwd2 | user2 | false |
| user3 | pwd3 | false |

#===========================================

可以再依功能需求添加更多 Scenario

7. 執行測試

在測試總管視窗,可以看到所有的測試了,執行後會顯示結果。

8. 產生 LivingDoc

需要先安裝 CLI 工具

1
dotnet tool install --global SpecFlow.Plus.LivingDoc.CLI

然後到測試專案的 bin\Debug\net8.0 (實際路徑依開發環境為準),執行

1
2
# SpecFlowTestProject.dll 應替換為 [你的專案名稱].dll
livingdoc test-assembly SpecFlowTestProject.dll -t TestExecution.json

這樣可以產出 LivingDoc.html,直接打開就能看到測試規格與結果了。

官網教學

9. 與Azure DevOps 管線整合

Azure DevOps 需要先安裝 SpecFlow+LivingDoc Extension

管線設定要先有一個 Task: dotnet test,後面再加上Task: SpecFlow LivingDoc

1
2
3
4
5
6
7
8
9
steps:
- task: techtalk.techtalk-specflow-plus.specflow-plus.SpecFlowPlus@0
displayName: 'SpecFlow LivingDoc'
inputs:
generatorSource: TestAssembly
testAssemblyFilePath: 'SpecFlowTestProject\bin\Release\net8.0\SpecFlowTestProject.dll'
testExecutionJson: 'SpecFlowTestProject\bin\Release\net8.0\TestExecution.json'
projectLanguage: en
bindingAssemblies: 'SpecFlowTestProject\bin\Release\net8.0\SpecFlowTestProject.dll'

這邊的設定僅供參考,需要依實際狀況做調整。

成功後就能把產生 LivingDoc 的步驟整合到CI裡面了

在Windows WSL2 上安裝地端Kubernetes (Minikube)

Prerequisite

安裝WSL2 + Docker

Install Minikube

1
2
3
4
5
6
7
8
9
10
11
# Download the latest Minikube
curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64

# Make it executable
chmod +x ./minikube

# Move it to your user's executable PATH
sudo mv ./minikube /usr/local/bin/

#Set the driver version to Docker
minikube config set driver docker

Install Kubectl

1
2
3
4
5
6
7
8
# Download the latest Kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"

# Make it executable
chmod +x ./kubectl

# Move it to your user's executable PATH
sudo mv ./kubectl /usr/local/bin/

Running Minikube

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
minikube start

kubectl config use-context minikube

# Start minikube again to enable kubectl in it
minikube start

kubectl get pods -A
# NAMESPACE NAME READY STATUS RESTARTS AGE
# kube-system coredns-7db6d8ff4d-v89pt 1/1 Running 2 (7m43s ago) 8d
# kube-system etcd-minikube 1/1 Running 2 (7m48s ago) 8d
# kube-system kube-apiserver-minikube 1/1 Running 2 (7m38s ago) 8d
# kube-system kube-controller-manager-minikube 1/1 Running 2 (7m48s ago) 8d
# kube-system kube-proxy-sdjmt 1/1 Running 2 (7m48s ago) 8d
# kube-system kube-scheduler-minikube 1/1 Running 2 (7m48s ago) 8d
# kube-system storage-provisioner 1/1 Running 4 (7m28s ago) 8d
# kubernetes-dashboard dashboard-metrics-scraper-b5fc48f67-gzqrj 1/1 Running 2 (7m48s ago) 8d
# kubernetes-dashboard kubernetes-dashboard-779776cb65-8df95 1/1 Running 3 (7m27s ago) 8d

minikube dashboard
# 用瀏覽器開啟儀表板連結
(ctrl + z)
bg # 讓dashboard在背景執行

Install Helm

1
2
3
4
5
6
7
8
9
curl --output helm-linux-amd64.tar.gz https://get.helm.sh/helm-v3.4.2-linux-amd64.tar.gz

tar -zxvf helm-linux-amd64.tar.gz

sudo mv linux-amd64/helm /usr/local/bin/helm

rm helm-linux-amd64.tar.gz

rm -rf linux-amd64

Install Kompose

1
2
3
4
5
curl -L https://github.com/kubernetes/kompose/releases/download/v1.34.0/kompose-linux-amd64 -o kompose

chmod +x kompose

sudo mv ./kompose /usr/local/bin/kompose

Check Version

1
2
3
4
5
6
7
8
9
10
11
12
13
14

minikube version
# minikube version: v1.33.1
# commit: 5883c09216182566a63dff4c326a6fc9ed2982ff

kubectl version
# Client Version: v1.30.2
# Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3

helm version
# version.BuildInfo{Version:"v3.4.2", GitCommit:"23dd3af5e19a02d4f4baa5b2f242645a1a3af629", GitTreeState:"clean", GoVersion:"go1.14.13"}

kompose version
# 1.34.0 (cbf2835db)

Docker技術分享

Docker簡介

  • Docker是一個開源的平台,用於開發、交付和執行應用程序。它透過容器(Container)技術實現應用程序的封裝,確保應用程序可以在任何環境中一致地運行。

  • 特點

    1. 輕量級:容器共享主機的操作系統內核,避免了虛擬機的額外開銷,使得容器更輕量,啟動速度更快。
    2. 一致性:開發、測試、部署環境一致,減少了「在我的電腦上可以運行」這類問題。
    3. 便捷性:容易打包、分享和部署應用,通過Dockerfile可以簡單自動化構建過程。
    4. 隔離性:每個容器都是獨立的運行環境,應用之間互不干擾,提高安全性和穩定性。
    5. 擴展性:容易擴展,可以輕鬆增加或減少容器數量以應對負載變化。
  • 與傳統虛擬機的比較

環境建置:Windows 11 + WSL2 (Ubuntu)

  1. 啟動WSL2

  2. 從 Microsoft Store 中安裝 Ubuntu (22.04)

  3. Windows Update

  4. (如果原本有安裝)移除Docker Desktop

  5. 啟動WSL2(Ubuntu)

  6. 在WSL2中安裝Docker

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    curl -fsSL https://get.docker.com -o get-docker.sh	
    sudo sh get-docker.sh
    sudo usermod -aG docker $USER
    sudo apt-get update && sudo apt-get install docker-compose docker-compose-plugin

    # Using Ubuntu 22.04 or Debian 10 / 11? You need to do 1 extra step for iptables
    # compatibility, you'll want to choose option (1) from the prompt to use iptables-legacy.

    sudo update-alternatives --config iptables # 選nftables-auto
    sudo service docker start
  7. 終端機美化(Optional)

    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
    # 安裝 zsh    
    sudo apt install zsh
    # 更改預設shell
    chsh -s $(which zsh)
    # 安裝 oh-my-zsh
    sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
    # 安裝 powerlevel10k
    git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k
    # 設定zsh的主題使用powerlevel10k
    sed -i 's/ZSH_THEME="[^"]*"/ZSH_THEME="powerlevel10k\/powerlevel10k"/' ~/.zshrc

    git clone https://github.com/zsh-users/zsh-autosuggestions.git $ZSH_CUSTOM/plugins/zsh-autosuggestions
    git clone https://github.com/zsh-users/zsh-syntax-highlighting.git $ZSH_CUSTOM/plugins/zsh-syntax-highlighting

    sed -i 's/# ENABLE_CORRECTION="true"/ENABLE_CORRECTION="true"/' ~/.zshrc
    sed -i 's/plugins=(git)/plugins=(git zsh-autosuggestions zsh-syntax-highlighting)/' ~/.zshrc

    # LS_COLORS
    # https://medium.com/@asvinjangid.kumar/changing-colors-of-files-and-folders-in-linux-5d29967c3012
    echo 'export LS_COLORS="bd=0;38;2;102;217;239;48;2;51;51;51:rs=0:mi=0;38;2;0;0;0;48;2;255;74;68:do=0;38;2;0;0;0;48;2;249;38;114:di=0;38;2;102;217;239:ln=0;38;2;249;38;114:ow=0:fi=0:ca=0:no=0:pi=0;38;2;0;0;0;48;2;102;217;239:st=0:so=0;38;2;0;0;0;48;2;249;38;114:sg=0:su=0:ex=1;38;2;249;38;114:cd=0;38;2;249;38;114;48;2;51;51;51:or=0;38;2;0;0;0;48;2;255;74;68:tw=0:mh=0:*~=0;38;2;122;112;112:*.m=0;38;2;0;255;135:*.z=4;38;2;249;38;114:*.d=0;38;2;0;255;135:*.h=0;38;2;0;255;135:*.o=0;38;2;122;112;112:*.p=0;38;2;0;255;135:*.t=0;38;2;0;255;135:*.a=1;38;2;249;38;114:*.r=0;38;2;0;255;135:*.c=0;38;2;0;255;135:*.pl=0;38;2;0;255;135:*.la=0;38;2;122;112;112:*.di=0;38;2;0;255;135:*.ml=0;38;2;0;255;135:*.md=0;38;2;226;209;57:*.hi=0;38;2;122;112;112:*.jl=0;38;2;0;255;135:*.wv=0;38;2;253;151;31:*.bz=4;38;2;249;38;114:*.cc=0;38;2;0;255;135:*.mn=0;38;2;0;255;135:*.bc=0;38;2;122;112;112:*.hh=0;38;2;0;255;135:*.ex=0;38;2;0;255;135:*.rb=0;38;2;0;255;135:*.rs=0;38;2;0;255;135:*.7z=4;38;2;249;38;114:*.td=0;38;2;0;255;135:*.pp=0;38;2;0;255;135:*.ui=0;38;2;166;226;46:*.sh=0;38;2;0;255;135:*.kt=0;38;2;0;255;135:*.lo=0;38;2;122;112;112:*.gv=0;38;2;0;255;135:*.cr=0;38;2;0;255;135:*.py=0;38;2;0;255;135:*.fs=0;38;2;0;255;135:*.so=1;38;2;249;38;114:*.ll=0;38;2;0;255;135:*css=0;38;2;0;255;135:*.ps=0;38;2;230;219;116:*.cp=0;38;2;0;255;135:*.gz=4;38;2;249;38;114:*.el=0;38;2;0;255;135:*.vb=0;38;2;0;255;135:*.pm=0;38;2;0;255;135:*.js=0;38;2;0;255;135:*.go=0;38;2;0;255;135:*.hs=0;38;2;0;255;135:*.ts=0;38;2;0;255;135:*.as=0;38;2;0;255;135:*.ko=1;38;2;249;38;114:*.xz=4;38;2;249;38;114:*.rm=0;38;2;253;151;31:*.cs=0;38;2;0;255;135:*.nb=0;38;2;0;255;135:*.rtf=0;38;2;230;219;116:*.com=1;38;2;249;38;114:*.tmp=0;38;2;122;112;112:*.bak=0;38;2;122;112;112:*.img=4;38;2;249;38;114:*.dll=1;38;2;249;38;114:*.git=0;38;2;122;112;112:*.exe=1;38;2;249;38;114:*.xls=0;38;2;230;219;116:*.bcf=0;38;2;122;112;112:*.xml=0;38;2;226;209;57:*.lua=0;38;2;0;255;135:*.sxi=0;38;2;230;219;116:*.ics=0;38;2;230;219;116:*.psd=0;38;2;253;151;31:*.php=0;38;2;0;255;135:*.m4v=0;38;2;253;151;31:*.nix=0;38;2;166;226;46:*TODO=1:*.tcl=0;38;2;0;255;135:*.mp4=0;38;2;253;151;31:*.tex=0;38;2;0;255;135:*.ttf=0;38;2;253;151;31:*.ppt=0;38;2;230;219;116:*.xlr=0;38;2;230;219;116:*.tif=0;38;2;253;151;31:*.hxx=0;38;2;0;255;135:*.gvy=0;38;2;0;255;135:*.pod=0;38;2;0;255;135:*.deb=4;38;2;249;38;114:*.mid=0;38;2;253;151;31:*.clj=0;38;2;0;255;135:*.gif=0;38;2;253;151;31:*.fls=0;38;2;122;112;112:*.ind=0;38;2;122;112;112:*.dpr=0;38;2;0;255;135:*.kts=0;38;2;0;255;135:*.eps=0;38;2;253;151;31:*.png=0;38;2;253;151;31:*.blg=0;38;2;122;112;112:*.vob=0;38;2;253;151;31:*.bin=4;38;2;249;38;114:*.bag=4;38;2;249;38;114:*.pas=0;38;2;0;255;135:*.pro=0;38;2;166;226;46:*.txt=0;38;2;226;209;57:*.vim=0;38;2;0;255;135:*.svg=0;38;2;253;151;31:*.ods=0;38;2;230;219;116:*.ipp=0;38;2;0;255;135:*.epp=0;38;2;0;255;135:*.def=0;38;2;0;255;135:*.awk=0;38;2;0;255;135:*.pgm=0;38;2;253;151;31:*.cxx=0;38;2;0;255;135:*.ini=0;38;2;166;226;46:*.wav=0;38;2;253;151;31:*.kex=0;38;2;230;219;116:*.rpm=4;38;2;249;38;114:*.mpg=0;38;2;253;151;31:*.tar=4;38;2;249;38;114:*.rar=4;38;2;249;38;114:*.jar=4;38;2;249;38;114:*.pyd=0;38;2;122;112;112:*.xcf=0;38;2;253;151;31:*.tbz=4;38;2;249;38;114:*.bmp=0;38;2;253;151;31:*.zst=4;38;2;249;38;114:*.dot=0;38;2;0;255;135:*.sxw=0;38;2;230;219;116:*.apk=4;38;2;249;38;114:*.ilg=0;38;2;122;112;112:*.wmv=0;38;2;253;151;31:*.odp=0;38;2;230;219;116:*.xmp=0;38;2;166;226;46:*.pid=0;38;2;122;112;112:*.bz2=4;38;2;249;38;114:*.cpp=0;38;2;0;255;135:*hgrc=0;38;2;166;226;46:*.pbm=0;38;2;253;151;31:*.swp=0;38;2;122;112;112:*.fsi=0;38;2;0;255;135:*.htc=0;38;2;0;255;135:*.cgi=0;38;2;0;255;135:*.toc=0;38;2;122;112;112:*.rst=0;38;2;226;209;57:*.ltx=0;38;2;0;255;135:*.csx=0;38;2;0;255;135:*.pkg=4;38;2;249;38;114:*.fnt=0;38;2;253;151;31:*.tml=0;38;2;166;226;46:*.htm=0;38;2;226;209;57:*.aux=0;38;2;122;112;112:*.mov=0;38;2;253;151;31:*.bib=0;38;2;166;226;46:*.ogg=0;38;2;253;151;31:*.mkv=0;38;2;253;151;31:*.sbt=0;38;2;0;255;135:*.bbl=0;38;2;122;112;112:*.tgz=4;38;2;249;38;114:*.asa=0;38;2;0;255;135:*.cfg=0;38;2;166;226;46:*.bsh=0;38;2;0;255;135:*.mir=0;38;2;0;255;135:*.bst=0;38;2;166;226;46:*.mli=0;38;2;0;255;135:*.odt=0;38;2;230;219;116:*.zip=4;38;2;249;38;114:*.erl=0;38;2;0;255;135:*.vcd=4;38;2;249;38;114:*.pdf=0;38;2;230;219;116:*.yml=0;38;2;166;226;46:*.wma=0;38;2;253;151;31:*.avi=0;38;2;253;151;31:*.inl=0;38;2;0;255;135:*.log=0;38;2;122;112;112:*.bat=1;38;2;249;38;114:*.hpp=0;38;2;0;255;135:*.otf=0;38;2;253;151;31:*.pyc=0;38;2;122;112;112:*.zsh=0;38;2;0;255;135:*.exs=0;38;2;0;255;135:*.jpg=0;38;2;253;151;31:*.dox=0;38;2;166;226;46:*.tsx=0;38;2;0;255;135:*.c++=0;38;2;0;255;135:*.fon=0;38;2;253;151;31:*.pyo=0;38;2;122;112;112:*.csv=0;38;2;226;209;57:*.mp3=0;38;2;253;151;31:*.ppm=0;38;2;253;151;31:*.doc=0;38;2;230;219;116:*.pps=0;38;2;230;219;116:*.arj=4;38;2;249;38;114:*.iso=4;38;2;249;38;114:*.m4a=0;38;2;253;151;31:*.idx=0;38;2;122;112;112:*.ps1=0;38;2;0;255;135:*.out=0;38;2;122;112;112:*.sql=0;38;2;0;255;135:*.inc=0;38;2;0;255;135:*.sty=0;38;2;122;112;112:*.elm=0;38;2;0;255;135:*.dmg=4;38;2;249;38;114:*.aif=0;38;2;253;151;31:*.h++=0;38;2;0;255;135:*.fsx=0;38;2;0;255;135:*.ico=0;38;2;253;151;31:*.flv=0;38;2;253;151;31:*.swf=0;38;2;253;151;31:*.docx=0;38;2;230;219;116:*.yaml=0;38;2;166;226;46:*.pptx=0;38;2;230;219;116:*.flac=0;38;2;253;151;31:*.rlib=0;38;2;122;112;112:*.purs=0;38;2;0;255;135:*.opus=0;38;2;253;151;31:*.epub=0;38;2;230;219;116:*.json=0;38;2;166;226;46:*.bash=0;38;2;0;255;135:*.hgrc=0;38;2;166;226;46:*.tiff=0;38;2;253;151;31:*.java=0;38;2;0;255;135:*.xlsx=0;38;2;230;219;116:*.less=0;38;2;0;255;135:*.dart=0;38;2;0;255;135:*.webm=0;38;2;253;151;31:*.lock=0;38;2;122;112;112:*.html=0;38;2;226;209;57:*.mpeg=0;38;2;253;151;31:*.psm1=0;38;2;0;255;135:*.conf=0;38;2;166;226;46:*.psd1=0;38;2;0;255;135:*.diff=0;38;2;0;255;135:*.h264=0;38;2;253;151;31:*.make=0;38;2;166;226;46:*.toml=0;38;2;166;226;46:*.lisp=0;38;2;0;255;135:*.fish=0;38;2;0;255;135:*.tbz2=4;38;2;249;38;114:*.orig=0;38;2;122;112;112:*.jpeg=0;38;2;253;151;31:*.mdown=0;38;2;226;209;57:*.cmake=0;38;2;166;226;46:*.swift=0;38;2;0;255;135:*.xhtml=0;38;2;226;209;57:*.dyn_o=0;38;2;122;112;112:*.class=0;38;2;122;112;112:*.cabal=0;38;2;0;255;135:*passwd=0;38;2;166;226;46:*README=0;38;2;0;0;0;48;2;230;219;116:*.toast=4;38;2;249;38;114:*shadow=0;38;2;166;226;46:*.shtml=0;38;2;226;209;57:*.patch=0;38;2;0;255;135:*.scala=0;38;2;0;255;135:*.cache=0;38;2;122;112;112:*.ipynb=0;38;2;0;255;135:*TODO.md=1:*.groovy=0;38;2;0;255;135:*INSTALL=0;38;2;0;0;0;48;2;230;219;116:*.gradle=0;38;2;0;255;135:*.matlab=0;38;2;0;255;135:*.config=0;38;2;166;226;46:*.dyn_hi=0;38;2;122;112;112:*LICENSE=0;38;2;182;182;182:*.flake8=0;38;2;166;226;46:*.ignore=0;38;2;166;226;46:*COPYING=0;38;2;182;182;182:*setup.py=0;38;2;166;226;46:*TODO.txt=1:*Makefile=0;38;2;166;226;46:*.desktop=0;38;2;166;226;46:*Doxyfile=0;38;2;166;226;46:*.gemspec=0;38;2;166;226;46:*.rgignore=0;38;2;166;226;46:*README.md=0;38;2;0;0;0;48;2;230;219;116:*.fdignore=0;38;2;166;226;46:*.markdown=0;38;2;226;209;57:*.cmake.in=0;38;2;166;226;46:*configure=0;38;2;166;226;46:*.kdevelop=0;38;2;166;226;46:*.DS_Store=0;38;2;122;112;112:*COPYRIGHT=0;38;2;182;182;182:*.gitignore=0;38;2;166;226;46:*.scons_opt=0;38;2;122;112;112:*CODEOWNERS=0;38;2;166;226;46:*SConscript=0;38;2;166;226;46:*Dockerfile=0;38;2;166;226;46:*INSTALL.md=0;38;2;0;0;0;48;2;230;219;116:*SConstruct=0;38;2;166;226;46:*README.txt=0;38;2;0;0;0;48;2;230;219;116:*.gitconfig=0;38;2;166;226;46:*.localized=0;38;2;122;112;112:*.gitmodules=0;38;2;166;226;46:*Makefile.am=0;38;2;166;226;46:*.synctex.gz=0;38;2;122;112;112:*INSTALL.txt=0;38;2;0;0;0;48;2;230;219;116:*Makefile.in=0;38;2;122;112;112:*.travis.yml=0;38;2;230;219;116:*MANIFEST.in=0;38;2;166;226;46:*LICENSE-MIT=0;38;2;182;182;182:*appveyor.yml=0;38;2;230;219;116:*configure.ac=0;38;2;166;226;46:*.applescript=0;38;2;0;255;135:*.fdb_latexmk=0;38;2;122;112;112:*CONTRIBUTORS=0;38;2;0;0;0;48;2;230;219;116:*.clang-format=0;38;2;166;226;46:*.gitattributes=0;38;2;166;226;46:*CMakeCache.txt=0;38;2;122;112;112:*CMakeLists.txt=0;38;2;166;226;46:*LICENSE-APACHE=0;38;2;182;182;182:*CONTRIBUTORS.md=0;38;2;0;0;0;48;2;230;219;116:*requirements.txt=0;38;2;166;226;46:*CONTRIBUTORS.txt=0;38;2;0;0;0;48;2;230;219;116:*.sconsign.dblite=0;38;2;122;112;112:*package-lock.json=0;38;2;122;112;112:*.CFUserTextEncoding=0;38;2;122;112;112"' >> ~/.zshrc
    echo "alias ll='ls -al'" >> ~/.zshrc

    # .vimrc
    # https://unix.stackexchange.com/questions/88879/better-colors-so-comments-arent-dark-blue-in-vim
    echo 'set number
    set encoding=utf-8
    set t_Co=256
    set background=dark
    let g:solarized_termcolors=256
    let g:solarized_termtrans=1' >> ~/.vimrc

    # 重新載入zsh設定檔
    source ~/.zshrc

    # 進行樣式選擇

基本概念

  • Dockerfile

    用來定義如何構建 Image 的文件。包含一系列指令,指定基礎 Image、需要安裝的套件、複製文件、設置環境變量等。

  • Image(映像檔)

    一個唯讀的模板,可以用來建立 Docker Container。
    例如:一個 Image 可以包含一個完整的 ubuntu 作業系統環境,裡面僅安裝了 Apache 或使用者需要的其它應用程式。

  • Container(容器)

    Container 是從 Image 建立的執行實例。它可以被啟動、開始、停止、刪除。每個 Container 都是相互隔離的、保證安全的平台。
    可以把 Container 看做是一個簡易版的 Linux 環境(包括 root 使用者權限、程式空間、使用者空間和網路空間等)和在其中執行的應用程式。

  • Docker Hub

    Docker 的公開映像倉庫,可直接下載已建置好的 Image。

  • Docker Compose

    Docker Compose 是一個工具,用於定義和運行多容器的 Docker 應用程序,可通過 YAML 文件來配置應用服務,然後使用單個命令來創建和啟動所有服務。

常用指令

1
2
3
4
5
6
7
8
9
10
11
12
13
# 停止所有Container
docker stop $(docker ps -aq)
# 刪除所有Container
docker rm $(docker ps -aq)
# 刪除所有image
docker rmi $(docker images -q)
# 刪除所有的volume
docker volume rm $(docker volume ls -q)

# 啟動docker-compose
docker-compose up -d
# 終止docker-compose
docker-compose down

動手製作 Dockerfile

  • Step1

    第一步就是先跑一台 Linux 出來

    1
    2
    3
    cd ~ && mkdir DockerTutorial && cd DockerTutorial # 建立資料夾
    touch Dockerfile # 建立檔案
    code . # 開啟VSCode
    1
    2
    3
    4
    5
    6
    7
    # 第一版

    # 基底 Image
    FROM ubuntu

    # 容器啟動後執行的命令
    CMD ["tail", "-f", "/dev/null"]

    建置 Image,並建立Container

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 建立Image
    docker build -t my-image-1 .
    # 查看Image
    docker image list

    #建立 container
    docker run -d --name my-container-1 my-image-1
    #查看 container
    docker container list

    此時已經成功把 Linux 跑起來了,連進去這台 Linux 看看

    1
    docker exec -it my-container /bin/bash
  • Step2

    目標是用Docker跑一個Node Express起來

    網路上找如何在 Linux 上安裝 Express 的教學,實際在這台 Linux 裡面試試看

    1
    2
    3
    4
    5
    6
    7
    8
    9
    DEBIAN_FRONTEND=noninteractive
    apt-get update -y
    #需要比較久,請稍等
    apt-get install nodejs npm vim -y
    mkdir app
    cd app
    npm init -y
    npm install express
    vim index.js

    把以下內容貼上 index.js(儲存離開 :wq)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const express = require('express')
    const app = express()
    const port = 3000

    app.get('/', (req, res) => {
    res.send('Hello World!')
    })

    app.listen(port, () => {
    console.log(`Example app listening at http://localhost:${port}`)
    })

    執行

    1
    node index.js

    以上看起來是成功了,接著把剛剛的步驟寫成 Dockerfile

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    # 第二版

    # 基底 Image
    FROM ubuntu

    ENV DEBIAN_FRONTEND=noninteractive

    # 安裝套件
    RUN apt-get update -y \
    && apt-get install nodejs npm -y

    WORKDIR app

    RUN npm init -y \
    && npm install express

    # 把編輯好的index.js放在跟Dockerfile同資料夾下
    ADD app/index.js .

    # 開放對外的 Port
    EXPOSE 3000

    # 容器啟動後執行的命令
    CMD ["node", "index.js"]

    建置 Image,並建立Container

    1
    2
    docker build -t my-image-2 .
    docker run -d -p 3000:3000 --name my-container-2 my-image-2

    瀏覽器查看 http://localhost:3000,成功得到回應

    • 如何瀏覽Http網址

      chrome://net-internals/#hsts

  • 練習:

    實際操作,並嘗試縮減建置出來的 Image 大小

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # 第三版

    # 基底 Image
    FROM node:alpine

    WORKDIR app

    RUN npm init -y \
    && npm install express

    ADD app/index.js .

    # 開放對外的 Port
    EXPOSE 3000

    # 容器啟動後執行的命令
    CMD ["node", "index.js"]

動手製作 docker-compose.yml (帶實作)

以上是只有一個 Container 的狀況,用指令操作還可以接受。但通常一個應用系統會需要多個 Container,每個 Container 要跑起來都要打一串指令,加一堆參數,誰受的了。

所以我們需要 docker-compose,可以用單一文件設定管理多個 Container。甚至我建議不管幾個 Container,都直接寫成 docker-compose!

  • Step4

    將資料夾結構調整成

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # 第四版

    # 基底 Image
    FROM node:alpine

    WORKDIR app

    # 開放對外的 Port
    EXPOSE 3000

    # 容器啟動後執行的命令
    CMD ["tail", "-f", "/dev/null"]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    version: '3'

    services:
    express:
    build: ./express
    container_name: ${APP_NAME}_express
    ports:
    - "3000:3000"
    entrypoint: npm run start
    volumes:
    - ./express/app:/app
    1
    APP_NAME=MyAPP
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    {
    "name": "test",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
    "start": "npm install && nodemon index.js"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "dependencies": {
    "express": "^4.19.2",
    "nodemon": "^3.1.2"
    }
    }

    然後一個指令就能建置 Image,並把 Container 跑起來

    1
    docker-compose up

    同樣一個指令就能把所有的 Container 停掉

    1
    docker-compose down

    以下說明所有的更動

    1. Dockerfile 一般來說不需自己從頭開始撰寫所有步驟,可以到 DockerHub 找別人已經包好的 Image,尤其是官方的 Image 優先使用。

    本 Container 只需要 nodejs 執行環境,所以從 DockerHub 找 node 的官方 Image,使用 alpine 版本是因為它是輕量的 Linux 發行版。

    另外把 npm install 跟 複製 index.js 拿掉,讓這個 Image 只是單純的 node 執行環境。
    2. docker-compose.yml 檔案用來描述所有的服務與設定。
    - 指定服務名稱,container名稱
    - 可讀取.env的變數內容
    - entrypoint是容器跑起來後要執行的指令,也就是程式進入點,這邊的設定會覆寫Dockerfile中的CMD設定
    - volume是把本機的路徑映射到容器中,這樣程式碼的部分可以不用打包到Image裡面,而且容器被刪掉的話,資料也可以持續保存在本機

  • Step5

    加入資料庫,這邊使用Postgres

    1
    2
    # 先建立postgres的資料夾
    mkdir -p postgres/data
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    services:
    express:
    ...
    postgres:
    image: postgres
    container_name: ${APP_NAME}_postgres
    restart: always
    user: "1000" # WSL Only
    ports:
    - "5442:5432"
    volumes:
    - ./postgres/data:/var/lib/postgresql/data
    environment:
    POSTGRES_USER: ${DB_USERNAME}
    POSTGRES_PASSWORD: ${DB_PASSWORD}
    POSTGRES_DB: ${DB_DATABASE}
  • Step6

    加入資料庫管理介面工具,pgAdmin,這樣就能連線進去新增資料表與資料。

    1
    2
    # 先建立pgadmin的資料夾
    mkdir pgadmin
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    services:
    express:
    ...
    postgres:
    ...
    pgadmin:
    image: dpage/pgadmin4
    container_name: ${APP_NAME}_pgadmin
    restart: "always"
    user: root
    environment:
    PGADMIN_DEFAULT_EMAIL: ${PGADMIN_USERNAME}
    PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD}
    volumes:
    - ./pgadmin:/var/lib/pgadmin
    ports:
    - "5050:80"
    depends_on:
    - postgres
    • pgadmin相依(depends_on)於postgres,這樣啟動container時,會在postgres成功啟動後,才會接續啟動pgadmin
    • 當沒有指定network時,container會預設使用default的網路,drive是bridge,而postgres預設expose是5432port,所以pgadmin可以直接連得到
    1
    2
    docker network ls
    docker network inspect [NETWORK_NAME]
    • ports跟expose的區別
  • Step7

    設定express連線postgres,讀取資料顯示出來。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    services:
    express:
    ...
    depends_on:
    - postgres
    environment:
    - NODE_ENV=${NODE_ENV}
    - DB_USERNAME=${DB_USERNAME}
    - DB_PASSWORD=${DB_PASSWORD}
    - DB_DATABASE=${DB_DATABASE}
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    require('dotenv').config();
    const { Pool } = require('pg');

    const pool = new Pool({
    user: process.env.DB_USERNAME,
    password: process.env.DB_PASSWORD,
    host: 'postgres',
    port: 5432, // default Postgres port
    database: process.env.DB_DATABASE
    });

    module.exports = {
    query: (text, params) => pool.query(text, params)
    };
    • db.js 是 node連結資料庫的方式,注意 host: postgres,這邊無法直接填ip,因為服務不會知道其他服務的ip,而是要直接填服務名稱!
    • 資料庫連線字串參數可用environment帶入container中,這樣就能在最上層的.env統一管理環境變數
  • Step9

    雖然可以用預設的default network很方便,但有時會想隔離container或做更細節的設定。

    Docker可以用network來描述網路模型,network有許多驅動模式,目前先使用bridge模式。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    services:
    express:
    ...
    networks:
    - app-network
    postgres:
    ...
    networks:
    - app-network

    networks:
    app-network:
    driver: bridge

    將container指定要使用的network,同樣network之間就可以互相連結得到。

    1
    2
    3
    docker network ls

    docker network inspect [NetworkName]
  • 練習

    延伸Step9,新開一台資料庫服務,使網頁同時讀取兩個ㄌ藥庫的資料,但兩個資料庫服務彼此是隔離的。

  • Step10

    1
    2
    3
    4
    5
    6
    7
    docker-compose up
    docker-compose up -d

    sudo ls -al /var/lib/docker/containers
    sudo cat /var/lib/docker/containers/[CONTAINER_ID]/[CONTAINER_ID]-json.log

    docker-compose logs express
  • Step13

    docker-compose.yml 檔案可以切分成

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    services:

    express:
    build: ./express
    container_name: ${APP_NAME}_express
    # ports: defined in [environment].yml
    # entrypoint: defined in [environment].yml
    volumes:
    - ./express/app:/app
    depends_on:
    - postgres
    networks:
    - app-network
    1
    2
    3
    4
    5
    6
    7
    services:

    express:
    ports:
    - "3000:3000"
    - "9229:9229"
    entrypoint: sh -c "npm install && npm run debug"
    1
    2
    3
    4
    5
    6
    services:

    express:
    ports:
    - "80:3000"
    entrypoint: sh -c "npm install && npm run start"

    這樣就能依環境切換不同的設定檔

    1
    2
    3
    4
    5
    6
    # 開發環境
    # 預設都不指定-f的話,就會抓docker-compose.yml跟docker-compose.override.yml
    docker-compose up

    # 正式環境
    docker-compose -f docker-compose.yml -f docker-compose.production.yml up

常用連結

疑難排解

1
2
3
4
5
6
7
8
9
10
# Installing, this may take a few minutes...
# WslRegisterDistribution failed with error: 0x800701bc
# Error: 0x800701bc WSL 2 ???????????????????? visit https://aka.ms/wsl2kernel
請參考這篇的解法
https://blog.darkthread.net/blog/wsl2-gui/

# docker: Error response from daemon: driver failed programming external connectivity on endpoint test-nginx (8c9ad828c53e7b9be16d44bb032b7dab46c9fea745b1549c64e03374e967cfaa): (iptables failed: iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --dport 8099 -j DNAT --to-destination 172.17.0.2:80 ! -i docker0: iptables: No chain/target/match by that name. (exit status 1)).
sudo iptables -t filter -F
sudo iptables -t filter -X
sudo systemctl restart docker

PostmanAPI 同步機制

Postman 是很好用的 HttpRequest 工具,個人使用沒有限制,但它的多人協作方案(Team,Business,Enterprise)是用 user/month 計費…太貴了…$_$

貧窮限制了我們的生產力,只好寫更多 Code 來彌補了!

此同步機制,使用 Postman API + Nodejs + Git 達成近似雲端協作的效果


Prerequisites

  1. git clone

  2. 安裝 Postman 應用程式

  3. 登入 Postman 帳號

Getting Started

1. 取得API Key

  • 打開Postman應用程式 –> UserProfile Icon –> Account Settings

  • Postman API keys –> Generate API Key

  • 輸入任意識別名稱

  • 產生成功,把 Key 複製起來備用

2. 安裝與設定

以下指令與步驟都是在PostmanAPI資料夾下進行

  • 安裝相依套件

    1
    npm install
  • .env.example 複製並更名為 .env

    1
    cp .env.example .env
  • 把Step1中取得的API Key貼到 .env

    1
    2
    POSTMAN_APIKey=貼上你的APIKey
    TEAM_WORKSPACE_NAME=Team LinkChain

How to Use

  • 由檔案匯入至 Postman

    1
    npm run import
  • Postman 匯出至檔案

    1
    npm run export
  • Git 同步

    1
    2
    3
    4
    5
    git pull # 提取
    .
    .
    .
    git push # 推送
  • 同步的Workspace : Team LinkChain


Use Cases

  1. 第一次使用

    1
    npm run import # 由檔案匯入至Postman
  2. 之前已經匯入過,同事通知有新的API內容

    1
    git pull # 提取
    1
    npm run import # 由檔案匯入至Postman
  3. 你修改了一些API內容,想傳送給其他同事

    1
    npm run export # 匯出Postman至檔案
    1
    2
    git add .
    git commit -m "提交內容描述"
    1
    2
    3
    4
    5
    git pull # 提取
    #
    # 若有衝突則先行解決
    #
    git push # 推送

Branch Strategy

  • master : 資料同步

  • develop : 核心程式開發

  • 其他功能性分支使用 git flow


Price and Limit

透過 Postman API 存取資源,每分鐘不可超過 60 次Request,且每個月不可超過 1000 次Request,因此要省點用XD。

x : Collection數量

y : Environment數量

每次執行匯入或匯出指令, API Request 使用量為:

1
2 + x + y

目標是盡量降低 x 與 y ,建議每個專案的API就放在一個Collection裡面,Environment就固定使用四個。


References

https://www.postman.com/postman/workspace/postman-public-workspace

K6 Introduction

  • 優點:

    1. Integrable 可整合:可整合至 CI / CD 流程內,以及測試結果可發送至像 Grafana 這類的外部儀表板系統內。
    2. Scriptable 可制定腳本:可以用腳本語言撰寫測試行為,才能夠更真實的模擬用戶行為。
    3. Able to be a service 提供服務:除了基礎的 CLI 程式外,最好還能有額外的測試服務,才能夠在未來日益加重的測試需求時,能夠用 load testing as a service 的模式做測試,而不用自行建立測試機台。
    4. Well-documented 良好的文件:圖文並茂而不冗長的文件,而不是只有 CLI 的說明頁或那冗長的 man page。
    5. Actively maintained 有持續維護更新:有更新才有可能支援較新的標準,例如 HTTP/2、HTTP/3、WebSocket、GraphQL、TLS 1.3 等。
    6. Modern CLI design 現代化:最好有 subcommand 把子功能分門別類,並且 subcommand / option / parameter / argument 的命名具有意義,不要是不知所謂的簡寫,像 Tar 這種老式工具沒有 subcommand 的概念,tar --help 一下就噴好幾頁的說明是不及格的。
    7. No runtime 不需要 runtime:不要有 runtime 或其它系統套件依賴,例如 JDK / JRE / .NET / Microsoft C++ Redistrubutable 這些 runtime 都只增加了配置環境時的複雜度,另一方面,用 Docker 容器方案當然也是增加配置複雜度的兇手之一。
  • VUs:虛擬用戶數量

    在K6中,VUs(虛擬用戶)是一個重要的概念,用於模擬同時訪問您的應用程序的虛擬用戶數量。這些虛擬用戶實際上是K6測試腳本中定義的JavaScript代碼,它們模擬真實用戶對您的應用程序的行為。以下是有關VUs的一些解釋:

    1. 虛擬用戶數量(VUs):VUs表示在測試過程中同時模擬的虛擬用戶數量。每個虛擬用戶都可以執行測試腳本中定義的操作,例如發送HTTP請求或執行其他操作。
    2. 并行性:VUs允許您模擬多個用戶同時訪問應用程序。通過增加VUs的數量,您可以增加測試的並行性,從而測試應用程序的性能和可擴展性。
    3. 延遲和並發:每個虛擬用戶之間可能存在隨機的延遲,以更好地模擬真實用戶的行為。這有助於確保測試更真實且更有意義。
    4. 定義VUs:在K6測試腳本中,您可以通過使用**VU**對象來定義虛擬用戶的行為。您可以指定虛擬用戶應執行的操作,以及其行為的規則。
    5. 監控和報告:K6允許您實時監控每個虛擬用戶的性能,並生成詳細的測試報告,以便評估應用程序的性能。

    總之,虛擬用戶數量(VUs)是K6中用來模擬並評估應用程序性能的重要概念。通過調整VUs的數量和定義虛擬用戶的行為,您可以進行不同類型的性能測試,並識別應用程序的性能瓶頸。

  • Iteration Duration:迭代持續時間

    通常是性能測試報告中的一個重要指標之一。它表示在測試過程中,每個迭代或事務所花費的時間。這個指標有助於評估應用程序的性能和效能,特別是在多次重複操作或事務的情況下。

    解釋Iteration Duration的意思如下:

    1. 一個迭代通常代表測試中的一個操作或事務,例如向應用程序發送一個HTTP請求。
    2. Iteration Duration表示這個操作或事務的完成時間,通常以毫秒(ms)為單位。
    3. 迭代持續時間的平均值可以用來評估應用程序的響應時間。較短的平均迭代持續時間通常表示較好的性能。
    4. 通過追蹤迭代持續時間的變化,您可以檢測性能問題,例如在某些情況下迭代持續時間明顯增加,這可能表示性能瓶頸或延遲。
    5. 迭代持續時間也可用於評估應用程序的可擴展性。當您增加負載時,迭代持續時間是否保持在合理的範圍內,或者隨著負載的增加而急劇增長?

    總之,Iteration Duration是一個重要的性能測試指標,它幫助您了解應用程序的性能,識別性能問題,並評估其可擴展性。較短的迭代持續時間通常是理想的,但具體的閾值可能因應用程序的要求而有所不同。

  • http_req_blocked:HTTP請求被阻止的次數

    在K6性能測試框架中,http_req_blocked 是一個性能測試指標,它表示HTTP請求被阻止的次數。這個指標的意義如下:

    1. HTTP請求阻止:http_req_blocked 計算了在測試過程中因各種原因而被阻止的HTTP請求的次數。這些原因可能包括網絡延遲、伺服器回應時間過長、TCP連接問題等。
    2. 阻塞次數:http_req_blocked 通常以整數值表示,該值代表在測試過程中發生的阻塞請求的次數。
    3. 性能問題檢測:當 http_req_blocked 值較高時,這可能表示您的應用程序在處理HTTP請求時遇到了性能問題或瓶頸。這些阻塞可能會導致用戶體驗不佳,因為用戶的請求無法得到及時處理。
    4. 診斷和優化:監控和記錄 http_req_blocked 可以幫助您識別應用程序的性能問題,並采取措施來優化它,例如改進伺服器的回應時間、增加伺服器容量或者緩解網絡延遲。

    總之,http_req_blocked 是K6中用於測試HTTP請求性能的一個指標,它有助於監視和評估應用程序的性能,特別是在處理大量並發請求的情況下。高 http_req_blocked 值可能需要進一步的調查和優化,以確保應用程序的穩定性和性能。

  • http_req_connecting:HTTP請求建立連接的時間

    在K6性能測試框架中,http_req_connecting 是一個性能測試指標,它表示HTTP請求建立連接的時間。這個指標的意義如下:

    1. HTTP請求連接時間:http_req_connecting 指標記錄了在發出HTTP請求後,建立到目標伺服器的連接所花費的時間。這包括DNS解析、TCP連接建立和SSL/TLS握手等過程。
    2. 連接時間統計:http_req_connecting 通常提供了有關HTTP請求建立連接時間的統計信息,例如平均連接時間、最小連接時間、最大連接時間等。
    3. 性能分析:監控 http_req_connecting 指標有助於評估應用程序的性能,特別是在處理多個並發HTTP請求的情況下。較長的連接時間可能會影響用戶體驗,因為用戶的請求需要更長的時間才能建立連接,從而導致較長的等待時間。
    4. 優化建議:當 http_req_connecting 指標顯示連接時間過長時,您可能需要優化伺服器的設置、網絡配置或者使用較快的硬件資源,以減少連接時間,從而改善應用程序的性能。

    總之,http_req_connecting 是K6中用於監控和評估HTTP請求連接時間的一個指標,它有助於識別應用程序性能中的潛在瓶頸,並提供有關請求建立連接時間的信息,以便優化應用程序的性能。

  • http_req_duration:HTTP請求的總持續時間

    在K6性能測試框架中,http_req_duration 是一個重要的性能測試指標,它表示一個HTTP請求的總持續時間。這個指標包括了從請求開始到收到回應完成的整個時間範圍。以下是對 http_req_duration 指標的解釋:

    1. HTTP請求持續時間:http_req_duration 記錄了每個HTTP請求的總時間,通常以毫秒(ms)為單位。這個時間包括了發送請求、等待回應、接收回應等所有與請求-回應週期相關的時間。
    2. 性能分析:監控 http_req_duration 指標有助於評估應用程序的性能,特別是在模擬多個並發用戶或客戶端對應用程序進行訪問時。較短的請求持續時間通常表示更快的回應時間,有助於提供更好的用戶體驗。
    3. 統計信息:http_req_duration 通常提供了一系列統計信息,如平均請求持續時間、最小請求持續時間、最大請求持續時間等。這些統計信息可以幫助您了解請求回應時間的分佈情況。
    4. 性能問題診斷:當 http_req_duration 值較長或波動較大時,這可能表明應用程序的性能存在問題。您可以使用這個指標來定位性能瓶頸、優化應用程序的回應時間、改進伺服器性能等。
    5. 優化建議:http_req_duration 可以指導性能優化工作。通過縮短請求持續時間,您可以提高應用程序的回應速度,減少用戶等待時間,從而改善用戶體驗。

    總之,http_req_duration 是K6中用於監測和評估HTTP請求性能的關鍵指標,它提供了有關請求-回應週期的時間信息,幫助您識別潛在的性能問題並進行性能優化。短而穩定的請求持續時間通常是良好性能的指標。

  • http_req_receiving:接收HTTP請求回應的時間

    在K6性能測試框架中,http_req_receiving 是一個性能測試指標,它表示接收HTTP請求回應的時間。這個指標包括了從伺服器開始發送回應數據到客戶端接收完整回應的整個時間範圍。以下是對 http_req_receiving 指標的解釋:

    1. HTTP請求接收時間:http_req_receiving 記錄了每個HTTP請求的回應接收總時間,通常以毫秒(ms)為單位。這個時間包括了伺服器發送回應數據、客戶端接收回應數據以及可能的處理時間。
    2. 性能分析:監控 http_req_receiving 指標有助於評估應用程序的性能,特別是在模擬多個並發用戶或客戶端對應用程序進行訪問時。較短的回應接收時間通常表示更快的回應速度,有助於提供更好的用戶體驗。
    3. 統計信息:http_req_receiving 通常提供了一系列統計信息,如平均回應接收時間、最小回應接收時間、最大回應接收時間等。這些統計信息可以幫助您了解回應接收時間的分佈情況。
    4. 性能問題診斷:當 http_req_receiving 值較長或波動較大時,這可能表明應用程序的性能存在問題。您可以使用這個指標來定位性能瓶頸、優化應用程序的回應時間、改進伺服器性能等。
    5. 優化建議:http_req_receiving 可以指導性能優化工作。通過縮短回應接收時間,您可以提高應用程序的回應速度,減少用戶等待時間,從而改善用戶體驗。

    總之,http_req_receiving 是K6中用於監測和評估HTTP請求回應接收性能的關鍵指標,它提供了有關回應接收時間的信息,幫助您識別潛在的性能問題並進行性能優化。短而穩定的回應接收時間通常是良好性能的指標。

  • http_req_sending:發送 HTTP 請求的時間

    在 K6 性能測試框架中,http_req_sending 是一個性能測試指標,表示發送 HTTP 請求的時間。這個指標用於衡量從測試腳本發出 HTTP 請求到請求完全發送給目標伺服器所花費的時間。以下是對 http_req_sending 指標的解釋:

    HTTP 請求發送時間:http_req_sending 記錄了每個 HTTP 請求的發送時間,通常以毫秒(ms)為單位。它代表了將請求數據從測試腳本發送到目標伺服器的時間。

    性能分析:監測 http_req_sending 指標有助於評估應用程序的性能,特別是在模擬多個並發用戶或客戶端對應用程序進行訪問時。這個指標可以幫助您了解請求發送的效率和速度,以及應用程序的性能如何。

    統計信息:http_req_sending 通常提供了一系列統計信息,如平均請求發送時間、最小請求發送時間、最大請求發送時間等。這些統計信息可以幫助您了解請求發送時間的分佈情況。

    性能問題診斷:當 http_req_sending 值較長或波動較大時,這可能表明在請求發送階段存在性能問題,可能需要優化請求發送的相關過程,以提高性能。

    總之,http_req_sending 是 K6 中用於監測和評估 HTTP 請求發送性能的重要指標,它提供了有關請求發送時間的信息,有助於識別應用程序性能中的潛在問題,並提供有關請求發送效率的洞察。短而穩定的請求發送時間通常是良好性能的指標。

  • http_req_tls_handshaking:執行 TLS 握手的時間

    在 K6 性能測試框架中,http_req_tls_handshaking 是一個性能測試指標,表示執行 TLS 握手的時間。TLS(Transport Layer Security)是一種安全協議,用於加密和保護數據在客戶端和伺服器之間的傳輸。http_req_tls_handshaking 指標記錄了從發送 TLS 安全連接請求到建立 TLS 握手所花費的時間。以下是對 http_req_tls_handshaking 指標的解釋:

    1. TLS 握手時間:http_req_tls_handshaking 指標表示執行 TLS 握手的時間,通常以毫秒(ms)為單位。這包括了與伺服器建立安全連接所需的握手協議的執行時間。
    2. 安全通信:TLS 握手是為了確保數據在傳輸過程中的機密性和完整性。它通常包括客戶端向伺服器發送加密請求、伺服器回應並建立加密通道等步驟。
    3. 性能分析:監控 http_req_tls_handshaking 指標有助於評估應用程序的性能,特別是在模擬多個並發用戶或客戶端對應用程序進行訪問時。較長的 TLS 握手時間可能會導致請求的延遲,從而影響用戶體驗。
    4. 統計信息:http_req_tls_handshaking 通常提供一系列統計信息,如平均 TLS 握手時間、最小和最大 TLS 握手時間等,以便更好地了解 TLS 握手時間的分佈情況。
    5. 性能問題診斷:當 http_req_tls_handshaking 值較長時,可能需要優化 TLS 握手過程,以減少它對性能的潛在影響。

    總之,http_req_tls_handshaking 是 K6 中用於監測和評估執行 TLS 握手的性能的指標。TLS 握手時間的快慢會影響應用程序的性能和用戶體驗。較短而穩定的 TLS 握手時間通常是理想的。

  • http_req_waiting:等待 HTTP 請求回應的時間

    在 K6 性能測試框架中,http_req_waiting 是一個性能測試指標,表示等待 HTTP 請求回應的時間。這個指標包括了從發送請求到接收伺服器回應之間的等待時間,即等待伺服器處理請求並返回回應的時間。以下是對 http_req_waiting 指標的解釋:

    1. HTTP 請求等待時間:http_req_waiting 指標記錄了每個 HTTP 請求的等待時間,通常以毫秒(ms)為單位。它代表了在發送請求後,等待伺服器處理請求並返回回應之間的時間。
    2. 性能分析:監控 http_req_waiting 指標有助於評估應用程序的性能,特別是在模擬多個並發用戶或客戶端對應用程序進行訪問時。較短的等待時間通常表示更快的回應速度,有助於提供更好的用戶體驗。
    3. 統計信息:http_req_waiting 通常提供了一系列統計信息,如平均等待時間、最小等待時間、最大等待時間等。這些統計信息可以幫助您了解等待時間的分佈情況。
    4. 性能問題診斷:當 http_req_waiting 值較長或波動較大時,這可能表明應用程序的性能存在問題,可能需要優化伺服器的處理能力、減少請求排隊時間等來改進性能。

    總之,http_req_waiting 是 K6 中用於監測和評估等待 HTTP 請求回應時間的關鍵指標,它提供了關於等待伺服器處理請求的時間的信息,有助於識別潛在的性能問題並進行性能優化。較短而穩定的等待時間通常有助於提供更好的用戶體驗。

  • 統計指標:

    • avg:平均值

      這個指標表示所有樣本數據的平均值。在性能測試中,通常用來表示請求的平均響應時間。較低的平均響應時間通常表示更好的性能。

    • max:最大值

      此指標表示樣本數據中的最大值。在性能測試中,它代表了請求的最長響應時間。這個指標用於識別性能測試中的最壞情況。

    • med:中位數

      中位數是樣本數據排序后位於中間位置的值。在性能測試中,它代表中間響應時間,用於了解響應時間的分佈情況。

    • min:最小值

      此指標表示樣本數據中的最小值。在性能測試中,通常用來表示請求的最短響應時間。較低的最小響應時間通常表示更好的性能。

    • p90:百分位数90

      表示在數據中有90%的樣本值小於或等於這個值。通常在性能測試中,它用於捕捉較長響應時間的一部分情況,以更好地了解性能的穩定性。

    • p95:百分位数95

      表示在數據中有95%的樣本值小於或等於這個值。與 p90 類似,它用於捕捉較長響應時間的一部分情況。

    • p99:百分位数99

      表示在數據中有99%的樣本值小於或等於這個值。通常用於捕捉極端情況下的響應時間,以更好地了解性能的可靠性。

滿滿的AI感XD。這一篇是當初想在公司導入K6,用來取代VisualStudio的Web效能和負載測試。所以寫了一個Demo範例,再搭配上這篇AI文簡單說明各個指標的意思。最後總算是順利導入了,擺脫VisualStudio2019就是爽!

自從經歷了公司直接把雙週會分享刪掉的事件(是有復原啦),就覺得要留個保險。是時候來試試 Hexo

簡報是一直習慣寫 Markdown,還為了在公司報告,研究了一個 VSCode 套件 Markdown PDF。所以轉換到用 Markdown 產生靜態網站的網誌系統應該不是難事。

開始吧,Hello Hexo!

0%