2020/12/22

Delete None Keeping Files

當我們在備份文件的時候,通常只保留一定的數量,例如說 10 天份,我們可能會這樣寫:

$ find PATH_TO_FILES -mtime +30 | xargs rm -f &> /dev/null
$ find PATH_TO_FILES -mtime +30 -exec rm {} \ &> /dev/null;

這兩種寫法結果一樣,都是會刪除建立超過三十天以上的檔案,不過這會有個問題,假設今天因為某些因素備份指令中斷了,但 crontab 依舊在跑刪除指令,若 op 沒有及時發現,備份檔終究會被刪光,因此另一種寫法我認為是比較好的

我們先製造六個檔案

i=1; while [ $i -lt 7 ]; do touch $i; ((i++)); done

$ ll -d ./*
-rw-r--r-- 1 root root 0 12月 22 11:45 ./1
-rw-r--r-- 1 root root 0 12月 22 11:45 ./2
-rw-r--r-- 1 root root 0 12月 22 11:45 ./3
-rw-r--r-- 1 root root 0 12月 22 11:45 ./4
-rw-r--r-- 1 root root 0 12月 22 11:45 ./5
-rw-r--r-- 1 root root 0 12月 22 11:45 ./6

假設我們只要保留 5 個檔案,指令就是:

$ ls -ltd ./* | tail -n +6 | awk '{print $NF}' | xargs rm -f &> /dev/null

-d 過濾了 ./ 以及 ../-t 會照時間排序,tail -n +6 就是拉出超過 n 數量的結果,要保留 5 份的話要填入 6,所以檔名 1-6 時 6 會被篩選出來,awk '{print $NF}' 會印出篩選出來資訊的尾端,也就是檔名,最後就用 xargs rm -f 刪除該檔案,這樣寫的話不管時間的影響該備份目錄永遠會留下你指定的檔案數量。

2020/12/15

Required Input On Bash

在寫 shell script 的時候有時候必須填寫必要參數,如果想要 ui friendly 的話可以使用 prompt 的互動方式請 user 填寫。

ask.sh
#!/bin/bash  
  
while [[ -z ${name} ]]; do  
  read -rp "your name: " name  
done  
  
while [[ -z ${age} ]]; do  
  read -rp "your age: " age  
done  
  
echo "Hello ${name^^}, your age is ${age}"

上方的執行過程如下:

$ /bin/bash ask.sh
your name: chan wu
your age: 40
Hello CHAN WU, your age is 40

2020/12/01

php-fpm config

apache 跟 nginx 都有接觸,nginx 上本就是用 php-fpm 跟 php 溝通,現在 apache 上我也捨棄內建的 php module,改用 fcgi 去溝通了,有幾個好處:

  1. apache 內建 php module 必須綁死 php 版本
  2. 因為綁死 php 版本如果有使用 virtual host 的話要做到每個網站跑自己的 php 版本很麻煩
  3. php-fpm 效能以及穩定性綜合值應該是優於 apache php module

在 Ubuntu 上我選擇了 ondrej/php 當作 repo

sudo add-apt-repository ppa:ondrej/php
sudo apt-get update
apt install php7.3 php7.3-fpm

CentOS 上使用 remi

dnf install dnf-utils http://rpms.remirepo.net/enterprise/remi-release-8.rpm
dnf module reset php
dnf module enable php:remi-7.4
dnf install php

Config

Apache

Through socket file
<VirtualHost>
    # someting config
    <FilesMatch \.php$>
        SetHandler "proxy:unix:/var/run/php/php7.2-fpm.sock|fcgi://localhost/"
    </FilesMatch>    
</VirtualHost>
Through port
<VirtualHost>
    # someting config
    <FilesMatch \.php$>
        setHandler "proxy:fcgi://127.0.0.1:9000"
    </FilesMatch>  
</VirtualHost>

Apache 使用上必須確定 proxy_module 以及 proxy_fcgi_module 這兩個 module 有開啟,前者必須在後者上方先載入。

Nginx

location ~* \.php$ {
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_split_path_info ^(.+\.php)(.*)$;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}

Reference

2020/11/26

Temporary SSL config for Apache and Nginx

開發時需要測試 ssl 的功能或配置結果但不需要真的 ssl 證書時,我們可以生成自己的 ssl 配置在本機使用 https 連入。

生成證書

openssl req -nodes -newkey rsa:2048 -sha256 -keyout server.key -out server.csr

# 生成過程其他問題都可以亂填,但 FQDN 必須填對
# 這邊使用 ssl.local 當作測試 domain
# Common Name (e.g. server FQDN or YOUR name) []:ssl.local

openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Nginx config

server {
    listen      443;
    listen  [::]:443;
    server_name  ssl.local;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    ssl on;
    ssl_certificate_key /etc/nginx/ssl/server.key;
    ssl_certificate /etc/nginx/ssl/server.crt;

    location ~ /\.ht {
        deny  all;
    }
}

Apache Config

<VirtualHost *:443>
    ServerName ssl.local
    DocumentRoot /var/www/ssl/
 
    SSLEngine on
    SSLCertificateKeyFile /usr/local/apache2/conf/server.key
    SSLCertificateFile /usr/local/apache2/conf/server.crt
    SSLCertificateChainFile /usr/local/apache2/conf/server.crt
 
    <Directory "/var/www/ssl/">
        Options Indexes FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>
</VirtualHost>

2020/11/23

手沖淺知識

玩手沖幾年了,寫一下心得希望對要踏入這個領域的親友可以有所幫助。

咖啡豆是什麼

咖啡豆是咖啡櫻桃裡面的種子,我們常聽到很多處理法,例如日曬、水洗以及蜜處理,這些是指把咖啡豆以外的部分去除的工法,選用不同的方式會讓日後咖啡在烘焙時產生不同的風味,除了莊園本身就喜歡強調某種風味以外,有時候是成本考量,例如水洗法需要大量的水,這樣對水資源較缺乏的地方成本負擔就太大,去除後的咖啡果果肉有些廠商會拿去做再加工,轉換為另一種食品,所謂的麝香貓咖啡就是咖啡農們相信麝香貓只會去找最甜的咖啡果吃,消化後的豆子經過他們胃酸的發酵別有風味,但現在市面上假貨太多,有的廠商也用非天然的方式去取得,所以不鼓勵喝。

影響咖啡的風味除了處理法以外,豆子的品種有也有很大的關係,目前最貴的豆種是 Geisha,因為跟日文藝伎的發音雷同所以大家又叫他藝伎豆,我覺得他另一個中譯名「瑰夏」更好聽就是了,Geisha 擁有特殊的柑橘花香氣以及不好栽種的原因讓他的身價一直居高不下,今年的咖啡展有人賣到 20g 5,000 元,現場沖 50ml 1,000 元一杯還有許多人願意掏錢就知道他多受歡迎。

烘豆是什麼

烘豆就是把咖啡生豆轉換為熟豆的一個過程,轉換結果有八種,可以參考咖啡烘焙全程變化有多大?烘焙類型知識點分享,為了讓消費者便於購買接近自己喜歡的風味,一般都只講淺、中、深三種焙度,前面提到咖啡果是一種水果,淺焙是最接近原生水果的味道,在這個烘焙區間的豆子比較多花香、果香等水果調性,酸甜也很分明,中或深焙讓焦糖化的效果更突出產生另一種風味,每個人口味不同,但多半長期喝精品的品飲者都會買淺焙,享受咖啡果實的原始風味,區隔性也較高,我是建議喝到中焙就好,過深的豆子已經很難分辨所謂的風味了有點可惜。

烘豆既然是一種熟化過程,只要你能妥善均勻加熱用炒鍋也可以,新竹有一間咖啡廳叫「邊境十三咖啡」就標榜用鍋炒來熟化,台灣因為咖啡太流行,也出了很多可以在家烘豆的器具,像是 rf300、sr540、boca boca,都可以簡單在家體驗烘豆樂趣,如果對自己烘出來的成品很滿意,買生豆自烘自喝除了口味獨特以外也非常省錢,鹹魚爸就是最好的例子。

手沖是什麼

其實沖煮咖啡就跟泡茶一樣都是萃取,也就是利用水將咖啡粉上的物質帶出轉化為飲品的過程,萃取變因很多,最基本的有咖啡豆保存狀況、磨豆的粗細、水溫、注水手法、注水的器具、水質,因為變數太多了,所以同一個豆子給不同的人煮風味完全不一樣,有的咖啡師甚至可以為了客人的喜好客製你喜歡的味道。

提到萃取必須上一張圖:

業界有一種說法叫金杯理論,也就是大眾最能接受的風味是萃取率介於 18% ~ 22% 之間,咖啡濃度在 1.2% ~ 1.45% 的範圍內,咖啡濃度單位叫 TDS,坊間都可以買到儀器測量,比賽選手也會透過 TDS 檢測來穩定自己的手法,如果你的出杯能夠穩定的在這個數據範圍就可以稱的上職人了,不過就像威士忌一樣,符合標準未必符合你口味,有的人就喜歡焦苦,那金杯就不適合你。

對於我們這種休閒玩家來說,希望出杯穩定主要重點有幾個:

  1. 水溫
  2. 咖啡粉粗細
  3. 萃取時間

想找出自己喜愛的味道一般有兩個調整方式最顯著

  1. 粉越細水流越慢味道越重(也容易過萃)
  2. 溫度越高味道越重(帶走咖啡的物質比例越高)

我發現很多人覺得味道太淡要調粗,這觀念是錯誤的,粉越細萃取率越高,因為單位面積變小了水觸碰面變高,而且水越細水流通道面積變窄越容易塞水,浸泡時間也變長,化繁為簡,如果你覺得你的咖啡太淡,可以調高水溫或者把粉磨細,太濃就相反,因此可以看到很多人深焙的建議水溫是抓 82 ~ 88,淺焙是 90 ~ 93,因為深焙不好的物質較多味道也較重,透過減低萃取時間比較可以平衡味道。

怎麼沖

手沖手法真的超級多,流派也很多,可以臨摹 youtube 上各位大師的教學,台灣咖啡很強,國際賽冠軍一堆,也不吝嗇分享,在台灣真的很幸福,以下介紹幾個我常用來操作的系統。

王策 - 單點注水

https://www.youtube.com/watch?v=OJLS9oAuzpk

  1. 15g 粉 250ml 水
  2. 粉磨細分段注水
  3. 快沖
  4. 分段注水 30ml -> 120ml -> 180ml -> 250ml
  5. 總時間約 2:00 ~ 2:15

粕谷哲 - 46 沖法

https://www.youtube.com/watch?v=Lc6v19pIqVs

  1. 20g 粉 300ml 水
  2. 粉磨粗分段注水
  3. 40ml -> 120ml -> 180ml -> 240ml -> 300ml
  4. 每次注水間隔 45 秒,也就是 45 -> 1:30 -> 2:15 -> 3:00

可樂哥 - 可樂流星芒濾杯注水法

https://www.youtube.com/watch?v=AX49aHryXUc

  1. 20g 粉 260 ml 水
  2. 不斷水注水法
  3. 40ml 快速繞水
  4. 40ml -> 120ml 緩慢繞水
  5. 120ml -> 220ml 最外圍大水柱繞水
  6. 220ml -> 260ml 繞回中心點收水
  7. 總時間約 1:30 ~ 1:40

吳則霖

https://www.youtube.com/watch?v=Q3RkC7hiUV0

  1. 16g 粉 240ml 水
  2. 40ml 悶蒸
  3. 40ml -> 120ml -> 200ml 粗水柱慢繞圈,每次都流乾再注水
  4. 200ml -> 240ml 細水注中心注水
  5. 總時間約 2:00 ~ 2:15

上面四個系統都有相同的特點,「控時」,這帶到一個核心問題,你在一家店喝到好喝的手沖,怎麼盡可能複製到自己家呢,我上面有提到的三核心,水溫、 粗細、萃取時間,水溫我們可用溫度計控制,但每個人的磨豆機不同,我該怎麼磨粗細才是對的,很簡單,就是看萃取時間,如果定溫而且注水量穩定後你的成品跟大師們時間差異過大,能調整的就是咖啡粗細,遠超過大師的萃取時間就調粗一點,過快就調細,這樣理論上就可以接近該系統希望達到的效果,所以可計時的電子秤才如此的重要,確保你的斷水分段穩定,減少外在變因影響味道,如果你不透過這些輔助器去沖,要嗎你就是超穩定的職人,要嗎你早上跟下午沖的兩杯味道可能不一樣,如果隨性的人當然無所謂,但想追求品質一致性的人溫控壺跟計時電子秤是必買的。

店家推薦

台灣的咖啡廳密度很高,好喝的店家也不少跟可購買的商品也不少,在這邊分享幾個我的愛店。

咖啡廳

  1. Coffee Sweet - 極強的賽風店家
  2. 虎記商行 - 極有風格的老闆,豆子很有風格
  3. 興波咖啡 - 這間不用多說了,Berg Wu 的店,亞洲第一
  4. VWI by CHADWANG - 我的愛店,也是冠軍級別
  5. Shawn Coffee - 前 milk glider 的店員出來開的,拿鐵跟拉花很強
  6. CHLIV Jiufen - 在日本得過世界拉花冠軍,拿鐵很強

咖啡豆

  1. KaKaLove
  2. 日出印象
  3. 虎記商行
  4. GK 咖啡

結論

台灣的咖發市場很大,每天人手一杯的大有人在,進入這個領域後也瞭解到很多事情,例如說不好的豆子對身體健康影響多大,我常提倡不要喝星巴克,這角度是從單品或濃縮出發,如果你是去點星冰樂的,go ahead,對我來說那不叫喝咖啡,就像不會有人說喝珍珠奶茶叫喝茶吧,一切的出發點都是希望我身邊愛喝咖啡的人可以健康,俊元兄日前也在他的頻道提出相關內容,星巴克派克市場 咖啡豆為什麼價差這麼大?-元食咖啡,商業瑕疵豆產生的毒素對身體會有什麼影響可以參考淺談「咖啡瑕疵豆」 美國精品咖啡協會(SCAA)的定義,真的需要咖啡因提神的,seven 的豆子品質都可能比較好,台灣咖啡廳密度這麼高,好單品隨手可得,挖掘出喜歡的店家也是一種樂趣,當然還有很多東西可以講,既然是淺談就寫到這啦,有興趣的人可以找我討論。

2020/11/13

SSL Common Knowledge

網站掛上 SSL 已經是基本要求了,市面上也很多免費產品,像是 let’s encryptcloudflare 等等,這些服務都可以透過簡單的設定或申請讓你的網站擁有 SSL,不過還是不乏會有自己花錢購買憑證的需求,此文記錄一些重點事項。

申請流程需要生成兩個檔案

  1. 私有金鑰 – private key
  2. 簽署要求 – certificate signing request (CSR)

CSR 產生後上繳給 SSL 販賣廠商,完成後他會返回憑證以及中繼憑證,只要有 key、crt、以及 ca 就可以配置 apache 跟 nginx 了。

產生 key 與 csr

key 跟 csr 可以一起產生或者分開產生

一起產生
openssl req -nodes -newkey rsa:2048 -sha256 -keyout server.key -out server.csr

CSR 會詢問很多問題,必須填寫正確,否則之後使用會有問題

分開產生

先產生了 key

openssl genrsa -out server.key 2048

透過 key 產生 csr

openssl req -new -key server.key -out server.csr

利用 key 與 csr 產生 crt

openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

憑證轉碼

憑證下來以後,大部分會拿到兩種檔案,一種是 cer,一種是 pfx,pfx 就是帶有私鑰的證書文件,多半會拿到的是 cer,用他來解出 crt。

cer -> crt
openssl x509 -in server.cer -out server.crt -inform DER
pfx -> crt and ca
openssl pkcs12 -in server.pfx -nokeys -out server.crt -nodes -password pass:123456
pfx -> key
openssl pkcs12 -in server.pfx -nocerts -out server.key -nodes -password pass:123456

驗證證書內容

openssl pkey -in server.key -pubout -outform pem | sha256sum
openssl x509 -in server.crt -pubkey -noout -outform pem | sha256sum
openssl req -in server.csr -pubkey -noout -outform pem | sha256sum

正常來說這三個檔案的 sha 值要相同

檢查 private key

openssl rsa -noout -text -check -in server.key

有時候我們要確認一下 key 有沒有 passphrase,否則直接安裝後他問密碼我們不知道那 http server 會直接開不了,假設這組 key 有密碼,而你也知道密碼,我們可以產一個沒有密碼的 key 出來。

openssl rsa -in server.key -out server.no_password.key

參考資料

openssl 指令 command line - 轉檔 pem/der/p7b/pfx/cer | SSORC.tw
[SSL 基礎]私有金鑰、CSR 、CRT 與 中繼憑證 | 哈部落

2020/11/11

awk search for specific key

一般我們的 envfile 會這樣配。

NAME=chan
AGE=40

假設今天 envfile 很長,你只想找出某個 key 的值該怎麼做呢,可以透過 awk

search.sh
#!/bin/bash

DIR=$1
KEY=$2

awk -F= -v key="$KEY" '{if ($1 == key) {print $2}}' $DIR

執行

bash search.sh envfile NAME

會得到 chan,補上變數跟目錄是否存在檢查就更完整了。

2020/11/04

Laravel Homestead Windows Folder Sync Issue

目前工作是基於 Laravel 開發公司產品,系統環境是 Windows,開發環境安裝了 Homestead,Homestead 是 Laravel 官方釋出,使用 Vagrant 安裝 Ubuntu,透過 config 可配置出 Laravel 開發需要的所有內容,包含 PHP(多種版本)、Apache 或 Nginx 提供選擇、Database、Redis 等等,Windows 以及 Mac 都可用,對 Windows user 來說最大的好處是開發環境可以較接近 production 環境(unix base)。

虛擬機器的工作模式多半會跟實體環境 mount 共同目錄,這樣可以直接在本機編輯檔案,虛擬環境連結的的內容會即時更新,但使用 Homestead 開發時一直遇到問題,例如在 vm 環境無法刪除某些檔案,或者是專案從 gitlab 下載以後 compose install 時會有錯誤訊息,像是:

[ErrorException]
  include(/home/vagrant/code/laravel/vendor/phpstan/extension-installer/src/Plugin.php): failed to open stream: No such file 
  or directory

只要把檔案放置在非 sync 的目錄下執行就不會有問題,因此我選擇了從別的地方 composer install or update 之後再複製到 sync 目錄,一直到日前我要開發新專案直接 new 一個新的目錄出後發生了更多大大小小的錯誤,包括測試會中斷,問題多到我無法像維護先前專案那樣換目錄執行套件安裝就好了,因此必須徹底解決這個問題。

其實問題很明顯,Windows sync 到 VM 後一定被外部的 Windows 影響到了目錄或檔案的權限,所以解法就朝變更 sync 方式發想,Vagrant 官方有提到幾種 sync 方式。

NFS

其中有一段文。

Windows users: NFS folders do not work on Windows hosts. Vagrant will ignore your request for NFS synced folders on Windows.

所以我就連試都沒試了。

RSync

Rsync 只能單方推送,我在 Windows 改變的檔案可以進去 VM,但在 VM 裡面執行產生的檔案不會同步回來,所以也不行。

SMB

Samba 有成功,之前發生的問題沒有了,但他非常慢,非常慢或許可以忍,但使用 SAMBA 後跑 unittest 會跑到 server 掛掉,這可就不能接受了。

上述方法使用無效以後,我還試了 WSL 以及 Multipass,WSL 我裝了 Ubuntu 20,但他 mount 的結果跟 Homestead 狀況一樣,multipass 也一樣,multipass 另外一個 issue 是如果使用 virtualbox 的話在 Windows 環境無法發派 IP,那你根本不能用 domain name 或 IP 進行測試,除非改用 hyper-v。

正當我試了一切想要放棄,打算使用 remote ssh 工作的時候,突然翻到 Homestead 有這麼一段說明:

To enable NFS, you only need to add a simple flag to your synced folder configuration:

When using NFS on Windows, you should consider installing the vagrant-winnfsd plug-in. This plug-in will maintain the correct user / group permissions for files and directories within the Homestead box.

What?

於是我安裝了 vagrant-winnfsd,然後 homestead 裡面配置了:

folders:
    - map: ~/code/project1
      to: /home/vagrant/project1
      type: "nfs"

所有問題都解決了,一切正常,而且速度很快,Vagrant 官方那段是在莊孝維嗎,為了解決這個問題我花了快一週,之後其他 Vagrant 配置也都會指定 sync 類型。

Vagrant.configure("2") do |config|
  config.vm.synced_folder ".", "/vagrant", type: "nfs"
end

很多東西解法其實很簡單,但有可能是前人嘗試了很久的結果,因為我順利解決了,所以留下這篇文章希望可以幫助到跟我遇到一樣問題的朋友。

2020/10/08

MySQL Common Command

檢查資料庫大小

SELECT table_name, table_rows, ((index_length+data_length)/1024) AS size FROM information_schema.tables WHERE table_schema = 'database_name';

匯入表單

mysql db_name < xxx.sql -u root -p --default-character-set=utf8

匯出表單

mysqldump --default-character-set=utf8 -u root -p db_name > xxx.sql
mysqldump --default-character-set=utf8 -u root -p db_name --skip-extended-insert > xxx.sql
-- 上方的語法可以將 insert 的內容逐行分離

建立資料庫

CREATE DATABASE db_name DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;

建立資料表

CREATE TABLE table_name (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(100) CHRACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT 'default' COMMENT 'your comment',
`fk` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'foreign key',
`created_at` TIMESTAMP NULL DEFAULT NULL,
`updated_at` TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
INDEX(`fk`)
) ENGINE=MYISAM CHARACTER SET utf8 COLLATE utf8_unicode_ci COMMENT 'your comment';

修改資料表名稱

RENAME TABLE old-name TO new-name

使用者

SELECT user, host FROM mysql.user; -- 查詢使用者
SHOW GRANTS; -- 檢視目前使用者權限
SHOW GRANTS FOR 'user'@'%'; -- 檢視 user@% 權限
CREATE USER 'user'@'%' IDENTIFIED BY 'password'; -- 新增使用者
ALTER USER 'user'@'example.org' IDENTIFIED BY 'new_password'; -- 修改密碼
GRANT ALL ON database_name.* TO 'user'@'%'; -- 賦予權限,使用 *.* 表示套用全部資料庫
GRANT ALL ON database_name.* TO 'user'@'%' WITH GRANT OPTION; --讓自身擁有的權限賦予該會員
REVOKE ALL ON database_name.* FROM 'user'@'%'; -- 移除權限
DROP USER 'user'@'%'; -- 移除使用者
GRANT USAGE ON *.* TO 'user'@'%' IDENTIFIED BY 'password'; -- 修改密碼
FLUSH PRIVILEGES; -- 更新權限表

設定密碼

mysqladmin -u root password 'new_password'

複製表格

CREATE TABLE new_table LIKE old_table; -- 複製一模一樣結構的資料庫
INSERT new_table SELECT * FROM old_table; -- 複製一模一樣結構資料庫的資料

2020/08/19

初探 ansible

ansible 是一個基於 python 的工具,在 CI/CD 的世界挺受歡迎,可以做的事情很多,網路上很多 ansible 教學了,我這邊筆記一下一些比較常用的東西

deploy.yml
- hosts: localhost
  vars:
    NAME: chan

  tasks:
  - name: echo name
    command: "echo {{ NAME }}"
  
  - name: echo age from outside
    command: "echo {{ AGE }}"
    
  - name: echo name from env
    command: "echo {{ lookup('env', 'LBJ') }}"

這是一個最基礎的 ansible playbook 架構,只要把命令寫好,ansible 就會照 task name 一個一個執行,上面我的範例第一個是 echo 本地設定的 NAME,第二個 AGE 會從外部導入,第三個 LBJ 是抓取環境變數,因此要正確執行的話要這樣下

$ export LBJ=GOAT
$ ansible-playbook deploy.yml -e "AGE=40" -v

執行後可以依序看到 NAMEAGELBJ 的變數結果相繼印出,基本上架構瞭解,做的事情只是從 tasks 去變化,搭配 ansible 本身強大的 modules 可以幾乎沒有事情辦不到,也可以使用 role 來做群組管理,但如果想要簡單部署,接下來示範如何把上面的工作打散

/a.yml
- hosts: localhost
  vars:
    TARGET: a
  vars_files:
    - ./vars/var.yml

  tasks:
    - include_tasks: ./tasks/deploy.yml

    - name: echo self stuff
      command: "echo this is {{ TARGET }}"
/vars/var.yml
NAME: chan
/tasks/deploy.yml
- name: echo name
  command: "echo {{ NAME }}"

- name: echo age from outside
  command: "echo {{ AGE }}"

這樣的設定,如果要生另一個類似的流程只要複製 a.yml 改一下內容即可。

2020/01/15

jq

JSON 格式的應用現在已經隨處可見了,目前使用的程式語言都有相關支援的套件,如果要在 Linux 底下操作的話有一個非常好用的工具叫 jq,下面來展示應用範例

應用網址:https://jsonplaceholder.typicode.com/users

curl -s https://jsonplaceholder.typicode.com/users | jq .

我們會得到格式漂亮的結果

[
  {
    "id": 1,
    "name": "Leanne Graham",
    "username": "Bret",
    "email": "Sincere@april.biz",
    "address": {
      "street": "Kulas Light",
      "suite": "Apt. 556",
      "city": "Gwenborough",
      "zipcode": "92998-3874",
      "geo": {
        "lat": "-37.3159",
        "lng": "81.1496"
      }
    },
    "phone": "1-770-736-8031 x56442",
    "website": "hildegard.org",
    "company": {
      "name": "Romaguera-Crona",
      "catchPhrase": "Multi-layered client-server neural-net",
      "bs": "harness real-time e-markets"
    }
  }
]

而 jq 可以做 node 的搜寻,以上面那个例子

curl -s https://jsonplaceholder.typicode.com/users | jq .[0].name # "Leanne Graham"
curl -s https://jsonplaceholder.typicode.com/users | jq .[0].address.street # "Kulas Light"

使用 jq 的一些參數也可以達成 json encode 的功能:

test
#!/bin/bash

NAME=$1
AGE=$2

JSON_STRING=$(jq -n \
    --arg name "$NAME" \
    --arg age "$AGE" \
    '{name: $name, age: $age}')

echo $JSON_STRING
./test chan 40 # { "name": "chan", "age": "40" }

jq 没有驗證 json format 的功能,但我們可以利用一些 shell script 的特性辦到這件事

#!/bin/bash

function json_validator() {
    echo $1 | jq . &> /dev/null

    if [[ $? == 0 ]]; then
        echo "$1 is valid format"
    else
        echo "$1 is invalid format"
    fi
}

JSON='{"name": "chan"}'
json_validator "$JSON"
# {"name": "chan"} is valid format

JSON='{"name":}'
json_validator "$JSON"
# {"name":} is invalid format

jq 也可以使用自定義模組,在 ~/.jq 裡面可以將一些複雜但常用的內容先寫好

def blurry($f):
  ($f | ascii_upcase) as $ucf
  | to_entries[]
  | select((.key|ascii_upcase) | startswith($ucf))
  | .value;


def very_blurry($f):
  ($f | ascii_upcase) as $ucf
  | to_entries[]
  | select(.key | ascii_upcase | index($ucf))
  | .value;

這樣的話像搜尋 docker 的 config 的話就非常好用,像是 docker inspect test | jq '.. | blurry("config")?' | objects

搜尋語法
$ jq 'map(select(.id=="1234"))'
$ jq 'map(select(.id|index("1234")))'
$ jq 'map(select(.id|contains("1234")))'
$ jq 'map(select(.id|test("1234";"i")))'
$ jq 'map(select(.id|match("1234";"i")))'