TechBridge 技術共筆部落格

var topics = ['Web前後端', '行動網路', '機器人/物聯網', '數據分析', '產品設計', 'etc.']

如何使用 K8S 自動化定期 CronJob 抓網路公開資料


https://static.coderbridge.com/img/TechBridgeWeekly/4d6ba07d383b4d5a937a2abfd2cd9542

前言

有使用 Linux 的讀者就知道,若是有定期需要執行的程式就可以 Crontab 把寫好的 script 透過定期的 scheduler 定期執行節省人力。一般常見的使用範疇就是定期更新檔案資料或是網路爬蟲等。今天我們則是要介紹,如何使用 Kubernetes(k8s) 的 CronJob 來自動化抓取網路公開資料(這邊我們使用政府公開資料的雨量資料 JSON 檔案),我們想要的定期執行程式的效果。好的,那就讓我們開始吧!

環境設定

若是對於 Kubernetes(k8s)比較不熟悉的讀者可以想成是 Kubernetes(k8s)是一個大型的 container 調度和管理工具,透過 config 設定可以管理你的 dockerize 後的 application。

在這篇文章中我們會使用 minikube 這個 local 開發測試用的 Kubenetes(k8s)cluster 當作測試 demo 使用。若你的電腦還沒有安裝 Kubernetes(k8s)的相關環境的話,可以先參考官方網站的教學我們之前的教學文章

這邊我們使用 macOS 當作範例,需要安裝的有 virtual box、kubernetes-cli 和 minikube 並登入好你的 docker hub 帳戶

確認一下若是你的 minikube 已經 start 成功,可以使用下列指令確認是否正常啟動:

1
$ kubectl cluster-info

另外也可以安裝 kubectx 這個好用小工具,方便你切換到不同 cluster,這邊我們要切換到 minikube。

撰寫 CronJob 程式和 Dockerfile

因為範例為求簡單,這邊我們使用 Python 撰寫一個簡單每分鐘定期抓取政府公開資料的 python 程式,主要功能為:

  1. 抓取網路公開資料
  2. 根據時間儲存成 {datatime}.json 檔案到 /data 資料夾下

範例程式 app.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import json
from datetime import datetime
import glob

import requests


def main():
url = 'https://opendata.cwb.gov.tw/fileapi/v1/opendataapi/O-A0002-001?Authorization=rdec-key-123-45678-011121314&format=JSON'
resp = requests.get(url)
data = resp.json()

with open('/data/{}.json'.format(datetime.utcnow()), 'w') as f:
json.dump(data, f)

if __name__ == '__main__':
main()

參考 Dockerfile

1
2
3
4
5
FROM python:3.7-alpine
ADD . /code
WORKDIR /code
RUN pip install -r requirements.txt
CMD ["python", "app.py"]

若是完成後可以透過將我們的程式打包成 docker image 然後上傳到 docker hub 上,讓之後的 k8s cronjob 可以抓下來(當然若是私人專案或是公司專案可以考慮使用 google cloud registry 來 host 你的 image)。

打包 image 檔案(xxxx 為你的 docker hub id,k8s-cronjob-pvc-example 為 image 名稱,v1 為 tag 名稱):

1
docker build -t xxxx/k8s-cronjob-pvc-example:v1

若是完成後可以使用 $ docker image list 觀看是否有正常顯示

接著就要推送到 docker hub 上面:

1
$ docker push xxxx/k8s-cronjob-pvc-example:v1

成功後應該就可以在你自己的 docker hub 上面看到上傳的 image 檔案!

撰寫 k8s CronJob config 檔案

上傳 image 到 docker hub 後,我們要開始將我們的程式 deploy 到 minikube 這個 local k8s cluster 上面!

首先我們先定義 schedule 格式為:*/1 * * * * (每分鐘執行一次)

cron 主要格式 * * * * * 就是由左到右分別為:

  • 分鐘
  • 小時
  • 每月中第幾天
  • 星期幾

若是你對於 cronjob 格式比較不熟悉,可以參考這個網站,他可以透過輸入你的設定值告訴目前格式的效果,十分方便!

以下是參考的 cronjob.yaml 檔案:

  1. 我們設定 apiVersion 版本和 k8s config 類型 kind 為 CronJob
  2. 從 kdchang/k8s-cronjob-pvc-example:v1 抓下來我們的程式
  3. 透過 /bin/sh 指令列印出 ls /data 寫入檔案列表
  4. 值得注意的是由於 k8s 資源利用的設計,每次 pod 重啟不一定會是在同一個 node 上部屬,另外隨著 pod 的重啟在 local 的檔案生命週期也會隨之消失。這對於定期產生的 pod 完成後就回收的 CronJob 來說會是一個問題:因為我們想要我們定期抓下來的網路資料可以持續存在。關於這個問題我們可以使用寫入資料庫或是宣告 k8s persistent volume 並掛載檔案路徑到 CronJob 中來解決。

