在Docker中定期執行指令 / Run a Scheduled Job Inside a Docker Container

原文约2500字,阅读约需6分钟。发表于:

總不會全天下只有我不能在Docker容器裡面執行crontab吧? cron不能運作 / cron is not working https://forums.docker.com/t/cron-does-not-run-in-a-php-docker-container/103897  根據大部分網路上說法,如果要在Docker容器裡面用cron做排程,主要是在Dockerfile裡面寫入以下指令: # 複製crontab檔案到cron.d目錄COPY ./docker/php-server/crontab /etc/cron.d/crontab# 設定執行權限RUN chmod 0644 /etc/cron.d/crontab# 啟用cron排程任務RUN crontab /etc/cron.d/crontab 而crontab的寫法可以參考下的寫法: * * * * * root php /var/www/artisan schedule:run >> /var/log/cron.log 2>&1 然而,我在Debian bullseye版本裡,這個方法並不能正常運作。我有確認cron的確有載入我的設定,但cron就是不能在我設定的時間內正常運作。 https://pypi.org/project/python-crontab/  如果系統上的cron無法正常運作,那我能不能用其他程式語言來做排程呢? 我嘗試了Python的python-crontab。它有種寫法可以在Windows環境運作,這可能表示它不需要仰賴Linux的cron,所以比較可能可以成功?但結果也是不行。 https://www.npmjs.com/package/node-cron  我之前試過Node.js的Node Cron套件,它的確能照我所想的運作。不過只是為了跑個排程,還要額外安裝Node.js,好像有點太過複雜了。有沒有更簡單的方法呢? 有,而且還是基本程式設計就會學到的做法:等待與無限迴圈。 用Bash實作的排程腳本 / Create a scheduled job with Bash 要完成這個任務,我們有兩階段設定需要進行。 腳本 / Script  第一個階段是是建立我們的排程腳本cron.sh。請將以下程式碼儲存到/cron.sh中,記得開啟執行權限(chmod +x cron.sh),程式碼內容如下: #!/bin/bash while :do # Seconds  sleep 30 # Your Scheduled job  echo `date` > /tmp/date.txtdone cron.sh的原理很簡單,首先用while執行無限迴圈。迴圈開頭會先用sleep等待30秒。30秒之後再輸出現在的時間(echo `date`)到/tmp/date.txt檔案中。 儘管認真的話也可以寫的像是crontab那樣,每分鐘都檢查一次分鐘、小時、天、月、週,但大多時候我只是要一段時間後執行某個腳本而已。沒錯,我就是在說certbot更新SSL憑證的這件事情。Let's Encrypt的憑證期限只有90天,我建議每30天就檢查一次憑證看需不需要更新。 背景程序 / Background process 有了腳本之後,接下來要讓它能夠執行,而且必須要讓它在背景執行,不能擋住原本Docker容器要執行的工作。 Docker容器必須要以一個特定的執行程序為主。當該程序中斷的時候,Docker容器就隨之關機。很多時候執行程序只是一個簡單的指令,但大多時候我們要在Docker容器裡面執行的工作都相當複雜,於是很多容器會建立docker-entrypoint.sh,或是鼓勵開發者將要執行的腳本放到 /docker-entrypoint.d/ 的目錄中。 https://stackoverflow.com/a/64205695 NGINX就是一個很好的例子。我們可以在/docker-entrypoint.d放入我們希望在NGINX正式啟動之前所執行的腳本,而這裡就是啟動排程腳本cron.sh的位置。 請建立/docker-entrypoint.d/startup.sh,給予它執行權限(chmod +x /docker-entrypoint.d/startup.sh)。startup.sh的內容如下: #!/bin/bash/cron.sh & /cron.sh後面的&表示是以背景程序執行。這樣Docker容器就不會被卡在/cron.sh的無限迴圈中,而能夠繼續啟動NGINX。 這樣我們就算是完成了。 小結 / In closing 用無限迴圈(while)跟等待(sleep)的做法簡單粗暴,但同時也存在著兩個排程時需要注意的隱憂: 排程執行的指令如果發生意外,整個排程會完全終止。最好加入「||」來避免這個問題。詳情請看Jayesh Bhoi的說明。 排程結果缺乏明確的記錄機制,讓人難以確定排程是否有順利完成,還是是否還在進行中。這也只能自行手動設定。 https://blog.longwin.com.tw/2020/07/docker-crontab-how-to-set-2020/  許多人認為排程任務不應該寫在Docker容器內,而是要由主機伺服器(host)自己的排程來啟動Docker容器。這點我並不認同,因為這必須修改主機伺服器,進而提高整個設定門檻。除非是需要使用者客製化調整的設定,不然能包在Docker容器裡就能完成的工作,我會希望它盡可能就在Docker容器裡完成就好。 最後要來問大家的問題是:為什麼我的Docker容器就是不能跑cron啊? 請求高手解惑QQ

本文介绍在Docker容器中使用cron做排程的方法,包括在Dockerfile中写入指令、使用Python和Node.js的套件等方法。提出使用Bash实现排程脚本的方法,并在/docker-entrypoint.d目录中启动脚本。需要注意两个排程时的隐患。应尽可能在Docker容器中完成工作。

在Docker中定期執行指令 / Run a Scheduled Job Inside a Docker Container
相关推荐 去reddit讨论