標籤

Docker

【Flagr】處理部署遇到 fcntl64 not found 的過程

前言

睽違三個月左右再度重新部署 Flagr,沒想到在這次部署超級不順利,搞不清楚到底是環境變數沒弄好,還是是 Dockerfile 有問題,遇到 fcntl64 not found 的問題,直到這幾天跟同學 pair programming 進 Bash 時才抓漏成功,以下就跟大家分享一下這次的過程。

繼續閱讀

【tetcontainer】使用 Python 在 Docker 中做資料庫的測試案例 | 來賓: PostgreSQL, Docker, Python, GitHub Actions

前言

這一陣子許多同事除了在內部分享會中分享 Testcontainer 的技術,也有到 JCConf 2021 上分享 - Integration testing with Testcontainers,過往我在寫單元測試(Unit)時,時常都把資料庫的函式都直接擋住(Mock),假裝他是成功的情況下往下走,但在一個 API 中資料庫往往是最容易在緊繃時掛掉,亦或是工程是手癢去改了某個欄位,讓整個服務瞬間炸掉,這些問題都是我們無法控制的部分...因此實際讓資料庫跑在測試時可以有個真的環境可以使用是很重要的一環,雖然看專案規模,測試時間有多有少有長有短,但放著一個 Container/VM 在那邊沒用就是很浪費啊,因此就有本次要介紹的 Test Container。

把 Test Container 分開寫比較懂他是幹嘛的,但在找資料時請以 testcontainer 去找才找得到喔!

Test Container 是一個 Java 的函式庫,支援 JUnit 來做測試,在跑測試時可以幫忙起個容器(Container),並可以放上各式資料庫、Selenium 瀏覽器...等等可以放在 Docker 上面跑的內容,那 Test Container 很好的地方就是他也提供 Python 的解決方案(testcontainers/testcontainers-python),讓我這個 Python 開發者可以有機會在 Docker 裡面很快地起一個 Container 來跑資料庫相關的整合測試,接下來就讓我娓娓道來我踩坑的過程 🖌️

有支援各種程式語言的函示庫喔,大家可以去挖挖看

繼續閱讀

將 Chatbot 丟入一台筆電中的 Kubernetes 叢集海 | k3d | Docker

前言

Kubernetes 幫忙處理掉許多以前很繁雜的問題(Auto-Scaling、容器管理..),讓開發者只要手持 Container 與大量 yaml 檔即可將工具部署上去(前提是容器要正常工作),但作為僅有一台筆電的開發者(我)想試玩總不能直接至雲端開叢集(金幣攻擊),因此找到了一個解決方案,使用 k3d 來幫助我們建立 Kubernetes 試玩,以下就一步步帶大家從容器建立到將服務部署於叢集上。

範例專案:louis70109/kubernetes-line-echo-bot

繼續閱讀

2020 一、二月的學習紀錄

learn records

前言

礙於最近做事有點手忙腳亂,沒有很有效的管理時間,記錄下來讓往後能有個經驗可循並增加自我管理能力。

實作項目

Docker & Docker-Compose

我記得上次自己弄 docker container 已經是一年多前,當時還結合 Drone CI 來跑(好久了 👀),對於 Dockerfile 使用方法依稀有點印象,而最近因為看了許多 open source 後對於 Dockerfile 的內容了解度也提升了許多(實在是個不錯的方法 👍),會這樣子弄的原因是我認為 Serverless 的架構很容易被 AWS 綁架,我認為 API 這類可拆出來的功能應該要包成 container 增加彈性不讓平台限制,被這個想法 trigger 後就來好好練習 Docker 了 🏋️‍♂️。

這次使用 Twitch-Bot 做我的練習對象,裡面主要用了 node 以及 mongo 兩個服務,在此同時如果各別起 docker 挺麻煩,因此就需要使用 docker-compose 幫忙啟動,而在這過程中學到了:

  • 把 Dockerfile 遷移到 docker-compose 上 (如何複製別人的檔案(大誤))。
  • 藉由 docker-compose 裡面的 network 連接兩個容器的使用方法。
  • Google container-registry 上傳以及 gcloud 過期的 docker 使用方法(參考),同時也修正後可以使用 docker 的原生指令將 container 送上 Google。

接下來就是趁六月 credit 過期前趕快來玩玩 Google Kubernetes 🚀

