2024-05-29

[Certbot] ImportError: cannot import name 'appengine' from 'urllib3.contrib' ...

*Certbot 是一個由 Let's Encrypt 的組織維護的一個用來申請加密憑證的工具

之前公司網站的 https 憑證是透過 Certbot 的來輔助申請使用的,公司網站的系統是 Ubuntu 18.04 LTS ,在安裝好 Certbot 後,它會在 /etc/cron.d 中增加一個 certbot 的排程,定期是每天的「0 */12 * * *」會執行 renew 檢測操作

憑證一般申請後的有效期是三個月,但一般應該是可以提前幾天就讓你 renew 展延

而最近我會發現異常是因為在五月初收到來自 Let's Encrypt Expir 寄過來告知還有 xx 天就要過期了,要記得去 renew ,當時我就覺得怪怪的,因為公司這個憑證已經運行有幾年了,我還是第一次收到通知信,不過當時我還有別的事在忙,想說因為有排程會去自動 renew 也就沒有多想

直到前幾天我又收到同一封告知即將要過期的信,我才認真的去檢查

一開始先查看是不是 /etc/cron.d/certbot 是不是被刪或裡面的排程設定被動過了,但檢查後覺得是正常的,再來就是去檢查排程執行時所記錄的 syslog ,在查看「grep -i "certbot" /var/log/syslog」後發現,certbot 的排程執行時有異常,大至的訊息如下

systemd[1]: Starting Certbot
certbot[...]: Traceback (most recent call last):
certbot[...]:  File "/usr/lib/python3/dist-packages/requests_toolbelt/_compat.py"....
...
...
...
certbot[...]: ImportError: cannot import name 'appengine' from 'urllib3.contrib' ...
systemd[1]: certbot.service: Main process exited, code=exited, status=1/FAILURE
systemd[1]: certbot.service: Failed with result 'exit-code'.
systemd[1]: Failed to start Certbot

在 google 之後,大部份的建議都是將 python library 中的 urllib3 給移除就可以了,然後執行「sudo pip uninstall urllib3」,再輸入 y 確定要移除
*用 sudo 是因為 certbot 是以 root 身份執行的,所以 urllib3 的套件是安裝在 root 的 python library 之下

然後再手動讓 certbot 跑 renew 就沒有出現上述的異常訊息,而且憑證也更新了
*手動 renew 指定「sudo certbot -q renew」

2024-05-25

[MQTT] 1 - 試著來架設 MQTT - RabbitMQ

*先說個前言,其實在下個人覺得,直接用 docker 來創建可以方便許多

前言2: 啥是 MQTT?是 Message Queuing Telemetry Transport 的縮寫,叫做「訊息隊列遙測傳輸」的意思,但這是啥東東,其實詳細的說明在下也不是很會講,但在下粗略的理解,就是訊息即時相關傳送、接收的意思,透過在指定的 Topic(主題) 進行發布(Publish)訊息,而有關聯的終端可以訂閱(Subscribe)想要接收訊息的 Topic 來取得發布的訊息,而 MQTT 就是為了這個操作而設計出來的協定。

前言3: MQTT 除了可以透過 MQTT 的協定來傳送資料,它另一種傳送的方式是 WebSockets,所以對於網頁前端來說,技術上也是比較友善,上手門檻不會太高;也因為是可以 over WebSockets 的關係,所以 MQTT 的技術是可以開發成即時通訊的架構,而且還有 keep alive 的特性

前言4: Topic 是以 UTF-8 編碼為主的字串,所以...Topic name 是可以使用中文的,大小寫是敏感的,可以被用在 Topic name 的符號中,雖空白是可以用但不建議,「/」是可以用的,但它似乎是有一些定義的用法

前言5: Topic 的訂閱是可以使用 topic filter 的方式來達成一次訂閱多個 Topic 的操作,filter 有點類似 regexp 的方式,但不完全一樣,詳細還是要網路上找一下

目前以網路上能找到比較主流且相關資料比較多的 MQTT Service 平台大至上有三個
  • Kafak
  • RocketMQ
  • RabbitMQ
在下主要是先拿 RabbitMQ 來用,至於為什麼先用它,主要有幾個思維
  • 在下在用的環境主要都是 client-server 的架構,所以選 RabbitMQ
  • 在下並沒有需要高吞吐量的,所以選 RabbitMQ
  • 以前在寫 JAVA 時有吃過 JAVA 吃爆記憶體的虧,所以不會太想選 RocketMQ(註: 這只是在下個人偏見,我知道現在 JAVA 越來越優化這部份,但就是我個人偏見)
  • 之後應該也會來玩 Kafak,所以現在先玩 RabbitMQ

接下來來講講怎麼架設 RabbitMQ(以在 Ubuntu 為例)

2024-04-28

[Python] 使用 CnOcr 進行辨識時出現在 Windows/Linux 和 MacOSX 的結果不一樣的情況

