.NET趕上Docker - Docker集成Cron定時運行.NETCore(ConsoleApp)程序.md

配置項目的Docker支持

對於VS中Docker的配置,依舊重複一些廢話。
給項目添加Docker支持,VS2015能夠直接使用Docker for VS插件,VS2017在安裝時選擇容器支持。VS配置好容器支持後,右鍵點擊項目,添加菜單中就可看到Docker Support選項。
VS2015的Docker for VS插件會把Dockerfile加入到package.json的publishOptions中。這樣一次dotnet publish操做就能夠得到含有Dockerfile能夠直接用於生成Image的輸出。
而VS2017中,使用「添加-Docker支持」菜單添加的Dockerfile文件不會自動配置爲輸出到輸出目錄,能夠選擇Dockerfile並右擊屬性,在屬性選項卡中,選擇「若是較新則複製」。linux

在Linux使用cron定時運行.NETCore App

一個坑

若是直接在crontab -e中經過下面的方法添加任務:docker

*/2 * * * * dotnet /publish/your.app.dll #2分鐘運行一次,用於測試shell

確定是沒有辦法執行的,經過tail -f /var/log/cron能夠看到以下錯誤輸出(CentOS):json

(root) CMDOUT (/bin/sh: dotnet: 未找到命令)ubuntu

爬坑

咱們須要使用以下腳原本幫助運行.NetCore應用:安全

#!/bin/sh
export  PATH=$PATH:/publish:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
cd /publish
dotnet your.app.dll >> /var/log/cron.log 2>&1 #將應用的輸出重定向(可選),默認輸出到`/var/log/cron`
exit;
EOF

一些已知限制,應用程序目錄中不能含有.bash

爲避免在cron輸出日誌時遇到No MTA installed, discarding output這樣的錯誤,建議重定向應用的輸出到指定的文件app

將這個文件保存爲rundotnet.sh並設置輸出到發佈文件中。這個文件將被cron調用定時來運行.NetCore程序。
將使用crontab -e修改cron任務以下(添加後可以使用crontab -l驗證添加結果):測試

*/2 * * * * /publish/rundotnet.shui

注意修改rundotnet.sh的權限使其具備執行權限

另外一種方式是直接將應用發佈爲可執行程序。
親測使用VS2017發佈.NetCore App(.NETCore版本1.0.4),能夠在安裝有.NetCore SDK 1.0.3的Linux上使用下面的cron配置正常執行。

*/2 * * * * /publish/your.app

一樣須要賦予your.app文件執行權限

而VS2015發佈.NetCore App(.NETCore版本1.0.0),在安裝有.NetCore SDK 1.0.1的Linux上就不能正常執行。

整合到Docker中

建立一個名爲crontab的文件用於保存cron命令,內容就是咱們以前使用crontab -e添加的任務:

*/2 * * * root /publish/rundotnet.sh # 用戶名root在這裏不可少,根據須要修改定時執行的時間
# 合法的cron文件須要留一行空行

可能有眼尖的園友發現爲何這裏有root這個用戶名而前文沒有,前文的測試是在一臺RedHat系(CentOS7)上進行的。而微軟的.NETCore Docker Iamge基於Debian繫系統,這裏必須有用戶名,否則會報相似「crontab文件格式不合法「相似的錯誤。

建立好文件後將其配置爲發佈到輸出目錄,以即可以在dotnet pulish後被docker build所使用

而後添加一個文件runcron.sh,這將做爲docker container的執行入口

rsyslogd
cron
touch /var/log/cron.log
tail -F /var/log/syslog /var/log/cron.log

最後一行分別輸出系統日誌(cron執行狀況,在syslog中)和dotnet app的輸出(在cron.log中,前提是前面添加了輸出的重定向)

tail命令將保證container一致執行,不會退出
也能夠用docker的--restart=always參數控制容器的運行

修改VS建立的Dockerfile文件中的內容爲相似以下的樣子:

FROM microsoft/dotnet:1.0-runtime
COPY . /publish
WORKDIR /publish
# 開始配置cron