AWS IoT Job

最近在公司實作 AWS IoT Job 部分的功能(以下稱為 Job),因為 Job 每次執行收費約 1 塊台幣,之所以會用它是因為在 IoT 執行時不是只會單純發送訊號出來讓後台收訊號做事,而是需要跟後台經過一連串的溝通來達成功能(例如 韌體更新),當然還有很多更複雜的功能,這邊只列舉一個小部分。

從這段時間的實作上學到的部分:

裝置工作列表

當後台的 Queue 同時塞進很多工作時要如何管理並通知裝置此時的工作有哪些(All Job)以及要做哪件事(Next Job),實作這功能時不能只考慮到一個裝置,而是考慮到 N 個裝置時要如何過濾並管理狀態機,限制裝置要依照狀態執行避免系統錯亂。

平台化

之前主要功能都是介接 AWS IoT,而這次是要實作一個類似的功能提供給其他使用者,不能只開一個 API 就想要功能都包好,而是將功能明確劃分,讓使用者可以有彈性的去組合,只是在此時我沒有處理得很好,之後的 Task 需要更注意。

LINE SDK - Narrowcast Client API

參考 Pull Request: Add narrowcast client api #237

工廠模式

功能主要是讓開發者可以透過 API 來做分眾的推播,在實作這個 issue 時讓我原本模糊的工廠模式清晰了許多,主要是 SDK 使用了 Python Class 來擔任 Model 的角色,讓進來資料可以經過 model 去轉換成對應的 key-value,所有的資料都分類進去對應的工廠處理完再回傳出來。

在還沒開始看 code 前只想著要寫什麼邏輯去處理,其實使用 Model 的方法就處理掉大部分資料格式的問題,很多 LINE 文件已經清楚定義的格式只要照著填就解決了,只是在這個 Task 遇到了Python 保留字的問題,而經過各種 google 後只好自己寫邏輯去判斷掉這件事,之後只能繼續看有沒有更好的寫法可以取代掉這個保留字的問題。

Lint

官方 Github 有寫要 Contribute 時需要執行的內容(參考),lint 則是遵照flake8,而執行tox後會對每個版本的 python 去做測試,但像我電腦只有 3.7 版 tox 就只會針對這個版本做測試。

  • 在這件事上學到的 tab空白鍵(space) 的差異,PEP-08 上也告訴建議使用空白鍵,而 python 3 之後也不允許兩個混用,畢盡 python 是很注重縮排,既然官網都寫了哪有不遵守的道理呢?😃

Lint 也不會無緣無故來刁難開發者 XD

  • 內部函式(Class、Function)都需要再第一行下註解,而會這樣用的因素可能在 python 上並沒有 publicprivate 的觀念,透過這樣的方法來表示它(Class、Function)是一個內部函式,藉由 Lint 讓開發者可以知道這個功能是內部還外部,只是在 python 只能使用這個 lint 讓大家遵守這規則,如果沒有 CI 要硬上的話其實也管不住,畢竟不像 golang 這類語言會編譯(汗顏)。

總之使用 lint 的好處就是開發風格可以統一,能夠盡量避免不必要的 programing 麻煩,在寫任何語言都推薦使用各個語言的 lint,雖然一開始會很討厭它,但它真的是在幫助你 😆。

Netflix

這時間與家人一起訂閱了一年份的會員,而我的初衷就是想把英文學好,而我也花了時間好好的看完一部全英文影集(發英與字幕),第一次嘗試這樣看全英文,並且邊看邊 Google 翻譯不懂的單字同時口述跟著念一遍增加記憶力,隨著工作量減輕後下班也可以再安排時間繼續看下個影集學了~

然後迷上了愛的迫降這個韓劇,推薦喜歡看愛情片的朋友去看 ❤️

武漢肺炎

最近剛好因為這傳染病盛行,除了防疫之餘,g0v 也提供 API 讓開發者可以拿去介接,隨著大家各種開發前端 web 以及 chatbot ...的應用後本來在想有個什麼想法可以參與這個全民黑客松,只是我認為用途實在重複性太高,而在大家開發應用時我又剛好在寫 LINE SDK,錯失了第一時間發佈口罩相關的服務建立時間,本來想到 LIFF v2 + LINE Notify,但只是在使用上很容易吵到用戶進而封鎖它(LINE Notify),因此要考慮好功能再來看會不會有比較好的使用情境。

