配置項目的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使用cron定時運行.NETCore App
一個坑
如果直接在crontab -e
中通過下面的方法添加任務:
*/2 * * * * dotnet /publish/your.app.dll #2分鍾運行一次,用於測試
肯定是沒有辦法執行的,通過tail -f /var/log/cron
可以看到如下錯誤輸出(CentOS):
(root) CMDOUT (/bin/sh: dotnet: 未找到命令)
爬坑
我們需要使用如下腳本來幫助運行.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
一些已知限制,應用程序目錄中不能含有
.
為避免在cron輸出日志時遇到
No MTA installed, discarding output
這樣的錯誤,建議重定向應用的輸出到指定的文件
將這個文件保存為rundotnet.sh
並設置輸出到發布文件中。這個文件將被cron調用定時來運行.NetCore程序。
將使用crontab -e
修改cron任務如下(添加后可使用crontab -l
驗證添加結果):
*/2 * * * * /publish/rundotnet.sh
注意修改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最主要的還是屏蔽不同底層系統的差異。順便可以讓不同的應用的定時任務可以分離。本文也是提供一種方法,供有需要的童鞋參考。