vault backup: 2025-07-22 22:14:08
Affected files: Too many files to list
This commit is contained in:
22
21.01. OS/21.01. Linux/00. 重灌基本步驟.md
Normal file
22
21.01. OS/21.01. Linux/00. 重灌基本步驟.md
Normal file
@@ -0,0 +1,22 @@
|
||||
```bash
|
||||
sudo apt update; sudo apt install -y cifs-utils lm-sensors
|
||||
```
|
||||
|
||||
1. 安裝必須的套件
|
||||
2. 修正時區
|
||||
3. `mkdir ~/log`
|
||||
4. 掛載 smb
|
||||
5. 掛載 lvm
|
||||
6. 設定 journalctl size
|
||||
7. 設定 crontab
|
||||
9. 啟動所有 docker
|
||||
10. 掛載mod [[開機自動掛載模組(modprobe nct6683)]]
|
||||
11. 設定 `sudo sensors-detect`
|
||||
|
||||
```shell
|
||||
sudo apt update; sudo apt install -y cifs-utils lm-sensors
|
||||
sudo timedatectl set-timezone Asia/Taipei
|
||||
mkdir ~/log
|
||||
|
||||
|
||||
```
|
||||
172
21.01. OS/21.01. Linux/CLI/cut.md
Normal file
172
21.01. OS/21.01. Linux/CLI/cut.md
Normal file
@@ -0,0 +1,172 @@
|
||||
## cut
|
||||
Linux 的 `cut` 指令是一個實用的文字處理工具,可以將每一行文字的部份字元或欄位擷取出來,以下是使用方式與範例。
|
||||
|
||||
### 擷取字元
|
||||
|
||||
對於欄位寬度是固定的資料,可以使用擷取固定位置字元的方式,把指定的欄位抓出來,典型的例子就是從 `ls` 指令的輸出中擷取檔案權限。假設我們的 `ls` 指令與輸出資料如下:
|
||||
```bash
|
||||
# 僅輸出最後 5 筆檔案資訊
|
||||
ls -l | tail -n 5
|
||||
```
|
||||
|
||||
```
|
||||
drwxr-xr-x 2 gtwang gtwang 4096 11月 7 22:29 影片
|
||||
drwxr-xr-x 7 gtwang gtwang 4096 2月 6 21:01 文件
|
||||
drwxr-xr-x 4 gtwang gtwang 4096 2月 22 21:09 桌面
|
||||
drwxr-xr-x 2 gtwang gtwang 4096 1月 6 2017 模板
|
||||
drwxrwxr-x 2 gtwang gtwang 4096 1月 6 2017 音樂
|
||||
```
|
||||
|
||||
如果我們想要擷取第一欄中的檔案權限(也就是第 2 個字元到第 10 個字元),可以使用 `cut` 指令配合 `-c` 參數,將每一行的第 2 個字元至第 10 個字元抓出來:
|
||||
|
||||
```bash
|
||||
# 擷取第 2 個字元至第 10 個字元
|
||||
ls -l | tail -n 5 | cut -c 2-10
|
||||
```
|
||||
|
||||
Output:
|
||||
```
|
||||
rwxr-xr-x
|
||||
rwxr-xr-x
|
||||
rwxr-xr-x
|
||||
rwxr-xr-x
|
||||
rwxrwxr-x
|
||||
```
|
||||
|
||||
如果要擷取多個不連續的的區段,逗號分隔每個區段,例如:
|
||||
|
||||
```bash
|
||||
# 擷取第 2-3 個、第 5-6 個與第 8-9 個字元
|
||||
ls -l | tail -n 5 | cut -c 2-3,5-6,8-9
|
||||
```
|
||||
|
||||
Output:
|
||||
```
|
||||
rwr-r-
|
||||
rwr-r-
|
||||
rwr-r-
|
||||
rwr-r-
|
||||
rwrwr-
|
||||
```
|
||||
|
||||
### 排除字元
|
||||
|
||||
上面的範例中我們都是設定要擷取的部份,如果想要設定排除的部份,可以加上 `--complement` 這個補集參數,這樣 `cut` 就會將指定的部份刪除,留下剩餘的部份:
|
||||
|
||||
```bash
|
||||
# 排除第 2 個字元至第 10 個字元
|
||||
ls -l | tail -n 5 | cut -c 2-10 --complement
|
||||
```
|
||||
|
||||
Output:
|
||||
```
|
||||
d 2 gtwang gtwang 4096 11月 7 22:29 影片
|
||||
d 7 gtwang gtwang 4096 2月 6 21:01 文件
|
||||
d 4 gtwang gtwang 4096 2月 22 21:09 桌面
|
||||
d 2 gtwang gtwang 4096 1月 6 2017 模板
|
||||
d 2 gtwang gtwang 4096 1月 6 2017 音樂
|
||||
```
|
||||
|
||||
### 擷取欄位
|
||||
|
||||
若我們的資料欄位寬度不是固定的,而是使用特定的字元分隔不同的欄位,例如逗點分隔檔(csv 檔):
|
||||
```
|
||||
5.1,3.5,1.4,0.2,"setosa"
|
||||
4.9,3,1.4,0.2,"setosa"
|
||||
7,3.2,4.7,1.4,"versicolor"
|
||||
6.4,3.2,4.5,1.5,"versicolor"
|
||||
5.9,3,5.1,1.8,"virginica"
|
||||
```
|
||||
|
||||
若要擷取這個 csv 檔的特定欄位,可以使用 `cut` 指令加上 `-d` 參數指定欄位分隔字元,並以 `-f` 參數指定欲擷取的欄位,例如擷取出第 2 個欄位:
|
||||
|
||||
```bash
|
||||
# 擷取 CSV 檔的第二個欄位
|
||||
cut -d , -f 2 data.csv
|
||||
```
|
||||
|
||||
Output:
|
||||
```
|
||||
3.5
|
||||
3
|
||||
3.2
|
||||
3.2
|
||||
3
|
||||
```
|
||||
|
||||
若要擷取多個欄位,也是使用逗號分隔每個欄位:
|
||||
|
||||
```bash
|
||||
# 擷取 CSV 檔的第 1-3 個與第 5 個欄位
|
||||
cut -d , -f 1-3,5 data.csv
|
||||
```
|
||||
|
||||
```
|
||||
5.1,3.5,1.4,"setosa"
|
||||
4.9,3,1.4,"setosa"
|
||||
7,3.2,4.7,"versicolor"
|
||||
6.4,3.2,4.5,"versicolor"
|
||||
5.9,3,5.1,"virginica"
|
||||
```
|
||||
|
||||
Linux 中的 `/etc/passwd` 檔案內容是以冒號分隔欄位的,若要從中擷取特定的欄位,可以指定以冒號為分隔字元:
|
||||
|
||||
```bash
|
||||
# 擷取 /etc/passwd 的第 1 個與第 7 個欄位
|
||||
head -n 5 /etc/passwd | cut -d : -f 1,7
|
||||
```
|
||||
|
||||
```
|
||||
root:/bin/bash
|
||||
daemon:/usr/sbin/nologin
|
||||
bin:/usr/sbin/nologin
|
||||
sys:/usr/sbin/nologin
|
||||
sync:/bin/sync
|
||||
```
|
||||
|
||||
### 排除欄位
|
||||
|
||||
若要排除某些特定欄位,而留下其餘的欄位,同樣可以使用 `--complement` 參數:
|
||||
|
||||
```bash
|
||||
# 排除 CSV 檔的第二個欄位
|
||||
cut -d , -f 2 --complement data.csv
|
||||
```
|
||||
|
||||
```
|
||||
5.1,1.4,0.2,"setosa"
|
||||
4.9,1.4,0.2,"setosa"
|
||||
7,4.7,1.4,"versicolor"
|
||||
6.4,4.5,1.5,"versicolor"
|
||||
5.9,5.1,1.8,"virginica"
|
||||
```
|
||||
|
||||
### 輸出分隔字元
|
||||
`cut` 在輸出多欄位的資料時,預設會以輸入檔案所使用的分隔字元來分隔輸出的欄位,若要改變輸出欄位的分隔字元,可以使用 `--output-delimiter` 參數來指定:
|
||||
|
||||
```bash
|
||||
# 指定輸出欄位分隔字元
|
||||
head -n 5 /etc/passwd | cut -d : -f 1,7 --output-delimiter="^_^"
|
||||
```
|
||||
|
||||
```
|
||||
root^_^/bin/bash
|
||||
daemon^_^/usr/sbin/nologin
|
||||
bin^_^/usr/sbin/nologin
|
||||
sys^_^/usr/sbin/nologin
|
||||
sync^_^/bin/sync
|
||||
```
|
||||
|
||||
### 實用範例
|
||||
Linux 的系統管理者時常會需要使用 `ps` 指令查看各行程的狀態,但由於 `ps` 的輸出資訊很多,如果我們只想看程式的 PID 與指令內容,就可以用 `cut` 把要用的資訊擷取來:
|
||||
|
||||
```bash
|
||||
# 找出所有 Python 程式的 PID 與指令內容
|
||||
ps aux | grep python | sed 's/\s\+/ /g' | cut -d ' ' -f 2,11-
|
||||
```
|
||||
|
||||
```
|
||||
17100 grep --color=auto python
|
||||
27904 /usr/bin/python -Es /usr/sbin/tuned -l -P
|
||||
33890 /usr/bin/python -Es /usr/sbin/firewalld --nofork --nopid
|
||||
```
|
||||
57
21.01. OS/21.01. Linux/CLI/scp.md
Normal file
57
21.01. OS/21.01. Linux/CLI/scp.md
Normal file
@@ -0,0 +1,57 @@
|
||||
`scp` 指令的語法跟一般的 `cp` 類似,只不過 `scp` 可以在不同的 Linux 主機之間複製檔案,其語法為:
|
||||
```
|
||||
scp [帳號@來源主機]:來源檔案 [帳號@目的主機]:目的檔案
|
||||
```
|
||||
|
||||
# 保留檔案時間與權限
|
||||
若要讓檔案在複製之後,還可保留原本的修改時間、存取時間與權限,可以加上 `-p` 參數:
|
||||
```
|
||||
scp -p /path/file1 myuser@192.168.0.1:/path/file2
|
||||
```
|
||||
|
||||
# 資料壓縮
|
||||
若要將資料壓縮之後再傳送,減少網路頻寬的使用量,可以加上 `-C` 參數:
|
||||
```
|
||||
scp -C /path/file1 myuser@192.168.0.1:/path/file2
|
||||
```
|
||||
|
||||
# 限制傳輸速度
|
||||
若要限制網路的使用頻寬,可以用 `-l` 指定可用的網路頻寬上限值(單位為 Kbit/s):
|
||||
```
|
||||
# 限制傳輸速度為 400 Kbit/s
|
||||
scp -l 400 /path/file1 myuser@192.168.0.1:/path/file2
|
||||
```
|
||||
|
||||
這樣就會限制 `scp` 只能使用 `400` Kbit/s,也就是 `400 / 8 = 50` KB/s。
|
||||
|
||||
# 自訂連接埠
|
||||
一般 SSH 伺服器的連接埠號為 22,如果遇到使用非標準埠號的伺服器,可以用 `-P` 來指定埠號。若遠端的 SSH 伺服器使用 `2222` 這個連接埠,我們就可以這樣複製檔案:
|
||||
```
|
||||
# 使用 2222 連接埠
|
||||
scp -P 2222 /path/file1 myuser@192.168.0.1:/path/file2
|
||||
```
|
||||
|
||||
# IPv4 與 IPv6
|
||||
`-4` 與 `-6` 兩個參數分別可以讓 `scp` 使用 IPv4 與 IPv6 來傳輸資料:
|
||||
```
|
||||
# 使用 IPv4
|
||||
scp -4 /path/file1 myuser@192.168.0.1:/path/file2
|
||||
|
||||
# 使用 IPv6
|
||||
scp -6 /path/file1 myuser@192.168.0.1:/path/file2
|
||||
```
|
||||
|
||||
# 更快的方法:使用SSH+TAR
|
||||
```
|
||||
ssh 使用者@主機 "cd 目標目錄 ;tar -zcvf - 目標" | cat > 目標.tar.gz
|
||||
```
|
||||
|
||||
例:
|
||||
```
|
||||
ssh 192.168.0.22 "cd /var ;tar -zcvf - log" | cat > 22_log.tar.gz
|
||||
```
|
||||
|
||||
# 參考
|
||||
- [SSH + TAR 取代 SCP @ Vexed's Blog :: 隨意窩 Xuite日誌](https://blog.xuite.net/vexed/tech/586811949)
|
||||
- [Linux中互传文件:ssh+tar 与Scp 比较 - 简书](https://www.jianshu.com/p/856a2dc883e0)
|
||||
- [轉貼--ssh tar 命令把遠端檔拉回來或推過去 --- 山城風雲的點滴](http://jimsung168.blogspot.com/2014/01/ssh-tar.html)
|
||||
4
21.01. OS/21.01. Linux/CLI/systemd.md
Normal file
4
21.01. OS/21.01. Linux/CLI/systemd.md
Normal file
@@ -0,0 +1,4 @@
|
||||
## 列出系統中的 systemd service
|
||||
```bash
|
||||
systemctl list-units --type=service
|
||||
```
|
||||
14
21.01. OS/21.01. Linux/CLI/timedatectl.md
Normal file
14
21.01. OS/21.01. Linux/CLI/timedatectl.md
Normal file
@@ -0,0 +1,14 @@
|
||||
用`timedatectl`可以看現在的時間、時區等等。也可以改變時區。
|
||||
![[Pasted image 20220516125616.png]]
|
||||
|
||||
用`timedatectl list-timezones`列出所有時區,我們已經知道我們的時區是Taipei,所以可以用grep直接把它抓出來:
|
||||
```bash
|
||||
timedatectl list-timezones | grep -i taipei
|
||||
```
|
||||
結果如下:
|
||||
![[Pasted image 20220516125742.png]]
|
||||
|
||||
設定時區:
|
||||
```
|
||||
timedatectl set-timezone Asia/Taipei
|
||||
```
|
||||
42
21.01. OS/21.01. Linux/Docker.md
Normal file
42
21.01. OS/21.01. Linux/Docker.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# 安裝
|
||||
根據[# Install Docker Engine on Ubuntu](https://docs.docker.com/engine/install/ubuntu/)來安裝Docker engine。
|
||||
|
||||
# 指令
|
||||
## 列出可用的版本
|
||||
```bash
|
||||
# List the available versions:
|
||||
apt-cache madison docker-ce | awk '{ print $3 }'
|
||||
|
||||
5:24.0.0-1~debian.11~bullseye
|
||||
5:23.0.6-1~debian.11~bullseye
|
||||
...
|
||||
```
|
||||
|
||||
## 列出 container
|
||||
`docker ps`會列出執行中的container(但是停止的不會)
|
||||
```bash
|
||||
sudo docker ps
|
||||
```
|
||||
|
||||
如果也要列出已停止的container
|
||||
```bash
|
||||
sudo docker ps -a
|
||||
```
|
||||
|
||||
## 刪除 container
|
||||
Container必須是停止狀態才可以刪除
|
||||
```bash
|
||||
sudo docker rm <CONTAINER_ID>
|
||||
```
|
||||
|
||||
## 進入 container 執行 bash
|
||||
```bash
|
||||
docker run -i -t <CONTAINER_NAME> /bin/bash
|
||||
```
|
||||
|
||||
## 列出 image
|
||||
```bash
|
||||
sudo docker image ls
|
||||
or
|
||||
sudo docker images
|
||||
```
|
||||
37
21.01. OS/21.01. Linux/NUT.md
Normal file
37
21.01. OS/21.01. Linux/NUT.md
Normal file
@@ -0,0 +1,37 @@
|
||||
---
|
||||
tags:
|
||||
aliases:
|
||||
date: 2025-01-07
|
||||
time: 22:52:59
|
||||
description:
|
||||
---
|
||||
|
||||
在啟用 NAS 的 UPS server 之後,可以安裝 `nut-client` 來接收 NAS 的通知以進行關機。
|
||||
|
||||
## 安裝套件
|
||||
```bash
|
||||
sudo apt install nut-client
|
||||
```
|
||||
|
||||
## 測試
|
||||
```bash
|
||||
upsc ups@192.168.1.11
|
||||
```
|
||||
|
||||
## 設定
|
||||
```bash
|
||||
sudo vim /etc/nut/upsmon.conf
|
||||
```
|
||||
|
||||
加入 `MODE=netclient`
|
||||
|
||||
```bash
|
||||
sudo vim /etc/nut/upsmon.conf
|
||||
```
|
||||
|
||||
加入 `MONITOR ups@192.168.1.11 1 monuser secret slave`
|
||||
|
||||
# 參考來源
|
||||
- [Linux 下使用 NUT 实现断电自动关机 | varkai](https://varkai.com/posts/operation/linux-uses-nut-to-realize-automatic-poweroff/)
|
||||
- [ups - Use Synology as NUT server for Ubuntu Server 20.04 - Ask Ubuntu](https://askubuntu.com/questions/1244064/use-synology-as-nut-server-for-ubuntu-server-20-04)
|
||||
- [UPS 低电压时通过群晖实现 Ubuntu 自动关机 - 杜老师说](https://dusays.com/557/)
|
||||
109
21.01. OS/21.01. Linux/Watchtower.md
Normal file
109
21.01. OS/21.01. Linux/Watchtower.md
Normal file
@@ -0,0 +1,109 @@
|
||||
## 安裝 Watchtower
|
||||
```shell
|
||||
docker pull Watchtower
|
||||
```
|
||||
|
||||
## 使用方法
|
||||
```shell
|
||||
docker run --detach \
|
||||
--name watchtower \
|
||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||
containrrr/watchtower
|
||||
```
|
||||
|
||||
使用剛剛的方法會拉取最新鏡像,但並不會自動刪除舊有鏡像,時間一長就會佔用很大空間,這裡可以使用 `--cleanup` 選項,在更新完舊容器之後自動刪除舊鏡像
|
||||
|
||||
```shell
|
||||
docker run -d \
|
||||
--name watchtower \
|
||||
--restart always \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
containrrr/watchtower \
|
||||
--cleanup
|
||||
```
|
||||
|
||||
### 或使用 docke-compose.yml
|
||||
```yaml
|
||||
version: "3"
|
||||
services:
|
||||
watchtower:
|
||||
image: containrrr/watchtower
|
||||
restart: always
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
command: --interval 86400 --cleanup
|
||||
```
|
||||
|
||||
### 設置自動更新檢測頻率
|
||||
Watchtower 默認是每 5min 檢測一次,如果需要更改週期,可以使用 `--interval`、`-i` 選項
|
||||
如設定每小時檢測一次:
|
||||
```shell
|
||||
docker run -d \
|
||||
--name watchtower \
|
||||
--restart always \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
containrrr/watchtower \
|
||||
--cleanup \
|
||||
-i 3600
|
||||
```
|
||||
|
||||
`-i 3600`:這裡的 `3600` 是設置的時間週期,單位是**秒** , `3600` 即 1 小時
|
||||
|
||||
### 指定更新檢測時間
|
||||
除了設置頻率,還可以使用 `--schedule`、`-s` 選項指定時間 如指定每天 UTC+8 時間凌晨 3 點更新。
|
||||
```shell
|
||||
docker run -d \
|
||||
--name watchtower \
|
||||
--restart always \
|
||||
-e TZ=Asia/Taipei \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
containrrr/watchtower \
|
||||
--cleanup \
|
||||
-s "0 0 3 * * *"
|
||||
```
|
||||
|
||||
這裡的執行時間為 UTC 時間,如果不指定時區,會比台北的 UTC+8:00 時間晚 8 小時
|
||||
|
||||
### 制定需要更新的容器
|
||||
如果不想更新所有容器,可以設置指定的容器進行更新
|
||||
以 `nginx` 和 `netdata` 這兩個容器舉例:
|
||||
```shell
|
||||
docker run -d \
|
||||
--name watchtower \
|
||||
--restart always \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
containrrr/watchtower \
|
||||
--cleanup \
|
||||
nginx netdata
|
||||
```
|
||||
|
||||
這裡指定的容器只需要填寫**容器名**,而不是填寫該容器的**鏡像名**
|
||||
|
||||
## 手動更新
|
||||
如果不想在使用容器時被自動更新打斷,可以使用 Watchtower 進行手動更新
|
||||
由於是手動更新,Watchtower 只需要用到一次,可以添加 `--rm` 和 `--run-once` 參數,在更新完之後過河拆橋
|
||||
|
||||
### 手動更新所有容器
|
||||
```shell
|
||||
docker run --rm \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
containrrr/watchtower \
|
||||
--cleanup \
|
||||
--run-once
|
||||
```
|
||||
|
||||
## 手動更新指定容器
|
||||
繼續以 `nginx` 和 `netdata` 這兩個容器舉例
|
||||
|
||||
```shell
|
||||
docker run --rm \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
containrrr/watchtower \
|
||||
--cleanup \
|
||||
--run-once \
|
||||
nginx netdata
|
||||
```
|
||||
|
||||
## 參考
|
||||
- [使用Watchtower自動更新Docker鏡像和容器 - Docker容器 - 計算機 | 🧂 = 鹽🧂的記事本 = ( ´∀`)ヵヵヵ](https://www.sio.moe/2021/12/18/computer/Docker-Container/Use-Watchtower-to-automatically-update-Docker-images-and-containers/)
|
||||
- [storjlabs/watchtower Tags | Docker Hub](https://hub.docker.com/r/storjlabs/watchtower/tags)
|
||||
29
21.01. OS/21.01. Linux/_Map.canvas
Normal file
29
21.01. OS/21.01. Linux/_Map.canvas
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"nodes":[
|
||||
{"id":"2387a7bafd0d1fa1","type":"text","text":"Linux","x":-60,"y":-60,"width":112,"height":60,"color":"1"},
|
||||
{"id":"480671b59b65fbee","type":"text","text":"網路","x":-260,"y":-200,"width":123,"height":60},
|
||||
{"id":"0da49f9f13cb5ea0","type":"text","text":"虛擬化","x":140,"y":-200,"width":125,"height":60},
|
||||
{"id":"67febece2a817d3a","type":"text","text":"系統管理","x":140,"y":80,"width":125,"height":60},
|
||||
{"id":"c30ec48841c09729","type":"text","text":"# LOG 管理\n[[journalctl]]","x":341,"y":80,"width":186,"height":100},
|
||||
{"id":"89e25cea38eee1c6","type":"text","text":"# 定時操作\n[[crontab]]","x":347,"y":220,"width":180,"height":100},
|
||||
{"id":"0211a8b636cb3542","type":"text","text":"指令操作","x":-262,"y":80,"width":125,"height":60},
|
||||
{"id":"584c8fe580aa5c65","type":"text","text":"- [[cut]]\n- [[scp]]\n- [[timedatectl]]\n- [[systemd]]","x":-620,"y":55,"width":250,"height":110},
|
||||
{"id":"5396ff224cf2433d","type":"text","text":"- [[Apache]]\n- [[Gitea]]\n- [[Grafana]]\n- [[Nextcloud]]\n- [[Pelican blog]]\n- [[Proxmox VE]]\n- [[Storj]]\n- [[filebrowser]]\n- [[freshrss]]\n- [[Grafana]]","x":-700,"y":-577,"width":242,"height":277},
|
||||
{"id":"631ba79f09378fa8","type":"text","text":"![[Docker|Docker]]","x":312,"y":-299,"width":348,"height":219},
|
||||
{"id":"d5901d4a7879a984","type":"text","text":"架站","x":-432,"y":-468,"width":125,"height":60},
|
||||
{"id":"8b9a102062abf2ea","type":"text","text":"![[smb client]]","x":-699,"y":-231,"width":330,"height":201}
|
||||
],
|
||||
"edges":[
|
||||
{"id":"2621855f17f1fce7","fromNode":"2387a7bafd0d1fa1","fromSide":"right","toNode":"0da49f9f13cb5ea0","toSide":"left"},
|
||||
{"id":"63fe0dc1ef02bcf0","fromNode":"2387a7bafd0d1fa1","fromSide":"right","toNode":"67febece2a817d3a","toSide":"left"},
|
||||
{"id":"8b1293fe476ce994","fromNode":"2387a7bafd0d1fa1","fromSide":"left","toNode":"480671b59b65fbee","toSide":"right"},
|
||||
{"id":"7b14c2274a6a7dce","fromNode":"480671b59b65fbee","fromSide":"left","toNode":"8b9a102062abf2ea","toSide":"right"},
|
||||
{"id":"3fb7bd17056728f2","fromNode":"0da49f9f13cb5ea0","fromSide":"right","toNode":"631ba79f09378fa8","toSide":"left"},
|
||||
{"id":"47dcc8ff2aa219d2","fromNode":"67febece2a817d3a","fromSide":"right","toNode":"c30ec48841c09729","toSide":"left"},
|
||||
{"id":"b9cbf23293526def","fromNode":"67febece2a817d3a","fromSide":"right","toNode":"89e25cea38eee1c6","toSide":"left"},
|
||||
{"id":"305a94a3648fc58b","fromNode":"d5901d4a7879a984","fromSide":"left","toNode":"5396ff224cf2433d","toSide":"right"},
|
||||
{"id":"1007d8512d956cdb","fromNode":"480671b59b65fbee","fromSide":"left","toNode":"d5901d4a7879a984","toSide":"right"},
|
||||
{"id":"c6875871d1de0864","fromNode":"2387a7bafd0d1fa1","fromSide":"left","toNode":"0211a8b636cb3542","toSide":"right"},
|
||||
{"id":"40f0ca450747f830","fromNode":"0211a8b636cb3542","fromSide":"left","toNode":"584c8fe580aa5c65","toSide":"right"}
|
||||
]
|
||||
}
|
||||
84
21.01. OS/21.01. Linux/crontab.md
Normal file
84
21.01. OS/21.01. Linux/crontab.md
Normal file
@@ -0,0 +1,84 @@
|
||||
### 加入
|
||||
使用`crontab -e`,然後加入這一行:
|
||||
`*/1 * * * * /home/awin/script/ddns.sh`
|
||||
|
||||
### 說明
|
||||
![[Pasted image 20240111231507.png]]
|
||||
依序是 **分鐘, 小時, 日期, 月份, 星期, command**
|
||||
參數為 0-59, 0-23, 1-31, 1-21, 0-6, 需要執行的command
|
||||
**※ 星期參數為 0 代表星期日**
|
||||
|
||||
- 【*】:星號,代表任何時刻都接受的意思
|
||||
- 【,】:逗號,代表分隔時段。例如:30 9,17 * * * command,代表早上 9 點半和下午五點半都執行 command。
|
||||
- 【-】:減號,代表一段時間範圍。例如:15 9-12 * * * command,代表從 9 點到 12 點的每個 15 分都執行 command。
|
||||
- 【/n】:斜線,n 代表數字,表示每個 n 單位間隔。例如:*/5 * * * * command,代表每隔 5 分鐘執行一次 command。
|
||||
|
||||
還有一些人性化的參數,一次取代全部五個數字參數
|
||||
- 【@reboot】 :僅在開機的時候執行一次。
|
||||
- 【@yearly】 :一年執行一次,和0 0 1 1 * command效果一樣。
|
||||
- 【@annually】:(和@yearly一樣)
|
||||
- 【@monthly】:一個月執行一次,和0 0 1 * * command效果一樣。
|
||||
- 【@weekly】:一個星期執行一次,和0 0 * * 0 command效果一樣。
|
||||
- 【@daily】:每天執行,和0 0 * * * command效果一樣。
|
||||
- 【@midnight】:(和@daily一樣)
|
||||
- 【@hourly】 :每小時執行,和0 * * * * command效果一樣。
|
||||
|
||||
### 範例
|
||||
- 每 5 分鐘執行一次:
|
||||
- `*/5 * * * * root /usr/libexec/atrun`
|
||||
- 每 5 小時執行一次
|
||||
- `* */5 * * * root /usr/libexec/atrun`
|
||||
- 每天 AM 5:00 執行指令(星號與星號之間要有空隔)
|
||||
- `00 05 * * * username /bin/bash /路徑/command`
|
||||
- 1 至 20 號每天執行一次
|
||||
- `0 1 1-20 * * root /usr/libexec/atrun`
|
||||
- 當分針移到第 5 分時,執行此 cron
|
||||
- `5 * * * * root /usr/libexec/atrun`
|
||||
- 當時針移到 1 點 1 分時,執行此 cron
|
||||
- `1 1 * * * root /usr/libexec/atrun`
|
||||
- 每週一的 1 點 1 分,執行
|
||||
- `1 1 * * 1 root /usr/libexec/atrun`
|
||||
- 2 月 29 日時針到 1 點 1 分,執行
|
||||
- `1 1 29 2 * root /usr/libexec/atrun`
|
||||
- 8 點到 16 點每 5 分鐘執行一次 cron
|
||||
- `/5 8-16 * * * root /usr/libexec/atrun`
|
||||
|
||||
### crontab 命令
|
||||
#### 啟動
|
||||
`sudo service cron start`
|
||||
|
||||
#### 重新啟動
|
||||
`/etc/init.d/cron restart`
|
||||
|
||||
#### 查詢service狀態
|
||||
`sudo /etc/init.d/cron status`
|
||||
|
||||
#### 編輯 crontab
|
||||
`crontab -e`
|
||||
|
||||
### `awin` 的 crontab
|
||||
```
|
||||
# m h day mon weekday command
|
||||
*/5 * * * * /home/awin/script/clean_nextcloud.sh
|
||||
```
|
||||
|
||||
### `root` 的 crontab
|
||||
```
|
||||
# m h day mon dow command
|
||||
*/3 * * * * /home/awin/script/ddns.sh > /home/awin/log/ddns.log 2>&1
|
||||
*/5 * * * * /home/awin/script/clean_nextcloud.sh > /home/awin/log/clean_nextcloud.log 2>&1
|
||||
1 2 * * 1 /home/awin/script/backup_adguardhome.sh > /home/awin/log/backup_docker_adguardhome.log 2>&1
|
||||
2 2 * * 1 /home/awin/script/backup_filebrowser.sh > /home/awin/log/backup_docker_filebrowser.log 2>&1
|
||||
3 2 * * 1 /home/awin/script/backup_freshrss.sh > /home/awin/log/backup_docker_freshrss.log 2>&1
|
||||
4 2 * * 1 /home/awin/script/backup_gitea.sh > /home/awin/log/backup_docker_gitea.log 2>&1
|
||||
5 2 * * 1 /home/awin/script/backup_immich.sh > /home/awin/log/backup_docker_immich.log 2>&1
|
||||
1 2 * * 2 /home/awin/script/backup_nextcloud.sh > /home/awin/log/backup_docker_nextcloud.log 2>&1
|
||||
* * 1 * * /home/awin/script/backup_dotfiles_awin-pc2.sh > /home/awin/log/backup_dotfiles_awin-pc2.log 2>&1
|
||||
1 1 * * * /home/awin/script/rsync_nasphoto.sh > /home/awin/log/rsync_nasphoto.log 2>&1
|
||||
@reboot /home/awin/script/reboot_echo.sh > /home/awin/log/reboot.log 2>&1
|
||||
|
||||
## Restart Docker containers
|
||||
# m h day mon dow command
|
||||
0 4 * * * docker restart grafana-prometheus-local_data_exporter-1 > /home/awin/log/restart_grafana-prometheus-local_data_exporter-1.log 2>&1
|
||||
```
|
||||
|
||||
38
21.01. OS/21.01. Linux/fstab.md
Normal file
38
21.01. OS/21.01. Linux/fstab.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# 看磁碟UUID
|
||||
```bash
|
||||
sudo blkid
|
||||
```
|
||||
```result
|
||||
/dev/mmcblk0p1: LABEL_FATBOOT="bootfs" LABEL="bootfs" UUID="62C9-51DB" BLOCK_SIZE="512" TYPE="vfat" PARTUUID="bd53c125-01"
|
||||
/dev/mmcblk0p2: LABEL="rootfs" UUID="2b2cb0b0-aa00-4bd0-b775-4abc1ff31eb2" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="bd53c125-02"
|
||||
/dev/sda1: UUID="8bd933c6-2625-498f-84cf-0b1394aa3f5e" BLOCK_SIZE="4096" TYPE="ext4" PARTLABEL="Linux filesystem" PARTUUID="6e7fd2d9-1c28-4570-aae2-022f5345781f"
|
||||
```
|
||||
|
||||
其中,`UUID="XXXXXXX....."` 這一串就是硬碟的UUID,複製下來,等一下要填到 `fstab` 裡面。
|
||||
|
||||
# `/etc/fstab`
|
||||
打開 `/etc/fstab`,加入一行:
|
||||
```config
|
||||
UUID=8bd933c6-2625-498f-84cf-0b1394aa3f5e /extusb1/storj ext4 defaults,nofail 0 0
|
||||
```
|
||||
|
||||
- `UUID=8bd933c6-2625-498f-84cf-0b1394aa3f5e`:指定要掛載的磁區是那一個
|
||||
- `/extusb1/storj`:指定要掛載的目錄
|
||||
- `ext4`: 指定要掛載的格式
|
||||
- `defaults,nofail`:檔案格式參數區。`nofail` 是說要是掛載失敗不要產生錯誤訊息,避免因為硬碟壞掉而卡在開機畫面,造成開不了機。尤其是當你的電腦沒有螢幕、鍵盤的時候,會很麻煩。
|
||||
- `0`:是否可以被 dump 指令備份 (0:不要做備份﹔1:要做備份﹔2:要做備份,重要度比 1 小)。
|
||||
- `0`:是否於開機時以 fsck 檢驗磁區 (0:不檢驗﹔1:先檢驗﹔2:後檢驗)。如果是內接式的硬碟可以改成`0 1`。
|
||||
|
||||
# AWIN-PC2 的 fstab
|
||||
```
|
||||
# <file system> <mount point> <type> <options> <dump> <pass>
|
||||
/dev/disk/by-uuid/38cb80c1-504f-4b07-8a86-27e1c22b5deb / ext4 defaults 0 1
|
||||
/dev/disk/by-uuid/A2D8-2DF1 /boot/efi vfat defaults 0 1
|
||||
/swap.img none swap sw 0 0
|
||||
|
||||
UUID=be92f54f-e427-496e-83e9-a29643aa5af0 /lvm1 ext4 defaults,nofail 0 2
|
||||
//192.168.1.11/share /media/share cifs credentials=/home/awin/.smbcredentials_shareview,defaults 0 0
|
||||
//192.168.1.11/upload /media/upload cifs credentials=/home/awin/.smbcredentials_shareview,defaults 0 0
|
||||
//192.168.1.11/Backup /media/backup cifs credentials=/home/awin/.smbcredentials_backup,defaults 0 0
|
||||
//192.168.1.11/photo /media/nasphoto cifs credentials=/home/awin/.smbcredentials_photoMgr,defaults 0 0
|
||||
```
|
||||
14
21.01. OS/21.01. Linux/iptable.md
Normal file
14
21.01. OS/21.01. Linux/iptable.md
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
tags:
|
||||
aliases:
|
||||
date: 2024-07-30
|
||||
time: 19:30:12
|
||||
description:
|
||||
---
|
||||
|
||||
## Allow all input
|
||||
```
|
||||
iptables -I INPUT -j ACCEPT
|
||||
```
|
||||
|
||||
# 參考來源
|
||||
129
21.01. OS/21.01. Linux/journalctl.md
Normal file
129
21.01. OS/21.01. Linux/journalctl.md
Normal file
@@ -0,0 +1,129 @@
|
||||
## 看log
|
||||
Raspberry Pi 4沒有`/var/log/syslog`,要使用`journalctl`。
|
||||
```bash
|
||||
journalctl
|
||||
```
|
||||
Or
|
||||
```bash
|
||||
journalctl | grep SOMETHING
|
||||
```
|
||||
|
||||
### 看系統訊息
|
||||
```bash
|
||||
journalctl -p 0
|
||||
```
|
||||
|
||||
#### Error code意思
|
||||
```
|
||||
0: 紧急情况
|
||||
1: 警报
|
||||
2: 危急
|
||||
3: 错误
|
||||
4: 警告
|
||||
5: 通知
|
||||
6: 信息
|
||||
7:调试
|
||||
```
|
||||
|
||||
### 看開機log
|
||||
```bash
|
||||
journalctl --list-boots
|
||||
```
|
||||
|
||||
- 第一個數字顯示的是journald 的唯一的啟動追蹤號碼,你可以在下一個命令中使用它來分析該特定的啟動。
|
||||
- 第二個數字是啟動ID,你也可以在指令中指定。
|
||||
- 接下來的兩個日期、時間組合是儲存在對應文件中的日誌的時間。如果你想找出某個特定日期、時間的日誌或錯誤,這就非常方便了。
|
||||
|
||||
例如:
|
||||
```bash
|
||||
journalctl -b -45
|
||||
```
|
||||
Or
|
||||
```bash
|
||||
journalctl -b 8bab42c7e82440f886a3f041a7c95b98
|
||||
```
|
||||
|
||||
也可以使用 `-x` 選項,在顯示器上加入systemd 錯誤訊息的解釋。在某些情況下,這是個救命稻草。例:
|
||||
```bash
|
||||
journalctl -xb -p 3
|
||||
```
|
||||
|
||||
### 看某一特定時間、日期的日誌記錄
|
||||
使用 `--since` 選項與 `yesterday`、`today`、`tomorrow` 或 `now` 組合。
|
||||
|
||||
以下是一些不同指令的範例。你可以根據你的需求修改它們。它們是不言自明的。以下命令中的日期、時間格式為 `"YYYY-MM-DD HH:MM:SS"`
|
||||
```bash
|
||||
journalctl --since "2020-12-04 06:00:00"
|
||||
journalctl --since "2020-12-03" --until "2020-12-05 03:00:00"
|
||||
journalctl --since yesterday
|
||||
journalctl --since 09:00 --until "1 hour ago"
|
||||
```
|
||||
|
||||
### 看內核特定的記錄
|
||||
```bash
|
||||
journalctl -k
|
||||
```
|
||||
|
||||
### 過濾出某個systemd 服務單元的特定日誌
|
||||
例如,如果要查看 NetworkManager 服務的日誌
|
||||
```bash
|
||||
journalctl -u NetworkManager.service
|
||||
```
|
||||
|
||||
如果不知道service name,看[[systemd#列出系統中的 systemd service]]
|
||||
|
||||
### 查看使用者、群組的日誌
|
||||
```bash
|
||||
id -u debugpoint # 先找出使用者的uid
|
||||
journalctl _UID=1000 --since today
|
||||
```
|
||||
|
||||
### 查看可執行檔的日誌
|
||||
```bash
|
||||
journalctl /usr/bin/gnome-shell --since today
|
||||
```
|
||||
|
||||
### 看log佔用的磁碟空間
|
||||
```bash
|
||||
journalctl --disk-usage
|
||||
```
|
||||
|
||||
### 清除日誌
|
||||
#### 手動清除
|
||||
```bash
|
||||
sudo journalctl --flush --rotate # 將所有日誌歸檔
|
||||
sudo journalctl --vacuum-time=7d # 只保留最近7天的日誌
|
||||
sudo journalctl --vacuum-time=1s # 只保留最近1秒的日誌
|
||||
```
|
||||
或者設定日誌的大小
|
||||
```bash
|
||||
sudo journalctl --vacuum-size=400M # 保留最後400M
|
||||
```
|
||||
|
||||
#### 自動清除
|
||||
修改`/etc/systemd/journald.conf`,裡面有下面幾個設定項:
|
||||
- `SystemMaxUse`: 指定日志在持久性存储中可使用的最大磁盘空间。例:`SystemMaxUse=500M`
|
||||
- `SystemKeepFree`: 指定在将日志条目添加到持久性存储时,日志应留出的空间量。例:`SystemKeepFree=100M`
|
||||
- `SystemMaxFileSize`: 控制单个日志文件在被轮换之前在持久性存储中可以增长到多大。例:`SystemMaxFileSize=100M`
|
||||
- `RuntimeMaxUse`: 指定在易失性存储中可以使用的最大磁盘空间(在 /run 文件系统内)。例:`RuntimeMaxUse=100M`
|
||||
- `RuntimeKeepFree`: 指定将数据写入易失性存储(在 /run 文件系统内)时为其他用途预留的空间数量。例:`RuntimeMaxUse=100M`
|
||||
- `RuntimeMaxFileSize`: 指定单个日志文件在被轮换之前在易失性存储(在 /run 文件系统内)所能占用的空间量。例:`RuntimeMaxFileSize=200M`
|
||||
|
||||
修改後記得重啟 `journalctl`:
|
||||
![[journalctl#重啟日誌]]
|
||||
|
||||
也請記得[[journalctl#確認日誌的完整性]]
|
||||
|
||||
### 確認日誌的完整性
|
||||
```bash
|
||||
journalctl --verify
|
||||
```
|
||||
|
||||
### 重啟日誌
|
||||
若是有改變設定,記得重啟以讓變更生效:
|
||||
```shell
|
||||
sudo systemctl restart systemd-journald
|
||||
```
|
||||
|
||||
### 參考
|
||||
- [系統運作|如何使用journalctl 檢視和分析systemd 日誌(附實例)](https://linux.cn/article-15544-1.html)
|
||||
42
21.01. OS/21.01. Linux/lsblk.md
Normal file
42
21.01. OS/21.01. Linux/lsblk.md
Normal file
@@ -0,0 +1,42 @@
|
||||
`lsblk -o` 可以看到所有硬碟的詳細資料,但是資料廖很大,可以在騎之後加上指定的蘭未來縮減資料量,例如:
|
||||
```bash
|
||||
sudo lsblk -o NAME,MODEL,SERIAL,WWN,HCTL
|
||||
```
|
||||
```result
|
||||
NAME MODEL SERIAL WWN HCTL
|
||||
sda ST3000VN000-1H41 W300JG66 0x5000c50069c93ec4 0:0:0:0
|
||||
└─sda1 0x5000c50069c93ec4
|
||||
├─vg1-lv1_rmeta_0
|
||||
│ └─vg1-lv1
|
||||
└─vg1-lv1_rimage_0
|
||||
└─vg1-lv1
|
||||
sdb WDC WDS480G2G0A- 20418C804426 0x5001b448bb7f096a 0:0:1:0
|
||||
├─sdb1 0x5001b448bb7f096a
|
||||
├─sdb2 0x5001b448bb7f096a
|
||||
├─sdb3 0x5001b448bb7f096a
|
||||
└─sdb4 0x5001b448bb7f096a
|
||||
sdc CT480BX500SSD1 2044E4C26B3C 0x500a0751e4c26b3c 0:0:2:0
|
||||
├─sdc1 0x500a0751e4c26b3c
|
||||
└─sdc2 0x500a0751e4c26b3c
|
||||
sdd ST1000LM035-1RK1 WDEM0VBP 0x5000c500ab7d2dde 0:0:3:0
|
||||
└─sdd1 0x5000c500ab7d2dde
|
||||
sde ST3000VN000-1H41 W300JHNF 0x5000c50069c8d4b2 0:0:4:0
|
||||
└─sde1 0x5000c50069c8d4b2
|
||||
├─vg1-lv1_rmeta_1
|
||||
│ └─vg1-lv1
|
||||
└─vg1-lv1_rimage_1
|
||||
└─vg1-lv1
|
||||
sdf TOSHIBA HDWN180 57F4K126FP9E 0x50000397cb881edb 0:0:5:0
|
||||
├─sdf1 0x50000397cb881edb
|
||||
├─sdf2 0x50000397cb881edb
|
||||
└─sdf5 0x50000397cb881edb
|
||||
└─md127
|
||||
sdg ST8000VN0022-2EL ZA19RA2H 0x5000c500a5e7e1bf 0:0:6:0
|
||||
├─sdg1 0x5000c500a5e7e1bf
|
||||
├─sdg2 0x5000c500a5e7e1bf
|
||||
└─sdg5 0x5000c500a5e7e1bf
|
||||
└─md127
|
||||
nvme0n1 ADATA LEGEND 710 2N422LABN7CR eui.324e3432324c41424ce000184e374352
|
||||
├─nvme0n1p1 eui.324e3432324c41424ce000184e374352
|
||||
└─nvme0n1p2 eui.324e3432324c41424ce000184e374352
|
||||
```
|
||||
187
21.01. OS/21.01. Linux/lvm.md
Normal file
187
21.01. OS/21.01. Linux/lvm.md
Normal file
@@ -0,0 +1,187 @@
|
||||
# PV(Physical Volume)
|
||||
|
||||
PV(Physical Volume) 就是LVM的磁碟分區。
|
||||
|
||||
## 建立PV
|
||||
建立PV的命令如下:
|
||||
```bash
|
||||
pvcreate /dev/sdb /dev/sdc /dev/sdd
|
||||
```
|
||||
|
||||
```result
|
||||
`Physical volume "/dev/sdb" successfully created`
|
||||
`Physical volume "/dev/sdc" successfully created`
|
||||
`Physical volume "/dev/sdd" successfully created`
|
||||
```
|
||||
|
||||
這樣我們就建立了3個PV。
|
||||
|
||||
## 查看 PV
|
||||
使用 `pvdisplay` 和 `pvs` 來檢視你建立的 PV。
|
||||
|
||||
`pvs` 輸出會比較簡短,例:
|
||||
```
|
||||
sudo pvs
|
||||
```
|
||||
```result
|
||||
PV VG Fmt Attr PSize PFree
|
||||
/dev/sda3 ubuntu-vg lvm2 a-- 57.62g 28.81g
|
||||
/dev/sdb1 vg1 lvm2 a-- <2.73t 0
|
||||
/dev/sdc1 vg1 lvm2 a-- <2.73t 0
|
||||
```
|
||||
|
||||
`pvdisplay` 就比較詳細:
|
||||
```
|
||||
sudo pvdisplay
|
||||
```
|
||||
```result
|
||||
--- Physical volume ---
|
||||
PV Name /dev/sdb1
|
||||
VG Name vg1
|
||||
PV Size <2.73 TiB / not usable 3.44 MiB
|
||||
Allocatable yes (but full)
|
||||
PE Size 4.00 MiB
|
||||
Total PE 715396
|
||||
Free PE 0
|
||||
Allocated PE 715396
|
||||
PV UUID cWvfBE-Vbyp-l09E-QH0O-ZZoC-AdSG-t1J7TT
|
||||
|
||||
--- Physical volume ---
|
||||
PV Name /dev/sdc1
|
||||
VG Name vg1
|
||||
PV Size <2.73 TiB / not usable 3.00 MiB
|
||||
Allocatable yes (but full)
|
||||
PE Size 4.00 MiB
|
||||
Total PE 715396
|
||||
Free PE 0
|
||||
Allocated PE 715396
|
||||
PV UUID eDdYr4-HSZC-wRBa-feGx-SHp1-Wfye-m0e1PY
|
||||
|
||||
--- Physical volume ---
|
||||
PV Name /dev/sda3
|
||||
VG Name ubuntu-vg
|
||||
PV Size 57.62 GiB / not usable 2.00 MiB
|
||||
Allocatable yes
|
||||
PE Size 4.00 MiB
|
||||
Total PE 14751
|
||||
Free PE 7376
|
||||
Allocated PE 7375
|
||||
PV UUID zUlIaB-1Uof-3eF6-z5I7-OnqJ-UYDk-gThxJQ
|
||||
```
|
||||
|
||||
# VG(Volume Group)
|
||||
|
||||
VG(Volume Group) 由 PV 組成,你可以自由的排列組合。我們拿剛剛建立的3個PV把它組成一個VG。
|
||||
|
||||
## 建立 VG
|
||||
```
|
||||
vgcreate vg1 /dev/sdb /dev/sdc /dev/sdd
|
||||
```
|
||||
|
||||
`vg1` 是你的VG 名字,可以自由更改。
|
||||
後面的`/dev/sdb`、`/dev/sdc`、`/dev/sdd` 就是你剛剛建立的 PV。
|
||||
|
||||
## 查看 VG
|
||||
使用 `vgdisplay` 和 `vgs` 來檢視你建立的 VG。
|
||||
|
||||
# LV(Logical Volume)
|
||||
|
||||
LV(Logical Volume) 可以對應到實際的硬碟,它才是可以被 mount 到 directory 的東西。LV 可以只使用 VG 某一部份的,也就是說一個VG可以切出很多LV。
|
||||
|
||||
## 建立 LV
|
||||
```
|
||||
lvcreate --size 10G --name lv1 vg1
|
||||
```
|
||||
`--size 10G` 表示 LV 的空間是 10G
|
||||
`--name lv1` 表示 LV的名字叫做 `lv1`
|
||||
最後的 `vg1` 則是你要從那一個 VG 來建立這個 LV。
|
||||
|
||||
當然可以直接指定LV使用所有的空間:
|
||||
```
|
||||
lvcreate -l +100%FREE --name lv1 vg1
|
||||
```
|
||||
`-l` 跟 `--size` 同義。
|
||||
|
||||
### 建立 raid 1
|
||||
使用 `--type raid1` 可以建立 raid 1 的 LVM,例:
|
||||
```
|
||||
lvcreate --type raid1 -l +100%FREE --name lv1 vg1
|
||||
```
|
||||
|
||||
## 查看 LV
|
||||
使用 `lvdisplay` 和 `lvs` 來檢視你建立的 LV。
|
||||
|
||||
# 格式化 LV
|
||||
建立好LV之後就可以格式化它然後掛載它,先用`lvdisplay`確認一下 LV的路徑:
|
||||
![[20240228_170525_WindowsTerminal_901x169.png]]
|
||||
格式化:
|
||||
```
|
||||
mkfs -t ext4 /dev/vg1/lv1
|
||||
```
|
||||
|
||||
# Mount LV
|
||||
|
||||
先建立一個目錄來掛載 LV:
|
||||
```
|
||||
mkdir /lvm1
|
||||
```
|
||||
|
||||
再把 LV 掛上去:
|
||||
```
|
||||
mount /dev/vg1/lv1 /lvm1
|
||||
```
|
||||
|
||||
這樣就可以在 /myLVM 操作了。
|
||||
|
||||
## 開機自動掛載
|
||||
![[開機自動掛載硬碟]]
|
||||
|
||||
# LVM 增加空間
|
||||
增加空間的大概步驟是這樣:
|
||||
1. 電腦裝上新硬碟
|
||||
2. 建立PV,如[[lvm#建立PV]]
|
||||
3. 用 `vgextend` 把這個新的 PV 加入到既有的 VG
|
||||
4. 用 `lvextend` 來擴大容量
|
||||
5. 用 `resize2fs` 來擴大容量
|
||||
|
||||
## 用 `vgextend` 新增 PV
|
||||
假設 vg1 是目前的 VG 名字,新增的 PV是 /dev/sdc:
|
||||
```
|
||||
vgextend vg1 /dev/sdc
|
||||
```
|
||||
|
||||
## 用 `lvextend` 來擴大容量
|
||||
先用`lvdisplay`確認一下 LV的路徑,假設是 `/dev/vg1/lv1`
|
||||
```
|
||||
lvextend -L +10G /dev/vg1/lv1 # 多 10G 空間
|
||||
or
|
||||
lvextend -l +40%FREE /dev/vg1/lv1 多 40% 空間
|
||||
```
|
||||
|
||||
## 用 `resize2fs` 來擴大容量
|
||||
```
|
||||
resize2fs /dev/vg1/lv1
|
||||
```
|
||||
|
||||
# LVM 換電腦
|
||||
可能你重灌,或是把硬碟從這一台電腦換到另一台電腦,這都需要重新 "active" 原本的 LVM。
|
||||
先用 `lvscan` 看看是否有找到原本的 LVM:
|
||||
![[20240311_194022_WindowsTerminal_925x99.png]]
|
||||
|
||||
如果有的話,紅框位置就是 LVM 的路徑,之後只要啟用它就可以了:
|
||||
```
|
||||
sudo lvchange -a y /dev/vg1/lv1
|
||||
```
|
||||
|
||||
之後再[[硬碟操作#掛載硬碟|mount]]它就好了。
|
||||
|
||||
# 參考
|
||||
- [What is LVM2 in Linux ?. LVM](https://medium.com/@The_CodeConductor/what-is-lvm2-in-linux-3d28b479e250)
|
||||
- [建立LVM磁區 - HackMD](https://hackmd.io/@yzai/BJUIhnAb9)
|
||||
- [LVM — pv, vg, lv](https://sean22492249.medium.com/lvm-pv-vg-lv-1777a84a3ce8)
|
||||
- [Linux LVM (建立、擴充、移除LVM磁區) 操作筆記](https://sc8log.blogspot.com/2017/03/linux-lvm-lvm.html)
|
||||
- [LVM2學習筆記](https://maxubuntu.blogspot.com/2010/05/lvm2.html)
|
||||
- [技术|如何在 Linux 中创建/配置 LVM(逻辑卷管理)](https://linux.cn/article-12670-1.html)
|
||||
- [系统运维|如何在 Linux 中扩展/增加 LVM 大小(逻辑卷调整)](https://linux.cn/article-12673-1.html)
|
||||
- [系统运维|如何在 Linux 中减少/缩小 LVM 大小(逻辑卷调整)](https://linux.cn/article-12740-1.html)
|
||||
- [使用 lvm 內建的 raid 1 功能達成硬碟故障時的高可用性](https://gholk.github.io/linux-lvm-raid-1-builtin-boot.html)
|
||||
292
21.01. OS/21.01. Linux/lxc.md
Normal file
292
21.01. OS/21.01. Linux/lxc.md
Normal file
@@ -0,0 +1,292 @@
|
||||
這裡分享我在 Ubuntu Server 22.04 用 LXC 安裝 Windows 11,以及分享內顯 i915給虛擬機的的紀錄。
|
||||
要讓虛擬機可以使用 GPU,最常見的是 GPU passthrough,但是 GPU passthrough 只能給一個虛擬機使用,要讓多個虛擬機同時使用的話,必須打開 i915 的 SR-IOV ,可以多 7 個 VGA來分享給虛擬機。
|
||||
|
||||
# 準備
|
||||
## 安裝 incus
|
||||
根據 https://linuxcontainers.org/incus/docs/main/installing/#installing 的說明,Ubuntu 22.04 還沒辦法使用 apt 來安裝,因此依照 https://github.com/zabbly/incus 的說明來安裝:
|
||||
```shell
|
||||
curl -fsSL https://pkgs.zabbly.com/key.asc | gpg --show-keys --fingerprint
|
||||
mkdir -p /etc/apt/keyrings/
|
||||
sudo curl -fsSL https://pkgs.zabbly.com/key.asc -o /etc/apt/keyrings/zabbly.asc
|
||||
|
||||
sudo sh -c 'cat <<EOF > /etc/apt/sources.list.d/zabbly-incus-stable.sources
|
||||
Enabled: yes
|
||||
Types: deb
|
||||
URIs: https://pkgs.zabbly.com/incus/stable
|
||||
Suites: $(. /etc/os-release && echo ${VERSION_CODENAME})
|
||||
Components: main
|
||||
Architectures: $(dpkg --print-architecture)
|
||||
Signed-By: /etc/apt/keyrings/zabbly.asc
|
||||
EOF'
|
||||
|
||||
sudo apt update
|
||||
sudo apt install incus
|
||||
```
|
||||
|
||||
## 設定 incus
|
||||
使用 `sudo incus admin init` 來設定,會問一堆問題,如下:
|
||||
```
|
||||
Would you like to use clustering? (yes/no) [default=no]:
|
||||
Do you want to configure a new storage pool? (yes/no) [default=yes]: no
|
||||
Would you like to create a new local network bridge? (yes/no) [default=yes]: no
|
||||
Would you like to use an existing bridge or host interface? (yes/no) [default=no]: yes
|
||||
Name of the existing bridge or host interface: enp3s0
|
||||
Would you like the server to be available over the network? (yes/no) [default=no]: yes
|
||||
Address to bind to (not including port) [default=all]:
|
||||
Port to bind to [default=8443]:
|
||||
Would you like stale cached images to be updated automatically? (yes/no) [default=yes]:
|
||||
Would you like a YAML "init" preseed to be printed? (yes/no) [default=no]:
|
||||
```
|
||||
|
||||
大部分都預設就可以。
|
||||
|
||||
## 建立 pool
|
||||
```shell
|
||||
sudo incus storage create vmpool dir source=/lvm1/lxd_storage
|
||||
```
|
||||
|
||||
## 建立 profile
|
||||
```shell
|
||||
sudo incus profile copy default windows
|
||||
```
|
||||
|
||||
編輯profile,內容如下:
|
||||
```
|
||||
config:
|
||||
limits.cpu: "16"
|
||||
limits.memory: 16GiB
|
||||
raw.qemu: -device intel-hda -device hda-duplex -audio spice
|
||||
description: 'Windows: 16CPU, 16GB RAM, 1024GB DISK'
|
||||
devices:
|
||||
eth0:
|
||||
name: eth0
|
||||
nictype: macvlan
|
||||
parent: br0
|
||||
type: nic
|
||||
root:
|
||||
path: /
|
||||
pool: vmpool
|
||||
type: disk
|
||||
vtpm:
|
||||
path: /dev/tpm0
|
||||
type: tpm
|
||||
name: windows
|
||||
used_by: []
|
||||
```
|
||||
|
||||
## 安裝需要的套件
|
||||
```shell
|
||||
sudo apt-get install genisoimage libguestfs-tools wimtools --yes
|
||||
sudo snap install distrobuilder --classic
|
||||
```
|
||||
|
||||
## 轉換 ISO
|
||||
我們需要把Windows ISO轉換為lxc可用的ISO,先準備好原本的Windows ISO,這裡的檔名是 `Win11_23H2_Chinese_Traditional_x64v2.iso`,記得換成你自己的檔名。
|
||||
命令如下:
|
||||
```shell
|
||||
sudo distrobuilder repack-windows Win11_23H2_Chinese_Traditional_x64v2.iso Win11_23H2_Chinese_Traditional_x64v2.lxd.iso
|
||||
```
|
||||
|
||||
我們把 `Win11_23H2_Chinese_Traditional_x64v2.iso` 轉為 `Win11_23H2_Chinese_Traditional_x64v2.lxd.iso`。
|
||||
|
||||
等一下 `Win11_23H2_Chinese_Traditional_x64v2.lxd.iso` 就是要餵給虛擬機安裝的檔案。
|
||||
|
||||
## 讓操作端跟 server 端可以互連
|
||||
因為 Ubuntu server 沒有 GUI,都是透過命令操作,所以當虛擬機開機之後沒有辦法顯示畫面。所以我們需要從另一台 Windows 來把虛擬機開機,並在這台 Windows 上顯示並操作安裝畫面,這樣才可以安裝 Windows 虛擬機。
|
||||
|
||||
Ubuntu server 我們就稱為 server 端。
|
||||
Windows 這邊我們就稱為操作端。
|
||||
|
||||
### server 端
|
||||
這邊我們要讓 lxc 新增一個操作端,如下:
|
||||
```shell
|
||||
sudo incus config trust add awn-pc1
|
||||
```
|
||||
然後會跳出一堆字串,類似這樣:
|
||||
```
|
||||
ucRZ8JO48d4J32MRZ1tuuvNh3Wg86Pb7LZ4QKk090BM3jA2SIRh9aDB1mQ4dZ0H76PJll1bb0YkG2ZK8l5YYPWX5Cw4UhVs2li722P5s7A45MW4B5WBXBQXFPT170L50MsMMjB8ZiVhO6Ug2JWXGwdxp897u8cELqE6AAbA901uUCBwo80qr5czfR2Pk3QS7JCRb9LFa6uKKQsQKSDHm76814UOD3Knf50E9cq3GB6C28A0B54NKBw9T5004ZQ75QqCZqBD0F32mjfAILGCI57R09RN81LHMJ0NLVAXAKQc2LTh0aHYjsO6J41ERLAQF8bk7T07cG4611YT6F57Y6lr93ZSc5L0W7F5R5RG7Xr6e0gJ6dXh5iI18uwpUrZ6MAhN6GSUSGYTqe218He5gLa3G3UMNAJY1PlLSShcV91UF3Z18QloVR8DP9O6wYa7R9LG2Cv04MDSIK8Hs94ZPQ4hsbS1BT2J5QqZ41su06R9a8WTjP9rX8hNsQz5x5744AJl2656SdUqbos4JKX9B2IbGheqK94D7Ya0SZYiODX7Y5rIWdH1P6M6e5J75nN6En0Y9UmgRCGE2WIeG6jXFhpb7
|
||||
```
|
||||
|
||||
這個記下來,等一下要在操作端輸入。
|
||||
|
||||
### 操作端
|
||||
命令:
|
||||
```
|
||||
incus remote add awin-pc2 192.168.1.24
|
||||
```
|
||||
|
||||
然後輸入剛剛那一串字串。
|
||||
|
||||
接著命令:
|
||||
```
|
||||
incus switch awin-pc2
|
||||
```
|
||||
|
||||
之後就可以在操作端啟動 server 端的虛擬機了。
|
||||
|
||||
# 建立虛擬機
|
||||
server 端命令:
|
||||
```shell
|
||||
sudo incus init --empty --vm --profile=windows $VM_NAME
|
||||
sudo incus config device add $VM_NAME install disk source=/home/awin/lxd/Win11_23H2_Chinese_Traditional_x64v2.lxd.iso boot.priority=10
|
||||
```
|
||||
|
||||
操作端命令:
|
||||
```shell
|
||||
incus start DENNY-VM-WIN11 --console=vga
|
||||
```
|
||||
|
||||
操作端會跳出一個新視窗,然後就是 Windows 的安裝流程,記得在 "Press any key to boot from CD" 文字出現的時候趕快按一個鍵進入安裝流程。
|
||||
來不及的話,左上角按鈕可以發送 `ctrl+alt+del` 來重新開機。
|
||||
|
||||
這邊要注意的是,一旦發生重開機的狀況,剛剛那個視窗會關掉,然後跳一堆錯誤訊息,像是:
|
||||
```
|
||||
(remote-viewer.exe:23816): GSpice-CRITICAL **: 22:48:14.989: _usbdk_hider_update: assertion 'priv->usbdk_api != NULL' failed
|
||||
|
||||
(remote-viewer.exe:23816): GLib-GIO-WARNING **: 22:48:15.475: Unexpectedly, UWP app `Microsoft.OutlookForWindows_1.2024.214.400_x64__8wekyb3d8bbwe' (AUMId `Microsoft.OutlookForWindows_8wekyb3d8bbwe!Microsoft.OutlookforWindows') supports 4 extensions but has no verbs
|
||||
|
||||
(remote-viewer.exe:23816): GLib-GIO-WARNING **: 22:48:15.598: Unexpectedly, UWP app `Microsoft.ScreenSketch_11.2401.37.0_x64__8wekyb3d8bbwe' (AUMId `Microsoft.ScreenSketch_8wekyb3d8bbwe!App') supports 29 extensions but has no verbs
|
||||
|
||||
(remote-viewer.exe:23816): GLib-GIO-WARNING **: 22:48:15.600: Unexpectedly, UWP app `Clipchamp.Clipchamp_3.0.10220.0_neutral__yxz26nhyzhsrt' (AUMId `Clipchamp.Clipchamp_yxz26nhyzhsrt!App') supports 41 extensions but has no verbs
|
||||
|
||||
(remote-viewer.exe:23816): GSpice-CRITICAL **: 22:48:15.677: _usbdk_hider_update: assertion 'priv->usbdk_api != NULL' failed
|
||||
|
||||
(remote-viewer.exe:23816): GSpice-WARNING **: 22:48:15.677: Warning no automount-inhibiting implementation available
|
||||
Error: tls: failed to send closeNotify alert (but connection was closed anyway): write tcp 192.168.1.24:8443->192.168.1.154:50714: write: broken pipe
|
||||
```
|
||||
|
||||
這時用 `incus console $VM_NAME --type=vga` 就可以再次連上已開機的虛擬機,不要用 `incus start DENNY-VM-WIN11 --console=vga`。
|
||||
只要虛擬機沒有關機,就是用 `incus console $VM_NAME --type=vga` 來連上畫面。
|
||||
關機的情況下才是用 `incus start DENNY-VM-WIN11 --console=vga` 來開機並顯示畫面。
|
||||
|
||||
再來 Windows 11 沒有網路會無法安裝,所以要跳過網路檢查,在最早的安裝畫面按 `shift+F10` 打開 command line,然後輸入:
|
||||
```
|
||||
oobe/bypassnro
|
||||
```
|
||||
|
||||
安裝之後,把虛擬機連上 macvlan。
|
||||
```shell
|
||||
sudo incus config device override $VM_NAME eth0 nictype=macvlan
|
||||
```
|
||||
|
||||
這樣虛擬機就有網路了。
|
||||
|
||||
## 虛擬機裝好之後
|
||||
### 虛擬機操作
|
||||
1. 把遠端桌面連線打開
|
||||
2. 下載 driver: [virtio-win-guest-tools.exe](https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.248-1/virtio-win-guest-tools.exe) ,然後安裝。
|
||||
|
||||
# 分享內顯給虛擬機
|
||||
## 準備
|
||||
安裝需要的套件
|
||||
```shell
|
||||
apt install build-* dkms
|
||||
```
|
||||
|
||||
確認你的 kernel 是 6.1 ~ 6.5:
|
||||
```shell
|
||||
uname -r
|
||||
# 6.5.0-26-generic
|
||||
```
|
||||
|
||||
## 安裝 i915 Driver
|
||||
下載 i915 Driver:
|
||||
```shell
|
||||
git clone https://github.com/strongtz/i915-sriov-dkms
|
||||
```
|
||||
|
||||
進到剛剛 clone 的目錄,修改 `dkms.conf`,把 `PACKAGE_NAME` 改為 `"i915-sriov-dkms"`,把 `PACKAGE_VERSION` 改為 `"6.5"`,看你的 kernel 版號多少就改多少。我的版本是 6.5 ,所以這裡填 6.5。
|
||||
```shell
|
||||
cd i915-sriov-dkms
|
||||
nano dkms.conf
|
||||
|
||||
# 前 2 行改成這樣
|
||||
# dkms.conf
|
||||
PACKAGE_NAME="i915-sriov-dkms"
|
||||
PACKAGE_VERSION="6.5"
|
||||
```
|
||||
|
||||
安裝 driver:
|
||||
```shell
|
||||
# 記得要在 i915-sriov-dkms 這目錄裡面
|
||||
dkms add .
|
||||
dkms install -m i915-sriov-dkms -v 6.5
|
||||
dkms remove -m i915-sriov-dkms -v 6.5
|
||||
dkms install -m i915-sriov-dkms -v 6.5
|
||||
```
|
||||
|
||||
如果有出現類似以下的錯誤:
|
||||
```
|
||||
update-initramfs: Generating /boot/initrd.img-6.5.0-26-generic
|
||||
W: Possible missing firmware /lib/firmware/i915/mtl_gsc_102.0.0.1511.bin for module i915
|
||||
W: Possible missing firmware /lib/firmware/i915/mtl_huc_8.4.3_gsc.bin for module i915
|
||||
W: Possible missing firmware /lib/firmware/i915/mtl_guc_70.6.4.bin for module i915
|
||||
```
|
||||
去 [https://cgit.freedesktop.org/drm/drm-firmware/refs/](https://cgit.freedesktop.org/drm/drm-firmware/refs/) 把檔案找出來,放到 `/lib/firmware/i915/` 然後再重新安裝。
|
||||
|
||||
檢查是否有安裝成功:
|
||||
```shell
|
||||
modinfo i915 | grep vf
|
||||
|
||||
# 應該要出現如下訊息
|
||||
# parm: max_vfs:Limit number of virtual functions to allocate. (0 = no VFs [default]; N = allow up to N VFs) (uint)
|
||||
```
|
||||
|
||||
如果沒有就重新安裝試試。
|
||||
|
||||
修改 grub:
|
||||
```shell
|
||||
nano /etc/default/grub
|
||||
|
||||
# "GRUB_CMDLINE_LINUX_DEFAULT" 這一行加入:"quiet intel_iommu=on i915.enable_guc=3 i915.max_vfs=7",如下:
|
||||
GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on i915.enable_guc=3 i915.max_vfs=7"
|
||||
```
|
||||
|
||||
更新 grub 和 initramfs:
|
||||
```shell
|
||||
update-initramfs -u -k all
|
||||
update-grub
|
||||
```
|
||||
|
||||
開機自動自動設定 vGPU 的數量:
|
||||
```shell
|
||||
sudo nano /etc/rc.local
|
||||
|
||||
# 加入
|
||||
echo 7 > /sys/devices/pci0000:00/0000:00:02.0/sriov_numvfs
|
||||
```
|
||||
|
||||
然後 `sudo chmod +x /etc/rc.local`
|
||||
|
||||
重開機,開機之後檢查 VGA 數量是不是有 8 個(1 個是原本的,另外 7 個是可以分享給虛擬機的 )。
|
||||
```shell
|
||||
lspci | grep 00:02
|
||||
|
||||
# 應該找到 8 個
|
||||
00:02.0 VGA compatible controller: Intel Corporation AlderLake-S GT1 (rev 0c)
|
||||
00:02.1 VGA compatible controller: Intel Corporation AlderLake-S GT1 (rev 0c)
|
||||
00:02.2 VGA compatible controller: Intel Corporation AlderLake-S GT1 (rev 0c)
|
||||
00:02.3 VGA compatible controller: Intel Corporation AlderLake-S GT1 (rev 0c)
|
||||
00:02.4 VGA compatible controller: Intel Corporation AlderLake-S GT1 (rev 0c)
|
||||
00:02.5 VGA compatible controller: Intel Corporation AlderLake-S GT1 (rev 0c)
|
||||
00:02.6 VGA compatible controller: Intel Corporation AlderLake-S GT1 (rev 0c)
|
||||
00:02.7 VGA compatible controller: Intel Corporation AlderLake-S GT1 (rev 0c)
|
||||
```
|
||||
|
||||
## 設定 vGPU 給虛擬機
|
||||
可以分享的 VGA 有 `00:02.1` ~ `00:02.7` ,然後在虛擬機裡面新增一個 device:
|
||||
```shell
|
||||
sudo incus config device add $VM_NAME gpu pci address=0000:00:02.1
|
||||
```
|
||||
|
||||
然後在操作端把虛擬機開機:
|
||||
```
|
||||
incus start $VM_NAME --console=vga
|
||||
```
|
||||
|
||||
這時後會變成黑畫面,像這樣:
|
||||
![[incus_srart_display_error.png]]
|
||||
|
||||
大概等個 1~3 分鐘就會跳出開機畫面了。
|
||||
|
||||
開機好之後,裝置管理員會出現一張顯卡,去 Windows Update 更新,就會出現 Intel UHD 770 顯示卡了。
|
||||
43
21.01. OS/21.01. Linux/smb client.md
Normal file
43
21.01. OS/21.01. Linux/smb client.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Connect to SMB folder
|
||||
## 安裝
|
||||
```shell
|
||||
sudo apt-get install cifs-utils
|
||||
```
|
||||
|
||||
## 設定
|
||||
### 建立 `~/.smbcredentials` ,用來存放帳號密碼
|
||||
```shell
|
||||
touch ~/.smbcredentials
|
||||
vim ~/.smbcredentials
|
||||
```
|
||||
|
||||
依下面格式填入
|
||||
```
|
||||
username=<your_username>
|
||||
password=<your_password>
|
||||
```
|
||||
|
||||
### 讓機器每次開機就自動掛載。
|
||||
建立掛載點
|
||||
```shell
|
||||
sudo mkdir /mnt/sambashare
|
||||
```
|
||||
`/mnt/sambashare` 改成你自己喜歡的路徑
|
||||
|
||||
打開 `/etc/fstab`,填入下面這一行:
|
||||
```
|
||||
//samba_server_ip/share_name /mnt/sambashare cifs credentials=/home/pi/.smbcredentials,uid=pi,gid=pi 0 0
|
||||
```
|
||||
|
||||
檢查
|
||||
```shell
|
||||
sudo systemctl daemon-reload
|
||||
sudo mount -a
|
||||
```
|
||||
|
||||
### 範例
|
||||
```
|
||||
//192.168.1.11/share /media/share cifs credentials=/home/awin/.smbcredentials_shareview,auto 0 0
|
||||
//192.168.1.11/upload /media/upload cifs credentials=/home/awin/.smbcredentials_shareview,auto 0 0
|
||||
//192.168.1.11/Backup /media/backup cifs credentials=/home/awin/.smbcredentials_backup,auto 0 0
|
||||
```
|
||||
86
21.01. OS/21.01. Linux/更改時區.md
Normal file
86
21.01. OS/21.01. Linux/更改時區.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# 前置條件
|
||||
|
||||
你需要有 **root** 或是 **sudo** 的權限才能更改系統的時區
|
||||
|
||||
# 檢查當前時區
|
||||
|
||||
在 Ubuntu 中,我們有三種方式查看當前時區設定
|
||||
|
||||
## 1. 使用 `timedatectl` 命令顯示當前的系統時區。
|
||||
```
|
||||
timedatectl
|
||||
```
|
||||
```result
|
||||
Local time: Fri 2021-01-07 22:45:47 UTC
|
||||
Universal time: Fri 2021-01-07 22:45:47 UTC
|
||||
RTC time: Fri 2021-01-07 22:45:48
|
||||
Time zone: Etc/UTC (UTC, +0000)
|
||||
System clock synchronized: yes
|
||||
systemd-timesyncd.service active: yes
|
||||
RTC in local TZ: no
|
||||
```
|
||||
|
||||
## 2. 查看 `/etc/localtime` 的連結指向
|
||||
```
|
||||
ls -l /etc/localtime
|
||||
```
|
||||
```result
|
||||
lrwxrwxrwx 1 root root 33 Jan 8 15:57 /etc/localtime -> ../usr/share/zoneinfo/Etc/UTC
|
||||
```
|
||||
|
||||
## 3. 查看 `/etc/timezome` 的內容
|
||||
```
|
||||
cat /etc/timezone
|
||||
```
|
||||
```result
|
||||
Etc/UTC
|
||||
```
|
||||
|
||||
# 修改時區
|
||||
|
||||
當我們檢查完時區後,接下來就是修改時區。不過假如你不知道要改的時區名稱,你可以透過以下指令來查看
|
||||
```
|
||||
timedatectl list-timezones
|
||||
```
|
||||
```result
|
||||
...
|
||||
Asia/Seoul
|
||||
Asia/Shanghai
|
||||
Asia/Singapore
|
||||
Asia/Srednekolymsk
|
||||
Asia/Taipei
|
||||
Asia/Tashkent
|
||||
Asia/Tbilisi
|
||||
Asia/Tehran
|
||||
Asia/Thimphu
|
||||
Asia/Tokyo
|
||||
...
|
||||
```
|
||||
|
||||
找到要修改的時區名稱後,接下就是以 sudo 權限執行以下命令
|
||||
```
|
||||
sudo timedatectl set-timezone 要修改的時區名稱
|
||||
```
|
||||
|
||||
例如要將系統修改為台北時區 `Asia/Taipei`,請輸入
|
||||
```
|
||||
sudo timedatectl set-timezone Asia/Taipei
|
||||
```
|
||||
|
||||
使用 `timedatectl` 指令確認時區是否正確修改
|
||||
```
|
||||
timedatectl
|
||||
```
|
||||
```result
|
||||
Local time: Fri 2021-01-08 18:38:49 CST
|
||||
Universal time: Fri 2021-01-08 10:38:49 UTC
|
||||
RTC time: Fri 2021-01-08 10:38:49
|
||||
Time zone: Asia/Taipei (CST, +0800)
|
||||
System clock synchronized: yes
|
||||
systemd-timesyncd.service active: yes
|
||||
RTC in local TZ: no
|
||||
```
|
||||
|
||||
|
||||
# 參考
|
||||
- [如何正確修改 Ubuntu 18.04 的系統時區](https://www.hanktsai.com/2021/01/configure-ubuntu1804-timezone.html)
|
||||
108
21.01. OS/21.01. Linux/架站/Apache.md
Normal file
108
21.01. OS/21.01. Linux/架站/Apache.md
Normal file
@@ -0,0 +1,108 @@
|
||||
## Install
|
||||
```
|
||||
sudo apt update && sudo apt install apache2
|
||||
```
|
||||
|
||||
## 測試Apache
|
||||
```
|
||||
sudo service apache2 status
|
||||
```
|
||||
|
||||
## 設置虛擬主機(Virtual Hosts)
|
||||
假設要建立2個網站*test1.ui-code.com*與*test2.ui-code.com*
|
||||
|
||||
### 建立目錄並設置權限(Permissions)
|
||||
```
|
||||
sudo mkdir -p /var/www/test1.ui-code.com/public_html
|
||||
sudo mkdir -p /var/www/test2.ui-code.com/public_html
|
||||
sudo chmod -R 755 /var/www
|
||||
```
|
||||
|
||||
### 建立測試頁面
|
||||
#### 建立test1.ui-code.com的測試頁面
|
||||
```
|
||||
sudo nano /var/www/test1.ui-code.com/public_html/index.html
|
||||
```
|
||||
填入以下內容:
|
||||
```html
|
||||
<html>
|
||||
<head>
|
||||
<title>Welcome to test1.ui-code.com</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Welcome to test1.ui-code.com</h2>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
#### 建立test2.ui-code.com的測試頁面
|
||||
```
|
||||
sudo nano /var/www/test2.ui-code.com/public_html/index.html
|
||||
```
|
||||
填入以下內容:
|
||||
```html
|
||||
<html>
|
||||
<head>
|
||||
<title>Welcome to test2.ui-code.com</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Welcome to test2.ui-code.com</h2>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### 建立虛擬主機文件(Virtual Host Files)
|
||||
虛擬主機文件位於 /etc/apache2/sites-available/ 中,其用於告訴 Apache 網頁伺服器如何響應(Respond )各種網域請求(Request)。
|
||||
讓我們為test1.ui-code.com 網域創建一個新的虛擬主機文件。
|
||||
```
|
||||
sudo nano /etc/apache2/sites-available/test1.ui-code.com.conf
|
||||
```
|
||||
|
||||
將以下內容貼上:
|
||||
```
|
||||
<VirtualHost *:80>
|
||||
ServerAdmin webmaster@test1.ui-code.com
|
||||
ServerName test1.ui-code.com
|
||||
ServerAlias www.test1.ui-code.com
|
||||
DocumentRoot /var/www/test1.ui-code.com/public_html
|
||||
ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||
CustomLog ${APACHE_LOG_DIR}/access.log combined
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
再來為test2.ui-code.com 網域創建一個新的虛擬主機文件。
|
||||
```
|
||||
sudo nano /etc/apache2/sites-available/test2.ui-code.com.conf
|
||||
```
|
||||
|
||||
將以下內容貼上:
|
||||
```
|
||||
<VirtualHost *:80>
|
||||
ServerAdmin webmaster@test2.ui-code.com
|
||||
ServerName test2.ui-code.com
|
||||
ServerAlias www.test2.ui-code.com
|
||||
DocumentRoot /var/www/test2.ui-code.com/public_html
|
||||
ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||
CustomLog ${APACHE_LOG_DIR}/access.log combined
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
### 啟用新的虛擬主機文件(Virtual Host Files)
|
||||
現在我們有兩個虛擬主機文件,我們需要使用 a2ensite 工具來啟用它們。
|
||||
```
|
||||
sudo a2ensite test1.ui-code.com
|
||||
sudo a2ensite test2.ui-code.com
|
||||
```
|
||||
|
||||
測試配置語法是否有錯誤。
|
||||
```
|
||||
apachectl configtest
|
||||
```
|
||||
|
||||
如果「Syntax OK」,重啟 Apache。
|
||||
```
|
||||
sudo systemctl reload apache2
|
||||
```
|
||||
|
||||
## 參考
|
||||
- [[教學][Ubuntu 架站] 在 Ubuntu 20.04 安裝 Apache 網頁伺服器,並架設多個網站(多網域) | 優程式](https://ui-code.com/archives/271)
|
||||
30
21.01. OS/21.01. Linux/架站/Gitea.md
Normal file
30
21.01. OS/21.01. Linux/架站/Gitea.md
Normal file
@@ -0,0 +1,30 @@
|
||||
## docker-compose.yml
|
||||
```yaml
|
||||
version: "3"
|
||||
|
||||
networks:
|
||||
gitea:
|
||||
external: false
|
||||
|
||||
services:
|
||||
server:
|
||||
image: gitea/gitea:latest
|
||||
container_name: gitea
|
||||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
restart: always
|
||||
networks:
|
||||
- gitea
|
||||
volumes:
|
||||
- ./data:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
ports:
|
||||
- "8020:3000"
|
||||
- "2244:22"
|
||||
```
|
||||
|
||||
## 文件
|
||||
- [Gitea Docs: Config Cheat Sheet](https://docs.gitea.io/zh-tw/config-cheat-sheet/)
|
||||
- [How to Install Gitea on Ubuntu Using Docker](https://www.digitalocean.com/community/tutorials/how-to-install-gitea-on-ubuntu-using-docker)
|
||||
97
21.01. OS/21.01. Linux/架站/Grafana-prometheus.md
Normal file
97
21.01. OS/21.01. Linux/架站/Grafana-prometheus.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# 要準備的檔案
|
||||
```
|
||||
├── data
|
||||
│ ├── grafana
|
||||
│ │ └── provisioning
|
||||
│ │ └── datasources
|
||||
│ │ └── datasources.yaml
|
||||
│ └── prometheus
|
||||
│ └── prometheus.yml
|
||||
├── docker-compose.yml
|
||||
```
|
||||
|
||||
- `docker-compose.yml`
|
||||
- `data/grafana/provisioning/datasources/datasources.yaml`
|
||||
- `data/prometheus/prometheus.yml`
|
||||
|
||||
# `docker-compose.yml`
|
||||
|
||||
```yaml hl:5
|
||||
services:
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
restart: always
|
||||
user: "1000"
|
||||
ports:
|
||||
- "8082:3000"
|
||||
volumes:
|
||||
- ./data/grafana/data:/var/lib/grafana # data path
|
||||
- ./data/grafana/grafana.ini:/etc/grafana/grafana.ini
|
||||
- ./data/grafana/provisioning/dashboards:/etc/grafana/provisioning/dashboards
|
||||
- ./data/grafana/provisioning/datasources:/etc/grafana/provisioning/datasources
|
||||
environment:
|
||||
- GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource
|
||||
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
container_name: grafana-prometheus-1
|
||||
restart: always
|
||||
command:
|
||||
- --storage.tsdb.retention.time=7d
|
||||
- --config.file=/etc/prometheus/prometheus.yml
|
||||
ports:
|
||||
- "8083:9090"
|
||||
volumes:
|
||||
- ./data/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
|
||||
|
||||
node_exporter:
|
||||
image: prom/node-exporter:latest
|
||||
restart: always
|
||||
ports:
|
||||
- "8084:9100"
|
||||
```
|
||||
|
||||
要注意 `user: "1000"` 這一行,這一行是你的 user ID,有可能會變,請用 `id -u` 確認一下。
|
||||
|
||||
# `datasources.yaml`
|
||||
|
||||
```yaml hl:6
|
||||
# datasources.yaml
|
||||
apiVersion: 1
|
||||
datasources:
|
||||
- name: Prometheus
|
||||
type: prometheus
|
||||
url: http://192.168.1.24:8083
|
||||
access: proxy
|
||||
```
|
||||
|
||||
要注意 `url: http://192.168.1.24:8083` 這一行,要更新 IP 位置。
|
||||
|
||||
# `prometheus.yml`
|
||||
|
||||
```yaml hl:11
|
||||
# prometheus.yml
|
||||
global:
|
||||
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
|
||||
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
|
||||
# scrape_timeout is set to the global default (10s).
|
||||
|
||||
scrape_configs:
|
||||
- job_name: 'node-exporter-local'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets: ['192.168.1.24:8084']
|
||||
```
|
||||
|
||||
要注意 `- targets: ['192.168.1.24:8084']` 這一行,要更新 IP 位置。
|
||||
|
||||
# Grafana template
|
||||
|
||||
template ID: `1860`
|
||||
|
||||
# 參考
|
||||
- [Docker Compose 部署监控系统 Prometheus + Grafana + Node Exporter + Cadvisor-腾讯云开发者社区-腾讯云](https://cloud.tencent.com/developer/article/2016801)
|
||||
- [基于docker-compose快速搭建Prometheus+Grafana监控系统 - 掘金](https://juejin.cn/post/7320525843737460771)
|
||||
- [Deep Dive into Using Docker Compose for Monitoring with Prometheus, Grafana, and node_exporter | by mefengl | Medium](https://medium.com/@mefengl/unknown-title-95cb5a15ce83)
|
||||
- [使用docker-compose快速部署Prometheus+grafana环境_docker-compose安装grafana-CSDN博客](https://blog.csdn.net/weixin_45070882/article/details/132104496)
|
||||
- [Dashboards | Grafana Labs](https://grafana.com/grafana/dashboards/?collector=nodeexporter&dataSource=prometheus)
|
||||
91
21.01. OS/21.01. Linux/架站/Grafana.md
Normal file
91
21.01. OS/21.01. Linux/架站/Grafana.md
Normal file
@@ -0,0 +1,91 @@
|
||||
|
||||
# 設定
|
||||
`docker-compose.yml` 如下:
|
||||
```yaml
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
container_name: grafana
|
||||
restart: always
|
||||
user: "1000" # needs to be `id -u` // alternatively chown the grafana/data dir to 472:472
|
||||
ports:
|
||||
- "8081:3000" # expose for localhost
|
||||
links:
|
||||
- influxdb
|
||||
volumes:
|
||||
- ./data/grafana/data:/var/lib/grafana # data path
|
||||
- ./data/grafana/provisioning:/etc/grafana/provisioning
|
||||
- ./data/grafana/grafana.ini:/etc/grafana/grafana.ini
|
||||
environment:
|
||||
- GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource
|
||||
|
||||
influxdb:
|
||||
image: influxdb
|
||||
ports:
|
||||
- "8082:8086"
|
||||
volumes:
|
||||
- ./data/influxdb/data:/var/lib/influxdb2
|
||||
|
||||
telegraf:
|
||||
image: telegraf
|
||||
user: telegraf:992 # Get 992 by `stat -c '%g' /var/run/docker.sock`, depend on system
|
||||
depends_on:
|
||||
- influxdb
|
||||
links:
|
||||
- influxdb
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- ./data/telegraf/telegraf.conf:/etc/telegraf/telegraf.conf:ro
|
||||
environment:
|
||||
- HOST_PROC=/proc
|
||||
- HOST_SYS=/sys
|
||||
- HOST_ETC=/etc
|
||||
```
|
||||
|
||||
檔案結構如下:
|
||||
```
|
||||
data\
|
||||
grafana\
|
||||
grafana.ini
|
||||
telegraf\
|
||||
telegraf.conf
|
||||
docker-compose.yml
|
||||
```
|
||||
|
||||
`data/grafana/grafana.ini` 與 `data/telegraf/telegraf.conf` 都是需要事先準備好的檔案。
|
||||
|
||||
## 設定 InfluxDB
|
||||
|
||||
先把 docker 建立起來,然後打開 influxdb([http://awinpi4:8082](http://awinpi4:8082/)),建立帳號、密碼、資料庫名稱。如下:
|
||||
![[20240217_212138_chrome_setup_influxdb.png]]
|
||||
|
||||
之後會出現一串Token,如下,這個要記起來。
|
||||
![[20240217_212319_chrome_1894x1254_influxdb_token.png]]
|
||||
|
||||
## 設定 telegraf
|
||||
然後打開 `./data/telegraf/telegraf.conf` ,找到 `[[outputs.influxdb_v2]]` 這個區塊,把 `urls`、`organization`、`bucket`、`token` 的值改為剛剛建立與複製的那一串。如圖:
|
||||
![[20240217_213900_Code_setup_telegraf_ini.png]]
|
||||
然後重啟 docker compose。
|
||||
|
||||
# 設定 InfluxDB 的 dashboard
|
||||
|
||||
到 [https://github.com/influxdata/community-templates#templates](https://github.com/influxdata/community-templates#templates) 挑一個 template,例如 [Raspberry Pi System Template](https://github.com/influxdata/community-templates/tree/master/raspberry-pi),找到他的網址,如下:
|
||||
![[20240217_213108_chrome_1864x1044_raspberrypi_template_on_github.png]]
|
||||
|
||||
複製這一行,然後到 InfluxDB 的 template 去把它 import 進來。如下:
|
||||
![[20240217_213237_chrome_2753x1254_setup_influxdb.png]]
|
||||
|
||||
![[20240217_213311_chrome_2753x1254_influxdb_install_template.png]]
|
||||
|
||||
接著 Dashboards 就會出現一個 Raspberry Pi System 的 dashboard 了。
|
||||
![[20240217_213343_chrome_1624x1120_influxdb_dashboard.png]]
|
||||
|
||||
點下去之後大概是長這樣:
|
||||
![[20240217_214001_chrome_2604x1716_influxdb_dashboard.png]]
|
||||
|
||||
# 參考
|
||||
- [建構 Grafana + Influxdb v2.0 + Telegraf 監控系統(docker版) - DSA Learning](https://dsalearning.github.io/grafana/influxdb-telegraf-docker/)
|
||||
- [Raspberry Pi, InfluxDB, Grafana, Docker | by Anton Karazeev | Medium](https://medium.com/@antonkarazeev/raspberry-pi-influxdb-grafana-docker-a526575d6e6f#id_token=eyJhbGciOiJSUzI1NiIsImtpZCI6ImVkODA2ZjE4NDJiNTg4MDU0YjE4YjY2OWRkMWEwOWE0ZjM2N2FmYzQiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiIyMTYyOTYwMzU4MzQtazFrNnFlMDYwczJ0cDJhMmphbTRsamRjbXMwMHN0dGcuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyMTYyOTYwMzU4MzQtazFrNnFlMDYwczJ0cDJhMmphbTRsamRjbXMwMHN0dGcuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDM4MDc4MzIzNTMyNTIzMDc3NDYiLCJlbWFpbCI6ImF3aW5odWFuZ0BnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmJmIjoxNzA4MTQ1MjU3LCJuYW1lIjoiQXdpbiBIdWFuZyIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS9BQ2c4b2NJZjNQY0d3WjZIcDdYM204b3BjczRlNGVlZnBHQ1pGeVdMamExcjNTVVNKd1ZnPXM5Ni1jIiwiZ2l2ZW5fbmFtZSI6IkF3aW4iLCJmYW1pbHlfbmFtZSI6Ikh1YW5nIiwibG9jYWxlIjoiemgtVFciLCJpYXQiOjE3MDgxNDU1NTcsImV4cCI6MTcwODE0OTE1NywianRpIjoiNzBmNjI3NDFiNzhiYmVlMTYwNjBiZWRlOTY2YmFjYTAyZTY0ZTZkOSJ9.SXAVZ3SXny4YjIc9Cg6fNFHlXKe0jrm-4uwJ7KH41Tmo_vRAQGlbUn7MmVHXWexpKdpMCSVECC8C1VuUielC-vm8AoHMs1PLJCyhdg02hUyTqEMA08ydscfjguGP6kuI3LoMVsxkAl51C06lQi8llYZ4XGkdHxhCWP12fXQStdGPfv-64KNCkPTIfI7Teo7sfJGyjSQsDMRa4v9GWS9qmbCqut06fhpLyj0lEVfntratbuTN8ThekVfuJyJyG29U6xclm1O0NgBp-BnXML_YtBxTBV2Td_DRYY0dfcVivDKxzH135FfY5xpp_2ZIewkjJG5-pTHpin1R_XLVmIhXuA)
|
||||
- [Raspberry Pi 4 使用 Grafana 监控_influxdb and grafana on raspberrypi-CSDN博客](https://blog.csdn.net/u013360850/article/details/115568985)
|
||||
143
21.01. OS/21.01. Linux/架站/Nextcloud.md
Normal file
143
21.01. OS/21.01. Linux/架站/Nextcloud.md
Normal file
@@ -0,0 +1,143 @@
|
||||
## docker-compose.yml
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
app:
|
||||
image: nextcloud
|
||||
ports:
|
||||
- 8080:80
|
||||
volumes:
|
||||
- ./data:/var/www/html
|
||||
restart: always
|
||||
```
|
||||
|
||||
## config.php
|
||||
Nextcloud 的 config 檔放在`/var/www/html/config/config.php`,對應到本機就是 `./data/config/config.php`,在安裝完成之後,需要修改 `trusted_domains`、`overwriteprotocol`、`overwrite.cli.url` 這幾個參數,如下:
|
||||
```php
|
||||
<?php
|
||||
$CONFIG = array (
|
||||
'htaccess.RewriteBase' => '/',
|
||||
'memcache.local' => '\\OC\\Memcache\\APCu',
|
||||
'apps_paths' =>
|
||||
array (
|
||||
0 =>
|
||||
array (
|
||||
'path' => '/var/www/html/apps',
|
||||
'url' => '/apps',
|
||||
'writable' => false,
|
||||
),
|
||||
1 =>
|
||||
array (
|
||||
'path' => '/var/www/html/custom_apps',
|
||||
'url' => '/custom_apps',
|
||||
'writable' => true,
|
||||
),
|
||||
),
|
||||
'memcache.distributed' => '\\OC\\Memcache\\Redis',
|
||||
'memcache.locking' => '\\OC\\Memcache\\Redis',
|
||||
'redis' =>
|
||||
array (
|
||||
'host' => 'redis',
|
||||
'password' => '',
|
||||
'port' => 6379,
|
||||
),
|
||||
'upgrade.disable-web' => true,
|
||||
'instanceid' => 'och3g4qo42hq',
|
||||
'passwordsalt' => 'kASfV5cf4Rh+EcvGNKQkmK01HD2UbI',
|
||||
'secret' => 'Vze6ZS+qgeOmacEn3ctbtV3uZaEpzeJDufjkkm4A9lgmUYpF',
|
||||
'trusted_domains' =>
|
||||
array (
|
||||
0 => 'nc.awin.one',
|
||||
),
|
||||
'datadirectory' => '/var/www/html/data',
|
||||
'dbtype' => 'mysql',
|
||||
'version' => '28.0.3.2',
|
||||
'dbname' => 'nextcloud',
|
||||
'dbhost' => 'db',
|
||||
'dbport' => '',
|
||||
'dbtableprefix' => 'oc_',
|
||||
'mysql.utf8mb4' => true,
|
||||
'dbuser' => 'nextcloud',
|
||||
'dbpassword' => 'F5vy&46Fzbn:hFnlHji.sWfS*SP~wC',
|
||||
'overwriteprotocol' => 'https',
|
||||
'overwrite.cli.url' => 'https://nc.awin.one',
|
||||
'maintenance_window_start' => 1,
|
||||
'default_phone_region' => 'TWN',
|
||||
'installed' => true,
|
||||
'mail_smtpmode' => 'smtp',
|
||||
'mail_sendmailmode' => 'smtp',
|
||||
'mail_from_address' => 'awinhuang',
|
||||
'mail_domain' => 'gmail.com',
|
||||
'mail_smtphost' => 'smtp.gmail.com',
|
||||
'mail_smtpport' => '587',
|
||||
'mail_smtpauth' => 1,
|
||||
'mail_smtpname' => 'awinhuang@gmail.com',
|
||||
'mail_smtppassword' => 'stcg ozpc ypsl enbp',
|
||||
'maintenance' => false,
|
||||
'loglevel' => 2,
|
||||
);
|
||||
```
|
||||
|
||||
## 遇到的問題
|
||||
1. 你經由安全的連線存取系統,但系統卻生成了不安全的 URL。這很有可能是因為你使用了反向代理伺服器,但反向代理伺服器的改寫規則並未正常工作,請閱讀關於此問題的文件頁面 ↗。
|
||||
1. 在 `config/config/php` 新增
|
||||
```
|
||||
'overwriteprotocol' => 'https',
|
||||
'overwrite.cli.url' => 'https://nc.awin.one',
|
||||
```
|
||||
這兩行
|
||||
|
||||
2. 增加 cron: `nextcloud_clean.sh` 在 crontab
|
||||
1. `*/5 * * * * /home/awin/script/nextcloud_clean.sh`
|
||||
|
||||
3. 伺服器未設定維護時段的開始時間。這代表了每天耗費大量資源的背景作業也會在您主要使用的時間內執行。我們建議將其設定為低使用率的時間,以減少使用者受到這些繁重任務帶來的負載影響。
|
||||
1. 在 `config/config/php` 增加 `'maintenance_window_start' => 1,`
|
||||
|
||||
4. 您並未設定手機國際冠碼。設定後使用者在個人檔案設定手機號碼時不必再輸入國際冠碼。若要這樣做,請新增「default_phone_region」至設定檔,允許的國家及地區請參閱 ISO 3166-1 code 清單。
|
||||
1. 在 `config/config/php` 增加 `'default_phone_region' => 'TWN',`
|
||||
|
||||
5. 您尚未為 WOPI 請求設定允許清單。若無此設定,使用者可以透過 WOPI 請求將受限制的檔案下載至 Nextcloud 伺服器
|
||||
|
||||
6. 此站台缺少一些建議的 PHP 模組。為了改善效能與相容性,強烈建立您安裝這些模組:bz2
|
||||
|
||||
7. How to know if redis is being used
|
||||
```
|
||||
docker exec -it redis /bin/sh
|
||||
cd
|
||||
redis-cli monitor
|
||||
ctrl+c
|
||||
```
|
||||
|
||||
8. gmail app password for nextcloud: `stcg ozpc ypsl enbp`
|
||||
|
||||
9. 大檔案無法上傳
|
||||
1. 改善傳輸的效率: `sudo docker exec -u 33 e84abbefd5ed php occ config:app:set files max_chunk_size --value 0`
|
||||
2. `docker-compose.yml` 要增加 3 個 environment:
|
||||
```yaml
|
||||
- PHP_MEMORY_LIMIT=10240M
|
||||
- PHP_UPLOAD_LIMIT=10240M
|
||||
- POST_MAX_SIZE=10240
|
||||
```
|
||||
3. ReverseProxy 要增加:
|
||||
|
||||
### 大檔案無法上傳
|
||||
1. 改善傳輸的效率: `sudo docker exec -u 33 e84abbefd5ed php occ config:app:set files max_chunk_size --value 0`
|
||||
2. `docker-compose.yml` 要增加 3 個 environment:
|
||||
```yaml
|
||||
- PHP_MEMORY_LIMIT=10240M
|
||||
- PHP_UPLOAD_LIMIT=10240M
|
||||
- POST_MAX_SIZE=10240
|
||||
```
|
||||
3. ReverseProxy 要增加:
|
||||
```yaml
|
||||
client_max_body_size 0;
|
||||
fastcgi_read_timeout 600;
|
||||
fastcgi_send_timeout 600;
|
||||
fastcgi_connect_timeout 600;
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
send_timeout 600;
|
||||
```````
|
||||
4. 上傳檔案時遇到 "server repliedL Not Found": `sudo docker exec -u 33 e84abbefd5ed php occ files:scan --all`
|
||||
26
21.01. OS/21.01. Linux/架站/Pelican blog.md
Normal file
26
21.01. OS/21.01. Linux/架站/Pelican blog.md
Normal file
@@ -0,0 +1,26 @@
|
||||
## Create a site
|
||||
Use `pelican-quickstart` to create a new site.
|
||||
|
||||
## Plugin
|
||||
```bash
|
||||
git clone --recursive https://github.com/getpelican/pelican-plugins.git
|
||||
```
|
||||
|
||||
## Theme
|
||||
先把所有佈景主題都clone下來:
|
||||
```bash
|
||||
git clone --recursive https://github.com/getpelican/pelican-themes.git
|
||||
```
|
||||
|
||||
把`pelicanconf.py`裡面的`THEME`指向theme的目錄就可以換佈景主題了。例如要用[[blue-penguin](https://github.com/jody-frankowski/blue-penguin)]這一個主題。把`pelicanconf.py`裡面加入`THEME = 'pelican-themes/blue-penguin'`就可以了。
|
||||
|
||||
## 預覽
|
||||
```
|
||||
make html
|
||||
make serve
|
||||
```
|
||||
|
||||
參考:
|
||||
- [koko's Note – Python - 安裝 Pelican Theme 來改變你的靜態網站主題](https://note.koko.guru/install-pelican-theme.html)
|
||||
- [nest theme](https://github.com/molivier/nest)
|
||||
- [Flex theme](https://github.com/alexandrevicenzi/Flex/wiki/Custom-Settings)
|
||||
260
21.01. OS/21.01. Linux/架站/Proxmox VE.md
Normal file
260
21.01. OS/21.01. Linux/架站/Proxmox VE.md
Normal file
@@ -0,0 +1,260 @@
|
||||
# 安裝
|
||||
## 下載ISO
|
||||
- [Get the free Proxmox VE ISO installer](https://www.proxmox.com/en/downloads/category/iso-images-pve)
|
||||
|
||||
## 準備USB disk
|
||||
- 用[Rufus](https://rufus.ie/)的話
|
||||
1. 在遇到詢問是否要下載 Grub 時,請選擇「否」
|
||||
2. 必須使用DD mode來建立開機碟。(參考:[Prepare Installation Media - Proxmox VE](https://pve.proxmox.com/wiki/Prepare_Installation_Media#_instructions_for_windows))
|
||||
![[Pasted image 20210128212917.png]]
|
||||
|
||||
# 設定
|
||||
## 關閉「闔上螢幕後休眠」
|
||||
打開`/etc/systemd/logind.conf`:
|
||||
```
|
||||
nano /etc/systemd/logind.conf
|
||||
```
|
||||
找到下面兩行,把值改成ignore:
|
||||
```
|
||||
HandleLidSwitch=ignore
|
||||
HandleLidSwitchDocked=ignore
|
||||
```
|
||||
然後重開機:
|
||||
```
|
||||
systemctl restart systemd-logind.service
|
||||
```
|
||||
圖示:
|
||||
![[Pasted image 20210129194144.png]]
|
||||
|
||||
## 增加硬碟
|
||||
先用`lsblk`列出所有硬碟,這裡假設`sda`是我們的開機磁碟,我要要新增`sdb`:
|
||||
```
|
||||
root@pve:~# lsblk
|
||||
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
|
||||
sda 8:0 0 931.5G 0 disk <-- 目前在用的
|
||||
├─sda1 8:1 0 1007K 0 part
|
||||
├─sda2 8:2 0 512M 0 part
|
||||
└─sda3 8:3 0 931G 0 part
|
||||
sdb 8:16 0 111.8G 0 disk <-- 要新增的
|
||||
├─sdb1 8:17 0 100M 0 part
|
||||
├─sdb2 8:18 0 16M 0 part
|
||||
├─sdb3 8:19 0 111.1G 0 part
|
||||
└─sdb4 8:20 0 563M 0 part
|
||||
```
|
||||
|
||||
然後安裝`parted`,我們要用它來分割硬碟:
|
||||
```
|
||||
apt install parted
|
||||
```
|
||||
|
||||
開始分割:
|
||||
```
|
||||
parted /dev/sdb mklabel gpt
|
||||
```
|
||||
|
||||
建立primary partition,格式為`ext4`:
|
||||
```
|
||||
parted -a opt /dev/sdb mkpart primary ext4 0% 100%
|
||||
```
|
||||
|
||||
再來將分割好的硬碟格式化為`ext4`,label命名為`data2`:
|
||||
```
|
||||
mkfs.ext4 -L data2 /dev/sdb1
|
||||
```
|
||||
|
||||
再用`lsblk`看一次,會發現sdb已經重新分割成1個partition了:
|
||||
```
|
||||
root@pve:~# lsblk
|
||||
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
|
||||
sda 8:0 0 931.5G 0 disk
|
||||
├─sda1 8:1 0 1007K 0 part
|
||||
├─sda2 8:2 0 512M 0 part
|
||||
└─sda3 8:3 0 931G 0 part
|
||||
sdb 8:16 0 111.8G 0 disk
|
||||
└─sdb1 8:17 0 111.8G 0 part
|
||||
```
|
||||
|
||||
用`lsblk -fs`可以看到每一個硬碟的檔案系統格式:
|
||||
```
|
||||
root@pve:~# lsblk -fs
|
||||
NAME FSTYPE LABEL UUID FSAVAIL FSUSE% MOUNTPOINT
|
||||
sda1 zfs_member rpool 11775123664036754029
|
||||
└─sda zfs_member rpool 11775123664036754029
|
||||
sda2 vfat rpool 32D0-3449
|
||||
└─sda zfs_member rpool 11775123664036754029
|
||||
sda3 zfs_member rpool 11775123664036754029
|
||||
└─sda zfs_member rpool 11775123664036754029
|
||||
sdb1 ext4 data2 bc6d2c41-a3ca-4b0f-a5de-51ee28ae9cec <-- 剛剛分割的
|
||||
└─sdb
|
||||
```
|
||||
|
||||
接下來,將新硬碟掛載到檔案目錄上,先建立一個新目錄來掛載新硬碟:
|
||||
```shell
|
||||
mkdir -p /mnt/data
|
||||
```
|
||||
|
||||
接下來編輯`/etc/fstab`,將新硬碟寫進來,這樣開機之後才會自動把它掛載起來:
|
||||
```
|
||||
nano /etc/fstab
|
||||
```
|
||||
加入這一行(注意:**data2**要改成你自己的label):
|
||||
```
|
||||
LABEL=data2 /mnt/data ext4 defaults 0 2
|
||||
```
|
||||
|
||||
剛新硬碟掛起來:
|
||||
```
|
||||
mount -a
|
||||
```
|
||||
|
||||
用`df`就可以看到新硬碟了:
|
||||
```
|
||||
root@pve:~# df
|
||||
Filesystem 1K-blocks Used Available Use% Mounted on
|
||||
udev 16288892 0 16288892 0% /dev
|
||||
tmpfs 3262688 9324 3253364 1% /run
|
||||
rpool/ROOT/pve-1 942667136 1267584 941399552 1% /
|
||||
tmpfs 16313440 43680 16269760 1% /dev/shm
|
||||
tmpfs 5120 0 5120 0% /run/lock
|
||||
tmpfs 16313440 0 16313440 0% /sys/fs/cgroup
|
||||
rpool 941399680 128 941399552 1% /rpool
|
||||
rpool/data 941399680 128 941399552 1% /rpool/data
|
||||
rpool/ROOT 941399680 128 941399552 1% /rpool/ROOT
|
||||
/dev/fuse 30720 16 30704 1% /etc/pve
|
||||
tmpfs 3262688 0 3262688 0% /run/user/0
|
||||
/dev/sdb1 114854020 61464 108915208 1% /mnt/data <-- 新硬碟在這裡
|
||||
```
|
||||
|
||||
參考:
|
||||
- [How to add storage to Proxmox](https://nubcakes.net/index.php/2019/03/05/how-to-add-storage-to-proxmox/)
|
||||
|
||||
## 增加iSCSI磁碟
|
||||
### 增加需要CHAP認證的iSCSI磁碟
|
||||
1. 先確認找的到iSCSI磁碟
|
||||
```
|
||||
iscsiadm -m discovery -t st -p 192.168.1.11:3260
|
||||
```
|
||||
如果有找到的話會回傳一串IQN值,像是:
|
||||
```
|
||||
root@pve:~# iscsiadm -m discovery -t st -p 192.168.1.11:3260
|
||||
192.168.1.11:3260,1 iqn.2000-01.com.synology:DiskStation.Target-1.3e589efea3
|
||||
[fe80::211:32ff:fe20:eadd]:3260,1 iqn.2000-01.com.synology:DiskStation.Target-1.3e589efea3
|
||||
```
|
||||
2. 有IQN就可以用下列的命令連線與掛載:
|
||||
```
|
||||
iscsiadm -m node -T iqn.2000-01.com.synology:DiskStation.Target-1.3e589efea3 --op update --name node.session.auth.username --value=名字
|
||||
iscsiadm -m node -T iqn.2000-01.com.synology:DiskStation.Target-1.3e589efea3 --op update --name node.session.auth.password --value=密碼
|
||||
iscsiadm -m node -T iqn.2000-01.com.synology:DiskStation.Target-1.3e589efea3 -l #連線
|
||||
iscsiadm -m node -o update -n node.startup -v automatic #設定開機自動掛載
|
||||
```
|
||||
|
||||
## 增加NFS磁碟
|
||||
1. 先在Synology上開一個NFS disk,設定如下:
|
||||
![[Pasted image 20220506091522.png]]
|
||||
2. 再到Proxmox的 Datacenter->Storage->Add 來增加一個 *NFS*,設定如下
|
||||
![[Pasted image 20220506091624.png]]
|
||||
|
||||
### 更改NFS mount為soft
|
||||
1. 編輯`/etc/pve/storage.cfg`
|
||||
2. 做如下修改
|
||||
![[Pasted image 20220506095531.png]]
|
||||
|
||||
### 參考
|
||||
- [[經驗分享]Proxmox VE 採用 NFS 連接儲存的重點事項](http://blog.jason.tools/2019/02/pve-nfs-mount.html)
|
||||
|
||||
## 設定VM備份目錄
|
||||
如果將VM或LXC備份到某個目錄,先建立要備份的目錄:
|
||||
```shell
|
||||
mkdir -p /mnt/data/backup/
|
||||
```
|
||||
|
||||
再來用WEB UI,操作如下:
|
||||
![[Pasted image 20210129202041.png]]
|
||||
![[Pasted image 20210129202047.png]]
|
||||
|
||||
最後再到 Datacenter->Backups,建立一個scheule來備份就可以了:
|
||||
![[Pasted image 20210129202231.png]]
|
||||
|
||||
## 將資料備份到NAS
|
||||
1. 先在NAS開一個share folder跟一個帳號。
|
||||
![[Pasted image 20210202190402.png]]
|
||||
![[Pasted image 20210202190537.png]]
|
||||
2. Proxmox:到裡將剛剛新開的folder給掛載起來。
|
||||
![[Pasted image 20210202190640.png]]
|
||||
會跳出一個視窗,如下圖來填,記得**content**那一欄有4個要選。
|
||||
![[Pasted image 20210202190709.png]]
|
||||
3. Proxmox:到 Datacenter->Backup 新增一個排程。
|
||||
![[Pasted image 20210202190903.png]]
|
||||
一樣會跳出一個視窗,依需求來填,要注意的是**Storage**必須是前一步驟的**ID**,**Selection Mode**可以選擇**All**。
|
||||
![[Pasted image 20210202191150.png]]
|
||||
|
||||
參考:
|
||||
- [HASS + Proxmox: Automatic Backups to Synology NAS](https://kleypot.com/automatic-offline-backups/)
|
||||
|
||||
## 設定 UPS
|
||||
因為 UPS 的 USB 是連接在 NAS 上,所以Proxmox這邊必須要去monitor NAS那邊所回報的狀態,請確定NAS端有打開「啟用網路不斷電系統伺服器」。
|
||||
1. 安裝 nut:`apt-get install nut`
|
||||
2. 修改 `/etc/nut/nut.conf`,設定 `MODE=netclient`
|
||||
3. 修改 `/etc/nut/upsmon.conf`,加入一行:`MONITOR ups@<NAS_IP> 1 <NAS_Username> <NAS_UserPassword> slave`
|
||||
4. 開始 upsmon:`upsmon start`
|
||||
5. 用 `ps -ef | grep upsmon` 確認 upsmon是否執行:
|
||||
![[Pasted image 20220811145852.png|600]]
|
||||
6. 若正常,可以取回UPS的一些硬體資料,`upsc ups@<NAS_IP>`
|
||||
![[Pasted image 20220811150034.png|360]]
|
||||
|
||||
### 參考
|
||||
- [UPSMON(8)](https://networkupstools.org/docs/man/upsmon.html)
|
||||
- [不斷電系統 | DSM - Synology 知識中心](https://kb.synology.com/zh-tw/DSM/help/DSM/AdminCenter/system_hardware_ups?version=6)
|
||||
- [設定 Proxmox VE連動Synology的不斷電系統](https://cychien.tw/wordpress/2022/02/02/%E8%A8%AD%E5%AE%9A-proxmox-ve%E9%80%A3%E5%8B%95synology%E7%9A%84%E4%B8%8D%E6%96%B7%E9%9B%BB%E7%B3%BB%E7%B5%B1/)
|
||||
|
||||
## 更新
|
||||
### 加入更新來源
|
||||
編輯`/etc/apt/sources.list`,加入:
|
||||
```
|
||||
deb http://ftp.debian.org/debian bullseye main contrib
|
||||
deb http://ftp.debian.org/debian bullseye-updates main contrib
|
||||
|
||||
# PVE pve-no-subscription repository provided by proxmox.com,
|
||||
# NOT recommended for production use
|
||||
deb http://download.proxmox.com/debian/pve bullseye pve-no-subscription
|
||||
|
||||
# security updates
|
||||
deb http://security.debian.org/debian-security bullseye-security main contrib
|
||||
```
|
||||
|
||||
### 取消訂閱服務
|
||||
編輯`/etc/apt/sources.list.d/pve-enterprise.list`,把下面這行注釋掉:
|
||||
```
|
||||
deb https://enterprise.proxmox.com/debian/pve buster pve-enterprise
|
||||
```
|
||||
也就是變成:
|
||||
```
|
||||
#deb https://enterprise.proxmox.com/debian/pve buster pve-enterprise
|
||||
```
|
||||
|
||||
使用`apt update`來更新套件。
|
||||
使用`apt dist-upgrade`來升級系統版本。
|
||||
|
||||
## 重灌後要做的事情
|
||||
1. 建立ZFS pool。
|
||||
2. 確認S.M.A.R.T. 是否啟用,預設是啟用的。
|
||||
`smartctl -a /dev/<SDA_N>`
|
||||
1. 打開IOMMU
|
||||
2. 打開vm aware
|
||||
3. 增加NFS共享磁碟
|
||||
4. 排程備份
|
||||
5. 上傳安裝Windows需要的驅動ISO
|
||||
1. [Windows VirtIO Drivers](https://pve.proxmox.com/wiki/Windows_VirtIO_Drivers)
|
||||
6. 把常用的VM轉為template
|
||||
7. 安裝[Cockpit-Linux Server](https://pvecli.xuan2host.com/cockpit/), 讓您的PVE有更棒的圖形管理介面。
|
||||
|
||||
## 參考
|
||||
- [套件功能的更新(Proxmox update)](https://wiki.freedomstu.com/books/proxmox-ve-%E8%99%9B%E6%93%AC%E7%B3%BB%E7%B5%B1%E8%A8%98%E9%8C%84/page/%E5%A5%97%E4%BB%B6%E5%8A%9F%E8%83%BD%E7%9A%84%E6%9B%B4%E6%96%B0%EF%BC%88proxmox-update%EF%BC%89)
|
||||
- [裝完PVE後的11件必作清單 (中文翻譯)](https://www.youtube.com/watch?v=pY4Lm2Hoqik)
|
||||
- [Before I do anything on Proxmox, I do this first...](https://www.youtube.com/watch?v=GoZaMgEgrHw&t=0s)
|
||||
|
||||
# Trouble shooting
|
||||
- *Emergency mode*,表示開機失敗,請檢查`/etc/fstab`是不是有無法掛載的disk。
|
||||
|
||||
## 參考
|
||||
- [[Fix] Getting out of emergency mode : Proxmox](https://www.reddit.com/r/Proxmox/comments/hai75k/fix_getting_out_of_emergency_mode/)
|
||||
120
21.01. OS/21.01. Linux/架站/Storj.md
Normal file
120
21.01. OS/21.01. Linux/架站/Storj.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# 步驟摘要
|
||||
1. 到[https://www.storj.io/host-a-node](https://www.storj.io/host-a-node)申請一個auth token。
|
||||
2. 用identify產生key。
|
||||
3. 認證 key。
|
||||
4. 備份 key
|
||||
5. Setup storj docker。
|
||||
6. Run storj docker。
|
||||
7. 更新
|
||||
|
||||
# 1. 申請一個auth token
|
||||
到[https://www.storj.io/host-a-node](https://www.storj.io/host-a-node),填入email,會產生一個伴隨email的隨機碼。
|
||||
![[Pasted image 20240114200907.png]]
|
||||
|
||||
這一串要記下來。
|
||||
|
||||
# 用identify產生key
|
||||
## 下載
|
||||
### Windows
|
||||
下載 `https://github.com/storj/storj/releases/latest/download/identity_windows_amd64.zip`
|
||||
|
||||
### Linux
|
||||
#### X86
|
||||
```bash
|
||||
curl -L https://github.com/storj/storj/releases/latest/download/identity_linux_amd64.zip -o identity_linux_amd64.zip
|
||||
unzip -o identity_linux_amd64.zip
|
||||
chmod +x identity
|
||||
sudo mv identity /usr/local/bin/identity
|
||||
```
|
||||
|
||||
#### ARM
|
||||
```bash
|
||||
curl -L https://github.com/storj/storj/releases/latest/download/identity_linux_arm.zip -o identity_linux_arm.zip
|
||||
unzip -o identity_linux_arm.zip
|
||||
chmod +x identity
|
||||
sudo mv identity /usr/local/bin/identity
|
||||
```
|
||||
|
||||
## 產生 identity
|
||||
這一步會跑很久,建議用CPU比較強的來跑,在樹莓派上面會跑很久。
|
||||
|
||||
### Windows
|
||||
`./identity.exe create storagenode`
|
||||
|
||||
### Linux
|
||||
`identity create storagenode`
|
||||
|
||||
# 認證 Key
|
||||
## 認證
|
||||
等一下的 `<email:characterstring>` 就是第1步說要記起來的那一串
|
||||
|
||||
### Windows
|
||||
`./identity.exe authorize storagenode <email:characterstring>`
|
||||
|
||||
### Linux
|
||||
`identity authorize storagenode <email:characterstring>`
|
||||
|
||||
## 確認
|
||||
### Windows
|
||||
`(sls BEGIN "$env:AppData\Storj\Identity\storagenode\ca.cert").count` 應該要return 2
|
||||
`(sls BEGIN "$env:AppData\Storj\Identity\storagenode\identity.cert").count` 應該要return 3
|
||||
|
||||
### Linux
|
||||
`grep -c BEGIN ~/.local/share/storj/identity/storagenode/ca.cert` 應該要return 2
|
||||
`grep -c BEGIN ~/.local/share/storj/identity/storagenode/identity.cert` 應該要return 3
|
||||
|
||||
# 備份 key
|
||||
Windows 上產生的 key 會放在 `%APPDATA%\Storj\Identity\storagenode`。
|
||||
Linux 上產生的 key 會放在 `~/.local/share/storj/identity/storagenode`。
|
||||
記得備份。
|
||||
|
||||
# Setup storj docker
|
||||
Do this **once**.
|
||||
```bash
|
||||
sudo docker run --rm -e SETUP="true" \
|
||||
--mount type=bind,source="/home/awin/storj/key",destination=/app/identity \
|
||||
--mount type=bind,source="/home/awin/storj/data",destination=/app/config \
|
||||
--name storagenode storjlabs/storagenode:latest
|
||||
```
|
||||
|
||||
# Run storj docker
|
||||
```bash
|
||||
sudo docker run -d --restart always --stop-timeout 300 \
|
||||
-p 28967:28967/tcp \
|
||||
-p 28967:28967/udp \
|
||||
-p 14002:14002 \
|
||||
-e WALLET="0x9Ce80345355Ad8C17991620E13d8423900CEDcd0" \
|
||||
-e EMAIL="awinhuang@gmail.com" \
|
||||
-e ADDRESS="storj.awin.one:28967" \
|
||||
-e STORAGE="1800GB" \
|
||||
--memory=800m \
|
||||
--log-opt max-size=50m \
|
||||
--log-opt max-file=10 \
|
||||
--sysctl net.ipv4.tcp_fastopen=3 \
|
||||
--mount type=bind,source=/home/awin/storj/key,destination=/app/identity \
|
||||
--mount type=bind,source=/extusb1/storj,destination=/app/config \
|
||||
--name storagenode storjlabs/storagenode:latest
|
||||
```
|
||||
|
||||
# 更新
|
||||
更新 node 可以選擇用 docker 裝[storjlabs/watchtower](https://hub.docker.com/r/storjlabs/watchtower/tags) ,或是手動更新
|
||||
|
||||
## watchtower
|
||||
```shell
|
||||
sudo docker pull storjlabs/watchtower
|
||||
sudo docker run -d --restart=always --name watchtower -v /var/run/docker.sock:/var/run/docker.sock storjlabs/watchtower storagenode watchtower --stop-timeout 300s
|
||||
```
|
||||
|
||||
等 [[Watchtower|Watchtower]] 跑起來之後,可以用 `sudo docker exec -it storagenode /app/dashboard.sh` 來即時觀察執行流量。
|
||||
|
||||
## 手動
|
||||
```shell
|
||||
sudo docker stop -t 300 storagenode
|
||||
sudo docker rm storagenode
|
||||
sudo docker pull storjlabs/storagenode:latest
|
||||
```
|
||||
|
||||
# 參考
|
||||
- [Step 2. Get an Authorization Token - Storj Docs](https://docs.storj.io/node/get-started/auth-token)
|
||||
- [Step 5. Create an Identity - Storj Docs](https://docs.storj.io/node/get-started/identity)
|
||||
- [Install storagenode on Raspberry Pi3 or higher version – Storj](https://support.storj.io/hc/en-us/articles/360026612332-Install-storagenode-on-Raspberry-Pi3-or-higher-version)
|
||||
25
21.01. OS/21.01. Linux/架站/_Server Map.canvas
Normal file
25
21.01. OS/21.01. Linux/架站/_Server Map.canvas
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"nodes":[
|
||||
{"id":"c910b905ac74e6ac","type":"group","x":20,"y":-700,"width":660,"height":860,"label":"Dockers"},
|
||||
{"id":"07f9200cb8cda96b","type":"group","x":340,"y":-360,"width":320,"height":362,"label":"grafana"},
|
||||
{"id":"6156176d915b8a66","type":"group","x":340,"y":-640,"width":320,"height":220,"label":"Nextcloud"},
|
||||
{"id":"f33aa20a0c8167ec","type":"text","text":"### blog\n- \"8010:80\"","x":40,"y":-445,"width":280,"height":90},
|
||||
{"id":"7ac25f505df8f886","type":"text","text":"### portainer\n- 8000:8000\n- 2443:9443","x":40,"y":-560,"width":280,"height":100},
|
||||
{"id":"f68bc5941384884f","type":"text","text":"### nginx-certbot\n- 80:80\n- 443:443","x":40,"y":-680,"width":280,"height":100},
|
||||
{"id":"daa7f9a1b63e3a74","type":"text","text":"### nextcloud\n- 8080:80","x":360,"y":-620,"width":280,"height":80},
|
||||
{"id":"5f777bb386a0b8aa","type":"text","text":"### collabora\n- 8081:9980","x":360,"y":-525,"width":280,"height":85},
|
||||
{"id":"8d78e0acaa9616d5","type":"text","text":"### adguardhome\n- \"53:53/tcp\"\n- \"53:53/udp\"\n- \"3000:3000/tcp\"\n- \"8050:80/tcp\"","x":40,"y":-120,"width":280,"height":160},
|
||||
{"id":"41ec11c5704a134c","type":"text","text":"### freshrss\n- \"8070:1200\"","x":40,"y":60,"width":280,"height":80},
|
||||
{"id":"5f8a89afeef02f38","type":"text","text":"### openspeedtest\n- '8093:3000'\n- '8094:3001'","x":360,"y":35,"width":280,"height":105},
|
||||
{"id":"4b08c3fa2d3fe2cf","type":"text","text":"### gitea\n- \"8020:3000\"\n- \"2244:22\"","x":40,"y":-340,"width":280,"height":100},
|
||||
{"id":"b112aedbb6b5ce68","type":"text","text":"### filebrowser\n- 8040:80","x":40,"y":-220,"width":280,"height":80},
|
||||
{"id":"5c65ba78253b985b","type":"text","text":"### AWIN-PC2\n`192.168.1.24`","x":-240,"y":-260,"width":180,"height":80,"color":"2"},
|
||||
{"id":"c0c54f342022f6db","type":"text","text":"### grafana\n- \"8082:3000\"","x":360,"y":-340,"width":280,"height":75},
|
||||
{"id":"520020bcf81de93b","type":"text","text":"### prometheus\n- \"8083:9090\"","x":360,"y":-240,"width":280,"height":90},
|
||||
{"id":"59d436dadba47e3c","type":"text","text":"### node_exporter\n- \"8084:9100\"","x":360,"y":-120,"width":280,"height":102},
|
||||
{"id":"ae5e0200e802c0ff","x":720,"y":-640,"width":250,"height":100,"type":"text","text":"### Minecraft\n- 8100"}
|
||||
],
|
||||
"edges":[
|
||||
{"id":"2155d66680f8b2ba","fromNode":"5c65ba78253b985b","fromSide":"right","toNode":"c910b905ac74e6ac","toSide":"left"}
|
||||
]
|
||||
}
|
||||
52
21.01. OS/21.01. Linux/架站/filebrowser.md
Normal file
52
21.01. OS/21.01. Linux/架站/filebrowser.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# docker-compose.yml
|
||||
```yml
|
||||
version: '3'
|
||||
services:
|
||||
file-browser:
|
||||
restart: always
|
||||
image: filebrowser/filebrowser:latest
|
||||
container_name: filebrowser
|
||||
user: 1000:1000
|
||||
ports:
|
||||
- 8040:80
|
||||
volumes:
|
||||
- /media/share:/srv
|
||||
- ./data/filebrowser.db:/database.db
|
||||
- ./data/settings.json:/.filebrowser.json
|
||||
- ./data/gafiled.png:/config/logo.png
|
||||
- ./data/branding:/branding
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
```
|
||||
|
||||
# 準備
|
||||
在 `docker compose up -d` 之前,需要先把檔案準備好。
|
||||
```shell
|
||||
touch data/filebrowser.db
|
||||
touch data/settings.json
|
||||
```
|
||||
|
||||
`data/settings.json` 的內容:
|
||||
```json
|
||||
{
|
||||
"port": 80,
|
||||
"baseURL": "",
|
||||
"address": "",
|
||||
"log": "stdout",
|
||||
"database": "/database.db",
|
||||
"root": "/srv"
|
||||
}
|
||||
```
|
||||
|
||||
# 登入
|
||||
預設的帳號密碼是`admin/admin`,記得要改掉。
|
||||
|
||||
# 問題
|
||||
因為Filebrowser會lock DB,所以docker在跑得時候會無法使用Filebrowser的command,所以需要先把docker停掉,然後用以下命令登入:
|
||||
```shell
|
||||
sudo docker run -it -v ./data/filebrowser.db:/database.db -v data/settings.json:/.filebrowser.json --entrypoint /bin/sh filebrowser/filebrowser
|
||||
```
|
||||
|
||||
# 參考
|
||||
- [Filebrowser Docker Installation | All about](https://bobcares.com/blog/filebrowser-installation-in-docker/)
|
||||
- [filebrowser/filebrowser: 📂 Web File Browser](https://github.com/filebrowser/filebrowser)
|
||||
26
21.01. OS/21.01. Linux/架站/freshrss.md
Normal file
26
21.01. OS/21.01. Linux/架站/freshrss.md
Normal file
@@ -0,0 +1,26 @@
|
||||
```yml
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
freshrss:
|
||||
image: linuxserver/Taipei:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:80"
|
||||
environment:
|
||||
TZ: Asia/Shanghai
|
||||
CRON_MIN: "*/60"
|
||||
PUID: 1000
|
||||
PGID: 1000
|
||||
volumes:
|
||||
- freshrss_data:/var/www/FreshRSS/data
|
||||
- freshrss_extensions:/var/www/FreshRSS/extensions
|
||||
|
||||
rsshub:
|
||||
image: diygod/rsshub:latest
|
||||
restart: unless-stopped
|
||||
expose:
|
||||
- "1200"
|
||||
environment:
|
||||
CACHE_EXPIRE: 3600
|
||||
```
|
||||
41
21.01. OS/21.01. Linux/架站/minecraft.md
Normal file
41
21.01. OS/21.01. Linux/架站/minecraft.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# `docker-compose.yml`
|
||||
|
||||
```yml
|
||||
services:
|
||||
minecraft:
|
||||
image: itzg/minecraft-server
|
||||
restart: unless-stopped
|
||||
tty: true
|
||||
stdin_open: true
|
||||
ports:
|
||||
- "8100:25565"
|
||||
environment:
|
||||
MEMORY: "16G" # 設定分配16GB RAM
|
||||
JVM_OPTS: "-XX:MaxRAMPercentage=75" # 設定JVM啟動參數,設定最多使用75% RAM
|
||||
|
||||
EULA: "TRUE" # 自動同意伺服器的EULA
|
||||
TYPE: "PAPER"
|
||||
VERSION: "1.19.4"
|
||||
MAX_BUILD_HEIGHT: 384
|
||||
VIEW_DISTANCE: 12
|
||||
MODE: "creative"
|
||||
ENABLE_WHITELIST: "TRUE"
|
||||
ENFORCE_WHITELIST: "TRUE"
|
||||
OPS: ""
|
||||
ONLINE_MODE: "TRUE"
|
||||
SERVER_NAME: "Crazy Smile City"
|
||||
MOTD: "Today is a good day~~~"
|
||||
ICON: ""
|
||||
OVERRIDE_SERVER_PROPERTIES: "TRUE"
|
||||
TZ:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
volumes:
|
||||
- ./data:/data
|
||||
```
|
||||
|
||||
# 參考
|
||||
- [如何在Ubuntu系統以Docker架設Minecraft Java版伺服器 · Ivon的部落格](https://ivonblog.com/posts/minecraft-java-edition-server-docker/)
|
||||
- [Docker Minecraft 开服记](https://blog.l3zc.com/2023/06/build-a-mc-server-with-docker/#%E8%BF%9B%E4%B8%80%E6%AD%A5%E8%B0%83%E6%95%B4)
|
||||
- [Variables - Minecraft Server on Docker (Java Edition)](https://docker-minecraft-server.readthedocs.io/en/latest/variables/#server)
|
||||
-
|
||||
32
21.01. OS/21.01. Linux/硬碟操作.md
Normal file
32
21.01. OS/21.01. Linux/硬碟操作.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# 看硬碟代號
|
||||
```
|
||||
lsblk
|
||||
```
|
||||
```result
|
||||
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
|
||||
sda 8:0 0 1.8T 0 disk
|
||||
└─sda1 8:1 0 1.8T 0 part /extusb1/storj
|
||||
mmcblk0 179:0 0 14.6G 0 disk
|
||||
├─mmcblk0p1 179:1 0 256M 0 part /boot
|
||||
└─mmcblk0p2 179:2 0 14.3G 0 part /
|
||||
```
|
||||
衍生出來的`sda1`、`mmcblk0p1`、`mmcblk0p2` 之類的就是硬碟代號
|
||||
|
||||
# 格式化
|
||||
```bash
|
||||
sudo mkfs.ext4 /dev/sdb123 # sdb123 要換成你自己的硬碟代號
|
||||
```
|
||||
|
||||
# 掛載硬碟
|
||||
```
|
||||
sudo mount <硬碟代號> <路徑>
|
||||
```
|
||||
|
||||
例如:
|
||||
```
|
||||
sudo mount /dev/sda1 /home/user/myusb
|
||||
```
|
||||
就是把`/dev/sda1` 掛載到 `/home/user/myusb` 這個目錄下面。
|
||||
|
||||
# 開機自動掛載硬碟
|
||||
![[開機自動掛載硬碟]]
|
||||
6
21.01. OS/21.01. Linux/開機自動掛載模組(modprobe nct6683).md
Normal file
6
21.01. OS/21.01. Linux/開機自動掛載模組(modprobe nct6683).md
Normal file
@@ -0,0 +1,6 @@
|
||||
在 `/etc/modules-load.d` 開一個檔案叫做 `nct6683.conf`,裡面填入:
|
||||
```
|
||||
nct6683
|
||||
```
|
||||
|
||||
下一次開機的時候,系統就會自動載入 `nct6683` 這個模組了。
|
||||
10
21.01. OS/21.01. Linux/開機自動掛載硬碟.md
Normal file
10
21.01. OS/21.01. Linux/開機自動掛載硬碟.md
Normal file
@@ -0,0 +1,10 @@
|
||||
要開機自動掛載的話,需要知道你要掛載硬碟的UUID,然後把它填到 `/etc/fstab` 就可以了。
|
||||
|
||||
用 `blkid` 來看 UUID:
|
||||
![[20240228_170818_WindowsTerminal_1733x303.png]]
|
||||
然後在 `/etc/fstab` 加入一行:
|
||||
```
|
||||
UUID=be92f54f-e427-496e-83e9-a29643aa5af0 /lvm1 ext4 defaults,nofail 0 2
|
||||
```
|
||||
|
||||
關於 `/etc/fstab` 詳細請再看:[[fstab]]
|
||||
39
21.01. OS/21.02. Windows/Msys2.md
Normal file
39
21.01. OS/21.02. Windows/Msys2.md
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
tags:
|
||||
aliases:
|
||||
date: 2025-05-05
|
||||
time: 10:08:21
|
||||
description:
|
||||
---
|
||||
|
||||
# Install Msys2
|
||||
根據[MSYS2](https://www.msys2.org/)官方頁面來下載並安裝最新的版本。
|
||||
基本上都只要下一步即可。
|
||||
|
||||
## 設定 `MSYS2_HOME` 環境變數
|
||||
把 Msys2 的 安裝路徑設為環境變數可以讓以後的設定更有彈性。如下:
|
||||
![[20250505_101259_SystemPropertiesAdvanced_839x208.png]]
|
||||
|
||||
## 設定 `path` 環境變數
|
||||
在 `path` 環境變數中新增 Msys2 的 bin 路徑,如下:
|
||||
![[20250505_101427_SystemPropertiesAdvanced_677x633.png]]
|
||||
|
||||
# 用 Msys2 安裝開發工具
|
||||
根據[Environments - MSYS2](https://www.msys2.org/docs/environments/#__tabbed_1_1),Msys2 提供多種開發環境。我們使用 UCRT64。
|
||||
![[20250505_101709_chrome_844x478.png]]
|
||||
|
||||
## 安裝 UCRT64 開發環境
|
||||
打開 UCRT64 terminal
|
||||
![[20250505_101809_Obsidian_267x313.png]]
|
||||
然後輸入`pacman -Syy --needed base-devel mingw-w64-ucrt-x86_64-toolchain`,之後都輸入`Y`來接受所有安裝。
|
||||
|
||||
# 用 Msys2 安裝工具
|
||||
用 `pacman -Syy <TOOL_NAME>` 就可以安裝工具,例如:
|
||||
```shell
|
||||
pacman -Syy zsh git
|
||||
```
|
||||
|
||||
# 參考來源
|
||||
- [Windows 命令行相关配置之 msys2+zsh+zi](https://sansui233.github.io/posts/windows-zsh-conf)
|
||||
- [在Windows上使用Fish替换cmd在日常开发过程中,我们也需要常常和命令行打交道,而Windows自带的cmd或者 - 掘金](https://juejin.cn/post/7362743871979749391)
|
||||
- [Msys2+VSCode配置Windows下C或C++环境在使用Windows开发C或者C++项目时,大多数人通常会选择 - 掘金](https://juejin.cn/post/7369903157646229556)
|
||||
132
21.01. OS/21.02. Windows/Windows 11 重灌.md
Normal file
132
21.01. OS/21.02. Windows/Windows 11 重灌.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# 要保存/恢復的檔案
|
||||
- `%userprofile%/.config`
|
||||
- `%userprofile%/.ssh`
|
||||
- `%userprofile%/.bash_profile`
|
||||
- `%userprofile%/.bashrc`
|
||||
- `%userprofile%/.zshrc`
|
||||
- `%userprofile%/.gitconfig`
|
||||
- `%userprofile%/.vimrc`
|
||||
|
||||
# 安裝工具
|
||||
## 使用 [WinGet](https://learn.microsoft.com/zh-tw/windows/package-manager/winget/) 安裝工具
|
||||
```bash
|
||||
winget install \
|
||||
Microsoft.PowerToys \
|
||||
7zip.7zip \
|
||||
MHNexus.HxD \
|
||||
SublimeHQ.SublimeText.4 \
|
||||
Git.Git \
|
||||
dandavison.delta \
|
||||
WinMerge.WinMerge \
|
||||
SoftDeluxe.FreeDownloadManager \
|
||||
Google.Chrome \
|
||||
CodecGuide.K-LiteCodecPack.Mega \
|
||||
Win32diskimager.win32diskimager \
|
||||
Google.GoogleDrive \
|
||||
Microsoft.VisualStudioCode \
|
||||
Google.AndroidStudio \
|
||||
Microsoft.PowerShell
|
||||
```
|
||||
|
||||
```PowerShell
|
||||
winget install `
|
||||
Microsoft.PowerToys `
|
||||
7zip.7zip `
|
||||
MHNexus.HxD `
|
||||
SublimeHQ.SublimeText.4 `
|
||||
Git.Git `
|
||||
dandavison.delta `
|
||||
WinMerge.WinMerge `
|
||||
SoftDeluxe.FreeDownloadManager `
|
||||
Google.Chrome `
|
||||
CodecGuide.K-LiteCodecPack.Mega `
|
||||
Win32diskimager.win32diskimager `
|
||||
Google.GoogleDrive `
|
||||
Microsoft.VisualStudioCode `
|
||||
Google.AndroidStudio \
|
||||
Microsoft.PowerShell
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 安裝 Chocolatey
|
||||
安裝[Chocolatey](https://chocolatey.org/),用Administrator身份打開powershell,輸入下列指令:
|
||||
```
|
||||
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
|
||||
```
|
||||
|
||||
## 用 Chocolatey 安裝工具
|
||||
```
|
||||
choco install powertoys 7zip vscode hxd sublimetext4 androidstudio intellijidea-community git winmerge freefilesync freedownloadmanager gsudo firacode cascadiacode sourcecodepro delta googlechrome googledrive enpass.install sharex win32diskimager k-litecodecpackmega obsidian anki enpass.install --yes
|
||||
```
|
||||
|
||||
可以在 [https://community.chocolatey.org/packages](https://community.chocolatey.org/packages) 找到其他工具,再加到清單後面即可。
|
||||
|
||||
上面的指令安裝了下列的軟體,可以依自己需求增刪:
|
||||
- [powertoys](https://community.chocolatey.org/packages/powertoys)
|
||||
- [7zip](https://community.chocolatey.org/packages/7zip)
|
||||
- [vscode](https://community.chocolatey.org/packages/vscode)
|
||||
- [hxd](https://community.chocolatey.org/packages/hxd)
|
||||
- [sublimetext4](https://community.chocolatey.org/packages/sublimetext4)
|
||||
- [androidstudio](https://community.chocolatey.org/packages/androidstudio)
|
||||
- [intellijidea-community](https://community.chocolatey.org/packages/intellijidea-community)
|
||||
- [git](https://community.chocolatey.org/packages/git)
|
||||
- [winmerge](https://community.chocolatey.org/packages/winmerge)
|
||||
- [freefilesync](https://community.chocolatey.org/packages/freefilesync)
|
||||
- [freedownloadmanager](https://community.chocolatey.org/packages/freedownloadmanager)
|
||||
- [gsudo](https://community.chocolatey.org/packages/gsudo)
|
||||
- [firacode](https://community.chocolatey.org/packages/firacode)
|
||||
- [cascadiacode](https://community.chocolatey.org/packages/cascadiacode)
|
||||
- [sourcecodepro](https://community.chocolatey.org/packages/sourcecodepro)
|
||||
- [delta](https://community.chocolatey.org/packages/delta)
|
||||
- [googlechrome](https://community.chocolatey.org/packages/googlechrome)
|
||||
- [googledrive](https://community.chocolatey.org/packages/googledrive)
|
||||
- [enpass.install](https://community.chocolatey.org/packages/enpass.install)
|
||||
- [sharex](https://community.chocolatey.org/packages/sharex)
|
||||
- [win32diskimager](https://community.chocolatey.org/packages/win32diskimager)
|
||||
- [k-litecodecpackmega](https://community.chocolatey.org/packages/k-litecodecpackmega)
|
||||
- [obsidian](https://community.chocolatey.org/packages/obsidian)
|
||||
- [anki](https://community.chocolatey.org/packages/anki)
|
||||
- [Enpass Password Manager](https://community.chocolatey.org/packages/enpass.install)
|
||||
|
||||
## 用 Chocolatey 升級軟體
|
||||
|
||||
```shell
|
||||
choco upgrade all -y
|
||||
```
|
||||
|
||||
# 手動安裝
|
||||
3. Python 3.6.3
|
||||
4. Python 3.9
|
||||
7. Visual Studio 2022
|
||||
8. Office 365
|
||||
9. [Sublime Text 4](https://www.sublimetext.com/download)
|
||||
10. Lightroom
|
||||
11. [卡巴斯基](https://www.kaspersky.com.tw/)
|
||||
12. 字型
|
||||
- [Caskaydia](\\diskstation\share\Tools\字型\Caskaydia Cove Nerd Font\)
|
||||
13. 安裝 [`wget`](https://eternallybored.org/misc/wget/)
|
||||
1. [Version 1.21.4](https://eternallybored.org/misc/wget/1.21.4/64/wget.exe)
|
||||
|
||||
# `~/.bashrc`
|
||||
1. 打開`~/.bashrc`。
|
||||
2. 內容如[[bashrc|bashrc]]
|
||||
|
||||
# Setup Windows Terminal
|
||||
1. 開啟Windows Terminal。
|
||||
2. 按`ctrl + ,`打開設定,之後參考[[Windows Terminal]]。
|
||||
|
||||
# 恢復右鍵選單
|
||||
- 以admin身份打開PowerShell,執行 `reg add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" /f /ve`
|
||||
- 要恢復Windows 11的右鍵選單則是執行:`reg delete "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}" /f`
|
||||
|
||||
# 設定使用者環境變數
|
||||
- `PYTHON_INCLUDE`: `C:\Python363\include`
|
||||
- `PYTHON_LIB`: `C:\Python363\libs`
|
||||
- `RobotRunCommonLib`: `C:\SynologyDrive\codes\CommonLib\RobotRunCommonLib`
|
||||
- `SWIGCmd`: `C:\SynologyDrive\PortableApps\swigwin-4.3.0\swig.exe`
|
||||
- `SYNODRIVE_PATH`: `C:\SynologyDrive`
|
||||
|
||||
# 參考
|
||||
- [How to open the full right-click menu by default on Windows 11](https://www.xda-developers.com/how-to-open-full-right-click-menu-by-default-windows-11/)
|
||||
- [【教學】Windows 11 系統優化](https://ofeyhong.pixnet.net/blog/post/225581177)
|
||||
25
21.01. OS/21.02. Windows/_Map.canvas
Normal file
25
21.01. OS/21.02. Windows/_Map.canvas
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"nodes":[
|
||||
{"id":"e724a0b36766d3a9","type":"group","x":440,"y":-480,"width":475,"height":880,"label":"應該是可用的流程"},
|
||||
{"id":"0138bfb5c46d71f1","type":"text","text":"1. 用[[powercfg powerthrottling]]關閉 VirtualBox power throttling。","x":-149,"y":-191,"width":329,"height":91},
|
||||
{"id":"d34f3157e07cb50d","type":"text","text":"開始","x":-200,"y":40,"width":100,"height":50,"color":"2"},
|
||||
{"id":"c276871e8748cbfe","type":"text","text":"[PowerWriteDCValueIndex](https://learn.microsoft.com/zh-tw/windows/win32/api/powersetting/nf-powersetting-powerwritedcvalueindex)\n```c\nPowerWriteDCValueIndex(NULL, scheme,\n &GUID_PROCESSOR_SETTINGS_SUBGROUP, \n &GUID_PROCESSOR_THROTTLE_MAXIMUM, percent);\n```","x":460,"y":-88,"width":429,"height":149},
|
||||
{"id":"b89cd7d463506018","type":"text","text":"[PowerSetActiveScheme](https://learn.microsoft.com/en-us/windows/win32/api/powersetting/nf-powersetting-powersetactivescheme)","x":549,"y":100,"width":252,"height":60},
|
||||
{"id":"dd89a32995de8e4a","type":"text","text":"# 參考\n- [Tweak CPU Power Elegantly on Windows - kkocdko's blog](https://kkocdko.site/post/202110041950)\n- [Powersetting.h header - Win32 apps | Microsoft Learn](https://learn.microsoft.com/en-us/windows/win32/api/powersetting/)","x":460,"y":200,"width":435,"height":180},
|
||||
{"id":"154d88218d26f035","type":"text","text":"[PowerWriteACValueIndex](https://learn.microsoft.com/en-us/windows/win32/api/powersetting/nf-powersetting-powerwriteacvalueindex)\n```c\nPowerWriteACValueIndex(NULL, scheme, \n &GUID_PROCESSOR_SETTINGS_SUBGROUP,\n &GUID_PROCESSOR_THROTTLE_MAXIMUM, percent);\n```","x":460,"y":-255,"width":429,"height":151},
|
||||
{"id":"bb0881e617ca2f52","type":"text","text":"[PowerGetActiveScheme](https://learn.microsoft.com/en-us/windows/win32/api/powersetting/nf-powersetting-powergetactivescheme)\n```c\nGUID guid, *scheme = &guid; PowerGetActiveScheme(NULL, &scheme);\n```","x":502,"y":-460,"width":346,"height":125},
|
||||
{"id":"1b7a2018be9a2542","type":"text","text":"- [[設定CPU Power mode]]","x":80,"y":35,"width":250,"height":60},
|
||||
{"id":"034536d7a91d7b62","x":-100,"y":320,"width":133,"height":60,"type":"text","text":"工具設定"},
|
||||
{"id":"197b4dc40754a989","x":-201,"y":460,"width":335,"height":211,"type":"text","text":"- [[Chrome]]\n- [[freefilesync]]\n- [[Obsidian 操作]]\n- [[SublimeText]]\n- [[vim]]\n- [[Visual Studio Code]]\n- [[Windows 11 重灌]]\n- [[Windows Terminal]]"}
|
||||
],
|
||||
"edges":[
|
||||
{"id":"5c4879a42c2db8ac","fromNode":"d34f3157e07cb50d","fromSide":"top","toNode":"0138bfb5c46d71f1","toSide":"bottom"},
|
||||
{"id":"631e78e7dee93490","fromNode":"d34f3157e07cb50d","fromSide":"right","toNode":"1b7a2018be9a2542","toSide":"left"},
|
||||
{"id":"f60c6e07e0ef6a98","fromNode":"c276871e8748cbfe","fromSide":"bottom","toNode":"b89cd7d463506018","toSide":"top"},
|
||||
{"id":"7fada69bb11ae874","fromNode":"154d88218d26f035","fromSide":"bottom","toNode":"c276871e8748cbfe","toSide":"top"},
|
||||
{"id":"d4c1beba2bea0171","fromNode":"bb0881e617ca2f52","fromSide":"bottom","toNode":"154d88218d26f035","toSide":"top","label":"SchemeGuid"},
|
||||
{"id":"7000cd2de2280a0a","fromNode":"1b7a2018be9a2542","fromSide":"right","toNode":"e724a0b36766d3a9","toSide":"left"},
|
||||
{"id":"82d29d89f73fd716","fromNode":"d34f3157e07cb50d","fromSide":"bottom","toNode":"034536d7a91d7b62","toSide":"top"},
|
||||
{"id":"035012a29ceb315e","fromNode":"034536d7a91d7b62","fromSide":"bottom","toNode":"197b4dc40754a989","toSide":"top"}
|
||||
]
|
||||
}
|
||||
15
21.01. OS/21.02. Windows/command.md
Normal file
15
21.01. OS/21.02. Windows/command.md
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
### 取得日期時間
|
||||
在 batch 檔裡面可以用 `%date%` 與 `%time%` 來取得日期時間。
|
||||
用 `%date:~0,4%` 來擷取特定欄位。
|
||||
`~0,4` 表示**從 index 0 開始取 4 位**,所以假設原本 `%date%` 會輸出 `2024/05/29`, `%date:~0,4%` 則會輸出 `2024`。
|
||||
|
||||
取得年、月、日、時、分、秒下:
|
||||
```bat
|
||||
set YYYY=%date:~0,4%
|
||||
set MM=%date:~5,2%
|
||||
set DD=%date:~8,2%
|
||||
set HOUR=%time:~0,2%
|
||||
set MIN=%time:~3,2%
|
||||
set SEC=%time:~6,2%
|
||||
```
|
||||
6
21.01. OS/21.02. Windows/powercfg powerthrottling.md
Normal file
6
21.01. OS/21.02. Windows/powercfg powerthrottling.md
Normal file
@@ -0,0 +1,6 @@
|
||||
對於特定的軟體,使用 `powercfg` 來關閉 powerthrottling。例如,讓 [VirtualBox](https://www.virtualbox.org/) 最大效能執行:
|
||||
```cmd
|
||||
powercfg /powerthrottling DISABLE /PATH "C:\Program Files\Oracle\VirtualBox\VirtualBoxVM.exe"
|
||||
powercfg /powerthrottling DISABLE /PATH "C:\Program Files\Oracle\VirtualBox\VBoxHeadless.exe"
|
||||
powercfg /powerthrottling list
|
||||
```
|
||||
16
21.01. OS/21.02. Windows/如何打造一個華麗又實用的 PowerShell 命令輸入環境.md
Normal file
16
21.01. OS/21.02. Windows/如何打造一個華麗又實用的 PowerShell 命令輸入環境.md
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
title: "如何打造一個華麗又實用的 PowerShell 命令輸入環境"
|
||||
author:
|
||||
- "[[Will Huang]]"
|
||||
tags:
|
||||
- "clippings"
|
||||
date: "2025-04-11T17:56:44+08:00"
|
||||
time: "2025-04-11T17:56:44+08:00"
|
||||
description: "The Will Will Web - 記載著 Will 在網路世界的學習心得與技術分享 - 每次看到 Scott Hanselman 那套華麗的 PowerShell 命令輸入環境,就覺得自己一定也要設定一個類似的環境,不但使用起來讓人覺得神清氣爽,在同事朋友面前也會顯得出類拔萃。今天這篇文"
|
||||
source: "https://blog.miniasp.com/post/2021/11/24/PowerShell-prompt-with-Oh-My-Posh-and-Windows-Terminal"
|
||||
published: 2021-11-24
|
||||
---
|
||||
|
||||
|
||||
# 參考來源
|
||||
- [如何打造一個華麗又實用的 PowerShell 命令輸入環境](https://blog.miniasp.com/post/2021/11/24/PowerShell-prompt-with-Oh-My-Posh-and-Windows-Terminal)
|
||||
171
21.01. OS/21.02. Windows/安裝新版 Oh My Posh 與插件來美化 PowerShell.md
Normal file
171
21.01. OS/21.02. Windows/安裝新版 Oh My Posh 與插件來美化 PowerShell.md
Normal file
@@ -0,0 +1,171 @@
|
||||
---
|
||||
title: "安裝新版 Oh My Posh 與插件來美化 PowerShell"
|
||||
author:
|
||||
- "[[kwchang0831]]"
|
||||
tags:
|
||||
- "clippings"
|
||||
date: "2025-04-11T19:56:45+08:00"
|
||||
time: "2025-04-11T19:56:45+08:00"
|
||||
description: "本篇文章紀錄 使用 Oh My Posh 來美化 PowerShell 7(pwsh)並安裝一些插件讓開發環境更高效。 插件可以安裝 Posh Git 讓使用 Git 指令的時候有自動完成的功能,或是安裝 ZLocation 讓我們可以更快速地跳到想去的資料夾,等等..."
|
||||
source: "https://www.kwchang0831.dev/dev-env/pwsh/oh-my-posh"
|
||||
published: 2022-05-22
|
||||
---
|
||||
[kwchang0831](https://github.com/kwchang0831)
|
||||
|
||||
更新於2 年前
|
||||
|
||||
## 開頭
|
||||
|
||||
[Oh My Posh](https://ohmyposh.dev/) 是一個主題引擎可以美化 PowerShell 7 (pwsh)。
|
||||
|
||||
本篇文章紀錄 Oh My Posh 的安裝與主題置換來美化你的 pwsh,並可更改主題 (theme)。除此之外,我們還會新增幾個插件來擴充 pwsh 的功能性,進一步提高使用效率。包含指令自動完成,快速切換資料夾等等。
|
||||
|
||||
本篇文章會介紹以下套件的安裝:
|
||||
|
||||
- [Oh My Posh](https://ohmyposh.dev/)
|
||||
- [Git](https://community.chocolatey.org/packages/git)
|
||||
- [Posh-Git](https://github.com/dahlbyk/posh-git)
|
||||
- [ZLocation](https://github.com/vors/ZLocation)
|
||||
- [NeoFetch](https://github.com/dylanaraps/neofetch)
|
||||
|
||||
## 環境配置
|
||||
|
||||
- Windows 10
|
||||
- Windows Terminal
|
||||
- PowerShell 7
|
||||
|
||||
## 安裝 gsudo
|
||||
|
||||
推薦安裝 gsudo ,可以更方便地提升權限到系統管理員權限,
|
||||
請參考: [gsudo - 讓 Windows 也有 sudo 功能](https://www.kwchang0831.dev/dev-env/gsudo)
|
||||
|
||||
## 安裝 PowerShell 7
|
||||
|
||||
若還沒有安裝最新版的 PowerShell 7 ,
|
||||
請參考: [PowerShell 7 - 來安裝最新版的 PowerShell](https://www.kwchang0831.dev/dev-env/pwsh)
|
||||
|
||||
## 安裝 Windows Terminal
|
||||
|
||||
若還沒有安裝最新版的 Windows Terminal,
|
||||
請參考: [改用 Windows Terminal - 比 Cmder 更好用的現代終端機](https://www.kwchang0831.dev/dev-env/windows-terminal)
|
||||
|
||||
## 安裝 Git
|
||||
|
||||
若還沒有安裝 Git ,可以使用 [chocolatey](https://chocolatey.org/install) 來安裝。
|
||||
|
||||
使用 gsudo 取得一次性系統管理員權限來安裝
|
||||
|
||||
## 安裝 Oh My Posh
|
||||
|
||||
pwsh 輸入
|
||||
|
||||
用文字編輯器編輯 `$Profile`
|
||||
|
||||
添加以下,儲存後關閉。
|
||||
|
||||
## $Profile
|
||||
|
||||
重新開啟 Windows Terminal 後生效,或是輸入以下指令應用修改,
|
||||
|
||||
## 安裝 Patched 字型
|
||||
|
||||
為了 Oh My Posh 的主題可以正常顯示字型與圖示,下載以下字型包並安裝:
|
||||
|
||||
[https://github.com/ryanoasis/nerd-fonts/releases/download/v2.1.0/Meslo.zip](https://github.com/ryanoasis/nerd-fonts/releases/download/v2.1.0/Meslo.zip)
|
||||
|
||||
或是使用 `oh-my-posh` 來安裝。這邊必須使用 gsudo 取得一次性系統管理員權限來安裝。
|
||||
|
||||
### 更改字型
|
||||
|
||||
#### Windows Terminal
|
||||
|
||||
Ctrl +, 打開設定,選擇 PowerShell 7 的設定檔 `外觀 > 字型` ,將字型改成 `MesloLGS NF` 之後儲存。
|
||||
|
||||

|
||||
|
||||
#### PowerShell 7
|
||||
|
||||
以系統管理員身分執行 PowerShell 7(x64),更改字型為 `MesloLGS NF`
|
||||
|
||||

|
||||
|
||||
### 更改 Oh My Posh 主題
|
||||
|
||||
Oh My Posh 內建很多不同的主題 (theme),請查看 [官網](https://ohmyposh.dev/docs/themes)
|
||||
|
||||
或是輸入以下指令查看內建的主題與預覽,
|
||||
|
||||
確定好了主題,讓我們修改 `$Profile` 來設定預設要使用的主題,
|
||||
|
||||
把 `oh-my-posh init pwsh ...` 的部分後面加上 `--config "$env:POSH_THEMES_PATH\{主題名稱}.omp.json"` 。
|
||||
|
||||
例如
|
||||
|
||||
## $Profile
|
||||
|
||||
重新開啟 Windows Terminal 後生效,或是輸入以下指令應用修改,
|
||||
|
||||
## posh-git
|
||||
|
||||
[posh-git](https://github.com/dahlbyk/posh-git) 讓 Git 的指令可已用 Tab 自動完成。
|
||||
|
||||
pwsh 輸入來安裝
|
||||
|
||||
在 `$Profile` 檔案最後一行新增以下指令:
|
||||
|
||||
## ZLocation
|
||||
|
||||
[ZLocation](https://github.com/vors/ZLocation) 類似於 [autojump](https://github.com/wting/autojump) 或是 [Zsh-z](https://github.com/agkozak/zsh-z) 的插件,
|
||||
可以用關鍵字直接跳到想去的資料夾,比使用 `cd` 更快速。
|
||||
|
||||
1.安裝 ZLocation
|
||||
|
||||
用 PowerShell 輸入以下指令:
|
||||
|
||||
輸入 \[A\] Yes to All ,全部同意。
|
||||
|
||||
2.修改使用者設定
|
||||
|
||||
在 `$Profile` 檔案最後一行新增以下指令,
|
||||
|
||||
## $Profile
|
||||
|
||||
重新開啟 Windows Terminal 後生效,
|
||||
或是輸入以下指令應用修改,
|
||||
|
||||
### ZLocation 使用方式
|
||||
|
||||
查看已知的資料夾位置
|
||||
|
||||
進入包含此字串的資料夾,可以用 `Tab` 來選擇結果,如果有多個資料夾符合 doc 的話。
|
||||
|
||||
回到之前的資料夾
|
||||
|
||||
## (選用) 安裝 NeoFetch
|
||||
|
||||
NeoFetch 用來顯示電腦配置。
|
||||
|
||||
即使已經有安裝 git 了,這邊還是要安裝 git ,因為 neofetch 會直接使用 scoop 安裝的 git 。
|
||||
|
||||
打開 pwsh 輸入以下指令,
|
||||
|
||||
執行 NeoFech
|
||||
|
||||
## (選用) 舊版錯誤訊息
|
||||
|
||||
如果你看到以下錯誤訊息,
|
||||
|
||||
表示你過去是用 `Install-Module` 的方式安裝 Oh My Posh,如以下:
|
||||
|
||||
詳細情況請參考 [官方網站](https://ohmyposh.dev/docs/migrating) 。
|
||||
|
||||
### 解決辦法
|
||||
|
||||
刪除過去的版本。打開 pwsh 輸入
|
||||
|
||||
移除 `$Profile` 裡的 `Import-Module oh-my-posh`
|
||||
|
||||
然後回到 [最上面的開始](https://www.kwchang0831.dev/dev-env/pwsh/#an1-zhuang1-oh-my-posh) 的流程重新安裝。
|
||||
|
||||
# 參考來源
|
||||
- [安裝新版 Oh My Posh 與插件來美化 PowerShell](https://www.kwchang0831.dev/dev-env/pwsh/oh-my-posh)
|
||||
8
21.01. OS/21.02. Windows/設定CPU Power mode.md
Normal file
8
21.01. OS/21.02. Windows/設定CPU Power mode.md
Normal file
@@ -0,0 +1,8 @@
|
||||
用 [`PowerWriteACValueIndex()`](https://learn.microsoft.com/en-us/windows/win32/api/powersetting/nf-powersetting-powerwriteacvalueindex) 或是 `PowerWriteDCValueIndex()` 來設定,然後用 `PowerSetActiveScheme()` 使其生效。
|
||||
|
||||
關於 scheme 的 GUID: https://learn.microsoft.com/en-us/windows/win32/power/power-setting-guids
|
||||
|
||||
C#的使用:[C#使用WinAPI 修改电源设置,临时禁止笔记本合上盖子时睡眠(使用PowerGetActiveScheme等函数,以及C#对WINAPI的调用) - findumars - 博客园](https://www.cnblogs.com/findumars/p/6298724.html)
|
||||
使用 API 的例子:[qt - Disable CPU package idle states in Windows from C++ code - Stack Overflow](https://stackoverflow.com/questions/69346153/disable-cpu-package-idle-states-in-windows-from-c-code)
|
||||
|
||||
[API for Minimum(Maximum) Processor State , C++ - Stack Overflow](https://stackoverflow.com/questions/22523708/api-for-minimummaximum-processor-state-c)
|
||||
20
21.01. OS/21.03. MAC/Install.md
Normal file
20
21.01. OS/21.03. MAC/Install.md
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
tags:
|
||||
aliases:
|
||||
date: 2025-02-23
|
||||
time: 20:11:25
|
||||
description:
|
||||
---
|
||||
|
||||
# Prepare
|
||||
## Install Homebrew
|
||||
- https://brew.sh/
|
||||
|
||||
|
||||
# APP
|
||||
```bash
|
||||
brew install git
|
||||
```
|
||||
|
||||
|
||||
# 參考來源
|
||||
48
21.01. OS/21.04. Android/ADB tcpip.md
Normal file
48
21.01. OS/21.04. Android/ADB tcpip.md
Normal file
@@ -0,0 +1,48 @@
|
||||
Use `adb tcpip` to enable ADB over network.
|
||||
|
||||
# Setup Android Device
|
||||
## Connect Device via USB
|
||||
Connect Android device to a PC via USB, and make sure ADB recognize your device.
|
||||
```bash
|
||||
$ adb devices
|
||||
List of devices attached
|
||||
0123456789ABCDEF device
|
||||
```
|
||||
|
||||
## Enable network of ADB
|
||||
Use below command to enable network of ADB:
|
||||
```bash
|
||||
adb tcpip 5555
|
||||
```
|
||||
|
||||
## Get IP of Device
|
||||
We have to get IP of Device, because another PC need this for connection.
|
||||
|
||||
If you connect your device to router with ethernet, pass `eth0` to below command to get IP address of device.
|
||||
```bash
|
||||
adb shell "ifconfig eth0 | grep 'inet addr' | cut -d: -f2 | awk '{print \$1}'"
|
||||
```
|
||||
|
||||
If you connect your device to router with WIFI, change `eth0` to `wlan0`, like:
|
||||
```bash
|
||||
adb shell "ifconfig wlan0 | grep 'inet addr' | cut -d: -f2 | awk '{print \$1}'"
|
||||
```
|
||||
|
||||
Above command will return IP address of eth0, like:
|
||||
![[20250115_100240_WindowsTerminal_1305x87.png]]
|
||||
|
||||
**Remember your IP address.**
|
||||
|
||||
# Setup PC
|
||||
Now we have to setup our PC that in the same network with our Android device. Please note this PC **doesn't connect to your Android device via USB**.
|
||||
So we have to enable connection between PC and your Android devicem, and we need IP address of Android device, you had this at step [[ADB tcpip#Get IP of Device|Get IP of Device]].
|
||||
|
||||
Pass your IP of Android device to below command to enable connection of ADB:
|
||||
```
|
||||
adb connect 192.168.1.108:5555
|
||||
```
|
||||
|
||||
Remember to change `192.168.1.108` to your really IP address.
|
||||
|
||||
Now we can use `adb devices` to check if we can recognize Android device by IP adress:
|
||||
![[20250115_101133_WindowsTerminal_496x107.png|400]]
|
||||
12
21.01. OS/21.04. Android/ADB 取得 APK 的 icon.md
Normal file
12
21.01. OS/21.04. Android/ADB 取得 APK 的 icon.md
Normal file
@@ -0,0 +1,12 @@
|
||||
所有 apk 在安裝之後必須要向 launcher 註冊,並將 icon 存在 launcher 的 `app_icons.db` 裡面。
|
||||
launcher 的 package 是 `com.android.launcher3`,所以 `app_icons.db` 的位置在 `/data/data/com.android.launcher3/databases/app_icons.db`。
|
||||
|
||||
用 `SQLiteDatabaseBrowserPortable.exe` 之類的工具可以打開 `app_icons.db`,其內容如下:
|
||||
![[Pasted image 20220712100904.png|800]]
|
||||
|
||||
icon 欄位的blob就是icon的圖檔,看來是PNG檔。
|
||||
|
||||
## 參考
|
||||
- [Can i get the icon image of an app through adb](https://stackoverflow.com/questions/39170162/can-i-get-the-icon-image-of-an-app-through-adb)
|
||||
- [只是简单看下Launcher_Jason_Lee155的博客-CSDN博客](https://blog.csdn.net/Jason_Lee155/article/details/125096966)
|
||||
- [Android Launcher3中微信联系人快捷方式无法卸载的解决方案 - 简书](https://www.jianshu.com/p/8ba912ad537e)
|
||||
73
21.01. OS/21.04. Android/ADB.md
Normal file
73
21.01. OS/21.04. Android/ADB.md
Normal file
@@ -0,0 +1,73 @@
|
||||
## am
|
||||
### start
|
||||
用`am start`來打開一個activity,例:
|
||||
```
|
||||
adb shell am start -S com.logitech.sentineliq/.MainActivity --es cameraId 0
|
||||
```
|
||||
其中`-S`是指先停止app再打開app。還有其他的命令如下:
|
||||
```
|
||||
-D: enable debugging
|
||||
-W: wait for launch to complete
|
||||
--start-profiler <FILE>: start profiler and send results to <FILE>
|
||||
-P <FILE>: like above, but profiling stops when app goes idle
|
||||
-R: repeat the activity launch <COUNT> times. Prior to each repeat,
|
||||
the top activity will be finished.
|
||||
-S: force stop the target app before starting the activity
|
||||
--opengl-trace: enable tracing of OpenGL functions
|
||||
```
|
||||
|
||||
### 參考
|
||||
- [Android activity manager "am" command help](https://gist.github.com/tsohr/5711945)
|
||||
|
||||
## pm
|
||||
### list packages
|
||||
列出所有安裝的apk
|
||||
```bash
|
||||
adb shell pm list packages
|
||||
```
|
||||
|
||||
只列出 user 自己安裝的 apk:
|
||||
```bash
|
||||
adb shell "pm list packages -3"
|
||||
```
|
||||
|
||||
## Forward
|
||||
ADB forward用來把PC端收到的TCP轉到Android去,這樣就可以透過USB ADB達到網路的功能。
|
||||
例:
|
||||
```
|
||||
adb forward tcp:6100 tcp:7100
|
||||
```
|
||||
|
||||
上述等於:
|
||||
```
|
||||
PC Android
|
||||
http://127.0.0.1:6100 APP(port: 8080)
|
||||
| |
|
||||
| |
|
||||
V----------> ADB(USB)----------->
|
||||
|
||||
```
|
||||
|
||||
Android端所回應的HTTP封包也會經由原路回來,但是如果Android端要發一個request的話,PC端就收不到了,必須經由[[ADB#Reverse]]才行。
|
||||
|
||||
### 參考
|
||||
* [Android Debug Bridge (adb) | Android Developers](https://developer.android.com/studio/command-line/adb#forwardports)
|
||||
|
||||
## Reverse
|
||||
ADB reverse用來監聽Android端收到的request,假設今天在Android APP上寫一個`http://127.0.0.1:8080/say/message`,並希望PC端可以收到的話,就可以用reverse來操作,例:
|
||||
```
|
||||
adb reverse tcp:8081 tcp:8080
|
||||
```
|
||||
也就是說Android那邊發過來的封包會送交給PC這邊的port 8081。因此,PC端還需要寫一個Server來監聽8081才行。
|
||||
|
||||
### 參考
|
||||
* [adb命令-adb reverse的研究-有解無憂](https://www.uj5u.com/qita/277742.html)
|
||||
|
||||
## Logcat
|
||||
- Enlarge logcat buffer to 16M: `adb logcat -G 16M`
|
||||
|
||||
## Get foreground activity
|
||||
#android #foreground #activity
|
||||
```
|
||||
adb shell "dumpsys activity activities | grep ResumedActivity"
|
||||
```
|
||||
2
21.01. OS/21.04. Android/AOSP.md
Normal file
2
21.01. OS/21.04. Android/AOSP.md
Normal file
@@ -0,0 +1,2 @@
|
||||
## AOSP framework jar
|
||||
To use AOSP jar file in Android Studio: [Import AOSP framework jar file](https://medium.com/@chauyan/import-aosp-framework-jar-file-f0c2ac979a8a)
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
|
||||
## 參考資料
|
||||
- [Android External Storage - Read, Write, Save File | DigitalOcean](https://www.digitalocean.com/community/tutorials/android-external-storage-read-write-save-file)
|
||||
- [Environment.getExternalStorageDirectory() is deprecated过时的替代方案_Mr_tigerchou的博客-CSDN博客](https://blog.csdn.net/shving/article/details/101057082)
|
||||
164
21.01. OS/21.04. Android/Android programming.md
Normal file
164
21.01. OS/21.04. Android/Android programming.md
Normal file
@@ -0,0 +1,164 @@
|
||||
## Build AOSP
|
||||
### Build compile environment
|
||||
1. Install Ubuntu 18.04
|
||||
2. Install packages: `sudo apt-get install git-core gnupg flex bison build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip fontconfig`
|
||||
- https://source.android.com/setup/build/initializing
|
||||
3. Install Repo
|
||||
```
|
||||
mkdir ~/bin
|
||||
PATH=~/bin:$PATH
|
||||
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo ;\
|
||||
chmod a+x ~/bin/repo ;\
|
||||
gpg --recv-key 8BB9AD793E8E6153AF0F9A4416530D5E920F5C65 ;\
|
||||
curl https://storage.googleapis.com/git-repo-downloads/repo.asc | gpg --verify - ~/bin/repo
|
||||
```
|
||||
- https://source.android.com/setup/develop#installing-repo
|
||||
4. Download AOSP source
|
||||
1. Create folder for AOSP
|
||||
```
|
||||
mkdir -p ~/codes/aosp ; cd ~/codes/aosp
|
||||
```
|
||||
2. Setup git
|
||||
```
|
||||
git config --global user.name AwinHuang ;\
|
||||
git config --global user.email awinhuang@gmail.com
|
||||
```
|
||||
3. Download source code
|
||||
```
|
||||
repo init -u https://android.googlesource.com/platform/manifest ;\
|
||||
repo sync -j8
|
||||
```
|
||||
- 如果要切換某一個特定版本可以使用`-b`,例如:`repo init -u https://android.googlesource.com/platform/manifest -b android-10.0.0_r47`。
|
||||
- 要知道版本tag可以查看:https://source.android.com/setup/start/build-numbers#source-code-tags-and-builds
|
||||
5. Build code
|
||||
```
|
||||
source build/envsetup.sh ;\
|
||||
lunch aosp_arm-eng ;\
|
||||
make clobber ;\
|
||||
make -j16
|
||||
```
|
||||
- `make clobber`用來刪除build資料夾
|
||||
|
||||
### Reference
|
||||
- [GitHub - henrymorgen/android-knowledge-system: Android应用开发最强原创知识体系](https://github.com/henrymorgen/android-knowledge-system)
|
||||
- [Android AOSP基础(二)AOSP源码和内核源码下载 | BATcoder - 刘望舒](http://liuwangshu.cn/framework/aosp/2-download-aosp.html)
|
||||
- [Android AOSP基础(三)Android系统源码的整编和单编 | BATcoder - 刘望舒](http://liuwangshu.cn/framework/aosp/3-compiling-aosp.html)
|
||||
|
||||
## Build kernel
|
||||
1. Download the code
|
||||
```
|
||||
mkdir -p ~/codes/kernel ;\
|
||||
cd ~/codes/kernel ;\
|
||||
repo init -u https://android.googlesource.com/kernel/manifest ;\
|
||||
repo sync -j16
|
||||
```
|
||||
|
||||
2. Compile
|
||||
```
|
||||
build/build.sh
|
||||
```
|
||||
- 如果遇到`Command 'java' not found, but can be installed with:`
|
||||
- 依序安裝
|
||||
- `sudo apt install default-jre`
|
||||
- `sudo apt install openjdk-11-jre-headless`
|
||||
- `sudo apt install openjdk-8-jre-headless`
|
||||
- 執行 `sudo update-alternatives --config java`
|
||||
- 選擇 `/usr/lib/jvm/java-11-openjdk-amd64/bin/java`
|
||||
- 再次compile
|
||||
- `source build/envsetup.sh`
|
||||
- `mm idegen`
|
||||
|
||||
3. 產生android.iml和android.ipr
|
||||
在source code跟目錄下執行:`development/tools/idegen/idegen.sh`
|
||||
|
||||
### Reference
|
||||
- [Android kernel源码下载与编译](https://blog.csdn.net/u010164190/article/details/106561022)
|
||||
|
||||
|
||||
## Android App programming
|
||||
- R的全名:`<PACKAGE_NAME> + .R`,例如package name是`com.awin.testapp`,那全名是`com.awin.testapp.R`。
|
||||
- AndroidX = Android eXtension
|
||||
- Layout
|
||||
- layout_margin: 物件與其他物件的距離
|
||||
- layout_gravity: 物件在容器內的位置(靠左、靠右、置中...)
|
||||
- textApperance: 字型大小
|
||||
- Extensions
|
||||
- Android 4.1 沒有自動加入的extension
|
||||
- 打開build.gradle,在`plugins`區塊中加入:
|
||||
```
|
||||
id 'kotlin-kapt'
|
||||
id 'kotlin-android-extensions'
|
||||
```
|
||||
|
||||
- 使用ViewModel & LiveData
|
||||
- 確認有 `kotlin-kapt` 這個plugin。
|
||||
![[Pasted image 20210330102148.png]]
|
||||
- [Android jetpack所有library](https://developer.android.com/jetpack/androidx/explorer)
|
||||
- [Android jetpack - Lifecycle](https://developer.android.com/jetpack/androidx/releases/lifecycle)
|
||||
- 從`Declaring dependencies`這區塊複製必要的module
|
||||
![[Pasted image 20210330110411.png]]
|
||||
```
|
||||
def lifecycle_version = "2.3.1"
|
||||
|
||||
// ViewModel
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
|
||||
// LiveData
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
|
||||
// Annotation processor
|
||||
kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
|
||||
```
|
||||
|
||||
- Create a ViewModel
|
||||
```kotlin
|
||||
viewModel = ViewModelProvider(this).get(GuessViewModel::class.java)
|
||||
```
|
||||
|
||||
- Observe a live data in ViewModel
|
||||
```kotlin
|
||||
viewModel.counter.observe(this, Observer {
|
||||
counter.setText(it.toString())
|
||||
})
|
||||
```
|
||||
counter這個變數是包含在ViewModel裡面的live data,我們的資料則是放在counter裡面的「value」。
|
||||
所以如果要取用我們的data,則是:`viewModel.counter.value`。
|
||||
|
||||
- 使用LiveData
|
||||
- `val counter = MutableLiveData<Int>()`
|
||||
|
||||
### Use ViewBinding
|
||||
ViewBinding is used to replace Kotlin Synthetics.
|
||||
1. 在`app/build.gradle`中加入:
|
||||
```
|
||||
plugins {
|
||||
...
|
||||
id 'kotlin-parcelize' <-- Add this
|
||||
}
|
||||
|
||||
android {
|
||||
...
|
||||
buildFeatures { <-- Add this
|
||||
viewBinding true
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
2. 在你的activity裡面
|
||||
1. `import <APP_DOMAIN_NAME>.databinding.<ACTIVITY_NAME>Binding`
|
||||
假如:APP_DOMAIN_NAME是`com.example.testmultisectioncyclerview`,ACTIVITY_NAME是`ActivityMain`,那就是:
|
||||
`import com.example.testmultisectioncyclerview.databinding.ActivityMainBinding`
|
||||
2. 用`lateinit`宣告一個變數,變數名稱是activity的名字加上binding,例如`ActivityMain`就是:
|
||||
`private lateinit var activityBinding: ActivityMainBinding`
|
||||
3. 在`onCreate()`中,就可以用`activityBinding`來取得view與其他元件了:
|
||||
```
|
||||
activityBinding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setContentView(activityBinding.root) <-- root就是view
|
||||
```
|
||||
|
||||
## ADB usage
|
||||
- [如何透過 adb command line 指令啟動 Android App](https://kkboxsqa.wordpress.com/2014/08/20/%E5%A6%82%E4%BD%95%E9%80%8F%E9%81%8E-adb-command-line-%E6%8C%87%E4%BB%A4%E5%95%9F%E5%8B%95-android-app/)
|
||||
|
||||
# MISC
|
||||
## 教學文
|
||||
- [Android Template 小技巧 及 寫程式常見的問題](https://www.eeaseries.com/2021/01/android-template.html?m=1)
|
||||
- [Jetpack Compose 基础知识](https://developers.google.com/codelabs/jetpack-compose-basics?hl=zh-cn#0)
|
||||
- [一文带你了解适配Android 11分区存储](https://zhuanlan.zhihu.com/p/354632087)
|
||||
58
21.01. OS/21.04. Android/AudioTrack.md
Normal file
58
21.01. OS/21.04. Android/AudioTrack.md
Normal file
@@ -0,0 +1,58 @@
|
||||
`AudioTrack` 和 `MediaPlayer` 都可以播放聲音,主要差別是 `AudioTrack` 沒有 decode 的能力,只能播放 PCM。`MediaPlayer` 除了可以 demux、decode 以外,也可以播放video。
|
||||
|
||||
## 底層原理
|
||||
每一個 audio stream 對應著一個 `AudioTrack` 類的一個實例,每個 `AudioTrack` 會在建立時會註冊到 `AudioFlinger` 中,由 `AudioFlinger` 把所有的 `AudioTrack` 進行混合(Mixer),然後輸送到 AudioHardware 中 進行播放,目前 Android 同時最多可以創建32個音頻流,也就是說,Mixer 最多會同時處理32個 `AudioTrack` 的資料。
|
||||
|
||||
## 建立 AudioTrack 物件
|
||||
```kotlin
|
||||
const val SAMPLE_RATE = 44100
|
||||
const val CHANNEL_OUT_FORMAT = AudioFormat.CHANNEL_OUT_STEREO
|
||||
const val AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT
|
||||
var audioBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_OUT_FORMAT, AUDIO_FORMAT)
|
||||
|
||||
audioTrack = AudioTrack(
|
||||
AudioManager.STREAM_MUSIC,
|
||||
SAMPLE_RATE,
|
||||
CHANNEL_OUT_FORMAT,
|
||||
AUDIO_FORMAT,
|
||||
audioBufferSize,
|
||||
AudioTrack.MODE_STREAM)
|
||||
audioTrack?.play()
|
||||
```
|
||||
|
||||
其中需要注意的是最後一個參數,`AudioTrack` 有兩種模式,分別是 `AudioTrack.MODE_STREAM` 與 `AudioTrack.MODE_STATIC`。
|
||||
|
||||
## AudioTrack.MODE_STREAM
|
||||
這個模式會邊讀邊播,必須不停的使用 `AudioTrack.write()` 來將資料寫入,若是來不及寫入會造成斷音,先呼叫 `AudioTrack.play()`,然後開始填資料,透過 `AudioTrack.write()`。
|
||||
|
||||
## AudioTrack.MODE_STATIC
|
||||
這個模式中,audioBufferSize 就是你要播放的聲音長度,一樣要透過 `AudioTrack.write()` 來寫入資料,寫完之後呼叫 `AudioTrack.play()` 開始播放。
|
||||
|
||||
## 狀態判斷
|
||||
### `getState()`
|
||||
用 `getState() : Int` 來取得目前的狀態。
|
||||
- `STATE_INITIALIZED` 表示 `AudioTrack` 已經是可以使用了。
|
||||
- `STATE_UNINITIALIZED` 表示 `AudioTrack` 創建時沒有成功地初始化。
|
||||
- `STATE_NO_STATIC_DATA` 表示當前是使用 `MODE_STATIC` ,但是還沒往緩衝區中寫入數據。當接收數據之後會變為 `STATE_INITIALIZED` 狀態。
|
||||
|
||||
### `getPlayState()`
|
||||
用 `getPlayState() : Int` 來取得目前的播放狀態。
|
||||
- `PLAYSTATE_STOPPED` 停止
|
||||
- `PLAYSTATE_PAUSED` 暫停
|
||||
- `PLAYSTATE_PLAYING` 正在播放
|
||||
|
||||
## 暫停
|
||||
`pause()` 可以暫停播放,但是暫存區不會被清空
|
||||
|
||||
## 停止
|
||||
如果是 `AudioTrack.MODE_STREAM` mode,需要先呼叫 `pause()` 再呼叫 `flush()` 才能馬上停止,否則會等暫存區清空才停止。
|
||||
`AudioTrack.MODE_STATIC` mode 直接使用 `stop()` 即可。
|
||||
|
||||
## 釋放
|
||||
使用 `release()` 來結束資源。
|
||||
|
||||
## 參考
|
||||
- [AudioTrack](https://developer.android.com/reference/android/media/AudioTrack)
|
||||
- [音视频开发之旅(三)AudioTrack播放PCM音频](https://zhuanlan.zhihu.com/p/265804902)
|
||||
- [深入剖析Android音頻之AudioTrack](https://blog.csdn.net/yangwen123/article/details/39989751)
|
||||
- [Android音频开发之AudioTrack](https://www.jianshu.com/p/c67fd0c2b379)
|
||||
82
21.01. OS/21.04. Android/Ktor.md
Normal file
82
21.01. OS/21.04. Android/Ktor.md
Normal file
@@ -0,0 +1,82 @@
|
||||
---
|
||||
tags:
|
||||
aliases:
|
||||
date: 2024-06-05
|
||||
time: 19:06:00
|
||||
description:
|
||||
---
|
||||
|
||||
Ktor是由Kotlin提供的一個framwork。
|
||||
要在Android使用Ktor,需要在build.gradle加入以下的dependency:
|
||||
```
|
||||
implementation "io.ktor:ktor-server-core:2.0.1" // Ktor的核心包
|
||||
implementation "io.ktor:ktor-server-jetty:2.0.1" // 供Ktor使用的引擎包,另外有Jetty, Tomcat, CIO可用
|
||||
implementation "io.ktor:ktor-gson:1.2.5"
|
||||
// implementation "io.ktor:ktor-server-call-logging:2.0.1" // 用於印出Request及Response的log用
|
||||
// implementation "io.ktor:ktor-server-partial-content:2.0.1" // 用於支援PartialContent用
|
||||
// implementation "io.ktor:ktor-server-cors:2.0.1" // 用於支援CORS用
|
||||
// implementation "io.ktor:ktor-server-html-builder:2.0.1" // 用於回傳客製html用
|
||||
```
|
||||
|
||||
在`packagingOptions`裡,也需要加入以下的設定來必面編譯問題[[Ktor#^68d958 ]] :
|
||||
```
|
||||
packagingOptions {
|
||||
exclude 'META-INF/*'
|
||||
}
|
||||
```
|
||||
|
||||
在`AndroidManifest.xml`中,記得加入internet的權限:
|
||||
```
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
```
|
||||
|
||||
然後就是 HTTP Server 的 code 了,注意 Netty 在 Android 上不能用,要改用 Jetty 或是 CIO:
|
||||
```kotlin
|
||||
import io.ktor.server.jetty.Jetty
|
||||
import io.ktor.server.engine.embeddedServer
|
||||
import io.ktor.server.routing.routing
|
||||
import io.ktor.server.routing.get
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.response.respondText
|
||||
|
||||
embeddedServer(Jetty, 9000) {
|
||||
routing {
|
||||
get("/") {
|
||||
call.respondText("Hello, world!")
|
||||
}
|
||||
}
|
||||
}.start(wait = false)
|
||||
```
|
||||
|
||||
但是這段code會block,所以需要一個thread把它包起來:
|
||||
```kotlin
|
||||
Thread {
|
||||
httpEngine = embeddedServer(Netty, 8080) {
|
||||
install(ContentNegotiation) {
|
||||
gson {}
|
||||
}
|
||||
routing {
|
||||
get("/") {
|
||||
call.respond(mapOf("message" to "Hello world"))
|
||||
}
|
||||
|
||||
get("/say/{something}") {
|
||||
call.respond(mapOf("message" to "You say: " + call.parameters["something"]))
|
||||
|
||||
activity?.findViewById<TextView>(R.id.textView)?.text = "You say: " + call.parameters["something"]
|
||||
}
|
||||
}
|
||||
}.start(wait = false)
|
||||
}.start()
|
||||
```
|
||||
|
||||
|
||||
# 參考來源
|
||||
|
||||
- 如果沒有這一段會產生如下錯誤 ^68d958
|
||||
```
|
||||
13 files found with path 'META-INF/INDEX.LIST'.
|
||||
Adding a packagingOptions block may help, please refer to
|
||||
https://developer.android.com/reference/tools/gradle-api/7.4/com/android/build/api/dsl/ResourcesPackagingOptions
|
||||
for more information
|
||||
```
|
||||
108
21.01. OS/21.04. Android/MediaCodec.md
Normal file
108
21.01. OS/21.04. Android/MediaCodec.md
Normal file
@@ -0,0 +1,108 @@
|
||||
## 一般流程
|
||||
1. 使用者從MediaCodec請求一個空的輸入buffer(ByteBuffer),填充滿數據後將它傳遞給MediaCodec處理。
|
||||
2. MediaCodec處理完這些數據並將處理結果輸出至一個空的輸出buffer(ByteBuffer)中。
|
||||
3. 使用者從MediaCodec獲取輸出buffer的數據,消耗掉裡面的數據,使用完輸出buffer的數據之後,將其釋放回編解碼器。
|
||||
|
||||
流程如下圖所示:
|
||||
![[android_mediacodec_flow.png]]
|
||||
|
||||
## 生命週期
|
||||
MediaCodec的生命週期有三種狀態:Stopped、Executing、Released。
|
||||
- Stopped,包含三種子狀態:Uninitialized、Configured、Error。
|
||||
- Executing,包含三種子狀態:Flushed、Running、End-of-Stream。
|
||||
![[android_mediacodec_life_cycle.png]]
|
||||
|
||||
**Stopped** 的三種子狀態:
|
||||
1. Uninitialized:當創建了一個MediaCodec對象,此時處於Uninitialized狀態。可以在任何狀態調用reset()方法使MediaCodec返回到Uninitialized狀態。
|
||||
2. Configured:使用configure(…)方法對MediaCodec進行配置轉為Configured狀態。
|
||||
3. Error:MediaCodec遇到錯誤時進入Error狀態。錯誤可能是在隊列操作時返回的錯誤或者異常導致的。
|
||||
|
||||
**Executing** 的三種子狀態:
|
||||
1. Flushed:在調用start()方法後MediaCodec立即進入Flushed子狀態,此時MediaCodec會擁有所有的緩存。可以在Executing狀態的任何時候通過調用flush()方法返回到Flushed子狀態。
|
||||
2. Running:一旦第一個輸入緩存(input buffer)被移出隊列,MediaCodec就轉入Running子狀態,這種狀態佔據了MediaCodec的大部分生命週期。通過調用stop()方法轉移到Uninitialized狀態。
|
||||
3. End-of-Stream:將一個帶有end-of-stream標記的輸入buffer入隊列時,MediaCodec將轉入End-of-Stream子狀態。在這種狀態下,MediaCodec不再接收之後的輸入buffer,但它仍然產生輸出buffer直到end-of-stream標記輸出。
|
||||
|
||||
**Released**
|
||||
1. 當使用完MediaCodec後,必須調用release()方法釋放其資源。調用release()方法進入最終的Released狀態。
|
||||
|
||||
## API
|
||||
### createEncoderByType
|
||||
- [createEncoderByType](https://developer.android.com/reference/android/media/MediaCodec#createEncoderByType(java.lang.String))
|
||||
|
||||
### createDecoderByType
|
||||
- [createDecoderByType](https://developer.android.com/reference/android/media/MediaCodec#createDecoderByType(java.lang.String))
|
||||
|
||||
### configure
|
||||
- [configure]([MediaCodec | Android Developers](https://developer.android.com/reference/android/media/MediaCodec#configure(android.media.MediaFormat,%20android.view.Surface,%20android.media.MediaCrypto,%20int)))
|
||||
|
||||
### start
|
||||
- [start](https://developer.android.com/reference/android/media/MediaCodec#start())
|
||||
|
||||
### dequeueInputBuffer
|
||||
- [dequeueInputBuffer](https://developer.android.com/reference/android/media/MediaCodec#dequeueInputBuffer(long))
|
||||
|
||||
### queueInputBuffer
|
||||
- [queueInputBuffer](https://developer.android.com/reference/android/media/MediaCodec#queueInputBuffer(int,%20int,%20int,%20long,%20int))
|
||||
|
||||
### getInputBuffer
|
||||
- [getInputBuffer](https://developer.android.com/reference/android/media/MediaCodec#getInputBuffer(int))
|
||||
|
||||
### dequeueOutputBuffer
|
||||
- [dequeueOutputBuffer](https://developer.android.com/reference/android/media/MediaCodec#dequeueOutputBuffer(android.media.MediaCodec.BufferInfo,%20long))
|
||||
|
||||
### getOutputBuffer
|
||||
- [getOutputBuffer](https://developer.android.com/reference/android/media/MediaCodec#getOutputBuffer(int))
|
||||
|
||||
### releaseOutputBuffer
|
||||
- [releaseOutputBuffer](https://developer.android.com/reference/android/media/MediaCodec#releaseOutputBuffer(int,%20boolean))
|
||||
|
||||
### stop
|
||||
- [stop](https://developer.android.com/reference/android/media/MediaCodec#stop())
|
||||
|
||||
### release
|
||||
- [release](https://developer.android.com/reference/android/media/MediaCodec#release())
|
||||
|
||||
## 使用
|
||||
1. 根據需求使用 [[#createEncoderByType]]或是 [[#createDecoderByType]] 建立codec。以下以 encode 為例。
|
||||
2. 呼叫 [[#configure]],傳入相應的 MediaFormat。
|
||||
3. 呼叫 [[#start]],開始 encode。
|
||||
4. 建立一個迴圈,不斷的傳入要 encode 的 buffer,也不斷的拿出已經 encode 的 buffer。
|
||||
5. 在迴圈內,要傳入的 buffer 處理方法:
|
||||
1. 呼叫 [[#dequeueInputBuffer]],試探是否有能用的 buffer,如果有,回傳值將大於等於0(>= 0)。這裡假設回傳值的變數叫做 index。
|
||||
2. 如果 index 合法,用 [[#queueInputBuffer]],像是 `inputBuffer = queueInputBuffer(index)` 來取得可用的 buffer。這裡假設 buffer 的變數叫做 inputBuffer。
|
||||
3. 將要 encode 的資料 copy 到 inputBuffer。
|
||||
4. 若要停止 encode,送出 `codec.queueInputBuffer(inputBufIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM)`。
|
||||
6. 在迴圈內,要取得已經encode buffer的方法:
|
||||
1. 呼叫 [[#dequeueOutputBuffer]],試探是否有 encoded buffer,如果有,回傳值將大於等於0(>= 0)。這裡假設回傳值的變數叫做 index。
|
||||
2. 如果 index合法,用 [[#getOutputBuffer]],像是`outputBuffer = getOutputBuffer(index)` 來取得可用的 buffer。這裡假設 buffer 的變數叫做 outputBuffer。
|
||||
3. outputBuffer 就是已經 encode 好的,就看你怎麼處理。
|
||||
4. 重要!呼叫 [[#releaseOutputBuffer]] 來回收剛剛那一塊 buffer。
|
||||
|
||||
Psuedo code 如下:
|
||||
```kotlin
|
||||
while (true)
|
||||
// send buffer to encode
|
||||
index = dequeueInputBuffer()
|
||||
if (index >= 0)
|
||||
if (!end)
|
||||
inputBuffer = queueInputBuffer(index)
|
||||
copy(inputBuffer, srcBuffer)
|
||||
else
|
||||
queueInputBuffer(inputBufIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM)
|
||||
// Get encoded buffer
|
||||
index = dequeueOutputBuffer()
|
||||
if (index >= 0)
|
||||
outputBuffer = getOutputBuffer(index)
|
||||
releaseOutputBuffer(index)
|
||||
```
|
||||
|
||||
## 參考資料
|
||||
- [Android音视频之使用MediaCodec编解码AAC - 简书](https://www.jianshu.com/p/14daab91b951)
|
||||
- [MultiMediaLearning/app/src/main/java/com/richie/multimedialearning/mediacodec at master · isuperqiang/MultiMediaLearning](https://github.com/isuperqiang/MultiMediaLearning/tree/master/app/src/main/java/com/richie/multimedialearning/mediacodec)
|
||||
- [初识MediaCodec - 知乎](https://zhuanlan.zhihu.com/p/45224834)
|
||||
- [MediaCodec的使用介绍 - 简书](https://www.jianshu.com/p/f5a1c9318524)
|
||||
- [Android原生编解码接口MediaCodec详解 - 掘金](https://juejin.cn/post/7086297619764346887)
|
||||
- [AndroidMediaCodecDemo/AudioDecoder.kt at main · king-ma1993/AndroidMediaCodecDemo](https://github.com/king-ma1993/AndroidMediaCodecDemo/blob/main/app/src/main/java/com/myl/mediacodedemo/decode/audio/AudioDecoder.kt)
|
||||
- [Android使用系统API进行音视频编码_key_max_input_size_blueberry_mu的博客-CSDN博客](https://blog.csdn.net/a992036795/article/details/54286654)
|
||||
- [MediaCodec 完成PCM编码成AAC - 知乎](https://zhuanlan.zhihu.com/p/564759685)
|
||||
- [MediaCodec 同步方式完成AAC硬解成PCM - 知乎](https://zhuanlan.zhihu.com/p/564734700)
|
||||
205
21.01. OS/21.04. Android/Service.md
Normal file
205
21.01. OS/21.04. Android/Service.md
Normal file
@@ -0,0 +1,205 @@
|
||||
## Service的生命週期
|
||||
![[Pasted image 20220307103552.png]]
|
||||
|
||||
## Service的啟動方式
|
||||
Service由`startService()`啟動之後,便獨立動作,啟動者(例如某個activity)無法取得Service的intance,也無法呼叫Service的API。Service可以被多次呼叫`startService()`,但是只要一旦`stopService()`被呼叫了,Service就會結束。所以需要確保Service的管理者是誰,統一管理者來呼叫`startService()`與`stopService()`才不會造成混亂。
|
||||
|
||||
`bindService()`則是像是典型的Server-Client架構,第一次`bindService()`的時候會建立Service的instance,然後可以多次`bindService()`與`unbindService()`,當Service沒也任何人跟它"Bind"的時候,Service才會結束。
|
||||
|
||||
### startService
|
||||
要建立自己的Service,需要繼承`Service()`類別,然後複寫4個成員函式:
|
||||
```kotlin
|
||||
class MyService : Service() {
|
||||
|
||||
override fun onCreate() {
|
||||
Log.i("Awin","onCreate - Thread ID = " + Thread.currentThread().id)
|
||||
super.onCreate()
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
Log.i("Awin", "onStartCommand - startId = " + startId + ", Thread ID = " + Thread.currentThread().id)
|
||||
return super.onStartCommand(intent, flags, startId)
|
||||
}
|
||||
|
||||
override fun onBind(p0: Intent?): IBinder? {
|
||||
Log.i("Awin", "onBind - Thread ID = " + Thread.currentThread().id)
|
||||
return null // 因為目前沒有要支援bindService(),所以這裡直接return null
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
Log.i("Awin", "onDestroy - Thread ID = " + Thread.currentThread().id)
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
假設現在由MainActivity呼叫`startService()`,因為是第一次呼叫,所以MyService的callback被呼叫的順序是:`onCreate()` -> `onStartCommand()`。
|
||||
第二次之後的呼叫就只會執行`onStartCommand()`。
|
||||
當MainActivity呼叫`stopService()`時,則會執行MyService的`onDestroy()`。
|
||||
|
||||
所以,必須將「長期任務」開個 Thread 並且執行在 `onStartCommand()` 方法內。
|
||||
|
||||
Client端的code:
|
||||
```kotlin
|
||||
val intent = Intent(this, ServiceDemo.class)
|
||||
startService(intent)
|
||||
```
|
||||
|
||||
### bindService
|
||||
使用`bindService()`來建立Service的一個好處就是可以取得Service的instance,然後藉由這個instance來使用Service的API。
|
||||
要使用`bindService()`的話,Service類別必須實做`onBind()`與`onUnbind()`至兩個override function。
|
||||
也必須提供一個Binder class(繼承自`Binder()`),來讓client呼叫。例:
|
||||
```kotlin
|
||||
class MyService : Service() {
|
||||
|
||||
//client 可以通过Binder获取Service实例
|
||||
inner class MyBinder : Binder() {
|
||||
val service: MyService
|
||||
get() = this@MyService
|
||||
}
|
||||
|
||||
//通过binder实现调用者client与Service之间的通信
|
||||
private val binder = MyBinder()
|
||||
|
||||
private val generator: Random = Random()
|
||||
|
||||
override fun onCreate() {
|
||||
Log.i("xiao", "MyService - onCreate - Thread = " + Thread.currentThread().name)
|
||||
super.onCreate()
|
||||
}
|
||||
|
||||
/**
|
||||
* @param intent 啟動時,啟動組件傳遞過來的Intent,如Activity可利用Intent封裝所需要的參數並傳遞給Service
|
||||
* @param flags 表示啟動請求時是否有額外數據,可選值有 0,START_FLAG_REDELIVERY,START_FLAG_RETRY
|
||||
* 0: 在正常創建Service的情況下,onStartCommand傳入的flags為0。
|
||||
*
|
||||
* START_FLAG_REDELIVERY:
|
||||
* 這個值代表了onStartCommand()方法的返回值為 START_REDELIVER_INTENT,
|
||||
* 而且在上一次服務被殺死前會去調用stopSelf()方法停止服務。
|
||||
* 其中START_REDELIVER_INTENT意味著當Service因記憶體不足而被系統kill後,
|
||||
* 則會重建服務,並透過傳遞給服務的最後一個 Intent調用 onStartCommand(),此時Intent時有值的。
|
||||
*
|
||||
* START_FLAG_RETRY
|
||||
* 該flag代表當onStartCommand()調用後一直沒有返回值時,會嘗試重新去調用onStartCommand()。
|
||||
*
|
||||
* @param startId 指明當前服務的唯一ID,與stopSelfResult(int startId)配合使用,stopSelfResult()可以更安全地根據ID停止服務。
|
||||
*
|
||||
* @return
|
||||
* START_STICKY:
|
||||
* 當Service因記憶體不足而被系統kill後,一段時間後記憶體再次空閒時,
|
||||
* 系統將會嘗試重新創建此Service,一旦創建成功後將回調onStartCommand方法,
|
||||
* 但其中的Intent將是null,除非有掛起的Intent,如pendingintent,
|
||||
* 這個狀態下比較適用於不執行命令、但無限期運行並等待作業的媒體播放器或類似服務
|
||||
*
|
||||
*
|
||||
* START_NOT_STICKY:
|
||||
* 當Service因記憶體不足而被系統kill後,即使系統記憶體再次空閒時,
|
||||
* 系統也不會嘗試重新創建此Service。除非程序中再次調用startService啟動此Service,
|
||||
* 這是最安全的選項,可以避免在不必要時以及應用能夠輕鬆重啟所有未完成的作業時運行服務。
|
||||
*
|
||||
* START_REDELIVER_INTENT:
|
||||
* 當Service因記憶體不足而被系統kill後,則會重建服務,
|
||||
* 並透過傳遞給服務的最後一個 Intent 調用 onStartCommand(),任何掛起 Intent均依次傳遞。
|
||||
* 與START_STICKY不同的是,其中的傳遞的Intent將是非空,是最後一次調用startService中的intent。
|
||||
* 這個值適用於主動執行應該立即恢復的作業(例如下載文件)的服務。
|
||||
*/
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
Log.i("xiao", "MyService - onStartCommand - startId = $startId, Thread = " + Thread.currentThread().name)
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent): IBinder{
|
||||
Log.i("xiao", "MyService - onBind - Thread = " + Thread.currentThread().name)
|
||||
return binder
|
||||
}
|
||||
|
||||
override fun onUnbind(intent: Intent): Boolean {
|
||||
Log.i("xiao", "MyService - onUnbind - from = " + intent.getStringExtra("from"))
|
||||
return super.onUnbind(intent)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
Log.i("xiao", "MyService - onDestroy - Thread = " + Thread.currentThread().name)
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
//getRandomNumber是Service暴露出去供client调用的公共方法
|
||||
fun getRandomNumber(): Int {
|
||||
return generator.nextInt()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Client端要做的事:
|
||||
1. 建立ServiceConnection類型實例,並覆載`onServiceConnected()`方法和`onServiceDisconnected()`方法。
|
||||
2. 當執行到onServiceConnected callback時,可通過IBinder instance得到Service的instance,這樣可實現client與Service的連接。
|
||||
3. onServiceDisconnected callback被執行時,表示client與Service已經斷開,在此可以寫一些斷開後需要做的處理。
|
||||
```kotlin
|
||||
class AActivity : AppCompatActivity() {
|
||||
|
||||
private var service: MyService? = null
|
||||
private var isBind = false
|
||||
|
||||
private var conn = object : ServiceConnection{
|
||||
override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {
|
||||
isBind = true
|
||||
val myBinder = p1 as MyService.MyBinder
|
||||
service = myBinder.service
|
||||
Log.i("xiao", "ActivityA - onServiceConnected")
|
||||
val num = service!!.getRandomNumber()
|
||||
Log.i("xiao", "ActivityA - getRandomNumber = $num");
|
||||
}
|
||||
|
||||
override fun onServiceDisconnected(p0: ComponentName?) {
|
||||
isBind = false
|
||||
Log.i("xiao", "ActivityA - onServiceDisconnected")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_a)
|
||||
|
||||
Log.i("xiao", "ActivityA - onCreate - Thread = " + Thread.currentThread().name)
|
||||
|
||||
btn_bind_service_a.setOnClickListener {
|
||||
val intent = Intent(this,MyService::class.java)
|
||||
intent.putExtra("from","ActivityA")
|
||||
Log.i("xiao", "----------------------------------------")
|
||||
Log.i("xiao", "ActivityA 执行 bindService");
|
||||
bindService(intent, conn, Context.BIND_AUTO_CREATE)
|
||||
}
|
||||
btn_unbind_service_a.setOnClickListener {
|
||||
if(isBind){
|
||||
Log.i("xiao", "----------------------------------------")
|
||||
Log.i("xiao", "ActivityA 执行 unbindService");
|
||||
unbindService(conn)
|
||||
}
|
||||
}
|
||||
btn_a_start_b.setOnClickListener {
|
||||
val intent = Intent(this,BActivity::class.java)
|
||||
Log.i("xiao", "----------------------------------------")
|
||||
Log.i("xiao", "ActivityA 启动 ActivityB");
|
||||
startActivity(intent)
|
||||
}
|
||||
btn_finish_a.setOnClickListener {
|
||||
Log.i("xiao", "----------------------------------------")
|
||||
Log.i("xiao", "ActivityA 执行 finish");
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
Log.i("xiao", "ActivityA - onDestroy")
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 參考
|
||||
1. [如何使用Service(kotlin)](https://givemepass.blogspot.com/2015/10/service.html)
|
||||
2. [Android kotlin service使用简析 - 簡書](https://www.jianshu.com/p/f9712b470b42)
|
||||
3. [《Android》『Service』- 背景執行服務的基本用法 - 賽肥膩膩の娛樂生活誌](https://xnfood.com.tw/android-service/#skill_02)
|
||||
17
21.01. OS/21.04. Android/Tools.md
Normal file
17
21.01. OS/21.04. Android/Tools.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# screenrecord
|
||||
## 螢幕錄影
|
||||
用`screenrecord `可以把目前的螢幕錄製下來,一個簡單的例子:
|
||||
```
|
||||
adb shell screenrecord --size 1200x1920 /storage/sdcard0/demo.mp4
|
||||
```
|
||||
|
||||
### 指定錄製時間
|
||||
```
|
||||
adb shell screenrecord --time-limit 10 /storage/sdcard0/demo.mp4
|
||||
```
|
||||
|
||||
### 指定bit rate
|
||||
```
|
||||
adb shell screenrecord --bit-rate 6000000 /storage/sdcard0/demo.mp4
|
||||
```
|
||||
沒有指定時間的話,就必須手動`Ctrl+c`來中止錄影。
|
||||
8
21.01. OS/21.04. Android/UI.md
Normal file
8
21.01. OS/21.04. Android/UI.md
Normal file
@@ -0,0 +1,8 @@
|
||||
## 在thread更新UI
|
||||
Android framework只能在main thread裡更新UI,若需要在其他的thread更新UI的話,需要呼叫activity的`runOnUiThread()`。
|
||||
例:
|
||||
```kotlin
|
||||
activity?.runOnUiThread {
|
||||
activity?.findViewById<TextView>(R.id.textView)?.text = "You say: " + call.parameters["something"]
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user