出入公共場所記得戴口罩,有帶隨身瓶酒精的記得消毒!😷

結論

有時候在思考與規劃的過程中如果經驗不夠時真的很難馬上到位,不過任何事情都一樣,若這件事可以輕鬆且又得心應手,代表它可能已經是你熟悉的領域或是過於簡單,就像我一開始處理社群一樣,若是沒有前輩們帶著走的話我跟本無法有效地處理事情,總之凡是起頭難,即早加入即早熟悉各個領域才是王道 😆

參考

AWS IoT 觸發後可以執行的功能 Job Events Tab 與 space 的差異(PEP-08)

繼續閱讀

Docker 學習筆記 - 將 Twitch Bot 容器化

前言

最近剛好看到許多EKSGKE相關的文章,趁著過年時刻先來補足一下 Docker 這個既熟悉又陌生的技能 😆,之後再接著研究如何串接至 kubernetes 並同時到雲平台上,接下來一起來看我從建立到建置的過程紀錄 🙂。

以下就使用我的 side project - Twitch-Bot 做範例囉!

主要使用的功能為 node 以及 mongo

新增檔案

這邊我使用 vscode 的 Docker extension 來幫助我快速建立 docker 相關的檔案:

  • Dockerfile
  • docer-compose.yml
  • .dockerignore

透過以下的 gif 可以快速建立以上三個檔案

操作方式為 Cmd+Shift+P >docker: add > 選擇語言(Node) > 設定輸出 Port

處理 dockerfile

藉由 extension 來幫我們產生檔案第一步就完成了,接著對 Dockerfile 稍做修改:

FROM node:10.13-alpine
MAINTAINER NiJia <louis70109@gmail.com>
ENV NODE_ENV production
WORKDIR /app
COPY ["package.json", "package-lock.json*", "/app/"]
RUN npm install
COPY . /app/
EXPOSE 5000
CMD ["npm", "start"]
  • FROM: 來自什麼映像檔,這裡使用預設給的 node 版。
  • MAINTAINER: 寫描述的位置,這邊我標註我的名稱與 EMail。
  • ENV: 環境變數寫在這,不過這個專案是放在 Github 上,所以我就沒把 chatbot 平台的密鑰放在這了。
  • WORKDIR: 當前在一個乾淨的環境下,而你預想的工作路目錄要叫什麼就在這設定,同時也會一起幫你建立好 (我用/app這個工作資料夾當作範例)。
  • COPY: 把檔案複製到想要放的地方,這裡為了先讓容器安裝完相依套件,因此先把 package.json 以及 package-lock.json 先複製進 /app/ 這個資料夾內。
  • RUN: 執行終端機指令,在上面檔案複製過來之後,這裡我就來安裝相依套件庫。
  • COPY: 安裝完產生 node_modules 之後把原本的有的東西都複製過來。
    • . = 當前目錄
    • /app/ = 欲複製前往的地方
  • EXPOSE: 容器要打出去的 Port 出口,在前面呼叫 extension 時就已經輸入完這欄了。
  • CMD: 幫我執行指令 (參考: CMD 與 ENTRYPOINT 的差別)

docker-compose.yml

這邊我將預設的修改為:

version: '3'

services:
  twitch-bot:
    image: twitch-bot
    restart: always
    build: .
    environment:
      NODE_ENV: production
    ports:
      - 5000:5000
    depends_on:
      - mongo
    networks:
      - chatbot-network
  mongo:
    image: mongo
    restart: always
    volumes:
      - ./data/db:/data/db
    networks:
      - chatbot-network

networks:
  chatbot-network:
    driver: bridge

首先將version改成 3,有向下相容的話當然就是要使用新的囉!

接著會建立兩個 container (services):

  1. twitch-bot build 後面接著 . 是指說建立在當前位置,depends_on 則是依賴哪個 container,最後則透過 networks (chatbot-network) 來讓服務互相溝通。
  2. mongo 這邊則就直接去 dockerhub 裡面抓,restart鐵定是必要設定,不然會沒有資料庫 🤣,volumes則是設定說你想映射的檔案位置在哪,這邊我設定當前目錄的/data/db (./data/db)裡面,對應到映像檔裡面的 /data/db 的位置,然後一樣透過 networks (chatbot-network) 來讓服務溝通。