# microsoft/dotnet:1.0-runtime鏡像不包含cron,先安裝,順便安裝rsyslog輸出日誌
RUN apt-get update \
    && apt-get install -y --no-install-recommends \
               cron \
               rsyslog \
    && rm -rf /var/lib/apt/lists/*

# 將咱們編輯的crontab任務文件添加到cron配置目錄
ADD crontab /etc/cron.d/dotnet-cron
# 賦予crontab文件讀權限(rw/r/r)
RUN chmod 0644 /etc/cron.d/dotnet-cron
# 建立日誌文件,以便執行tail命令
RUN touch /var/log/cron.log
# 賦予runcron.sh和rundotnet.sh執行權限
RUN chmod +x /publish/rundotnet.sh
RUN chmod +x /publish/runcron.sh
# 執行入口腳本runcron.sh
CMD ["bash","/publish/runcron.sh"]

在Dockerfile中咱們向基礎容器添加了cron和rsyslog,在debian/ubuntu上(dotnet官方鏡像的基礎系統)cron須要靠rsyslog來輸出日誌

最終輸出目錄要包含下列文件:

"appsettings.json",
"Dockerfile",
"crontab",
"rundotnet.sh",
"runcron.sh"

使用以下命令publish項目

dotnet publish --framework netcoreapp1.0 --configuration release --output publish

將publish中文件傳到安裝有docker的環境中準備生成docker image

生成Docker映像,運行Container

咱們將生成運行(包含清理舊映像)的腳本整合爲一個buildhelper.sh:

#!/bin/bash
contName=$1
contName=${contName:="containerName"}
imagName=$2
imagName=${imagName:="orgname/projname:tag"}
docker stop ${contName}
docker rm -f ${contName}
docker rmi ${imagName}
docker ps -a
docker images
sudo docker build --rm -t orgname/projname:tag .
sudo docker run --name containerName -it orgname/projname:tag

依然配置此文件發佈到輸出到發佈目錄(在Linux上要賦予執行權限)。

容器運行後能夠鏈接到container的bash查看運行狀況

docker exec -it containerName /bin/bash

若是感受測試時,每次Docker Image都會進行apt-get安裝cron很麻煩,能夠先生成一個包含cron以及rsyslog的鏡像,並以此做爲這個例子的基礎鏡像。(按照博主提供的這些基本能夠一次成功)

提示

全部shell腳本文件(xxx.sh),若是是UTF8格式,都要使用無BOM的UTF8編碼。或者使用ASCII。否則bash沒法正常運行。
一鍵去BOM的方法: grep -r -I -l $'^\xEF\xBB\xBF' /path | xargs sed -i 's/^\xEF\xBB\xBF//g'


若是在Windows裏編輯過sh文件,在linux種可能出現錯誤:「/bin/bash^M:損壞的解釋器: 沒有那個文件或目錄」
這是因爲兩種系統換行符不一樣,Windows爲\n\r,Linux爲\n,而\r會被顯示爲^M。
一鍵替換 sed -i 's/\r$//g' filename
大體有以下文件須要處理:

sed -i 's/\r$//g' crontab
sed -i 's/\r$//g' buildhelper.sh
sed -i 's/\r$//g' rundotnet.sh
sed -i 's/\r$//g' runcron.sh

crontab處理換行很重要,否則在linux會致使必須存在的空行沒法被識別而沒法正茬加載。


rsyslogd的以下錯誤提示能夠安全忽略:
rsyslogd: imklog: cannot open kernel log(/proc/kmsg): Operation not permitted.
而錯誤:
Could not open output pipe '/dev/xconsole': No such file or directory
暫時不知道有無影響(實測不會對rsyslog的工做產生影響)


定時任務時間 對於定時任務,要注意如以前使用的基礎鏡像microsoft/dotnet:1.0.1-core的時區都是UTC時間,對於咱們UTC+8的地方要自行在配置cron的時間時加上8個小時。
好辦法 在生成鏡像的時候直接修改好時區,Dockerfile中加入 RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime


可能會有小朋友質疑,用Docker運行這種定時任務有必要嗎,樓主感受Docker最主要的仍是屏蔽不一樣底層系統的差別。順即可以讓不一樣的應用的定時任務能夠分離。本文也是提供一種方法,供有須要的童鞋參考。

相關文章
相關標籤/搜索