以下我們宣告 hostPath volumes 並把 volume mount 到 /data 下面(hostPath 你可以想成若是 pod 重啟,會去找到上次的 pod 的檔案路徑和保留的檔案,當實務上會造成 pod 沒辦法有效 deploy 到適合的 node 上,此處因為使用 minikube 測試所以沒使用 GCP、AWS等 persistent volume 和外掛檔案系統)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: k8s-cronjob-pvc-example
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: k8s-cronjob-pvc-example
image: kdchang/k8s-cronjob-pvc-example:v1
args:
- /bin/sh
- -c
- ls /data
- date; echo Hello from the Kubernetes cluster
volumeMounts:
- mountPath: /data
name: crawl-data
restartPolicy: OnFailure
volumes:
- name: crawl-data
hostPath:
# directory location on host
path: /data
# this field is optional
type: Directory

接著執行我們的 cronjob.yaml

1
2
$ kubectl create -f cronjob.yaml
cronjob.batch/k8s-cronjob-pvc-example created

此時使用以下指令應該就會看到 cronjob 開始執行

1
2
3
$ kubectl get cronjob
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
k8s-cronjob-pvc-example */1 * * * * False 0 <none> 11s

一分鐘後看到 cronjob pod 成功開始執行!

1
2
3
4
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
k8s-cronjob-pvc-example-1561892400-cbpc4 0/1 Completed 0 75s
k8s-cronjob-pvc-example-1561892460-t9ckq 0/1 Completed 0 15s

觀看 log

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ kubectl logs -f k8s-cronjob-pvc-example-1561892400-cbpc4
2019-06-29 10:27:57.140583.json
2019-06-29 10:27:57.492762.json
2019-06-29 10:27:57.737316.json
2019-06-29 10:27:58.996981.json
2019-06-29 10:27:59.125029.json
2019-06-29 10:27:59.140703.json
2019-06-29 10:28:12.885361.json
2019-06-29 10:28:12.942726.json
2019-06-29 10:28:15.883667.json
2019-06-29 10:28:40.844267.json
2019-06-29 10:28:43.823896.json
2019-06-29 10:28:44.787840.json
2019-06-29 10:28:47.097306.json
2019-06-29 10:28:48.122653.json
2019-06-29 10:29:02.764501.json
2019-06-29 10:29:21.785981.json
2019-06-29 10:29:29.779006.json
2019-06-29 10:29:35.822945.json
2019-06-29 10:30:10.770817.json
2019-06-29 10:30:53.822591.json
2019-06-29 10:31:09.812561.json

若你要移除的話可以使用以下指令:

1
2
$ kubectl delete cronjob k8s-cronjob-pvc-example
cronjob.batch "k8s-cronjob-pvc-example" deleted

總結

以上簡單介紹了如何使用 K8S 自動化定期 CronJob 抓網路公開資料。有許多開發者在從裸機 bare metal server 轉換到 Kubenetes(k8s) 的過程中常常會覺得 deubg 不太習慣,主要原因就是原本可以隨便 ssh 進去主機和抓取最新的資料並重啟機器的簡單粗暴方式變得麻煩,但若是能克服這一點的話,就能享受 dockerize 的可攜性和 k8s 的簡單擴展和部屬特性,更加專注在業務邏輯上。我們下回見囉,掰撲!

參考文件

  1. Running Automated Tasks with a CronJob
  2. Kubernetes, Docker, and Cron

關於作者:
@kdchang 文藝型開發者,夢想是做出人們想用的產品和辦一所心目中理想的學校。A Starter & Maker. JavaScript, Python & Arduino/Android lover.:)

喜歡我們的文章嗎?歡迎分享按讚給予我們支持和鼓勵!





訂閱 TechBridge Weekly 技術週刊,每週發送最精華的技術開發、產品設計的資訊給您



TechBridge Weekly 技術週刊編輯團隊

TechBridge Weekly 技術週刊團隊是一群對用技術改變世界懷抱熱情的團隊。本技術共筆部落格初期專注於Web前後端、行動網路、機器人/物聯網、資料科學與產品設計等技術分享。This is TechBridge Weekly Team Tech Blog, which focus on web, mobile, robot, IoT, Data Science technology sharing.

關於我們 / 技術日報 / 技術週刊 / 粉絲專頁 / 訂閱RSS

留言討論