networks 這邊就有點像主機設定網卡一樣,我設定一個 chatbot-network 的網卡它是使用橋接(bridge)模式來驅動(driver)

這部分是參考知乎,對照改出來的

補給站: 一般看到 5000:5000 或是 ./data/db:/data/db 的寫法,它意思是 本地端位置 對應「:」到 容器的位置,像上述檔案就有 port 以及 資料庫位置,這邊就會因應服務而對應到不同的功能。

修改 .dockerignore

這邊因為我很偷懶不想把.env裡的環境變數寫進dockerfile😆,因此在這就把檔案中的**/.env拔掉方便做事 🤣

測試容器

啟動

docker-compose up -d
  • -d 表示讓容器跑在背景,如果沒加的話就會在終端機上看到容器們的行為。
  • 會建立本地端的 container image。

關閉

docker-compose down
  • 若是使用 Twitch-bot 來試玩的話,則需要多開一個視窗執行 npx ngrok http 5000 來建立一個暫時含有 SSL 的 URL。

建置(build)

如果是按照原本 docker-compose.yml 的打法:

services:
  twitch-bot:
    image: twitch-bot

這樣的話 docker 預設會幫忙下一個 latest 版號的 tag。

如果是按造以下做法的話在 build 就會幫忙建立 帳號/容器名,並下一個 0.1 的 tag

services:
  twitch-bot:
    image: louis70109/twitch-bot:0.1

接下來就執行 docker-compose build 幫忙建立一個有版本號(tag)的容器映像檔(container image)。

補給站:

  • 記得要 docker login 哦!
  • 到 dockerhub 或其他私有倉庫建立 container repository

結碖

趁著春節的零碎時間來跟這個熟悉陌生技能打個招呼 😆,同時也體會到大家說到 docker 好用的地方以及給予的彈性,之前都是有需要測試某些功能才會用到,對於 dockerfile 以及 docker-compose.yml 就甚少了解,藉著年假空檔練習,之後只要在熟悉一下整體的使用方法應該就能好好的~用它來幫忙做事了 🚀。

references

連線 mongo container docker CMD 使用 Overview of Docker Compose Twitch-Bot

繼續閱讀

[Docker] Mysql & PHPMyadmin 映射 & 連接方法

詳細文件參考

docker 抓 mysql 最新的版本

docker pull mysql:tag

若只是要建立普通容器用以下指令:

docker run -d -p 3306:3306 -e MYSQL_USER="myname" -e MYSQL_PASSWORD="mypasswd" -e MYSQL_ROOT_PASSWORD="root_pwd" --name mysqltest1 mysql:5.7 --character-set-server=utf8 --collation-server=utf8_general_ci

由於會有備份的問題,所以要先建立資料夾們

mkdir ~/docker
mkdir ~/docker/mysql
mkdir ~/docker/mysql/conf
mkdir ~/docker/mysql/data

新增 my.cnf 配置文件

vim ~/docker/mysql/conf/my.cnf

my.cnf 加入如下内容:

[mysqld]
  user=mysql
  character-set-server=utf8
  default_authentication_plugin=mysql_native_password
[client]
  default-character-set=utf8
[mysql]
  default-character-set=utf8

將 /docker 這個資料夾映射到容器內的 /etcmysql/my.cnf

docker run -d -p 3306:3306 --privileged=true -v ~/docker/mysql/conf/my.cnf:/etc/mysql/my.cnf -v ~/docker/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysqltest2 mysql:5.7
  • --privileged=true:容器内的 root 永有真正 root 权限,否則容器内 root 只是外部普通用戶權限
  • -v ~/docker/mysql/conf/my.cnf:/etc/my.cnf:映射 config 資料夾
  • -v ~/docker/mysql/data:/var/lib/mysql:映射 data 資料夾 (table 都在這)

如此一來就可以儲存 /docker 這個資料夾達到備份的功能

PHPMyadmin

將 myadmin 連接 mysql 的容器指令:

docker run --name myadmin -d --link mysql_db_server:db -p 9100:80 phpmyadmin/phpmyadmin

mysql_db_server = mysql container id

在瀏覽器上輸入 localhost:9100 就可以看到 phpmyadmin 囉!

Docker 查詢容器 IP

docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_name_or_id
繼續閱讀