最近公司的案子有要使用 OCR 辨識,然後技術方面是要用 python 去處理,公司的 RD 就利用 CnOcr 開發了一個程式…

然後最近這個案子的相關成員就跟老闆匯報進度跟問題,在會後老闆就在跟 RD 討論問題的部份,然後老闆就讓 RD 來找在下一起討論,看看我有沒有想法。

這邊遇到的問題是這樣的

因為 RD 在轉交辨識程式給案子其他的開發者時,有一位後端反應該程式運行時有狀況,無法正常辨識…先說明一下,該程式是要辨識表格中的數據,然後回傳某幾欄跟列的值,而遇到問題的後端是運行程式後,最後出現錯誤是『Indexerror: list index out of range』

我說: 這不就很明顯,就是辨識完後的結果並不存在指定的 index 位置
RD說: 是,但這不太可能,同一個程式用同一個模型去辨識同一個檔案,我在自己的環境跑是正常的
我說: 那有確定後端那邊的環境,python 安裝的套件的版本是一樣的嗎?
RD說: 是沒確認過,等等我問問
我說: 那你先把程式跟要辨識的檔案給我一份,我在我的環境用用看
....
我說: 我這邊跑是正常耶
RD說: 剛也跟後端確認過了,套件的版本是一樣的
我說: 後端那邊的系統是?
RD說: Mac電腦
我說: 呃,會是 MacOSX 有什麼特別的?比如 cpu 特別?或支援的指令集不同?
RD說: 這就不太確定了
老闆說: 公司這邊還有一台 Macbook Pro 2019 的,要不試試?
....
我說: 欸,奇了,在這台 Mac 跑也是有問題,而且問題的反饋還跟後端的不完全一樣…後端那邊反饋是應該要返回四個值,但結果是一個都沒有,可是公司這台的結果反而是有辨識到三個
....

2024-03-24

[Windows] docker desktop 4.26.0 開始會遇到 container 在啟動後維持了一定時間(大概30分鐘)時,外部host就無法對該容器進行操作

先說明,這有可能只是在下自己遇到的情況…

就是,某天在下 Windows 11 當時使用的 docker desktop 是在 4.25.0 然後更新到 4.26.0 時發生了一些奇怪的問題…

先說明在未更新前的環境

os: win11

cpu: amd ryzen 2700x

ram: 2 * 16G

app: docker desktop 4.25.0

containers: ubuntu 20.04 lts(內裝了 apache, php, mysql, phpmyadmin)

因為我大部份進行開發都是在公司上班時用工作機(筆電),當時工作機的 docker desktop 是更新到 4.25.2,家裡的桌機主要是為了在家工作時可以拿來開發,所以平時 docker desktop 我是不太會去更新

然後就有天看到有提醒有新版本 4.26.0 可以更新,我也沒想太多,就進行動作,然後更新完就把 docker desktop 關掉了,也沒去留意。

直到有天是公司 pm 告知客戶有反應前次更新有一些狀況,問我能不能先在家更新,更新完再來上班,我想說也行,就在30分鐘內完成了修正然後 hotfix 到客戶端去,正準備結束時就不知道為啥就按到了系統頁面的重新整理,結果發現一直在 loading…

2024-03-23

docker-compose 在 windows 環境該如何在 volumns 中設定掛載外部路徑

在 docker run 建立 container 的指令中,可以用 "-v {host-path}:{container-host-path}" 的方式來掛載主機路徑(host-path)至容器路徑(container-host-path)。

而主機路徑可以直接用絕對路徑的寫法,像 "-v D:\abc:/var/www/html"...

但,這方式在 docker-compose.yml 的 volumns 中這樣寫雖然不會報錯,但容器路徑 /var/www/html 卻會是空的,我假設 docker-compose.yml 中是這樣寫的(容器路徑我是假設的)
volumns:
  - "D:\abc:/var/www/html"
  - "./def:/var/www/html2"

"./def" 是以 docker-compose.yml 這個檔案的路徑開始中的 def 資料匣

我假定在 D:\abc 和 def 中都放了一個 index.html,在 container 啟動後,實際到 /var/www/html 路徑下查看,會發現是空的…而到 /var/www/html2 中查看則會有看到 index.html

在下試過很多寫法,但好像都無法掛載不是跟 docker-compose.yml 同路徑的其他路徑…但後來在 google 搜尋之後,發現了狀況,要掛載非 docker-compose.yml 同路徑的其他路徑,除了要寫絕對路徑的寫法外,寫法要改成

//{Disk drive}/path

例如: D:\abc 的掛載就要寫成

- "//d/abc:/var/www/html"

如此就能正常掛載到想要的外部路徑

註: 我自己後來把 docker desktop 在「用/不用 WSL」切換來切換去,有發現似乎「//d/abc」的這個方式是在「用 WSL」的情境下才有支援,「不用 WSL」的情境下還是要使用「D:\abc」的寫法,供大家參考